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