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