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