5ba9c4a6cc2c981070c5495c3a7ac8412afd0e1f
[WebKit-https.git] / WebCore / editing / visible_units.cpp
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 "visible_units.h"
28
29 #include "Document.h"
30 #include "Element.h"
31 #include "HTMLNames.h"
32 #include "RenderBlock.h"
33 #include "RenderLayer.h"
34 #include "TextBoundaries.h"
35 #include "TextBreakIterator.h"
36 #include "TextIterator.h"
37 #include "VisiblePosition.h"
38 #include "htmlediting.h"
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
44 static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
45 {
46     Position pos = c.deepEquivalent();
47     Node *n = pos.node();
48     if (!n)
49         return VisiblePosition();
50     Document *d = n->document();
51     Node *de = d->documentElement();
52     if (!de)
53         return VisiblePosition();
54     Node *boundary = n->enclosingBlockFlowElement();
55     if (!boundary)
56         return VisiblePosition();
57     bool isContentEditable = boundary->isContentEditable();
58     while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
59         boundary = boundary->parentNode();
60
61     Position start = rangeCompliantEquivalent(Position(boundary, 0));
62     Position end = rangeCompliantEquivalent(pos);
63     RefPtr<Range> searchRange = Range::create(d);
64     
65     int exception = 0;
66     searchRange->setStart(start.node(), start.offset(), exception);
67     searchRange->setEnd(end.node(), end.offset(), exception);
68     
69     ASSERT(!exception);
70     if (exception)
71         return VisiblePosition();
72         
73     SimplifiedBackwardsTextIterator it(searchRange.get());
74     Vector<UChar, 1024> string;
75     unsigned next = 0;
76     bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
77     while (!it.atEnd()) {
78         // iterate to get chunks until the searchFunction returns a non-zero value.
79         if (!inTextSecurityMode) 
80             string.prepend(it.characters(), it.length());
81         else {
82             // Treat bullets used in the text security mode as regular characters when looking for boundaries
83             String iteratorString(it.characters(), it.length());
84             iteratorString = iteratorString.impl()->secure('x');
85             string.prepend(iteratorString.characters(), iteratorString.length());
86         }
87         
88         next = searchFunction(string.data(), string.size());
89         if (next != 0)
90             break;
91         it.advance();
92     }
93     
94     if (it.atEnd() && next == 0) {
95         pos = it.range()->startPosition();
96     } else if (next != 0) {
97         Node *node = it.range()->startContainer(exception);
98         if (node->isTextNode() || (node->renderer() && node->renderer()->isBR()))
99             // The next variable contains a usable index into a text node
100             pos = Position(node, next);
101         else {
102             // Use the end of the found range, the start is not guaranteed to
103             // be correct.
104             Position end = it.range()->endPosition();
105             VisiblePosition boundary(end);
106             unsigned i = it.length() - next;
107             while (i--)
108                 boundary = boundary.previous();
109             return boundary;
110         }
111     }
112
113     return VisiblePosition(pos, DOWNSTREAM);
114 }
115
116 static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
117 {
118     Position pos = c.deepEquivalent();
119     Node *n = pos.node();
120     if (!n)
121         return VisiblePosition();
122     Document *d = n->document();
123     Node *de = d->documentElement();
124     if (!de)
125         return VisiblePosition();
126     Node *boundary = n->enclosingBlockFlowElement();
127     if (!boundary)
128         return VisiblePosition();
129     bool isContentEditable = boundary->isContentEditable();
130     while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
131         boundary = boundary->parentNode();
132
133     RefPtr<Range> searchRange(d->createRange());
134     Position start(rangeCompliantEquivalent(pos));
135     ExceptionCode ec = 0;
136     searchRange->selectNodeContents(boundary, ec);
137     searchRange->setStart(start.node(), start.offset(), ec);
138     TextIterator it(searchRange.get(), true);
139     Vector<UChar, 1024> string;
140     unsigned next = 0;
141     bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
142     while (!it.atEnd()) {
143         // Keep asking the iterator for chunks until the search function
144         // returns an end value not equal to the length of the string passed to it.
145         if (!inTextSecurityMode)
146             string.append(it.characters(), it.length());
147         else {
148             // Treat bullets used in the text security mode as regular characters when looking for boundaries
149             String iteratorString(it.characters(), it.length());
150             iteratorString = iteratorString.impl()->secure('x');
151             string.append(iteratorString.characters(), iteratorString.length());
152         }
153
154         next = searchFunction(string.data(), string.size());
155         if (next != string.size())
156             break;
157         it.advance();
158     }
159     
160     if (it.atEnd() && next == string.size()) {
161         pos = it.range()->startPosition();
162     } else if (next != 0) {
163         // Use the character iterator to translate the next value into a DOM position.
164         CharacterIterator charIt(searchRange.get(), true);
165         charIt.advance(next - 1);
166         pos = charIt.range()->endPosition();
167         
168         // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593)
169         VisiblePosition visPos = VisiblePosition(pos);
170         if (visPos == VisiblePosition(charIt.range()->startPosition()))
171             pos = visPos.next(true).deepEquivalent();
172     }
173
174     // generate VisiblePosition, use UPSTREAM affinity if possible
175     return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
176 }
177
178 // ---------
179
180 static unsigned startWordBoundary(const UChar* characters, unsigned length)
181 {
182     int start, end;
183     findWordBoundary(characters, length, length, &start, &end);
184     return start;
185 }
186
187 VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
188 {
189     // FIXME: This returns a null VP for c at the start of the document
190     // and side == LeftWordIfOnBoundary
191     VisiblePosition p = c;
192     if (side == RightWordIfOnBoundary) {
193         // at paragraph end, the startofWord is the current position
194         if (isEndOfParagraph(c))
195             return c;
196         
197         p = c.next();
198         if (p.isNull())
199             return c;
200     }
201     return previousBoundary(p, startWordBoundary);
202 }
203
204 static unsigned endWordBoundary(const UChar* characters, unsigned length)
205 {
206     int start, end;
207     findWordBoundary(characters, length, 0, &start, &end);
208     return end;
209 }
210
211 VisiblePosition endOfWord(const VisiblePosition &c, EWordSide side)
212 {
213     VisiblePosition p = c;
214     if (side == LeftWordIfOnBoundary) {
215         if (isStartOfParagraph(c))
216             return c;
217             
218         p = c.previous();
219         if (p.isNull())
220             return c;
221     } else if (isEndOfParagraph(c))
222         return c;
223     
224     return nextBoundary(p, endWordBoundary);
225 }
226
227 static unsigned previousWordPositionBoundary(const UChar* characters, unsigned length)
228 {
229     return findNextWordFromIndex(characters, length, length, false);
230 }
231
232 VisiblePosition previousWordPosition(const VisiblePosition &c)
233 {
234     VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary);
235     return c.honorEditableBoundaryAtOrAfter(prev);
236 }
237
238 static unsigned nextWordPositionBoundary(const UChar* characters, unsigned length)
239 {
240     return findNextWordFromIndex(characters, length, 0, true);
241 }
242
243 VisiblePosition nextWordPosition(const VisiblePosition &c)
244 {
245     VisiblePosition next = nextBoundary(c, nextWordPositionBoundary);    
246     return c.honorEditableBoundaryAtOrBefore(next);
247 }
248
249 // ---------
250
251 static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
252 {
253     Position p = c.deepEquivalent();
254     Node *node = p.node();
255     if (!node)
256         return 0;
257
258     RenderObject *renderer = node->renderer();
259     if (!renderer)
260         return 0;
261
262     InlineBox* box;
263     int offset;
264     c.getInlineBoxAndOffset(box, offset);
265     
266     return box ? box->root() : 0;
267 }
268
269 static VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c)
270 {
271     // return table offset 0 instead of the first VisiblePosition inside the table
272     VisiblePosition previous = c.previous();
273     if (isLastPositionBeforeTable(previous))
274         return previous;
275     
276     return c;
277 }
278
279 static VisiblePosition startPositionForLine(const VisiblePosition& c)
280 {
281     if (c.isNull())
282         return VisiblePosition();
283
284     RootInlineBox *rootBox = rootBoxForLine(c);
285     if (!rootBox) {
286         // There are VisiblePositions at offset 0 in blocks without
287         // RootInlineBoxes, like empty editable blocks and bordered blocks.
288         Position p = c.deepEquivalent();
289         if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.offset() == 0)
290             return positionAvoidingFirstPositionInTable(c);
291         
292         return VisiblePosition();
293     }
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->renderer();
305         if (!startRenderer)
306             return VisiblePosition();
307
308         startNode = startRenderer->node();
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->start();
319     }
320   
321     VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM);
322     return positionAvoidingFirstPositionInTable(visPos);
323 }
324
325 VisiblePosition startOfLine(const VisiblePosition& c)
326 {
327     VisiblePosition visPos = startPositionForLine(c);
328     
329     if (visPos.isNotNull()) {
330         // Make sure the start of line is not greater than the given input position.  Else use the previous position to 
331         // obtain start of line.  This condition happens when the input position is before the space character at the end 
332         // of a soft-wrapped non-editable line. In this scenario, startPositionForLine would incorrectly hand back a position
333         // greater than the input position.  This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space 
334         // style versus lines without that style, which would break before a space by default. 
335         Position p = visPos.deepEquivalent();
336         if (p.offset() > c.deepEquivalent().offset() && p.node()->isSameNode(c.deepEquivalent().node())) {
337             visPos = c.previous();
338             if (visPos.isNull())
339                 return VisiblePosition();
340             visPos = startPositionForLine(visPos);
341         }
342     }
343
344     return c.honorEditableBoundaryAtOrAfter(visPos);
345 }
346
347 static VisiblePosition endPositionForLine(const VisiblePosition& c)
348 {
349     if (c.isNull())
350         return VisiblePosition();
351
352     RootInlineBox *rootBox = rootBoxForLine(c);
353     if (!rootBox) {
354         // There are VisiblePositions at offset 0 in blocks without
355         // RootInlineBoxes, like empty editable blocks and bordered blocks.
356         Position p = c.deepEquivalent();
357         if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.offset() == 0)
358             return c;
359         return VisiblePosition();
360     }
361     
362     // Generated content (e.g. list markers and CSS :before and :after
363     // pseudoelements) have no corresponding DOM element, and so cannot be
364     // represented by a VisiblePosition.  Use whatever precedes instead.
365     Node *endNode;
366     InlineBox *endBox = rootBox->lastLeafChild();
367     while (1) {
368         if (!endBox)
369             return VisiblePosition();
370
371         RenderObject *endRenderer = endBox->renderer();
372         if (!endRenderer)
373             return VisiblePosition();
374
375         endNode = endRenderer->node();
376         if (endNode)
377             break;
378         
379         endBox = endBox->prevLeafChild();
380     }
381     
382     int endOffset = 1;
383     if (endNode->hasTagName(brTag)) {
384         endOffset = 0;
385     } else if (endBox->isInlineTextBox()) {
386         InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
387         endOffset = endTextBox->start();
388         if (!endTextBox->isLineBreak())
389             endOffset += endTextBox->len();
390     }
391     
392     return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
393 }
394
395 VisiblePosition endOfLine(const VisiblePosition& c)
396 {
397     VisiblePosition visPos = endPositionForLine(c);
398     
399     // Make sure the end of line is at the same line as the given input position.  Else use the previous position to 
400     // obtain end of line.  This condition happens when the input position is before the space character at the end 
401     // of a soft-wrapped non-editable line. In this scenario, endPositionForLine would incorrectly hand back a position
402     // in the next line instead. This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space style
403     // versus lines without that style, which would break before a space by default. 
404     if (!inSameLine(c, visPos)) {
405         visPos = c.previous();
406         if (visPos.isNull())
407             return VisiblePosition();
408         visPos = endPositionForLine(visPos);
409     }
410     
411     return c.honorEditableBoundaryAtOrBefore(visPos);
412 }
413
414 bool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
415 {
416     return a.isNotNull() && startOfLine(a) == startOfLine(b);
417 }
418
419 bool isStartOfLine(const VisiblePosition &p)
420 {
421     return p.isNotNull() && p == startOfLine(p);
422 }
423
424 bool isEndOfLine(const VisiblePosition &p)
425 {
426     return p.isNotNull() && p == endOfLine(p);
427 }
428
429 // The first leaf before node that has the same editability as node.
430 static Node* previousLeafWithSameEditability(Node* node)
431 {
432     bool editable = node->isContentEditable();
433     Node* n = node->previousLeafNode();
434     while (n) {
435         if (editable == n->isContentEditable())
436             return n;
437         n = n->previousLeafNode();
438     }
439     return 0;
440 }
441
442 VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
443 {
444     Position p = visiblePosition.deepEquivalent();
445     Node *node = p.node();
446     Node* highestRoot = highestEditableRoot(p);
447     if (!node)
448         return VisiblePosition();
449     
450     node->document()->updateLayoutIgnorePendingStylesheets();
451     
452     RenderObject *renderer = node->renderer();
453     if (!renderer)
454         return VisiblePosition();
455
456     RenderBlock *containingBlock = 0;
457     RootInlineBox *root = 0;
458     InlineBox* box;
459     int ignoredCaretOffset;
460     visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
461     if (box) {
462         root = box->root()->prevRootBox();
463         if (root)
464             containingBlock = renderer->containingBlock();
465     }
466
467     if (!root) {
468         // This containing editable block does not have a previous line.
469         // Need to move back to previous containing editable block in this root editable
470         // block and find the last root line box in that block.
471         Node* startBlock = enclosingBlock(node);
472         Node* n = previousLeafWithSameEditability(node);
473         while (n && startBlock == enclosingBlock(n))
474             n = previousLeafWithSameEditability(n);
475         while (n) {
476             if (highestEditableRoot(Position(n, 0)) != highestRoot)
477                 break;
478             Position pos(n, caretMinOffset(n));
479             if (pos.isCandidate()) {
480                 ASSERT(n->renderer());
481                 Position maxPos(n, caretMaxOffset(n));
482                 maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
483                 if (box) {
484                     // previous root line box found
485                     root = box->root();
486                     containingBlock = n->renderer()->containingBlock();
487                     break;
488                 }
489
490                 return VisiblePosition(pos, DOWNSTREAM);
491             }
492             n = previousLeafWithSameEditability(n);
493         }
494     }
495     
496     if (root) {
497         // FIXME: Can be wrong for multi-column layout and with transforms.
498         FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint());
499         if (containingBlock->hasOverflowClip())
500             absPos -= containingBlock->layer()->scrolledContentOffset();
501         RenderObject* renderer = root->closestLeafChildForXPos(x - absPos.x(), isEditablePosition(p))->renderer();
502         Node* node = renderer->node();
503         if (editingIgnoresContent(node))
504             return Position(node->parent(), node->nodeIndex());
505         return renderer->positionForCoordinates(x - absPos.x(), root->topOverflow());
506     }
507     
508     // Could not find a previous line. This means we must already be on the first line.
509     // Move to the start of the content in this block, which effectively moves us
510     // to the start of the line we're on.
511     Node* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
512     return VisiblePosition(rootElement, 0, DOWNSTREAM);
513 }
514
515 static Node* nextLeafWithSameEditability(Node* node, int offset)
516 {
517     bool editable = node->isContentEditable();
518     ASSERT(offset >= 0);
519     Node* child = node->childNode(offset);
520     Node* n = child ? child->nextLeafNode() : node->nextLeafNode();
521     while (n) {
522         if (editable == n->isContentEditable())
523             return n;
524         n = n->nextLeafNode();
525     }
526     return 0;
527 }
528
529 static Node* nextLeafWithSameEditability(Node* node)
530 {
531     if (!node)
532         return 0;
533     
534     bool editable = node->isContentEditable();
535     Node* n = node->nextLeafNode();
536     while (n) {
537         if (editable == n->isContentEditable())
538             return n;
539         n = n->nextLeafNode();
540     }
541     return 0;
542 }
543
544 VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
545 {
546     Position p = visiblePosition.deepEquivalent();
547     Node *node = p.node();
548     Node* highestRoot = highestEditableRoot(p);
549     if (!node)
550         return VisiblePosition();
551     
552     node->document()->updateLayoutIgnorePendingStylesheets();
553
554     RenderObject *renderer = node->renderer();
555     if (!renderer)
556         return VisiblePosition();
557
558     RenderBlock *containingBlock = 0;
559     RootInlineBox *root = 0;
560     InlineBox* box;
561     int ignoredCaretOffset;
562     visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
563     if (box) {
564         root = box->root()->nextRootBox();
565         if (root)
566             containingBlock = renderer->containingBlock();
567     }
568
569     if (!root) {
570         // This containing editable block does not have a next line.
571         // Need to move forward to next containing editable block in this root editable
572         // block and find the first root line box in that block.
573         Node* startBlock = enclosingBlock(node);
574         Node* n = nextLeafWithSameEditability(node, p.offset());
575         while (n && startBlock == enclosingBlock(n))
576             n = nextLeafWithSameEditability(n);
577         while (n) {
578             if (highestEditableRoot(Position(n, 0)) != highestRoot)
579                 break;
580             Position pos(n, caretMinOffset(n));
581             if (pos.isCandidate()) {
582                 ASSERT(n->renderer());
583                 pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
584                 if (box) {
585                     // next root line box found
586                     root = box->root();
587                     containingBlock = n->renderer()->containingBlock();
588                     break;
589                 }
590
591                 return VisiblePosition(pos, DOWNSTREAM);
592             }
593             n = nextLeafWithSameEditability(n);
594         }
595     }
596     
597     if (root) {
598         // FIXME: Can be wrong for multi-column layout and with transforms.
599         FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint());
600         if (containingBlock->hasOverflowClip())
601             absPos -= containingBlock->layer()->scrolledContentOffset();
602         RenderObject* renderer = root->closestLeafChildForXPos(x - absPos.x(), isEditablePosition(p))->renderer();
603         Node* node = renderer->node();
604         if (editingIgnoresContent(node))
605             return Position(node->parent(), node->nodeIndex());
606         return renderer->positionForCoordinates(x - absPos.x(), root->topOverflow());
607     }    
608
609     // Could not find a next line. This means we must already be on the last line.
610     // Move to the end of the content in this block, which effectively moves us
611     // to the end of the line we're on.
612     Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
613     return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
614 }
615
616 // ---------
617
618 static unsigned startSentenceBoundary(const UChar* characters, unsigned length)
619 {
620     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
621     // FIXME: The following function can return -1; we don't handle that.
622     return textBreakPreceding(iterator, length);
623 }
624
625 VisiblePosition startOfSentence(const VisiblePosition &c)
626 {
627     return previousBoundary(c, startSentenceBoundary);
628 }
629
630 static unsigned endSentenceBoundary(const UChar* characters, unsigned length)
631 {
632     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
633     return textBreakNext(iterator);
634 }
635
636 // FIXME: This includes the space after the punctuation that marks the end of the sentence.
637 VisiblePosition endOfSentence(const VisiblePosition &c)
638 {
639     return nextBoundary(c, endSentenceBoundary);
640 }
641
642 static unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length)
643 {
644     // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right.
645     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
646     // FIXME: The following function can return -1; we don't handle that.
647     return textBreakPreceding(iterator, length);
648 }
649
650 VisiblePosition previousSentencePosition(const VisiblePosition &c)
651 {
652     VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary);
653     return c.honorEditableBoundaryAtOrAfter(prev);
654 }
655
656 static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length)
657 {
658     // FIXME: This is identical to endSentenceBoundary.  This isn't right, it needs to 
659     // move to the equivlant position in the following sentence.
660     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
661     return textBreakFollowing(iterator, 0);
662 }
663
664 VisiblePosition nextSentencePosition(const VisiblePosition &c)
665 {
666     VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary);    
667     return c.honorEditableBoundaryAtOrBefore(next);
668 }
669
670 // FIXME: Broken for positions before/after images that aren't inline (5027702)
671 VisiblePosition startOfParagraph(const VisiblePosition &c)
672 {
673     Position p = c.deepEquivalent();
674     Node *startNode = p.node();
675
676     if (!startNode)
677         return VisiblePosition();
678     
679     if (startNode->renderer()
680         && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
681             || startNode->renderer()->isHR())
682         && p.offset() == maxDeepOffset(startNode))
683         return VisiblePosition(Position(startNode, 0));
684
685     Node* startBlock = enclosingBlock(startNode);
686
687     Node *node = startNode;
688     int offset = p.offset();
689
690     Node *n = startNode;
691     while (n) {
692         if (n->isContentEditable() != startNode->isContentEditable())
693             break;
694         RenderObject *r = n->renderer();
695         if (!r) {
696             n = n->traversePreviousNodePostOrder(startBlock);
697             continue;
698         }
699         RenderStyle *style = r->style();
700         if (style->visibility() != VISIBLE) {
701             n = n->traversePreviousNodePostOrder(startBlock);
702             continue;
703         }
704         
705         if (r->isBR() || isBlock(n))
706             break;
707             
708         if (r->isText()) {
709             if (style->preserveNewline()) {
710                 const UChar* chars = toRenderText(r)->characters();
711                 int i = toRenderText(r)->textLength();
712                 int o = offset;
713                 if (n == startNode && o < i)
714                     i = max(0, o);
715                 while (--i >= 0)
716                     if (chars[i] == '\n')
717                         return VisiblePosition(n, i + 1, DOWNSTREAM);
718             }
719             node = n;
720             offset = 0;
721             n = n->traversePreviousNodePostOrder(startBlock);
722         } else if (editingIgnoresContent(n) || isTableElement(n)) {
723             node = n;
724             offset = 0;
725             n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
726         } else
727             n = n->traversePreviousNodePostOrder(startBlock);
728     }
729
730     return VisiblePosition(node, offset, DOWNSTREAM);
731 }
732
733 // FIXME: Broken for positions before/after images that aren't inline (5027702)
734 VisiblePosition endOfParagraph(const VisiblePosition &c)
735 {    
736     if (c.isNull())
737         return VisiblePosition();
738
739     Position p = c.deepEquivalent();
740     Node* startNode = p.node();
741
742     if (startNode->renderer()
743         && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
744             || startNode->renderer()->isHR())
745         && p.offset() == 0)
746         return VisiblePosition(Position(startNode, maxDeepOffset(startNode)));
747     
748     Node* startBlock = enclosingBlock(startNode);
749     Node *stayInsideBlock = startBlock;
750     
751     Node *node = startNode;
752     int offset = p.offset();
753
754     Node *n = startNode;
755     while (n) {
756         if (n->isContentEditable() != startNode->isContentEditable())
757             break;
758         RenderObject *r = n->renderer();
759         if (!r) {
760             n = n->traverseNextNode(stayInsideBlock);
761             continue;
762         }
763         RenderStyle *style = r->style();
764         if (style->visibility() != VISIBLE) {
765             n = n->traverseNextNode(stayInsideBlock);
766             continue;
767         }
768         
769         if (r->isBR() || isBlock(n))
770             break;
771             
772         // FIXME: We avoid returning a position where the renderer can't accept the caret.
773         // We should probably do this in other cases such as startOfParagraph.
774         if (r->isText() && r->caretMaxRenderedOffset() > 0) {
775             int length = toRenderText(r)->textLength();
776             if (style->preserveNewline()) {
777                 const UChar* chars = toRenderText(r)->characters();
778                 int o = n == startNode ? offset : 0;
779                 for (int i = o; i < length; ++i)
780                     if (chars[i] == '\n')
781                         return VisiblePosition(n, i, DOWNSTREAM);
782             }
783             node = n;
784             offset = r->caretMaxOffset();
785             n = n->traverseNextNode(stayInsideBlock);
786         } else if (editingIgnoresContent(n) || isTableElement(n)) {
787             node = n;
788             offset = maxDeepOffset(n);
789             n = n->traverseNextSibling(stayInsideBlock);
790         } else
791             n = n->traverseNextNode(stayInsideBlock);
792     }
793
794     return VisiblePosition(node, offset, DOWNSTREAM);
795 }
796
797 VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
798 {
799     VisiblePosition paragraphEnd(endOfParagraph(visiblePosition));
800     VisiblePosition afterParagraphEnd(paragraphEnd.next(true));
801     // The position after the last position in the last cell of a table
802     // is not the start of the next paragraph.
803     if (isFirstPositionAfterTable(afterParagraphEnd))
804         return afterParagraphEnd.next(true);
805     return afterParagraphEnd;
806 }
807
808 bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
809 {
810     return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
811 }
812
813 bool isStartOfParagraph(const VisiblePosition &pos)
814 {
815     return pos.isNotNull() && pos == startOfParagraph(pos);
816 }
817
818 bool isEndOfParagraph(const VisiblePosition &pos)
819 {
820     return pos.isNotNull() && pos == endOfParagraph(pos);
821 }
822
823 VisiblePosition previousParagraphPosition(const VisiblePosition &p, int x)
824 {
825     VisiblePosition pos = p;
826     do {
827         VisiblePosition n = previousLinePosition(pos, x);
828         if (n.isNull() || n == pos)
829             return p;
830         pos = n;
831     } while (inSameParagraph(p, pos));
832     return pos;
833 }
834
835 VisiblePosition nextParagraphPosition(const VisiblePosition &p, int x)
836 {
837     VisiblePosition pos = p;
838     do {
839         VisiblePosition n = nextLinePosition(pos, x);
840         if (n.isNull() || n == pos)
841             return p;
842         pos = n;
843     } while (inSameParagraph(p, pos));
844     return pos;
845 }
846
847 // ---------
848
849 VisiblePosition startOfBlock(const VisiblePosition &c)
850 {
851     Position p = c.deepEquivalent();
852     Node *startNode = p.node();
853     if (!startNode)
854         return VisiblePosition();
855     return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
856 }
857
858 VisiblePosition endOfBlock(const VisiblePosition &c)
859 {
860     Position p = c.deepEquivalent();
861
862     Node *startNode = p.node();
863     if (!startNode)
864         return VisiblePosition();
865
866     Node *startBlock = startNode->enclosingBlockFlowElement();
867     
868     return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);   
869 }
870
871 bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
872 {
873     return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
874 }
875
876 bool isStartOfBlock(const VisiblePosition &pos)
877 {
878     return pos.isNotNull() && pos == startOfBlock(pos);
879 }
880
881 bool isEndOfBlock(const VisiblePosition &pos)
882 {
883     return pos.isNotNull() && pos == endOfBlock(pos);
884 }
885
886 // ---------
887
888 VisiblePosition startOfDocument(const Node* node)
889 {
890     if (!node)
891         return VisiblePosition();
892     
893     return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
894 }
895
896 VisiblePosition startOfDocument(const VisiblePosition &c)
897 {
898     return startOfDocument(c.deepEquivalent().node());
899 }
900
901 VisiblePosition endOfDocument(const Node* node)
902 {
903     if (!node || !node->document())
904         return VisiblePosition();
905     
906     Element* doc = node->document()->documentElement();
907     return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
908 }
909
910 VisiblePosition endOfDocument(const VisiblePosition &c)
911 {
912     return endOfDocument(c.deepEquivalent().node());
913 }
914
915 bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
916 {
917     Position ap = a.deepEquivalent();
918     Node *an = ap.node();
919     if (!an)
920         return false;
921     Position bp = b.deepEquivalent();
922     Node *bn = bp.node();
923     if (an == bn)
924         return true;
925
926     return an->document() == bn->document();
927 }
928
929 bool isStartOfDocument(const VisiblePosition &p)
930 {
931     return p.isNotNull() && p.previous().isNull();
932 }
933
934 bool isEndOfDocument(const VisiblePosition &p)
935 {
936     return p.isNotNull() && p.next().isNull();
937 }
938
939 // ---------
940
941 VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
942 {
943     Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
944     if (!highestRoot)
945         return VisiblePosition();
946
947     return VisiblePosition(highestRoot, 0, DOWNSTREAM);
948 }
949
950 VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
951 {
952     Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
953     if (!highestRoot)
954         return VisiblePosition();
955
956     return VisiblePosition(highestRoot, maxDeepOffset(highestRoot), DOWNSTREAM);
957 }
958
959 }