|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef __selectionstate_h__ |
|
7 #define __selectionstate_h__ |
|
8 |
|
9 #include "nsCOMPtr.h" |
|
10 #include "nsIDOMNode.h" |
|
11 #include "nsINode.h" |
|
12 #include "nsTArray.h" |
|
13 #include "nscore.h" |
|
14 |
|
15 class nsCycleCollectionTraversalCallback; |
|
16 class nsIDOMCharacterData; |
|
17 class nsIDOMRange; |
|
18 class nsISelection; |
|
19 class nsRange; |
|
20 namespace mozilla { |
|
21 namespace dom { |
|
22 class Selection; |
|
23 } |
|
24 } |
|
25 |
|
26 /*************************************************************************** |
|
27 * class for recording selection info. stores selection as collection of |
|
28 * { {startnode, startoffset} , {endnode, endoffset} } tuples. Can't store |
|
29 * ranges since dom gravity will possibly change the ranges. |
|
30 */ |
|
31 |
|
32 // first a helper struct for saving/setting ranges |
|
33 struct nsRangeStore MOZ_FINAL |
|
34 { |
|
35 nsRangeStore(); |
|
36 |
|
37 private: |
|
38 // Private destructor, to discourage deletion outside of Release(): |
|
39 ~nsRangeStore(); |
|
40 |
|
41 public: |
|
42 nsresult StoreRange(nsIDOMRange *aRange); |
|
43 nsresult GetRange(nsRange** outRange); |
|
44 |
|
45 NS_INLINE_DECL_REFCOUNTING(nsRangeStore) |
|
46 |
|
47 nsCOMPtr<nsIDOMNode> startNode; |
|
48 int32_t startOffset; |
|
49 nsCOMPtr<nsIDOMNode> endNode; |
|
50 int32_t endOffset; |
|
51 // DEBUG: static int32_t n; |
|
52 }; |
|
53 |
|
54 class nsSelectionState |
|
55 { |
|
56 public: |
|
57 |
|
58 nsSelectionState(); |
|
59 ~nsSelectionState(); |
|
60 |
|
61 void DoTraverse(nsCycleCollectionTraversalCallback &cb); |
|
62 void DoUnlink() { MakeEmpty(); } |
|
63 |
|
64 void SaveSelection(mozilla::dom::Selection *aSel); |
|
65 nsresult RestoreSelection(nsISelection *aSel); |
|
66 bool IsCollapsed(); |
|
67 bool IsEqual(nsSelectionState *aSelState); |
|
68 void MakeEmpty(); |
|
69 bool IsEmpty(); |
|
70 protected: |
|
71 nsTArray<nsRefPtr<nsRangeStore> > mArray; |
|
72 |
|
73 friend class nsRangeUpdater; |
|
74 }; |
|
75 |
|
76 class nsRangeUpdater |
|
77 { |
|
78 public: |
|
79 |
|
80 nsRangeUpdater(); |
|
81 ~nsRangeUpdater(); |
|
82 |
|
83 void RegisterRangeItem(nsRangeStore *aRangeItem); |
|
84 void DropRangeItem(nsRangeStore *aRangeItem); |
|
85 nsresult RegisterSelectionState(nsSelectionState &aSelState); |
|
86 nsresult DropSelectionState(nsSelectionState &aSelState); |
|
87 |
|
88 // editor selection gravity routines. Note that we can't always depend on |
|
89 // DOM Range gravity to do what we want to the "real" selection. For instance, |
|
90 // if you move a node, that corresponds to deleting it and reinserting it. |
|
91 // DOM Range gravity will promote the selection out of the node on deletion, |
|
92 // which is not what you want if you know you are reinserting it. |
|
93 nsresult SelAdjCreateNode(nsIDOMNode *aParent, int32_t aPosition); |
|
94 nsresult SelAdjInsertNode(nsIDOMNode *aParent, int32_t aPosition); |
|
95 void SelAdjDeleteNode(nsIDOMNode *aNode); |
|
96 nsresult SelAdjSplitNode(nsIDOMNode *aOldRightNode, int32_t aOffset, nsIDOMNode *aNewLeftNode); |
|
97 nsresult SelAdjJoinNodes(nsIDOMNode *aLeftNode, |
|
98 nsIDOMNode *aRightNode, |
|
99 nsIDOMNode *aParent, |
|
100 int32_t aOffset, |
|
101 int32_t aOldLeftNodeLength); |
|
102 nsresult SelAdjInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, const nsAString &aString); |
|
103 nsresult SelAdjDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength); |
|
104 // the following gravity routines need will/did sandwiches, because the other gravity |
|
105 // routines will be called inside of these sandwiches, but should be ignored. |
|
106 nsresult WillReplaceContainer(); |
|
107 nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode); |
|
108 nsresult WillRemoveContainer(); |
|
109 nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aOffset, uint32_t aNodeOrigLen); |
|
110 nsresult WillInsertContainer(); |
|
111 nsresult DidInsertContainer(); |
|
112 void WillMoveNode(); |
|
113 void DidMoveNode(nsINode* aOldParent, int32_t aOldOffset, |
|
114 nsINode* aNewParent, int32_t aNewOffset); |
|
115 protected: |
|
116 nsTArray<nsRefPtr<nsRangeStore> > mArray; |
|
117 bool mLock; |
|
118 }; |
|
119 |
|
120 |
|
121 /*************************************************************************** |
|
122 * helper class for using nsSelectionState. stack based class for doing |
|
123 * preservation of dom points across editor actions |
|
124 */ |
|
125 |
|
126 class MOZ_STACK_CLASS nsAutoTrackDOMPoint |
|
127 { |
|
128 private: |
|
129 nsRangeUpdater &mRU; |
|
130 nsCOMPtr<nsIDOMNode> *mNode; |
|
131 int32_t *mOffset; |
|
132 nsRefPtr<nsRangeStore> mRangeItem; |
|
133 public: |
|
134 nsAutoTrackDOMPoint(nsRangeUpdater &aRangeUpdater, nsCOMPtr<nsIDOMNode> *aNode, int32_t *aOffset) : |
|
135 mRU(aRangeUpdater) |
|
136 ,mNode(aNode) |
|
137 ,mOffset(aOffset) |
|
138 { |
|
139 mRangeItem = new nsRangeStore(); |
|
140 mRangeItem->startNode = *mNode; |
|
141 mRangeItem->endNode = *mNode; |
|
142 mRangeItem->startOffset = *mOffset; |
|
143 mRangeItem->endOffset = *mOffset; |
|
144 mRU.RegisterRangeItem(mRangeItem); |
|
145 } |
|
146 |
|
147 ~nsAutoTrackDOMPoint() |
|
148 { |
|
149 mRU.DropRangeItem(mRangeItem); |
|
150 *mNode = mRangeItem->startNode; |
|
151 *mOffset = mRangeItem->startOffset; |
|
152 } |
|
153 }; |
|
154 |
|
155 |
|
156 |
|
157 /*************************************************************************** |
|
158 * another helper class for nsSelectionState. stack based class for doing |
|
159 * Will/DidReplaceContainer() |
|
160 */ |
|
161 |
|
162 class MOZ_STACK_CLASS nsAutoReplaceContainerSelNotify |
|
163 { |
|
164 private: |
|
165 nsRangeUpdater &mRU; |
|
166 nsIDOMNode *mOriginalNode; |
|
167 nsIDOMNode *mNewNode; |
|
168 |
|
169 public: |
|
170 nsAutoReplaceContainerSelNotify(nsRangeUpdater &aRangeUpdater, nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode) : |
|
171 mRU(aRangeUpdater) |
|
172 ,mOriginalNode(aOriginalNode) |
|
173 ,mNewNode(aNewNode) |
|
174 { |
|
175 mRU.WillReplaceContainer(); |
|
176 } |
|
177 |
|
178 ~nsAutoReplaceContainerSelNotify() |
|
179 { |
|
180 mRU.DidReplaceContainer(mOriginalNode, mNewNode); |
|
181 } |
|
182 }; |
|
183 |
|
184 |
|
185 /*************************************************************************** |
|
186 * another helper class for nsSelectionState. stack based class for doing |
|
187 * Will/DidRemoveContainer() |
|
188 */ |
|
189 |
|
190 class MOZ_STACK_CLASS nsAutoRemoveContainerSelNotify |
|
191 { |
|
192 private: |
|
193 nsRangeUpdater &mRU; |
|
194 nsIDOMNode *mNode; |
|
195 nsIDOMNode *mParent; |
|
196 int32_t mOffset; |
|
197 uint32_t mNodeOrigLen; |
|
198 |
|
199 public: |
|
200 nsAutoRemoveContainerSelNotify(nsRangeUpdater& aRangeUpdater, |
|
201 nsINode* aNode, |
|
202 nsINode* aParent, |
|
203 int32_t aOffset, |
|
204 uint32_t aNodeOrigLen) |
|
205 : mRU(aRangeUpdater) |
|
206 , mNode(aNode->AsDOMNode()) |
|
207 , mParent(aParent->AsDOMNode()) |
|
208 , mOffset(aOffset) |
|
209 , mNodeOrigLen(aNodeOrigLen) |
|
210 { |
|
211 mRU.WillRemoveContainer(); |
|
212 } |
|
213 |
|
214 ~nsAutoRemoveContainerSelNotify() |
|
215 { |
|
216 mRU.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen); |
|
217 } |
|
218 }; |
|
219 |
|
220 /*************************************************************************** |
|
221 * another helper class for nsSelectionState. stack based class for doing |
|
222 * Will/DidInsertContainer() |
|
223 */ |
|
224 |
|
225 class MOZ_STACK_CLASS nsAutoInsertContainerSelNotify |
|
226 { |
|
227 private: |
|
228 nsRangeUpdater &mRU; |
|
229 |
|
230 public: |
|
231 nsAutoInsertContainerSelNotify(nsRangeUpdater &aRangeUpdater) : |
|
232 mRU(aRangeUpdater) |
|
233 { |
|
234 mRU.WillInsertContainer(); |
|
235 } |
|
236 |
|
237 ~nsAutoInsertContainerSelNotify() |
|
238 { |
|
239 mRU.DidInsertContainer(); |
|
240 } |
|
241 }; |
|
242 |
|
243 |
|
244 /*************************************************************************** |
|
245 * another helper class for nsSelectionState. stack based class for doing |
|
246 * Will/DidMoveNode() |
|
247 */ |
|
248 |
|
249 class MOZ_STACK_CLASS nsAutoMoveNodeSelNotify |
|
250 { |
|
251 private: |
|
252 nsRangeUpdater &mRU; |
|
253 nsINode* mOldParent; |
|
254 nsINode* mNewParent; |
|
255 int32_t mOldOffset; |
|
256 int32_t mNewOffset; |
|
257 |
|
258 public: |
|
259 nsAutoMoveNodeSelNotify(nsRangeUpdater &aRangeUpdater, |
|
260 nsINode* aOldParent, |
|
261 int32_t aOldOffset, |
|
262 nsINode* aNewParent, |
|
263 int32_t aNewOffset) |
|
264 : mRU(aRangeUpdater) |
|
265 , mOldParent(aOldParent) |
|
266 , mNewParent(aNewParent) |
|
267 , mOldOffset(aOldOffset) |
|
268 , mNewOffset(aNewOffset) |
|
269 { |
|
270 MOZ_ASSERT(aOldParent); |
|
271 MOZ_ASSERT(aNewParent); |
|
272 mRU.WillMoveNode(); |
|
273 } |
|
274 |
|
275 ~nsAutoMoveNodeSelNotify() |
|
276 { |
|
277 mRU.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset); |
|
278 } |
|
279 }; |
|
280 |
|
281 #endif |
|
282 |
|
283 |