• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2009 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 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.
24  */
25 
26 #include "config.h"
27 #include "core/dom/Position.h"
28 
29 #include "core/HTMLNames.h"
30 #include "core/css/CSSComputedStyleDeclaration.h"
31 #include "core/dom/PositionIterator.h"
32 #include "core/dom/Text.h"
33 #include "core/editing/TextIterator.h"
34 #include "core/editing/VisiblePosition.h"
35 #include "core/editing/VisibleUnits.h"
36 #include "core/editing/htmlediting.h"
37 #include "core/frame/LocalFrame.h"
38 #include "core/frame/Settings.h"
39 #include "core/html/HTMLTableElement.h"
40 #include "core/rendering/InlineIterator.h"
41 #include "core/rendering/InlineTextBox.h"
42 #include "core/rendering/RenderBlock.h"
43 #include "core/rendering/RenderInline.h"
44 #include "core/rendering/RenderText.h"
45 #include "platform/Logging.h"
46 #include "wtf/text/CString.h"
47 #include "wtf/unicode/CharacterNames.h"
48 #include <stdio.h>
49 
50 namespace WebCore {
51 
52 using namespace HTMLNames;
53 
nextRenderedEditable(Node * node)54 static Node* nextRenderedEditable(Node* node)
55 {
56     while ((node = node->nextLeafNode())) {
57         RenderObject* renderer = node->renderer();
58         if (!renderer)
59             continue;
60         if (!node->rendererIsEditable())
61             continue;
62         if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
63             return node;
64     }
65     return 0;
66 }
67 
previousRenderedEditable(Node * node)68 static Node* previousRenderedEditable(Node* node)
69 {
70     while ((node = node->previousLeafNode())) {
71         RenderObject* renderer = node->renderer();
72         if (!renderer)
73             continue;
74         if (!node->rendererIsEditable())
75             continue;
76         if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
77             return node;
78     }
79     return 0;
80 }
81 
Position(PassRefPtrWillBeRawPtr<Node> anchorNode,LegacyEditingOffset offset)82 Position::Position(PassRefPtrWillBeRawPtr<Node> anchorNode, LegacyEditingOffset offset)
83     : m_anchorNode(anchorNode)
84     , m_offset(offset.value())
85     , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
86     , m_isLegacyEditingPosition(true)
87 {
88     ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
89 }
90 
Position(PassRefPtrWillBeRawPtr<Node> anchorNode,AnchorType anchorType)91 Position::Position(PassRefPtrWillBeRawPtr<Node> anchorNode, AnchorType anchorType)
92     : m_anchorNode(anchorNode)
93     , m_offset(0)
94     , m_anchorType(anchorType)
95     , m_isLegacyEditingPosition(false)
96 {
97     ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
98 
99     ASSERT(anchorType != PositionIsOffsetInAnchor);
100     ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren)
101         && (m_anchorNode->isTextNode() || editingIgnoresContent(m_anchorNode.get()))));
102 }
103 
Position(PassRefPtrWillBeRawPtr<Node> anchorNode,int offset,AnchorType anchorType)104 Position::Position(PassRefPtrWillBeRawPtr<Node> anchorNode, int offset, AnchorType anchorType)
105     : m_anchorNode(anchorNode)
106     , m_offset(offset)
107     , m_anchorType(anchorType)
108     , m_isLegacyEditingPosition(false)
109 {
110     ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
111 
112     ASSERT(anchorType == PositionIsOffsetInAnchor);
113 }
114 
Position(PassRefPtrWillBeRawPtr<Text> textNode,unsigned offset)115 Position::Position(PassRefPtrWillBeRawPtr<Text> textNode, unsigned offset)
116     : m_anchorNode(textNode)
117     , m_offset(static_cast<int>(offset))
118     , m_anchorType(PositionIsOffsetInAnchor)
119     , m_isLegacyEditingPosition(false)
120 {
121     ASSERT(m_anchorNode);
122 }
123 
moveToPosition(PassRefPtrWillBeRawPtr<Node> node,int offset)124 void Position::moveToPosition(PassRefPtrWillBeRawPtr<Node> node, int offset)
125 {
126     ASSERT(!editingIgnoresContent(node.get()));
127     ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
128     m_anchorNode = node;
129     m_offset = offset;
130     if (m_isLegacyEditingPosition)
131         m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
132 }
moveToOffset(int offset)133 void Position::moveToOffset(int offset)
134 {
135     ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
136     m_offset = offset;
137     if (m_isLegacyEditingPosition)
138         m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
139 }
140 
containerNode() const141 Node* Position::containerNode() const
142 {
143     if (!m_anchorNode)
144         return 0;
145 
146     switch (anchorType()) {
147     case PositionIsBeforeChildren:
148     case PositionIsAfterChildren:
149     case PositionIsOffsetInAnchor:
150         return m_anchorNode.get();
151     case PositionIsBeforeAnchor:
152     case PositionIsAfterAnchor:
153         return m_anchorNode->parentNode();
154     }
155     ASSERT_NOT_REACHED();
156     return 0;
157 }
158 
containerText() const159 Text* Position::containerText() const
160 {
161     switch (anchorType()) {
162     case PositionIsOffsetInAnchor:
163         return m_anchorNode && m_anchorNode->isTextNode() ? toText(m_anchorNode) : 0;
164     case PositionIsBeforeAnchor:
165     case PositionIsAfterAnchor:
166         return 0;
167     case PositionIsBeforeChildren:
168     case PositionIsAfterChildren:
169         ASSERT(!m_anchorNode || !m_anchorNode->isTextNode());
170         return 0;
171     }
172     ASSERT_NOT_REACHED();
173     return 0;
174 }
175 
computeOffsetInContainerNode() const176 int Position::computeOffsetInContainerNode() const
177 {
178     if (!m_anchorNode)
179         return 0;
180 
181     switch (anchorType()) {
182     case PositionIsBeforeChildren:
183         return 0;
184     case PositionIsAfterChildren:
185         return lastOffsetInNode(m_anchorNode.get());
186     case PositionIsOffsetInAnchor:
187         return minOffsetForNode(m_anchorNode.get(), m_offset);
188     case PositionIsBeforeAnchor:
189         return m_anchorNode->nodeIndex();
190     case PositionIsAfterAnchor:
191         return m_anchorNode->nodeIndex() + 1;
192     }
193     ASSERT_NOT_REACHED();
194     return 0;
195 }
196 
offsetForPositionAfterAnchor() const197 int Position::offsetForPositionAfterAnchor() const
198 {
199     ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren);
200     ASSERT(!m_isLegacyEditingPosition);
201     return lastOffsetForEditing(m_anchorNode.get());
202 }
203 
204 // Neighbor-anchored positions are invalid DOM positions, so they need to be
205 // fixed up before handing them off to the Range object.
parentAnchoredEquivalent() const206 Position Position::parentAnchoredEquivalent() const
207 {
208     if (!m_anchorNode)
209         return Position();
210 
211     // FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
212     if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType != PositionIsAfterChildren)) {
213         if (m_anchorNode->parentNode() && (editingIgnoresContent(m_anchorNode.get()) || isRenderedTableElement(m_anchorNode.get())))
214             return positionInParentBeforeNode(*m_anchorNode);
215         return Position(m_anchorNode.get(), 0, PositionIsOffsetInAnchor);
216     }
217     if (!m_anchorNode->offsetInCharacters()
218         && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->countChildren())
219         && (editingIgnoresContent(m_anchorNode.get()) || isRenderedTableElement(m_anchorNode.get()))
220         && containerNode()) {
221         return positionInParentAfterNode(*m_anchorNode);
222     }
223 
224     return Position(containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor);
225 }
226 
computeNodeBeforePosition() const227 Node* Position::computeNodeBeforePosition() const
228 {
229     if (!m_anchorNode)
230         return 0;
231     switch (anchorType()) {
232     case PositionIsBeforeChildren:
233         return 0;
234     case PositionIsAfterChildren:
235         return m_anchorNode->lastChild();
236     case PositionIsOffsetInAnchor:
237         return m_anchorNode->traverseToChildAt(m_offset - 1); // -1 converts to traverseToChildAt((unsigned)-1) and returns null.
238     case PositionIsBeforeAnchor:
239         return m_anchorNode->previousSibling();
240     case PositionIsAfterAnchor:
241         return m_anchorNode.get();
242     }
243     ASSERT_NOT_REACHED();
244     return 0;
245 }
246 
computeNodeAfterPosition() const247 Node* Position::computeNodeAfterPosition() const
248 {
249     if (!m_anchorNode)
250         return 0;
251 
252     switch (anchorType()) {
253     case PositionIsBeforeChildren:
254         return m_anchorNode->firstChild();
255     case PositionIsAfterChildren:
256         return 0;
257     case PositionIsOffsetInAnchor:
258         return m_anchorNode->traverseToChildAt(m_offset);
259     case PositionIsBeforeAnchor:
260         return m_anchorNode.get();
261     case PositionIsAfterAnchor:
262         return m_anchorNode->nextSibling();
263     }
264     ASSERT_NOT_REACHED();
265     return 0;
266 }
267 
anchorTypeForLegacyEditingPosition(Node * anchorNode,int offset)268 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
269 {
270     if (anchorNode && editingIgnoresContent(anchorNode)) {
271         if (offset == 0)
272             return Position::PositionIsBeforeAnchor;
273         return Position::PositionIsAfterAnchor;
274     }
275     return Position::PositionIsOffsetInAnchor;
276 }
277 
278 // FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
element() const279 Element* Position::element() const
280 {
281     Node* n = anchorNode();
282     while (n && !n->isElementNode())
283         n = n->parentNode();
284     return toElement(n);
285 }
286 
computedStyle() const287 PassRefPtrWillBeRawPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
288 {
289     Element* elem = element();
290     if (!elem)
291         return nullptr;
292     return CSSComputedStyleDeclaration::create(elem);
293 }
294 
previous(PositionMoveType moveType) const295 Position Position::previous(PositionMoveType moveType) const
296 {
297     Node* node = deprecatedNode();
298     if (!node)
299         return *this;
300 
301     int offset = deprecatedEditingOffset();
302     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
303     ASSERT(offset >= 0);
304 
305     if (offset > 0) {
306         if (Node* child = node->traverseToChildAt(offset - 1))
307             return lastPositionInOrAfterNode(child);
308 
309         // There are two reasons child might be 0:
310         //   1) The node is node like a text node that is not an element, and therefore has no children.
311         //      Going backward one character at a time is correct.
312         //   2) The old offset was a bogus offset like (<br>, 1), and there is no child.
313         //      Going from 1 to 0 is correct.
314         switch (moveType) {
315         case CodePoint:
316             return createLegacyEditingPosition(node, offset - 1);
317         case Character:
318             return createLegacyEditingPosition(node, uncheckedPreviousOffset(node, offset));
319         case BackwardDeletion:
320             return createLegacyEditingPosition(node, uncheckedPreviousOffsetForBackwardDeletion(node, offset));
321         }
322     }
323 
324     if (ContainerNode* parent = node->parentNode())
325         return createLegacyEditingPosition(parent, node->nodeIndex());
326     return *this;
327 }
328 
next(PositionMoveType moveType) const329 Position Position::next(PositionMoveType moveType) const
330 {
331     ASSERT(moveType != BackwardDeletion);
332 
333     Node* node = deprecatedNode();
334     if (!node)
335         return *this;
336 
337     int offset = deprecatedEditingOffset();
338     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
339     ASSERT(offset >= 0);
340 
341     if (Node* child = node->traverseToChildAt(offset))
342         return firstPositionInOrBeforeNode(child);
343 
344     if (!node->hasChildren() && offset < lastOffsetForEditing(node)) {
345         // There are two reasons child might be 0:
346         //   1) The node is node like a text node that is not an element, and therefore has no children.
347         //      Going forward one character at a time is correct.
348         //   2) The new offset is a bogus offset like (<br>, 1), and there is no child.
349         //      Going from 0 to 1 is correct.
350         return createLegacyEditingPosition(node, (moveType == Character) ? uncheckedNextOffset(node, offset) : offset + 1);
351     }
352 
353     if (ContainerNode* parent = node->parentNode())
354         return createLegacyEditingPosition(parent, node->nodeIndex() + 1);
355     return *this;
356 }
357 
uncheckedPreviousOffset(const Node * n,int current)358 int Position::uncheckedPreviousOffset(const Node* n, int current)
359 {
360     return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
361 }
362 
uncheckedPreviousOffsetForBackwardDeletion(const Node * n,int current)363 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
364 {
365     return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
366 }
367 
uncheckedNextOffset(const Node * n,int current)368 int Position::uncheckedNextOffset(const Node* n, int current)
369 {
370     return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
371 }
372 
atFirstEditingPositionForNode() const373 bool Position::atFirstEditingPositionForNode() const
374 {
375     if (isNull())
376         return true;
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:
384         return true;
385     case PositionIsAfterChildren:
386     case PositionIsAfterAnchor:
387         return !lastOffsetForEditing(deprecatedNode());
388     }
389     ASSERT_NOT_REACHED();
390     return false;
391 }
392 
atLastEditingPositionForNode() const393 bool Position::atLastEditingPositionForNode() const
394 {
395     if (isNull())
396         return true;
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());
400 }
401 
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
404 //    is non editable.
405 // 2. It is the last position in the node and the previous visually equivalent position
406 //    is non editable.
407 // 3. It is an editable position and both the next and previous visually equivalent
408 //    positions are both non editable.
atEditingBoundary() const409 bool Position::atEditingBoundary() const
410 {
411     Position nextPosition = downstream(CanCrossEditingBoundary);
412     if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable())
413         return true;
414 
415     Position prevPosition = upstream(CanCrossEditingBoundary);
416     if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable())
417         return true;
418 
419     return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable()
420         && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable();
421 }
422 
parentEditingBoundary() const423 Node* Position::parentEditingBoundary() const
424 {
425     if (!m_anchorNode)
426         return 0;
427 
428     Node* documentElement = m_anchorNode->document().documentElement();
429     if (!documentElement)
430         return 0;
431 
432     Node* boundary = m_anchorNode.get();
433     while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && m_anchorNode->rendererIsEditable() == boundary->parentNode()->rendererIsEditable())
434         boundary = boundary->nonShadowBoundaryParentNode();
435 
436     return boundary;
437 }
438 
439 
atStartOfTree() const440 bool Position::atStartOfTree() const
441 {
442     if (isNull())
443         return true;
444     return !deprecatedNode()->parentNode() && m_offset <= 0;
445 }
446 
atEndOfTree() const447 bool Position::atEndOfTree() const
448 {
449     if (isNull())
450         return true;
451     return !deprecatedNode()->parentNode() && m_offset >= lastOffsetForEditing(deprecatedNode());
452 }
453 
renderedOffset() const454 int Position::renderedOffset() const
455 {
456     if (!deprecatedNode()->isTextNode())
457         return m_offset;
458 
459     if (!deprecatedNode()->renderer())
460         return m_offset;
461 
462     int result = 0;
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)
468             return result;
469         if (m_offset <= end) {
470             result += m_offset - start;
471             return result;
472         }
473         result += box->len();
474     }
475     return result;
476 }
477 
478 // return first preceding DOM position rendered at a different location, or "this"
previousCharacterPosition(EAffinity affinity) const479 Position Position::previousCharacterPosition(EAffinity affinity) const
480 {
481     if (isNull())
482         return Position();
483 
484     Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
485 
486     bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
487     bool rendered = isCandidate();
488 
489     Position currentPos = *this;
490     while (!currentPos.atStartOfTree()) {
491         currentPos = currentPos.previous();
492 
493         if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
494             return *this;
495 
496         if (atStartOfLine || !rendered) {
497             if (currentPos.isCandidate())
498                 return currentPos;
499         } else if (rendersInDifferentPosition(currentPos))
500             return currentPos;
501     }
502 
503     return *this;
504 }
505 
506 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
507 // If true, adjacent candidates are visually distinct.
508 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
509 // FIXME: Share code with isCandidate, if possible.
endsOfNodeAreVisuallyDistinctPositions(Node * node)510 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
511 {
512     if (!node || !node->renderer())
513         return false;
514 
515     if (!node->renderer()->isInline())
516         return true;
517 
518     // Don't include inline tables.
519     if (isHTMLTableElement(*node))
520         return false;
521 
522     // A Marquee elements are moving so we should assume their ends are always
523     // visibily distinct.
524     if (isHTMLMarqueeElement(*node))
525         return true;
526 
527     // There is a VisiblePosition inside an empty inline-block container.
528     return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild();
529 }
530 
enclosingVisualBoundary(Node * node)531 static Node* enclosingVisualBoundary(Node* node)
532 {
533     while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
534         node = node->parentNode();
535 
536     return node;
537 }
538 
539 // upstream() and downstream() want to return positions that are either in a
540 // text node or at just before a non-text node.  This method checks for that.
isStreamer(const PositionIterator & pos)541 static bool isStreamer(const PositionIterator& pos)
542 {
543     if (!pos.node())
544         return true;
545 
546     if (isAtomicNode(pos.node()))
547         return true;
548 
549     return pos.atStartOfNode();
550 }
551 
552 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
553 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
554 // that map to the VisiblePosition between 'b' and the space.  This function will return the left candidate
555 // and downstream() will return the right one.
556 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
557 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
upstream(EditingBoundaryCrossingRule rule) const558 Position Position::upstream(EditingBoundaryCrossingRule rule) const
559 {
560     Node* startNode = deprecatedNode();
561     if (!startNode)
562         return Position();
563 
564     // iterate backward from there, looking for a qualified position
565     Node* boundary = enclosingVisualBoundary(startNode);
566     // FIXME: PositionIterator should respect Before and After positions.
567     PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
568     PositionIterator currentPos = lastVisible;
569     bool startEditable = startNode->rendererIsEditable();
570     Node* lastNode = startNode;
571     bool boundaryCrossed = false;
572     for (; !currentPos.atStart(); currentPos.decrement()) {
573         Node* currentNode = currentPos.node();
574 
575         // Don't check for an editability change if we haven't moved to a different node,
576         // to avoid the expense of computing rendererIsEditable().
577         if (currentNode != lastNode) {
578             // Don't change editability.
579             bool currentEditable = currentNode->rendererIsEditable();
580             if (startEditable != currentEditable) {
581                 if (rule == CannotCrossEditingBoundary)
582                     break;
583                 boundaryCrossed = true;
584             }
585             lastNode = currentNode;
586         }
587 
588         // If we've moved to a position that is visually distinct, return the last saved position. There
589         // is code below that terminates early if we're *about* to move to a visually distinct position.
590         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
591             return lastVisible;
592 
593         // skip position in unrendered or invisible node
594         RenderObject* renderer = currentNode->renderer();
595         if (!renderer || renderer->style()->visibility() != VISIBLE)
596             continue;
597 
598         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
599             lastVisible = currentPos;
600             break;
601         }
602 
603         // track last visible streamer position
604         if (isStreamer(currentPos))
605             lastVisible = currentPos;
606 
607         // Don't move past a position that is visually distinct.  We could rely on code above to terminate and
608         // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
609         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
610             return lastVisible;
611 
612         // Return position after tables and nodes which have content that can be ignored.
613         if (editingIgnoresContent(currentNode) || isRenderedTableElement(currentNode)) {
614             if (currentPos.atEndOfNode())
615                 return positionAfterNode(currentNode);
616             continue;
617         }
618 
619         // return current position if it is in rendered text
620         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
621             if (currentNode != startNode) {
622                 // This assertion fires in layout tests in the case-transform.html test because
623                 // of a mix-up between offsets in the text in the DOM tree with text in the
624                 // render tree which can have a different length due to case transformation.
625                 // Until we resolve that, disable this so we can run the layout tests!
626                 //ASSERT(currentOffset >= renderer->caretMaxOffset());
627                 return createLegacyEditingPosition(currentNode, renderer->caretMaxOffset());
628             }
629 
630             unsigned textOffset = currentPos.offsetInLeafNode();
631             RenderText* textRenderer = toRenderText(renderer);
632             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
633             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
634                 if (textOffset <= box->start() + box->len()) {
635                     if (textOffset > box->start())
636                         return currentPos;
637                     continue;
638                 }
639 
640                 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
641                     continue;
642 
643                 // The text continues on the next line only if the last text box is not on this line and
644                 // none of the boxes on this line have a larger start offset.
645 
646                 bool continuesOnNextLine = true;
647                 InlineBox* otherBox = box;
648                 while (continuesOnNextLine) {
649                     otherBox = otherBox->nextLeafChild();
650                     if (!otherBox)
651                         break;
652                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() > textOffset))
653                         continuesOnNextLine = false;
654                 }
655 
656                 otherBox = box;
657                 while (continuesOnNextLine) {
658                     otherBox = otherBox->prevLeafChild();
659                     if (!otherBox)
660                         break;
661                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() > textOffset))
662                         continuesOnNextLine = false;
663                 }
664 
665                 if (continuesOnNextLine)
666                     return currentPos;
667             }
668         }
669     }
670 
671     return lastVisible;
672 }
673 
674 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
675 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
676 // that map to the VisiblePosition between 'b' and the space.  This function will return the right candidate
677 // and upstream() will return the left one.
678 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
679 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
680 // FIXME: This function should never be called when the line box tree is dirty. See https://bugs.webkit.org/show_bug.cgi?id=97264
downstream(EditingBoundaryCrossingRule rule) const681 Position Position::downstream(EditingBoundaryCrossingRule rule) const
682 {
683     Node* startNode = deprecatedNode();
684     if (!startNode)
685         return Position();
686 
687     // iterate forward from there, looking for a qualified position
688     Node* boundary = enclosingVisualBoundary(startNode);
689     // FIXME: PositionIterator should respect Before and After positions.
690     PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
691     PositionIterator currentPos = lastVisible;
692     bool startEditable = startNode->rendererIsEditable();
693     Node* lastNode = startNode;
694     bool boundaryCrossed = false;
695     for (; !currentPos.atEnd(); currentPos.increment()) {
696         Node* currentNode = currentPos.node();
697 
698         // Don't check for an editability change if we haven't moved to a different node,
699         // to avoid the expense of computing rendererIsEditable().
700         if (currentNode != lastNode) {
701             // Don't change editability.
702             bool currentEditable = currentNode->rendererIsEditable();
703             if (startEditable != currentEditable) {
704                 if (rule == CannotCrossEditingBoundary)
705                     break;
706                 boundaryCrossed = true;
707             }
708 
709             lastNode = currentNode;
710         }
711 
712         // stop before going above the body, up into the head
713         // return the last visible streamer position
714         if (isHTMLBodyElement(*currentNode) && currentPos.atEndOfNode())
715             break;
716 
717         // Do not move to a visually distinct position.
718         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
719             return lastVisible;
720         // Do not move past a visually disinct position.
721         // Note: The first position after the last in a node whose ends are visually distinct
722         // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
723         if (boundary && boundary->parentNode() == currentNode)
724             return lastVisible;
725 
726         // skip position in unrendered or invisible node
727         RenderObject* renderer = currentNode->renderer();
728         if (!renderer || renderer->style()->visibility() != VISIBLE)
729             continue;
730 
731         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
732             lastVisible = currentPos;
733             break;
734         }
735 
736         // track last visible streamer position
737         if (isStreamer(currentPos))
738             lastVisible = currentPos;
739 
740         // Return position before tables and nodes which have content that can be ignored.
741         if (editingIgnoresContent(currentNode) || isRenderedTableElement(currentNode)) {
742             if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
743                 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
744             continue;
745         }
746 
747         // return current position if it is in rendered text
748         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
749             if (currentNode != startNode) {
750                 ASSERT(currentPos.atStartOfNode());
751                 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
752             }
753 
754             unsigned textOffset = currentPos.offsetInLeafNode();
755             RenderText* textRenderer = toRenderText(renderer);
756             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
757             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
758                 if (textOffset <= box->end()) {
759                     if (textOffset >= box->start())
760                         return currentPos;
761                     continue;
762                 }
763 
764                 if (box == lastTextBox || textOffset != box->start() + box->len())
765                     continue;
766 
767                 // The text continues on the next line only if the last text box is not on this line and
768                 // none of the boxes on this line have a larger start offset.
769 
770                 bool continuesOnNextLine = true;
771                 InlineBox* otherBox = box;
772                 while (continuesOnNextLine) {
773                     otherBox = otherBox->nextLeafChild();
774                     if (!otherBox)
775                         break;
776                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() >= textOffset))
777                         continuesOnNextLine = false;
778                 }
779 
780                 otherBox = box;
781                 while (continuesOnNextLine) {
782                     otherBox = otherBox->prevLeafChild();
783                     if (!otherBox)
784                         break;
785                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() >= textOffset))
786                         continuesOnNextLine = false;
787                 }
788 
789                 if (continuesOnNextLine)
790                     return currentPos;
791             }
792         }
793     }
794 
795     return lastVisible;
796 }
797 
boundingBoxLogicalHeight(RenderObject * o,const IntRect & rect)798 static int boundingBoxLogicalHeight(RenderObject *o, const IntRect &rect)
799 {
800     return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width();
801 }
802 
hasRenderedNonAnonymousDescendantsWithHeight(RenderObject * renderer)803 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
804 {
805     RenderObject* stop = renderer->nextInPreOrderAfterChildren();
806     for (RenderObject *o = renderer->slowFirstChild(); o && o != stop; o = o->nextInPreOrder())
807         if (o->nonPseudoNode()) {
808             if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->linesBoundingBox()))
809                 || (o->isBox() && toRenderBox(o)->pixelSnappedLogicalHeight())
810                 || (o->isRenderInline() && isEmptyInline(o) && boundingBoxLogicalHeight(o, toRenderInline(o)->linesBoundingBox())))
811                 return true;
812         }
813     return false;
814 }
815 
nodeIsUserSelectNone(Node * node)816 bool Position::nodeIsUserSelectNone(Node* node)
817 {
818     return node && node->renderer() && !node->renderer()->isSelectable();
819 }
820 
nodeIsUserSelectAll(const Node * node)821 bool Position::nodeIsUserSelectAll(const Node* node)
822 {
823     return RuntimeEnabledFeatures::userSelectAllEnabled() && node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_ALL;
824 }
825 
rootUserSelectAllForNode(Node * node)826 Node* Position::rootUserSelectAllForNode(Node* node)
827 {
828     if (!node || !nodeIsUserSelectAll(node))
829         return 0;
830     Node* parent = node->parentNode();
831     if (!parent)
832         return node;
833 
834     Node* candidateRoot = node;
835     while (parent) {
836         if (!parent->renderer()) {
837             parent = parent->parentNode();
838             continue;
839         }
840         if (!nodeIsUserSelectAll(parent))
841             break;
842         candidateRoot = parent;
843         parent = candidateRoot->parentNode();
844     }
845     return candidateRoot;
846 }
847 
isCandidate() const848 bool Position::isCandidate() const
849 {
850     if (isNull())
851         return false;
852 
853     RenderObject* renderer = deprecatedNode()->renderer();
854     if (!renderer)
855         return false;
856 
857     if (renderer->style()->visibility() != VISIBLE)
858         return false;
859 
860     if (renderer->isBR())
861         // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
862         return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
863 
864     if (renderer->isText())
865         return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
866 
867     if (renderer->isSVG()) {
868         // We don't consider SVG elements are contenteditable except for
869         // associated renderer returns isText() true, e.g. RenderSVGInlineText.
870         return false;
871     }
872 
873     if (isRenderedTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode()))
874         return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
875 
876     if (isHTMLHtmlElement(*m_anchorNode))
877         return false;
878 
879     if (renderer->isRenderBlockFlow()) {
880         if (toRenderBlock(renderer)->logicalHeight() || isHTMLBodyElement(*m_anchorNode)) {
881             if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
882                 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
883             return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
884         }
885     } else {
886         LocalFrame* frame = m_anchorNode->document().frame();
887         bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled();
888         return (caretBrowsing || m_anchorNode->rendererIsEditable()) && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
889     }
890 
891     return false;
892 }
893 
inRenderedText() const894 bool Position::inRenderedText() const
895 {
896     if (isNull() || !deprecatedNode()->isTextNode())
897         return false;
898 
899     RenderObject* renderer = deprecatedNode()->renderer();
900     if (!renderer)
901         return false;
902 
903     RenderText *textRenderer = toRenderText(renderer);
904     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
905         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
906             // The offset we're looking for is before this node
907             // this means the offset must be in content that is
908             // not rendered. Return false.
909             return false;
910         }
911         if (box->containsCaretOffset(m_offset))
912             // Return false for offsets inside composed characters.
913             return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
914     }
915 
916     return false;
917 }
918 
isRenderedCharacter() const919 bool Position::isRenderedCharacter() const
920 {
921     if (isNull() || !deprecatedNode()->isTextNode())
922         return false;
923 
924     RenderObject* renderer = deprecatedNode()->renderer();
925     if (!renderer)
926         return false;
927 
928     RenderText* textRenderer = toRenderText(renderer);
929     for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
930         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
931             // The offset we're looking for is before this node
932             // this means the offset must be in content that is
933             // not rendered. Return false.
934             return false;
935         }
936         if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
937             return true;
938     }
939 
940     return false;
941 }
942 
rendersInDifferentPosition(const Position & pos) const943 bool Position::rendersInDifferentPosition(const Position &pos) const
944 {
945     if (isNull() || pos.isNull())
946         return false;
947 
948     RenderObject* renderer = deprecatedNode()->renderer();
949     if (!renderer)
950         return false;
951 
952     RenderObject* posRenderer = pos.deprecatedNode()->renderer();
953     if (!posRenderer)
954         return false;
955 
956     if (renderer->style()->visibility() != VISIBLE ||
957         posRenderer->style()->visibility() != VISIBLE)
958         return false;
959 
960     if (deprecatedNode() == pos.deprecatedNode()) {
961         if (isHTMLBRElement(*deprecatedNode()))
962             return false;
963 
964         if (m_offset == pos.deprecatedEditingOffset())
965             return false;
966 
967         if (!deprecatedNode()->isTextNode() && !pos.deprecatedNode()->isTextNode()) {
968             if (m_offset != pos.deprecatedEditingOffset())
969                 return true;
970         }
971     }
972 
973     if (isHTMLBRElement(*deprecatedNode()) && pos.isCandidate())
974         return true;
975 
976     if (isHTMLBRElement(*pos.deprecatedNode()) && isCandidate())
977         return true;
978 
979     if (deprecatedNode()->enclosingBlockFlowElement() != pos.deprecatedNode()->enclosingBlockFlowElement())
980         return true;
981 
982     if (deprecatedNode()->isTextNode() && !inRenderedText())
983         return false;
984 
985     if (pos.deprecatedNode()->isTextNode() && !pos.inRenderedText())
986         return false;
987 
988     int thisRenderedOffset = renderedOffset();
989     int posRenderedOffset = pos.renderedOffset();
990 
991     if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
992         return false;
993 
994     int ignoredCaretOffset;
995     InlineBox* b1;
996     getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
997     InlineBox* b2;
998     pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
999 
1000     WTF_LOG(Editing, "renderer:               %p [%p]\n", renderer, b1);
1001     WTF_LOG(Editing, "thisRenderedOffset:         %d\n", thisRenderedOffset);
1002     WTF_LOG(Editing, "posRenderer:            %p [%p]\n", posRenderer, b2);
1003     WTF_LOG(Editing, "posRenderedOffset:      %d\n", posRenderedOffset);
1004     WTF_LOG(Editing, "node min/max:           %d:%d\n", caretMinOffset(deprecatedNode()), caretMaxOffset(deprecatedNode()));
1005     WTF_LOG(Editing, "pos node min/max:       %d:%d\n", caretMinOffset(pos.deprecatedNode()), caretMaxOffset(pos.deprecatedNode()));
1006     WTF_LOG(Editing, "----------------------------------------------------------------------\n");
1007 
1008     if (!b1 || !b2) {
1009         return false;
1010     }
1011 
1012     if (b1->root() != b2->root()) {
1013         return true;
1014     }
1015 
1016     if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1017         && thisRenderedOffset == caretMaxOffset(deprecatedNode()) && !posRenderedOffset) {
1018         return false;
1019     }
1020 
1021     if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1022         && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.deprecatedNode())) {
1023         return false;
1024     }
1025 
1026     return true;
1027 }
1028 
1029 // This assumes that it starts in editable content.
leadingWhitespacePosition(EAffinity affinity,bool considerNonCollapsibleWhitespace) const1030 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
1031 {
1032     ASSERT(isEditablePosition(*this, ContentIsEditable, DoNotUpdateStyle));
1033     if (isNull())
1034         return Position();
1035 
1036     if (isHTMLBRElement(*upstream().deprecatedNode()))
1037         return Position();
1038 
1039     Position prev = previousCharacterPosition(affinity);
1040     if (prev != *this && prev.deprecatedNode()->inSameContainingBlockFlowElement(deprecatedNode()) && prev.deprecatedNode()->isTextNode()) {
1041         String string = toText(prev.deprecatedNode())->data();
1042         UChar c = string[prev.deprecatedEditingOffset()];
1043         if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1044             if (isEditablePosition(prev))
1045                 return prev;
1046     }
1047 
1048     return Position();
1049 }
1050 
1051 // This assumes that it starts in editable content.
trailingWhitespacePosition(EAffinity,bool considerNonCollapsibleWhitespace) const1052 Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
1053 {
1054     ASSERT(isEditablePosition(*this, ContentIsEditable, DoNotUpdateStyle));
1055     if (isNull())
1056         return Position();
1057 
1058     VisiblePosition v(*this);
1059     UChar c = v.characterAfter();
1060     // The space must not be in another paragraph and it must be editable.
1061     if (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
1062         if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1063             return *this;
1064 
1065     return Position();
1066 }
1067 
getInlineBoxAndOffset(EAffinity affinity,InlineBox * & inlineBox,int & caretOffset) const1068 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
1069 {
1070     getInlineBoxAndOffset(affinity, primaryDirection(), inlineBox, caretOffset);
1071 }
1072 
isNonTextLeafChild(RenderObject * object)1073 static bool isNonTextLeafChild(RenderObject* object)
1074 {
1075     if (object->slowFirstChild())
1076         return false;
1077     if (object->isText())
1078         return false;
1079     return true;
1080 }
1081 
searchAheadForBetterMatch(RenderObject * renderer)1082 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
1083 {
1084     RenderBlock* container = renderer->containingBlock();
1085     RenderObject* next = renderer;
1086     while ((next = next->nextInPreOrder(container))) {
1087         if (next->isRenderBlock())
1088             return 0;
1089         if (next->isBR())
1090             return 0;
1091         if (isNonTextLeafChild(next))
1092             return 0;
1093         if (next->isText()) {
1094             InlineTextBox* match = 0;
1095             int minOffset = INT_MAX;
1096             for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
1097                 int caretMinOffset = box->caretMinOffset();
1098                 if (caretMinOffset < minOffset) {
1099                     match = box;
1100                     minOffset = caretMinOffset;
1101                 }
1102             }
1103             if (match)
1104                 return match;
1105         }
1106     }
1107     return 0;
1108 }
1109 
downstreamIgnoringEditingBoundaries(Position position)1110 static Position downstreamIgnoringEditingBoundaries(Position position)
1111 {
1112     Position lastPosition;
1113     while (position != lastPosition) {
1114         lastPosition = position;
1115         position = position.downstream(CanCrossEditingBoundary);
1116     }
1117     return position;
1118 }
1119 
upstreamIgnoringEditingBoundaries(Position position)1120 static Position upstreamIgnoringEditingBoundaries(Position position)
1121 {
1122     Position lastPosition;
1123     while (position != lastPosition) {
1124         lastPosition = position;
1125         position = position.upstream(CanCrossEditingBoundary);
1126     }
1127     return position;
1128 }
1129 
getInlineBoxAndOffset(EAffinity affinity,TextDirection primaryDirection,InlineBox * & inlineBox,int & caretOffset) const1130 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
1131 {
1132     caretOffset = deprecatedEditingOffset();
1133     RenderObject* renderer = deprecatedNode()->renderer();
1134 
1135     if (!renderer->isText()) {
1136         inlineBox = 0;
1137         if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isRenderBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
1138             // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in
1139             // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning
1140             // of RenderObject::createVisiblePosition().
1141             Position equivalent = downstreamIgnoringEditingBoundaries(*this);
1142             if (equivalent == *this) {
1143                 equivalent = upstreamIgnoringEditingBoundaries(*this);
1144                 if (equivalent == *this || downstreamIgnoringEditingBoundaries(equivalent) == *this)
1145                     return;
1146             }
1147 
1148             equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1149             return;
1150         }
1151         if (renderer->isBox()) {
1152             inlineBox = toRenderBox(renderer)->inlineBoxWrapper();
1153             if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1154                 return;
1155         }
1156     } else {
1157         RenderText* textRenderer = toRenderText(renderer);
1158 
1159         InlineTextBox* box;
1160         InlineTextBox* candidate = 0;
1161 
1162         for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
1163             int caretMinOffset = box->caretMinOffset();
1164             int caretMaxOffset = box->caretMaxOffset();
1165 
1166             if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1167                 continue;
1168 
1169             if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1170                 inlineBox = box;
1171                 return;
1172             }
1173 
1174             if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
1175                 || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
1176                 || (caretOffset == caretMaxOffset && box->nextLeafChild() && box->nextLeafChild()->isLineBreak()))
1177                 break;
1178 
1179             candidate = box;
1180         }
1181         if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
1182             box = searchAheadForBetterMatch(textRenderer);
1183             if (box)
1184                 caretOffset = box->caretMinOffset();
1185         }
1186         inlineBox = box ? box : candidate;
1187     }
1188 
1189     if (!inlineBox)
1190         return;
1191 
1192     unsigned char level = inlineBox->bidiLevel();
1193 
1194     if (inlineBox->direction() == primaryDirection) {
1195         if (caretOffset == inlineBox->caretRightmostOffset()) {
1196             InlineBox* nextBox = inlineBox->nextLeafChild();
1197             if (!nextBox || nextBox->bidiLevel() >= level)
1198                 return;
1199 
1200             level = nextBox->bidiLevel();
1201             InlineBox* prevBox = inlineBox;
1202             do {
1203                 prevBox = prevBox->prevLeafChild();
1204             } while (prevBox && prevBox->bidiLevel() > level);
1205 
1206             if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
1207                 return;
1208 
1209             // For example, abc 123 ^ CBA
1210             while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1211                 if (nextBox->bidiLevel() < level)
1212                     break;
1213                 inlineBox = nextBox;
1214             }
1215             caretOffset = inlineBox->caretRightmostOffset();
1216         } else {
1217             InlineBox* prevBox = inlineBox->prevLeafChild();
1218             if (!prevBox || prevBox->bidiLevel() >= level)
1219                 return;
1220 
1221             level = prevBox->bidiLevel();
1222             InlineBox* nextBox = inlineBox;
1223             do {
1224                 nextBox = nextBox->nextLeafChild();
1225             } while (nextBox && nextBox->bidiLevel() > level);
1226 
1227             if (nextBox && nextBox->bidiLevel() == level)
1228                 return;
1229 
1230             while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1231                 if (prevBox->bidiLevel() < level)
1232                     break;
1233                 inlineBox = prevBox;
1234             }
1235             caretOffset = inlineBox->caretLeftmostOffset();
1236         }
1237         return;
1238     }
1239 
1240     if (caretOffset == inlineBox->caretLeftmostOffset()) {
1241         InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak();
1242         if (!prevBox || prevBox->bidiLevel() < level) {
1243             // Left edge of a secondary run. Set to the right edge of the entire run.
1244             while (InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1245                 if (nextBox->bidiLevel() < level)
1246                     break;
1247                 inlineBox = nextBox;
1248             }
1249             caretOffset = inlineBox->caretRightmostOffset();
1250         } else if (prevBox->bidiLevel() > level) {
1251             // Right edge of a "tertiary" run. Set to the left edge of that run.
1252             while (InlineBox* tertiaryBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1253                 if (tertiaryBox->bidiLevel() <= level)
1254                     break;
1255                 inlineBox = tertiaryBox;
1256             }
1257             caretOffset = inlineBox->caretLeftmostOffset();
1258         }
1259     } else {
1260         InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak();
1261         if (!nextBox || nextBox->bidiLevel() < level) {
1262             // Right edge of a secondary run. Set to the left edge of the entire run.
1263             while (InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1264                 if (prevBox->bidiLevel() < level)
1265                     break;
1266                 inlineBox = prevBox;
1267             }
1268             if (m_anchorNode->selfOrAncestorHasDirAutoAttribute())
1269                 caretOffset = inlineBox->bidiLevel() < level ? inlineBox->caretLeftmostOffset() : inlineBox->caretRightmostOffset();
1270             else
1271                 caretOffset = inlineBox->caretLeftmostOffset();
1272         } else if (nextBox->bidiLevel() > level) {
1273             // Left edge of a "tertiary" run. Set to the right edge of that run.
1274             while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1275                 if (tertiaryBox->bidiLevel() <= level)
1276                     break;
1277                 inlineBox = tertiaryBox;
1278             }
1279             caretOffset = inlineBox->caretRightmostOffset();
1280         }
1281     }
1282 }
1283 
primaryDirection() const1284 TextDirection Position::primaryDirection() const
1285 {
1286     TextDirection primaryDirection = LTR;
1287     for (const RenderObject* r = m_anchorNode->renderer(); r; r = r->parent()) {
1288         if (r->isRenderBlockFlow()) {
1289             primaryDirection = r->style()->direction();
1290             break;
1291         }
1292     }
1293 
1294     return primaryDirection;
1295 }
1296 
trace(Visitor * visitor)1297 void Position::trace(Visitor* visitor)
1298 {
1299     visitor->trace(m_anchorNode);
1300 }
1301 
debugPosition(const char * msg) const1302 void Position::debugPosition(const char* msg) const
1303 {
1304     if (isNull())
1305         fprintf(stderr, "Position [%s]: null\n", msg);
1306     else
1307         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, deprecatedNode()->nodeName().utf8().data(), deprecatedNode(), m_offset);
1308 }
1309 
1310 #ifndef NDEBUG
1311 
formatForDebugger(char * buffer,unsigned length) const1312 void Position::formatForDebugger(char* buffer, unsigned length) const
1313 {
1314     StringBuilder result;
1315 
1316     if (isNull())
1317         result.appendLiteral("<null>");
1318     else {
1319         char s[1024];
1320         result.appendLiteral("offset ");
1321         result.appendNumber(m_offset);
1322         result.appendLiteral(" of ");
1323         deprecatedNode()->formatForDebugger(s, sizeof(s));
1324         result.append(s);
1325     }
1326 
1327     strncpy(buffer, result.toString().utf8().data(), length - 1);
1328 }
1329 
showAnchorTypeAndOffset() const1330 void Position::showAnchorTypeAndOffset() const
1331 {
1332     if (m_isLegacyEditingPosition)
1333         fputs("legacy, ", stderr);
1334     switch (anchorType()) {
1335     case PositionIsOffsetInAnchor:
1336         fputs("offset", stderr);
1337         break;
1338     case PositionIsBeforeChildren:
1339         fputs("beforeChildren", stderr);
1340         break;
1341     case PositionIsAfterChildren:
1342         fputs("afterChildren", stderr);
1343         break;
1344     case PositionIsBeforeAnchor:
1345         fputs("before", stderr);
1346         break;
1347     case PositionIsAfterAnchor:
1348         fputs("after", stderr);
1349         break;
1350     }
1351     fprintf(stderr, ", offset:%d\n", m_offset);
1352 }
1353 
showTreeForThis() const1354 void Position::showTreeForThis() const
1355 {
1356     if (anchorNode()) {
1357         anchorNode()->showTreeForThis();
1358         showAnchorTypeAndOffset();
1359     }
1360 }
1361 
1362 #endif
1363 
1364 
1365 
1366 } // namespace WebCore
1367 
1368 #ifndef NDEBUG
1369 
showTree(const WebCore::Position & pos)1370 void showTree(const WebCore::Position& pos)
1371 {
1372     pos.showTreeForThis();
1373 }
1374 
showTree(const WebCore::Position * pos)1375 void showTree(const WebCore::Position* pos)
1376 {
1377     if (pos)
1378         pos->showTreeForThis();
1379 }
1380 
1381 #endif
1382