|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef mozilla_Selection_h__ |
|
8 #define mozilla_Selection_h__ |
|
9 |
|
10 #include "nsIWeakReference.h" |
|
11 |
|
12 #include "nsISelection.h" |
|
13 #include "nsISelectionController.h" |
|
14 #include "nsISelectionPrivate.h" |
|
15 #include "nsRange.h" |
|
16 #include "nsThreadUtils.h" |
|
17 #include "mozilla/TextRange.h" |
|
18 #include "nsWrapperCache.h" |
|
19 |
|
20 struct CachedOffsetForFrame; |
|
21 class nsAutoScrollTimer; |
|
22 class nsIContentIterator; |
|
23 class nsIFrame; |
|
24 class nsFrameSelection; |
|
25 struct SelectionDetails; |
|
26 |
|
27 namespace mozilla { |
|
28 class ErrorResult; |
|
29 } |
|
30 |
|
31 struct RangeData |
|
32 { |
|
33 RangeData(nsRange* aRange) |
|
34 : mRange(aRange) |
|
35 {} |
|
36 |
|
37 nsRefPtr<nsRange> mRange; |
|
38 mozilla::TextRangeStyle mTextRangeStyle; |
|
39 }; |
|
40 |
|
41 // Note, the ownership of mozilla::dom::Selection depends on which way the |
|
42 // object is created. When nsFrameSelection has created Selection, |
|
43 // addreffing/releasing the Selection object is aggregated to nsFrameSelection. |
|
44 // Otherwise normal addref/release is used. This ensures that nsFrameSelection |
|
45 // is never deleted before its Selections. |
|
46 namespace mozilla { |
|
47 namespace dom { |
|
48 |
|
49 class Selection : public nsISelectionPrivate, |
|
50 public nsWrapperCache, |
|
51 public nsSupportsWeakReference |
|
52 { |
|
53 public: |
|
54 Selection(); |
|
55 Selection(nsFrameSelection *aList); |
|
56 virtual ~Selection(); |
|
57 |
|
58 NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
|
59 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Selection, nsISelectionPrivate) |
|
60 NS_DECL_NSISELECTION |
|
61 NS_DECL_NSISELECTIONPRIVATE |
|
62 |
|
63 nsIDocument* GetParentObject() const; |
|
64 |
|
65 // utility methods for scrolling the selection into view |
|
66 nsPresContext* GetPresContext() const; |
|
67 nsIPresShell* GetPresShell() const; |
|
68 nsFrameSelection* GetFrameSelection() const { return mFrameSelection; } |
|
69 // Returns a rect containing the selection region, and frame that that |
|
70 // position is relative to. For SELECTION_ANCHOR_REGION or |
|
71 // SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For |
|
72 // SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus |
|
73 // region rects. |
|
74 nsIFrame* GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect *aRect); |
|
75 // Returns the position of the region (SELECTION_ANCHOR_REGION or |
|
76 // SELECTION_FOCUS_REGION only), and frame that that position is relative to. |
|
77 // The 'position' is a zero-width rectangle. |
|
78 nsIFrame* GetSelectionEndPointGeometry(SelectionRegion aRegion, nsRect *aRect); |
|
79 |
|
80 nsresult PostScrollSelectionIntoViewEvent( |
|
81 SelectionRegion aRegion, |
|
82 int32_t aFlags, |
|
83 nsIPresShell::ScrollAxis aVertical, |
|
84 nsIPresShell::ScrollAxis aHorizontal); |
|
85 enum { |
|
86 SCROLL_SYNCHRONOUS = 1<<1, |
|
87 SCROLL_FIRST_ANCESTOR_ONLY = 1<<2, |
|
88 SCROLL_DO_FLUSH = 1<<3, |
|
89 SCROLL_OVERFLOW_HIDDEN = 1<<5 |
|
90 }; |
|
91 // aDoFlush only matters if aIsSynchronous is true. If not, we'll just flush |
|
92 // when the scroll event fires so we make sure to scroll to the right place. |
|
93 nsresult ScrollIntoView(SelectionRegion aRegion, |
|
94 nsIPresShell::ScrollAxis aVertical = |
|
95 nsIPresShell::ScrollAxis(), |
|
96 nsIPresShell::ScrollAxis aHorizontal = |
|
97 nsIPresShell::ScrollAxis(), |
|
98 int32_t aFlags = 0); |
|
99 nsresult SubtractRange(RangeData* aRange, nsRange* aSubtract, |
|
100 nsTArray<RangeData>* aOutput); |
|
101 nsresult AddItem(nsRange *aRange, int32_t* aOutIndex); |
|
102 nsresult RemoveItem(nsRange *aRange); |
|
103 nsresult RemoveCollapsedRanges(); |
|
104 nsresult Clear(nsPresContext* aPresContext); |
|
105 nsresult Collapse(nsINode* aParentNode, int32_t aOffset); |
|
106 nsresult Extend(nsINode* aParentNode, int32_t aOffset); |
|
107 nsRange* GetRangeAt(int32_t aIndex); |
|
108 int32_t GetRangeCount() { return mRanges.Length(); } |
|
109 |
|
110 // Get the anchor-to-focus range if we don't care which end is |
|
111 // anchor and which end is focus. |
|
112 const nsRange* GetAnchorFocusRange() const { |
|
113 return mAnchorFocusRange; |
|
114 } |
|
115 |
|
116 nsDirection GetDirection(){return mDirection;} |
|
117 void SetDirection(nsDirection aDir){mDirection = aDir;} |
|
118 nsresult SetAnchorFocusToRange(nsRange *aRange); |
|
119 void ReplaceAnchorFocusRange(nsRange *aRange); |
|
120 |
|
121 // NS_IMETHOD GetPrimaryFrameForRangeEndpoint(nsIDOMNode *aNode, int32_t aOffset, bool aIsEndNode, nsIFrame **aResultFrame); |
|
122 NS_IMETHOD GetPrimaryFrameForAnchorNode(nsIFrame **aResultFrame); |
|
123 NS_IMETHOD GetPrimaryFrameForFocusNode(nsIFrame **aResultFrame, int32_t *aOffset, bool aVisual); |
|
124 NS_IMETHOD LookUpSelection(nsIContent *aContent, int32_t aContentOffset, int32_t aContentLength, |
|
125 SelectionDetails **aReturnDetails, SelectionType aType, bool aSlowCheck); |
|
126 NS_IMETHOD Repaint(nsPresContext* aPresContext); |
|
127 |
|
128 // Note: StartAutoScrollTimer might destroy arbitrary frames etc. |
|
129 nsresult StartAutoScrollTimer(nsIFrame *aFrame, |
|
130 nsPoint& aPoint, |
|
131 uint32_t aDelay); |
|
132 |
|
133 nsresult StopAutoScrollTimer(); |
|
134 |
|
135 JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; |
|
136 |
|
137 // WebIDL methods |
|
138 nsINode* GetAnchorNode(); |
|
139 uint32_t AnchorOffset(); |
|
140 nsINode* GetFocusNode(); |
|
141 uint32_t FocusOffset(); |
|
142 |
|
143 bool IsCollapsed(); |
|
144 void Collapse(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv); |
|
145 void CollapseToStart(mozilla::ErrorResult& aRv); |
|
146 void CollapseToEnd(mozilla::ErrorResult& aRv); |
|
147 |
|
148 void Extend(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv); |
|
149 |
|
150 void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv); |
|
151 void DeleteFromDocument(mozilla::ErrorResult& aRv); |
|
152 |
|
153 uint32_t RangeCount() const |
|
154 { |
|
155 return mRanges.Length(); |
|
156 } |
|
157 nsRange* GetRangeAt(uint32_t aIndex, mozilla::ErrorResult& aRv); |
|
158 void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv); |
|
159 void RemoveRange(nsRange& aRange, mozilla::ErrorResult& aRv); |
|
160 void RemoveAllRanges(mozilla::ErrorResult& aRv); |
|
161 |
|
162 void Stringify(nsAString& aResult); |
|
163 |
|
164 bool ContainsNode(nsINode* aNode, bool aPartlyContained, mozilla::ErrorResult& aRv); |
|
165 |
|
166 void Modify(const nsAString& aAlter, const nsAString& aDirection, |
|
167 const nsAString& aGranularity, mozilla::ErrorResult& aRv); |
|
168 |
|
169 bool GetInterlinePosition(mozilla::ErrorResult& aRv); |
|
170 void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv); |
|
171 |
|
172 void ToStringWithFormat(const nsAString& aFormatType, |
|
173 uint32_t aFlags, |
|
174 int32_t aWrapColumn, |
|
175 nsAString& aReturn, |
|
176 mozilla::ErrorResult& aRv); |
|
177 void AddSelectionListener(nsISelectionListener* aListener, |
|
178 mozilla::ErrorResult& aRv); |
|
179 void RemoveSelectionListener(nsISelectionListener* aListener, |
|
180 mozilla::ErrorResult& aRv); |
|
181 |
|
182 int16_t Type() const { return mType; } |
|
183 |
|
184 void GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset, |
|
185 nsINode& aEndNode, int32_t aEndOffset, |
|
186 bool aAllowAdjacent, |
|
187 nsTArray<nsRefPtr<nsRange>>& aReturn, |
|
188 mozilla::ErrorResult& aRv); |
|
189 |
|
190 void ScrollIntoView(int16_t aRegion, bool aIsSynchronous, |
|
191 int16_t aVPercent, int16_t aHPercent, |
|
192 mozilla::ErrorResult& aRv); |
|
193 |
|
194 private: |
|
195 friend class ::nsAutoScrollTimer; |
|
196 |
|
197 // Note: DoAutoScroll might destroy arbitrary frames etc. |
|
198 nsresult DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint); |
|
199 |
|
200 public: |
|
201 SelectionType GetType(){return mType;} |
|
202 void SetType(SelectionType aType){mType = aType;} |
|
203 |
|
204 nsresult NotifySelectionListeners(); |
|
205 |
|
206 private: |
|
207 |
|
208 class ScrollSelectionIntoViewEvent; |
|
209 friend class ScrollSelectionIntoViewEvent; |
|
210 |
|
211 class ScrollSelectionIntoViewEvent : public nsRunnable { |
|
212 public: |
|
213 NS_DECL_NSIRUNNABLE |
|
214 ScrollSelectionIntoViewEvent(Selection* aSelection, |
|
215 SelectionRegion aRegion, |
|
216 nsIPresShell::ScrollAxis aVertical, |
|
217 nsIPresShell::ScrollAxis aHorizontal, |
|
218 int32_t aFlags) |
|
219 : mSelection(aSelection), |
|
220 mRegion(aRegion), |
|
221 mVerticalScroll(aVertical), |
|
222 mHorizontalScroll(aHorizontal), |
|
223 mFlags(aFlags) { |
|
224 NS_ASSERTION(aSelection, "null parameter"); |
|
225 } |
|
226 void Revoke() { mSelection = nullptr; } |
|
227 private: |
|
228 Selection *mSelection; |
|
229 SelectionRegion mRegion; |
|
230 nsIPresShell::ScrollAxis mVerticalScroll; |
|
231 nsIPresShell::ScrollAxis mHorizontalScroll; |
|
232 int32_t mFlags; |
|
233 }; |
|
234 |
|
235 void setAnchorFocusRange(int32_t aIndex); // pass in index into mRanges; |
|
236 // negative value clears |
|
237 // mAnchorFocusRange |
|
238 nsresult SelectAllFramesForContent(nsIContentIterator *aInnerIter, |
|
239 nsIContent *aContent, |
|
240 bool aSelected); |
|
241 nsresult selectFrames(nsPresContext* aPresContext, nsRange *aRange, bool aSelect); |
|
242 nsresult getTableCellLocationFromRange(nsRange *aRange, int32_t *aSelectionType, int32_t *aRow, int32_t *aCol); |
|
243 nsresult addTableCellRange(nsRange *aRange, bool *aDidAddRange, int32_t *aOutIndex); |
|
244 |
|
245 nsresult FindInsertionPoint( |
|
246 nsTArray<RangeData>* aElementArray, |
|
247 nsINode* aPointNode, int32_t aPointOffset, |
|
248 nsresult (*aComparator)(nsINode*,int32_t,nsRange*,int32_t*), |
|
249 int32_t* aPoint); |
|
250 bool EqualsRangeAtPoint(nsINode* aBeginNode, int32_t aBeginOffset, |
|
251 nsINode* aEndNode, int32_t aEndOffset, |
|
252 int32_t aRangeIndex); |
|
253 nsresult GetIndicesForInterval(nsINode* aBeginNode, int32_t aBeginOffset, |
|
254 nsINode* aEndNode, int32_t aEndOffset, |
|
255 bool aAllowAdjacent, |
|
256 int32_t* aStartIndex, int32_t* aEndIndex); |
|
257 RangeData* FindRangeData(nsIDOMRange* aRange); |
|
258 |
|
259 // These are the ranges inside this selection. They are kept sorted in order |
|
260 // of DOM start position. |
|
261 // |
|
262 // This data structure is sorted by the range beginnings. As the ranges are |
|
263 // disjoint, it is also implicitly sorted by the range endings. This allows |
|
264 // us to perform binary searches when searching for existence of a range, |
|
265 // giving us O(log n) search time. |
|
266 // |
|
267 // Inserting a new range requires finding the overlapping interval, requiring |
|
268 // two binary searches plus up to an additional 6 DOM comparisons. If this |
|
269 // proves to be a performance concern, then an interval tree may be a |
|
270 // possible solution, allowing the calculation of the overlap interval in |
|
271 // O(log n) time, though this would require rebalancing and other overhead. |
|
272 nsTArray<RangeData> mRanges; |
|
273 |
|
274 nsRefPtr<nsRange> mAnchorFocusRange; |
|
275 nsRefPtr<nsFrameSelection> mFrameSelection; |
|
276 nsRefPtr<nsAutoScrollTimer> mAutoScrollTimer; |
|
277 nsCOMArray<nsISelectionListener> mSelectionListeners; |
|
278 nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent; |
|
279 CachedOffsetForFrame *mCachedOffsetForFrame; |
|
280 nsDirection mDirection; |
|
281 SelectionType mType; |
|
282 }; |
|
283 |
|
284 } // namespace dom |
|
285 } // namespace mozilla |
|
286 |
|
287 #endif // mozilla_Selection_h__ |