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 "InlineTextBox.h"
33 #include "PositionIterator.h"
34 #include "RenderBlock.h"
35 #include "RenderText.h"
37 #include "TextIterator.h"
38 #include "VisiblePosition.h"
39 #include "htmlediting.h"
40 #include "visible_units.h"
42 #include <wtf/text/CString.h>
43 #include <wtf/unicode/CharacterNames.h>
47 using namespace HTMLNames;
49 static Node* nextRenderedEditable(Node* node)
51 while ((node = node->nextLeafNode())) {
52 if (!node->rendererIsEditable())
54 RenderObject* renderer = node->renderer();
57 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
63 static Node* previousRenderedEditable(Node* node)
65 while ((node = node->previousLeafNode())) {
66 if (!node->rendererIsEditable())
68 RenderObject* renderer = node->renderer();
71 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
77 Position::Position(PassRefPtr<Node> anchorNode, LegacyEditingOffset offset)
78 : m_anchorNode(anchorNode)
79 , m_offset(offset.value())
80 , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
81 , m_isLegacyEditingPosition(true)
83 ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot());
86 Position::Position(PassRefPtr<Node> anchorNode, AnchorType anchorType)
87 : m_anchorNode(anchorNode)
89 , m_anchorType(anchorType)
90 , m_isLegacyEditingPosition(false)
92 ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot());
93 ASSERT(anchorType != PositionIsOffsetInAnchor);
94 ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren)
95 && (m_anchorNode->isTextNode() || editingIgnoresContent(m_anchorNode.get()))));
98 Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
99 : m_anchorNode(anchorNode)
101 , m_anchorType(anchorType)
102 , m_isLegacyEditingPosition(false)
104 ASSERT(!m_anchorNode || !editingIgnoresContent(m_anchorNode.get()) || !m_anchorNode->isShadowRoot());
105 ASSERT(anchorType == PositionIsOffsetInAnchor);
108 Position::Position(PassRefPtr<Text> textNode, unsigned offset)
109 : m_anchorNode(textNode)
110 , m_offset(static_cast<int>(offset))
111 , m_anchorType(PositionIsOffsetInAnchor)
112 , m_isLegacyEditingPosition(false)
114 ASSERT(m_anchorNode);
117 void Position::moveToPosition(PassRefPtr<Node> node, int offset)
119 ASSERT(!editingIgnoresContent(node.get()));
120 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
123 if (m_isLegacyEditingPosition)
124 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
126 void Position::moveToOffset(int offset)
128 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
130 if (m_isLegacyEditingPosition)
131 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
134 Node* Position::containerNode() const
139 switch (anchorType()) {
140 case PositionIsBeforeChildren:
141 case PositionIsAfterChildren:
142 case PositionIsOffsetInAnchor:
143 return m_anchorNode.get();
144 case PositionIsBeforeAnchor:
145 case PositionIsAfterAnchor:
146 return m_anchorNode->nonShadowBoundaryParentNode();
148 ASSERT_NOT_REACHED();
152 Text* Position::containerText() const
154 switch (anchorType()) {
155 case PositionIsOffsetInAnchor:
156 return m_anchorNode && m_anchorNode->isTextNode() ? static_cast<Text*>(m_anchorNode.get()) : 0;
157 case PositionIsBeforeAnchor:
158 case PositionIsAfterAnchor:
160 case PositionIsBeforeChildren:
161 case PositionIsAfterChildren:
162 ASSERT(!m_anchorNode || !m_anchorNode->isTextNode());
165 ASSERT_NOT_REACHED();
169 int Position::computeOffsetInContainerNode() const
174 switch (anchorType()) {
175 case PositionIsBeforeChildren:
177 case PositionIsAfterChildren:
178 return lastOffsetInNode(m_anchorNode.get());
179 case PositionIsOffsetInAnchor:
180 return std::min(lastOffsetInNode(m_anchorNode.get()), m_offset);
181 case PositionIsBeforeAnchor:
182 return m_anchorNode->nodeIndex();
183 case PositionIsAfterAnchor:
184 return m_anchorNode->nodeIndex() + 1;
186 ASSERT_NOT_REACHED();
190 int Position::offsetForPositionAfterAnchor() const
192 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren);
193 ASSERT(!m_isLegacyEditingPosition);
194 return lastOffsetForEditing(m_anchorNode.get());
197 // Neighbor-anchored positions are invalid DOM positions, so they need to be
198 // fixed up before handing them off to the Range object.
199 Position Position::parentAnchoredEquivalent() const
204 // FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
205 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType != PositionIsAfterChildren)) {
206 if (m_anchorNode->nonShadowBoundaryParentNode() && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get())))
207 return positionInParentBeforeNode(m_anchorNode.get());
208 return Position(m_anchorNode.get(), 0, PositionIsOffsetInAnchor);
210 if (!m_anchorNode->offsetInCharacters()
211 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount())
212 && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get()))
213 && containerNode()) {
214 return positionInParentAfterNode(m_anchorNode.get());
217 return Position(containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor);
220 Node* Position::computeNodeBeforePosition() const
225 switch (anchorType()) {
226 case PositionIsBeforeChildren:
228 case PositionIsAfterChildren:
229 return m_anchorNode->lastChild();
230 case PositionIsOffsetInAnchor:
231 return m_anchorNode->childNode(m_offset - 1); // -1 converts to childNode((unsigned)-1) and returns null.
232 case PositionIsBeforeAnchor:
233 return m_anchorNode->previousSibling();
234 case PositionIsAfterAnchor:
235 return m_anchorNode.get();
237 ASSERT_NOT_REACHED();
241 Node* Position::computeNodeAfterPosition() const
246 switch (anchorType()) {
247 case PositionIsBeforeChildren:
248 return m_anchorNode->firstChild();
249 case PositionIsAfterChildren:
251 case PositionIsOffsetInAnchor:
252 return m_anchorNode->childNode(m_offset);
253 case PositionIsBeforeAnchor:
254 return m_anchorNode.get();
255 case PositionIsAfterAnchor:
256 return m_anchorNode->nextSibling();
258 ASSERT_NOT_REACHED();
262 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
264 if (anchorNode && editingIgnoresContent(anchorNode)) {
266 return Position::PositionIsBeforeAnchor;
267 return Position::PositionIsAfterAnchor;
269 return Position::PositionIsOffsetInAnchor;
272 // FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
273 Element* Position::element() const
275 Node* n = anchorNode();
276 while (n && !n->isElementNode())
278 return static_cast<Element*>(n);
281 PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
283 Element* elem = element();
286 return WebCore::computedStyle(elem);
289 Position Position::previous(PositionMoveType moveType) const
291 Node* n = deprecatedNode();
295 int o = deprecatedEditingOffset();
296 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
300 Node* child = n->childNode(o - 1);
302 return lastPositionInOrAfterNode(child);
304 // There are two reasons child might be 0:
305 // 1) The node is node like a text node that is not an element, and therefore has no children.
306 // Going backward one character at a time is correct.
307 // 2) The old offset was a bogus offset like (<br>, 1), and there is no child.
308 // Going from 1 to 0 is correct.
311 return createLegacyEditingPosition(n, o - 1);
313 return createLegacyEditingPosition(n, uncheckedPreviousOffset(n, o));
314 case BackwardDeletion:
315 return createLegacyEditingPosition(n, uncheckedPreviousOffsetForBackwardDeletion(n, o));
319 ContainerNode* parent = n->nonShadowBoundaryParentNode();
323 return createLegacyEditingPosition(parent, n->nodeIndex());
326 Position Position::next(PositionMoveType moveType) const
328 ASSERT(moveType != BackwardDeletion);
330 Node* n = deprecatedNode();
334 int o = deprecatedEditingOffset();
335 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
338 Node* child = n->childNode(o);
339 if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n))) {
341 return firstPositionInOrBeforeNode(child);
343 // There are two reasons child might be 0:
344 // 1) The node is node like a text node that is not an element, and therefore has no children.
345 // Going forward one character at a time is correct.
346 // 2) The new offset is a bogus offset like (<br>, 1), and there is no child.
347 // Going from 0 to 1 is correct.
348 return createLegacyEditingPosition(n, (moveType == Character) ? uncheckedNextOffset(n, o) : o + 1);
351 ContainerNode* parent = n->nonShadowBoundaryParentNode();
355 return createLegacyEditingPosition(parent, n->nodeIndex() + 1);
358 int Position::uncheckedPreviousOffset(const Node* n, int current)
360 return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
363 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
365 return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
368 int Position::uncheckedNextOffset(const Node* n, int current)
370 return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
373 bool Position::atFirstEditingPositionForNode() const
377 // FIXME: Position before anchor shouldn't be considered as at the first editing position for node
378 // since that position resides outside of the node.
379 switch (m_anchorType) {
380 case PositionIsOffsetInAnchor:
381 return m_offset <= 0;
382 case PositionIsBeforeChildren:
383 case PositionIsBeforeAnchor:
385 case PositionIsAfterChildren:
386 case PositionIsAfterAnchor:
387 return !lastOffsetForEditing(deprecatedNode());
389 ASSERT_NOT_REACHED();
393 bool Position::atLastEditingPositionForNode() const
397 // FIXME: Position after anchor shouldn't be considered as at the first editing position for node
398 // since that position resides outside of the node.
399 return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || m_offset >= lastOffsetForEditing(deprecatedNode());
402 // A position is considered at editing boundary if one of the following is true:
403 // 1. It is the first position in the node and the next visually equivalent position
405 // 2. It is the last position in the node and the previous visually equivalent position
407 // 3. It is an editable position and both the next and previous visually equivalent
408 // positions are both non editable.
409 bool Position::atEditingBoundary() const
411 Position nextPosition = downstream(CanCrossEditingBoundary);
412 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable())
415 Position prevPosition = upstream(CanCrossEditingBoundary);
416 if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable())
419 return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable()
420 && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable();
423 Node* Position::parentEditingBoundary() const
425 if (!m_anchorNode || !m_anchorNode->document())
428 Node* documentElement = m_anchorNode->document()->documentElement();
429 if (!documentElement)
432 Node* boundary = m_anchorNode.get();
433 while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && m_anchorNode->rendererIsEditable() == boundary->parentNode()->rendererIsEditable())
434 boundary = boundary->nonShadowBoundaryParentNode();
440 bool Position::atStartOfTree() const
444 return !deprecatedNode()->nonShadowBoundaryParentNode() && m_offset <= 0;
447 bool Position::atEndOfTree() const
451 return !deprecatedNode()->nonShadowBoundaryParentNode() && m_offset >= lastOffsetForEditing(deprecatedNode());
454 int Position::renderedOffset() const
456 if (!deprecatedNode()->isTextNode())
459 if (!deprecatedNode()->renderer())
463 RenderText* textRenderer = toRenderText(deprecatedNode()->renderer());
464 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
465 int start = box->start();
466 int end = box->start() + box->len();
467 if (m_offset < start)
469 if (m_offset <= end) {
470 result += m_offset - start;
473 result += box->len();
478 // return first preceding DOM position rendered at a different location, or "this"
479 Position Position::previousCharacterPosition(EAffinity affinity) const
484 Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
486 bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
487 bool rendered = isCandidate();
489 Position currentPos = *this;
490 while (!currentPos.atStartOfTree()) {
491 currentPos = currentPos.previous();
493 if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
496 if (atStartOfLine || !rendered) {
497 if (currentPos.isCandidate())
499 } else if (rendersInDifferentPosition(currentPos))
506 // return first following position rendered at a different location, or "this"
507 Position Position::nextCharacterPosition(EAffinity affinity) const
512 Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
514 bool atEndOfLine = isEndOfLine(VisiblePosition(*this, affinity));
515 bool rendered = isCandidate();
517 Position currentPos = *this;
518 while (!currentPos.atEndOfTree()) {
519 currentPos = currentPos.next();
521 if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
524 if (atEndOfLine || !rendered) {
525 if (currentPos.isCandidate())
527 } else if (rendersInDifferentPosition(currentPos))
534 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
535 // If true, adjacent candidates are visually distinct.
536 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
537 // FIXME: Share code with isCandidate, if possible.
538 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
540 if (!node || !node->renderer())
543 if (!node->renderer()->isInline())
546 // Don't include inline tables.
547 if (node->hasTagName(tableTag))
550 // There is a VisiblePosition inside an empty inline-block container.
551 return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild();
554 static Node* enclosingVisualBoundary(Node* node)
556 while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
557 node = node->parentNode();
562 // upstream() and downstream() want to return positions that are either in a
563 // text node or at just before a non-text node. This method checks for that.
564 static bool isStreamer(const PositionIterator& pos)
569 if (isAtomicNode(pos.node()))
572 return pos.atStartOfNode();
575 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
576 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
577 // that map to the VisiblePosition between 'b' and the space. This function will return the left candidate
578 // and downstream() will return the right one.
579 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
580 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
581 Position Position::upstream(EditingBoundaryCrossingRule rule) const
583 Node* startNode = deprecatedNode();
587 // iterate backward from there, looking for a qualified position
588 Node* boundary = enclosingVisualBoundary(startNode);
589 // FIXME: PositionIterator should respect Before and After positions.
590 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
591 PositionIterator currentPos = lastVisible;
592 bool startEditable = startNode->rendererIsEditable();
593 Node* lastNode = startNode;
594 bool boundaryCrossed = false;
595 for (; !currentPos.atStart(); currentPos.decrement()) {
596 Node* currentNode = currentPos.node();
598 // Don't check for an editability change if we haven't moved to a different node,
599 // to avoid the expense of computing rendererIsEditable().
600 if (currentNode != lastNode) {
601 // Don't change editability.
602 bool currentEditable = currentNode->rendererIsEditable();
603 if (startEditable != currentEditable) {
604 if (rule == CannotCrossEditingBoundary)
606 boundaryCrossed = true;
608 lastNode = currentNode;
611 // If we've moved to a position that is visually distinct, return the last saved position. There
612 // is code below that terminates early if we're *about* to move to a visually distinct position.
613 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
616 // skip position in unrendered or invisible node
617 RenderObject* renderer = currentNode->renderer();
618 if (!renderer || renderer->style()->visibility() != VISIBLE)
621 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
622 lastVisible = currentPos;
626 // track last visible streamer position
627 if (isStreamer(currentPos))
628 lastVisible = currentPos;
630 // Don't move past a position that is visually distinct. We could rely on code above to terminate and
631 // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
632 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
635 // Return position after tables and nodes which have content that can be ignored.
636 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
637 if (currentPos.atEndOfNode())
638 return positionAfterNode(currentNode);
642 // return current position if it is in rendered text
643 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
644 if (currentNode != startNode) {
645 // This assertion fires in layout tests in the case-transform.html test because
646 // of a mix-up between offsets in the text in the DOM tree with text in the
647 // render tree which can have a different length due to case transformation.
648 // Until we resolve that, disable this so we can run the layout tests!
649 //ASSERT(currentOffset >= renderer->caretMaxOffset());
650 return createLegacyEditingPosition(currentNode, renderer->caretMaxOffset());
653 unsigned textOffset = currentPos.offsetInLeafNode();
654 RenderText* textRenderer = toRenderText(renderer);
655 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
656 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
657 if (textOffset <= box->start() + box->len()) {
658 if (textOffset > box->start())
663 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
666 // The text continues on the next line only if the last text box is not on this line and
667 // none of the boxes on this line have a larger start offset.
669 bool continuesOnNextLine = true;
670 InlineBox* otherBox = box;
671 while (continuesOnNextLine) {
672 otherBox = otherBox->nextLeafChild();
675 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
676 continuesOnNextLine = false;
680 while (continuesOnNextLine) {
681 otherBox = otherBox->prevLeafChild();
684 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
685 continuesOnNextLine = false;
688 if (continuesOnNextLine)
697 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
698 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
699 // that map to the VisiblePosition between 'b' and the space. This function will return the right candidate
700 // and upstream() will return the left one.
701 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
702 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
703 Position Position::downstream(EditingBoundaryCrossingRule rule) const
705 Node* startNode = deprecatedNode();
709 // iterate forward from there, looking for a qualified position
710 Node* boundary = enclosingVisualBoundary(startNode);
711 // FIXME: PositionIterator should respect Before and After positions.
712 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
713 PositionIterator currentPos = lastVisible;
714 bool startEditable = startNode->rendererIsEditable();
715 Node* lastNode = startNode;
716 bool boundaryCrossed = false;
717 for (; !currentPos.atEnd(); currentPos.increment()) {
718 Node* currentNode = currentPos.node();
720 // Don't check for an editability change if we haven't moved to a different node,
721 // to avoid the expense of computing rendererIsEditable().
722 if (currentNode != lastNode) {
723 // Don't change editability.
724 bool currentEditable = currentNode->rendererIsEditable();
725 if (startEditable != currentEditable) {
726 if (rule == CannotCrossEditingBoundary)
728 boundaryCrossed = true;
731 lastNode = currentNode;
734 // stop before going above the body, up into the head
735 // return the last visible streamer position
736 if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode())
739 // Do not move to a visually distinct position.
740 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
742 // Do not move past a visually disinct position.
743 // Note: The first position after the last in a node whose ends are visually distinct
744 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
745 if (boundary && boundary->parentNode() == currentNode)
748 // skip position in unrendered or invisible node
749 RenderObject* renderer = currentNode->renderer();
750 if (!renderer || renderer->style()->visibility() != VISIBLE)
753 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
754 lastVisible = currentPos;
758 // track last visible streamer position
759 if (isStreamer(currentPos))
760 lastVisible = currentPos;
762 // Return position before tables and nodes which have content that can be ignored.
763 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
764 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
765 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
769 // return current position if it is in rendered text
770 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
771 if (currentNode != startNode) {
772 ASSERT(currentPos.atStartOfNode());
773 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
776 unsigned textOffset = currentPos.offsetInLeafNode();
777 RenderText* textRenderer = toRenderText(renderer);
778 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
779 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
780 if (textOffset <= box->end()) {
781 if (textOffset >= box->start())
786 if (box == lastTextBox || textOffset != box->start() + box->len())
789 // The text continues on the next line only if the last text box is not on this line and
790 // none of the boxes on this line have a larger start offset.
792 bool continuesOnNextLine = true;
793 InlineBox* otherBox = box;
794 while (continuesOnNextLine) {
795 otherBox = otherBox->nextLeafChild();
798 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
799 continuesOnNextLine = false;
803 while (continuesOnNextLine) {
804 otherBox = otherBox->prevLeafChild();
807 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
808 continuesOnNextLine = false;
811 if (continuesOnNextLine)
820 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
822 RenderObject* stop = renderer->nextInPreOrderAfterChildren();
823 for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
825 if ((o->isText() && toRenderText(o)->linesBoundingBox().height()) ||
826 (o->isBox() && toRenderBox(o)->borderBoundingBox().height()))
832 bool Position::nodeIsUserSelectNone(Node* node)
834 return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE;
837 bool Position::isCandidate() const
842 RenderObject* renderer = deprecatedNode()->renderer();
846 if (renderer->style()->visibility() != VISIBLE)
849 if (renderer->isBR())
850 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
851 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
853 if (renderer->isText())
854 return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
856 if (isTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode()))
857 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
859 if (m_anchorNode->hasTagName(htmlTag))
862 if (renderer->isBlockFlow()) {
863 if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
864 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
865 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
866 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
869 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
874 bool Position::inRenderedText() const
876 if (isNull() || !deprecatedNode()->isTextNode())
879 RenderObject* renderer = deprecatedNode()->renderer();
883 RenderText *textRenderer = toRenderText(renderer);
884 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
885 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
886 // The offset we're looking for is before this node
887 // this means the offset must be in content that is
888 // not rendered. Return false.
891 if (box->containsCaretOffset(m_offset))
892 // Return false for offsets inside composed characters.
893 return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
899 static unsigned caretMaxRenderedOffset(const Node* n)
901 RenderObject* r = n->renderer();
903 return r->caretMaxRenderedOffset();
905 if (n->isCharacterDataNode())
906 return static_cast<const CharacterData*>(n)->length();
910 bool Position::isRenderedCharacter() const
912 if (isNull() || !deprecatedNode()->isTextNode())
915 RenderObject* renderer = deprecatedNode()->renderer();
919 RenderText* textRenderer = toRenderText(renderer);
920 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
921 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
922 // The offset we're looking for is before this node
923 // this means the offset must be in content that is
924 // not rendered. Return false.
927 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
934 bool Position::rendersInDifferentPosition(const Position &pos) const
936 if (isNull() || pos.isNull())
939 RenderObject* renderer = deprecatedNode()->renderer();
943 RenderObject* posRenderer = pos.deprecatedNode()->renderer();
947 if (renderer->style()->visibility() != VISIBLE ||
948 posRenderer->style()->visibility() != VISIBLE)
951 if (deprecatedNode() == pos.deprecatedNode()) {
952 if (deprecatedNode()->hasTagName(brTag))
955 if (m_offset == pos.deprecatedEditingOffset())
958 if (!deprecatedNode()->isTextNode() && !pos.deprecatedNode()->isTextNode()) {
959 if (m_offset != pos.deprecatedEditingOffset())
964 if (deprecatedNode()->hasTagName(brTag) && pos.isCandidate())
967 if (pos.deprecatedNode()->hasTagName(brTag) && isCandidate())
970 if (deprecatedNode()->enclosingBlockFlowElement() != pos.deprecatedNode()->enclosingBlockFlowElement())
973 if (deprecatedNode()->isTextNode() && !inRenderedText())
976 if (pos.deprecatedNode()->isTextNode() && !pos.inRenderedText())
979 int thisRenderedOffset = renderedOffset();
980 int posRenderedOffset = pos.renderedOffset();
982 if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
985 int ignoredCaretOffset;
987 getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
989 pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
991 LOG(Editing, "renderer: %p [%p]\n", renderer, b1);
992 LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
993 LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, b2);
994 LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset);
995 LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(deprecatedNode()), caretMaxRenderedOffset(deprecatedNode()));
996 LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.deprecatedNode()), caretMaxRenderedOffset(pos.deprecatedNode()));
997 LOG(Editing, "----------------------------------------------------------------------\n");
1003 if (b1->root() != b2->root()) {
1007 if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1008 && thisRenderedOffset == (int)caretMaxRenderedOffset(deprecatedNode()) && !posRenderedOffset) {
1012 if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1013 && !thisRenderedOffset && posRenderedOffset == (int)caretMaxRenderedOffset(pos.deprecatedNode())) {
1020 // This assumes that it starts in editable content.
1021 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
1023 ASSERT(isEditablePosition(*this));
1027 if (upstream().deprecatedNode()->hasTagName(brTag))
1030 Position prev = previousCharacterPosition(affinity);
1031 if (prev != *this && prev.deprecatedNode()->inSameContainingBlockFlowElement(deprecatedNode()) && prev.deprecatedNode()->isTextNode()) {
1032 String string = static_cast<Text *>(prev.deprecatedNode())->data();
1033 UChar c = string[prev.deprecatedEditingOffset()];
1034 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1035 if (isEditablePosition(prev))
1042 // This assumes that it starts in editable content.
1043 Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
1045 ASSERT(isEditablePosition(*this));
1049 VisiblePosition v(*this);
1050 UChar c = v.characterAfter();
1051 // The space must not be in another paragraph and it must be editable.
1052 if (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
1053 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1059 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
1061 getInlineBoxAndOffset(affinity, primaryDirection(), inlineBox, caretOffset);
1064 static bool isNonTextLeafChild(RenderObject* object)
1066 if (object->firstChild())
1068 if (object->isText())
1073 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
1075 RenderBlock* container = renderer->containingBlock();
1076 RenderObject* next = renderer;
1077 while ((next = next->nextInPreOrder(container))) {
1078 if (next->isRenderBlock())
1082 if (isNonTextLeafChild(next))
1084 if (next->isText()) {
1085 InlineTextBox* match = 0;
1086 int minOffset = INT_MAX;
1087 for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
1088 int caretMinOffset = box->caretMinOffset();
1089 if (caretMinOffset < minOffset) {
1091 minOffset = caretMinOffset;
1101 static Position downstreamIgnoringEditingBoundaries(Position position)
1103 Position lastPosition;
1104 while (position != lastPosition) {
1105 lastPosition = position;
1106 position = position.downstream(CanCrossEditingBoundary);
1111 static Position upstreamIgnoringEditingBoundaries(Position position)
1113 Position lastPosition;
1114 while (position != lastPosition) {
1115 lastPosition = position;
1116 position = position.upstream(CanCrossEditingBoundary);
1121 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
1123 caretOffset = deprecatedEditingOffset();
1124 RenderObject* renderer = deprecatedNode()->renderer();
1126 if (!renderer->isText()) {
1128 if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
1129 // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in
1130 // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning
1131 // of RenderObject::createVisiblePosition().
1132 Position equivalent = downstreamIgnoringEditingBoundaries(*this);
1133 if (equivalent == *this) {
1134 equivalent = upstreamIgnoringEditingBoundaries(*this);
1135 if (equivalent == *this || downstreamIgnoringEditingBoundaries(equivalent) == *this)
1139 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1142 if (renderer->isBox()) {
1143 inlineBox = toRenderBox(renderer)->inlineBoxWrapper();
1144 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1148 RenderText* textRenderer = toRenderText(renderer);
1151 InlineTextBox* candidate = 0;
1153 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
1154 int caretMinOffset = box->caretMinOffset();
1155 int caretMaxOffset = box->caretMaxOffset();
1157 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1160 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1165 if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
1166 || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM)))
1171 if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
1172 box = searchAheadForBetterMatch(textRenderer);
1174 caretOffset = box->caretMinOffset();
1176 inlineBox = box ? box : candidate;
1182 unsigned char level = inlineBox->bidiLevel();
1184 if (inlineBox->direction() == primaryDirection) {
1185 if (caretOffset == inlineBox->caretRightmostOffset()) {
1186 InlineBox* nextBox = inlineBox->nextLeafChild();
1187 if (!nextBox || nextBox->bidiLevel() >= level)
1190 level = nextBox->bidiLevel();
1191 InlineBox* prevBox = inlineBox;
1193 prevBox = prevBox->prevLeafChild();
1194 } while (prevBox && prevBox->bidiLevel() > level);
1196 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
1199 // For example, abc 123 ^ CBA
1200 while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1201 if (nextBox->bidiLevel() < level)
1203 inlineBox = nextBox;
1205 caretOffset = inlineBox->caretRightmostOffset();
1207 InlineBox* prevBox = inlineBox->prevLeafChild();
1208 if (!prevBox || prevBox->bidiLevel() >= level)
1211 level = prevBox->bidiLevel();
1212 InlineBox* nextBox = inlineBox;
1214 nextBox = nextBox->nextLeafChild();
1215 } while (nextBox && nextBox->bidiLevel() > level);
1217 if (nextBox && nextBox->bidiLevel() == level)
1220 while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1221 if (prevBox->bidiLevel() < level)
1223 inlineBox = prevBox;
1225 caretOffset = inlineBox->caretLeftmostOffset();
1230 if (caretOffset == inlineBox->caretLeftmostOffset()) {
1231 InlineBox* prevBox = inlineBox->prevLeafChild();
1232 if (!prevBox || prevBox->bidiLevel() < level) {
1233 // Left edge of a secondary run. Set to the right edge of the entire run.
1234 while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1235 if (nextBox->bidiLevel() < level)
1237 inlineBox = nextBox;
1239 caretOffset = inlineBox->caretRightmostOffset();
1240 } else if (prevBox->bidiLevel() > level) {
1241 // Right edge of a "tertiary" run. Set to the left edge of that run.
1242 while (InlineBox* tertiaryBox = inlineBox->prevLeafChild()) {
1243 if (tertiaryBox->bidiLevel() <= level)
1245 inlineBox = tertiaryBox;
1247 caretOffset = inlineBox->caretLeftmostOffset();
1250 InlineBox* nextBox = inlineBox->nextLeafChild();
1251 if (!nextBox || nextBox->bidiLevel() < level) {
1252 // Right edge of a secondary run. Set to the left edge of the entire run.
1253 while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1254 if (prevBox->bidiLevel() < level)
1256 inlineBox = prevBox;
1258 caretOffset = inlineBox->caretLeftmostOffset();
1259 } else if (nextBox->bidiLevel() > level) {
1260 // Left edge of a "tertiary" run. Set to the right edge of that run.
1261 while (InlineBox* tertiaryBox = inlineBox->nextLeafChild()) {
1262 if (tertiaryBox->bidiLevel() <= level)
1264 inlineBox = tertiaryBox;
1266 caretOffset = inlineBox->caretRightmostOffset();
1271 TextDirection Position::primaryDirection() const
1273 TextDirection primaryDirection = LTR;
1274 for (const RenderObject* r = m_anchorNode->renderer(); r; r = r->parent()) {
1275 if (r->isBlockFlow()) {
1276 primaryDirection = r->style()->direction();
1281 return primaryDirection;
1285 void Position::debugPosition(const char* msg) const
1288 fprintf(stderr, "Position [%s]: null\n", msg);
1290 fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, deprecatedNode()->nodeName().utf8().data(), deprecatedNode(), m_offset);
1295 void Position::formatForDebugger(char* buffer, unsigned length) const
1303 result += "offset ";
1304 result += String::number(m_offset);
1306 deprecatedNode()->formatForDebugger(s, sizeof(s));
1310 strncpy(buffer, result.utf8().data(), length - 1);
1313 void Position::showAnchorTypeAndOffset() const
1315 if (m_isLegacyEditingPosition)
1316 fputs("legacy, ", stderr);
1317 switch (anchorType()) {
1318 case PositionIsOffsetInAnchor:
1319 fputs("offset", stderr);
1321 case PositionIsBeforeChildren:
1322 fputs("beforeChildren", stderr);
1324 case PositionIsAfterChildren:
1325 fputs("afterChildren", stderr);
1327 case PositionIsBeforeAnchor:
1328 fputs("before", stderr);
1330 case PositionIsAfterAnchor:
1331 fputs("after", stderr);
1334 fprintf(stderr, ", offset:%d\n", m_offset);
1337 void Position::showTreeForThis() const
1340 anchorNode()->showTreeForThis();
1341 showAnchorTypeAndOffset();
1349 } // namespace WebCore
1353 void showTree(const WebCore::Position& pos)
1355 pos.showTreeForThis();
1358 void showTree(const WebCore::Position* pos)
1361 pos->showTreeForThis();