• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "Position.h"
28 
29 #include "CSSComputedStyleDeclaration.h"
30 #include "CString.h"
31 #include "CharacterNames.h"
32 #include "Logging.h"
33 #include "PositionIterator.h"
34 #include "RenderBlock.h"
35 #include "Text.h"
36 #include "TextIterator.h"
37 #include "VisiblePosition.h"
38 #include "htmlediting.h"
39 #include "visible_units.h"
40 #include <stdio.h>
41 
42 namespace WebCore {
43 
44 using namespace HTMLNames;
45 
nextRenderedEditable(Node * node)46 static Node* nextRenderedEditable(Node* node)
47 {
48     while (1) {
49         node = node->nextEditable();
50         if (!node)
51             return 0;
52         RenderObject* renderer = node->renderer();
53         if (!renderer)
54             continue;
55         if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
56             return node;
57     }
58     return 0;
59 }
60 
previousRenderedEditable(Node * node)61 static Node* previousRenderedEditable(Node* node)
62 {
63     while (1) {
64         node = node->previousEditable();
65         if (!node)
66             return 0;
67         RenderObject* renderer = node->renderer();
68         if (!renderer)
69             continue;
70         if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
71             return node;
72     }
73     return 0;
74 }
75 
Position(PassRefPtr<Node> anchorNode,int offset)76 Position::Position(PassRefPtr<Node> anchorNode, int offset)
77     : m_anchorNode(anchorNode)
78     , m_offset(offset)
79     , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
80     , m_isLegacyEditingPosition(true)
81 {
82 }
83 
Position(PassRefPtr<Node> anchorNode,AnchorType anchorType)84 Position::Position(PassRefPtr<Node> anchorNode, AnchorType anchorType)
85     : m_anchorNode(anchorNode)
86     , m_offset(0)
87     , m_anchorType(anchorType)
88     , m_isLegacyEditingPosition(false)
89 {
90     ASSERT(anchorType != PositionIsOffsetInAnchor);
91 }
92 
Position(PassRefPtr<Node> anchorNode,int offset,AnchorType anchorType)93 Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
94     : m_anchorNode(anchorNode)
95     , m_offset(offset)
96     , m_anchorType(anchorType)
97     , m_isLegacyEditingPosition(false)
98 {
99     ASSERT(anchorType == PositionIsOffsetInAnchor);
100 }
101 
moveToPosition(PassRefPtr<Node> node,int offset)102 void Position::moveToPosition(PassRefPtr<Node> node, int offset)
103 {
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 
computeNodeBeforePosition() const151 Node* Position::computeNodeBeforePosition() const
152 {
153     if (!m_anchorNode)
154         return 0;
155 
156     switch (anchorType()) {
157     case PositionIsOffsetInAnchor:
158         return m_anchorNode->childNode(m_offset - 1); // -1 converts to childNode((unsigned)-1) and returns null.
159     case PositionIsBeforeAnchor:
160         return m_anchorNode->previousSibling();
161     case PositionIsAfterAnchor:
162         return m_anchorNode.get();
163     }
164     ASSERT_NOT_REACHED();
165     return 0;
166 }
167 
computeNodeAfterPosition() const168 Node* Position::computeNodeAfterPosition() const
169 {
170     if (!m_anchorNode)
171         return 0;
172 
173     switch (anchorType()) {
174     case PositionIsOffsetInAnchor:
175         return m_anchorNode->childNode(m_offset);
176     case PositionIsBeforeAnchor:
177         return m_anchorNode.get();
178     case PositionIsAfterAnchor:
179         return m_anchorNode->nextSibling();
180     }
181     ASSERT_NOT_REACHED();
182     return 0;
183 }
184 
anchorTypeForLegacyEditingPosition(Node * anchorNode,int offset)185 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
186 {
187     if (anchorNode && editingIgnoresContent(anchorNode)) {
188         if (offset == 0)
189             return Position::PositionIsBeforeAnchor;
190         return Position::PositionIsAfterAnchor;
191     }
192     return Position::PositionIsOffsetInAnchor;
193 }
194 
195 // FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
element() const196 Element* Position::element() const
197 {
198     Node* n = anchorNode();
199     while (n && !n->isElementNode())
200         n = n->parentNode();
201     return static_cast<Element*>(n);
202 }
203 
computedStyle() const204 PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
205 {
206     Element* elem = element();
207     if (!elem)
208         return 0;
209     return WebCore::computedStyle(elem);
210 }
211 
previous(PositionMoveType moveType) const212 Position Position::previous(PositionMoveType moveType) const
213 {
214     Node* n = node();
215     if (!n)
216         return *this;
217 
218     int o = m_offset;
219     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
220     ASSERT(o >= 0);
221 
222     if (o > 0) {
223         Node* child = n->childNode(o - 1);
224         if (child)
225             return lastDeepEditingPositionForNode(child);
226 
227         // There are two reasons child might be 0:
228         //   1) The node is node like a text node that is not an element, and therefore has no children.
229         //      Going backward one character at a time is correct.
230         //   2) The old offset was a bogus offset like (<br>, 1), and there is no child.
231         //      Going from 1 to 0 is correct.
232         switch (moveType) {
233         case CodePoint:
234             return Position(n, o - 1);
235         case Character:
236             return Position(n, uncheckedPreviousOffset(n, o));
237         case BackwardDeletion:
238             return Position(n, uncheckedPreviousOffsetForBackwardDeletion(n, o));
239         }
240     }
241 
242     Node* parent = n->parentNode();
243     if (!parent)
244         return *this;
245 
246     return Position(parent, n->nodeIndex());
247 }
248 
next(PositionMoveType moveType) const249 Position Position::next(PositionMoveType moveType) const
250 {
251     ASSERT(moveType != BackwardDeletion);
252 
253     Node* n = node();
254     if (!n)
255         return *this;
256 
257     int o = m_offset;
258     // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
259     ASSERT(o >= 0);
260 
261     Node* child = n->childNode(o);
262     if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n))) {
263         if (child)
264             return firstDeepEditingPositionForNode(child);
265 
266         // There are two reasons child might be 0:
267         //   1) The node is node like a text node that is not an element, and therefore has no children.
268         //      Going forward one character at a time is correct.
269         //   2) The new offset is a bogus offset like (<br>, 1), and there is no child.
270         //      Going from 0 to 1 is correct.
271         return Position(n, (moveType == Character) ? uncheckedNextOffset(n, o) : o + 1);
272     }
273 
274     Node* parent = n->parentNode();
275     if (!parent)
276         return *this;
277 
278     return Position(parent, n->nodeIndex() + 1);
279 }
280 
uncheckedPreviousOffset(const Node * n,int current)281 int Position::uncheckedPreviousOffset(const Node* n, int current)
282 {
283     return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
284 }
285 
uncheckedPreviousOffsetForBackwardDeletion(const Node * n,int current)286 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
287 {
288     return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
289 }
290 
uncheckedNextOffset(const Node * n,int current)291 int Position::uncheckedNextOffset(const Node* n, int current)
292 {
293     return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
294 }
295 
atFirstEditingPositionForNode() const296 bool Position::atFirstEditingPositionForNode() const
297 {
298     if (isNull())
299         return true;
300     return m_offset <= 0;
301 }
302 
atLastEditingPositionForNode() const303 bool Position::atLastEditingPositionForNode() const
304 {
305     if (isNull())
306         return true;
307     return m_offset >= lastOffsetForEditing(node());
308 }
309 
310 // A position is considered at editing boundary if one of the following is true:
311 // 1. It is the first position in the node and the next visually equivalent position
312 //    is non editable.
313 // 2. It is the last position in the node and the previous visually equivalent position
314 //    is non editable.
315 // 3. It is an editable position and both the next and previous visually equivalent
316 //    positions are both non editable.
atEditingBoundary() const317 bool Position::atEditingBoundary() const
318 {
319     Position nextPosition = downstream(CanCrossEditingBoundary);
320     if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.node()->isContentEditable())
321         return true;
322 
323     Position prevPosition = upstream(CanCrossEditingBoundary);
324     if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.node()->isContentEditable())
325         return true;
326 
327     return nextPosition.isNotNull() && !nextPosition.node()->isContentEditable()
328         && prevPosition.isNotNull() && !prevPosition.node()->isContentEditable();
329 }
330 
atStartOfTree() const331 bool Position::atStartOfTree() const
332 {
333     if (isNull())
334         return true;
335     return !node()->parentNode() && m_offset <= 0;
336 }
337 
atEndOfTree() const338 bool Position::atEndOfTree() const
339 {
340     if (isNull())
341         return true;
342     return !node()->parentNode() && m_offset >= lastOffsetForEditing(node());
343 }
344 
renderedOffset() const345 int Position::renderedOffset() const
346 {
347     if (!node()->isTextNode())
348         return m_offset;
349 
350     if (!node()->renderer())
351         return m_offset;
352 
353     int result = 0;
354     RenderText *textRenderer = toRenderText(node()->renderer());
355     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
356         int start = box->start();
357         int end = box->start() + box->len();
358         if (m_offset < start)
359             return result;
360         if (m_offset <= end) {
361             result += m_offset - start;
362             return result;
363         }
364         result += box->len();
365     }
366     return result;
367 }
368 
369 // return first preceding DOM position rendered at a different location, or "this"
previousCharacterPosition(EAffinity affinity) const370 Position Position::previousCharacterPosition(EAffinity affinity) const
371 {
372     if (isNull())
373         return Position();
374 
375     Node *fromRootEditableElement = node()->rootEditableElement();
376 
377     bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
378     bool rendered = isCandidate();
379 
380     Position currentPos = *this;
381     while (!currentPos.atStartOfTree()) {
382         currentPos = currentPos.previous();
383 
384         if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
385             return *this;
386 
387         if (atStartOfLine || !rendered) {
388             if (currentPos.isCandidate())
389                 return currentPos;
390         } else if (rendersInDifferentPosition(currentPos))
391             return currentPos;
392     }
393 
394     return *this;
395 }
396 
397 // return first following position rendered at a different location, or "this"
nextCharacterPosition(EAffinity affinity) const398 Position Position::nextCharacterPosition(EAffinity affinity) const
399 {
400     if (isNull())
401         return Position();
402 
403     Node *fromRootEditableElement = node()->rootEditableElement();
404 
405     bool atEndOfLine = isEndOfLine(VisiblePosition(*this, affinity));
406     bool rendered = isCandidate();
407 
408     Position currentPos = *this;
409     while (!currentPos.atEndOfTree()) {
410         currentPos = currentPos.next();
411 
412         if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
413             return *this;
414 
415         if (atEndOfLine || !rendered) {
416             if (currentPos.isCandidate())
417                 return currentPos;
418         } else if (rendersInDifferentPosition(currentPos))
419             return currentPos;
420     }
421 
422     return *this;
423 }
424 
425 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
426 // If true, adjacent candidates are visually distinct.
427 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
428 // FIXME: Share code with isCandidate, if possible.
endsOfNodeAreVisuallyDistinctPositions(Node * node)429 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
430 {
431     if (!node || !node->renderer())
432         return false;
433 
434     if (!node->renderer()->isInline())
435         return true;
436 
437     // Don't include inline tables.
438     if (node->hasTagName(tableTag))
439         return false;
440 
441     // There is a VisiblePosition inside an empty inline-block container.
442     return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild();
443 }
444 
enclosingVisualBoundary(Node * node)445 static Node* enclosingVisualBoundary(Node* node)
446 {
447     while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
448         node = node->parentNode();
449 
450     return node;
451 }
452 
453 // upstream() and downstream() want to return positions that are either in a
454 // text node or at just before a non-text node.  This method checks for that.
isStreamer(const PositionIterator & pos)455 static bool isStreamer(const PositionIterator& pos)
456 {
457     if (!pos.node())
458         return true;
459 
460     if (isAtomicNode(pos.node()))
461         return true;
462 
463     return pos.atStartOfNode();
464 }
465 
466 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
467 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
468 // that map to the VisiblePosition between 'b' and the space.  This function will return the left candidate
469 // and downstream() will return the right one.
470 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
471 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
upstream(EditingBoundaryCrossingRule rule) const472 Position Position::upstream(EditingBoundaryCrossingRule rule) const
473 {
474     Node* startNode = node();
475     if (!startNode)
476         return Position();
477 
478     // iterate backward from there, looking for a qualified position
479     Node* boundary = enclosingVisualBoundary(startNode);
480     PositionIterator lastVisible = *this;
481     PositionIterator currentPos = lastVisible;
482     bool startEditable = startNode->isContentEditable();
483     Node* lastNode = startNode;
484     bool boundaryCrossed = false;
485     for (; !currentPos.atStart(); currentPos.decrement()) {
486         Node* currentNode = currentPos.node();
487 
488         // Don't check for an editability change if we haven't moved to a different node,
489         // to avoid the expense of computing isContentEditable().
490         if (currentNode != lastNode) {
491             // Don't change editability.
492             bool currentEditable = currentNode->isContentEditable();
493             if (startEditable != currentEditable) {
494                 if (rule == CannotCrossEditingBoundary)
495                     break;
496                 boundaryCrossed = true;
497             }
498             lastNode = currentNode;
499         }
500 
501         // If we've moved to a position that is visually distinct, return the last saved position. There
502         // is code below that terminates early if we're *about* to move to a visually distinct position.
503         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
504             return lastVisible;
505 
506         // skip position in unrendered or invisible node
507         RenderObject* renderer = currentNode->renderer();
508         if (!renderer || renderer->style()->visibility() != VISIBLE)
509             continue;
510 
511         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
512             lastVisible = currentPos;
513             break;
514         }
515 
516         // track last visible streamer position
517         if (isStreamer(currentPos))
518             lastVisible = currentPos;
519 
520         // Don't move past a position that is visually distinct.  We could rely on code above to terminate and
521         // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
522         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
523             return lastVisible;
524 
525         // Return position after tables and nodes which have content that can be ignored.
526         if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
527             if (currentPos.atEndOfNode())
528                 return lastDeepEditingPositionForNode(currentNode);
529             continue;
530         }
531 
532         // return current position if it is in rendered text
533         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
534             if (currentNode != startNode) {
535                 // This assertion fires in layout tests in the case-transform.html test because
536                 // of a mix-up between offsets in the text in the DOM tree with text in the
537                 // render tree which can have a different length due to case transformation.
538                 // Until we resolve that, disable this so we can run the layout tests!
539                 //ASSERT(currentOffset >= renderer->caretMaxOffset());
540                 return Position(currentNode, renderer->caretMaxOffset());
541             }
542 
543             unsigned textOffset = currentPos.offsetInLeafNode();
544             RenderText* textRenderer = toRenderText(renderer);
545             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
546             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
547                 if (textOffset <= box->start() + box->len()) {
548                     if (textOffset > box->start())
549                         return currentPos;
550                     continue;
551                 }
552 
553                 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
554                     continue;
555 
556                 // The text continues on the next line only if the last text box is not on this line and
557                 // none of the boxes on this line have a larger start offset.
558 
559                 bool continuesOnNextLine = true;
560                 InlineBox* otherBox = box;
561                 while (continuesOnNextLine) {
562                     otherBox = otherBox->nextLeafChild();
563                     if (!otherBox)
564                         break;
565                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
566                         continuesOnNextLine = false;
567                 }
568 
569                 otherBox = box;
570                 while (continuesOnNextLine) {
571                     otherBox = otherBox->prevLeafChild();
572                     if (!otherBox)
573                         break;
574                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
575                         continuesOnNextLine = false;
576                 }
577 
578                 if (continuesOnNextLine)
579                     return currentPos;
580             }
581         }
582     }
583 
584     return lastVisible;
585 }
586 
587 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
588 // For example, for the text node "foo     bar" where whitespace is collapsible, there are two candidates
589 // that map to the VisiblePosition between 'b' and the space.  This function will return the right candidate
590 // and upstream() will return the left one.
591 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
592 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
downstream(EditingBoundaryCrossingRule rule) const593 Position Position::downstream(EditingBoundaryCrossingRule rule) const
594 {
595     Node* startNode = node();
596     if (!startNode)
597         return Position();
598 
599     // iterate forward from there, looking for a qualified position
600     Node* boundary = enclosingVisualBoundary(startNode);
601     PositionIterator lastVisible = *this;
602     PositionIterator currentPos = lastVisible;
603     bool startEditable = startNode->isContentEditable();
604     Node* lastNode = startNode;
605     bool boundaryCrossed = false;
606     for (; !currentPos.atEnd(); currentPos.increment()) {
607         Node* currentNode = currentPos.node();
608 
609         // Don't check for an editability change if we haven't moved to a different node,
610         // to avoid the expense of computing isContentEditable().
611         if (currentNode != lastNode) {
612             // Don't change editability.
613             bool currentEditable = currentNode->isContentEditable();
614             if (startEditable != currentEditable) {
615                 if (rule == CannotCrossEditingBoundary)
616                     break;
617                 boundaryCrossed = true;
618             }
619 
620             lastNode = currentNode;
621         }
622 
623         // stop before going above the body, up into the head
624         // return the last visible streamer position
625         if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode())
626             break;
627 
628         // Do not move to a visually distinct position.
629         if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
630             return lastVisible;
631         // Do not move past a visually disinct position.
632         // Note: The first position after the last in a node whose ends are visually distinct
633         // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
634         if (boundary && boundary->parentNode() == currentNode)
635             return lastVisible;
636 
637         // skip position in unrendered or invisible node
638         RenderObject* renderer = currentNode->renderer();
639         if (!renderer || renderer->style()->visibility() != VISIBLE)
640             continue;
641 
642         if (rule == CanCrossEditingBoundary && boundaryCrossed) {
643             lastVisible = currentPos;
644             break;
645         }
646 
647         // track last visible streamer position
648         if (isStreamer(currentPos))
649             lastVisible = currentPos;
650 
651         // Return position before tables and nodes which have content that can be ignored.
652         if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
653             if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
654                 return Position(currentNode, renderer->caretMinOffset());
655             continue;
656         }
657 
658         // return current position if it is in rendered text
659         if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
660             if (currentNode != startNode) {
661                 ASSERT(currentPos.atStartOfNode());
662                 return Position(currentNode, renderer->caretMinOffset());
663             }
664 
665             unsigned textOffset = currentPos.offsetInLeafNode();
666             RenderText* textRenderer = toRenderText(renderer);
667             InlineTextBox* lastTextBox = textRenderer->lastTextBox();
668             for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
669                 if (textOffset <= box->end()) {
670                     if (textOffset >= box->start())
671                         return currentPos;
672                     continue;
673                 }
674 
675                 if (box == lastTextBox || textOffset != box->start() + box->len())
676                     continue;
677 
678                 // The text continues on the next line only if the last text box is not on this line and
679                 // none of the boxes on this line have a larger start offset.
680 
681                 bool continuesOnNextLine = true;
682                 InlineBox* otherBox = box;
683                 while (continuesOnNextLine) {
684                     otherBox = otherBox->nextLeafChild();
685                     if (!otherBox)
686                         break;
687                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
688                         continuesOnNextLine = false;
689                 }
690 
691                 otherBox = box;
692                 while (continuesOnNextLine) {
693                     otherBox = otherBox->prevLeafChild();
694                     if (!otherBox)
695                         break;
696                     if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
697                         continuesOnNextLine = false;
698                 }
699 
700                 if (continuesOnNextLine)
701                     return currentPos;
702             }
703         }
704     }
705 
706     return lastVisible;
707 }
708 
hasRenderedNonAnonymousDescendantsWithHeight(RenderObject * renderer)709 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
710 {
711     RenderObject* stop = renderer->nextInPreOrderAfterChildren();
712     for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
713         if (o->node()) {
714             if ((o->isText() && toRenderText(o)->linesBoundingBox().height()) ||
715                 (o->isBox() && toRenderBox(o)->borderBoundingBox().height()))
716                 return true;
717         }
718     return false;
719 }
720 
nodeIsUserSelectNone(Node * node)721 bool Position::nodeIsUserSelectNone(Node* node)
722 {
723     return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE;
724 }
725 
isCandidate() const726 bool Position::isCandidate() const
727 {
728     if (isNull())
729         return false;
730 
731     RenderObject *renderer = node()->renderer();
732     if (!renderer)
733         return false;
734 
735     if (renderer->style()->visibility() != VISIBLE)
736         return false;
737 
738     if (renderer->isBR())
739         return m_offset == 0 && !nodeIsUserSelectNone(node()->parent());
740 
741     if (renderer->isText())
742         return inRenderedText() && !nodeIsUserSelectNone(node());
743 
744     if (isTableElement(node()) || editingIgnoresContent(node()))
745         return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(node()->parent());
746 
747     if (m_anchorNode->hasTagName(htmlTag))
748         return false;
749 
750     if (renderer->isBlockFlow()) {
751         if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
752             if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
753                 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(node());
754             return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(node()) && atEditingBoundary();
755         }
756     } else
757         return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(node()) && atEditingBoundary();
758 
759     return false;
760 }
761 
inRenderedText() const762 bool Position::inRenderedText() const
763 {
764     if (isNull() || !node()->isTextNode())
765         return false;
766 
767     RenderObject *renderer = node()->renderer();
768     if (!renderer)
769         return false;
770 
771     RenderText *textRenderer = toRenderText(renderer);
772     for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
773         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
774             // The offset we're looking for is before this node
775             // this means the offset must be in content that is
776             // not rendered. Return false.
777             return false;
778         }
779         if (box->containsCaretOffset(m_offset))
780             // Return false for offsets inside composed characters.
781             return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
782     }
783 
784     return false;
785 }
786 
caretMaxRenderedOffset(const Node * n)787 static unsigned caretMaxRenderedOffset(const Node* n)
788 {
789     RenderObject* r = n->renderer();
790     if (r)
791         return r->caretMaxRenderedOffset();
792 
793     if (n->isCharacterDataNode())
794         return static_cast<const CharacterData*>(n)->length();
795     return 1;
796 }
797 
isRenderedCharacter() const798 bool Position::isRenderedCharacter() const
799 {
800     if (isNull() || !node()->isTextNode())
801         return false;
802 
803     RenderObject* renderer = node()->renderer();
804     if (!renderer)
805         return false;
806 
807     RenderText* textRenderer = toRenderText(renderer);
808     for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
809         if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
810             // The offset we're looking for is before this node
811             // this means the offset must be in content that is
812             // not rendered. Return false.
813             return false;
814         }
815         if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
816             return true;
817     }
818 
819     return false;
820 }
821 
rendersInDifferentPosition(const Position & pos) const822 bool Position::rendersInDifferentPosition(const Position &pos) const
823 {
824     if (isNull() || pos.isNull())
825         return false;
826 
827     RenderObject *renderer = node()->renderer();
828     if (!renderer)
829         return false;
830 
831     RenderObject *posRenderer = pos.node()->renderer();
832     if (!posRenderer)
833         return false;
834 
835     if (renderer->style()->visibility() != VISIBLE ||
836         posRenderer->style()->visibility() != VISIBLE)
837         return false;
838 
839     if (node() == pos.node()) {
840         if (node()->hasTagName(brTag))
841             return false;
842 
843         if (m_offset == pos.deprecatedEditingOffset())
844             return false;
845 
846         if (!node()->isTextNode() && !pos.node()->isTextNode()) {
847             if (m_offset != pos.deprecatedEditingOffset())
848                 return true;
849         }
850     }
851 
852     if (node()->hasTagName(brTag) && pos.isCandidate())
853         return true;
854 
855     if (pos.node()->hasTagName(brTag) && isCandidate())
856         return true;
857 
858     if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
859         return true;
860 
861     if (node()->isTextNode() && !inRenderedText())
862         return false;
863 
864     if (pos.node()->isTextNode() && !pos.inRenderedText())
865         return false;
866 
867     int thisRenderedOffset = renderedOffset();
868     int posRenderedOffset = pos.renderedOffset();
869 
870     if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
871         return false;
872 
873     int ignoredCaretOffset;
874     InlineBox* b1;
875     getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
876     InlineBox* b2;
877     pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
878 
879     LOG(Editing, "renderer:               %p [%p]\n", renderer, b1);
880     LOG(Editing, "thisRenderedOffset:         %d\n", thisRenderedOffset);
881     LOG(Editing, "posRenderer:            %p [%p]\n", posRenderer, b2);
882     LOG(Editing, "posRenderedOffset:      %d\n", posRenderedOffset);
883     LOG(Editing, "node min/max:           %d:%d\n", caretMinOffset(node()), caretMaxRenderedOffset(node()));
884     LOG(Editing, "pos node min/max:       %d:%d\n", caretMinOffset(pos.node()), caretMaxRenderedOffset(pos.node()));
885     LOG(Editing, "----------------------------------------------------------------------\n");
886 
887     if (!b1 || !b2) {
888         return false;
889     }
890 
891     if (b1->root() != b2->root()) {
892         return true;
893     }
894 
895     if (nextRenderedEditable(node()) == pos.node() &&
896         thisRenderedOffset == (int)caretMaxRenderedOffset(node()) && posRenderedOffset == 0) {
897         return false;
898     }
899 
900     if (previousRenderedEditable(node()) == pos.node() &&
901         thisRenderedOffset == 0 && posRenderedOffset == (int)caretMaxRenderedOffset(pos.node())) {
902         return false;
903     }
904 
905     return true;
906 }
907 
908 // This assumes that it starts in editable content.
leadingWhitespacePosition(EAffinity affinity,bool considerNonCollapsibleWhitespace) const909 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
910 {
911     ASSERT(isEditablePosition(*this));
912     if (isNull())
913         return Position();
914 
915     if (upstream().node()->hasTagName(brTag))
916         return Position();
917 
918     Position prev = previousCharacterPosition(affinity);
919     if (prev != *this && prev.node()->inSameContainingBlockFlowElement(node()) && prev.node()->isTextNode()) {
920         String string = static_cast<Text *>(prev.node())->data();
921         UChar c = string[prev.deprecatedEditingOffset()];
922         if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
923             if (isEditablePosition(prev))
924                 return prev;
925     }
926 
927     return Position();
928 }
929 
930 // This assumes that it starts in editable content.
trailingWhitespacePosition(EAffinity,bool considerNonCollapsibleWhitespace) const931 Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
932 {
933     ASSERT(isEditablePosition(*this));
934     if (isNull())
935         return Position();
936 
937     VisiblePosition v(*this);
938     UChar c = v.characterAfter();
939     // The space must not be in another paragraph and it must be editable.
940     if (!isEndOfParagraph(v) && v.next(true).isNotNull())
941         if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
942             return *this;
943 
944     return Position();
945 }
946 
getInlineBoxAndOffset(EAffinity affinity,InlineBox * & inlineBox,int & caretOffset) const947 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
948 {
949     TextDirection primaryDirection = LTR;
950     for (RenderObject* r = node()->renderer(); r; r = r->parent()) {
951         if (r->isBlockFlow()) {
952             primaryDirection = r->style()->direction();
953             break;
954         }
955     }
956     getInlineBoxAndOffset(affinity, primaryDirection, inlineBox, caretOffset);
957 }
958 
isNonTextLeafChild(RenderObject * object)959 static bool isNonTextLeafChild(RenderObject* object)
960 {
961     if (object->firstChild())
962         return false;
963     if (object->isText())
964         return false;
965     return true;
966 }
967 
searchAheadForBetterMatch(RenderObject * renderer)968 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
969 {
970     RenderBlock* container = renderer->containingBlock();
971     RenderObject* next = renderer;
972     while ((next = next->nextInPreOrder(container))) {
973         if (next->isRenderBlock())
974             return 0;
975         if (next->isBR())
976             return 0;
977         if (isNonTextLeafChild(next))
978             return 0;
979         if (next->isText()) {
980             InlineTextBox* match = 0;
981             int minOffset = INT_MAX;
982             for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
983                 int caretMinOffset = box->caretMinOffset();
984                 if (caretMinOffset < minOffset) {
985                     match = box;
986                     minOffset = caretMinOffset;
987                 }
988             }
989             if (match)
990                 return match;
991         }
992     }
993     return 0;
994 }
995 
getInlineBoxAndOffset(EAffinity affinity,TextDirection primaryDirection,InlineBox * & inlineBox,int & caretOffset) const996 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
997 {
998     caretOffset = m_offset;
999     RenderObject* renderer = node()->renderer();
1000 
1001     if (!renderer->isText()) {
1002         if (!renderer->isRenderButton() && renderer->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
1003             bool lastPosition = caretOffset == lastOffsetInNode(node());
1004             Node* startNode = lastPosition ? node()->childNode(caretOffset - 1) : node()->childNode(caretOffset);
1005             while (startNode && (!startNode->renderer() || (startNode->isTextNode() && toRenderText(startNode->renderer())->isAllCollapsibleWhitespace())))
1006                 startNode = (lastPosition)? startNode->previousSibling(): startNode->nextSibling();
1007             if (startNode) {
1008                 Position pos(startNode, 0);
1009                 pos = pos.downstream(CanCrossEditingBoundary);
1010                 pos.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1011                 if (lastPosition && inlineBox)
1012                     caretOffset = inlineBox->caretMaxOffset();
1013                 return;
1014             }
1015         }
1016         inlineBox = 0;
1017         if (renderer->isBox()) {
1018             inlineBox = toRenderBox(renderer)->inlineBoxWrapper();
1019             if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1020                 return;
1021         } else if (node()->isContentEditable()) {
1022             Position pos = positionInParentBeforeNode(node()).upstream();
1023             pos.getInlineBoxAndOffset(DOWNSTREAM, primaryDirection, inlineBox, caretOffset);
1024             return;
1025         }
1026     } else {
1027         RenderText* textRenderer = toRenderText(renderer);
1028 
1029         InlineTextBox* box;
1030         InlineTextBox* candidate = 0;
1031 
1032         for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
1033             int caretMinOffset = box->caretMinOffset();
1034             int caretMaxOffset = box->caretMaxOffset();
1035 
1036             if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1037                 continue;
1038 
1039             if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1040                 inlineBox = box;
1041                 return;
1042             }
1043 
1044             if ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
1045                 break;
1046 
1047             candidate = box;
1048         }
1049         if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
1050             box = searchAheadForBetterMatch(textRenderer);
1051             if (box)
1052                 caretOffset = box->caretMinOffset();
1053         }
1054         inlineBox = box ? box : candidate;
1055     }
1056 
1057     if (!inlineBox)
1058         return;
1059 
1060     unsigned char level = inlineBox->bidiLevel();
1061 
1062     if (inlineBox->direction() == primaryDirection) {
1063         if (caretOffset == inlineBox->caretRightmostOffset()) {
1064             InlineBox* nextBox = inlineBox->nextLeafChild();
1065             if (!nextBox || nextBox->bidiLevel() >= level)
1066                 return;
1067 
1068             level = nextBox->bidiLevel();
1069             InlineBox* prevBox = inlineBox;
1070             do {
1071                 prevBox = prevBox->prevLeafChild();
1072             } while (prevBox && prevBox->bidiLevel() > level);
1073 
1074             if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
1075                 return;
1076 
1077             // For example, abc 123 ^ CBA
1078             while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1079                 if (nextBox->bidiLevel() < level)
1080                     break;
1081                 inlineBox = nextBox;
1082             }
1083             caretOffset = inlineBox->caretRightmostOffset();
1084         } else {
1085             InlineBox* prevBox = inlineBox->prevLeafChild();
1086             if (!prevBox || prevBox->bidiLevel() >= level)
1087                 return;
1088 
1089             level = prevBox->bidiLevel();
1090             InlineBox* nextBox = inlineBox;
1091             do {
1092                 nextBox = nextBox->nextLeafChild();
1093             } while (nextBox && nextBox->bidiLevel() > level);
1094 
1095             if (nextBox && nextBox->bidiLevel() == level)
1096                 return;
1097 
1098             while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1099                 if (prevBox->bidiLevel() < level)
1100                     break;
1101                 inlineBox = prevBox;
1102             }
1103             caretOffset = inlineBox->caretLeftmostOffset();
1104         }
1105         return;
1106     }
1107 
1108     if (caretOffset == inlineBox->caretLeftmostOffset()) {
1109         InlineBox* prevBox = inlineBox->prevLeafChild();
1110         if (!prevBox || prevBox->bidiLevel() < level) {
1111             // Left edge of a secondary run. Set to the right edge of the entire run.
1112             while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1113                 if (nextBox->bidiLevel() < level)
1114                     break;
1115                 inlineBox = nextBox;
1116             }
1117             caretOffset = inlineBox->caretRightmostOffset();
1118         } else if (prevBox->bidiLevel() > level) {
1119             // Right edge of a "tertiary" run. Set to the left edge of that run.
1120             while (InlineBox* tertiaryBox = inlineBox->prevLeafChild()) {
1121                 if (tertiaryBox->bidiLevel() <= level)
1122                     break;
1123                 inlineBox = tertiaryBox;
1124             }
1125             caretOffset = inlineBox->caretLeftmostOffset();
1126         }
1127     } else {
1128         InlineBox* nextBox = inlineBox->nextLeafChild();
1129         if (!nextBox || nextBox->bidiLevel() < level) {
1130             // Right edge of a secondary run. Set to the left edge of the entire run.
1131             while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1132                 if (prevBox->bidiLevel() < level)
1133                     break;
1134                 inlineBox = prevBox;
1135             }
1136             caretOffset = inlineBox->caretLeftmostOffset();
1137         } else if (nextBox->bidiLevel() > level) {
1138             // Left edge of a "tertiary" run. Set to the right edge of that run.
1139             while (InlineBox* tertiaryBox = inlineBox->nextLeafChild()) {
1140                 if (tertiaryBox->bidiLevel() <= level)
1141                     break;
1142                 inlineBox = tertiaryBox;
1143             }
1144             caretOffset = inlineBox->caretRightmostOffset();
1145         }
1146     }
1147 }
1148 
debugPosition(const char * msg) const1149 void Position::debugPosition(const char* msg) const
1150 {
1151     if (isNull())
1152         fprintf(stderr, "Position [%s]: null\n", msg);
1153     else
1154         fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().utf8().data(), node(), m_offset);
1155 }
1156 
1157 #ifndef NDEBUG
1158 
formatForDebugger(char * buffer,unsigned length) const1159 void Position::formatForDebugger(char* buffer, unsigned length) const
1160 {
1161     String result;
1162 
1163     if (isNull())
1164         result = "<null>";
1165     else {
1166         char s[1024];
1167         result += "offset ";
1168         result += String::number(m_offset);
1169         result += " of ";
1170         node()->formatForDebugger(s, sizeof(s));
1171         result += s;
1172     }
1173 
1174     strncpy(buffer, result.utf8().data(), length - 1);
1175 }
1176 
showTreeForThis() const1177 void Position::showTreeForThis() const
1178 {
1179     if (node()) {
1180         node()->showTreeForThis();
1181         fprintf(stderr, "offset: %d\n", m_offset);
1182     }
1183 }
1184 
1185 #endif
1186 
1187 
1188 
1189 } // namespace WebCore
1190 
1191 #ifndef NDEBUG
1192 
showTree(const WebCore::Position & pos)1193 void showTree(const WebCore::Position& pos)
1194 {
1195     pos.showTreeForThis();
1196 }
1197 
showTree(const WebCore::Position * pos)1198 void showTree(const WebCore::Position* pos)
1199 {
1200     if (pos)
1201         pos->showTreeForThis();
1202 }
1203 
1204 #endif
1205