1 /* 2 * Copyright (C) 2004, 2005, 2006 Apple Computer, 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/VisibleSelection.h" 28 29 #include "bindings/core/v8/ExceptionState.h" 30 #include "core/dom/Document.h" 31 #include "core/dom/Element.h" 32 #include "core/dom/Range.h" 33 #include "core/editing/TextIterator.h" 34 #include "core/editing/VisibleUnits.h" 35 #include "core/editing/htmlediting.h" 36 #include "core/rendering/RenderObject.h" 37 #include "platform/geometry/LayoutPoint.h" 38 #include "wtf/Assertions.h" 39 #include "wtf/text/CString.h" 40 #include "wtf/text/StringBuilder.h" 41 #include "wtf/unicode/CharacterNames.h" 42 43 #ifndef NDEBUG 44 #include <stdio.h> 45 #endif 46 47 namespace blink { 48 49 VisibleSelection::VisibleSelection() 50 : m_affinity(DOWNSTREAM) 51 , m_changeObserver(nullptr) 52 , m_selectionType(NoSelection) 53 , m_baseIsFirst(true) 54 , m_isDirectional(false) 55 { 56 } 57 58 VisibleSelection::VisibleSelection(const Position& pos, EAffinity affinity, bool isDirectional) 59 : m_base(pos) 60 , m_extent(pos) 61 , m_affinity(affinity) 62 , m_changeObserver(nullptr) 63 , m_isDirectional(isDirectional) 64 { 65 validate(); 66 } 67 68 VisibleSelection::VisibleSelection(const Position& base, const Position& extent, EAffinity affinity, bool isDirectional) 69 : m_base(base) 70 , m_extent(extent) 71 , m_affinity(affinity) 72 , m_changeObserver(nullptr) 73 , m_isDirectional(isDirectional) 74 { 75 validate(); 76 } 77 78 VisibleSelection::VisibleSelection(const VisiblePosition& pos, bool isDirectional) 79 : m_base(pos.deepEquivalent()) 80 , m_extent(pos.deepEquivalent()) 81 , m_affinity(pos.affinity()) 82 , m_changeObserver(nullptr) 83 , m_isDirectional(isDirectional) 84 { 85 validate(); 86 } 87 88 VisibleSelection::VisibleSelection(const VisiblePosition& base, const VisiblePosition& extent, bool isDirectional) 89 : m_base(base.deepEquivalent()) 90 , m_extent(extent.deepEquivalent()) 91 , m_affinity(base.affinity()) 92 , m_changeObserver(nullptr) 93 , m_isDirectional(isDirectional) 94 { 95 validate(); 96 } 97 98 VisibleSelection::VisibleSelection(const Range* range, EAffinity affinity, bool isDirectional) 99 : m_base(range->startPosition()) 100 , m_extent(range->endPosition()) 101 , m_affinity(affinity) 102 , m_changeObserver(nullptr) 103 , m_isDirectional(isDirectional) 104 { 105 validate(); 106 } 107 108 VisibleSelection::VisibleSelection(const VisibleSelection& other) 109 : m_base(other.m_base) 110 , m_extent(other.m_extent) 111 , m_start(other.m_start) 112 , m_end(other.m_end) 113 , m_affinity(other.m_affinity) 114 , m_changeObserver(nullptr) // Observer is associated with only one VisibleSelection, so this should not be copied. 115 , m_selectionType(other.m_selectionType) 116 , m_baseIsFirst(other.m_baseIsFirst) 117 , m_isDirectional(other.m_isDirectional) 118 { 119 } 120 121 VisibleSelection& VisibleSelection::operator=(const VisibleSelection& other) 122 { 123 didChange(); 124 125 m_base = other.m_base; 126 m_extent = other.m_extent; 127 m_start = other.m_start; 128 m_end = other.m_end; 129 m_affinity = other.m_affinity; 130 m_changeObserver = nullptr; 131 m_selectionType = other.m_selectionType; 132 m_baseIsFirst = other.m_baseIsFirst; 133 m_isDirectional = other.m_isDirectional; 134 return *this; 135 } 136 137 VisibleSelection::~VisibleSelection() 138 { 139 #if !ENABLE(OILPAN) 140 didChange(); 141 #endif 142 } 143 144 VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node) 145 { 146 ASSERT(!editingIgnoresContent(node)); 147 return VisibleSelection(firstPositionInNode(node), lastPositionInNode(node), DOWNSTREAM); 148 } 149 150 void VisibleSelection::setBase(const Position& position) 151 { 152 Position oldBase = m_base; 153 m_base = position; 154 validate(); 155 if (m_base != oldBase) 156 didChange(); 157 } 158 159 void VisibleSelection::setBase(const VisiblePosition& visiblePosition) 160 { 161 Position oldBase = m_base; 162 m_base = visiblePosition.deepEquivalent(); 163 validate(); 164 if (m_base != oldBase) 165 didChange(); 166 } 167 168 void VisibleSelection::setExtent(const Position& position) 169 { 170 Position oldExtent = m_extent; 171 m_extent = position; 172 validate(); 173 if (m_extent != oldExtent) 174 didChange(); 175 } 176 177 void VisibleSelection::setExtent(const VisiblePosition& visiblePosition) 178 { 179 Position oldExtent = m_extent; 180 m_extent = visiblePosition.deepEquivalent(); 181 validate(); 182 if (m_extent != oldExtent) 183 didChange(); 184 } 185 186 PassRefPtrWillBeRawPtr<Range> VisibleSelection::firstRange() const 187 { 188 if (isNone()) 189 return nullptr; 190 Position start = m_start.parentAnchoredEquivalent(); 191 Position end = m_end.parentAnchoredEquivalent(); 192 return Range::create(*start.document(), start, end); 193 } 194 195 bool VisibleSelection::intersectsNode(Node* node) const 196 { 197 if (isNone()) 198 return false; 199 Position start = m_start.parentAnchoredEquivalent(); 200 Position end = m_end.parentAnchoredEquivalent(); 201 TrackExceptionState exceptionState; 202 return Range::intersectsNode(node, start, end, exceptionState) && !exceptionState.hadException(); 203 } 204 205 PassRefPtrWillBeRawPtr<Range> VisibleSelection::toNormalizedRange() const 206 { 207 Position start, end; 208 if (toNormalizedPositions(start, end)) 209 return Range::create(*start.document(), start, end); 210 return nullptr; 211 } 212 213 bool VisibleSelection::toNormalizedPositions(Position& start, Position& end) const 214 { 215 if (isNone()) 216 return false; 217 218 // Make sure we have an updated layout since this function is called 219 // in the course of running edit commands which modify the DOM. 220 // Failing to call this can result in equivalentXXXPosition calls returning 221 // incorrect results. 222 m_start.document()->updateLayout(); 223 224 // Check again, because updating layout can clear the selection. 225 if (isNone()) 226 return false; 227 228 if (isCaret()) { 229 // If the selection is a caret, move the range start upstream. This helps us match 230 // the conventions of text editors tested, which make style determinations based 231 // on the character before the caret, if any. 232 start = m_start.upstream().parentAnchoredEquivalent(); 233 end = start; 234 } else { 235 // If the selection is a range, select the minimum range that encompasses the selection. 236 // Again, this is to match the conventions of text editors tested, which make style 237 // determinations based on the first character of the selection. 238 // For instance, this operation helps to make sure that the "X" selected below is the 239 // only thing selected. The range should not be allowed to "leak" out to the end of the 240 // previous text node, or to the beginning of the next text node, each of which has a 241 // different style. 242 // 243 // On a treasure map, <b>X</b> marks the spot. 244 // ^ selected 245 // 246 ASSERT(isRange()); 247 start = m_start.downstream(); 248 end = m_end.upstream(); 249 if (comparePositions(start, end) > 0) { 250 // Make sure the start is before the end. 251 // The end can wind up before the start if collapsed whitespace is the only thing selected. 252 Position tmp = start; 253 start = end; 254 end = tmp; 255 } 256 start = start.parentAnchoredEquivalent(); 257 end = end.parentAnchoredEquivalent(); 258 } 259 260 if (!start.containerNode() || !end.containerNode()) 261 return false; 262 263 return true; 264 } 265 266 bool VisibleSelection::expandUsingGranularity(TextGranularity granularity) 267 { 268 if (isNone()) 269 return false; 270 271 // FIXME: Do we need to check all of them? 272 Position oldBase = m_base; 273 Position oldExtent = m_extent; 274 Position oldStart = m_start; 275 Position oldEnd = m_end; 276 validate(granularity); 277 if (m_base != oldBase || m_extent != oldExtent || m_start != oldStart || m_end != oldEnd) 278 didChange(); 279 return true; 280 } 281 282 static PassRefPtrWillBeRawPtr<Range> makeSearchRange(const Position& pos) 283 { 284 Node* node = pos.deprecatedNode(); 285 if (!node) 286 return nullptr; 287 Document& document = node->document(); 288 if (!document.documentElement()) 289 return nullptr; 290 Element* boundary = enclosingBlockFlowElement(*node); 291 if (!boundary) 292 return nullptr; 293 294 RefPtrWillBeRawPtr<Range> searchRange(Range::create(document)); 295 TrackExceptionState exceptionState; 296 297 Position start(pos.parentAnchoredEquivalent()); 298 searchRange->selectNodeContents(boundary, exceptionState); 299 searchRange->setStart(start.containerNode(), start.offsetInContainerNode(), exceptionState); 300 301 ASSERT(!exceptionState.hadException()); 302 if (exceptionState.hadException()) 303 return nullptr; 304 305 return searchRange.release(); 306 } 307 308 void VisibleSelection::appendTrailingWhitespace() 309 { 310 RefPtrWillBeRawPtr<Range> searchRange = makeSearchRange(m_end); 311 if (!searchRange) 312 return; 313 314 CharacterIterator charIt(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions); 315 bool changed = false; 316 317 for (; charIt.length(); charIt.advance(1)) { 318 UChar c = charIt.characterAt(0); 319 if ((!isSpaceOrNewline(c) && c != noBreakSpace) || c == '\n') 320 break; 321 m_end = charIt.endPosition(); 322 changed = true; 323 } 324 if (changed) 325 didChange(); 326 } 327 328 void VisibleSelection::setBaseAndExtentToDeepEquivalents() 329 { 330 // Move the selection to rendered positions, if possible. 331 bool baseAndExtentEqual = m_base == m_extent; 332 if (m_base.isNotNull()) { 333 m_base = VisiblePosition(m_base, m_affinity).deepEquivalent(); 334 if (baseAndExtentEqual) 335 m_extent = m_base; 336 } 337 if (m_extent.isNotNull() && !baseAndExtentEqual) 338 m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent(); 339 340 // Make sure we do not have a dangling base or extent. 341 if (m_base.isNull() && m_extent.isNull()) 342 m_baseIsFirst = true; 343 else if (m_base.isNull()) { 344 m_base = m_extent; 345 m_baseIsFirst = true; 346 } else if (m_extent.isNull()) { 347 m_extent = m_base; 348 m_baseIsFirst = true; 349 } else 350 m_baseIsFirst = comparePositions(m_base, m_extent) <= 0; 351 } 352 353 void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity granularity) 354 { 355 if (m_baseIsFirst) { 356 m_start = m_base; 357 m_end = m_extent; 358 } else { 359 m_start = m_extent; 360 m_end = m_base; 361 } 362 363 switch (granularity) { 364 case CharacterGranularity: 365 // Don't do any expansion. 366 break; 367 case WordGranularity: { 368 // General case: Select the word the caret is positioned inside of, or at the start of (RightWordIfOnBoundary). 369 // Edge case: If the caret is after the last word in a soft-wrapped line or the last word in 370 // the document, select that last word (LeftWordIfOnBoundary). 371 // Edge case: If the caret is after the last word in a paragraph, select from the the end of the 372 // last word to the line break (also RightWordIfOnBoundary); 373 VisiblePosition start = VisiblePosition(m_start, m_affinity); 374 VisiblePosition originalEnd(m_end, m_affinity); 375 EWordSide side = RightWordIfOnBoundary; 376 if (isEndOfEditableOrNonEditableContent(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start))) 377 side = LeftWordIfOnBoundary; 378 m_start = startOfWord(start, side).deepEquivalent(); 379 side = RightWordIfOnBoundary; 380 if (isEndOfEditableOrNonEditableContent(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd))) 381 side = LeftWordIfOnBoundary; 382 383 VisiblePosition wordEnd(endOfWord(originalEnd, side)); 384 VisiblePosition end(wordEnd); 385 386 if (isEndOfParagraph(originalEnd) && !isEmptyTableCell(m_start.deprecatedNode())) { 387 // Select the paragraph break (the space from the end of a paragraph to the start of 388 // the next one) to match TextEdit. 389 end = wordEnd.next(); 390 391 if (Element* table = isFirstPositionAfterTable(end)) { 392 // The paragraph break after the last paragraph in the last cell of a block table ends 393 // at the start of the paragraph after the table. 394 if (isBlock(table)) 395 end = end.next(CannotCrossEditingBoundary); 396 else 397 end = wordEnd; 398 } 399 400 if (end.isNull()) 401 end = wordEnd; 402 403 } 404 405 m_end = end.deepEquivalent(); 406 break; 407 } 408 case SentenceGranularity: { 409 m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent(); 410 m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent(); 411 break; 412 } 413 case LineGranularity: { 414 m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent(); 415 VisiblePosition end = endOfLine(VisiblePosition(m_end, m_affinity)); 416 // If the end of this line is at the end of a paragraph, include the space 417 // after the end of the line in the selection. 418 if (isEndOfParagraph(end)) { 419 VisiblePosition next = end.next(); 420 if (next.isNotNull()) 421 end = next; 422 } 423 m_end = end.deepEquivalent(); 424 break; 425 } 426 case LineBoundary: 427 m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent(); 428 m_end = endOfLine(VisiblePosition(m_end, m_affinity)).deepEquivalent(); 429 break; 430 case ParagraphGranularity: { 431 VisiblePosition pos(m_start, m_affinity); 432 if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos)) 433 pos = pos.previous(); 434 m_start = startOfParagraph(pos).deepEquivalent(); 435 VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition(m_end, m_affinity)); 436 437 // Include the "paragraph break" (the space from the end of this paragraph to the start 438 // of the next one) in the selection. 439 VisiblePosition end(visibleParagraphEnd.next()); 440 441 if (Element* table = isFirstPositionAfterTable(end)) { 442 // The paragraph break after the last paragraph in the last cell of a block table ends 443 // at the start of the paragraph after the table, not at the position just after the table. 444 if (isBlock(table)) 445 end = end.next(CannotCrossEditingBoundary); 446 // There is no parargraph break after the last paragraph in the last cell of an inline table. 447 else 448 end = visibleParagraphEnd; 449 } 450 451 if (end.isNull()) 452 end = visibleParagraphEnd; 453 454 m_end = end.deepEquivalent(); 455 break; 456 } 457 case DocumentBoundary: 458 m_start = startOfDocument(VisiblePosition(m_start, m_affinity)).deepEquivalent(); 459 m_end = endOfDocument(VisiblePosition(m_end, m_affinity)).deepEquivalent(); 460 break; 461 case ParagraphBoundary: 462 m_start = startOfParagraph(VisiblePosition(m_start, m_affinity)).deepEquivalent(); 463 m_end = endOfParagraph(VisiblePosition(m_end, m_affinity)).deepEquivalent(); 464 break; 465 case SentenceBoundary: 466 m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent(); 467 m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent(); 468 break; 469 } 470 471 // Make sure we do not have a dangling start or end. 472 if (m_start.isNull()) 473 m_start = m_end; 474 if (m_end.isNull()) 475 m_end = m_start; 476 } 477 478 void VisibleSelection::updateSelectionType() 479 { 480 if (m_start.isNull()) { 481 ASSERT(m_end.isNull()); 482 m_selectionType = NoSelection; 483 } else if (m_start == m_end || m_start.upstream() == m_end.upstream()) { 484 m_selectionType = CaretSelection; 485 } else 486 m_selectionType = RangeSelection; 487 488 // Affinity only makes sense for a caret 489 if (m_selectionType != CaretSelection) 490 m_affinity = DOWNSTREAM; 491 } 492 493 void VisibleSelection::validate(TextGranularity granularity) 494 { 495 setBaseAndExtentToDeepEquivalents(); 496 setStartAndEndFromBaseAndExtentRespectingGranularity(granularity); 497 adjustSelectionToAvoidCrossingShadowBoundaries(); 498 adjustSelectionToAvoidCrossingEditingBoundaries(); 499 updateSelectionType(); 500 501 if (selectionType() == RangeSelection) { 502 // "Constrain" the selection to be the smallest equivalent range of nodes. 503 // This is a somewhat arbitrary choice, but experience shows that it is 504 // useful to make to make the selection "canonical" (if only for 505 // purposes of comparing selections). This is an ideal point of the code 506 // to do this operation, since all selection changes that result in a RANGE 507 // come through here before anyone uses it. 508 // FIXME: Canonicalizing is good, but haven't we already done it (when we 509 // set these two positions to VisiblePosition deepEquivalent()s above)? 510 m_start = m_start.downstream(); 511 m_end = m_end.upstream(); 512 513 // FIXME: Position::downstream() or Position::upStream() might violate editing boundaries 514 // if an anchor node has a Shadow DOM. So we adjust selection to avoid crossing editing 515 // boundaries again. See https://bugs.webkit.org/show_bug.cgi?id=87463 516 adjustSelectionToAvoidCrossingEditingBoundaries(); 517 } 518 } 519 520 // FIXME: This function breaks the invariant of this class. 521 // But because we use VisibleSelection to store values in editing commands for use when 522 // undoing the command, we need to be able to create a selection that while currently 523 // invalid, will be valid once the changes are undone. This is a design problem. 524 // To fix it we either need to change the invariants of VisibleSelection or create a new 525 // class for editing to use that can manipulate selections that are not currently valid. 526 void VisibleSelection::setWithoutValidation(const Position& base, const Position& extent) 527 { 528 ASSERT(!base.isNull()); 529 ASSERT(!extent.isNull()); 530 ASSERT(m_affinity == DOWNSTREAM); 531 m_base = base; 532 m_extent = extent; 533 m_baseIsFirst = comparePositions(base, extent) <= 0; 534 if (m_baseIsFirst) { 535 m_start = base; 536 m_end = extent; 537 } else { 538 m_start = extent; 539 m_end = base; 540 } 541 m_selectionType = base == extent ? CaretSelection : RangeSelection; 542 didChange(); 543 } 544 545 static Position adjustPositionForEnd(const Position& currentPosition, Node* startContainerNode) 546 { 547 TreeScope& treeScope = startContainerNode->treeScope(); 548 549 ASSERT(currentPosition.containerNode()->treeScope() != treeScope); 550 551 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.containerNode())) { 552 if (ancestor->contains(startContainerNode)) 553 return positionAfterNode(ancestor); 554 return positionBeforeNode(ancestor); 555 } 556 557 if (Node* lastChild = treeScope.rootNode().lastChild()) 558 return positionAfterNode(lastChild); 559 560 return Position(); 561 } 562 563 static Position adjustPositionForStart(const Position& currentPosition, Node* endContainerNode) 564 { 565 TreeScope& treeScope = endContainerNode->treeScope(); 566 567 ASSERT(currentPosition.containerNode()->treeScope() != treeScope); 568 569 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.containerNode())) { 570 if (ancestor->contains(endContainerNode)) 571 return positionBeforeNode(ancestor); 572 return positionAfterNode(ancestor); 573 } 574 575 if (Node* firstChild = treeScope.rootNode().firstChild()) 576 return positionBeforeNode(firstChild); 577 578 return Position(); 579 } 580 581 void VisibleSelection::adjustSelectionToAvoidCrossingShadowBoundaries() 582 { 583 if (m_base.isNull() || m_start.isNull() || m_end.isNull()) 584 return; 585 586 if (m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope()) 587 return; 588 589 if (m_baseIsFirst) { 590 m_extent = adjustPositionForEnd(m_end, m_start.containerNode()); 591 m_end = m_extent; 592 } else { 593 m_extent = adjustPositionForStart(m_start, m_end.containerNode()); 594 m_start = m_extent; 595 } 596 597 ASSERT(m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope()); 598 } 599 600 void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries() 601 { 602 if (m_base.isNull() || m_start.isNull() || m_end.isNull()) 603 return; 604 605 ContainerNode* baseRoot = highestEditableRoot(m_base); 606 ContainerNode* startRoot = highestEditableRoot(m_start); 607 ContainerNode* endRoot = highestEditableRoot(m_end); 608 609 Element* baseEditableAncestor = lowestEditableAncestor(m_base.containerNode()); 610 611 // The base, start and end are all in the same region. No adjustment necessary. 612 if (baseRoot == startRoot && baseRoot == endRoot) 613 return; 614 615 // The selection is based in editable content. 616 if (baseRoot) { 617 // If the start is outside the base's editable root, cap it at the start of that root. 618 // If the start is in non-editable content that is inside the base's editable root, put it 619 // at the first editable position after start inside the base's editable root. 620 if (startRoot != baseRoot) { 621 VisiblePosition first = firstEditableVisiblePositionAfterPositionInRoot(m_start, baseRoot); 622 m_start = first.deepEquivalent(); 623 if (m_start.isNull()) { 624 ASSERT_NOT_REACHED(); 625 m_start = m_end; 626 } 627 } 628 // If the end is outside the base's editable root, cap it at the end of that root. 629 // If the end is in non-editable content that is inside the base's root, put it 630 // at the last editable position before the end inside the base's root. 631 if (endRoot != baseRoot) { 632 VisiblePosition last = lastEditableVisiblePositionBeforePositionInRoot(m_end, baseRoot); 633 m_end = last.deepEquivalent(); 634 if (m_end.isNull()) 635 m_end = m_start; 636 } 637 // The selection is based in non-editable content. 638 } else { 639 // FIXME: Non-editable pieces inside editable content should be atomic, in the same way that editable 640 // pieces in non-editable content are atomic. 641 642 // The selection ends in editable content or non-editable content inside a different editable ancestor, 643 // move backward until non-editable content inside the same lowest editable ancestor is reached. 644 Element* endEditableAncestor = lowestEditableAncestor(m_end.containerNode()); 645 if (endRoot || endEditableAncestor != baseEditableAncestor) { 646 647 Position p = previousVisuallyDistinctCandidate(m_end); 648 Element* shadowAncestor = endRoot ? endRoot->shadowHost() : 0; 649 if (p.isNull() && shadowAncestor) 650 p = positionAfterNode(shadowAncestor); 651 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) { 652 Element* root = editableRootForPosition(p); 653 shadowAncestor = root ? root->shadowHost() : 0; 654 p = isAtomicNode(p.containerNode()) ? positionInParentBeforeNode(*p.containerNode()) : previousVisuallyDistinctCandidate(p); 655 if (p.isNull() && shadowAncestor) 656 p = positionAfterNode(shadowAncestor); 657 } 658 VisiblePosition previous(p); 659 660 if (previous.isNull()) { 661 // The selection crosses an Editing boundary. This is a 662 // programmer error in the editing code. Happy debugging! 663 ASSERT_NOT_REACHED(); 664 m_base = Position(); 665 m_extent = Position(); 666 validate(); 667 return; 668 } 669 m_end = previous.deepEquivalent(); 670 } 671 672 // The selection starts in editable content or non-editable content inside a different editable ancestor, 673 // move forward until non-editable content inside the same lowest editable ancestor is reached. 674 Element* startEditableAncestor = lowestEditableAncestor(m_start.containerNode()); 675 if (startRoot || startEditableAncestor != baseEditableAncestor) { 676 Position p = nextVisuallyDistinctCandidate(m_start); 677 Element* shadowAncestor = startRoot ? startRoot->shadowHost() : 0; 678 if (p.isNull() && shadowAncestor) 679 p = positionBeforeNode(shadowAncestor); 680 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) { 681 Element* root = editableRootForPosition(p); 682 shadowAncestor = root ? root->shadowHost() : 0; 683 p = isAtomicNode(p.containerNode()) ? positionInParentAfterNode(*p.containerNode()) : nextVisuallyDistinctCandidate(p); 684 if (p.isNull() && shadowAncestor) 685 p = positionBeforeNode(shadowAncestor); 686 } 687 VisiblePosition next(p); 688 689 if (next.isNull()) { 690 // The selection crosses an Editing boundary. This is a 691 // programmer error in the editing code. Happy debugging! 692 ASSERT_NOT_REACHED(); 693 m_base = Position(); 694 m_extent = Position(); 695 validate(); 696 return; 697 } 698 m_start = next.deepEquivalent(); 699 } 700 } 701 702 // Correct the extent if necessary. 703 if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode())) 704 m_extent = m_baseIsFirst ? m_end : m_start; 705 } 706 707 VisiblePosition VisibleSelection::visiblePositionRespectingEditingBoundary(const LayoutPoint& localPoint, Node* targetNode) const 708 { 709 if (!targetNode->renderer()) 710 return VisiblePosition(); 711 712 LayoutPoint selectionEndPoint = localPoint; 713 Element* editableElement = rootEditableElement(); 714 715 if (editableElement && !editableElement->contains(targetNode)) { 716 if (!editableElement->renderer()) 717 return VisiblePosition(); 718 719 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint)); 720 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint)); 721 targetNode = editableElement; 722 } 723 724 return VisiblePosition(targetNode->renderer()->positionForPoint(selectionEndPoint)); 725 } 726 727 728 bool VisibleSelection::isContentEditable() const 729 { 730 return isEditablePosition(start()); 731 } 732 733 bool VisibleSelection::hasEditableStyle() const 734 { 735 return isEditablePosition(start(), ContentIsEditable, DoNotUpdateStyle); 736 } 737 738 bool VisibleSelection::isContentRichlyEditable() const 739 { 740 return isRichlyEditablePosition(start()); 741 } 742 743 Element* VisibleSelection::rootEditableElement() const 744 { 745 return editableRootForPosition(start()); 746 } 747 748 Node* VisibleSelection::nonBoundaryShadowTreeRootNode() const 749 { 750 return start().deprecatedNode() ? start().deprecatedNode()->nonBoundaryShadowTreeRootNode() : 0; 751 } 752 753 VisibleSelection::ChangeObserver::ChangeObserver() 754 { 755 } 756 757 VisibleSelection::ChangeObserver::~ChangeObserver() 758 { 759 } 760 761 void VisibleSelection::setChangeObserver(ChangeObserver& observer) 762 { 763 ASSERT(!m_changeObserver); 764 m_changeObserver = &observer; 765 } 766 767 void VisibleSelection::clearChangeObserver() 768 { 769 ASSERT(m_changeObserver); 770 m_changeObserver = nullptr; 771 } 772 773 void VisibleSelection::didChange() 774 { 775 if (m_changeObserver) 776 m_changeObserver->didChangeVisibleSelection(); 777 } 778 779 void VisibleSelection::trace(Visitor* visitor) 780 { 781 visitor->trace(m_base); 782 visitor->trace(m_extent); 783 visitor->trace(m_start); 784 visitor->trace(m_end); 785 visitor->trace(m_changeObserver); 786 } 787 788 static bool isValidPosition(const Position& position) 789 { 790 if (!position.inDocument()) 791 return false; 792 793 if (position.anchorType() != Position::PositionIsOffsetInAnchor) 794 return true; 795 796 if (position.offsetInContainerNode() < 0) 797 return false; 798 799 const unsigned offset = static_cast<unsigned>(position.offsetInContainerNode()); 800 const unsigned nodeLength = position.anchorNode()->lengthOfContents(); 801 return offset <= nodeLength; 802 } 803 804 void VisibleSelection::validatePositionsIfNeeded() 805 { 806 if (!isValidPosition(m_base) || !isValidPosition(m_extent) || !isValidPosition(m_start) || !isValidPosition(m_end)) 807 validate(); 808 } 809 810 #ifndef NDEBUG 811 812 void VisibleSelection::debugPosition() const 813 { 814 fprintf(stderr, "VisibleSelection ===============\n"); 815 816 if (!m_start.anchorNode()) 817 fputs("pos: null", stderr); 818 else if (m_start == m_end) { 819 fprintf(stderr, "pos: %s ", m_start.anchorNode()->nodeName().utf8().data()); 820 m_start.showAnchorTypeAndOffset(); 821 } else { 822 fprintf(stderr, "start: %s ", m_start.anchorNode()->nodeName().utf8().data()); 823 m_start.showAnchorTypeAndOffset(); 824 fprintf(stderr, "end: %s ", m_end.anchorNode()->nodeName().utf8().data()); 825 m_end.showAnchorTypeAndOffset(); 826 } 827 828 fprintf(stderr, "================================\n"); 829 } 830 831 void VisibleSelection::formatForDebugger(char* buffer, unsigned length) const 832 { 833 StringBuilder result; 834 String s; 835 836 if (isNone()) { 837 result.appendLiteral("<none>"); 838 } else { 839 const int FormatBufferSize = 1024; 840 char s[FormatBufferSize]; 841 result.appendLiteral("from "); 842 start().formatForDebugger(s, FormatBufferSize); 843 result.append(s); 844 result.appendLiteral(" to "); 845 end().formatForDebugger(s, FormatBufferSize); 846 result.append(s); 847 } 848 849 strncpy(buffer, result.toString().utf8().data(), length - 1); 850 } 851 852 void VisibleSelection::showTreeForThis() const 853 { 854 if (start().anchorNode()) { 855 start().anchorNode()->showTreeAndMark(start().anchorNode(), "S", end().anchorNode(), "E"); 856 fputs("start: ", stderr); 857 start().showAnchorTypeAndOffset(); 858 fputs("end: ", stderr); 859 end().showAnchorTypeAndOffset(); 860 } 861 } 862 863 #endif 864 865 } // namespace blink 866 867 #ifndef NDEBUG 868 869 void showTree(const blink::VisibleSelection& sel) 870 { 871 sel.showTreeForThis(); 872 } 873 874 void showTree(const blink::VisibleSelection* sel) 875 { 876 if (sel) 877 sel->showTreeForThis(); 878 } 879 880 #endif 881