Home | History | Annotate | Download | only in editing
      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