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 "core/editing/htmlediting.h" 30#include "core/html/HTMLHtmlElement.h" 31#include "core/rendering/RenderBlock.h" 32 33namespace blink { 34 35using namespace HTMLNames; 36 37PositionIterator::operator Position() const 38{ 39 if (m_nodeAfterPositionInAnchor) { 40 ASSERT(m_nodeAfterPositionInAnchor->parentNode() == m_anchorNode); 41 // FIXME: This check is inadaquete because any ancestor could be ignored by editing 42 if (editingIgnoresContent(m_nodeAfterPositionInAnchor->parentNode())) 43 return positionBeforeNode(m_anchorNode); 44 return positionInParentBeforeNode(*m_nodeAfterPositionInAnchor); 45 } 46 if (m_anchorNode->hasChildren()) 47 return lastPositionInOrAfterNode(m_anchorNode); 48 return createLegacyEditingPosition(m_anchorNode, m_offsetInAnchor); 49} 50 51void PositionIterator::increment() 52{ 53 if (!m_anchorNode) 54 return; 55 56 if (m_nodeAfterPositionInAnchor) { 57 m_anchorNode = m_nodeAfterPositionInAnchor; 58 m_nodeAfterPositionInAnchor = m_anchorNode->firstChild(); 59 m_offsetInAnchor = 0; 60 return; 61 } 62 63 if (!m_anchorNode->hasChildren() && m_offsetInAnchor < lastOffsetForEditing(m_anchorNode)) 64 m_offsetInAnchor = Position::uncheckedNextOffset(m_anchorNode, m_offsetInAnchor); 65 else { 66 m_nodeAfterPositionInAnchor = m_anchorNode; 67 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode(); 68 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->nextSibling(); 69 m_offsetInAnchor = 0; 70 } 71} 72 73void PositionIterator::decrement() 74{ 75 if (!m_anchorNode) 76 return; 77 78 if (m_nodeAfterPositionInAnchor) { 79 m_anchorNode = m_nodeAfterPositionInAnchor->previousSibling(); 80 if (m_anchorNode) { 81 m_nodeAfterPositionInAnchor = nullptr; 82 m_offsetInAnchor = m_anchorNode->hasChildren() ? 0 : lastOffsetForEditing(m_anchorNode); 83 } else { 84 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->parentNode(); 85 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode(); 86 m_offsetInAnchor = 0; 87 } 88 return; 89 } 90 91 if (m_anchorNode->hasChildren()) { 92 m_anchorNode = m_anchorNode->lastChild(); 93 m_offsetInAnchor = m_anchorNode->hasChildren()? 0: lastOffsetForEditing(m_anchorNode); 94 } else { 95 if (m_offsetInAnchor) 96 m_offsetInAnchor = Position::uncheckedPreviousOffset(m_anchorNode, m_offsetInAnchor); 97 else { 98 m_nodeAfterPositionInAnchor = m_anchorNode; 99 m_anchorNode = m_anchorNode->parentNode(); 100 } 101 } 102} 103 104bool PositionIterator::atStart() const 105{ 106 if (!m_anchorNode) 107 return true; 108 if (m_anchorNode->parentNode()) 109 return false; 110 return (!m_anchorNode->hasChildren() && !m_offsetInAnchor) || (m_nodeAfterPositionInAnchor && !m_nodeAfterPositionInAnchor->previousSibling()); 111} 112 113bool PositionIterator::atEnd() const 114{ 115 if (!m_anchorNode) 116 return true; 117 if (m_nodeAfterPositionInAnchor) 118 return false; 119 return !m_anchorNode->parentNode() && (m_anchorNode->hasChildren() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode)); 120} 121 122bool PositionIterator::atStartOfNode() const 123{ 124 if (!m_anchorNode) 125 return true; 126 if (!m_nodeAfterPositionInAnchor) 127 return !m_anchorNode->hasChildren() && !m_offsetInAnchor; 128 return !m_nodeAfterPositionInAnchor->previousSibling(); 129} 130 131bool PositionIterator::atEndOfNode() const 132{ 133 if (!m_anchorNode) 134 return true; 135 if (m_nodeAfterPositionInAnchor) 136 return false; 137 return m_anchorNode->hasChildren() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode); 138} 139 140bool PositionIterator::isCandidate() const 141{ 142 if (!m_anchorNode) 143 return false; 144 145 RenderObject* renderer = m_anchorNode->renderer(); 146 if (!renderer) 147 return false; 148 149 if (renderer->style()->visibility() != VISIBLE) 150 return false; 151 152 if (renderer->isBR()) { 153 // For br element, the condition 154 // |(!m_anchorNode->hasChildren() || m_nodeAfterPositionInAnchor)| 155 // corresponds to the condition 156 // |m_anchorType != PositionIsAfterAnchor| in Position.isCandaite. 157 // Both conditions say this position is not in tail of the element. 158 // If conditions lose consitency, VisiblePosition::canonicalPosition 159 // will fail on |canonicalizeCandidate(previousCandidate(position))|, 160 // because previousCandidate returns a Position converted from 161 // a "Candidate" PositionIterator and cannonicalizeCandidate(Position) 162 // assumes the Position is "Candidate". 163 return !m_offsetInAnchor && (!m_anchorNode->hasChildren() || m_nodeAfterPositionInAnchor) && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode()); 164 } 165 if (renderer->isText()) 166 return !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).inRenderedText(); 167 168 if (renderer->isSVG()) { 169 // We don't consider SVG elements are contenteditable except for 170 // associated renderer returns isText() true, e.g. RenderSVGInlineText. 171 return false; 172 } 173 174 if (isRenderedHTMLTableElement(m_anchorNode) || editingIgnoresContent(m_anchorNode)) 175 return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode()); 176 177 if (!isHTMLHtmlElement(*m_anchorNode) && renderer->isRenderBlockFlow()) { 178 if (toRenderBlock(renderer)->logicalHeight() || isHTMLBodyElement(*m_anchorNode)) { 179 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer)) 180 return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode); 181 return m_anchorNode->hasEditableStyle() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary(); 182 } 183 } 184 185 return false; 186} 187 188} // namespace blink 189