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