/src/mozilla-central/editor/libeditor/SelectionState.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "mozilla/SelectionState.h" |
7 | | |
8 | | #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc. |
9 | | #include "mozilla/EditorUtils.h" // for EditorUtils |
10 | | #include "mozilla/dom/RangeBinding.h" |
11 | | #include "mozilla/dom/Selection.h" // for Selection |
12 | | #include "nsAString.h" // for nsAString::Length |
13 | | #include "nsCycleCollectionParticipant.h" |
14 | | #include "nsDebug.h" // for NS_ENSURE_TRUE, etc. |
15 | | #include "nsError.h" // for NS_OK, etc. |
16 | | #include "nsIContent.h" // for nsIContent |
17 | | #include "nsISupportsImpl.h" // for nsRange::Release |
18 | | #include "nsRange.h" // for nsRange |
19 | | |
20 | | namespace mozilla { |
21 | | |
22 | | using namespace dom; |
23 | | |
24 | | /****************************************************************************** |
25 | | * mozilla::SelectionState |
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 | | template nsresult |
33 | | RangeUpdater::SelAdjCreateNode(const EditorDOMPoint& aPoint); |
34 | | template nsresult |
35 | | RangeUpdater::SelAdjCreateNode(const EditorRawDOMPoint& aPoint); |
36 | | template nsresult |
37 | | RangeUpdater::SelAdjInsertNode(const EditorDOMPoint& aPoint); |
38 | | template nsresult |
39 | | RangeUpdater::SelAdjInsertNode(const EditorRawDOMPoint& aPoint); |
40 | | |
41 | | SelectionState::SelectionState() |
42 | | : mDirection(eDirNext) |
43 | 0 | { |
44 | 0 | } |
45 | | |
46 | | SelectionState::~SelectionState() |
47 | 0 | { |
48 | 0 | MakeEmpty(); |
49 | 0 | } |
50 | | |
51 | | void |
52 | | SelectionState::SaveSelection(Selection* aSel) |
53 | 0 | { |
54 | 0 | MOZ_ASSERT(aSel); |
55 | 0 | int32_t arrayCount = mArray.Length(); |
56 | 0 | int32_t rangeCount = aSel->RangeCount(); |
57 | 0 |
|
58 | 0 | // if we need more items in the array, new them |
59 | 0 | if (arrayCount < rangeCount) { |
60 | 0 | for (int32_t i = arrayCount; i < rangeCount; i++) { |
61 | 0 | mArray.AppendElement(); |
62 | 0 | mArray[i] = new RangeItem(); |
63 | 0 | } |
64 | 0 | } else if (arrayCount > rangeCount) { |
65 | 0 | // else if we have too many, delete them |
66 | 0 | for (int32_t i = arrayCount - 1; i >= rangeCount; i--) { |
67 | 0 | mArray.RemoveElementAt(i); |
68 | 0 | } |
69 | 0 | } |
70 | 0 |
|
71 | 0 | // now store the selection ranges |
72 | 0 | for (int32_t i = 0; i < rangeCount; i++) { |
73 | 0 | mArray[i]->StoreRange(aSel->GetRangeAt(i)); |
74 | 0 | } |
75 | 0 |
|
76 | 0 | mDirection = aSel->GetDirection(); |
77 | 0 | } |
78 | | |
79 | | nsresult |
80 | | SelectionState::RestoreSelection(Selection* aSel) |
81 | 0 | { |
82 | 0 | NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER); |
83 | 0 |
|
84 | 0 | // clear out selection |
85 | 0 | aSel->RemoveAllRanges(IgnoreErrors()); |
86 | 0 |
|
87 | 0 | aSel->SetDirection(mDirection); |
88 | 0 |
|
89 | 0 | // set the selection ranges anew |
90 | 0 | size_t arrayCount = mArray.Length(); |
91 | 0 | for (size_t i = 0; i < arrayCount; i++) { |
92 | 0 | RefPtr<nsRange> range = mArray[i]->GetRange(); |
93 | 0 | NS_ENSURE_TRUE(range, NS_ERROR_UNEXPECTED); |
94 | 0 |
|
95 | 0 | ErrorResult rv; |
96 | 0 | aSel->AddRange(*range, rv); |
97 | 0 | if (rv.Failed()) { |
98 | 0 | return rv.StealNSResult(); |
99 | 0 | } |
100 | 0 | } |
101 | 0 | return NS_OK; |
102 | 0 | } |
103 | | |
104 | | bool |
105 | | SelectionState::IsCollapsed() |
106 | 0 | { |
107 | 0 | if (mArray.Length() != 1) { |
108 | 0 | return false; |
109 | 0 | } |
110 | 0 | RefPtr<nsRange> range = mArray[0]->GetRange(); |
111 | 0 | NS_ENSURE_TRUE(range, false); |
112 | 0 | return range->Collapsed(); |
113 | 0 | } |
114 | | |
115 | | bool |
116 | | SelectionState::IsEqual(SelectionState* aSelState) |
117 | 0 | { |
118 | 0 | NS_ENSURE_TRUE(aSelState, false); |
119 | 0 | size_t myCount = mArray.Length(), itsCount = aSelState->mArray.Length(); |
120 | 0 | if (myCount != itsCount) { |
121 | 0 | return false; |
122 | 0 | } |
123 | 0 | if (!myCount) { |
124 | 0 | return false; |
125 | 0 | } |
126 | 0 | if (mDirection != aSelState->mDirection) { |
127 | 0 | return false; |
128 | 0 | } |
129 | 0 | |
130 | 0 | for (size_t i = 0; i < myCount; i++) { |
131 | 0 | RefPtr<nsRange> myRange = mArray[i]->GetRange(); |
132 | 0 | RefPtr<nsRange> itsRange = aSelState->mArray[i]->GetRange(); |
133 | 0 | NS_ENSURE_TRUE(myRange && itsRange, false); |
134 | 0 |
|
135 | 0 | IgnoredErrorResult rv; |
136 | 0 | int16_t compResult = |
137 | 0 | myRange->CompareBoundaryPoints(Range_Binding::START_TO_START, *itsRange, rv); |
138 | 0 | if (rv.Failed() || compResult) { |
139 | 0 | return false; |
140 | 0 | } |
141 | 0 | compResult = |
142 | 0 | myRange->CompareBoundaryPoints(Range_Binding::END_TO_END, *itsRange, rv); |
143 | 0 | if (rv.Failed() || compResult) { |
144 | 0 | return false; |
145 | 0 | } |
146 | 0 | } |
147 | 0 | // if we got here, they are equal |
148 | 0 | return true; |
149 | 0 | } |
150 | | |
151 | | void |
152 | | SelectionState::MakeEmpty() |
153 | 0 | { |
154 | 0 | // free any items in the array |
155 | 0 | mArray.Clear(); |
156 | 0 | mDirection = eDirNext; |
157 | 0 | } |
158 | | |
159 | | bool |
160 | | SelectionState::IsEmpty() |
161 | 0 | { |
162 | 0 | return mArray.IsEmpty(); |
163 | 0 | } |
164 | | |
165 | | /****************************************************************************** |
166 | | * mozilla::RangeUpdater |
167 | | * |
168 | | * Class for updating nsRanges in response to editor actions. |
169 | | ******************************************************************************/ |
170 | | |
171 | | RangeUpdater::RangeUpdater() |
172 | | : mLock(false) |
173 | 0 | { |
174 | 0 | } |
175 | | |
176 | | RangeUpdater::~RangeUpdater() |
177 | 0 | { |
178 | 0 | // nothing to do, we don't own the items in our array. |
179 | 0 | } |
180 | | |
181 | | void |
182 | | RangeUpdater::RegisterRangeItem(RangeItem* aRangeItem) |
183 | 0 | { |
184 | 0 | if (!aRangeItem) { |
185 | 0 | return; |
186 | 0 | } |
187 | 0 | if (mArray.Contains(aRangeItem)) { |
188 | 0 | NS_ERROR("tried to register an already registered range"); |
189 | 0 | return; // don't register it again. It would get doubly adjusted. |
190 | 0 | } |
191 | 0 | mArray.AppendElement(aRangeItem); |
192 | 0 | } |
193 | | |
194 | | void |
195 | | RangeUpdater::DropRangeItem(RangeItem* aRangeItem) |
196 | 0 | { |
197 | 0 | if (!aRangeItem) { |
198 | 0 | return; |
199 | 0 | } |
200 | 0 | mArray.RemoveElement(aRangeItem); |
201 | 0 | } |
202 | | |
203 | | nsresult |
204 | | RangeUpdater::RegisterSelectionState(SelectionState& aSelState) |
205 | 0 | { |
206 | 0 | size_t theCount = aSelState.mArray.Length(); |
207 | 0 | if (theCount < 1) { |
208 | 0 | return NS_ERROR_FAILURE; |
209 | 0 | } |
210 | 0 | |
211 | 0 | for (size_t i = 0; i < theCount; i++) { |
212 | 0 | RegisterRangeItem(aSelState.mArray[i]); |
213 | 0 | } |
214 | 0 |
|
215 | 0 | return NS_OK; |
216 | 0 | } |
217 | | |
218 | | nsresult |
219 | | RangeUpdater::DropSelectionState(SelectionState& aSelState) |
220 | 0 | { |
221 | 0 | size_t theCount = aSelState.mArray.Length(); |
222 | 0 | if (theCount < 1) { |
223 | 0 | return NS_ERROR_FAILURE; |
224 | 0 | } |
225 | 0 | |
226 | 0 | for (size_t i = 0; i < theCount; i++) { |
227 | 0 | DropRangeItem(aSelState.mArray[i]); |
228 | 0 | } |
229 | 0 |
|
230 | 0 | return NS_OK; |
231 | 0 | } |
232 | | |
233 | | // gravity methods: |
234 | | |
235 | | template<typename PT, typename CT> |
236 | | nsresult |
237 | | RangeUpdater::SelAdjCreateNode(const EditorDOMPointBase<PT, CT>& aPoint) |
238 | 0 | { |
239 | 0 | if (mLock) { |
240 | 0 | // lock set by Will/DidReplaceParent, etc... |
241 | 0 | return NS_OK; |
242 | 0 | } |
243 | 0 | size_t count = mArray.Length(); |
244 | 0 | if (!count) { |
245 | 0 | return NS_OK; |
246 | 0 | } |
247 | 0 | |
248 | 0 | if (NS_WARN_IF(!aPoint.IsSetAndValid())) { |
249 | 0 | return NS_ERROR_FAILURE; |
250 | 0 | } |
251 | 0 | |
252 | 0 | for (size_t i = 0; i < count; i++) { |
253 | 0 | RangeItem* item = mArray[i]; |
254 | 0 | NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER); |
255 | 0 |
|
256 | 0 | if (item->mStartContainer == aPoint.GetContainer() && |
257 | 0 | item->mStartOffset > static_cast<int32_t>(aPoint.Offset())) { |
258 | 0 | item->mStartOffset++; |
259 | 0 | } |
260 | 0 | if (item->mEndContainer == aPoint.GetContainer() && |
261 | 0 | item->mEndOffset > static_cast<int32_t>(aPoint.Offset())) { |
262 | 0 | item->mEndOffset++; |
263 | 0 | } |
264 | 0 | } |
265 | 0 | return NS_OK; |
266 | 0 | } Unexecuted instantiation: nsresult mozilla::RangeUpdater::SelAdjCreateNode<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&) Unexecuted instantiation: nsresult mozilla::RangeUpdater::SelAdjCreateNode<nsINode*, nsIContent*>(mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&) |
267 | | |
268 | | template<typename PT, typename CT> |
269 | | nsresult |
270 | | RangeUpdater::SelAdjInsertNode(const EditorDOMPointBase<PT, CT>& aPoint) |
271 | 0 | { |
272 | 0 | return SelAdjCreateNode(aPoint); |
273 | 0 | } Unexecuted instantiation: nsresult mozilla::RangeUpdater::SelAdjInsertNode<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&) Unexecuted instantiation: nsresult mozilla::RangeUpdater::SelAdjInsertNode<nsINode*, nsIContent*>(mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&) |
274 | | |
275 | | void |
276 | | RangeUpdater::SelAdjDeleteNode(nsINode* aNode) |
277 | 0 | { |
278 | 0 | if (mLock) { |
279 | 0 | // lock set by Will/DidReplaceParent, etc... |
280 | 0 | return; |
281 | 0 | } |
282 | 0 | MOZ_ASSERT(aNode); |
283 | 0 | size_t count = mArray.Length(); |
284 | 0 | if (!count) { |
285 | 0 | return; |
286 | 0 | } |
287 | 0 | |
288 | 0 | nsCOMPtr<nsINode> parent = aNode->GetParentNode(); |
289 | 0 | int32_t offset = parent ? parent->ComputeIndexOf(aNode) : -1; |
290 | 0 |
|
291 | 0 | // check for range endpoints that are after aNode and in the same parent |
292 | 0 | for (size_t i = 0; i < count; i++) { |
293 | 0 | RangeItem* item = mArray[i]; |
294 | 0 | MOZ_ASSERT(item); |
295 | 0 |
|
296 | 0 | if (item->mStartContainer == parent && item->mStartOffset > offset) { |
297 | 0 | item->mStartOffset--; |
298 | 0 | } |
299 | 0 | if (item->mEndContainer == parent && item->mEndOffset > offset) { |
300 | 0 | item->mEndOffset--; |
301 | 0 | } |
302 | 0 |
|
303 | 0 | // check for range endpoints that are in aNode |
304 | 0 | if (item->mStartContainer == aNode) { |
305 | 0 | item->mStartContainer = parent; |
306 | 0 | item->mStartOffset = offset; |
307 | 0 | } |
308 | 0 | if (item->mEndContainer == aNode) { |
309 | 0 | item->mEndContainer = parent; |
310 | 0 | item->mEndOffset = offset; |
311 | 0 | } |
312 | 0 |
|
313 | 0 | // check for range endpoints that are in descendants of aNode |
314 | 0 | nsCOMPtr<nsINode> oldStart; |
315 | 0 | if (EditorUtils::IsDescendantOf(*item->mStartContainer, *aNode)) { |
316 | 0 | oldStart = item->mStartContainer; // save for efficiency hack below. |
317 | 0 | item->mStartContainer = parent; |
318 | 0 | item->mStartOffset = offset; |
319 | 0 | } |
320 | 0 |
|
321 | 0 | // avoid having to call IsDescendantOf() for common case of range startnode == range endnode. |
322 | 0 | if (item->mEndContainer == oldStart || |
323 | 0 | EditorUtils::IsDescendantOf(*item->mEndContainer, *aNode)) { |
324 | 0 | item->mEndContainer = parent; |
325 | 0 | item->mEndOffset = offset; |
326 | 0 | } |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | | nsresult |
331 | | RangeUpdater::SelAdjSplitNode(nsIContent& aRightNode, |
332 | | nsIContent* aNewLeftNode) |
333 | 0 | { |
334 | 0 | if (mLock) { |
335 | 0 | // lock set by Will/DidReplaceParent, etc... |
336 | 0 | return NS_OK; |
337 | 0 | } |
338 | 0 | if (NS_WARN_IF(!aNewLeftNode)) { |
339 | 0 | return NS_ERROR_FAILURE; |
340 | 0 | } |
341 | 0 | |
342 | 0 | size_t count = mArray.Length(); |
343 | 0 | if (!count) { |
344 | 0 | return NS_OK; |
345 | 0 | } |
346 | 0 | |
347 | 0 | EditorRawDOMPoint atLeftNode(aNewLeftNode); |
348 | 0 | nsresult rv = SelAdjInsertNode(atLeftNode); |
349 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
350 | 0 | return rv; |
351 | 0 | } |
352 | 0 | |
353 | 0 | // If point in the ranges is in left node, change its container to the left |
354 | 0 | // node. If point in the ranges is in right node, subtract numbers of |
355 | 0 | // children moved to left node from the offset. |
356 | 0 | int32_t lengthOfLeftNode = aNewLeftNode->Length(); |
357 | 0 | for (RefPtr<RangeItem>& item : mArray) { |
358 | 0 | if (NS_WARN_IF(!item)) { |
359 | 0 | return NS_ERROR_FAILURE; |
360 | 0 | } |
361 | 0 | |
362 | 0 | if (item->mStartContainer == &aRightNode) { |
363 | 0 | if (item->mStartOffset > lengthOfLeftNode) { |
364 | 0 | item->mStartOffset -= lengthOfLeftNode; |
365 | 0 | } else { |
366 | 0 | item->mStartContainer = aNewLeftNode; |
367 | 0 | } |
368 | 0 | } |
369 | 0 | if (item->mEndContainer == &aRightNode) { |
370 | 0 | if (item->mEndOffset > lengthOfLeftNode) { |
371 | 0 | item->mEndOffset -= lengthOfLeftNode; |
372 | 0 | } else { |
373 | 0 | item->mEndContainer = aNewLeftNode; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | } |
377 | 0 | return NS_OK; |
378 | 0 | } |
379 | | |
380 | | nsresult |
381 | | RangeUpdater::SelAdjJoinNodes(nsINode& aLeftNode, |
382 | | nsINode& aRightNode, |
383 | | nsINode& aParent, |
384 | | int32_t aOffset, |
385 | | int32_t aOldLeftNodeLength) |
386 | 0 | { |
387 | 0 | if (mLock) { |
388 | 0 | // lock set by Will/DidReplaceParent, etc... |
389 | 0 | return NS_OK; |
390 | 0 | } |
391 | 0 | size_t count = mArray.Length(); |
392 | 0 | if (!count) { |
393 | 0 | return NS_OK; |
394 | 0 | } |
395 | 0 | |
396 | 0 | for (size_t i = 0; i < count; i++) { |
397 | 0 | RangeItem* item = mArray[i]; |
398 | 0 | NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER); |
399 | 0 |
|
400 | 0 | if (item->mStartContainer == &aParent) { |
401 | 0 | // adjust start point in aParent |
402 | 0 | if (item->mStartOffset > aOffset) { |
403 | 0 | item->mStartOffset--; |
404 | 0 | } else if (item->mStartOffset == aOffset) { |
405 | 0 | // join keeps right hand node |
406 | 0 | item->mStartContainer = &aRightNode; |
407 | 0 | item->mStartOffset = aOldLeftNodeLength; |
408 | 0 | } |
409 | 0 | } else if (item->mStartContainer == &aRightNode) { |
410 | 0 | // adjust start point in aRightNode |
411 | 0 | item->mStartOffset += aOldLeftNodeLength; |
412 | 0 | } else if (item->mStartContainer == &aLeftNode) { |
413 | 0 | // adjust start point in aLeftNode |
414 | 0 | item->mStartContainer = &aRightNode; |
415 | 0 | } |
416 | 0 |
|
417 | 0 | if (item->mEndContainer == &aParent) { |
418 | 0 | // adjust end point in aParent |
419 | 0 | if (item->mEndOffset > aOffset) { |
420 | 0 | item->mEndOffset--; |
421 | 0 | } else if (item->mEndOffset == aOffset) { |
422 | 0 | // join keeps right hand node |
423 | 0 | item->mEndContainer = &aRightNode; |
424 | 0 | item->mEndOffset = aOldLeftNodeLength; |
425 | 0 | } |
426 | 0 | } else if (item->mEndContainer == &aRightNode) { |
427 | 0 | // adjust end point in aRightNode |
428 | 0 | item->mEndOffset += aOldLeftNodeLength; |
429 | 0 | } else if (item->mEndContainer == &aLeftNode) { |
430 | 0 | // adjust end point in aLeftNode |
431 | 0 | item->mEndContainer = &aRightNode; |
432 | 0 | } |
433 | 0 | } |
434 | 0 |
|
435 | 0 | return NS_OK; |
436 | 0 | } |
437 | | |
438 | | void |
439 | | RangeUpdater::SelAdjInsertText(Text& aTextNode, |
440 | | int32_t aOffset, |
441 | | const nsAString& aString) |
442 | 0 | { |
443 | 0 | if (mLock) { |
444 | 0 | // lock set by Will/DidReplaceParent, etc... |
445 | 0 | return; |
446 | 0 | } |
447 | 0 | |
448 | 0 | size_t count = mArray.Length(); |
449 | 0 | if (!count) { |
450 | 0 | return; |
451 | 0 | } |
452 | 0 | |
453 | 0 | size_t len = aString.Length(); |
454 | 0 | for (size_t i = 0; i < count; i++) { |
455 | 0 | RangeItem* item = mArray[i]; |
456 | 0 | MOZ_ASSERT(item); |
457 | 0 |
|
458 | 0 | if (item->mStartContainer == &aTextNode && item->mStartOffset > aOffset) { |
459 | 0 | item->mStartOffset += len; |
460 | 0 | } |
461 | 0 | if (item->mEndContainer == &aTextNode && item->mEndOffset > aOffset) { |
462 | 0 | item->mEndOffset += len; |
463 | 0 | } |
464 | 0 | } |
465 | 0 | } |
466 | | |
467 | | nsresult |
468 | | RangeUpdater::SelAdjDeleteText(nsIContent* aTextNode, |
469 | | int32_t aOffset, |
470 | | int32_t aLength) |
471 | 0 | { |
472 | 0 | if (mLock) { |
473 | 0 | // lock set by Will/DidReplaceParent, etc... |
474 | 0 | return NS_OK; |
475 | 0 | } |
476 | 0 | |
477 | 0 | size_t count = mArray.Length(); |
478 | 0 | if (!count) { |
479 | 0 | return NS_OK; |
480 | 0 | } |
481 | 0 | NS_ENSURE_TRUE(aTextNode, NS_ERROR_NULL_POINTER); |
482 | 0 |
|
483 | 0 | for (size_t i = 0; i < count; i++) { |
484 | 0 | RangeItem* item = mArray[i]; |
485 | 0 | NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER); |
486 | 0 |
|
487 | 0 | if (item->mStartContainer == aTextNode && item->mStartOffset > aOffset) { |
488 | 0 | item->mStartOffset -= aLength; |
489 | 0 | if (item->mStartOffset < 0) { |
490 | 0 | item->mStartOffset = 0; |
491 | 0 | } |
492 | 0 | } |
493 | 0 | if (item->mEndContainer == aTextNode && item->mEndOffset > aOffset) { |
494 | 0 | item->mEndOffset -= aLength; |
495 | 0 | if (item->mEndOffset < 0) { |
496 | 0 | item->mEndOffset = 0; |
497 | 0 | } |
498 | 0 | } |
499 | 0 | } |
500 | 0 | return NS_OK; |
501 | 0 | } |
502 | | |
503 | | nsresult |
504 | | RangeUpdater::WillReplaceContainer() |
505 | 0 | { |
506 | 0 | if (mLock) { |
507 | 0 | return NS_ERROR_UNEXPECTED; |
508 | 0 | } |
509 | 0 | mLock = true; |
510 | 0 | return NS_OK; |
511 | 0 | } |
512 | | |
513 | | nsresult |
514 | | RangeUpdater::DidReplaceContainer(Element* aOriginalNode, |
515 | | Element* aNewNode) |
516 | 0 | { |
517 | 0 | NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED); |
518 | 0 | mLock = false; |
519 | 0 |
|
520 | 0 | NS_ENSURE_TRUE(aOriginalNode && aNewNode, NS_ERROR_NULL_POINTER); |
521 | 0 | size_t count = mArray.Length(); |
522 | 0 | if (!count) { |
523 | 0 | return NS_OK; |
524 | 0 | } |
525 | 0 | |
526 | 0 | for (size_t i = 0; i < count; i++) { |
527 | 0 | RangeItem* item = mArray[i]; |
528 | 0 | NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER); |
529 | 0 |
|
530 | 0 | if (item->mStartContainer == aOriginalNode) { |
531 | 0 | item->mStartContainer = aNewNode; |
532 | 0 | } |
533 | 0 | if (item->mEndContainer == aOriginalNode) { |
534 | 0 | item->mEndContainer = aNewNode; |
535 | 0 | } |
536 | 0 | } |
537 | 0 | return NS_OK; |
538 | 0 | } |
539 | | |
540 | | nsresult |
541 | | RangeUpdater::WillRemoveContainer() |
542 | 0 | { |
543 | 0 | if (mLock) { |
544 | 0 | return NS_ERROR_UNEXPECTED; |
545 | 0 | } |
546 | 0 | mLock = true; |
547 | 0 | return NS_OK; |
548 | 0 | } |
549 | | |
550 | | nsresult |
551 | | RangeUpdater::DidRemoveContainer(nsINode* aNode, |
552 | | nsINode* aParent, |
553 | | int32_t aOffset, |
554 | | uint32_t aNodeOrigLen) |
555 | 0 | { |
556 | 0 | NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED); |
557 | 0 | mLock = false; |
558 | 0 |
|
559 | 0 | NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER); |
560 | 0 | size_t count = mArray.Length(); |
561 | 0 | if (!count) { |
562 | 0 | return NS_OK; |
563 | 0 | } |
564 | 0 | |
565 | 0 | for (size_t i = 0; i < count; i++) { |
566 | 0 | RangeItem* item = mArray[i]; |
567 | 0 | NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER); |
568 | 0 |
|
569 | 0 | if (item->mStartContainer == aNode) { |
570 | 0 | item->mStartContainer = aParent; |
571 | 0 | item->mStartOffset += aOffset; |
572 | 0 | } else if (item->mStartContainer == aParent && |
573 | 0 | item->mStartOffset > aOffset) { |
574 | 0 | item->mStartOffset += (int32_t)aNodeOrigLen - 1; |
575 | 0 | } |
576 | 0 |
|
577 | 0 | if (item->mEndContainer == aNode) { |
578 | 0 | item->mEndContainer = aParent; |
579 | 0 | item->mEndOffset += aOffset; |
580 | 0 | } else if (item->mEndContainer == aParent && item->mEndOffset > aOffset) { |
581 | 0 | item->mEndOffset += (int32_t)aNodeOrigLen - 1; |
582 | 0 | } |
583 | 0 | } |
584 | 0 | return NS_OK; |
585 | 0 | } |
586 | | |
587 | | nsresult |
588 | | RangeUpdater::WillInsertContainer() |
589 | 0 | { |
590 | 0 | if (mLock) { |
591 | 0 | return NS_ERROR_UNEXPECTED; |
592 | 0 | } |
593 | 0 | mLock = true; |
594 | 0 | return NS_OK; |
595 | 0 | } |
596 | | |
597 | | nsresult |
598 | | RangeUpdater::DidInsertContainer() |
599 | 0 | { |
600 | 0 | NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED); |
601 | 0 | mLock = false; |
602 | 0 | return NS_OK; |
603 | 0 | } |
604 | | |
605 | | void |
606 | | RangeUpdater::WillMoveNode() |
607 | 0 | { |
608 | 0 | mLock = true; |
609 | 0 | } |
610 | | |
611 | | void |
612 | | RangeUpdater::DidMoveNode(nsINode* aOldParent, int32_t aOldOffset, |
613 | | nsINode* aNewParent, int32_t aNewOffset) |
614 | 0 | { |
615 | 0 | MOZ_ASSERT(aOldParent); |
616 | 0 | MOZ_ASSERT(aNewParent); |
617 | 0 | NS_ENSURE_TRUE_VOID(mLock); |
618 | 0 | mLock = false; |
619 | 0 |
|
620 | 0 | for (size_t i = 0, count = mArray.Length(); i < count; ++i) { |
621 | 0 | RangeItem* item = mArray[i]; |
622 | 0 | NS_ENSURE_TRUE_VOID(item); |
623 | 0 |
|
624 | 0 | // like a delete in aOldParent |
625 | 0 | if (item->mStartContainer == aOldParent && |
626 | 0 | item->mStartOffset > aOldOffset) { |
627 | 0 | item->mStartOffset--; |
628 | 0 | } |
629 | 0 | if (item->mEndContainer == aOldParent && item->mEndOffset > aOldOffset) { |
630 | 0 | item->mEndOffset--; |
631 | 0 | } |
632 | 0 |
|
633 | 0 | // and like an insert in aNewParent |
634 | 0 | if (item->mStartContainer == aNewParent && |
635 | 0 | item->mStartOffset > aNewOffset) { |
636 | 0 | item->mStartOffset++; |
637 | 0 | } |
638 | 0 | if (item->mEndContainer == aNewParent && item->mEndOffset > aNewOffset) { |
639 | 0 | item->mEndOffset++; |
640 | 0 | } |
641 | 0 | } |
642 | 0 | } |
643 | | |
644 | | /****************************************************************************** |
645 | | * mozilla::RangeItem |
646 | | * |
647 | | * Helper struct for SelectionState. This stores range endpoints. |
648 | | ******************************************************************************/ |
649 | | |
650 | | RangeItem::RangeItem() |
651 | | : mStartOffset{0} |
652 | | , mEndOffset{0} |
653 | 0 | { |
654 | 0 | } |
655 | | |
656 | | RangeItem::~RangeItem() |
657 | 0 | { |
658 | 0 | } |
659 | | |
660 | | NS_IMPL_CYCLE_COLLECTION(RangeItem, mStartContainer, mEndContainer) |
661 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(RangeItem, AddRef) |
662 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(RangeItem, Release) |
663 | | |
664 | | void |
665 | | RangeItem::StoreRange(nsRange* aRange) |
666 | 0 | { |
667 | 0 | MOZ_ASSERT(aRange); |
668 | 0 | mStartContainer = aRange->GetStartContainer(); |
669 | 0 | mStartOffset = aRange->StartOffset(); |
670 | 0 | mEndContainer = aRange->GetEndContainer(); |
671 | 0 | mEndOffset = aRange->EndOffset(); |
672 | 0 | } |
673 | | |
674 | | already_AddRefed<nsRange> |
675 | | RangeItem::GetRange() |
676 | 0 | { |
677 | 0 | RefPtr<nsRange> range = new nsRange(mStartContainer); |
678 | 0 | if (NS_FAILED(range->SetStartAndEnd(mStartContainer, mStartOffset, |
679 | 0 | mEndContainer, mEndOffset))) { |
680 | 0 | return nullptr; |
681 | 0 | } |
682 | 0 | return range.forget(); |
683 | 0 | } |
684 | | |
685 | | } // namespace mozilla |