1 /* 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "core/dom/PositionIterator.h" 28 29 #include "HTMLNames.h" 30 #include "core/editing/htmlediting.h" 31 #include "core/html/HTMLHtmlElement.h" 32 #include "core/rendering/RenderBlock.h" 33 34 namespace WebCore { 35 36 using namespace HTMLNames; 37 38 PositionIterator::operator Position() const 39 { 40 if (m_nodeAfterPositionInAnchor) { 41 ASSERT(m_nodeAfterPositionInAnchor->parentNode() == m_anchorNode); 42 // FIXME: This check is inadaquete because any ancestor could be ignored by editing 43 if (editingIgnoresContent(m_nodeAfterPositionInAnchor->parentNode())) 44 return positionBeforeNode(m_anchorNode); 45 return positionInParentBeforeNode(m_nodeAfterPositionInAnchor); 46 } 47 if (m_anchorNode->hasChildNodes()) 48 return lastPositionInOrAfterNode(m_anchorNode); 49 return createLegacyEditingPosition(m_anchorNode, m_offsetInAnchor); 50 } 51 52 void PositionIterator::increment() 53 { 54 if (!m_anchorNode) 55 return; 56 57 if (m_nodeAfterPositionInAnchor) { 58 m_anchorNode = m_nodeAfterPositionInAnchor; 59 m_nodeAfterPositionInAnchor = m_anchorNode->firstChild(); 60 m_offsetInAnchor = 0; 61 return; 62 } 63 64 if (!m_anchorNode->hasChildNodes() && m_offsetInAnchor < lastOffsetForEditing(m_anchorNode)) 65 m_offsetInAnchor = Position::uncheckedNextOffset(m_anchorNode, m_offsetInAnchor); 66 else { 67 m_nodeAfterPositionInAnchor = m_anchorNode; 68 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode(); 69 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->nextSibling(); 70 m_offsetInAnchor = 0; 71 } 72 } 73 74 void PositionIterator::decrement() 75 { 76 if (!m_anchorNode) 77 return; 78 79 if (m_nodeAfterPositionInAnchor) { 80 m_anchorNode = m_nodeAfterPositionInAnchor->previousSibling(); 81 if (m_anchorNode) { 82 m_nodeAfterPositionInAnchor = 0; 83 m_offsetInAnchor = m_anchorNode->hasChildNodes() ? 0 : lastOffsetForEditing(m_anchorNode); 84 } else { 85 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->parentNode(); 86 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode(); 87 m_offsetInAnchor = 0; 88 } 89 return; 90 } 91 92 if (m_anchorNode->hasChildNodes()) { 93 m_anchorNode = m_anchorNode->lastChild(); 94 m_offsetInAnchor = m_anchorNode->hasChildNodes()? 0: lastOffsetForEditing(m_anchorNode); 95 } else { 96 if (m_offsetInAnchor) 97 m_offsetInAnchor = Position::uncheckedPreviousOffset(m_anchorNode, m_offsetInAnchor); 98 else { 99 m_nodeAfterPositionInAnchor = m_anchorNode; 100 m_anchorNode = m_anchorNode->parentNode(); 101 } 102 } 103 } 104 105 bool PositionIterator::atStart() const 106 { 107 if (!m_anchorNode) 108 return true; 109 if (m_anchorNode->parentNode()) 110 return false; 111 return (!m_anchorNode->hasChildNodes() && !m_offsetInAnchor) || (m_nodeAfterPositionInAnchor && !m_nodeAfterPositionInAnchor->previousSibling()); 112 } 113 114 bool PositionIterator::atEnd() const 115 { 116 if (!m_anchorNode) 117 return true; 118 if (m_nodeAfterPositionInAnchor) 119 return false; 120 return !m_anchorNode->parentNode() && (m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode)); 121 } 122 123 bool PositionIterator::atStartOfNode() const 124 { 125 if (!m_anchorNode) 126 return true; 127 if (!m_nodeAfterPositionInAnchor) 128 return !m_anchorNode->hasChildNodes() && !m_offsetInAnchor; 129 return !m_nodeAfterPositionInAnchor->previousSibling(); 130 } 131 132 bool PositionIterator::atEndOfNode() const 133 { 134 if (!m_anchorNode) 135 return true; 136 if (m_nodeAfterPositionInAnchor) 137 return false; 138 return m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode); 139 } 140 141 bool PositionIterator::isCandidate() const 142 { 143 if (!m_anchorNode) 144 return false; 145 146 RenderObject* renderer = m_anchorNode->renderer(); 147 if (!renderer) 148 return false; 149 150 if (renderer->style()->visibility() != VISIBLE) 151 return false; 152 153 if (renderer->isBR()) 154 return !m_offsetInAnchor && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode()); 155 156 if (renderer->isText()) 157 return !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).inRenderedText(); 158 159 if (isTableElement(m_anchorNode) || editingIgnoresContent(m_anchorNode)) 160 return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode()); 161 162 if (!isHTMLHtmlElement(m_anchorNode) && renderer->isRenderBlockFlow()) { 163 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName(bodyTag)) { 164 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer)) 165 return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode); 166 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary(); 167 } 168 } 169 170 return false; 171 } 172 173 } // namespace WebCore 174