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