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