• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VisibleSelection()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 
VisibleSelection(const Position & pos,EAffinity affinity,bool isDirectional)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 
VisibleSelection(const Position & base,const Position & extent,EAffinity affinity,bool isDirectional)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 
VisibleSelection(const VisiblePosition & pos,bool isDirectional)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 
VisibleSelection(const VisiblePosition & base,const VisiblePosition & extent,bool isDirectional)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 
VisibleSelection(const Range * range,EAffinity affinity,bool isDirectional)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 
VisibleSelection(const VisibleSelection & other)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 
operator =(const VisibleSelection & other)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 
~VisibleSelection()137 VisibleSelection::~VisibleSelection()
138 {
139 #if !ENABLE(OILPAN)
140     didChange();
141 #endif
142 }
143 
selectionFromContentsOfNode(Node * node)144 VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node)
145 {
146     ASSERT(!editingIgnoresContent(node));
147     return VisibleSelection(firstPositionInNode(node), lastPositionInNode(node), DOWNSTREAM);
148 }
149 
setBase(const Position & position)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 
setBase(const VisiblePosition & visiblePosition)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 
setExtent(const Position & position)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 
setExtent(const VisiblePosition & visiblePosition)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 
firstRange() const186 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 
intersectsNode(Node * node) const195 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 
toNormalizedRange() const205 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 
toNormalizedPositions(Position & start,Position & end) const213 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 
expandUsingGranularity(TextGranularity granularity)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 
makeSearchRange(const Position & pos)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 
appendTrailingWhitespace()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 
setBaseAndExtentToDeepEquivalents()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 
setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity granularity)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 
updateSelectionType()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 
validate(TextGranularity granularity)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.
setWithoutValidation(const Position & base,const Position & extent)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 
adjustPositionForEnd(const Position & currentPosition,Node * startContainerNode)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 
adjustPositionForStart(const Position & currentPosition,Node * endContainerNode)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 
adjustSelectionToAvoidCrossingShadowBoundaries()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 
adjustSelectionToAvoidCrossingEditingBoundaries()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 
visiblePositionRespectingEditingBoundary(const LayoutPoint & localPoint,Node * targetNode) const707 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 
isContentEditable() const728 bool VisibleSelection::isContentEditable() const
729 {
730     return isEditablePosition(start());
731 }
732 
hasEditableStyle() const733 bool VisibleSelection::hasEditableStyle() const
734 {
735     return isEditablePosition(start(), ContentIsEditable, DoNotUpdateStyle);
736 }
737 
isContentRichlyEditable() const738 bool VisibleSelection::isContentRichlyEditable() const
739 {
740     return isRichlyEditablePosition(start());
741 }
742 
rootEditableElement() const743 Element* VisibleSelection::rootEditableElement() const
744 {
745     return editableRootForPosition(start());
746 }
747 
nonBoundaryShadowTreeRootNode() const748 Node* VisibleSelection::nonBoundaryShadowTreeRootNode() const
749 {
750     return start().deprecatedNode() ? start().deprecatedNode()->nonBoundaryShadowTreeRootNode() : 0;
751 }
752 
ChangeObserver()753 VisibleSelection::ChangeObserver::ChangeObserver()
754 {
755 }
756 
~ChangeObserver()757 VisibleSelection::ChangeObserver::~ChangeObserver()
758 {
759 }
760 
setChangeObserver(ChangeObserver & observer)761 void VisibleSelection::setChangeObserver(ChangeObserver& observer)
762 {
763     ASSERT(!m_changeObserver);
764     m_changeObserver = &observer;
765 }
766 
clearChangeObserver()767 void VisibleSelection::clearChangeObserver()
768 {
769     ASSERT(m_changeObserver);
770     m_changeObserver = nullptr;
771 }
772 
didChange()773 void VisibleSelection::didChange()
774 {
775     if (m_changeObserver)
776         m_changeObserver->didChangeVisibleSelection();
777 }
778 
trace(Visitor * visitor)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 
isValidPosition(const Position & position)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 
validatePositionsIfNeeded()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 
debugPosition() const812 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 
formatForDebugger(char * buffer,unsigned length) const831 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 
showTreeForThis() const852 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 
showTree(const blink::VisibleSelection & sel)869 void showTree(const blink::VisibleSelection& sel)
870 {
871     sel.showTreeForThis();
872 }
873 
showTree(const blink::VisibleSelection * sel)874 void showTree(const blink::VisibleSelection* sel)
875 {
876     if (sel)
877         sel->showTreeForThis();
878 }
879 
880 #endif
881