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