Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
7 #ifndef mozilla_Selection_h__
8 #define mozilla_Selection_h__
10 #include "nsIWeakReference.h"
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"
20 struct CachedOffsetForFrame;
21 class nsAutoScrollTimer;
22 class nsIContentIterator;
23 class nsIFrame;
24 class nsFrameSelection;
25 struct SelectionDetails;
27 namespace mozilla {
28 class ErrorResult;
29 }
31 struct RangeData
32 {
33 RangeData(nsRange* aRange)
34 : mRange(aRange)
35 {}
37 nsRefPtr<nsRange> mRange;
38 mozilla::TextRangeStyle mTextRangeStyle;
39 };
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 {
49 class Selection : public nsISelectionPrivate,
50 public nsWrapperCache,
51 public nsSupportsWeakReference
52 {
53 public:
54 Selection();
55 Selection(nsFrameSelection *aList);
56 virtual ~Selection();
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
63 nsIDocument* GetParentObject() const;
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);
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(); }
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 }
116 nsDirection GetDirection(){return mDirection;}
117 void SetDirection(nsDirection aDir){mDirection = aDir;}
118 nsresult SetAnchorFocusToRange(nsRange *aRange);
119 void ReplaceAnchorFocusRange(nsRange *aRange);
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);
128 // Note: StartAutoScrollTimer might destroy arbitrary frames etc.
129 nsresult StartAutoScrollTimer(nsIFrame *aFrame,
130 nsPoint& aPoint,
131 uint32_t aDelay);
133 nsresult StopAutoScrollTimer();
135 JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
137 // WebIDL methods
138 nsINode* GetAnchorNode();
139 uint32_t AnchorOffset();
140 nsINode* GetFocusNode();
141 uint32_t FocusOffset();
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);
148 void Extend(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
150 void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv);
151 void DeleteFromDocument(mozilla::ErrorResult& aRv);
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);
162 void Stringify(nsAString& aResult);
164 bool ContainsNode(nsINode* aNode, bool aPartlyContained, mozilla::ErrorResult& aRv);
166 void Modify(const nsAString& aAlter, const nsAString& aDirection,
167 const nsAString& aGranularity, mozilla::ErrorResult& aRv);
169 bool GetInterlinePosition(mozilla::ErrorResult& aRv);
170 void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv);
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);
182 int16_t Type() const { return mType; }
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);
190 void ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
191 int16_t aVPercent, int16_t aHPercent,
192 mozilla::ErrorResult& aRv);
194 private:
195 friend class ::nsAutoScrollTimer;
197 // Note: DoAutoScroll might destroy arbitrary frames etc.
198 nsresult DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint);
200 public:
201 SelectionType GetType(){return mType;}
202 void SetType(SelectionType aType){mType = aType;}
204 nsresult NotifySelectionListeners();
206 private:
208 class ScrollSelectionIntoViewEvent;
209 friend class ScrollSelectionIntoViewEvent;
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 };
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);
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);
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;
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 };
284 } // namespace dom
285 } // namespace mozilla
287 #endif // mozilla_Selection_h__