• 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 blink {
51 
52 using namespace HTMLNames;
53 
nextRenderedEditable(Node * node)54 static Node* nextRenderedEditable(Node* node)
55 {
56     for (node = node->nextLeafNode(); node; node = node->nextLeafNode()) {
57         RenderObject* renderer = node->renderer();
58         if (!renderer)
59             continue;
60         if (!node->hasEditableStyle())
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     for (node = node->previousLeafNode(); node; node = node->previousLeafNode()) {
71         RenderObject* renderer = node->renderer();
72         if (!renderer)
73             continue;
74         if (!node->hasEditableStyle())
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()) || isRenderedHTMLTableElement(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()) || isRenderedHTMLTableElement(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_offset ? NodeTraversal::childAt(*m_anchorNode, m_offset - 1) : 0;
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 NodeTraversal::childAt(*m_anchorNode, 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* node = anchorNode();
282     if (!node || node->isElementNode())
283         return toElement(node);
284     return node->parentElement();
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 = NodeTraversal::childAt(*node, 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 = NodeTraversal::childAt(*node, 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()->hasEditableStyle())
413         return true;
414 
415     Position prevPosition = upstream(CanCrossEditingBoundary);
416     if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->hasEditableStyle())
417         return true;
418 
419     return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->hasEditableStyle()
420         && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->hasEditableStyle();
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->hasEditableStyle() == boundary->parentNode()->hasEditableStyle())
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 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
479 // If true, adjacent candidates are visually distinct.
480 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
481 // FIXME: Share code with isCandidate, if possible.
endsOfNodeAreVisuallyDistinctPositions(Node * node)482 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
483 {
484     if (!node || !node->renderer())
485         return false;
486 
487     if (!node->renderer()->isInline())
488         return true;
489 
490     // Don't include inline tables.
491     if (isHTMLTableElement(*node))
492         return false;
493 
494     // A Marquee elements are moving so we should assume their ends are always
495     // visibily distinct.
496     if (isHTMLMarqueeElement(*node))
497         return true;
498 
499     // There is a VisiblePosition inside an empty inline-block container.
500     return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->hasChildren();
501 }
502 
enclosingVisualBoundary(Node * node)503 static Node* enclosingVisualBoundary(Node* node)
504 {
505     while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
506         node = node->parentNode();
507 
508     return node;
509 }
510 
511 // upstream() and downstream() want to return positions that are either in a
512 // text node or at just before a non-text node.  This method checks for that.
isStreamer(const PositionIterator & pos)513 static bool isStreamer(const PositionIterator& pos)
514 {
515     if (!pos.node())
516         return true;
517 
518     if (isAtomicNode(pos.node()))
519         return true;
520 
521     return pos.atStartOfNode();
522 }
523 
524 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
525 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
526 // that map to the VisiblePosition between 'b' and the space.  This function will return the left candidate
527 // and downstream() will return the right one.
528 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
529 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
upstream(EditingBoundaryCrossingRule rule) const530 Position Position::upstream(EditingBoundaryCrossingRule rule) const
531 {
532     Node* startNode = deprecatedNode();
533     if (!startNode)
534         return Position();
535 
536     // iterate backward from there, looking for a qualified position
537     Node* boundary = enclosingVisualBoundary(startNode);
538     // FIXME: PositionIterator should respect Before and After positions.
539     PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
540     PositionIterator currentPos = lastVisible;
541     bool startEditable = startNode->hasEditableStyle();
542     Node* lastNode = startNode;
543     bool boundaryCrossed = false;
544     for (; !currentPos.atStart(); currentPos.decrement()) {
545         Node* currentNode = currentPos.node();
546 
547         // Don't check for an editability change if we haven't moved to a different node,
548         // to avoid the expense of computing hasEditableStyle().
549         if (currentNode != lastNode) {
550             // Don't change editability.
551             bool currentEditable = currentNode->hasEditableStyle();
552             if (startEditable != currentEditable) {
553                 if (rule == CannotCrossEditingBoundary)
554                     break;
555                 boundaryCrossed = true;
556             }
557             lastNode = currentNode;
558         }
559 
560         // If we've moved to a position that is visually distinct, return the last saved position. There
561         // is code below that terminates early if we're *about* to move to a visually distinct position.
562         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
563             return lastVisible;
564 
565         // skip position in unrendered or invisible node
566         RenderObject* renderer = currentNode->renderer();
567         if (!renderer || renderer->style()->visibility() != VISIBLE)
568             continue;
569 
570         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
571             lastVisible = currentPos;
572             break;
573         }
574 
575         // track last visible streamer position
576         if (isStreamer(currentPos))
577             lastVisible = currentPos;
578 
579         // Don't move past a position that is visually distinct.  We could rely on code above to terminate and
580         // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
581         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
582             return lastVisible;
583 
584         // Return position after tables and nodes which have content that can be ignored.
585         if (editingIgnoresContent(currentNode) || isRenderedHTMLTableElement(currentNode)) {
586             if (currentPos.atEndOfNode())
587                 return positionAfterNode(currentNode);
588             continue;
589         }
590 
591         // return current position if it is in rendered text
592         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
593             if (currentNode != startNode) {
594                 // This assertion fires in layout tests in the case-transform.html test because
595                 // of a mix-up between offsets in the text in the DOM tree with text in the
596                 // render tree which can have a different length due to case transformation.
597                 // Until we resolve that, disable this so we can run the layout tests!
598                 //ASSERT(currentOffset >= renderer->caretMaxOffset());
599                 return createLegacyEditingPosition(currentNode, renderer->caretMaxOffset());
600             }
601 
602             unsigned textOffset = currentPos.offsetInLeafNode();
603             RenderText* textRenderer = toRenderText(renderer);
604             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
605             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
606                 if (textOffset <= box->start() + box->len()) {
607                     if (textOffset > box->start())
608                         return currentPos;
609                     continue;
610                 }
611 
612                 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
613                     continue;
614 
615                 // The text continues on the next line only if the last text box is not on this line and
616                 // none of the boxes on this line have a larger start offset.
617 
618                 bool continuesOnNextLine = true;
619                 InlineBox* otherBox = box;
620                 while (continuesOnNextLine) {
621                     otherBox = otherBox->nextLeafChild();
622                     if (!otherBox)
623                         break;
624                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() > textOffset))
625                         continuesOnNextLine = false;
626                 }
627 
628                 otherBox = box;
629                 while (continuesOnNextLine) {
630                     otherBox = otherBox->prevLeafChild();
631                     if (!otherBox)
632                         break;
633                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() > textOffset))
634                         continuesOnNextLine = false;
635                 }
636 
637                 if (continuesOnNextLine)
638                     return currentPos;
639             }
640         }
641     }
642 
643     return lastVisible;
644 }
645 
646 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
647 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
648 // that map to the VisiblePosition between 'b' and the space.  This function will return the right candidate
649 // and upstream() will return the left one.
650 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
651 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
652 // 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) const653 Position Position::downstream(EditingBoundaryCrossingRule rule) const
654 {
655     Node* startNode = deprecatedNode();
656     if (!startNode)
657         return Position();
658 
659     // iterate forward from there, looking for a qualified position
660     Node* boundary = enclosingVisualBoundary(startNode);
661     // FIXME: PositionIterator should respect Before and After positions.
662     PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
663     PositionIterator currentPos = lastVisible;
664     bool startEditable = startNode->hasEditableStyle();
665     Node* lastNode = startNode;
666     bool boundaryCrossed = false;
667     for (; !currentPos.atEnd(); currentPos.increment()) {
668         Node* currentNode = currentPos.node();
669 
670         // Don't check for an editability change if we haven't moved to a different node,
671         // to avoid the expense of computing hasEditableStyle().
672         if (currentNode != lastNode) {
673             // Don't change editability.
674             bool currentEditable = currentNode->hasEditableStyle();
675             if (startEditable != currentEditable) {
676                 if (rule == CannotCrossEditingBoundary)
677                     break;
678                 boundaryCrossed = true;
679             }
680 
681             lastNode = currentNode;
682         }
683 
684         // stop before going above the body, up into the head
685         // return the last visible streamer position
686         if (isHTMLBodyElement(*currentNode) && currentPos.atEndOfNode())
687             break;
688 
689         // Do not move to a visually distinct position.
690         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
691             return lastVisible;
692         // Do not move past a visually disinct position.
693         // Note: The first position after the last in a node whose ends are visually distinct
694         // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
695         if (boundary && boundary->parentNode() == currentNode)
696             return lastVisible;
697 
698         // skip position in unrendered or invisible node
699         RenderObject* renderer = currentNode->renderer();
700         if (!renderer || renderer->style()->visibility() != VISIBLE)
701             continue;
702 
703         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
704             lastVisible = currentPos;
705             break;
706         }
707 
708         // track last visible streamer position
709         if (isStreamer(currentPos))
710             lastVisible = currentPos;
711 
712         // Return position before tables and nodes which have content that can be ignored.
713         if (editingIgnoresContent(currentNode) || isRenderedHTMLTableElement(currentNode)) {
714             if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
715                 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
716             continue;
717         }
718 
719         // return current position if it is in rendered text
720         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
721             if (currentNode != startNode) {
722                 ASSERT(currentPos.atStartOfNode());
723                 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
724             }
725 
726             unsigned textOffset = currentPos.offsetInLeafNode();
727             RenderText* textRenderer = toRenderText(renderer);
728             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
729             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
730                 if (textOffset <= box->end()) {
731                     if (textOffset >= box->start())
732                         return currentPos;
733                     continue;
734                 }
735 
736                 if (box == lastTextBox || textOffset != box->start() + box->len())
737                     continue;
738 
739                 // The text continues on the next line only if the last text box is not on this line and
740                 // none of the boxes on this line have a larger start offset.
741 
742                 bool continuesOnNextLine = true;
743                 InlineBox* otherBox = box;
744                 while (continuesOnNextLine) {
745                     otherBox = otherBox->nextLeafChild();
746                     if (!otherBox)
747                         break;
748                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() >= textOffset))
749                         continuesOnNextLine = false;
750                 }
751 
752                 otherBox = box;
753                 while (continuesOnNextLine) {
754                     otherBox = otherBox->prevLeafChild();
755                     if (!otherBox)
756                         break;
757                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() >= textOffset))
758                         continuesOnNextLine = false;
759                 }
760 
761                 if (continuesOnNextLine)
762                     return currentPos;
763             }
764         }
765     }
766 
767     return lastVisible;
768 }
769 
boundingBoxLogicalHeight(RenderObject * o,const IntRect & rect)770 static int boundingBoxLogicalHeight(RenderObject *o, const IntRect &rect)
771 {
772     return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width();
773 }
774 
hasRenderedNonAnonymousDescendantsWithHeight(RenderObject * renderer)775 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
776 {
777     RenderObject* stop = renderer->nextInPreOrderAfterChildren();
778     for (RenderObject *o = renderer->slowFirstChild(); o && o != stop; o = o->nextInPreOrder())
779         if (o->nonPseudoNode()) {
780             if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->linesBoundingBox()))
781                 || (o->isBox() && toRenderBox(o)->pixelSnappedLogicalHeight())
782                 || (o->isRenderInline() && isEmptyInline(o) && boundingBoxLogicalHeight(o, toRenderInline(o)->linesBoundingBox())))
783                 return true;
784         }
785     return false;
786 }
787 
nodeIsUserSelectNone(Node * node)788 bool Position::nodeIsUserSelectNone(Node* node)
789 {
790     return node && node->renderer() && !node->renderer()->isSelectable();
791 }
792 
nodeIsUserSelectAll(const Node * node)793 bool Position::nodeIsUserSelectAll(const Node* node)
794 {
795     return RuntimeEnabledFeatures::userSelectAllEnabled() && node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_ALL;
796 }
797 
rootUserSelectAllForNode(Node * node)798 Node* Position::rootUserSelectAllForNode(Node* node)
799 {
800     if (!node || !nodeIsUserSelectAll(node))
801         return 0;
802     Node* parent = node->parentNode();
803     if (!parent)
804         return node;
805 
806     Node* candidateRoot = node;
807     while (parent) {
808         if (!parent->renderer()) {
809             parent = parent->parentNode();
810             continue;
811         }
812         if (!nodeIsUserSelectAll(parent))
813             break;
814         candidateRoot = parent;
815         parent = candidateRoot->parentNode();
816     }
817     return candidateRoot;
818 }
819 
isCandidate() const820 bool Position::isCandidate() const
821 {
822     if (isNull())
823         return false;
824 
825     RenderObject* renderer = deprecatedNode()->renderer();
826     if (!renderer)
827         return false;
828 
829     if (renderer->style()->visibility() != VISIBLE)
830         return false;
831 
832     if (renderer->isBR())
833         // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
834         return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
835 
836     if (renderer->isText())
837         return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
838 
839     if (renderer->isSVG()) {
840         // We don't consider SVG elements are contenteditable except for
841         // associated renderer returns isText() true, e.g. RenderSVGInlineText.
842         return false;
843     }
844 
845     if (isRenderedHTMLTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode()))
846         return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
847 
848     if (isHTMLHtmlElement(*m_anchorNode))
849         return false;
850 
851     if (renderer->isRenderBlockFlow()) {
852         if (toRenderBlock(renderer)->logicalHeight() || isHTMLBodyElement(*m_anchorNode)) {
853             if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
854                 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
855             return m_anchorNode->hasEditableStyle() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
856         }
857     } else {
858         LocalFrame* frame = m_anchorNode->document().frame();
859         bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled();
860         return (caretBrowsing || m_anchorNode->hasEditableStyle()) && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
861     }
862 
863     return false;
864 }
865 
inRenderedText() const866 bool Position::inRenderedText() const
867 {
868     if (isNull() || !deprecatedNode()->isTextNode())
869         return false;
870 
871     RenderObject* renderer = deprecatedNode()->renderer();
872     if (!renderer)
873         return false;
874 
875     RenderText *textRenderer = toRenderText(renderer);
876     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
877         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
878             // The offset we're looking for is before this node
879             // this means the offset must be in content that is
880             // not rendered. Return false.
881             return false;
882         }
883         if (box->containsCaretOffset(m_offset))
884             // Return false for offsets inside composed characters.
885             return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
886     }
887 
888     return false;
889 }
890 
isRenderedCharacter() const891 bool Position::isRenderedCharacter() const
892 {
893     if (isNull() || !deprecatedNode()->isTextNode())
894         return false;
895 
896     RenderObject* renderer = deprecatedNode()->renderer();
897     if (!renderer)
898         return false;
899 
900     RenderText* textRenderer = toRenderText(renderer);
901     for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
902         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
903             // The offset we're looking for is before this node
904             // this means the offset must be in content that is
905             // not rendered. Return false.
906             return false;
907         }
908         if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
909             return true;
910     }
911 
912     return false;
913 }
914 
rendersInDifferentPosition(const Position & pos) const915 bool Position::rendersInDifferentPosition(const Position &pos) const
916 {
917     if (isNull() || pos.isNull())
918         return false;
919 
920     RenderObject* renderer = deprecatedNode()->renderer();
921     if (!renderer)
922         return false;
923 
924     RenderObject* posRenderer = pos.deprecatedNode()->renderer();
925     if (!posRenderer)
926         return false;
927 
928     if (renderer->style()->visibility() != VISIBLE ||
929         posRenderer->style()->visibility() != VISIBLE)
930         return false;
931 
932     if (deprecatedNode() == pos.deprecatedNode()) {
933         if (isHTMLBRElement(*deprecatedNode()))
934             return false;
935 
936         if (m_offset == pos.deprecatedEditingOffset())
937             return false;
938 
939         if (!deprecatedNode()->isTextNode() && !pos.deprecatedNode()->isTextNode()) {
940             if (m_offset != pos.deprecatedEditingOffset())
941                 return true;
942         }
943     }
944 
945     if (isHTMLBRElement(*deprecatedNode()) && pos.isCandidate())
946         return true;
947 
948     if (isHTMLBRElement(*pos.deprecatedNode()) && isCandidate())
949         return true;
950 
951     if (!inSameContainingBlockFlowElement(deprecatedNode(), pos.deprecatedNode()))
952         return true;
953 
954     if (deprecatedNode()->isTextNode() && !inRenderedText())
955         return false;
956 
957     if (pos.deprecatedNode()->isTextNode() && !pos.inRenderedText())
958         return false;
959 
960     int thisRenderedOffset = renderedOffset();
961     int posRenderedOffset = pos.renderedOffset();
962 
963     if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
964         return false;
965 
966     int ignoredCaretOffset;
967     InlineBox* b1;
968     getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
969     InlineBox* b2;
970     pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
971 
972     WTF_LOG(Editing, "renderer:               %p [%p]\n", renderer, b1);
973     WTF_LOG(Editing, "thisRenderedOffset:         %d\n", thisRenderedOffset);
974     WTF_LOG(Editing, "posRenderer:            %p [%p]\n", posRenderer, b2);
975     WTF_LOG(Editing, "posRenderedOffset:      %d\n", posRenderedOffset);
976     WTF_LOG(Editing, "node min/max:           %d:%d\n", caretMinOffset(deprecatedNode()), caretMaxOffset(deprecatedNode()));
977     WTF_LOG(Editing, "pos node min/max:       %d:%d\n", caretMinOffset(pos.deprecatedNode()), caretMaxOffset(pos.deprecatedNode()));
978     WTF_LOG(Editing, "----------------------------------------------------------------------\n");
979 
980     if (!b1 || !b2) {
981         return false;
982     }
983 
984     if (b1->root() != b2->root()) {
985         return true;
986     }
987 
988     if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
989         && thisRenderedOffset == caretMaxOffset(deprecatedNode()) && !posRenderedOffset) {
990         return false;
991     }
992 
993     if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
994         && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.deprecatedNode())) {
995         return false;
996     }
997 
998     return true;
999 }
1000 
getInlineBoxAndOffset(EAffinity affinity,InlineBox * & inlineBox,int & caretOffset) const1001 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
1002 {
1003     getInlineBoxAndOffset(affinity, primaryDirection(), inlineBox, caretOffset);
1004 }
1005 
isNonTextLeafChild(RenderObject * object)1006 static bool isNonTextLeafChild(RenderObject* object)
1007 {
1008     if (object->slowFirstChild())
1009         return false;
1010     if (object->isText())
1011         return false;
1012     return true;
1013 }
1014 
searchAheadForBetterMatch(RenderObject * renderer)1015 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
1016 {
1017     RenderBlock* container = renderer->containingBlock();
1018     for (RenderObject* next = renderer->nextInPreOrder(container); next; next = next->nextInPreOrder(container)) {
1019         if (next->isRenderBlock())
1020             return 0;
1021         if (next->isBR())
1022             return 0;
1023         if (isNonTextLeafChild(next))
1024             return 0;
1025         if (next->isText()) {
1026             InlineTextBox* match = 0;
1027             int minOffset = INT_MAX;
1028             for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
1029                 int caretMinOffset = box->caretMinOffset();
1030                 if (caretMinOffset < minOffset) {
1031                     match = box;
1032                     minOffset = caretMinOffset;
1033                 }
1034             }
1035             if (match)
1036                 return match;
1037         }
1038     }
1039     return 0;
1040 }
1041 
downstreamIgnoringEditingBoundaries(Position position)1042 static Position downstreamIgnoringEditingBoundaries(Position position)
1043 {
1044     Position lastPosition;
1045     while (position != lastPosition) {
1046         lastPosition = position;
1047         position = position.downstream(CanCrossEditingBoundary);
1048     }
1049     return position;
1050 }
1051 
upstreamIgnoringEditingBoundaries(Position position)1052 static Position upstreamIgnoringEditingBoundaries(Position position)
1053 {
1054     Position lastPosition;
1055     while (position != lastPosition) {
1056         lastPosition = position;
1057         position = position.upstream(CanCrossEditingBoundary);
1058     }
1059     return position;
1060 }
1061 
getInlineBoxAndOffset(EAffinity affinity,TextDirection primaryDirection,InlineBox * & inlineBox,int & caretOffset) const1062 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
1063 {
1064     caretOffset = deprecatedEditingOffset();
1065     RenderObject* renderer = deprecatedNode()->renderer();
1066 
1067     if (!renderer->isText()) {
1068         inlineBox = 0;
1069         if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isRenderBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
1070             // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in
1071             // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning
1072             // of RenderObject::createVisiblePosition().
1073             Position equivalent = downstreamIgnoringEditingBoundaries(*this);
1074             if (equivalent == *this) {
1075                 equivalent = upstreamIgnoringEditingBoundaries(*this);
1076                 if (equivalent == *this || downstreamIgnoringEditingBoundaries(equivalent) == *this)
1077                     return;
1078             }
1079 
1080             equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1081             return;
1082         }
1083         if (renderer->isBox()) {
1084             inlineBox = toRenderBox(renderer)->inlineBoxWrapper();
1085             if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1086                 return;
1087         }
1088     } else {
1089         RenderText* textRenderer = toRenderText(renderer);
1090 
1091         InlineTextBox* box;
1092         InlineTextBox* candidate = 0;
1093 
1094         for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
1095             int caretMinOffset = box->caretMinOffset();
1096             int caretMaxOffset = box->caretMaxOffset();
1097 
1098             if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1099                 continue;
1100 
1101             if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1102                 inlineBox = box;
1103                 return;
1104             }
1105 
1106             if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
1107                 || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
1108                 || (caretOffset == caretMaxOffset && box->nextLeafChild() && box->nextLeafChild()->isLineBreak()))
1109                 break;
1110 
1111             candidate = box;
1112         }
1113         if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
1114             box = searchAheadForBetterMatch(textRenderer);
1115             if (box)
1116                 caretOffset = box->caretMinOffset();
1117         }
1118         inlineBox = box ? box : candidate;
1119     }
1120 
1121     if (!inlineBox)
1122         return;
1123 
1124     unsigned char level = inlineBox->bidiLevel();
1125 
1126     if (inlineBox->direction() == primaryDirection) {
1127         if (caretOffset == inlineBox->caretRightmostOffset()) {
1128             InlineBox* nextBox = inlineBox->nextLeafChild();
1129             if (!nextBox || nextBox->bidiLevel() >= level)
1130                 return;
1131 
1132             level = nextBox->bidiLevel();
1133             InlineBox* prevBox = inlineBox;
1134             do {
1135                 prevBox = prevBox->prevLeafChild();
1136             } while (prevBox && prevBox->bidiLevel() > level);
1137 
1138             if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
1139                 return;
1140 
1141             // For example, abc 123 ^ CBA
1142             while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1143                 if (nextBox->bidiLevel() < level)
1144                     break;
1145                 inlineBox = nextBox;
1146             }
1147             caretOffset = inlineBox->caretRightmostOffset();
1148         } else {
1149             InlineBox* prevBox = inlineBox->prevLeafChild();
1150             if (!prevBox || prevBox->bidiLevel() >= level)
1151                 return;
1152 
1153             level = prevBox->bidiLevel();
1154             InlineBox* nextBox = inlineBox;
1155             do {
1156                 nextBox = nextBox->nextLeafChild();
1157             } while (nextBox && nextBox->bidiLevel() > level);
1158 
1159             if (nextBox && nextBox->bidiLevel() == level)
1160                 return;
1161 
1162             while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1163                 if (prevBox->bidiLevel() < level)
1164                     break;
1165                 inlineBox = prevBox;
1166             }
1167             caretOffset = inlineBox->caretLeftmostOffset();
1168         }
1169         return;
1170     }
1171 
1172     if (caretOffset == inlineBox->caretLeftmostOffset()) {
1173         InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak();
1174         if (!prevBox || prevBox->bidiLevel() < level) {
1175             // Left edge of a secondary run. Set to the right edge of the entire run.
1176             while (InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1177                 if (nextBox->bidiLevel() < level)
1178                     break;
1179                 inlineBox = nextBox;
1180             }
1181             caretOffset = inlineBox->caretRightmostOffset();
1182         } else if (prevBox->bidiLevel() > level) {
1183             // Right edge of a "tertiary" run. Set to the left edge of that run.
1184             while (InlineBox* tertiaryBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1185                 if (tertiaryBox->bidiLevel() <= level)
1186                     break;
1187                 inlineBox = tertiaryBox;
1188             }
1189             caretOffset = inlineBox->caretLeftmostOffset();
1190         }
1191     } else if (m_anchorNode->selfOrAncestorHasDirAutoAttribute()) {
1192         if (inlineBox->bidiLevel() < level)
1193             caretOffset = inlineBox->caretLeftmostOffset();
1194         else
1195             caretOffset = inlineBox->caretRightmostOffset();
1196     } else {
1197         InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak();
1198         if (!nextBox || nextBox->bidiLevel() < level) {
1199             // Right edge of a secondary run. Set to the left edge of the entire run.
1200             while (InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1201                 if (prevBox->bidiLevel() < level)
1202                     break;
1203                 inlineBox = prevBox;
1204             }
1205             caretOffset = inlineBox->caretLeftmostOffset();
1206         } else if (nextBox->bidiLevel() > level) {
1207             // Left edge of a "tertiary" run. Set to the right edge of that run.
1208             while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1209                 if (tertiaryBox->bidiLevel() <= level)
1210                     break;
1211                 inlineBox = tertiaryBox;
1212             }
1213             caretOffset = inlineBox->caretRightmostOffset();
1214         }
1215     }
1216 }
1217 
primaryDirection() const1218 TextDirection Position::primaryDirection() const
1219 {
1220     TextDirection primaryDirection = LTR;
1221     for (const RenderObject* r = m_anchorNode->renderer(); r; r = r->parent()) {
1222         if (r->isRenderBlockFlow()) {
1223             primaryDirection = r->style()->direction();
1224             break;
1225         }
1226     }
1227 
1228     return primaryDirection;
1229 }
1230 
trace(Visitor * visitor)1231 void Position::trace(Visitor* visitor)
1232 {
1233     visitor->trace(m_anchorNode);
1234 }
1235 
debugPosition(const char * msg) const1236 void Position::debugPosition(const char* msg) const
1237 {
1238     if (isNull())
1239         fprintf(stderr, "Position [%s]: null\n", msg);
1240     else
1241         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, deprecatedNode()->nodeName().utf8().data(), deprecatedNode(), m_offset);
1242 }
1243 
1244 #ifndef NDEBUG
1245 
formatForDebugger(char * buffer,unsigned length) const1246 void Position::formatForDebugger(char* buffer, unsigned length) const
1247 {
1248     StringBuilder result;
1249 
1250     if (isNull())
1251         result.appendLiteral("<null>");
1252     else {
1253         char s[1024];
1254         result.appendLiteral("offset ");
1255         result.appendNumber(m_offset);
1256         result.appendLiteral(" of ");
1257         deprecatedNode()->formatForDebugger(s, sizeof(s));
1258         result.append(s);
1259     }
1260 
1261     strncpy(buffer, result.toString().utf8().data(), length - 1);
1262 }
1263 
showAnchorTypeAndOffset() const1264 void Position::showAnchorTypeAndOffset() const
1265 {
1266     if (m_isLegacyEditingPosition)
1267         fputs("legacy, ", stderr);
1268     switch (anchorType()) {
1269     case PositionIsOffsetInAnchor:
1270         fputs("offset", stderr);
1271         break;
1272     case PositionIsBeforeChildren:
1273         fputs("beforeChildren", stderr);
1274         break;
1275     case PositionIsAfterChildren:
1276         fputs("afterChildren", stderr);
1277         break;
1278     case PositionIsBeforeAnchor:
1279         fputs("before", stderr);
1280         break;
1281     case PositionIsAfterAnchor:
1282         fputs("after", stderr);
1283         break;
1284     }
1285     fprintf(stderr, ", offset:%d\n", m_offset);
1286 }
1287 
showTreeForThis() const1288 void Position::showTreeForThis() const
1289 {
1290     if (anchorNode()) {
1291         anchorNode()->showTreeForThis();
1292         showAnchorTypeAndOffset();
1293     }
1294 }
1295 
1296 #endif
1297 
1298 
1299 
1300 } // namespace blink
1301 
1302 #ifndef NDEBUG
1303 
showTree(const blink::Position & pos)1304 void showTree(const blink::Position& pos)
1305 {
1306     pos.showTreeForThis();
1307 }
1308 
showTree(const blink::Position * pos)1309 void showTree(const blink::Position* pos)
1310 {
1311     if (pos)
1312         pos->showTreeForThis();
1313 }
1314 
1315 #endif
1316