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 "visible_units.h" 28 29 #include "Document.h" 30 #include "Element.h" 31 #include "HTMLNames.h" 32 #include "Position.h" 33 #include "RenderBlock.h" 34 #include "RenderLayer.h" 35 #include "RenderObject.h" 36 #include "TextBoundaries.h" 37 #include "TextBreakIterator.h" 38 #include "TextIterator.h" 39 #include "VisiblePosition.h" 40 #include "VisibleSelection.h" 41 #include "htmlediting.h" 42 #include <wtf/unicode/Unicode.h> 43 44 namespace WebCore { 45 46 using namespace HTMLNames; 47 using namespace WTF::Unicode; 48 49 enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext }; 50 51 typedef unsigned (*BoundarySearchFunction)(const UChar*, unsigned length, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext); 52 53 static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction) 54 { 55 Position pos = c.deepEquivalent(); 56 Node* boundary = pos.parentEditingBoundary(); 57 if (!boundary) 58 return VisiblePosition(); 59 60 Document* d = boundary->document(); 61 Position start = Position(boundary, 0).parentAnchoredEquivalent(); 62 Position end = pos.parentAnchoredEquivalent(); 63 RefPtr<Range> searchRange = Range::create(d); 64 65 Vector<UChar, 1024> string; 66 unsigned suffixLength = 0; 67 68 ExceptionCode ec = 0; 69 if (requiresContextForWordBoundary(c.characterBefore())) { 70 RefPtr<Range> forwardsScanRange(d->createRange()); 71 forwardsScanRange->setEndAfter(boundary, ec); 72 forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec); 73 TextIterator forwardsIterator(forwardsScanRange.get()); 74 while (!forwardsIterator.atEnd()) { 75 const UChar* characters = forwardsIterator.characters(); 76 int length = forwardsIterator.length(); 77 int i = endOfFirstWordBoundaryContext(characters, length); 78 string.append(characters, i); 79 suffixLength += i; 80 if (i < length) 81 break; 82 forwardsIterator.advance(); 83 } 84 } 85 86 searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec); 87 searchRange->setEnd(end.deprecatedNode(), end.deprecatedEditingOffset(), ec); 88 89 ASSERT(!ec); 90 if (ec) 91 return VisiblePosition(); 92 93 SimplifiedBackwardsTextIterator it(searchRange.get()); 94 unsigned next = 0; 95 bool inTextSecurityMode = start.deprecatedNode() && start.deprecatedNode()->renderer() && start.deprecatedNode()->renderer()->style()->textSecurity() != TSNONE; 96 bool needMoreContext = false; 97 while (!it.atEnd()) { 98 // iterate to get chunks until the searchFunction returns a non-zero value. 99 if (!inTextSecurityMode) 100 string.prepend(it.characters(), it.length()); 101 else { 102 // Treat bullets used in the text security mode as regular characters when looking for boundaries 103 String iteratorString(it.characters(), it.length()); 104 iteratorString = iteratorString.impl()->secure('x'); 105 string.prepend(iteratorString.characters(), iteratorString.length()); 106 } 107 next = searchFunction(string.data(), string.size(), string.size() - suffixLength, MayHaveMoreContext, needMoreContext); 108 if (next != 0) 109 break; 110 it.advance(); 111 } 112 if (needMoreContext) { 113 // The last search returned the beginning of the buffer and asked for more context, 114 // but there is no earlier text. Force a search with what's available. 115 next = searchFunction(string.data(), string.size(), string.size() - suffixLength, DontHaveMoreContext, needMoreContext); 116 ASSERT(!needMoreContext); 117 } 118 119 if (!next) 120 return VisiblePosition(it.atEnd() ? it.range()->startPosition() : pos, DOWNSTREAM); 121 122 Node* node = it.range()->startContainer(ec); 123 if ((node->isTextNode() && static_cast<int>(next) <= node->maxCharacterOffset()) || (node->renderer() && node->renderer()->isBR() && !next)) 124 // The next variable contains a usable index into a text node 125 return VisiblePosition(Position(node, next), DOWNSTREAM); 126 127 // Use the character iterator to translate the next value into a DOM position. 128 BackwardsCharacterIterator charIt(searchRange.get()); 129 charIt.advance(string.size() - suffixLength - next); 130 // FIXME: charIt can get out of shadow host. 131 return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM); 132 } 133 134 static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction) 135 { 136 Position pos = c.deepEquivalent(); 137 Node* boundary = pos.parentEditingBoundary(); 138 if (!boundary) 139 return VisiblePosition(); 140 141 Document* d = boundary->document(); 142 RefPtr<Range> searchRange(d->createRange()); 143 Position start(pos.parentAnchoredEquivalent()); 144 145 Vector<UChar, 1024> string; 146 unsigned prefixLength = 0; 147 148 ExceptionCode ec = 0; 149 if (requiresContextForWordBoundary(c.characterAfter())) { 150 RefPtr<Range> backwardsScanRange(d->createRange()); 151 backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), ec); 152 SimplifiedBackwardsTextIterator backwardsIterator(backwardsScanRange.get()); 153 while (!backwardsIterator.atEnd()) { 154 const UChar* characters = backwardsIterator.characters(); 155 int length = backwardsIterator.length(); 156 int i = startOfLastWordBoundaryContext(characters, length); 157 string.prepend(characters + i, length - i); 158 prefixLength += length - i; 159 if (i > 0) 160 break; 161 backwardsIterator.advance(); 162 } 163 } 164 165 searchRange->selectNodeContents(boundary, ec); 166 searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec); 167 TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions); 168 unsigned next = 0; 169 bool inTextSecurityMode = start.deprecatedNode() && start.deprecatedNode()->renderer() && start.deprecatedNode()->renderer()->style()->textSecurity() != TSNONE; 170 bool needMoreContext = false; 171 while (!it.atEnd()) { 172 // Keep asking the iterator for chunks until the search function 173 // returns an end value not equal to the length of the string passed to it. 174 if (!inTextSecurityMode) 175 string.append(it.characters(), it.length()); 176 else { 177 // Treat bullets used in the text security mode as regular characters when looking for boundaries 178 String iteratorString(it.characters(), it.length()); 179 iteratorString = iteratorString.impl()->secure('x'); 180 string.append(iteratorString.characters(), iteratorString.length()); 181 } 182 next = searchFunction(string.data(), string.size(), prefixLength, MayHaveMoreContext, needMoreContext); 183 if (next != string.size()) 184 break; 185 it.advance(); 186 } 187 if (needMoreContext) { 188 // The last search returned the end of the buffer and asked for more context, 189 // but there is no further text. Force a search with what's available. 190 next = searchFunction(string.data(), string.size(), prefixLength, DontHaveMoreContext, needMoreContext); 191 ASSERT(!needMoreContext); 192 } 193 194 if (it.atEnd() && next == string.size()) { 195 pos = it.range()->startPosition(); 196 } else if (next != prefixLength) { 197 // Use the character iterator to translate the next value into a DOM position. 198 CharacterIterator charIt(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions); 199 charIt.advance(next - prefixLength - 1); 200 RefPtr<Range> characterRange = charIt.range(); 201 pos = characterRange->endPosition(); 202 203 if (*charIt.characters() == '\n') { 204 // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593) 205 VisiblePosition visPos = VisiblePosition(pos); 206 if (visPos == VisiblePosition(characterRange->startPosition())) { 207 charIt.advance(1); 208 pos = charIt.range()->startPosition(); 209 } 210 } 211 } 212 213 // generate VisiblePosition, use UPSTREAM affinity if possible 214 return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE); 215 } 216 217 static bool canHaveCursor(RenderObject* o) 218 { 219 return (o->isText() && toRenderText(o)->linesBoundingBox().height()) 220 || (o->isBox() && toRenderBox(o)->borderBoundingBox().height()); 221 } 222 223 // --------- 224 225 static unsigned startWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 226 { 227 ASSERT(offset); 228 if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) { 229 needMoreContext = true; 230 return 0; 231 } 232 needMoreContext = false; 233 int start, end; 234 findWordBoundary(characters, length, offset - 1, &start, &end); 235 return start; 236 } 237 238 VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side) 239 { 240 // FIXME: This returns a null VP for c at the start of the document 241 // and side == LeftWordIfOnBoundary 242 VisiblePosition p = c; 243 if (side == RightWordIfOnBoundary) { 244 // at paragraph end, the startofWord is the current position 245 if (isEndOfParagraph(c)) 246 return c; 247 248 p = c.next(); 249 if (p.isNull()) 250 return c; 251 } 252 return previousBoundary(p, startWordBoundary); 253 } 254 255 static unsigned endWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 256 { 257 ASSERT(offset <= length); 258 if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) { 259 needMoreContext = true; 260 return length; 261 } 262 needMoreContext = false; 263 int start, end; 264 findWordBoundary(characters, length, offset, &start, &end); 265 return end; 266 } 267 268 VisiblePosition endOfWord(const VisiblePosition &c, EWordSide side) 269 { 270 VisiblePosition p = c; 271 if (side == LeftWordIfOnBoundary) { 272 if (isStartOfParagraph(c)) 273 return c; 274 275 p = c.previous(); 276 if (p.isNull()) 277 return c; 278 } else if (isEndOfParagraph(c)) 279 return c; 280 281 return nextBoundary(p, endWordBoundary); 282 } 283 284 static unsigned previousWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 285 { 286 if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) { 287 needMoreContext = true; 288 return 0; 289 } 290 needMoreContext = false; 291 return findNextWordFromIndex(characters, length, offset, false); 292 } 293 294 VisiblePosition previousWordPosition(const VisiblePosition &c) 295 { 296 VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary); 297 return c.honorEditableBoundaryAtOrBefore(prev); 298 } 299 300 static unsigned nextWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 301 { 302 if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) { 303 needMoreContext = true; 304 return length; 305 } 306 needMoreContext = false; 307 return findNextWordFromIndex(characters, length, offset, true); 308 } 309 310 VisiblePosition nextWordPosition(const VisiblePosition &c) 311 { 312 VisiblePosition next = nextBoundary(c, nextWordPositionBoundary); 313 return c.honorEditableBoundaryAtOrAfter(next); 314 } 315 316 // --------- 317 318 static RootInlineBox *rootBoxForLine(const VisiblePosition &c) 319 { 320 Position p = c.deepEquivalent(); 321 Node* node = p.deprecatedNode(); 322 if (!node) 323 return 0; 324 325 RenderObject *renderer = node->renderer(); 326 if (!renderer) 327 return 0; 328 329 InlineBox* box; 330 int offset; 331 c.getInlineBoxAndOffset(box, offset); 332 333 return box ? box->root() : 0; 334 } 335 336 static VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c) 337 { 338 // return table offset 0 instead of the first VisiblePosition inside the table 339 VisiblePosition previous = c.previous(); 340 if (isLastPositionBeforeTable(previous) && isEditablePosition(previous.deepEquivalent())) 341 return previous; 342 343 return c; 344 } 345 346 static VisiblePosition startPositionForLine(const VisiblePosition& c) 347 { 348 if (c.isNull()) 349 return VisiblePosition(); 350 351 RootInlineBox *rootBox = rootBoxForLine(c); 352 if (!rootBox) { 353 // There are VisiblePositions at offset 0 in blocks without 354 // RootInlineBoxes, like empty editable blocks and bordered blocks. 355 Position p = c.deepEquivalent(); 356 if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 357 return positionAvoidingFirstPositionInTable(c); 358 359 return VisiblePosition(); 360 } 361 362 // Generated content (e.g. list markers and CSS :before and :after 363 // pseudoelements) have no corresponding DOM element, and so cannot be 364 // represented by a VisiblePosition. Use whatever follows instead. 365 InlineBox *startBox = rootBox->firstLeafChild(); 366 Node *startNode; 367 while (1) { 368 if (!startBox) 369 return VisiblePosition(); 370 371 RenderObject *startRenderer = startBox->renderer(); 372 if (!startRenderer) 373 return VisiblePosition(); 374 375 startNode = startRenderer->node(); 376 if (startNode) 377 break; 378 379 startBox = startBox->nextLeafChild(); 380 } 381 382 VisiblePosition visPos = startNode->isTextNode() ? VisiblePosition(Position(startNode, static_cast<InlineTextBox *>(startBox)->start(), Position::PositionIsOffsetInAnchor), DOWNSTREAM) 383 : VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM); 384 return positionAvoidingFirstPositionInTable(visPos); 385 } 386 387 VisiblePosition startOfLine(const VisiblePosition& c) 388 { 389 VisiblePosition visPos = startPositionForLine(c); 390 391 return c.honorEditableBoundaryAtOrBefore(visPos); 392 } 393 394 static VisiblePosition endPositionForLine(const VisiblePosition& c) 395 { 396 if (c.isNull()) 397 return VisiblePosition(); 398 399 RootInlineBox *rootBox = rootBoxForLine(c); 400 if (!rootBox) { 401 // There are VisiblePositions at offset 0 in blocks without 402 // RootInlineBoxes, like empty editable blocks and bordered blocks. 403 Position p = c.deepEquivalent(); 404 if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 405 return c; 406 return VisiblePosition(); 407 } 408 409 // Generated content (e.g. list markers and CSS :before and :after 410 // pseudoelements) have no corresponding DOM element, and so cannot be 411 // represented by a VisiblePosition. Use whatever precedes instead. 412 Node *endNode; 413 InlineBox *endBox = rootBox->lastLeafChild(); 414 while (1) { 415 if (!endBox) 416 return VisiblePosition(); 417 418 RenderObject *endRenderer = endBox->renderer(); 419 if (!endRenderer) 420 return VisiblePosition(); 421 422 endNode = endRenderer->node(); 423 if (endNode) 424 break; 425 426 endBox = endBox->prevLeafChild(); 427 } 428 429 Position pos; 430 if (endNode->hasTagName(brTag)) { 431 pos = positionBeforeNode(endNode); 432 } else if (endBox->isInlineTextBox()) { 433 InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox); 434 int endOffset = endTextBox->start(); 435 if (!endTextBox->isLineBreak()) 436 endOffset += endTextBox->len(); 437 pos = Position(endNode, endOffset, Position::PositionIsOffsetInAnchor); 438 } else 439 pos = positionAfterNode(endNode); 440 441 return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE); 442 } 443 444 VisiblePosition endOfLine(const VisiblePosition& c) 445 { 446 VisiblePosition visPos = endPositionForLine(c); 447 448 // Make sure the end of line is at the same line as the given input position. Else use the previous position to 449 // obtain end of line. This condition happens when the input position is before the space character at the end 450 // of a soft-wrapped non-editable line. In this scenario, endPositionForLine would incorrectly hand back a position 451 // in the next line instead. This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space style 452 // versus lines without that style, which would break before a space by default. 453 if (!inSameLine(c, visPos)) { 454 visPos = c.previous(); 455 if (visPos.isNull()) 456 return VisiblePosition(); 457 visPos = endPositionForLine(visPos); 458 } 459 460 return c.honorEditableBoundaryAtOrAfter(visPos); 461 } 462 463 bool inSameLine(const VisiblePosition &a, const VisiblePosition &b) 464 { 465 return a.isNotNull() && startOfLine(a) == startOfLine(b); 466 } 467 468 bool isStartOfLine(const VisiblePosition &p) 469 { 470 return p.isNotNull() && p == startOfLine(p); 471 } 472 473 bool isEndOfLine(const VisiblePosition &p) 474 { 475 return p.isNotNull() && p == endOfLine(p); 476 } 477 478 // The first leaf before node that has the same editability as node. 479 static Node* previousLeafWithSameEditability(Node* node) 480 { 481 bool editable = node->rendererIsEditable(); 482 Node* n = node->previousLeafNode(); 483 while (n) { 484 if (editable == n->rendererIsEditable()) 485 return n; 486 n = n->previousLeafNode(); 487 } 488 return 0; 489 } 490 491 static Node* enclosingNodeWithNonInlineRenderer(Node* n) 492 { 493 for (Node* p = n; p; p = p->parentNode()) { 494 if (p->renderer() && !p->renderer()->isInline()) 495 return p; 496 } 497 return 0; 498 } 499 500 VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x) 501 { 502 Position p = visiblePosition.deepEquivalent(); 503 Node* node = p.deprecatedNode(); 504 Node* highestRoot = highestEditableRoot(p); 505 if (!node) 506 return VisiblePosition(); 507 508 node->document()->updateLayoutIgnorePendingStylesheets(); 509 510 RenderObject *renderer = node->renderer(); 511 if (!renderer) 512 return VisiblePosition(); 513 514 RenderBlock *containingBlock = 0; 515 RootInlineBox *root = 0; 516 InlineBox* box; 517 int ignoredCaretOffset; 518 visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset); 519 if (box) { 520 root = box->root()->prevRootBox(); 521 // We want to skip zero height boxes. 522 // This could happen in case it is a TrailingFloatsRootInlineBox. 523 if (root && root->logicalHeight()) 524 containingBlock = renderer->containingBlock(); 525 else 526 root = 0; 527 } 528 529 if (!root) { 530 // This containing editable block does not have a previous line. 531 // Need to move back to previous containing editable block in this root editable 532 // block and find the last root line box in that block. 533 Node* startBlock = enclosingNodeWithNonInlineRenderer(node); 534 Node* n = previousLeafWithSameEditability(node); 535 while (n && startBlock == enclosingNodeWithNonInlineRenderer(n)) 536 n = previousLeafWithSameEditability(n); 537 while (n) { 538 if (highestEditableRoot(firstPositionInOrBeforeNode(n)) != highestRoot) 539 break; 540 Position pos(n, caretMinOffset(n)); 541 if (pos.isCandidate()) { 542 RenderObject* o = n->renderer(); 543 ASSERT(o); 544 if (canHaveCursor(o)) { 545 Position maxPos(n, caretMaxOffset(n)); 546 maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset); 547 if (box) { 548 // previous root line box found 549 root = box->root(); 550 containingBlock = n->renderer()->containingBlock(); 551 break; 552 } 553 554 return VisiblePosition(pos, DOWNSTREAM); 555 } 556 } 557 n = previousLeafWithSameEditability(n); 558 } 559 } 560 561 if (root) { 562 // FIXME: Can be wrong for multi-column layout and with transforms. 563 FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint()); 564 if (containingBlock->hasOverflowClip()) 565 absPos -= containingBlock->layer()->scrolledContentOffset(); 566 RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer(); 567 Node* node = renderer->node(); 568 if (node && editingIgnoresContent(node)) 569 return positionInParentBeforeNode(node); 570 return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop())); 571 } 572 573 // Could not find a previous line. This means we must already be on the first line. 574 // Move to the start of the content in this block, which effectively moves us 575 // to the start of the line we're on. 576 Element* rootElement = node->rendererIsEditable() ? node->rootEditableElement() : node->document()->documentElement(); 577 if (!rootElement) 578 return VisiblePosition(); 579 return VisiblePosition(firstPositionInNode(rootElement), DOWNSTREAM); 580 } 581 582 static Node* nextLeafWithSameEditability(Node* node, int offset) 583 { 584 bool editable = node->rendererIsEditable(); 585 ASSERT(offset >= 0); 586 Node* child = node->childNode(offset); 587 Node* n = child ? child->nextLeafNode() : node->lastDescendant()->nextLeafNode(); 588 while (n) { 589 if (editable == n->rendererIsEditable()) 590 return n; 591 n = n->nextLeafNode(); 592 } 593 return 0; 594 } 595 596 static Node* nextLeafWithSameEditability(Node* node) 597 { 598 if (!node) 599 return 0; 600 601 bool editable = node->rendererIsEditable(); 602 Node* n = node->nextLeafNode(); 603 while (n) { 604 if (editable == n->rendererIsEditable()) 605 return n; 606 n = n->nextLeafNode(); 607 } 608 return 0; 609 } 610 611 VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x) 612 { 613 Position p = visiblePosition.deepEquivalent(); 614 Node* node = p.deprecatedNode(); 615 Node* highestRoot = highestEditableRoot(p); 616 if (!node) 617 return VisiblePosition(); 618 619 node->document()->updateLayoutIgnorePendingStylesheets(); 620 621 RenderObject *renderer = node->renderer(); 622 if (!renderer) 623 return VisiblePosition(); 624 625 RenderBlock *containingBlock = 0; 626 RootInlineBox *root = 0; 627 InlineBox* box; 628 int ignoredCaretOffset; 629 visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset); 630 if (box) { 631 root = box->root()->nextRootBox(); 632 // We want to skip zero height boxes. 633 // This could happen in case it is a TrailingFloatsRootInlineBox. 634 if (root && root->logicalHeight()) 635 containingBlock = renderer->containingBlock(); 636 else 637 root = 0; 638 } 639 640 if (!root) { 641 // This containing editable block does not have a next line. 642 // Need to move forward to next containing editable block in this root editable 643 // block and find the first root line box in that block. 644 Node* startBlock = enclosingNodeWithNonInlineRenderer(node); 645 Node* n = nextLeafWithSameEditability(node, p.deprecatedEditingOffset()); 646 while (n && startBlock == enclosingNodeWithNonInlineRenderer(n)) 647 n = nextLeafWithSameEditability(n); 648 while (n) { 649 if (highestEditableRoot(firstPositionInOrBeforeNode(n)) != highestRoot) 650 break; 651 Position pos(n, caretMinOffset(n)); 652 if (pos.isCandidate()) { 653 ASSERT(n->renderer()); 654 pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset); 655 if (box) { 656 // next root line box found 657 root = box->root(); 658 containingBlock = n->renderer()->containingBlock(); 659 break; 660 } 661 662 return VisiblePosition(pos, DOWNSTREAM); 663 } 664 n = nextLeafWithSameEditability(n); 665 } 666 } 667 668 if (root) { 669 // FIXME: Can be wrong for multi-column layout and with transforms. 670 FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint()); 671 if (containingBlock->hasOverflowClip()) 672 absPos -= containingBlock->layer()->scrolledContentOffset(); 673 RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer(); 674 Node* node = renderer->node(); 675 if (node && editingIgnoresContent(node)) 676 return positionInParentBeforeNode(node); 677 return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop())); 678 } 679 680 // Could not find a next line. This means we must already be on the last line. 681 // Move to the end of the content in this block, which effectively moves us 682 // to the end of the line we're on. 683 Element* rootElement = node->rendererIsEditable() ? node->rootEditableElement() : node->document()->documentElement(); 684 if (!rootElement) 685 return VisiblePosition(); 686 return VisiblePosition(lastPositionInNode(rootElement), DOWNSTREAM); 687 } 688 689 // --------- 690 691 static unsigned startSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 692 { 693 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 694 // FIXME: The following function can return -1; we don't handle that. 695 return textBreakPreceding(iterator, length); 696 } 697 698 VisiblePosition startOfSentence(const VisiblePosition &c) 699 { 700 return previousBoundary(c, startSentenceBoundary); 701 } 702 703 static unsigned endSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 704 { 705 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 706 return textBreakNext(iterator); 707 } 708 709 // FIXME: This includes the space after the punctuation that marks the end of the sentence. 710 VisiblePosition endOfSentence(const VisiblePosition &c) 711 { 712 return nextBoundary(c, endSentenceBoundary); 713 } 714 715 static unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 716 { 717 // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right. 718 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 719 // FIXME: The following function can return -1; we don't handle that. 720 return textBreakPreceding(iterator, length); 721 } 722 723 VisiblePosition previousSentencePosition(const VisiblePosition &c) 724 { 725 VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary); 726 return c.honorEditableBoundaryAtOrBefore(prev); 727 } 728 729 static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 730 { 731 // FIXME: This is identical to endSentenceBoundary. This isn't right, it needs to 732 // move to the equivlant position in the following sentence. 733 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 734 return textBreakFollowing(iterator, 0); 735 } 736 737 VisiblePosition nextSentencePosition(const VisiblePosition &c) 738 { 739 VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary); 740 return c.honorEditableBoundaryAtOrAfter(next); 741 } 742 743 VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule) 744 { 745 Position p = c.deepEquivalent(); 746 Node* startNode = p.deprecatedNode(); 747 748 if (!startNode) 749 return VisiblePosition(); 750 751 if (isRenderedAsNonInlineTableImageOrHR(startNode)) 752 return positionBeforeNode(startNode); 753 754 Node* startBlock = enclosingBlock(startNode); 755 756 Node* node = startNode; 757 Node* highestRoot = highestEditableRoot(p); 758 int offset = p.deprecatedEditingOffset(); 759 Position::AnchorType type = p.anchorType(); 760 761 Node* n = startNode; 762 while (n) { 763 if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable()) 764 break; 765 if (boundaryCrossingRule == CanSkipOverEditingBoundary) { 766 while (n && n->rendererIsEditable() != startNode->rendererIsEditable()) 767 n = n->traversePreviousNodePostOrder(startBlock); 768 if (!n || !n->isDescendantOf(highestRoot)) 769 break; 770 } 771 RenderObject *r = n->renderer(); 772 if (!r) { 773 n = n->traversePreviousNodePostOrder(startBlock); 774 continue; 775 } 776 RenderStyle *style = r->style(); 777 if (style->visibility() != VISIBLE) { 778 n = n->traversePreviousNodePostOrder(startBlock); 779 continue; 780 } 781 782 if (r->isBR() || isBlock(n)) 783 break; 784 785 if (r->isText() && r->caretMaxRenderedOffset() > 0) { 786 type = Position::PositionIsOffsetInAnchor; 787 if (style->preserveNewline()) { 788 const UChar* chars = toRenderText(r)->characters(); 789 int i = toRenderText(r)->textLength(); 790 int o = offset; 791 if (n == startNode && o < i) 792 i = max(0, o); 793 while (--i >= 0) 794 if (chars[i] == '\n') 795 return VisiblePosition(Position(n, i + 1, Position::PositionIsOffsetInAnchor), DOWNSTREAM); 796 } 797 node = n; 798 offset = 0; 799 n = n->traversePreviousNodePostOrder(startBlock); 800 } else if (editingIgnoresContent(n) || isTableElement(n)) { 801 node = n; 802 type = Position::PositionIsBeforeAnchor; 803 n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock); 804 } else 805 n = n->traversePreviousNodePostOrder(startBlock); 806 } 807 808 if (type == Position::PositionIsOffsetInAnchor) 809 return VisiblePosition(Position(node, offset, type), DOWNSTREAM); 810 811 return VisiblePosition(Position(node, type), DOWNSTREAM); 812 } 813 814 VisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossingRule boundaryCrossingRule) 815 { 816 if (c.isNull()) 817 return VisiblePosition(); 818 819 Position p = c.deepEquivalent(); 820 Node* startNode = p.deprecatedNode(); 821 822 if (isRenderedAsNonInlineTableImageOrHR(startNode)) 823 return positionAfterNode(startNode); 824 825 Node* startBlock = enclosingBlock(startNode); 826 Node* stayInsideBlock = startBlock; 827 828 Node* node = startNode; 829 Node* highestRoot = highestEditableRoot(p); 830 int offset = p.deprecatedEditingOffset(); 831 Position::AnchorType type = p.anchorType(); 832 833 Node* n = startNode; 834 while (n) { 835 if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable()) 836 break; 837 if (boundaryCrossingRule == CanSkipOverEditingBoundary) { 838 while (n && n->rendererIsEditable() != startNode->rendererIsEditable()) 839 n = n->traverseNextNode(stayInsideBlock); 840 if (!n || !n->isDescendantOf(highestRoot)) 841 break; 842 } 843 844 RenderObject *r = n->renderer(); 845 if (!r) { 846 n = n->traverseNextNode(stayInsideBlock); 847 continue; 848 } 849 RenderStyle *style = r->style(); 850 if (style->visibility() != VISIBLE) { 851 n = n->traverseNextNode(stayInsideBlock); 852 continue; 853 } 854 855 if (r->isBR() || isBlock(n)) 856 break; 857 858 // FIXME: We avoid returning a position where the renderer can't accept the caret. 859 if (r->isText() && r->caretMaxRenderedOffset() > 0) { 860 int length = toRenderText(r)->textLength(); 861 type = Position::PositionIsOffsetInAnchor; 862 if (style->preserveNewline()) { 863 const UChar* chars = toRenderText(r)->characters(); 864 int o = n == startNode ? offset : 0; 865 for (int i = o; i < length; ++i) 866 if (chars[i] == '\n') 867 return VisiblePosition(Position(n, i, Position::PositionIsOffsetInAnchor), DOWNSTREAM); 868 } 869 node = n; 870 offset = r->caretMaxOffset(); 871 n = n->traverseNextNode(stayInsideBlock); 872 } else if (editingIgnoresContent(n) || isTableElement(n)) { 873 node = n; 874 type = Position::PositionIsAfterAnchor; 875 n = n->traverseNextSibling(stayInsideBlock); 876 } else 877 n = n->traverseNextNode(stayInsideBlock); 878 } 879 880 if (type == Position::PositionIsOffsetInAnchor) 881 return VisiblePosition(Position(node, offset, type), DOWNSTREAM); 882 883 return VisiblePosition(Position(node, type), DOWNSTREAM); 884 } 885 886 // FIXME: isStartOfParagraph(startOfNextParagraph(pos)) is not always true 887 VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition) 888 { 889 VisiblePosition paragraphEnd(endOfParagraph(visiblePosition, CanSkipOverEditingBoundary)); 890 VisiblePosition afterParagraphEnd(paragraphEnd.next(CannotCrossEditingBoundary)); 891 // The position after the last position in the last cell of a table 892 // is not the start of the next paragraph. 893 if (isFirstPositionAfterTable(afterParagraphEnd)) 894 return afterParagraphEnd.next(CannotCrossEditingBoundary); 895 return afterParagraphEnd; 896 } 897 898 bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b, EditingBoundaryCrossingRule boundaryCrossingRule) 899 { 900 return a.isNotNull() && startOfParagraph(a, boundaryCrossingRule) == startOfParagraph(b, boundaryCrossingRule); 901 } 902 903 bool isStartOfParagraph(const VisiblePosition &pos, EditingBoundaryCrossingRule boundaryCrossingRule) 904 { 905 return pos.isNotNull() && pos == startOfParagraph(pos, boundaryCrossingRule); 906 } 907 908 bool isEndOfParagraph(const VisiblePosition &pos, EditingBoundaryCrossingRule boundaryCrossingRule) 909 { 910 return pos.isNotNull() && pos == endOfParagraph(pos, boundaryCrossingRule); 911 } 912 913 VisiblePosition previousParagraphPosition(const VisiblePosition& p, int x) 914 { 915 VisiblePosition pos = p; 916 do { 917 VisiblePosition n = previousLinePosition(pos, x); 918 if (n.isNull() || n == pos) 919 break; 920 pos = n; 921 } while (inSameParagraph(p, pos)); 922 return pos; 923 } 924 925 VisiblePosition nextParagraphPosition(const VisiblePosition& p, int x) 926 { 927 VisiblePosition pos = p; 928 do { 929 VisiblePosition n = nextLinePosition(pos, x); 930 if (n.isNull() || n == pos) 931 break; 932 pos = n; 933 } while (inSameParagraph(p, pos)); 934 return pos; 935 } 936 937 // --------- 938 939 VisiblePosition startOfBlock(const VisiblePosition& visiblePosition, EditingBoundaryCrossingRule rule) 940 { 941 Position position = visiblePosition.deepEquivalent(); 942 Node* startBlock; 943 if (!position.containerNode() || !(startBlock = enclosingBlock(position.containerNode(), rule))) 944 return VisiblePosition(); 945 return firstPositionInNode(startBlock); 946 } 947 948 VisiblePosition endOfBlock(const VisiblePosition& visiblePosition, EditingBoundaryCrossingRule rule) 949 { 950 Position position = visiblePosition.deepEquivalent(); 951 Node* endBlock; 952 if (!position.containerNode() || !(endBlock = enclosingBlock(position.containerNode(), rule))) 953 return VisiblePosition(); 954 return lastPositionInNode(endBlock); 955 } 956 957 bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b) 958 { 959 return !a.isNull() && enclosingBlock(a.deepEquivalent().containerNode()) == enclosingBlock(b.deepEquivalent().containerNode()); 960 } 961 962 bool isStartOfBlock(const VisiblePosition &pos) 963 { 964 return pos.isNotNull() && pos == startOfBlock(pos, CanCrossEditingBoundary); 965 } 966 967 bool isEndOfBlock(const VisiblePosition &pos) 968 { 969 return pos.isNotNull() && pos == endOfBlock(pos, CanCrossEditingBoundary); 970 } 971 972 // --------- 973 974 VisiblePosition startOfDocument(const Node* node) 975 { 976 if (!node) 977 return VisiblePosition(); 978 979 return VisiblePosition(firstPositionInNode(node->document()->documentElement()), DOWNSTREAM); 980 } 981 982 VisiblePosition startOfDocument(const VisiblePosition &c) 983 { 984 return startOfDocument(c.deepEquivalent().deprecatedNode()); 985 } 986 987 VisiblePosition endOfDocument(const Node* node) 988 { 989 if (!node || !node->document() || !node->document()->documentElement()) 990 return VisiblePosition(); 991 992 Element* doc = node->document()->documentElement(); 993 return VisiblePosition(lastPositionInNode(doc), DOWNSTREAM); 994 } 995 996 VisiblePosition endOfDocument(const VisiblePosition &c) 997 { 998 return endOfDocument(c.deepEquivalent().deprecatedNode()); 999 } 1000 1001 bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b) 1002 { 1003 Position ap = a.deepEquivalent(); 1004 Node* an = ap.deprecatedNode(); 1005 if (!an) 1006 return false; 1007 Position bp = b.deepEquivalent(); 1008 Node* bn = bp.deprecatedNode(); 1009 if (an == bn) 1010 return true; 1011 1012 return an->document() == bn->document(); 1013 } 1014 1015 bool isStartOfDocument(const VisiblePosition &p) 1016 { 1017 return p.isNotNull() && p.previous().isNull(); 1018 } 1019 1020 bool isEndOfDocument(const VisiblePosition &p) 1021 { 1022 return p.isNotNull() && p.next().isNull(); 1023 } 1024 1025 // --------- 1026 1027 VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition) 1028 { 1029 Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent()); 1030 if (!highestRoot) 1031 return VisiblePosition(); 1032 1033 return firstPositionInNode(highestRoot); 1034 } 1035 1036 VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition) 1037 { 1038 Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent()); 1039 if (!highestRoot) 1040 return VisiblePosition(); 1041 1042 return lastPositionInNode(highestRoot); 1043 } 1044 1045 static VisiblePosition logicalStartPositionForLine(const VisiblePosition& c) 1046 { 1047 if (c.isNull()) 1048 return VisiblePosition(); 1049 1050 RootInlineBox* rootBox = rootBoxForLine(c); 1051 if (!rootBox) { 1052 // There are VisiblePositions at offset 0 in blocks without 1053 // RootInlineBoxes, like empty editable blocks and bordered blocks. 1054 Position p = c.deepEquivalent(); 1055 if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 1056 return positionAvoidingFirstPositionInTable(c); 1057 1058 return VisiblePosition(); 1059 } 1060 1061 InlineBox* logicalStartBox; 1062 Node* logicalStartNode = rootBox->getLogicalStartBoxWithNode(logicalStartBox); 1063 1064 if (!logicalStartNode) 1065 return VisiblePosition(); 1066 1067 VisiblePosition visPos = logicalStartNode->isTextNode() ? VisiblePosition(Position(logicalStartNode, logicalStartBox->caretMinOffset(), Position::PositionIsOffsetInAnchor), DOWNSTREAM) 1068 : VisiblePosition(positionBeforeNode(logicalStartNode), DOWNSTREAM); 1069 return positionAvoidingFirstPositionInTable(visPos); 1070 } 1071 1072 VisiblePosition logicalStartOfLine(const VisiblePosition& c) 1073 { 1074 // TODO: this is the current behavior that might need to be fixed. 1075 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail. 1076 VisiblePosition visPos = logicalStartPositionForLine(c); 1077 1078 return c.honorEditableBoundaryAtOrBefore(visPos); 1079 } 1080 1081 static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c) 1082 { 1083 if (c.isNull()) 1084 return VisiblePosition(); 1085 1086 RootInlineBox* rootBox = rootBoxForLine(c); 1087 if (!rootBox) { 1088 // There are VisiblePositions at offset 0 in blocks without 1089 // RootInlineBoxes, like empty editable blocks and bordered blocks. 1090 Position p = c.deepEquivalent(); 1091 if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 1092 return c; 1093 return VisiblePosition(); 1094 } 1095 1096 InlineBox* logicalEndBox; 1097 Node* logicalEndNode = rootBox->getLogicalEndBoxWithNode(logicalEndBox); 1098 1099 if (!logicalEndNode) 1100 return VisiblePosition(); 1101 1102 Position pos; 1103 if (logicalEndNode->hasTagName(brTag)) 1104 pos = positionBeforeNode(logicalEndNode); 1105 else if (logicalEndBox->isInlineTextBox()) { 1106 InlineTextBox* endTextBox = static_cast<InlineTextBox*>(logicalEndBox); 1107 int endOffset = endTextBox->start(); 1108 if (!endTextBox->isLineBreak()) 1109 endOffset += endTextBox->len(); 1110 pos = Position(logicalEndNode, endOffset, Position::PositionIsOffsetInAnchor); 1111 } else 1112 pos = positionAfterNode(logicalEndNode); 1113 1114 return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE); 1115 } 1116 1117 bool inSameLogicalLine(const VisiblePosition& a, const VisiblePosition& b) 1118 { 1119 return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b); 1120 } 1121 1122 VisiblePosition logicalEndOfLine(const VisiblePosition& c) 1123 { 1124 // TODO: this is the current behavior that might need to be fixed. 1125 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail. 1126 1127 VisiblePosition visPos = logicalEndPositionForLine(c); 1128 1129 // Make sure the end of line is at the same line as the given input position. For a wrapping line, the logical end 1130 // position for the not-last-2-lines might incorrectly hand back the logical beginning of the next line. 1131 // For example, <div contenteditable dir="rtl" style="line-break:before-white-space">abcdefg abcdefg abcdefg 1132 // a abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg </div> 1133 // In this case, use the previous position of the computed logical end position. 1134 if (!inSameLogicalLine(c, visPos)) 1135 visPos = visPos.previous(); 1136 1137 return c.honorEditableBoundaryAtOrAfter(visPos); 1138 } 1139 1140 VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction) 1141 { 1142 return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c); 1143 } 1144 1145 VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction) 1146 { 1147 return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c); 1148 } 1149 1150 static const int invalidOffset = -1; 1151 1152 static VisiblePosition previousWordBreakInBoxInsideBlockWithSameDirectionality(const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak) 1153 { 1154 bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull(); 1155 // In a LTR block, the word break should be on the left boundary of a word. 1156 // In a RTL block, the word break should be on the right boundary of a word. 1157 // Because nextWordPosition() returns the word break on the right boundary of the word for LTR text, 1158 // we need to use previousWordPosition() to traverse words within the inline boxes from right to left 1159 // to find the previous word break (i.e. the first word break on the left). The same applies to RTL text. 1160 1161 VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 1162 1163 // FIXME: handle multi-spaces (http://webkit.org/b/57543). 1164 1165 wordBreak = previousWordPosition(wordBreak); 1166 if (previousWordBreak == wordBreak) 1167 return VisiblePosition(); 1168 1169 InlineBox* boxContainingPreviousWordBreak; 1170 wordBreak.getInlineBoxAndOffset(boxContainingPreviousWordBreak, offsetOfWordBreak); 1171 if (boxContainingPreviousWordBreak != box) 1172 return VisiblePosition(); 1173 return wordBreak; 1174 } 1175 1176 static VisiblePosition leftmostPositionInRTLBoxInLTRBlock(const InlineBox* box) 1177 { 1178 // FIXME: Probably need to take care of bidi level too. 1179 Node* node = box->renderer()->node(); 1180 InlineBox* previousLeaf = box->prevLeafChild(); 1181 InlineBox* nextLeaf = box->nextLeafChild(); 1182 1183 if (previousLeaf && !previousLeaf->isLeftToRightDirection()) 1184 return Position(node, box->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 1185 1186 if (nextLeaf && !nextLeaf->isLeftToRightDirection()) { 1187 if (previousLeaf) 1188 return Position(previousLeaf->renderer()->node(), previousLeaf->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 1189 1190 InlineBox* lastRTLLeaf; 1191 do { 1192 lastRTLLeaf = nextLeaf; 1193 nextLeaf = nextLeaf->nextLeafChild(); 1194 } while (nextLeaf && !nextLeaf->isLeftToRightDirection()); 1195 return Position(lastRTLLeaf->renderer()->node(), lastRTLLeaf->caretMinOffset(), Position::PositionIsOffsetInAnchor); 1196 } 1197 1198 return Position(node, box->caretMinOffset(), Position::PositionIsOffsetInAnchor); 1199 } 1200 1201 static VisiblePosition rightmostPositionInLTRBoxInRTLBlock(const InlineBox* box) 1202 { 1203 // FIXME: Probably need to take care of bidi level too. 1204 Node* node = box->renderer()->node(); 1205 InlineBox* previousLeaf = box->prevLeafChild(); 1206 InlineBox* nextLeaf = box->nextLeafChild(); 1207 1208 if (nextLeaf && nextLeaf->isLeftToRightDirection()) 1209 return Position(node, box->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 1210 1211 if (previousLeaf && previousLeaf->isLeftToRightDirection()) { 1212 if (nextLeaf) 1213 return Position(nextLeaf->renderer()->node(), nextLeaf->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 1214 1215 InlineBox* firstLTRLeaf; 1216 do { 1217 firstLTRLeaf = previousLeaf; 1218 previousLeaf = previousLeaf->prevLeafChild(); 1219 } while (previousLeaf && previousLeaf->isLeftToRightDirection()); 1220 return Position(firstLTRLeaf->renderer()->node(), firstLTRLeaf->caretMinOffset(), Position::PositionIsOffsetInAnchor); 1221 } 1222 1223 return Position(node, box->caretMinOffset(), Position::PositionIsOffsetInAnchor); 1224 } 1225 1226 static VisiblePosition lastWordBreakInBox(const InlineBox* box, int& offsetOfWordBreak) 1227 { 1228 // Add the leftmost word break for RTL box or rightmost word break for LTR box. 1229 InlineBox* previousLeaf = box->prevLeafChild(); 1230 InlineBox* nextLeaf = box->nextLeafChild(); 1231 VisiblePosition boundaryPosition; 1232 if (box->direction() == RTL && (!previousLeaf || previousLeaf->isLeftToRightDirection())) 1233 boundaryPosition = leftmostPositionInRTLBoxInLTRBlock(box); 1234 else if (box->direction() == LTR && (!nextLeaf || !nextLeaf->isLeftToRightDirection())) 1235 boundaryPosition = rightmostPositionInLTRBoxInRTLBlock(box); 1236 1237 if (boundaryPosition.isNull()) 1238 return VisiblePosition(); 1239 1240 VisiblePosition wordBreak = nextWordPosition(boundaryPosition); 1241 if (wordBreak != boundaryPosition) 1242 wordBreak = previousWordPosition(wordBreak); 1243 1244 InlineBox* boxOfWordBreak; 1245 wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak); 1246 if (boxOfWordBreak == box) 1247 return wordBreak; 1248 return VisiblePosition(); 1249 } 1250 1251 static bool positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(const VisiblePosition& wordBreak, const InlineBox* box, int& offsetOfWordBreak) 1252 { 1253 int previousOffset = offsetOfWordBreak; 1254 InlineBox* boxOfWordBreak; 1255 wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak); 1256 if (boxOfWordBreak == box && (previousOffset == invalidOffset || previousOffset < offsetOfWordBreak)) 1257 return true; 1258 return false; 1259 } 1260 1261 static VisiblePosition nextWordBreakInBoxInsideBlockWithDifferentDirectionality( 1262 const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak, bool& isLastWordBreakInBox) 1263 { 1264 // FIXME: Probably need to take care of bidi level too. 1265 1266 // In a LTR block, the word break should be on the left boundary of a word. 1267 // In a RTL block, the word break should be on the right boundary of a word. 1268 // Because previousWordPosition() returns the word break on the right boundary of the word for RTL text, 1269 // we need to use nextWordPosition() to traverse words within the inline boxes from right to left to find the next word break. 1270 // The same applies to LTR text, in which words are traversed within the inline boxes from left to right. 1271 1272 // FIXME: handle multi-spaces (http://webkit.org/b/57543). 1273 1274 bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull(); 1275 VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMinOffset(), Position::PositionIsOffsetInAnchor); 1276 wordBreak = nextWordPosition(wordBreak); 1277 1278 if (wordBreak == previousWordBreak) { 1279 isLastWordBreakInBox = true; 1280 return VisiblePosition(); 1281 } 1282 1283 1284 // Given RTL box "ABC DEF" either follows a LTR box or is the first visual box in an LTR block as an example, 1285 // the visual display of the RTL box is: "(0)J(10)I(9)H(8) (7)F(6)E(5)D(4) (3)C(2)B(1)A(11)", 1286 // where the number in parenthesis represents offset in visiblePosition. 1287 // Start at offset 0, the first word break is at offset 3, the 2nd word break is at offset 7, and the 3rd word break should be at offset 0. 1288 // But nextWordPosition() of offset 7 is offset 11, which should be ignored, 1289 // and the position at offset 0 should be manually added as the last word break within the box. 1290 if (positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(wordBreak, box, offsetOfWordBreak)) { 1291 isLastWordBreakInBox = false; 1292 return wordBreak; 1293 } 1294 1295 isLastWordBreakInBox = true; 1296 return lastWordBreakInBox(box, offsetOfWordBreak); 1297 } 1298 1299 struct WordBoundaryEntry { 1300 WordBoundaryEntry() 1301 : offsetInInlineBox(invalidOffset) 1302 { 1303 } 1304 1305 WordBoundaryEntry(const VisiblePosition& position, int offset) 1306 : visiblePosition(position) 1307 , offsetInInlineBox(offset) 1308 { 1309 } 1310 1311 VisiblePosition visiblePosition; 1312 int offsetInInlineBox; 1313 }; 1314 1315 typedef Vector<WordBoundaryEntry, 50> WordBoundaryVector; 1316 1317 static void collectWordBreaksInBoxInsideBlockWithSameDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries) 1318 { 1319 orderedWordBoundaries.clear(); 1320 1321 VisiblePosition wordBreak; 1322 int offsetOfWordBreak = invalidOffset; 1323 while (1) { 1324 wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak); 1325 if (wordBreak.isNull()) 1326 break; 1327 WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak); 1328 orderedWordBoundaries.append(wordBoundaryEntry); 1329 } 1330 } 1331 1332 static void collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries) 1333 { 1334 orderedWordBoundaries.clear(); 1335 1336 VisiblePosition wordBreak; 1337 int offsetOfWordBreak = invalidOffset; 1338 while (1) { 1339 bool isLastWordBreakInBox = false; 1340 wordBreak = nextWordBreakInBoxInsideBlockWithDifferentDirectionality(box, wordBreak, offsetOfWordBreak, isLastWordBreakInBox); 1341 if (wordBreak.isNotNull()) { 1342 WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak); 1343 orderedWordBoundaries.append(wordBoundaryEntry); 1344 } 1345 if (isLastWordBreakInBox) 1346 break; 1347 } 1348 } 1349 1350 static VisiblePosition previousWordBreakInBox(const InlineBox* box, int offset, TextDirection blockDirection) 1351 { 1352 int offsetOfWordBreak = 0; 1353 VisiblePosition wordBreak; 1354 while (true) { 1355 if (box->direction() == blockDirection) 1356 wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak); 1357 // FIXME: Implement the 'else' case when the box direction is not equal to the block direction. 1358 if (wordBreak.isNull()) 1359 break; 1360 if (offset == invalidOffset || offsetOfWordBreak != offset) 1361 return wordBreak; 1362 } 1363 return VisiblePosition(); 1364 } 1365 1366 static int greatestValueUnder(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries) 1367 { 1368 if (!orderedWordBoundaries.size()) 1369 return invalidOffset; 1370 // FIXME: binary search. 1371 if (boxAndBlockAreInSameDirection) { 1372 for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) { 1373 if (orderedWordBoundaries[i].offsetInInlineBox < offset) 1374 return i; 1375 } 1376 return invalidOffset; 1377 } 1378 for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) { 1379 if (orderedWordBoundaries[i].offsetInInlineBox < offset) 1380 return i; 1381 } 1382 return invalidOffset; 1383 } 1384 1385 static int smallestOffsetAbove(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries) 1386 { 1387 if (!orderedWordBoundaries.size()) 1388 return invalidOffset; 1389 // FIXME: binary search. 1390 if (boxAndBlockAreInSameDirection) { 1391 for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) { 1392 if (orderedWordBoundaries[i].offsetInInlineBox > offset) 1393 return i; 1394 } 1395 return invalidOffset; 1396 } 1397 for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) { 1398 if (orderedWordBoundaries[i].offsetInInlineBox > offset) 1399 return i; 1400 } 1401 return invalidOffset; 1402 } 1403 1404 static VisiblePosition leftWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection) 1405 { 1406 VisiblePosition wordBreak; 1407 for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->prevLeafChild()) { 1408 if (blockDirection == LTR) 1409 wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 1410 // FIXME: Implement the "else" case. 1411 if (wordBreak.isNotNull()) 1412 return wordBreak; 1413 } 1414 return VisiblePosition(); 1415 } 1416 1417 static VisiblePosition rightWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection) 1418 { 1419 1420 VisiblePosition wordBreak; 1421 for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->nextLeafChild()) { 1422 if (blockDirection == RTL) 1423 wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 1424 // FIXME: Implement the "else" case. 1425 if (!wordBreak.isNull()) 1426 return wordBreak; 1427 } 1428 return VisiblePosition(); 1429 } 1430 1431 static bool positionIsInsideBox(const VisiblePosition& wordBreak, const InlineBox* box) 1432 { 1433 InlineBox* boxOfWordBreak; 1434 int offsetOfWordBreak; 1435 wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak); 1436 return box == boxOfWordBreak && offsetOfWordBreak != box->caretMaxOffset() && offsetOfWordBreak != box->caretMinOffset(); 1437 } 1438 1439 static VisiblePosition positionBeforeNextWord(const VisiblePosition& position) 1440 { 1441 VisiblePosition positionAfterCurrentWord = nextWordPosition(position); 1442 VisiblePosition positionAfterNextWord = nextWordPosition(positionAfterCurrentWord); 1443 if (positionAfterCurrentWord == positionAfterNextWord) 1444 return positionAfterCurrentWord; 1445 return previousWordPosition(positionAfterNextWord); 1446 } 1447 1448 static VisiblePosition positionAfterPreviousWord(const VisiblePosition& position) 1449 { 1450 VisiblePosition positionBeforeCurrentWord = previousWordPosition(position); 1451 VisiblePosition positionBeforePreviousWord = previousWordPosition(positionBeforeCurrentWord); 1452 if (positionBeforeCurrentWord == positionBeforePreviousWord) 1453 return positionBeforeCurrentWord; 1454 return nextWordPosition(positionBeforePreviousWord); 1455 } 1456 1457 VisiblePosition leftWordPosition(const VisiblePosition& visiblePosition) 1458 { 1459 InlineBox* box; 1460 int offset; 1461 visiblePosition.getInlineBoxAndOffset(box, offset); 1462 TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent()); 1463 1464 // FIXME: If the box's directionality is the same as that of the enclosing block, when the offset is at the box boundary 1465 // and the direction is towards inside the box, do I still need to make it a special case? For example, a LTR box inside a LTR block, 1466 // when offset is at box's caretMinOffset and the direction is DirectionRight, should it be taken care as a general case? 1467 if (offset == box->caretLeftmostOffset()) 1468 return leftWordBoundary(box->prevLeafChild(), invalidOffset, blockDirection); 1469 if (offset == box->caretRightmostOffset()) 1470 return leftWordBoundary(box, offset, blockDirection); 1471 1472 1473 VisiblePosition wordBreak; 1474 if (box->direction() == blockDirection) { 1475 if (blockDirection == RTL) 1476 wordBreak = positionBeforeNextWord(visiblePosition); 1477 else 1478 wordBreak = previousWordPosition(visiblePosition); 1479 } else { 1480 if (blockDirection == RTL) 1481 wordBreak = positionAfterPreviousWord(visiblePosition); 1482 else 1483 wordBreak = nextWordPosition(visiblePosition); 1484 } 1485 if (positionIsInsideBox(wordBreak, box)) 1486 return wordBreak; 1487 1488 WordBoundaryVector orderedWordBoundaries; 1489 if (box->direction() == blockDirection) 1490 collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries); 1491 else 1492 collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries); 1493 1494 int index = box->isLeftToRightDirection() ? greatestValueUnder(offset, blockDirection == LTR, orderedWordBoundaries) : 1495 smallestOffsetAbove(offset, blockDirection == RTL, orderedWordBoundaries); 1496 if (index != invalidOffset) 1497 return orderedWordBoundaries[index].visiblePosition; 1498 1499 return leftWordBoundary(box->prevLeafChild(), invalidOffset, blockDirection); 1500 } 1501 1502 VisiblePosition rightWordPosition(const VisiblePosition& visiblePosition) 1503 { 1504 InlineBox* box; 1505 int offset; 1506 visiblePosition.getInlineBoxAndOffset(box, offset); 1507 TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent()); 1508 1509 if (offset == box->caretLeftmostOffset()) 1510 return rightWordBoundary(box, offset, blockDirection); 1511 if (offset == box->caretRightmostOffset()) 1512 return rightWordBoundary(box->nextLeafChild(), invalidOffset, blockDirection); 1513 1514 VisiblePosition wordBreak; 1515 if (box->direction() == blockDirection) { 1516 if (blockDirection == LTR) 1517 wordBreak = positionBeforeNextWord(visiblePosition); 1518 else 1519 wordBreak = previousWordPosition(visiblePosition); 1520 } else { 1521 if (blockDirection == LTR) 1522 wordBreak = positionAfterPreviousWord(visiblePosition); 1523 else 1524 wordBreak = nextWordPosition(visiblePosition); 1525 } 1526 if (positionIsInsideBox(wordBreak, box)) 1527 return wordBreak; 1528 1529 WordBoundaryVector orderedWordBoundaries; 1530 if (box->direction() == blockDirection) 1531 collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries); 1532 else 1533 collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries); 1534 int index = box->isLeftToRightDirection() ? smallestOffsetAbove(offset, blockDirection == LTR, orderedWordBoundaries) : 1535 greatestValueUnder(offset, blockDirection == RTL, orderedWordBoundaries); 1536 if (index != invalidOffset) 1537 return orderedWordBoundaries[index].visiblePosition; 1538 1539 return rightWordBoundary(box->nextLeafChild(), invalidOffset, blockDirection); 1540 } 1541 1542 } 1543