Gracefully handle XMLDocumentParser being detached by mutation events.
[chromium-blink-merge.git] / third_party / WebKit / Source / core / editing / VisibleSelection.h
blob8b83c00e0495ae293e8da9216678506c46933d79
1 /*
2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
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.
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.
26 #ifndef VisibleSelection_h
27 #define VisibleSelection_h
29 #include "core/CoreExport.h"
30 #include "core/editing/EditingStrategy.h"
31 #include "core/editing/EphemeralRange.h"
32 #include "core/editing/SelectionType.h"
33 #include "core/editing/TextGranularity.h"
34 #include "core/editing/VisiblePosition.h"
35 #include "core/editing/VisibleUnits.h"
37 namespace blink {
39 class LayoutPoint;
41 const EAffinity SEL_DEFAULT_AFFINITY = DOWNSTREAM;
42 enum SelectionDirection { DirectionForward, DirectionBackward, DirectionRight, DirectionLeft };
44 class CORE_EXPORT VisibleSelection {
45 DISALLOW_ALLOCATION();
46 DECLARE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(VisibleSelection);
47 public:
48 class InDOMTree {
49 public:
50 using PositionType = Position;
51 using Strategy = EditingStrategy;
53 static EphemeralRange asRange(const VisibleSelection&);
54 static bool equalSelections(const VisibleSelection&, const VisibleSelection&);
55 static PositionType selectionBase(const VisibleSelection& selection) { return selection.base(); }
56 static PositionType selectionExtent(const VisibleSelection& selection) { return selection.extent(); }
57 static PositionType selectionStart(const VisibleSelection& selection) { return selection.start(); }
58 static PositionType selectionEnd(const VisibleSelection& selection) { return selection.end(); }
59 static SelectionType selectionType(const VisibleSelection& selection) { return selection.selectionType(); }
60 static VisiblePosition selectionVisibleStart(const VisibleSelection& selection) { return selection.visibleStart(); }
61 static VisiblePosition selectionVisibleEnd(const VisibleSelection& selection) { return selection.visibleEnd(); }
62 static PositionType toPositionType(const Position& position) { return position; }
65 class InComposedTree {
66 public:
67 using PositionType = PositionInComposedTree;
68 using Strategy = EditingInComposedTreeStrategy;
70 static EphemeralRangeInComposedTree asRange(const VisibleSelection&);
71 static bool equalSelections(const VisibleSelection&, const VisibleSelection&);
72 static bool isRange(const VisibleSelection& selection) { return selectionType(selection) == RangeSelection; }
73 static PositionType selectionBase(const VisibleSelection& selection) { return selection.baseInComposedTree(); }
74 static PositionType selectionExtent(const VisibleSelection& selection) { return selection.extentInComposedTree(); }
75 static PositionType selectionStart(const VisibleSelection& selection) { return selection.startInComposedTree(); }
76 static PositionType selectionEnd(const VisibleSelection& selection) { return selection.endInComposedTree(); }
77 static SelectionType selectionType(const VisibleSelection& selection) { return selection.selectionTypeInComposedTree(); }
78 static VisiblePosition selectionVisibleStart(const VisibleSelection& selection)
80 return VisiblePosition(selectionStart(selection), isRange(selection) ? DOWNSTREAM : selection.affinity());
82 static VisiblePosition selectionVisibleEnd(const VisibleSelection& selection)
84 return VisiblePosition(selectionEnd(selection), isRange(selection) ? UPSTREAM : selection.affinity());
86 static PositionType toPositionType(const Position& position) { return toPositionInComposedTree(position); }
89 VisibleSelection();
91 VisibleSelection(const Position&, EAffinity, bool isDirectional = false);
92 VisibleSelection(const Position& base, const Position& extent, EAffinity = SEL_DEFAULT_AFFINITY, bool isDirectional = false);
93 VisibleSelection(const PositionInComposedTree& base, const PositionInComposedTree& extent, EAffinity = SEL_DEFAULT_AFFINITY, bool isDirectional = false);
95 explicit VisibleSelection(const EphemeralRange&, EAffinity = SEL_DEFAULT_AFFINITY, bool isDirectional = false);
96 explicit VisibleSelection(const Range*, EAffinity = SEL_DEFAULT_AFFINITY, bool isDirectional = false);
98 explicit VisibleSelection(const VisiblePosition&, bool isDirectional = false);
99 VisibleSelection(const VisiblePosition&, const VisiblePosition&, bool isDirectional = false);
101 VisibleSelection(const VisibleSelection&);
102 VisibleSelection& operator=(const VisibleSelection&);
104 static VisibleSelection selectionFromContentsOfNode(Node*);
106 SelectionType selectionType() const { return m_selectionType; }
107 SelectionType selectionTypeInComposedTree() const;
109 void setAffinity(EAffinity affinity) { m_affinity = affinity; }
110 EAffinity affinity() const { return m_affinity; }
112 void setBase(const Position&);
113 void setBase(const PositionInComposedTree&);
114 void setBase(const VisiblePosition&);
115 void setExtent(const Position&);
116 void setExtent(const PositionInComposedTree&);
117 void setExtent(const VisiblePosition&);
119 Position base() const { return m_base; }
120 Position extent() const { return m_extent; }
121 Position start() const { return m_start; }
122 Position end() const { return m_end; }
123 PositionInComposedTree baseInComposedTree() const;
124 PositionInComposedTree extentInComposedTree() const;
125 PositionInComposedTree startInComposedTree() const;
126 PositionInComposedTree endInComposedTree() const;
128 VisiblePosition visibleStart() const { return VisiblePosition(m_start, isRange() ? DOWNSTREAM : affinity()); }
129 VisiblePosition visibleEnd() const { return VisiblePosition(m_end, isRange() ? UPSTREAM : affinity()); }
130 VisiblePosition visibleBase() const { return VisiblePosition(m_base, isRange() ? (isBaseFirst() ? UPSTREAM : DOWNSTREAM) : affinity()); }
131 VisiblePosition visibleExtent() const { return VisiblePosition(m_extent, isRange() ? (isBaseFirst() ? DOWNSTREAM : UPSTREAM) : affinity()); }
133 bool isNone() const { return selectionType() == NoSelection; }
134 bool isCaret() const { return selectionType() == CaretSelection; }
135 bool isRange() const { return selectionType() == RangeSelection; }
136 bool isCaretOrRange() const { return selectionType() != NoSelection; }
137 bool isNonOrphanedRange() const { return isRange() && !start().isOrphan() && !end().isOrphan(); }
138 bool isNonOrphanedCaretOrRange() const { return isCaretOrRange() && !start().isOrphan() && !end().isOrphan(); }
139 static SelectionType selectionType(const Position& start, const Position& end);
140 static SelectionType selectionType(const PositionInComposedTree& start, const PositionInComposedTree& end);
142 bool isBaseFirst() const { return m_baseIsFirst; }
143 bool isDirectional() const { return m_isDirectional; }
144 void setIsDirectional(bool isDirectional) { m_isDirectional = isDirectional; }
146 void appendTrailingWhitespace();
148 bool expandUsingGranularity(TextGranularity);
149 bool expandUsingGranularityInComposedTree(TextGranularity);
151 // We don't yet support multi-range selections, so we only ever have one range to return.
152 PassRefPtrWillBeRawPtr<Range> firstRange() const;
154 bool intersectsNode(Node*) const;
156 // FIXME: Most callers probably don't want these functions, but
157 // are using them for historical reasons. toNormalizedRange and
158 // toNormalizedEphemeralRange contracts the range around text, and
159 // moves the caret upstream before returning the range/positions.
160 PassRefPtrWillBeRawPtr<Range> toNormalizedRange() const;
161 EphemeralRange toNormalizedEphemeralRange() const;
162 static EphemeralRange normalizeRange(const EphemeralRange&);
163 static EphemeralRangeInComposedTree normalizeRange(const EphemeralRangeInComposedTree&);
165 Element* rootEditableElement() const;
166 bool isContentEditable() const;
167 bool hasEditableStyle() const;
168 bool isContentRichlyEditable() const;
169 // Returns a shadow tree node for legacy shadow trees, a child of the
170 // ShadowRoot node for new shadow trees, or 0 for non-shadow trees.
171 Node* nonBoundaryShadowTreeRootNode() const;
173 VisiblePosition visiblePositionRespectingEditingBoundary(const LayoutPoint& localPoint, Node* targetNode) const;
174 PositionWithAffinity positionRespectingEditingBoundary(const LayoutPoint& localPoint, Node* targetNode) const;
176 void setWithoutValidation(const Position&, const Position&);
177 void setWithoutValidation(const PositionInComposedTree&, const PositionInComposedTree&);
179 // Listener of VisibleSelection modification. didChangeVisibleSelection() will be invoked when base, extent, start
180 // or end is moved to a different position.
182 // Objects implementing |ChangeObserver| interface must outlive the VisibleSelection object.
183 class CORE_EXPORT ChangeObserver : public WillBeGarbageCollectedMixin {
184 WTF_MAKE_NONCOPYABLE(ChangeObserver);
185 public:
186 ChangeObserver();
187 virtual ~ChangeObserver();
188 virtual void didChangeVisibleSelection() = 0;
189 DEFINE_INLINE_VIRTUAL_TRACE() { }
192 void setChangeObserver(ChangeObserver&);
193 void clearChangeObserver();
194 void didChange(); // Fire the change observer, if any.
196 DECLARE_TRACE();
198 void validatePositionsIfNeeded();
200 #ifndef NDEBUG
201 void debugPosition(const char* message) const;
202 void formatForDebugger(char* buffer, unsigned length) const;
203 void showTreeForThis() const;
204 #endif
206 void setStartRespectingGranularity(TextGranularity, EWordSide = RightWordIfOnBoundary);
207 void setEndRespectingGranularity(TextGranularity, EWordSide = RightWordIfOnBoundary);
209 private:
210 void validate(TextGranularity = CharacterGranularity);
211 void resetPositionsInComposedTree();
213 // Support methods for validate()
214 void setBaseAndExtentToDeepEquivalents();
215 void adjustSelectionToAvoidCrossingShadowBoundaries();
216 void adjustSelectionToAvoidCrossingSelectionBoundaryInComposedTree();
217 bool isBaseFirstInComposedTree() const;
218 void adjustSelectionToAvoidCrossingEditingBoundaries();
219 void adjustStartAndEndInComposedTree();
220 void updateSelectionType();
222 // We need to store these as Positions because VisibleSelection is
223 // used to store values in editing commands for use when
224 // undoing the command. We need to be able to create a selection that, while currently
225 // invalid, will be valid once the changes are undone.
227 Position m_base; // Where the first click happened
228 Position m_extent; // Where the end click happened
229 Position m_start; // Leftmost position when expanded to respect granularity
230 Position m_end; // Rightmost position when expanded to respect granularity
232 // TODO(hajimehoshi, yosin): The members m_*InComposedTree are now always
233 // computed from the respective positions at validate(). To have selections
234 // work on the composed tree more accurately, we need to compute the DOM
235 // positions from the composed tree positions. To do this, we need to add
236 // considable amount of fixes (including htmlediting.cpp, VisibleUnit.cpp,
237 // and VisiblePosition.cpp). We'll do that in the future.
238 PositionInComposedTree m_baseInComposedTree;
239 PositionInComposedTree m_extentInComposedTree;
240 PositionInComposedTree m_startInComposedTree;
241 PositionInComposedTree m_endInComposedTree;
243 EAffinity m_affinity; // the upstream/downstream affinity of the caret
245 // Oilpan: this reference has a lifetime that is at least as long
246 // as this object.
247 RawPtrWillBeMember<ChangeObserver> m_changeObserver;
249 // these are cached, can be recalculated by validate()
250 SelectionType m_selectionType; // None, Caret, Range
251 bool m_baseIsFirst : 1; // True if base is before the extent
252 bool m_isDirectional : 1; // Non-directional ignores m_baseIsFirst and selection always extends on shift + arrow key.
255 } // namespace blink
257 #ifndef NDEBUG
258 // Outside the WebCore namespace for ease of invocation from gdb.
259 void showTree(const blink::VisibleSelection&);
260 void showTree(const blink::VisibleSelection*);
261 #endif
263 #endif // VisibleSelection_h