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
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"
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
);
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
{
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
); }
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
);
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.
198 void validatePositionsIfNeeded();
201 void debugPosition(const char* message
) const;
202 void formatForDebugger(char* buffer
, unsigned length
) const;
203 void showTreeForThis() const;
206 void setStartRespectingGranularity(TextGranularity
, EWordSide
= RightWordIfOnBoundary
);
207 void setEndRespectingGranularity(TextGranularity
, EWordSide
= RightWordIfOnBoundary
);
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
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.
258 // Outside the WebCore namespace for ease of invocation from gdb.
259 void showTree(const blink::VisibleSelection
&);
260 void showTree(const blink::VisibleSelection
*);
263 #endif // VisibleSelection_h