• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 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 "VisiblePosition.h"
28 
29 #include "Document.h"
30 #include "FloatQuad.h"
31 #include "HTMLElement.h"
32 #include "HTMLNames.h"
33 #include "InlineTextBox.h"
34 #include "Logging.h"
35 #include "Range.h"
36 #include "RootInlineBox.h"
37 #include "Text.h"
38 #include "htmlediting.h"
39 #include "visible_units.h"
40 #include <stdio.h>
41 #include <wtf/text/CString.h>
42 
43 namespace WebCore {
44 
45 using namespace HTMLNames;
46 
VisiblePosition(const Position & pos,EAffinity affinity)47 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
48 {
49     init(pos, affinity);
50 }
51 
init(const Position & position,EAffinity affinity)52 void VisiblePosition::init(const Position& position, EAffinity affinity)
53 {
54     m_affinity = affinity;
55 
56     m_deepPosition = canonicalPosition(position);
57 
58     // When not at a line wrap, make sure to end up with DOWNSTREAM affinity.
59     if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this)))
60         m_affinity = DOWNSTREAM;
61 }
62 
next(EditingBoundaryCrossingRule rule) const63 VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
64 {
65     // FIXME: Support CanSkipEditingBoundary
66     ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
67     VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
68 
69     if (rule == CanCrossEditingBoundary)
70         return next;
71 
72     return honorEditableBoundaryAtOrAfter(next);
73 }
74 
previous(EditingBoundaryCrossingRule rule) const75 VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
76 {
77     // FIXME: Support CanSkipEditingBoundary
78     ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
79     // find first previous DOM position that is visible
80     Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
81 
82     // return null visible position if there is no previous visible position
83     if (pos.atStartOfTree())
84         return VisiblePosition();
85 
86     VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
87     ASSERT(prev != *this);
88 
89 #ifndef NDEBUG
90     // we should always be able to make the affinity DOWNSTREAM, because going previous from an
91     // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
92     if (prev.isNotNull() && m_affinity == UPSTREAM) {
93         VisiblePosition temp = prev;
94         temp.setAffinity(UPSTREAM);
95         ASSERT(inSameLine(temp, prev));
96     }
97 #endif
98 
99     if (rule == CanCrossEditingBoundary)
100         return prev;
101 
102     return honorEditableBoundaryAtOrBefore(prev);
103 }
104 
leftVisuallyDistinctCandidate() const105 Position VisiblePosition::leftVisuallyDistinctCandidate() const
106 {
107     Position p = m_deepPosition;
108     if (p.isNull())
109         return Position();
110 
111     Position downstreamStart = p.downstream();
112     TextDirection primaryDirection = p.primaryDirection();
113 
114     while (true) {
115         InlineBox* box;
116         int offset;
117         p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
118         if (!box)
119             return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
120 
121         RenderObject* renderer = box->renderer();
122 
123         while (true) {
124             if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
125                 return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
126 
127             offset = box->isLeftToRightDirection() ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
128 
129             int caretMinOffset = box->caretMinOffset();
130             int caretMaxOffset = box->caretMaxOffset();
131 
132             if (offset > caretMinOffset && offset < caretMaxOffset)
133                 break;
134 
135             if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) {
136                 // Overshot to the left.
137                 InlineBox* prevBox = box->prevLeafChild();
138                 if (!prevBox) {
139                     Position positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
140                     if (positionOnLeft.isNull())
141                         return Position();
142 
143                     InlineBox* boxOnLeft;
144                     int offsetOnLeft;
145                     positionOnLeft.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnLeft, offsetOnLeft);
146                     if (boxOnLeft && boxOnLeft->root() == box->root())
147                         return Position();
148                     return positionOnLeft;
149                 }
150 
151                 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
152                 box = prevBox;
153                 renderer = box->renderer();
154                 offset = prevBox->caretRightmostOffset();
155                 continue;
156             }
157 
158             ASSERT(offset == box->caretLeftmostOffset());
159 
160             unsigned char level = box->bidiLevel();
161             InlineBox* prevBox = box->prevLeafChild();
162 
163             if (box->direction() == primaryDirection) {
164                 if (!prevBox) {
165                     InlineBox* logicalStart = 0;
166                     if (primaryDirection == LTR ? box->root()->getLogicalStartBoxWithNode(logicalStart) : box->root()->getLogicalEndBoxWithNode(logicalStart)) {
167                         box = logicalStart;
168                         renderer = box->renderer();
169                         offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
170                     }
171                     break;
172                 }
173                 if (prevBox->bidiLevel() >= level)
174                     break;
175 
176                 level = prevBox->bidiLevel();
177 
178                 InlineBox* nextBox = box;
179                 do {
180                     nextBox = nextBox->nextLeafChild();
181                 } while (nextBox && nextBox->bidiLevel() > level);
182 
183                 if (nextBox && nextBox->bidiLevel() == level)
184                     break;
185 
186                 box = prevBox;
187                 renderer = box->renderer();
188                 offset = box->caretRightmostOffset();
189                 if (box->direction() == primaryDirection)
190                     break;
191                 continue;
192             }
193 
194             if (prevBox) {
195                 box = prevBox;
196                 renderer = box->renderer();
197                 offset = box->caretRightmostOffset();
198                 if (box->bidiLevel() > level) {
199                     do {
200                         prevBox = prevBox->prevLeafChild();
201                     } while (prevBox && prevBox->bidiLevel() > level);
202 
203                     if (!prevBox || prevBox->bidiLevel() < level)
204                         continue;
205                 }
206             } else {
207                 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
208                 while (true) {
209                     while (InlineBox* nextBox = box->nextLeafChild()) {
210                         if (nextBox->bidiLevel() < level)
211                             break;
212                         box = nextBox;
213                     }
214                     if (box->bidiLevel() == level)
215                         break;
216                     level = box->bidiLevel();
217                     while (InlineBox* prevBox = box->prevLeafChild()) {
218                         if (prevBox->bidiLevel() < level)
219                             break;
220                         box = prevBox;
221                     }
222                     if (box->bidiLevel() == level)
223                         break;
224                     level = box->bidiLevel();
225                 }
226                 renderer = box->renderer();
227                 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
228             }
229             break;
230         }
231 
232         p = Position(renderer->node(), offset);
233 
234         if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
235             return p;
236     }
237 }
238 
left(bool stayInEditableContent) const239 VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
240 {
241     Position pos = leftVisuallyDistinctCandidate();
242     // FIXME: Why can't we move left from the last position in a tree?
243     if (pos.atStartOfTree() || pos.atEndOfTree())
244         return VisiblePosition();
245 
246     VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
247     ASSERT(left != *this);
248 
249     if (!stayInEditableContent)
250         return left;
251 
252     // FIXME: This may need to do something different from "before".
253     return honorEditableBoundaryAtOrBefore(left);
254 }
255 
rightVisuallyDistinctCandidate() const256 Position VisiblePosition::rightVisuallyDistinctCandidate() const
257 {
258     Position p = m_deepPosition;
259     if (p.isNull())
260         return Position();
261 
262     Position downstreamStart = p.downstream();
263     TextDirection primaryDirection = p.primaryDirection();
264 
265     while (true) {
266         InlineBox* box;
267         int offset;
268         p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
269         if (!box)
270             return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
271 
272         RenderObject* renderer = box->renderer();
273 
274         while (true) {
275             if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
276                 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
277 
278             offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
279 
280             int caretMinOffset = box->caretMinOffset();
281             int caretMaxOffset = box->caretMaxOffset();
282 
283             if (offset > caretMinOffset && offset < caretMaxOffset)
284                 break;
285 
286             if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) {
287                 // Overshot to the right.
288                 InlineBox* nextBox = box->nextLeafChild();
289                 if (!nextBox) {
290                     Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
291                     if (positionOnRight.isNull())
292                         return Position();
293 
294                     InlineBox* boxOnRight;
295                     int offsetOnRight;
296                     positionOnRight.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnRight, offsetOnRight);
297                     if (boxOnRight && boxOnRight->root() == box->root())
298                         return Position();
299                     return positionOnRight;
300                 }
301 
302                 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
303                 box = nextBox;
304                 renderer = box->renderer();
305                 offset = nextBox->caretLeftmostOffset();
306                 continue;
307             }
308 
309             ASSERT(offset == box->caretRightmostOffset());
310 
311             unsigned char level = box->bidiLevel();
312             InlineBox* nextBox = box->nextLeafChild();
313 
314             if (box->direction() == primaryDirection) {
315                 if (!nextBox) {
316                     InlineBox* logicalEnd = 0;
317                     if (primaryDirection == LTR ? box->root()->getLogicalEndBoxWithNode(logicalEnd) : box->root()->getLogicalStartBoxWithNode(logicalEnd)) {
318                         box = logicalEnd;
319                         renderer = box->renderer();
320                         offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
321                     }
322                     break;
323                 }
324                 if (nextBox->bidiLevel() >= level)
325                     break;
326 
327                 level = nextBox->bidiLevel();
328 
329                 InlineBox* prevBox = box;
330                 do {
331                     prevBox = prevBox->prevLeafChild();
332                 } while (prevBox && prevBox->bidiLevel() > level);
333 
334                 if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
335                     break;
336 
337                 // For example, abc 123 ^ CBA or 123 ^ CBA abc
338                 box = nextBox;
339                 renderer = box->renderer();
340                 offset = box->caretLeftmostOffset();
341                 if (box->direction() == primaryDirection)
342                     break;
343                 continue;
344             }
345 
346             if (nextBox) {
347                 box = nextBox;
348                 renderer = box->renderer();
349                 offset = box->caretLeftmostOffset();
350                 if (box->bidiLevel() > level) {
351                     do {
352                         nextBox = nextBox->nextLeafChild();
353                     } while (nextBox && nextBox->bidiLevel() > level);
354 
355                     if (!nextBox || nextBox->bidiLevel() < level)
356                         continue;
357                 }
358             } else {
359                 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
360                 while (true) {
361                     while (InlineBox* prevBox = box->prevLeafChild()) {
362                         if (prevBox->bidiLevel() < level)
363                             break;
364                         box = prevBox;
365                     }
366                     if (box->bidiLevel() == level)
367                         break;
368                     level = box->bidiLevel();
369                     while (InlineBox* nextBox = box->nextLeafChild()) {
370                         if (nextBox->bidiLevel() < level)
371                             break;
372                         box = nextBox;
373                     }
374                     if (box->bidiLevel() == level)
375                         break;
376                     level = box->bidiLevel();
377                 }
378                 renderer = box->renderer();
379                 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
380             }
381             break;
382         }
383 
384         p = Position(renderer->node(), offset);
385 
386         if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
387             return p;
388     }
389 }
390 
right(bool stayInEditableContent) const391 VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
392 {
393     Position pos = rightVisuallyDistinctCandidate();
394     // FIXME: Why can't we move left from the last position in a tree?
395     if (pos.atStartOfTree() || pos.atEndOfTree())
396         return VisiblePosition();
397 
398     VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
399     ASSERT(right != *this);
400 
401     if (!stayInEditableContent)
402         return right;
403 
404     // FIXME: This may need to do something different from "after".
405     return honorEditableBoundaryAtOrAfter(right);
406 }
407 
honorEditableBoundaryAtOrBefore(const VisiblePosition & pos) const408 VisiblePosition VisiblePosition::honorEditableBoundaryAtOrBefore(const VisiblePosition &pos) const
409 {
410     if (pos.isNull())
411         return pos;
412 
413     Node* highestRoot = highestEditableRoot(deepEquivalent());
414 
415     // Return empty position if pos is not somewhere inside the editable region containing this position
416     if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
417         return VisiblePosition();
418 
419     // Return pos itself if the two are from the very same editable region, or both are non-editable
420     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
421     // to it is allowed.  VisibleSelection::adjustForEditableContent has this problem too.
422     if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
423         return pos;
424 
425     // Return empty position if this position is non-editable, but pos is editable
426     // FIXME: Move to the previous non-editable region.
427     if (!highestRoot)
428         return VisiblePosition();
429 
430     // Return the last position before pos that is in the same editable region as this position
431     return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
432 }
433 
honorEditableBoundaryAtOrAfter(const VisiblePosition & pos) const434 VisiblePosition VisiblePosition::honorEditableBoundaryAtOrAfter(const VisiblePosition &pos) const
435 {
436     if (pos.isNull())
437         return pos;
438 
439     Node* highestRoot = highestEditableRoot(deepEquivalent());
440 
441     // Return empty position if pos is not somewhere inside the editable region containing this position
442     if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
443         return VisiblePosition();
444 
445     // Return pos itself if the two are from the very same editable region, or both are non-editable
446     // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
447     // to it is allowed.  VisibleSelection::adjustForEditableContent has this problem too.
448     if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
449         return pos;
450 
451     // Return empty position if this position is non-editable, but pos is editable
452     // FIXME: Move to the next non-editable region.
453     if (!highestRoot)
454         return VisiblePosition();
455 
456     // Return the next position after pos that is in the same editable region as this position
457     return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
458 }
459 
canonicalizeCandidate(const Position & candidate)460 static Position canonicalizeCandidate(const Position& candidate)
461 {
462     if (candidate.isNull())
463         return Position();
464     ASSERT(candidate.isCandidate());
465     Position upstream = candidate.upstream();
466     if (upstream.isCandidate())
467         return upstream;
468     return candidate;
469 }
470 
canonicalPosition(const Position & passedPosition)471 Position VisiblePosition::canonicalPosition(const Position& passedPosition)
472 {
473     // The updateLayout call below can do so much that even the position passed
474     // in to us might get changed as a side effect. Specifically, there are code
475     // paths that pass selection endpoints, and updateLayout can change the selection.
476     Position position = passedPosition;
477 
478     // FIXME (9535):  Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will
479     // ask renderers to paint downstream carets for other renderers.
480     // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
481     // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
482     // unless the affinity is upstream.
483     if (position.isNull())
484         return Position();
485 
486     Node* node = position.containerNode();
487 
488     ASSERT(position.document());
489     position.document()->updateLayoutIgnorePendingStylesheets();
490 
491     Position candidate = position.upstream();
492     if (candidate.isCandidate())
493         return candidate;
494     candidate = position.downstream();
495     if (candidate.isCandidate())
496         return candidate;
497 
498     // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave
499     // blocks or enter new ones), we search forward and backward until we find one.
500     Position next = canonicalizeCandidate(nextCandidate(position));
501     Position prev = canonicalizeCandidate(previousCandidate(position));
502     Node* nextNode = next.deprecatedNode();
503     Node* prevNode = prev.deprecatedNode();
504 
505     // The new position must be in the same editable element. Enforce that first.
506     // Unless the descent is from a non-editable html element to an editable body.
507     if (node && node->hasTagName(htmlTag) && !node->rendererIsEditable() && node->document()->body() && node->document()->body()->rendererIsEditable())
508         return next.isNotNull() ? next : prev;
509 
510     Node* editingRoot = editableRootForPosition(position);
511 
512     // If the html element is editable, descending into its body will look like a descent
513     // from non-editable to editable content since rootEditableElement() always stops at the body.
514     if ((editingRoot && editingRoot->hasTagName(htmlTag)) || position.deprecatedNode()->isDocumentNode())
515         return next.isNotNull() ? next : prev;
516 
517     bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
518     bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
519     if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
520         return prev;
521 
522     if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
523         return next;
524 
525     if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
526         return Position();
527 
528     // The new position should be in the same block flow element. Favor that.
529     Node* originalBlock = node ? node->enclosingBlockFlowElement() : 0;
530     bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
531     bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
532     if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
533         return prev;
534 
535     return next;
536 }
537 
characterAfter() const538 UChar32 VisiblePosition::characterAfter() const
539 {
540     // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
541     // is the one that will be inside the text node containing the character after this visible position.
542     Position pos = m_deepPosition.downstream();
543     Node* node = pos.containerNode();
544     if (!node || !node->isTextNode() || pos.anchorType() == Position::PositionIsAfterAnchor)
545         return 0;
546     ASSERT(pos.anchorType() == Position::PositionIsBeforeAnchor || pos.anchorType() == Position::PositionIsOffsetInAnchor);
547     Text* textNode = static_cast<Text*>(pos.containerNode());
548     unsigned offset = pos.anchorType() == Position::PositionIsOffsetInAnchor ? pos.offsetInContainerNode() : 0;
549     unsigned length = textNode->length();
550     if (offset >= length)
551         return 0;
552 
553     UChar32 ch;
554     const UChar* characters = textNode->data().characters();
555     U16_NEXT(characters, offset, length, ch);
556     return ch;
557 }
558 
localCaretRect(RenderObject * & renderer) const559 IntRect VisiblePosition::localCaretRect(RenderObject*& renderer) const
560 {
561     if (m_deepPosition.isNull()) {
562         renderer = 0;
563         return IntRect();
564     }
565     Node* node = m_deepPosition.anchorNode();
566 
567     renderer = node->renderer();
568     if (!renderer)
569         return IntRect();
570 
571     InlineBox* inlineBox;
572     int caretOffset;
573     getInlineBoxAndOffset(inlineBox, caretOffset);
574 
575     if (inlineBox)
576         renderer = inlineBox->renderer();
577 
578     return renderer->localCaretRect(inlineBox, caretOffset);
579 }
580 
absoluteCaretBounds() const581 IntRect VisiblePosition::absoluteCaretBounds() const
582 {
583     RenderObject* renderer;
584     IntRect localRect = localCaretRect(renderer);
585     if (localRect.isEmpty() || !renderer)
586         return IntRect();
587 
588     return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
589 }
590 
xOffsetForVerticalNavigation() const591 int VisiblePosition::xOffsetForVerticalNavigation() const
592 {
593     RenderObject* renderer;
594     IntRect localRect = localCaretRect(renderer);
595     if (localRect.isEmpty() || !renderer)
596         return 0;
597 
598     // This ignores transforms on purpose, for now. Vertical navigation is done
599     // without consulting transforms, so that 'up' in transformed text is 'up'
600     // relative to the text, not absolute 'up'.
601     return renderer->localToAbsolute(localRect.location()).x();
602 }
603 
604 #ifndef NDEBUG
605 
debugPosition(const char * msg) const606 void VisiblePosition::debugPosition(const char* msg) const
607 {
608     if (isNull())
609         fprintf(stderr, "Position [%s]: null\n", msg);
610     else {
611         fprintf(stderr, "Position [%s]: %s, ", msg, m_deepPosition.deprecatedNode()->nodeName().utf8().data());
612         m_deepPosition.showAnchorTypeAndOffset();
613     }
614 }
615 
formatForDebugger(char * buffer,unsigned length) const616 void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
617 {
618     m_deepPosition.formatForDebugger(buffer, length);
619 }
620 
showTreeForThis() const621 void VisiblePosition::showTreeForThis() const
622 {
623     m_deepPosition.showTreeForThis();
624 }
625 
626 #endif
627 
makeRange(const VisiblePosition & start,const VisiblePosition & end)628 PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
629 {
630     if (start.isNull() || end.isNull())
631         return 0;
632 
633     Position s = start.deepEquivalent().parentAnchoredEquivalent();
634     Position e = end.deepEquivalent().parentAnchoredEquivalent();
635     return Range::create(s.containerNode()->document(), s.containerNode(), s.offsetInContainerNode(), e.containerNode(), e.offsetInContainerNode());
636 }
637 
startVisiblePosition(const Range * r,EAffinity affinity)638 VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
639 {
640     int exception = 0;
641     return VisiblePosition(Position(r->startContainer(exception), r->startOffset(exception), Position::PositionIsOffsetInAnchor), affinity);
642 }
643 
endVisiblePosition(const Range * r,EAffinity affinity)644 VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
645 {
646     int exception = 0;
647     return VisiblePosition(Position(r->endContainer(exception), r->endOffset(exception), Position::PositionIsOffsetInAnchor), affinity);
648 }
649 
setStart(Range * r,const VisiblePosition & visiblePosition)650 bool setStart(Range *r, const VisiblePosition &visiblePosition)
651 {
652     if (!r)
653         return false;
654     Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
655     int code = 0;
656     r->setStart(p.containerNode(), p.offsetInContainerNode(), code);
657     return code == 0;
658 }
659 
setEnd(Range * r,const VisiblePosition & visiblePosition)660 bool setEnd(Range *r, const VisiblePosition &visiblePosition)
661 {
662     if (!r)
663         return false;
664     Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
665     int code = 0;
666     r->setEnd(p.containerNode(), p.offsetInContainerNode(), code);
667     return code == 0;
668 }
669 
enclosingBlockFlowElement(const VisiblePosition & visiblePosition)670 Element* enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
671 {
672     if (visiblePosition.isNull())
673         return NULL;
674 
675     return visiblePosition.deepEquivalent().deprecatedNode()->enclosingBlockFlowElement();
676 }
677 
isFirstVisiblePositionInNode(const VisiblePosition & visiblePosition,const Node * node)678 bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
679 {
680     if (visiblePosition.isNull())
681         return false;
682 
683     if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
684         return false;
685 
686     VisiblePosition previous = visiblePosition.previous();
687     return previous.isNull() || !previous.deepEquivalent().deprecatedNode()->isDescendantOf(node);
688 }
689 
isLastVisiblePositionInNode(const VisiblePosition & visiblePosition,const Node * node)690 bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
691 {
692     if (visiblePosition.isNull())
693         return false;
694 
695     if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
696         return false;
697 
698     VisiblePosition next = visiblePosition.next();
699     return next.isNull() || !next.deepEquivalent().deprecatedNode()->isDescendantOf(node);
700 }
701 
702 }  // namespace WebCore
703 
704 #ifndef NDEBUG
705 
showTree(const WebCore::VisiblePosition * vpos)706 void showTree(const WebCore::VisiblePosition* vpos)
707 {
708     if (vpos)
709         vpos->showTreeForThis();
710 }
711 
showTree(const WebCore::VisiblePosition & vpos)712 void showTree(const WebCore::VisiblePosition& vpos)
713 {
714     vpos.showTreeForThis();
715 }
716 
717 #endif
718