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