Reviewed by Anders.
[WebKit-https.git] / WebCore / editing / visible_units.cpp
1 /*
2  * Copyright (C) 2004 Apple Computer, 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 "visible_units.h"
28
29 #include "Document.h"
30 #include "Element.h"
31 #include "RenderBlock.h"
32 #include "TextBoundaries.h"
33 #include "htmlediting.h"
34 #include "HTMLNames.h"
35 #include "TextIterator.h"
36
37 namespace WebCore {
38
39 using namespace HTMLNames;
40
41 static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
42 {
43     Position pos = c.deepEquivalent();
44     Node *n = pos.node();
45     if (!n)
46         return VisiblePosition();
47     Document *d = n->document();
48     Node *de = d->documentElement();
49     if (!de)
50         return VisiblePosition();
51     Node *boundary = n->enclosingBlockFlowElement();
52     if (!boundary)
53         return VisiblePosition();
54     bool isContentEditable = boundary->isContentEditable();
55     while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
56         boundary = boundary->parentNode();
57
58     Position start = rangeCompliantEquivalent(Position(boundary, 0));
59     Position end = rangeCompliantEquivalent(pos);
60     RefPtr<Range> searchRange = new Range(d);
61     
62     int exception = 0;
63     searchRange->setStart(start.node(), start.offset(), exception);
64     searchRange->setEnd(end.node(), end.offset(), exception);
65     
66     ASSERT(!exception);
67     if (exception)
68         return VisiblePosition();
69         
70     SimplifiedBackwardsTextIterator it(searchRange.get());
71     DeprecatedString string;
72     unsigned next = 0;
73     bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
74     while (!it.atEnd() && it.length() > 0) {
75         // iterate to get chunks until the searchFunction returns a non-zero value.
76         String iteratorString(it.characters(), it.length());
77         // Treat bullets used in the text security mode as regular characters when looking for boundaries
78         if (inTextSecurityMode)
79             iteratorString = iteratorString.impl()->secure('x');
80         string.prepend(iteratorString.deprecatedString());
81         next = searchFunction(reinterpret_cast<const UChar*>(string.unicode()), string.length());
82         if (next != 0)
83             break;
84         it.advance();
85     }
86     
87     if (it.atEnd() && next == 0) {
88         RefPtr<Range> range(it.range());
89         pos = Position(range->startContainer(exception), range->startOffset(exception));
90     } else if (!it.atEnd() && it.length() == 0) {
91         // Got a zero-length chunk.
92         // This means we have hit a replaced element.
93         // Make a check to see if the position should be before or after the replaced element
94         // by performing an additional check with a modified string which uses an "X" 
95         // character to stand in for the replaced element.
96         DeprecatedChar chars[2];
97         chars[0] = 'X';
98         chars[1] = ' ';
99         string.prepend(chars, 2);
100         unsigned pastImage = searchFunction(reinterpret_cast<const UChar*>(string.unicode()), string.length());
101         RefPtr<Range> range(it.range());
102         if (pastImage == 0)
103             pos = Position(range->startContainer(exception), range->startOffset(exception));
104         else
105             pos = Position(range->endContainer(exception), range->endOffset(exception));
106     } else if (next != 0) {
107         // The simpler iterator used in this function, as compared to the one used in 
108         // nextWordPosition(), gives us results we can use directly without having to 
109         // iterate again to translate the next value into a DOM position. 
110         Node *node = it.range()->startContainer(exception);
111         if (node->isTextNode() || (node->renderer() && node->renderer()->isBR()))
112             // The next variable contains a usable index into a text node
113             pos = Position(node, next);
114         else
115             // If we are not in a text node, we ended on a node boundary, so the
116             // range start offset should be used.
117             pos = Position(node, it.range()->startOffset(exception));
118     }
119
120     return VisiblePosition(pos, DOWNSTREAM);
121 }
122
123 static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
124 {
125     Position pos = c.deepEquivalent();
126     Node *n = pos.node();
127     if (!n)
128         return VisiblePosition();
129     Document *d = n->document();
130     Node *de = d->documentElement();
131     if (!de)
132         return VisiblePosition();
133     Node *boundary = n->enclosingBlockFlowElement();
134     if (!boundary)
135         return VisiblePosition();
136     bool isContentEditable = boundary->isContentEditable();
137     while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
138         boundary = boundary->parentNode();
139
140     RefPtr<Range> searchRange(d->createRange());
141     Position start(rangeCompliantEquivalent(pos));
142     ExceptionCode ec = 0;
143     searchRange->selectNodeContents(boundary, ec);
144     searchRange->setStart(start.node(), start.offset(), ec);
145     TextIterator it(searchRange.get(), RUNFINDER);
146     DeprecatedString string;
147     unsigned next = 0;
148     bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
149     while (!it.atEnd() && it.length() > 0) {
150         // Keep asking the iterator for chunks until the search function
151         // returns an end value not equal to the length of the string passed to it.
152         String iteratorString(it.characters(), it.length());
153         // Treat bullets used in the text security mode as regular characters when looking for boundaries
154         if (inTextSecurityMode)
155             iteratorString = iteratorString.impl()->secure('x');
156         string.append(iteratorString.deprecatedString());
157         next = searchFunction(reinterpret_cast<const UChar*>(string.unicode()), string.length());
158         if (next != string.length())
159             break;
160         it.advance();
161     }
162     
163     if (it.atEnd() && next == string.length()) {
164         RefPtr<Range> range(it.range());
165         int exception = 0;
166         pos = Position(range->startContainer(exception), range->startOffset(exception));
167     } else if (!it.atEnd() && it.length() == 0) {
168         // Got a zero-length chunk.
169         // This means we have hit a replaced element.
170         // Make a check to see if the position should be before or after the replaced element
171         // by performing an additional check with a modified string which uses an "X" 
172         // character to stand in for the replaced element.
173         DeprecatedChar chars[2];
174         chars[0] = ' ';
175         chars[1] = 'X';
176         string.append(chars, 2);
177         unsigned pastImage = searchFunction(reinterpret_cast<const UChar*>(string.unicode()), string.length());
178         RefPtr<Range> range(it.range());
179         int exception = 0;
180         if (next != pastImage)
181             pos = Position(range->endContainer(exception), range->endOffset(exception));
182         else
183             pos = Position(range->startContainer(exception), range->startOffset(exception));
184     } else if (next != 0) {
185         // Use the character iterator to translate the next value into a DOM position.
186         CharacterIterator charIt(searchRange.get());
187         charIt.advance(next - 1);
188         pos = Position(charIt.range()->endContainer(ec), charIt.range()->endOffset(ec));
189     }
190
191     // generate VisiblePosition, use UPSTREAM affinity if possible
192     return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
193 }
194
195 // ---------
196
197 static unsigned startWordBoundary(const UChar* characters, unsigned length)
198 {
199     int start, end;
200     findWordBoundary(characters, length, length, &start, &end);
201     return start;
202 }
203
204 VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
205 {
206     // FIXME: This returns a null VP for c at the start of the document
207     // and side == LeftWordIfOnBoundary
208     VisiblePosition p = c;
209     if (side == RightWordIfOnBoundary) {
210         // at paragraph end, the startofWord is the current position
211         if (isEndOfParagraph(c))
212             return c;
213         
214         p = c.next();
215         if (p.isNull())
216             return c;
217     }
218     return previousBoundary(p, startWordBoundary);
219 }
220
221 static unsigned endWordBoundary(const UChar* characters, unsigned length)
222 {
223     int start, end;
224     findWordBoundary(characters, length, 0, &start, &end);
225     return end;
226 }
227
228 VisiblePosition endOfWord(const VisiblePosition &c, EWordSide side)
229 {
230     VisiblePosition p = c;
231     if (side == LeftWordIfOnBoundary) {
232         if (isStartOfParagraph(c))
233             return c;
234             
235         p = c.previous();
236         if (p.isNull())
237             return c;
238     } else {
239         // at paragraph end, the endOfWord is the start of next paragraph
240         if (isEndOfParagraph(c)) {
241             p = c.next();
242             return p.isNotNull() ? p : c;
243         }
244     }
245     
246     return nextBoundary(p, endWordBoundary);
247 }
248
249 static unsigned previousWordPositionBoundary(const UChar* characters, unsigned length)
250 {
251     return findNextWordFromIndex(characters, length, length, false);
252 }
253
254 VisiblePosition previousWordPosition(const VisiblePosition &c)
255 {
256     return previousBoundary(c, previousWordPositionBoundary);
257 }
258
259 static unsigned nextWordPositionBoundary(const UChar* characters, unsigned length)
260 {
261     return findNextWordFromIndex(characters, length, 0, true);
262 }
263
264 VisiblePosition nextWordPosition(const VisiblePosition &c)
265 {
266     return nextBoundary(c, nextWordPositionBoundary);
267 }
268
269 // ---------
270
271 static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
272 {
273     Position p = c.deepEquivalent();
274     Node *node = p.node();
275     if (!node)
276         return 0;
277
278     RenderObject *renderer = node->renderer();
279     if (!renderer)
280         return 0;
281     
282     InlineBox *box = renderer->inlineBox(p.offset(), c.affinity());
283     if (!box)
284         return 0;
285     
286     return box->root();
287 }
288
289 VisiblePosition startOfLine(const VisiblePosition &c)
290 {
291     RootInlineBox *rootBox = rootBoxForLine(c);
292     if (!rootBox)
293         return VisiblePosition();
294     
295     // Generated content (e.g. list markers and CSS :before and :after
296     // pseudoelements) have no corresponding DOM element, and so cannot be
297     // represented by a VisiblePosition.  Use whatever follows instead.
298     InlineBox *startBox = rootBox->firstLeafChild();
299     Node *startNode;
300     while (1) {
301         if (!startBox)
302             return VisiblePosition();
303
304         RenderObject *startRenderer = startBox->object();
305         if (!startRenderer)
306             return VisiblePosition();
307
308         startNode = startRenderer->element();
309         if (startNode)
310             break;
311         
312         startBox = startBox->nextLeafChild();
313     }
314     
315     int startOffset = 0;
316     if (startBox->isInlineTextBox()) {
317         InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
318         startOffset = startTextBox->m_start;
319     }
320     
321     return VisiblePosition(startNode, startOffset, DOWNSTREAM);
322 }
323
324 VisiblePosition endOfLine(const VisiblePosition &c)
325 {
326     RootInlineBox *rootBox = rootBoxForLine(c);
327     if (!rootBox)
328         return VisiblePosition();
329     
330     // Generated content (e.g. list markers and CSS :before and :after
331     // pseudoelements) have no corresponding DOM element, and so cannot be
332     // represented by a VisiblePosition.  Use whatever precedes instead.
333     Node *endNode;
334     InlineBox *endBox = rootBox->lastLeafChild();
335     while (1) {
336         if (!endBox)
337             return VisiblePosition();
338
339         RenderObject *endRenderer = endBox->object();
340         if (!endRenderer)
341             return VisiblePosition();
342
343         endNode = endRenderer->element();
344         if (endNode)
345             break;
346         
347         endBox = endBox->prevLeafChild();
348     }
349     
350     int endOffset = 1;
351     if (endNode->hasTagName(brTag)) {
352         endOffset = 0;
353     } else if (endBox->isInlineTextBox()) {
354         InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
355         endOffset = endTextBox->m_start + endTextBox->m_len;
356     }
357     
358     return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
359 }
360
361 bool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
362 {
363     return a.isNotNull() && startOfLine(a) == startOfLine(b);
364 }
365
366 bool isStartOfLine(const VisiblePosition &p)
367 {
368     return p.isNotNull() && p == startOfLine(p);
369 }
370
371 bool isEndOfLine(const VisiblePosition &p)
372 {
373     return p.isNotNull() && p == endOfLine(p);
374 }
375
376 VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
377 {
378     Position p = visiblePosition.deepEquivalent();
379     Node *node = p.node();
380     if (!node)
381         return VisiblePosition();
382     
383     node->document()->updateLayoutIgnorePendingStylesheets();
384     
385     RenderObject *renderer = node->renderer();
386     if (!renderer)
387         return VisiblePosition();
388
389     RenderBlock *containingBlock = 0;
390     RootInlineBox *root = 0;
391     InlineBox *box = renderer->inlineBox(p.offset(), visiblePosition.affinity());
392     if (box) {
393         root = box->root()->prevRootBox();
394         if (root)
395             containingBlock = renderer->containingBlock();
396     }
397
398     if (!root) {
399         // This containing editable block does not have a previous line.
400         // Need to move back to previous containing editable block in this root editable
401         // block and find the last root line box in that block.
402         Node *startBlock = node->enclosingBlockFlowElement();
403         Node *n = node->previousEditable();
404         while (n && startBlock == n->enclosingBlockFlowElement())
405             n = n->previousEditable();
406         while (n) {
407             if (!n->inSameRootEditableElement(node))
408                 break;
409             Position pos(n, n->caretMinOffset());
410             if (pos.inRenderedContent()) {
411                 assert(n->renderer());
412                 box = n->renderer()->inlineBox(n->caretMaxOffset());
413                 if (box) {
414                     // previous root line box found
415                     root = box->root();
416                     containingBlock = n->renderer()->containingBlock();
417                     break;
418                 }
419
420                 return VisiblePosition(pos, DOWNSTREAM);
421             }
422             n = n->previousEditable();
423         }
424     }
425     
426     if (root) {
427         int absx, absy;
428         containingBlock->absolutePositionForContent(absx, absy);
429         if (containingBlock->hasOverflowClip())
430             containingBlock->layer()->subtractScrollOffset(absx, absy);
431         RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
432         Node* node = renderer->element();
433         if (editingIgnoresContent(node))
434             return Position(node->parent(), node->nodeIndex());
435         return renderer->positionForCoordinates(x, absy + root->topOverflow());
436     }
437     
438     // Could not find a previous line. This means we must already be on the first line.
439     // Move to the start of the content in this block, which effectively moves us
440     // to the start of the line we're on.
441     return VisiblePosition(node->rootEditableElement(), 0, DOWNSTREAM);
442 }
443
444 VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
445 {
446     Position p = visiblePosition.deepEquivalent();
447     Node *node = p.node();
448     if (!node)
449         return VisiblePosition();
450     
451     node->document()->updateLayoutIgnorePendingStylesheets();
452
453     RenderObject *renderer = node->renderer();
454     if (!renderer)
455         return VisiblePosition();
456
457     RenderBlock *containingBlock = 0;
458     RootInlineBox *root = 0;
459     InlineBox *box = renderer->inlineBox(p.offset(), visiblePosition.affinity());
460     if (box) {
461         root = box->root()->nextRootBox();
462         if (root)
463             containingBlock = renderer->containingBlock();
464     }
465
466     if (!root) {
467         // This containing editable block does not have a next line.
468         // Need to move forward to next containing editable block in this root editable
469         // block and find the first root line box in that block.
470         Node *startBlock = node->enclosingBlockFlowElement();
471         Node *n = node->nextEditable(p.offset());
472         while (n && startBlock == n->enclosingBlockFlowElement())
473             n = n->nextEditable();
474         while (n) {
475             if (!n->inSameRootEditableElement(node))
476                 break;
477             Position pos(n, n->caretMinOffset());
478             if (pos.inRenderedContent()) {
479                 assert(n->renderer());
480                 box = n->renderer()->inlineBox(n->caretMinOffset());
481                 if (box) {
482                     // next root line box found
483                     root = box->root();
484                     containingBlock = n->renderer()->containingBlock();
485                     break;
486                 }
487
488                 return VisiblePosition(pos, DOWNSTREAM);
489             }
490             n = n->nextEditable();
491         }
492     }
493     
494     if (root) {
495         int absx, absy;
496         containingBlock->absolutePositionForContent(absx, absy);
497         if (containingBlock->hasOverflowClip())
498             containingBlock->layer()->subtractScrollOffset(absx, absy);
499         RenderObject *renderer = root->closestLeafChildForXPos(x, absx)->object();
500         Node* node = renderer->element();
501         if (editingIgnoresContent(node))
502             return Position(node->parent(), node->nodeIndex());
503         return renderer->positionForCoordinates(x, absy + root->topOverflow());
504     }    
505
506     // Could not find a next line. This means we must already be on the last line.
507     // Move to the end of the content in this block, which effectively moves us
508     // to the end of the line we're on.
509     Element *rootElement = node->rootEditableElement();
510     return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
511 }
512
513 // ---------
514
515 static unsigned startSentenceBoundary(const UChar* characters, unsigned length)
516 {
517     int start, end;
518     findSentenceBoundary(characters, length, length, &start, &end);
519     return start;
520 }
521
522 VisiblePosition startOfSentence(const VisiblePosition &c)
523 {
524     return previousBoundary(c, startSentenceBoundary);
525 }
526
527 static unsigned endSentenceBoundary(const UChar* characters, unsigned length)
528 {
529     int start, end;
530     findSentenceBoundary(characters, length, 0, &start, &end);
531     return end;
532 }
533
534 VisiblePosition endOfSentence(const VisiblePosition &c)
535 {
536     return nextBoundary(c, endSentenceBoundary);
537 }
538
539 static unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length)
540 {
541     return findNextSentenceFromIndex(characters, length, length, false);
542 }
543
544 VisiblePosition previousSentencePosition(const VisiblePosition &c)
545 {
546     return previousBoundary(c, previousSentencePositionBoundary);
547 }
548
549 static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length)
550 {
551     return findNextSentenceFromIndex(characters, length, 0, true);
552 }
553
554 VisiblePosition nextSentencePosition(const VisiblePosition &c)
555 {
556     return nextBoundary(c, nextSentencePositionBoundary);
557 }
558
559 VisiblePosition startOfParagraph(const VisiblePosition &c)
560 {
561     Position p = c.deepEquivalent();
562     Node *startNode = p.node();
563
564     if (!startNode)
565         return VisiblePosition();
566     
567     if (startNode->renderer()
568         && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
569             || startNode->renderer()->isHR())
570         && p.offset() == maxDeepOffset(startNode))
571         return VisiblePosition(Position(startNode, 0));
572
573     Node *startBlock = startNode->enclosingBlockFlowElement();
574
575     Node *node = startNode;
576     int offset = p.offset();
577
578     Node *n = startNode;
579     while (n) {
580         if (n->isContentEditable() != startNode->isContentEditable())
581             break;
582         RenderObject *r = n->renderer();
583         if (!r) {
584             n = n->traversePreviousNodePostOrder(startBlock);
585             continue;
586         }
587         RenderStyle *style = r->style();
588         if (style->visibility() != VISIBLE) {
589             n = n->traversePreviousNodePostOrder(startBlock);
590             continue;
591         }
592         // FIXME: isBlockFlow should not exclude non-inline tables
593         if (r->isBR() || r->isBlockFlow() || (r->isTable() && !r->isInline()))
594             break;
595             
596         if (r->isText()) {
597             if (style->preserveNewline()) {
598                 const UChar* text = static_cast<RenderText*>(r)->text();
599                 int i = static_cast<RenderText*>(r)->length();
600                 int o = offset;
601                 if (n == startNode && o < i)
602                     i = max(0, o);
603                 while (--i >= 0)
604                     if (text[i] == '\n')
605                         return VisiblePosition(n, i + 1, DOWNSTREAM);
606             }
607             node = n;
608             offset = 0;
609             n = n->traversePreviousNodePostOrder(startBlock);
610         } else if (editingIgnoresContent(n) || isTableElement(n)) {
611             node = n;
612             offset = 0;
613             n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
614         } else
615             n = n->traversePreviousNodePostOrder(startBlock);
616     }
617
618     return VisiblePosition(node, offset, DOWNSTREAM);
619 }
620
621 VisiblePosition endOfParagraph(const VisiblePosition &c)
622 {    
623     if (c.isNull())
624         return VisiblePosition();
625
626     Position p = c.deepEquivalent();
627     Node* startNode = p.node();
628
629     if (startNode->renderer()
630         && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
631             || startNode->renderer()->isHR())
632         && p.offset() == 0)
633         return VisiblePosition(Position(startNode, maxDeepOffset(startNode)));
634     
635     Node *startBlock = startNode->enclosingBlockFlowElement();
636     Node *stayInsideBlock = startBlock;
637     
638     Node *node = startNode;
639     int offset = p.offset();
640
641     Node *n = startNode;
642     while (n) {
643         if (n->isContentEditable() != startNode->isContentEditable())
644             break;
645         RenderObject *r = n->renderer();
646         if (!r) {
647             n = n->traverseNextNode(stayInsideBlock);
648             continue;
649         }
650         RenderStyle *style = r->style();
651         if (style->visibility() != VISIBLE) {
652             n = n->traverseNextNode(stayInsideBlock);
653             continue;
654         }
655         
656         // FIXME: isBlockFlow should not exclude non-inline tables
657         if (r->isBR() || r->isBlockFlow() || (r->isTable() && !r->isInline()))
658             break;
659             
660         // FIXME: We avoid returning a position where the renderer can't accept the caret.
661         // We should probably do this in other cases such as startOfParagraph.
662         if (r->isText() && r->caretMaxRenderedOffset() > 0) {
663             int length = static_cast<RenderText *>(r)->length();
664             if (style->preserveNewline()) {
665                 const UChar* text = static_cast<RenderText *>(r)->text();
666                 int o = n == startNode ? offset : 0;
667                 for (int i = o; i < length; ++i)
668                     if (text[i] == '\n')
669                         return VisiblePosition(n, i, DOWNSTREAM);
670             }
671             node = n;
672             offset = r->caretMaxOffset();
673             n = n->traverseNextNode(stayInsideBlock);
674         } else if (editingIgnoresContent(n) || isTableElement(n)) {
675             node = n;
676             offset = maxDeepOffset(n);
677             n = n->traverseNextSibling(stayInsideBlock);
678         } else
679             n = n->traverseNextNode(stayInsideBlock);
680     }
681
682     return VisiblePosition(node, offset, DOWNSTREAM);
683 }
684
685 bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
686 {
687     return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
688 }
689
690 bool isStartOfParagraph(const VisiblePosition &pos)
691 {
692     return pos.isNotNull() && pos == startOfParagraph(pos);
693 }
694
695 bool isEndOfParagraph(const VisiblePosition &pos)
696 {
697     return pos.isNotNull() && pos == endOfParagraph(pos);
698 }
699
700 VisiblePosition previousParagraphPosition(const VisiblePosition &p, int x)
701 {
702     VisiblePosition pos = p;
703     do {
704         VisiblePosition n = previousLinePosition(pos, x);
705         if (n.isNull() || n == pos)
706             return p;
707         pos = n;
708     } while (inSameParagraph(p, pos));
709     return pos;
710 }
711
712 VisiblePosition nextParagraphPosition(const VisiblePosition &p, int x)
713 {
714     VisiblePosition pos = p;
715     do {
716         VisiblePosition n = nextLinePosition(pos, x);
717         if (n.isNull() || n == pos)
718             return p;
719         pos = n;
720     } while (inSameParagraph(p, pos));
721     return pos;
722 }
723
724 // ---------
725
726 VisiblePosition startOfBlock(const VisiblePosition &c)
727 {
728     Position p = c.deepEquivalent();
729     Node *startNode = p.node();
730     if (!startNode)
731         return VisiblePosition();
732     return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
733 }
734
735 VisiblePosition endOfBlock(const VisiblePosition &c)
736 {
737     Position p = c.deepEquivalent();
738
739     Node *startNode = p.node();
740     if (!startNode)
741         return VisiblePosition();
742
743     Node *startBlock = startNode->enclosingBlockFlowElement();
744     
745     return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);   
746 }
747
748 bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
749 {
750     return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
751 }
752
753 bool isStartOfBlock(const VisiblePosition &pos)
754 {
755     return pos.isNotNull() && pos == startOfBlock(pos);
756 }
757
758 bool isEndOfBlock(const VisiblePosition &pos)
759 {
760     return pos.isNotNull() && pos == endOfBlock(pos);
761 }
762
763 // ---------
764
765 VisiblePosition startOfDocument(const Node* node)
766 {
767     if (!node)
768         return VisiblePosition();
769     
770     return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
771 }
772
773 VisiblePosition startOfDocument(const VisiblePosition &c)
774 {
775     return startOfDocument(c.deepEquivalent().node());
776 }
777
778 VisiblePosition endOfDocument(const Node* node)
779 {
780     if (!node || !node->document())
781         return VisiblePosition();
782     
783     Element* doc = node->document()->documentElement();
784     return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
785 }
786
787 VisiblePosition endOfDocument(const VisiblePosition &c)
788 {
789     return endOfDocument(c.deepEquivalent().node());
790 }
791
792 bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
793 {
794     Position ap = a.deepEquivalent();
795     Node *an = ap.node();
796     if (!an)
797         return false;
798     Position bp = b.deepEquivalent();
799     Node *bn = bp.node();
800     if (an == bn)
801         return true;
802
803     return an->document() == bn->document();
804 }
805
806 bool isStartOfDocument(const VisiblePosition &p)
807 {
808     return p.isNotNull() && p.previous().isNull();
809 }
810
811 bool isEndOfDocument(const VisiblePosition &p)
812 {
813     return p.isNotNull() && p.next().isNull();
814 }
815
816 // ---------
817
818 VisiblePosition startOfEditableContent(const VisiblePosition &c)
819 {
820     Position p = c.deepEquivalent();
821     Node *node = p.node();
822     if (!node)
823         return VisiblePosition();
824
825     return VisiblePosition(node->rootEditableElement(), 0, DOWNSTREAM);
826 }
827
828 VisiblePosition endOfEditableContent(const VisiblePosition &c)
829 {
830     Position p = c.deepEquivalent();
831     Node *node = p.node();
832     if (!node)
833         return VisiblePosition();
834
835     node = node->rootEditableElement();
836     if (!node)
837         return VisiblePosition();
838
839     return VisiblePosition(node, node->childNodeCount(), DOWNSTREAM);
840 }
841
842 bool inSameEditableContent(const VisiblePosition &a, const VisiblePosition &b)
843 {
844     Position ap = a.deepEquivalent();
845     Node *an = ap.node();
846     if (!an)
847         return false;
848         
849     Position bp = b.deepEquivalent();
850     Node *bn = bp.node();
851     if (!bn)
852         return false;
853     
854     if (!an->isContentEditable() || !bn->isContentEditable())
855         return false;
856
857     return an->rootEditableElement() == bn->rootEditableElement();
858 }
859
860 bool isStartOfEditableContent(const VisiblePosition &p)
861 {
862     return !inSameEditableContent(p, p.previous());
863 }
864
865 bool isEndOfEditableContent(const VisiblePosition &p)
866 {
867     return !inSameEditableContent(p, p.next());
868 }
869
870 }