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