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