2 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 COMPUTER, 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.
29 #include "CSSComputedStyleDeclaration.h"
30 #include "HTMLNames.h"
31 #include "InlineIterator.h"
32 #include "InlineTextBox.h"
34 #include "PositionIterator.h"
35 #include "RenderBlock.h"
36 #include "RenderInline.h"
37 #include "RenderText.h"
38 #include "RuntimeEnabledFeatures.h"
40 #include "TextIterator.h"
41 #include "VisiblePosition.h"
42 #include "VisibleUnits.h"
43 #include "htmlediting.h"
45 #include <wtf/text/CString.h>
46 #include <wtf/unicode/CharacterNames.h>
50 using namespace HTMLNames;
52 static Node* nextRenderedEditable(Node* node)
54 while ((node = nextLeafNode(node))) {
55 if (!node->rendererIsEditable())
57 RenderObject* renderer = node->renderer();
60 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
66 static Node* previousRenderedEditable(Node* node)
68 while ((node = previousLeafNode(node))) {
69 if (!node->rendererIsEditable())
71 RenderObject* renderer = node->renderer();
74 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
80 Position::Position(PassRefPtr<Node> anchorNode, LegacyEditingOffset offset)
81 : m_anchorNode(anchorNode)
82 , m_offset(offset.value())
83 , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
84 , m_isLegacyEditingPosition(true)
86 #if ENABLE(SHADOW_DOM)
87 ASSERT((m_anchorNode && RuntimeEnabledFeatures::shadowDOMEnabled())
88 || !m_anchorNode || !m_anchorNode->isShadowRoot());
90 ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot());
92 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
95 Position::Position(PassRefPtr<Node> anchorNode, AnchorType anchorType)
96 : m_anchorNode(anchorNode)
98 , m_anchorType(anchorType)
99 , m_isLegacyEditingPosition(false)
101 #if ENABLE(SHADOW_DOM)
102 ASSERT((m_anchorNode && RuntimeEnabledFeatures::shadowDOMEnabled())
103 || !m_anchorNode || !m_anchorNode->isShadowRoot());
105 ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot());
108 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
110 ASSERT(anchorType != PositionIsOffsetInAnchor);
111 ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren)
112 && (m_anchorNode->isTextNode() || editingIgnoresContent(m_anchorNode.get()))));
115 Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
116 : m_anchorNode(anchorNode)
118 , m_anchorType(anchorType)
119 , m_isLegacyEditingPosition(false)
121 #if ENABLE(SHADOW_DOM)
122 ASSERT((m_anchorNode && RuntimeEnabledFeatures::shadowDOMEnabled())
123 || !m_anchorNode || !editingIgnoresContent(m_anchorNode.get()) || !m_anchorNode->isShadowRoot());
125 ASSERT(!m_anchorNode || !editingIgnoresContent(m_anchorNode.get()) || !m_anchorNode->isShadowRoot());
128 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
130 ASSERT(anchorType == PositionIsOffsetInAnchor);
133 Position::Position(PassRefPtr<Text> textNode, unsigned offset)
134 : m_anchorNode(textNode)
135 , m_offset(static_cast<int>(offset))
136 , m_anchorType(PositionIsOffsetInAnchor)
137 , m_isLegacyEditingPosition(false)
139 ASSERT(m_anchorNode);
142 void Position::moveToPosition(PassRefPtr<Node> node, int offset)
144 ASSERT(!editingIgnoresContent(node.get()));
145 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
148 if (m_isLegacyEditingPosition)
149 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
151 void Position::moveToOffset(int offset)
153 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
155 if (m_isLegacyEditingPosition)
156 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
159 Node* Position::containerNode() const
164 switch (anchorType()) {
165 case PositionIsBeforeChildren:
166 case PositionIsAfterChildren:
167 case PositionIsOffsetInAnchor:
168 return m_anchorNode.get();
169 case PositionIsBeforeAnchor:
170 case PositionIsAfterAnchor:
171 return findParent(m_anchorNode.get());
173 ASSERT_NOT_REACHED();
177 Text* Position::containerText() const
179 switch (anchorType()) {
180 case PositionIsOffsetInAnchor:
181 return m_anchorNode && m_anchorNode->isTextNode() ? toText(m_anchorNode.get()) : 0;
182 case PositionIsBeforeAnchor:
183 case PositionIsAfterAnchor:
185 case PositionIsBeforeChildren:
186 case PositionIsAfterChildren:
187 ASSERT(!m_anchorNode || !m_anchorNode->isTextNode());
190 ASSERT_NOT_REACHED();
194 int Position::computeOffsetInContainerNode() const
199 switch (anchorType()) {
200 case PositionIsBeforeChildren:
202 case PositionIsAfterChildren:
203 return lastOffsetInNode(m_anchorNode.get());
204 case PositionIsOffsetInAnchor:
205 return minOffsetForNode(m_anchorNode.get(), m_offset);
206 case PositionIsBeforeAnchor:
207 return m_anchorNode->nodeIndex();
208 case PositionIsAfterAnchor:
209 return m_anchorNode->nodeIndex() + 1;
211 ASSERT_NOT_REACHED();
215 int Position::offsetForPositionAfterAnchor() const
217 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren);
218 ASSERT(!m_isLegacyEditingPosition);
219 return lastOffsetForEditing(m_anchorNode.get());
222 // Neighbor-anchored positions are invalid DOM positions, so they need to be
223 // fixed up before handing them off to the Range object.
224 Position Position::parentAnchoredEquivalent() const
229 // FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
230 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType != PositionIsAfterChildren)) {
231 if (findParent(m_anchorNode.get()) && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get())))
232 return positionInParentBeforeNode(m_anchorNode.get());
233 return Position(m_anchorNode.get(), 0, PositionIsOffsetInAnchor);
235 if (!m_anchorNode->offsetInCharacters()
236 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount())
237 && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get()))
238 && containerNode()) {
239 return positionInParentAfterNode(m_anchorNode.get());
242 return Position(containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor);
245 Node* Position::computeNodeBeforePosition() const
250 switch (anchorType()) {
251 case PositionIsBeforeChildren:
253 case PositionIsAfterChildren:
254 return m_anchorNode->lastChild();
255 case PositionIsOffsetInAnchor:
256 return m_anchorNode->childNode(m_offset - 1); // -1 converts to childNode((unsigned)-1) and returns null.
257 case PositionIsBeforeAnchor:
258 return m_anchorNode->previousSibling();
259 case PositionIsAfterAnchor:
260 return m_anchorNode.get();
262 ASSERT_NOT_REACHED();
266 Node* Position::computeNodeAfterPosition() const
271 switch (anchorType()) {
272 case PositionIsBeforeChildren:
273 return m_anchorNode->firstChild();
274 case PositionIsAfterChildren:
276 case PositionIsOffsetInAnchor:
277 return m_anchorNode->childNode(m_offset);
278 case PositionIsBeforeAnchor:
279 return m_anchorNode.get();
280 case PositionIsAfterAnchor:
281 return m_anchorNode->nextSibling();
283 ASSERT_NOT_REACHED();
287 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
289 if (anchorNode && editingIgnoresContent(anchorNode)) {
291 return Position::PositionIsBeforeAnchor;
292 return Position::PositionIsAfterAnchor;
294 return Position::PositionIsOffsetInAnchor;
297 // FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
298 Element* Position::element() const
300 Node* n = anchorNode();
301 while (n && !n->isElementNode())
306 PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
308 Element* elem = element();
311 return CSSComputedStyleDeclaration::create(elem);
314 Position Position::previous(PositionMoveType moveType) const
316 Node* n = deprecatedNode();
320 int o = deprecatedEditingOffset();
321 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
325 Node* child = n->childNode(o - 1);
327 return lastPositionInOrAfterNode(child);
329 // There are two reasons child might be 0:
330 // 1) The node is node like a text node that is not an element, and therefore has no children.
331 // Going backward one character at a time is correct.
332 // 2) The old offset was a bogus offset like (<br>, 1), and there is no child.
333 // Going from 1 to 0 is correct.
336 return createLegacyEditingPosition(n, o - 1);
338 return createLegacyEditingPosition(n, uncheckedPreviousOffset(n, o));
339 case BackwardDeletion:
340 return createLegacyEditingPosition(n, uncheckedPreviousOffsetForBackwardDeletion(n, o));
344 ContainerNode* parent = findParent(n);
348 return createLegacyEditingPosition(parent, n->nodeIndex());
351 Position Position::next(PositionMoveType moveType) const
353 ASSERT(moveType != BackwardDeletion);
355 Node* n = deprecatedNode();
359 int o = deprecatedEditingOffset();
360 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
363 Node* child = n->childNode(o);
364 if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n))) {
366 return firstPositionInOrBeforeNode(child);
368 // There are two reasons child might be 0:
369 // 1) The node is node like a text node that is not an element, and therefore has no children.
370 // Going forward one character at a time is correct.
371 // 2) The new offset is a bogus offset like (<br>, 1), and there is no child.
372 // Going from 0 to 1 is correct.
373 return createLegacyEditingPosition(n, (moveType == Character) ? uncheckedNextOffset(n, o) : o + 1);
376 ContainerNode* parent = findParent(n);
380 return createLegacyEditingPosition(parent, n->nodeIndex() + 1);
383 int Position::uncheckedPreviousOffset(const Node* n, int current)
385 return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
388 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
390 return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
393 int Position::uncheckedNextOffset(const Node* n, int current)
395 return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
398 bool Position::atFirstEditingPositionForNode() const
402 // FIXME: Position before anchor shouldn't be considered as at the first editing position for node
403 // since that position resides outside of the node.
404 switch (m_anchorType) {
405 case PositionIsOffsetInAnchor:
406 return m_offset <= 0;
407 case PositionIsBeforeChildren:
408 case PositionIsBeforeAnchor:
410 case PositionIsAfterChildren:
411 case PositionIsAfterAnchor:
412 return !lastOffsetForEditing(deprecatedNode());
414 ASSERT_NOT_REACHED();
418 bool Position::atLastEditingPositionForNode() const
422 // FIXME: Position after anchor shouldn't be considered as at the first editing position for node
423 // since that position resides outside of the node.
424 return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || m_offset >= lastOffsetForEditing(deprecatedNode());
427 // A position is considered at editing boundary if one of the following is true:
428 // 1. It is the first position in the node and the next visually equivalent position
430 // 2. It is the last position in the node and the previous visually equivalent position
432 // 3. It is an editable position and both the next and previous visually equivalent
433 // positions are both non editable.
434 bool Position::atEditingBoundary() const
436 Position nextPosition = downstream(CanCrossEditingBoundary);
437 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable())
440 Position prevPosition = upstream(CanCrossEditingBoundary);
441 if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable())
444 return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable()
445 && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable();
448 Node* Position::parentEditingBoundary() const
450 if (!m_anchorNode || !m_anchorNode->document())
453 Node* documentElement = m_anchorNode->document()->documentElement();
454 if (!documentElement)
457 Node* boundary = m_anchorNode.get();
458 while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && m_anchorNode->rendererIsEditable() == boundary->parentNode()->rendererIsEditable())
459 boundary = boundary->nonShadowBoundaryParentNode();
465 bool Position::atStartOfTree() const
469 return !findParent(deprecatedNode()) && m_offset <= 0;
472 bool Position::atEndOfTree() const
476 return !findParent(deprecatedNode()) && m_offset >= lastOffsetForEditing(deprecatedNode());
479 int Position::renderedOffset() const
481 if (!deprecatedNode()->isTextNode())
484 if (!deprecatedNode()->renderer())
488 RenderText* textRenderer = toRenderText(deprecatedNode()->renderer());
489 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
490 int start = box->start();
491 int end = box->start() + box->len();
492 if (m_offset < start)
494 if (m_offset <= end) {
495 result += m_offset - start;
498 result += box->len();
503 // return first preceding DOM position rendered at a different location, or "this"
504 Position Position::previousCharacterPosition(EAffinity affinity) const
509 Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
511 bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
512 bool rendered = isCandidate();
514 Position currentPos = *this;
515 while (!currentPos.atStartOfTree()) {
516 currentPos = currentPos.previous();
518 if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
521 if (atStartOfLine || !rendered) {
522 if (currentPos.isCandidate())
524 } else if (rendersInDifferentPosition(currentPos))
531 // return first following position rendered at a different location, or "this"
532 Position Position::nextCharacterPosition(EAffinity affinity) const
537 Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
539 bool atEndOfLine = isEndOfLine(VisiblePosition(*this, affinity));
540 bool rendered = isCandidate();
542 Position currentPos = *this;
543 while (!currentPos.atEndOfTree()) {
544 currentPos = currentPos.next();
546 if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
549 if (atEndOfLine || !rendered) {
550 if (currentPos.isCandidate())
552 } else if (rendersInDifferentPosition(currentPos))
559 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
560 // If true, adjacent candidates are visually distinct.
561 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
562 // FIXME: Share code with isCandidate, if possible.
563 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
565 if (!node || !node->renderer())
568 if (!node->renderer()->isInline())
571 // Don't include inline tables.
572 if (node->hasTagName(tableTag))
575 // There is a VisiblePosition inside an empty inline-block container.
576 return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild();
579 static Node* enclosingVisualBoundary(Node* node)
581 while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
582 node = node->parentNode();
587 // upstream() and downstream() want to return positions that are either in a
588 // text node or at just before a non-text node. This method checks for that.
589 static bool isStreamer(const PositionIterator& pos)
594 if (isAtomicNode(pos.node()))
597 return pos.atStartOfNode();
600 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
601 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
602 // that map to the VisiblePosition between 'b' and the space. This function will return the left candidate
603 // and downstream() will return the right one.
604 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
605 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
606 Position Position::upstream(EditingBoundaryCrossingRule rule) const
608 Node* startNode = deprecatedNode();
612 // iterate backward from there, looking for a qualified position
613 Node* boundary = enclosingVisualBoundary(startNode);
614 // FIXME: PositionIterator should respect Before and After positions.
615 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
616 PositionIterator currentPos = lastVisible;
617 bool startEditable = startNode->rendererIsEditable();
618 Node* lastNode = startNode;
619 bool boundaryCrossed = false;
620 for (; !currentPos.atStart(); currentPos.decrement()) {
621 Node* currentNode = currentPos.node();
623 // Don't check for an editability change if we haven't moved to a different node,
624 // to avoid the expense of computing rendererIsEditable().
625 if (currentNode != lastNode) {
626 // Don't change editability.
627 bool currentEditable = currentNode->rendererIsEditable();
628 if (startEditable != currentEditable) {
629 if (rule == CannotCrossEditingBoundary)
631 boundaryCrossed = true;
633 lastNode = currentNode;
636 // If we've moved to a position that is visually distinct, return the last saved position. There
637 // is code below that terminates early if we're *about* to move to a visually distinct position.
638 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
641 // skip position in unrendered or invisible node
642 RenderObject* renderer = currentNode->renderer();
643 if (!renderer || renderer->style()->visibility() != VISIBLE)
646 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
647 lastVisible = currentPos;
651 // track last visible streamer position
652 if (isStreamer(currentPos))
653 lastVisible = currentPos;
655 // Don't move past a position that is visually distinct. We could rely on code above to terminate and
656 // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
657 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
660 // Return position after tables and nodes which have content that can be ignored.
661 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
662 if (currentPos.atEndOfNode())
663 return positionAfterNode(currentNode);
667 // return current position if it is in rendered text
668 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
669 if (currentNode != startNode) {
670 // This assertion fires in layout tests in the case-transform.html test because
671 // of a mix-up between offsets in the text in the DOM tree with text in the
672 // render tree which can have a different length due to case transformation.
673 // Until we resolve that, disable this so we can run the layout tests!
674 //ASSERT(currentOffset >= renderer->caretMaxOffset());
675 return createLegacyEditingPosition(currentNode, renderer->caretMaxOffset());
678 unsigned textOffset = currentPos.offsetInLeafNode();
679 RenderText* textRenderer = toRenderText(renderer);
680 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
681 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
682 if (textOffset <= box->start() + box->len()) {
683 if (textOffset > box->start())
688 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
691 // The text continues on the next line only if the last text box is not on this line and
692 // none of the boxes on this line have a larger start offset.
694 bool continuesOnNextLine = true;
695 InlineBox* otherBox = box;
696 while (continuesOnNextLine) {
697 otherBox = otherBox->nextLeafChild();
700 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
701 continuesOnNextLine = false;
705 while (continuesOnNextLine) {
706 otherBox = otherBox->prevLeafChild();
709 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
710 continuesOnNextLine = false;
713 if (continuesOnNextLine)
722 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
723 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
724 // that map to the VisiblePosition between 'b' and the space. This function will return the right candidate
725 // and upstream() will return the left one.
726 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
727 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
728 // FIXME: This function should never be called when the line box tree is dirty. See https://bugs.webkit.org/show_bug.cgi?id=97264
729 Position Position::downstream(EditingBoundaryCrossingRule rule) const
731 Node* startNode = deprecatedNode();
735 // iterate forward from there, looking for a qualified position
736 Node* boundary = enclosingVisualBoundary(startNode);
737 // FIXME: PositionIterator should respect Before and After positions.
738 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
739 PositionIterator currentPos = lastVisible;
740 bool startEditable = startNode->rendererIsEditable();
741 Node* lastNode = startNode;
742 bool boundaryCrossed = false;
743 for (; !currentPos.atEnd(); currentPos.increment()) {
744 Node* currentNode = currentPos.node();
746 // Don't check for an editability change if we haven't moved to a different node,
747 // to avoid the expense of computing rendererIsEditable().
748 if (currentNode != lastNode) {
749 // Don't change editability.
750 bool currentEditable = currentNode->rendererIsEditable();
751 if (startEditable != currentEditable) {
752 if (rule == CannotCrossEditingBoundary)
754 boundaryCrossed = true;
757 lastNode = currentNode;
760 // stop before going above the body, up into the head
761 // return the last visible streamer position
762 if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode())
765 // Do not move to a visually distinct position.
766 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
768 // Do not move past a visually disinct position.
769 // Note: The first position after the last in a node whose ends are visually distinct
770 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
771 if (boundary && boundary->parentNode() == currentNode)
774 // skip position in unrendered or invisible node
775 RenderObject* renderer = currentNode->renderer();
776 if (!renderer || renderer->style()->visibility() != VISIBLE)
779 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
780 lastVisible = currentPos;
784 // track last visible streamer position
785 if (isStreamer(currentPos))
786 lastVisible = currentPos;
788 // Return position before tables and nodes which have content that can be ignored.
789 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
790 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
791 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
795 // return current position if it is in rendered text
796 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
797 if (currentNode != startNode) {
798 ASSERT(currentPos.atStartOfNode());
799 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
802 unsigned textOffset = currentPos.offsetInLeafNode();
803 RenderText* textRenderer = toRenderText(renderer);
804 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
805 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
806 if (textOffset <= box->end()) {
807 if (textOffset >= box->start())
812 if (box == lastTextBox || textOffset != box->start() + box->len())
815 // The text continues on the next line only if the last text box is not on this line and
816 // none of the boxes on this line have a larger start offset.
818 bool continuesOnNextLine = true;
819 InlineBox* otherBox = box;
820 while (continuesOnNextLine) {
821 otherBox = otherBox->nextLeafChild();
824 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
825 continuesOnNextLine = false;
829 while (continuesOnNextLine) {
830 otherBox = otherBox->prevLeafChild();
833 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
834 continuesOnNextLine = false;
837 if (continuesOnNextLine)
846 static int boundingBoxLogicalHeight(RenderObject *o, const IntRect &rect)
848 return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width();
851 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
853 RenderObject* stop = renderer->nextInPreOrderAfterChildren();
854 for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
855 if (o->nonPseudoNode()) {
856 if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->linesBoundingBox()))
857 || (o->isBox() && toRenderBox(o)->pixelSnappedLogicalHeight())
858 || (o->isRenderInline() && isEmptyInline(o) && boundingBoxLogicalHeight(o, toRenderInline(o)->linesBoundingBox())))
864 bool Position::nodeIsUserSelectNone(Node* node)
866 return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE;
869 ContainerNode* Position::findParent(const Node* node)
871 // FIXME: See http://web.ug/82697
873 #if ENABLE(SHADOW_DOM)
874 if (RuntimeEnabledFeatures::shadowDOMEnabled())
875 return node->parentNode();
878 return node->nonShadowBoundaryParentNode();
881 #if ENABLE(USERSELECT_ALL)
882 bool Position::nodeIsUserSelectAll(const Node* node)
884 return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_ALL;
887 Node* Position::rootUserSelectAllForNode(Node* node)
889 if (!node || !nodeIsUserSelectAll(node))
891 Node* parent = node->parentNode();
895 Node* candidateRoot = node;
897 if (!parent->renderer()) {
898 parent = parent->parentNode();
901 if (!nodeIsUserSelectAll(parent))
903 candidateRoot = parent;
904 parent = candidateRoot->parentNode();
906 return candidateRoot;
910 bool Position::isCandidate() const
915 RenderObject* renderer = deprecatedNode()->renderer();
919 if (renderer->style()->visibility() != VISIBLE)
922 if (renderer->isBR())
923 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
924 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
926 if (renderer->isText())
927 return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
929 if (isTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode()))
930 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
932 if (m_anchorNode->hasTagName(htmlTag))
935 if (renderer->isBlockFlow()) {
936 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName(bodyTag)) {
937 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
938 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
939 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
942 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
947 bool Position::inRenderedText() const
949 if (isNull() || !deprecatedNode()->isTextNode())
952 RenderObject* renderer = deprecatedNode()->renderer();
956 RenderText *textRenderer = toRenderText(renderer);
957 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
958 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
959 // The offset we're looking for is before this node
960 // this means the offset must be in content that is
961 // not rendered. Return false.
964 if (box->containsCaretOffset(m_offset))
965 // Return false for offsets inside composed characters.
966 return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
972 bool Position::isRenderedCharacter() const
974 if (isNull() || !deprecatedNode()->isTextNode())
977 RenderObject* renderer = deprecatedNode()->renderer();
981 RenderText* textRenderer = toRenderText(renderer);
982 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
983 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
984 // The offset we're looking for is before this node
985 // this means the offset must be in content that is
986 // not rendered. Return false.
989 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
996 static bool inSameEnclosingBlockFlowElement(Node* a, Node* b)
998 return a && b && deprecatedEnclosingBlockFlowElement(a) == deprecatedEnclosingBlockFlowElement(b);
1001 bool Position::rendersInDifferentPosition(const Position &pos) const
1003 if (isNull() || pos.isNull())
1006 RenderObject* renderer = deprecatedNode()->renderer();
1010 RenderObject* posRenderer = pos.deprecatedNode()->renderer();
1014 if (renderer->style()->visibility() != VISIBLE ||
1015 posRenderer->style()->visibility() != VISIBLE)
1018 if (deprecatedNode() == pos.deprecatedNode()) {
1019 if (deprecatedNode()->hasTagName(brTag))
1022 if (m_offset == pos.deprecatedEditingOffset())
1025 if (!deprecatedNode()->isTextNode() && !pos.deprecatedNode()->isTextNode()) {
1026 if (m_offset != pos.deprecatedEditingOffset())
1031 if (deprecatedNode()->hasTagName(brTag) && pos.isCandidate())
1034 if (pos.deprecatedNode()->hasTagName(brTag) && isCandidate())
1037 if (!inSameEnclosingBlockFlowElement(deprecatedNode(), pos.deprecatedNode()))
1040 if (deprecatedNode()->isTextNode() && !inRenderedText())
1043 if (pos.deprecatedNode()->isTextNode() && !pos.inRenderedText())
1046 int thisRenderedOffset = renderedOffset();
1047 int posRenderedOffset = pos.renderedOffset();
1049 if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
1052 int ignoredCaretOffset;
1054 getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
1056 pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
1058 LOG(Editing, "renderer: %p [%p]\n", renderer, b1);
1059 LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
1060 LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, b2);
1061 LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset);
1062 LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(deprecatedNode()), caretMaxOffset(deprecatedNode()));
1063 LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.deprecatedNode()), caretMaxOffset(pos.deprecatedNode()));
1064 LOG(Editing, "----------------------------------------------------------------------\n");
1070 if (b1->root() != b2->root()) {
1074 if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1075 && thisRenderedOffset == caretMaxOffset(deprecatedNode()) && !posRenderedOffset) {
1079 if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1080 && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.deprecatedNode())) {
1087 // This assumes that it starts in editable content.
1088 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
1090 ASSERT(isEditablePosition(*this));
1094 if (upstream().deprecatedNode()->hasTagName(brTag))
1097 Position prev = previousCharacterPosition(affinity);
1098 if (prev != *this && inSameEnclosingBlockFlowElement(deprecatedNode(), prev.deprecatedNode()) && prev.deprecatedNode()->isTextNode()) {
1099 String string = toText(prev.deprecatedNode())->data();
1100 UChar c = string[prev.deprecatedEditingOffset()];
1101 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1102 if (isEditablePosition(prev))
1109 // This assumes that it starts in editable content.
1110 Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
1112 ASSERT(isEditablePosition(*this));
1116 VisiblePosition v(*this);
1117 UChar c = v.characterAfter();
1118 // The space must not be in another paragraph and it must be editable.
1119 if (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
1120 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1126 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
1128 getInlineBoxAndOffset(affinity, primaryDirection(), inlineBox, caretOffset);
1131 static bool isNonTextLeafChild(RenderObject* object)
1133 if (object->firstChild())
1135 if (object->isText())
1140 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
1142 RenderBlock* container = renderer->containingBlock();
1143 RenderObject* next = renderer;
1144 while ((next = next->nextInPreOrder(container))) {
1145 if (next->isRenderBlock())
1149 if (isNonTextLeafChild(next))
1151 if (next->isText()) {
1152 InlineTextBox* match = 0;
1153 int minOffset = INT_MAX;
1154 for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
1155 int caretMinOffset = box->caretMinOffset();
1156 if (caretMinOffset < minOffset) {
1158 minOffset = caretMinOffset;
1168 static Position downstreamIgnoringEditingBoundaries(Position position)
1170 Position lastPosition;
1171 while (position != lastPosition) {
1172 lastPosition = position;
1173 position = position.downstream(CanCrossEditingBoundary);
1178 static Position upstreamIgnoringEditingBoundaries(Position position)
1180 Position lastPosition;
1181 while (position != lastPosition) {
1182 lastPosition = position;
1183 position = position.upstream(CanCrossEditingBoundary);
1188 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
1190 caretOffset = deprecatedEditingOffset();
1191 RenderObject* renderer = deprecatedNode()->renderer();
1193 if (!renderer->isText()) {
1195 if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
1196 // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in
1197 // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning
1198 // of RenderObject::createVisiblePosition().
1199 Position equivalent = downstreamIgnoringEditingBoundaries(*this);
1200 if (equivalent == *this) {
1201 equivalent = upstreamIgnoringEditingBoundaries(*this);
1202 if (equivalent == *this || downstreamIgnoringEditingBoundaries(equivalent) == *this)
1206 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1209 if (renderer->isBox()) {
1210 inlineBox = toRenderBox(renderer)->inlineBoxWrapper();
1211 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1215 RenderText* textRenderer = toRenderText(renderer);
1218 InlineTextBox* candidate = 0;
1220 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
1221 int caretMinOffset = box->caretMinOffset();
1222 int caretMaxOffset = box->caretMaxOffset();
1224 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1227 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1232 if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
1233 || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
1234 || (caretOffset == caretMaxOffset && box->nextLeafChild() && box->nextLeafChild()->isLineBreak()))
1239 if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
1240 box = searchAheadForBetterMatch(textRenderer);
1242 caretOffset = box->caretMinOffset();
1244 inlineBox = box ? box : candidate;
1250 unsigned char level = inlineBox->bidiLevel();
1252 if (inlineBox->direction() == primaryDirection) {
1253 if (caretOffset == inlineBox->caretRightmostOffset()) {
1254 InlineBox* nextBox = inlineBox->nextLeafChild();
1255 if (!nextBox || nextBox->bidiLevel() >= level)
1258 level = nextBox->bidiLevel();
1259 InlineBox* prevBox = inlineBox;
1261 prevBox = prevBox->prevLeafChild();
1262 } while (prevBox && prevBox->bidiLevel() > level);
1264 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
1267 // For example, abc 123 ^ CBA
1268 while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1269 if (nextBox->bidiLevel() < level)
1271 inlineBox = nextBox;
1273 caretOffset = inlineBox->caretRightmostOffset();
1275 InlineBox* prevBox = inlineBox->prevLeafChild();
1276 if (!prevBox || prevBox->bidiLevel() >= level)
1279 level = prevBox->bidiLevel();
1280 InlineBox* nextBox = inlineBox;
1282 nextBox = nextBox->nextLeafChild();
1283 } while (nextBox && nextBox->bidiLevel() > level);
1285 if (nextBox && nextBox->bidiLevel() == level)
1288 while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1289 if (prevBox->bidiLevel() < level)
1291 inlineBox = prevBox;
1293 caretOffset = inlineBox->caretLeftmostOffset();
1298 if (caretOffset == inlineBox->caretLeftmostOffset()) {
1299 InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak();
1300 if (!prevBox || prevBox->bidiLevel() < level) {
1301 // Left edge of a secondary run. Set to the right edge of the entire run.
1302 while (InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1303 if (nextBox->bidiLevel() < level)
1305 inlineBox = nextBox;
1307 caretOffset = inlineBox->caretRightmostOffset();
1308 } else if (prevBox->bidiLevel() > level) {
1309 // Right edge of a "tertiary" run. Set to the left edge of that run.
1310 while (InlineBox* tertiaryBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1311 if (tertiaryBox->bidiLevel() <= level)
1313 inlineBox = tertiaryBox;
1315 caretOffset = inlineBox->caretLeftmostOffset();
1318 InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak();
1319 if (!nextBox || nextBox->bidiLevel() < level) {
1320 // Right edge of a secondary run. Set to the left edge of the entire run.
1321 while (InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1322 if (prevBox->bidiLevel() < level)
1324 inlineBox = prevBox;
1326 caretOffset = inlineBox->caretLeftmostOffset();
1327 } else if (nextBox->bidiLevel() > level) {
1328 // Left edge of a "tertiary" run. Set to the right edge of that run.
1329 while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1330 if (tertiaryBox->bidiLevel() <= level)
1332 inlineBox = tertiaryBox;
1334 caretOffset = inlineBox->caretRightmostOffset();
1339 TextDirection Position::primaryDirection() const
1341 TextDirection primaryDirection = LTR;
1342 for (const RenderObject* r = m_anchorNode->renderer(); r; r = r->parent()) {
1343 if (r->isBlockFlow()) {
1344 primaryDirection = r->style()->direction();
1349 return primaryDirection;
1353 void Position::debugPosition(const char* msg) const
1356 fprintf(stderr, "Position [%s]: null\n", msg);
1358 fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, deprecatedNode()->nodeName().utf8().data(), deprecatedNode(), m_offset);
1363 void Position::formatForDebugger(char* buffer, unsigned length) const
1365 StringBuilder result;
1368 result.appendLiteral("<null>");
1371 result.appendLiteral("offset ");
1372 result.appendNumber(m_offset);
1373 result.appendLiteral(" of ");
1374 deprecatedNode()->formatForDebugger(s, sizeof(s));
1378 strncpy(buffer, result.toString().utf8().data(), length - 1);
1381 void Position::showAnchorTypeAndOffset() const
1383 if (m_isLegacyEditingPosition)
1384 fputs("legacy, ", stderr);
1385 switch (anchorType()) {
1386 case PositionIsOffsetInAnchor:
1387 fputs("offset", stderr);
1389 case PositionIsBeforeChildren:
1390 fputs("beforeChildren", stderr);
1392 case PositionIsAfterChildren:
1393 fputs("afterChildren", stderr);
1395 case PositionIsBeforeAnchor:
1396 fputs("before", stderr);
1398 case PositionIsAfterAnchor:
1399 fputs("after", stderr);
1402 fprintf(stderr, ", offset:%d\n", m_offset);
1405 void Position::showTreeForThis() const
1408 anchorNode()->showTreeForThis();
1409 showAnchorTypeAndOffset();
1417 } // namespace WebCore
1421 void showTree(const WebCore::Position& pos)
1423 pos.showTreeForThis();
1426 void showTree(const WebCore::Position* pos)
1429 pos->showTreeForThis();