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