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