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