2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "visible_units.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 "htmlediting.h"
41 using namespace HTMLNames;
43 static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
45 Position pos = c.deepEquivalent();
48 return VisiblePosition();
49 Document *d = n->document();
50 Node *de = d->documentElement();
52 return VisiblePosition();
53 Node *boundary = n->enclosingBlockFlowElement();
55 return VisiblePosition();
56 bool isContentEditable = boundary->isContentEditable();
57 while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
58 boundary = boundary->parentNode();
60 Position start = rangeCompliantEquivalent(Position(boundary, 0));
61 Position end = rangeCompliantEquivalent(pos);
62 RefPtr<Range> searchRange = new Range(d);
65 searchRange->setStart(start.node(), start.offset(), exception);
66 searchRange->setEnd(end.node(), end.offset(), exception);
70 return VisiblePosition();
72 SimplifiedBackwardsTextIterator it(searchRange.get());
73 Vector<UChar, 1024> string;
75 bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
77 // iterate to get chunks until the searchFunction returns a non-zero value.
78 if (!inTextSecurityMode)
79 string.prepend(it.characters(), it.length());
81 // Treat bullets used in the text security mode as regular characters when looking for boundaries
82 String iteratorString(it.characters(), it.length());
83 iteratorString = iteratorString.impl()->secure('x');
84 string.prepend(iteratorString.characters(), iteratorString.length());
87 next = searchFunction(string.data(), string.size());
93 if (it.atEnd() && next == 0) {
94 pos = it.range()->startPosition();
95 } else if (next != 0) {
96 Node *node = it.range()->startContainer(exception);
97 if (node->isTextNode() || (node->renderer() && node->renderer()->isBR()))
98 // The next variable contains a usable index into a text node
99 pos = Position(node, next);
101 // Use the end of the found range, the start is not guaranteed to
103 Position end = it.range()->endPosition();
104 VisiblePosition boundary(end);
105 unsigned i = it.length() - next;
107 boundary = boundary.previous();
112 return VisiblePosition(pos, DOWNSTREAM);
115 static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
117 Position pos = c.deepEquivalent();
118 Node *n = pos.node();
120 return VisiblePosition();
121 Document *d = n->document();
122 Node *de = d->documentElement();
124 return VisiblePosition();
125 Node *boundary = n->enclosingBlockFlowElement();
127 return VisiblePosition();
128 bool isContentEditable = boundary->isContentEditable();
129 while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
130 boundary = boundary->parentNode();
132 RefPtr<Range> searchRange(d->createRange());
133 Position start(rangeCompliantEquivalent(pos));
134 ExceptionCode ec = 0;
135 searchRange->selectNodeContents(boundary, ec);
136 searchRange->setStart(start.node(), start.offset(), ec);
137 TextIterator it(searchRange.get(), true);
138 Vector<UChar, 1024> string;
140 bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
141 while (!it.atEnd()) {
142 // Keep asking the iterator for chunks until the search function
143 // returns an end value not equal to the length of the string passed to it.
144 if (!inTextSecurityMode)
145 string.append(it.characters(), it.length());
147 // Treat bullets used in the text security mode as regular characters when looking for boundaries
148 String iteratorString(it.characters(), it.length());
149 iteratorString = iteratorString.impl()->secure('x');
150 string.append(iteratorString.characters(), iteratorString.length());
153 next = searchFunction(string.data(), string.size());
154 if (next != string.size())
159 if (it.atEnd() && next == string.size()) {
160 pos = it.range()->startPosition();
161 } else if (next != 0) {
162 // Use the character iterator to translate the next value into a DOM position.
163 CharacterIterator charIt(searchRange.get(), true);
164 charIt.advance(next - 1);
165 pos = charIt.range()->endPosition();
167 // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593)
168 VisiblePosition visPos = VisiblePosition(pos);
169 if (visPos == VisiblePosition(charIt.range()->startPosition()))
170 pos = visPos.next(true).deepEquivalent();
173 // generate VisiblePosition, use UPSTREAM affinity if possible
174 return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
179 static unsigned startWordBoundary(const UChar* characters, unsigned length)
182 findWordBoundary(characters, length, length, &start, &end);
186 VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
188 // FIXME: This returns a null VP for c at the start of the document
189 // and side == LeftWordIfOnBoundary
190 VisiblePosition p = c;
191 if (side == RightWordIfOnBoundary) {
192 // at paragraph end, the startofWord is the current position
193 if (isEndOfParagraph(c))
200 return previousBoundary(p, startWordBoundary);
203 static unsigned endWordBoundary(const UChar* characters, unsigned length)
206 findWordBoundary(characters, length, 0, &start, &end);
210 VisiblePosition endOfWord(const VisiblePosition &c, EWordSide side)
212 VisiblePosition p = c;
213 if (side == LeftWordIfOnBoundary) {
214 if (isStartOfParagraph(c))
221 // at paragraph end, the endOfWord is the start of next paragraph
222 if (isEndOfParagraph(c)) {
224 return p.isNotNull() ? p : c;
228 return nextBoundary(p, endWordBoundary);
231 static unsigned previousWordPositionBoundary(const UChar* characters, unsigned length)
233 return findNextWordFromIndex(characters, length, length, false);
236 VisiblePosition previousWordPosition(const VisiblePosition &c)
238 VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary);
239 return c.firstEditablePositionAtOrAfter(prev);
242 static unsigned nextWordPositionBoundary(const UChar* characters, unsigned length)
244 return findNextWordFromIndex(characters, length, 0, true);
247 VisiblePosition nextWordPosition(const VisiblePosition &c)
249 VisiblePosition next = nextBoundary(c, nextWordPositionBoundary);
250 return c.lastEditablePositionAtOrBefore(next);
255 static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
257 Position p = c.deepEquivalent();
258 Node *node = p.node();
262 RenderObject *renderer = node->renderer();
266 InlineBox *box = renderer->inlineBox(p.offset(), c.affinity());
274 static VisiblePosition startPositionForLine(const VisiblePosition& c)
277 return VisiblePosition();
279 RootInlineBox *rootBox = rootBoxForLine(c);
281 // There are VisiblePositions at offset 0 in blocks without
282 // RootInlineBoxes, like empty editable blocks and bordered blocks.
283 Position p = c.deepEquivalent();
284 if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.offset() == 0)
286 return VisiblePosition();
289 // Generated content (e.g. list markers and CSS :before and :after
290 // pseudoelements) have no corresponding DOM element, and so cannot be
291 // represented by a VisiblePosition. Use whatever follows instead.
292 InlineBox *startBox = rootBox->firstLeafChild();
296 return VisiblePosition();
298 RenderObject *startRenderer = startBox->object();
300 return VisiblePosition();
302 startNode = startRenderer->element();
306 startBox = startBox->nextLeafChild();
310 if (startBox->isInlineTextBox()) {
311 InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
312 startOffset = startTextBox->m_start;
315 VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM);
317 // return table offset 0 instead of the first VisiblePosition inside the table
318 VisiblePosition visPrevious = visPos.previous();
319 if (isLastPositionBeforeTable(visPrevious))
320 visPos = visPrevious;
325 VisiblePosition startOfLine(const VisiblePosition& c)
327 VisiblePosition visPos = startPositionForLine(c);
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();
339 return VisiblePosition();
340 visPos = startPositionForLine(visPos);
344 return c.firstEditablePositionAtOrAfter(visPos);
347 static VisiblePosition endPositionForLine(const VisiblePosition& c)
350 return VisiblePosition();
352 RootInlineBox *rootBox = rootBoxForLine(c);
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)
359 return VisiblePosition();
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.
366 InlineBox *endBox = rootBox->lastLeafChild();
369 return VisiblePosition();
371 RenderObject *endRenderer = endBox->object();
373 return VisiblePosition();
375 endNode = endRenderer->element();
379 endBox = endBox->prevLeafChild();
383 if (endNode->hasTagName(brTag)) {
385 } else if (endBox->isInlineTextBox()) {
386 InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
387 endOffset = endTextBox->m_start;
388 if (!endTextBox->isLineBreak())
389 endOffset += endTextBox->m_len;
392 return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
395 VisiblePosition endOfLine(const VisiblePosition& c)
397 VisiblePosition visPos = endPositionForLine(c);
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();
407 return VisiblePosition();
408 visPos = endPositionForLine(visPos);
411 return c.lastEditablePositionAtOrBefore(visPos);
414 bool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
416 return a.isNotNull() && startOfLine(a) == startOfLine(b);
419 bool isStartOfLine(const VisiblePosition &p)
421 return p.isNotNull() && p == startOfLine(p);
424 bool isEndOfLine(const VisiblePosition &p)
426 return p.isNotNull() && p == endOfLine(p);
429 VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
431 Position p = visiblePosition.deepEquivalent();
432 Node *node = p.node();
433 Node* highestRoot = highestEditableRoot(p);
435 return VisiblePosition();
437 node->document()->updateLayoutIgnorePendingStylesheets();
439 RenderObject *renderer = node->renderer();
441 return VisiblePosition();
443 RenderBlock *containingBlock = 0;
444 RootInlineBox *root = 0;
445 InlineBox *box = renderer->inlineBox(p.offset(), visiblePosition.affinity());
447 root = box->root()->prevRootBox();
449 containingBlock = renderer->containingBlock();
453 // This containing editable block does not have a previous line.
454 // Need to move back to previous containing editable block in this root editable
455 // block and find the last root line box in that block.
456 Node* startBlock = enclosingBlock(node);
457 Node *n = node->previousEditable();
458 while (n && startBlock == enclosingBlock(n))
459 n = n->previousEditable();
461 if (highestEditableRoot(Position(n, 0)) != highestRoot)
463 Position pos(n, n->caretMinOffset());
464 if (pos.isCandidate()) {
465 ASSERT(n->renderer());
466 box = n->renderer()->inlineBox(n->caretMaxOffset());
468 // previous root line box found
470 containingBlock = n->renderer()->containingBlock();
474 return VisiblePosition(pos, DOWNSTREAM);
476 n = n->previousEditable();
481 // FIXME: Can be wrong for multi-column layout.
483 containingBlock->absolutePositionForContent(absx, absy);
484 if (containingBlock->hasOverflowClip())
485 containingBlock->layer()->subtractScrollOffset(absx, absy);
486 RenderObject *renderer = root->closestLeafChildForXPos(x - absx, isEditablePosition(p))->object();
487 Node* node = renderer->element();
488 if (editingIgnoresContent(node))
489 return Position(node->parent(), node->nodeIndex());
490 return renderer->positionForCoordinates(x - absx, root->topOverflow());
493 // Could not find a previous line. This means we must already be on the first line.
494 // Move to the start of the content in this block, which effectively moves us
495 // to the start of the line we're on.
496 return VisiblePosition(node->rootEditableElement(), 0, DOWNSTREAM);
499 VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
501 Position p = visiblePosition.deepEquivalent();
502 Node *node = p.node();
503 Node* highestRoot = highestEditableRoot(p);
505 return VisiblePosition();
507 node->document()->updateLayoutIgnorePendingStylesheets();
509 RenderObject *renderer = node->renderer();
511 return VisiblePosition();
513 RenderBlock *containingBlock = 0;
514 RootInlineBox *root = 0;
515 InlineBox *box = renderer->inlineBox(p.offset(), visiblePosition.affinity());
517 root = box->root()->nextRootBox();
519 containingBlock = renderer->containingBlock();
523 // This containing editable block does not have a next line.
524 // Need to move forward to next containing editable block in this root editable
525 // block and find the first root line box in that block.
526 Node* startBlock = enclosingBlock(node);
527 Node *n = node->nextEditable(p.offset());
528 while (n && startBlock == enclosingBlock(n))
529 n = n->nextEditable();
531 if (highestEditableRoot(Position(n, 0)) != highestRoot)
533 Position pos(n, n->caretMinOffset());
534 if (pos.isCandidate()) {
535 ASSERT(n->renderer());
536 box = n->renderer()->inlineBox(n->caretMinOffset());
538 // next root line box found
540 containingBlock = n->renderer()->containingBlock();
544 return VisiblePosition(pos, DOWNSTREAM);
546 n = n->nextEditable();
551 // FIXME: Can be wrong for multi-column layout.
553 containingBlock->absolutePositionForContent(absx, absy);
554 if (containingBlock->hasOverflowClip())
555 containingBlock->layer()->subtractScrollOffset(absx, absy);
556 RenderObject *renderer = root->closestLeafChildForXPos(x - absx, isEditablePosition(p))->object();
557 Node* node = renderer->element();
558 if (editingIgnoresContent(node))
559 return Position(node->parent(), node->nodeIndex());
560 return renderer->positionForCoordinates(x - absx, root->topOverflow());
563 // Could not find a next line. This means we must already be on the last line.
564 // Move to the end of the content in this block, which effectively moves us
565 // to the end of the line we're on.
566 Element *rootElement = node->rootEditableElement();
567 return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
572 static unsigned startSentenceBoundary(const UChar* characters, unsigned length)
574 TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
575 // FIXME: The following function can return -1; we don't handle that.
576 return textBreakPreceding(iterator, length);
579 VisiblePosition startOfSentence(const VisiblePosition &c)
581 return previousBoundary(c, startSentenceBoundary);
584 static unsigned endSentenceBoundary(const UChar* characters, unsigned length)
586 TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
587 return textBreakNext(iterator);
590 // FIXME: This includes the space after the punctuation that marks the end of the sentence.
591 VisiblePosition endOfSentence(const VisiblePosition &c)
593 return nextBoundary(c, endSentenceBoundary);
596 static unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length)
598 // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right.
599 TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
600 // FIXME: The following function can return -1; we don't handle that.
601 return textBreakPreceding(iterator, length);
604 VisiblePosition previousSentencePosition(const VisiblePosition &c)
606 VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary);
607 return c.firstEditablePositionAtOrAfter(prev);
610 static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length)
612 // FIXME: This is identical to endSentenceBoundary. This isn't right, it needs to
613 // move to the equivlant position in the following sentence.
614 TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
615 return textBreakFollowing(iterator, 0);
618 VisiblePosition nextSentencePosition(const VisiblePosition &c)
620 VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary);
621 return c.lastEditablePositionAtOrBefore(next);
624 // FIXME: Broken for positions before/after images that aren't inline (5027702)
625 VisiblePosition startOfParagraph(const VisiblePosition &c)
627 Position p = c.deepEquivalent();
628 Node *startNode = p.node();
631 return VisiblePosition();
633 if (startNode->renderer()
634 && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
635 || startNode->renderer()->isHR())
636 && p.offset() == maxDeepOffset(startNode))
637 return VisiblePosition(Position(startNode, 0));
639 Node* startBlock = enclosingBlock(startNode);
641 Node *node = startNode;
642 int offset = p.offset();
646 if (n->isContentEditable() != startNode->isContentEditable())
648 RenderObject *r = n->renderer();
650 n = n->traversePreviousNodePostOrder(startBlock);
653 RenderStyle *style = r->style();
654 if (style->visibility() != VISIBLE) {
655 n = n->traversePreviousNodePostOrder(startBlock);
659 if (r->isBR() || isBlock(n))
663 if (style->preserveNewline()) {
664 const UChar* chars = static_cast<RenderText*>(r)->characters();
665 int i = static_cast<RenderText*>(r)->textLength();
667 if (n == startNode && o < i)
670 if (chars[i] == '\n')
671 return VisiblePosition(n, i + 1, DOWNSTREAM);
675 n = n->traversePreviousNodePostOrder(startBlock);
676 } else if (editingIgnoresContent(n) || isTableElement(n)) {
679 n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
681 n = n->traversePreviousNodePostOrder(startBlock);
684 return VisiblePosition(node, offset, DOWNSTREAM);
687 // FIXME: Broken for positions before/after images that aren't inline (5027702)
688 VisiblePosition endOfParagraph(const VisiblePosition &c)
691 return VisiblePosition();
693 Position p = c.deepEquivalent();
694 Node* startNode = p.node();
696 if (startNode->renderer()
697 && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
698 || startNode->renderer()->isHR())
700 return VisiblePosition(Position(startNode, maxDeepOffset(startNode)));
702 Node* startBlock = enclosingBlock(startNode);
703 Node *stayInsideBlock = startBlock;
705 Node *node = startNode;
706 int offset = p.offset();
710 if (n->isContentEditable() != startNode->isContentEditable())
712 RenderObject *r = n->renderer();
714 n = n->traverseNextNode(stayInsideBlock);
717 RenderStyle *style = r->style();
718 if (style->visibility() != VISIBLE) {
719 n = n->traverseNextNode(stayInsideBlock);
723 if (r->isBR() || isBlock(n))
726 // FIXME: We avoid returning a position where the renderer can't accept the caret.
727 // We should probably do this in other cases such as startOfParagraph.
728 if (r->isText() && r->caretMaxRenderedOffset() > 0) {
729 int length = static_cast<RenderText*>(r)->textLength();
730 if (style->preserveNewline()) {
731 const UChar* chars = static_cast<RenderText*>(r)->characters();
732 int o = n == startNode ? offset : 0;
733 for (int i = o; i < length; ++i)
734 if (chars[i] == '\n')
735 return VisiblePosition(n, i, DOWNSTREAM);
738 offset = r->caretMaxOffset();
739 n = n->traverseNextNode(stayInsideBlock);
740 } else if (editingIgnoresContent(n) || isTableElement(n)) {
742 offset = maxDeepOffset(n);
743 n = n->traverseNextSibling(stayInsideBlock);
745 n = n->traverseNextNode(stayInsideBlock);
748 return VisiblePosition(node, offset, DOWNSTREAM);
751 bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
753 return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
756 bool isStartOfParagraph(const VisiblePosition &pos)
758 return pos.isNotNull() && pos == startOfParagraph(pos);
761 bool isEndOfParagraph(const VisiblePosition &pos)
763 return pos.isNotNull() && pos == endOfParagraph(pos);
766 VisiblePosition previousParagraphPosition(const VisiblePosition &p, int x)
768 VisiblePosition pos = p;
770 VisiblePosition n = previousLinePosition(pos, x);
771 if (n.isNull() || n == pos)
774 } while (inSameParagraph(p, pos));
778 VisiblePosition nextParagraphPosition(const VisiblePosition &p, int x)
780 VisiblePosition pos = p;
782 VisiblePosition n = nextLinePosition(pos, x);
783 if (n.isNull() || n == pos)
786 } while (inSameParagraph(p, pos));
792 VisiblePosition startOfBlock(const VisiblePosition &c)
794 Position p = c.deepEquivalent();
795 Node *startNode = p.node();
797 return VisiblePosition();
798 return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
801 VisiblePosition endOfBlock(const VisiblePosition &c)
803 Position p = c.deepEquivalent();
805 Node *startNode = p.node();
807 return VisiblePosition();
809 Node *startBlock = startNode->enclosingBlockFlowElement();
811 return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);
814 bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
816 return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
819 bool isStartOfBlock(const VisiblePosition &pos)
821 return pos.isNotNull() && pos == startOfBlock(pos);
824 bool isEndOfBlock(const VisiblePosition &pos)
826 return pos.isNotNull() && pos == endOfBlock(pos);
831 VisiblePosition startOfDocument(const Node* node)
834 return VisiblePosition();
836 return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
839 VisiblePosition startOfDocument(const VisiblePosition &c)
841 return startOfDocument(c.deepEquivalent().node());
844 VisiblePosition endOfDocument(const Node* node)
846 if (!node || !node->document())
847 return VisiblePosition();
849 Element* doc = node->document()->documentElement();
850 return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
853 VisiblePosition endOfDocument(const VisiblePosition &c)
855 return endOfDocument(c.deepEquivalent().node());
858 bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
860 Position ap = a.deepEquivalent();
861 Node *an = ap.node();
864 Position bp = b.deepEquivalent();
865 Node *bn = bp.node();
869 return an->document() == bn->document();
872 bool isStartOfDocument(const VisiblePosition &p)
874 return p.isNotNull() && p.previous().isNull();
877 bool isEndOfDocument(const VisiblePosition &p)
879 return p.isNotNull() && p.next().isNull();
884 VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
886 Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
888 return VisiblePosition();
890 return VisiblePosition(highestRoot, 0, DOWNSTREAM);
893 VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
895 Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
897 return VisiblePosition();
899 return VisiblePosition(highestRoot, maxDeepOffset(highestRoot), DOWNSTREAM);