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
43namespace WebCore {
44
45using namespace HTMLNames;
46
47VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
48{
49    init(pos, affinity);
50}
51
52void 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
63VisiblePosition 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
75VisiblePosition 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
105Position 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
239VisiblePosition 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
256Position 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
391VisiblePosition 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
408VisiblePosition 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
434VisiblePosition 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
460static 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
471Position 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
538UChar32 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
559IntRect 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
581IntRect 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
591int 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
606void 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
616void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
617{
618    m_deepPosition.formatForDebugger(buffer, length);
619}
620
621void VisiblePosition::showTreeForThis() const
622{
623    m_deepPosition.showTreeForThis();
624}
625
626#endif
627
628PassRefPtr<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
638VisiblePosition 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
644VisiblePosition 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
650bool 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
660bool 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
670Element* enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
671{
672    if (visiblePosition.isNull())
673        return NULL;
674
675    return visiblePosition.deepEquivalent().deprecatedNode()->enclosingBlockFlowElement();
676}
677
678bool 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
690bool 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
706void showTree(const WebCore::VisiblePosition* vpos)
707{
708    if (vpos)
709        vpos->showTreeForThis();
710}
711
712void showTree(const WebCore::VisiblePosition& vpos)
713{
714    vpos.showTreeForThis();
715}
716
717#endif
718