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/dom/Node.h" 31 #include "core/editing/htmlediting.h" 32 #include "core/html/HTMLHtmlElement.h" 33 #include "core/rendering/RenderBlock.h" 34 35 namespace WebCore { 36 37 using namespace HTMLNames; 38 39 PositionIterator::operator Position() const 40 { 41 if (m_nodeAfterPositionInAnchor) { 42 ASSERT(m_nodeAfterPositionInAnchor->parentNode() == m_anchorNode); 43 // FIXME: This check is inadaquete because any ancestor could be ignored by editing 44 if (editingIgnoresContent(m_nodeAfterPositionInAnchor->parentNode())) 45 return positionBeforeNode(m_anchorNode); 46 return positionInParentBeforeNode(m_nodeAfterPositionInAnchor); 47 } 48 if (m_anchorNode->hasChildNodes()) 49 return lastPositionInOrAfterNode(m_anchorNode); 50 return createLegacyEditingPosition(m_anchorNode, m_offsetInAnchor); 51 } 52 53 void PositionIterator::increment() 54 { 55 if (!m_anchorNode) 56 return; 57 58 if (m_nodeAfterPositionInAnchor) { 59 m_anchorNode = m_nodeAfterPositionInAnchor; 60 m_nodeAfterPositionInAnchor = m_anchorNode->firstChild(); 61 m_offsetInAnchor = 0; 62 return; 63 } 64 65 if (!m_anchorNode->hasChildNodes() && m_offsetInAnchor < lastOffsetForEditing(m_anchorNode)) 66 m_offsetInAnchor = Position::uncheckedNextOffset(m_anchorNode, m_offsetInAnchor); 67 else { 68 m_nodeAfterPositionInAnchor = m_anchorNode; 69 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode(); 70 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->nextSibling(); 71 m_offsetInAnchor = 0; 72 } 73 } 74 75 void PositionIterator::decrement() 76 { 77 if (!m_anchorNode) 78 return; 79 80 if (m_nodeAfterPositionInAnchor) { 81 m_anchorNode = m_nodeAfterPositionInAnchor->previousSibling(); 82 if (m_anchorNode) { 83 m_nodeAfterPositionInAnchor = 0; 84 m_offsetInAnchor = m_anchorNode->hasChildNodes() ? 0 : lastOffsetForEditing(m_anchorNode); 85 } else { 86 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->parentNode(); 87 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode(); 88 m_offsetInAnchor = 0; 89 } 90 return; 91 } 92 93 if (m_anchorNode->hasChildNodes()) { 94 m_anchorNode = m_anchorNode->lastChild(); 95 m_offsetInAnchor = m_anchorNode->hasChildNodes()? 0: lastOffsetForEditing(m_anchorNode); 96 } else { 97 if (m_offsetInAnchor) 98 m_offsetInAnchor = Position::uncheckedPreviousOffset(m_anchorNode, m_offsetInAnchor); 99 else { 100 m_nodeAfterPositionInAnchor = m_anchorNode; 101 m_anchorNode = m_anchorNode->parentNode(); 102 } 103 } 104 } 105 106 bool PositionIterator::atStart() const 107 { 108 if (!m_anchorNode) 109 return true; 110 if (m_anchorNode->parentNode()) 111 return false; 112 return (!m_anchorNode->hasChildNodes() && !m_offsetInAnchor) || (m_nodeAfterPositionInAnchor && !m_nodeAfterPositionInAnchor->previousSibling()); 113 } 114 115 bool PositionIterator::atEnd() const 116 { 117 if (!m_anchorNode) 118 return true; 119 if (m_nodeAfterPositionInAnchor) 120 return false; 121 return !m_anchorNode->parentNode() && (m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode)); 122 } 123 124 bool PositionIterator::atStartOfNode() const 125 { 126 if (!m_anchorNode) 127 return true; 128 if (!m_nodeAfterPositionInAnchor) 129 return !m_anchorNode->hasChildNodes() && !m_offsetInAnchor; 130 return !m_nodeAfterPositionInAnchor->previousSibling(); 131 } 132 133 bool PositionIterator::atEndOfNode() const 134 { 135 if (!m_anchorNode) 136 return true; 137 if (m_nodeAfterPositionInAnchor) 138 return false; 139 return m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode); 140 } 141 142 bool PositionIterator::isCandidate() const 143 { 144 if (!m_anchorNode) 145 return false; 146 147 RenderObject* renderer = m_anchorNode->renderer(); 148 if (!renderer) 149 return false; 150 151 if (renderer->style()->visibility() != VISIBLE) 152 return false; 153 154 if (renderer->isBR()) 155 return !m_offsetInAnchor && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode()); 156 157 if (renderer->isText()) 158 return !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).inRenderedText(); 159 160 if (isTableElement(m_anchorNode) || editingIgnoresContent(m_anchorNode)) 161 return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode()); 162 163 if (!isHTMLHtmlElement(m_anchorNode) && renderer->isBlockFlow()) { 164 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName(bodyTag)) { 165 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer)) 166 return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode); 167 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary(); 168 } 169 } 170 171 return false; 172 } 173 174 } // namespace WebCore 175