Bumping manifests a=b2g-bump
[gecko.git] / editor / txmgr / nsTransactionManager.cpp
blobd266aeef09c6606507d46a00e6ce5bc30f5c4203
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/. */
6 #include "mozilla/Assertions.h"
7 #include "mozilla/mozalloc.h"
8 #include "nsAutoPtr.h"
9 #include "nsCOMPtr.h"
10 #include "nsDebug.h"
11 #include "nsError.h"
12 #include "nsISupportsBase.h"
13 #include "nsISupportsUtils.h"
14 #include "nsITransaction.h"
15 #include "nsITransactionList.h"
16 #include "nsITransactionListener.h"
17 #include "nsIWeakReference.h"
18 #include "nsTransactionItem.h"
19 #include "nsTransactionList.h"
20 #include "nsTransactionManager.h"
21 #include "nsTransactionStack.h"
23 nsTransactionManager::nsTransactionManager(int32_t aMaxTransactionCount)
24 : mMaxTransactionCount(aMaxTransactionCount)
25 , mDoStack(nsTransactionStack::FOR_UNDO)
26 , mUndoStack(nsTransactionStack::FOR_UNDO)
27 , mRedoStack(nsTransactionStack::FOR_REDO)
31 nsTransactionManager::~nsTransactionManager()
35 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTransactionManager)
37 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTransactionManager)
38 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListeners)
39 tmp->mDoStack.DoUnlink();
40 tmp->mUndoStack.DoUnlink();
41 tmp->mRedoStack.DoUnlink();
42 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTransactionManager)
45 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListeners)
46 tmp->mDoStack.DoTraverse(cb);
47 tmp->mUndoStack.DoTraverse(cb);
48 tmp->mRedoStack.DoTraverse(cb);
49 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
51 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTransactionManager)
52 NS_INTERFACE_MAP_ENTRY(nsITransactionManager)
53 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
54 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITransactionManager)
55 NS_INTERFACE_MAP_END
57 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTransactionManager)
58 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTransactionManager)
60 NS_IMETHODIMP
61 nsTransactionManager::DoTransaction(nsITransaction *aTransaction)
63 nsresult result;
65 NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
67 bool doInterrupt = false;
69 result = WillDoNotify(aTransaction, &doInterrupt);
71 if (NS_FAILED(result)) {
72 return result;
75 if (doInterrupt) {
76 return NS_OK;
79 result = BeginTransaction(aTransaction, nullptr);
81 if (NS_FAILED(result)) {
82 DidDoNotify(aTransaction, result);
83 return result;
86 result = EndTransaction(false);
88 nsresult result2 = DidDoNotify(aTransaction, result);
90 if (NS_SUCCEEDED(result))
91 result = result2;
93 return result;
96 NS_IMETHODIMP
97 nsTransactionManager::UndoTransaction()
99 nsresult result = NS_OK;
101 // It is illegal to call UndoTransaction() while the transaction manager is
102 // executing a transaction's DoTransaction() method! If this happens,
103 // the UndoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
105 nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
107 if (tx) {
108 return NS_ERROR_FAILURE;
111 // Peek at the top of the undo stack. Don't remove the transaction
112 // until it has successfully completed.
113 tx = mUndoStack.Peek();
115 // Bail if there's nothing on the stack.
116 if (!tx) {
117 return NS_OK;
120 nsCOMPtr<nsITransaction> t = tx->GetTransaction();
122 bool doInterrupt = false;
124 result = WillUndoNotify(t, &doInterrupt);
126 if (NS_FAILED(result)) {
127 return result;
130 if (doInterrupt) {
131 return NS_OK;
134 result = tx->UndoTransaction(this);
136 if (NS_SUCCEEDED(result)) {
137 tx = mUndoStack.Pop();
138 mRedoStack.Push(tx);
141 nsresult result2 = DidUndoNotify(t, result);
143 if (NS_SUCCEEDED(result))
144 result = result2;
146 return result;
149 NS_IMETHODIMP
150 nsTransactionManager::RedoTransaction()
152 nsresult result = NS_OK;
154 // It is illegal to call RedoTransaction() while the transaction manager is
155 // executing a transaction's DoTransaction() method! If this happens,
156 // the RedoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
158 nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
160 if (tx) {
161 return NS_ERROR_FAILURE;
164 // Peek at the top of the redo stack. Don't remove the transaction
165 // until it has successfully completed.
166 tx = mRedoStack.Peek();
168 // Bail if there's nothing on the stack.
169 if (!tx) {
170 return NS_OK;
173 nsCOMPtr<nsITransaction> t = tx->GetTransaction();
175 bool doInterrupt = false;
177 result = WillRedoNotify(t, &doInterrupt);
179 if (NS_FAILED(result)) {
180 return result;
183 if (doInterrupt) {
184 return NS_OK;
187 result = tx->RedoTransaction(this);
189 if (NS_SUCCEEDED(result)) {
190 tx = mRedoStack.Pop();
191 mUndoStack.Push(tx);
194 nsresult result2 = DidRedoNotify(t, result);
196 if (NS_SUCCEEDED(result))
197 result = result2;
199 return result;
202 NS_IMETHODIMP
203 nsTransactionManager::Clear()
205 nsresult result;
207 result = ClearRedoStack();
209 if (NS_FAILED(result)) {
210 return result;
213 result = ClearUndoStack();
215 return result;
218 NS_IMETHODIMP
219 nsTransactionManager::BeginBatch(nsISupports* aData)
221 nsresult result;
223 // We can batch independent transactions together by simply pushing
224 // a dummy transaction item on the do stack. This dummy transaction item
225 // will be popped off the do stack, and then pushed on the undo stack
226 // in EndBatch().
228 bool doInterrupt = false;
230 result = WillBeginBatchNotify(&doInterrupt);
232 if (NS_FAILED(result)) {
233 return result;
236 if (doInterrupt) {
237 return NS_OK;
240 result = BeginTransaction(0, aData);
242 nsresult result2 = DidBeginBatchNotify(result);
244 if (NS_SUCCEEDED(result))
245 result = result2;
247 return result;
250 NS_IMETHODIMP
251 nsTransactionManager::EndBatch(bool aAllowEmpty)
253 nsCOMPtr<nsITransaction> ti;
254 nsresult result;
256 // XXX: Need to add some mechanism to detect the case where the transaction
257 // at the top of the do stack isn't the dummy transaction, so we can
258 // throw an error!! This can happen if someone calls EndBatch() within
259 // the DoTransaction() method of a transaction.
261 // For now, we can detect this case by checking the value of the
262 // dummy transaction's mTransaction field. If it is our dummy
263 // transaction, it should be nullptr. This may not be true in the
264 // future when we allow users to execute a transaction when beginning
265 // a batch!!!!
267 nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
269 if (tx) {
270 ti = tx->GetTransaction();
273 if (!tx || ti) {
274 return NS_ERROR_FAILURE;
277 bool doInterrupt = false;
279 result = WillEndBatchNotify(&doInterrupt);
281 if (NS_FAILED(result)) {
282 return result;
285 if (doInterrupt) {
286 return NS_OK;
289 result = EndTransaction(aAllowEmpty);
291 nsresult result2 = DidEndBatchNotify(result);
293 if (NS_SUCCEEDED(result))
294 result = result2;
296 return result;
299 NS_IMETHODIMP
300 nsTransactionManager::GetNumberOfUndoItems(int32_t *aNumItems)
302 *aNumItems = mUndoStack.GetSize();
303 return NS_OK;
306 NS_IMETHODIMP
307 nsTransactionManager::GetNumberOfRedoItems(int32_t *aNumItems)
309 *aNumItems = mRedoStack.GetSize();
310 return NS_OK;
313 NS_IMETHODIMP
314 nsTransactionManager::GetMaxTransactionCount(int32_t *aMaxCount)
316 NS_ENSURE_TRUE(aMaxCount, NS_ERROR_NULL_POINTER);
318 *aMaxCount = mMaxTransactionCount;
320 return NS_OK;
323 NS_IMETHODIMP
324 nsTransactionManager::SetMaxTransactionCount(int32_t aMaxCount)
326 int32_t numUndoItems = 0, numRedoItems = 0, total = 0;
328 // It is illegal to call SetMaxTransactionCount() while the transaction
329 // manager is executing a transaction's DoTransaction() method because
330 // the undo and redo stacks might get pruned! If this happens, the
331 // SetMaxTransactionCount() request is ignored, and we return
332 // NS_ERROR_FAILURE.
334 nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
336 if (tx) {
337 return NS_ERROR_FAILURE;
340 // If aMaxCount is less than zero, the user wants unlimited
341 // levels of undo! No need to prune the undo or redo stacks!
343 if (aMaxCount < 0) {
344 mMaxTransactionCount = -1;
345 return NS_OK;
348 numUndoItems = mUndoStack.GetSize();
350 numRedoItems = mRedoStack.GetSize();
352 total = numUndoItems + numRedoItems;
354 // If aMaxCount is greater than the number of transactions that currently
355 // exist on the undo and redo stack, there is no need to prune the
356 // undo or redo stacks!
358 if (aMaxCount > total ) {
359 mMaxTransactionCount = aMaxCount;
360 return NS_OK;
363 // Try getting rid of some transactions on the undo stack! Start at
364 // the bottom of the stack and pop towards the top.
366 while (numUndoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
367 tx = mUndoStack.PopBottom();
369 if (!tx) {
370 return NS_ERROR_FAILURE;
373 --numUndoItems;
376 // If necessary, get rid of some transactions on the redo stack! Start at
377 // the bottom of the stack and pop towards the top.
379 while (numRedoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
380 tx = mRedoStack.PopBottom();
382 if (!tx) {
383 return NS_ERROR_FAILURE;
386 --numRedoItems;
389 mMaxTransactionCount = aMaxCount;
391 return NS_OK;
394 NS_IMETHODIMP
395 nsTransactionManager::PeekUndoStack(nsITransaction **aTransaction)
397 MOZ_ASSERT(aTransaction);
398 *aTransaction = PeekUndoStack().take();
399 return NS_OK;
402 already_AddRefed<nsITransaction>
403 nsTransactionManager::PeekUndoStack()
405 nsRefPtr<nsTransactionItem> tx = mUndoStack.Peek();
407 if (!tx) {
408 return nullptr;
411 return tx->GetTransaction();
414 NS_IMETHODIMP
415 nsTransactionManager::PeekRedoStack(nsITransaction** aTransaction)
417 MOZ_ASSERT(aTransaction);
418 *aTransaction = PeekRedoStack().take();
419 return NS_OK;
422 already_AddRefed<nsITransaction>
423 nsTransactionManager::PeekRedoStack()
425 nsRefPtr<nsTransactionItem> tx = mRedoStack.Peek();
427 if (!tx) {
428 return nullptr;
431 return tx->GetTransaction();
434 NS_IMETHODIMP
435 nsTransactionManager::GetUndoList(nsITransactionList **aTransactionList)
437 NS_ENSURE_TRUE(aTransactionList, NS_ERROR_NULL_POINTER);
439 *aTransactionList = (nsITransactionList *)new nsTransactionList(this, &mUndoStack);
441 NS_IF_ADDREF(*aTransactionList);
443 return (! *aTransactionList) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
446 NS_IMETHODIMP
447 nsTransactionManager::GetRedoList(nsITransactionList **aTransactionList)
449 NS_ENSURE_TRUE(aTransactionList, NS_ERROR_NULL_POINTER);
451 *aTransactionList = (nsITransactionList *)new nsTransactionList(this, &mRedoStack);
453 NS_IF_ADDREF(*aTransactionList);
455 return (! *aTransactionList) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
458 nsresult
459 nsTransactionManager::BatchTopUndo()
461 if (mUndoStack.GetSize() < 2) {
462 // Not enough transactions to merge into one batch.
463 return NS_OK;
466 nsRefPtr<nsTransactionItem> lastUndo;
467 nsRefPtr<nsTransactionItem> previousUndo;
469 lastUndo = mUndoStack.Pop();
470 MOZ_ASSERT(lastUndo, "There should be at least two transactions.");
472 previousUndo = mUndoStack.Peek();
473 MOZ_ASSERT(previousUndo, "There should be at least two transactions.");
475 nsresult result = previousUndo->AddChild(lastUndo);
477 // Transfer data from the transactions that is going to be
478 // merged to the transaction that it is being merged with.
479 nsCOMArray<nsISupports>& lastData = lastUndo->GetData();
480 nsCOMArray<nsISupports>& previousData = previousUndo->GetData();
481 NS_ENSURE_TRUE(previousData.AppendObjects(lastData), NS_ERROR_UNEXPECTED);
482 lastData.Clear();
484 return result;
487 nsresult
488 nsTransactionManager::RemoveTopUndo()
490 nsRefPtr<nsTransactionItem> lastUndo;
492 lastUndo = mUndoStack.Peek();
493 if (!lastUndo) {
494 return NS_OK;
497 lastUndo = mUndoStack.Pop();
499 return NS_OK;
502 NS_IMETHODIMP
503 nsTransactionManager::AddListener(nsITransactionListener *aListener)
505 NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
507 return mListeners.AppendObject(aListener) ? NS_OK : NS_ERROR_FAILURE;
510 NS_IMETHODIMP
511 nsTransactionManager::RemoveListener(nsITransactionListener *aListener)
513 NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER);
515 return mListeners.RemoveObject(aListener) ? NS_OK : NS_ERROR_FAILURE;
518 NS_IMETHODIMP
519 nsTransactionManager::ClearUndoStack()
521 mUndoStack.Clear();
522 return NS_OK;
525 NS_IMETHODIMP
526 nsTransactionManager::ClearRedoStack()
528 mRedoStack.Clear();
529 return NS_OK;
532 nsresult
533 nsTransactionManager::WillDoNotify(nsITransaction *aTransaction, bool *aInterrupt)
535 nsresult result = NS_OK;
536 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
538 nsITransactionListener *listener = mListeners[i];
540 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
542 result = listener->WillDo(this, aTransaction, aInterrupt);
544 if (NS_FAILED(result) || *aInterrupt)
545 break;
548 return result;
551 nsresult
552 nsTransactionManager::DidDoNotify(nsITransaction *aTransaction, nsresult aDoResult)
554 nsresult result = NS_OK;
555 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
557 nsITransactionListener *listener = mListeners[i];
559 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
561 result = listener->DidDo(this, aTransaction, aDoResult);
563 if (NS_FAILED(result))
564 break;
567 return result;
570 nsresult
571 nsTransactionManager::WillUndoNotify(nsITransaction *aTransaction, bool *aInterrupt)
573 nsresult result = NS_OK;
574 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
576 nsITransactionListener *listener = mListeners[i];
578 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
580 result = listener->WillUndo(this, aTransaction, aInterrupt);
582 if (NS_FAILED(result) || *aInterrupt)
583 break;
586 return result;
589 nsresult
590 nsTransactionManager::DidUndoNotify(nsITransaction *aTransaction, nsresult aUndoResult)
592 nsresult result = NS_OK;
593 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
595 nsITransactionListener *listener = mListeners[i];
597 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
599 result = listener->DidUndo(this, aTransaction, aUndoResult);
601 if (NS_FAILED(result))
602 break;
605 return result;
608 nsresult
609 nsTransactionManager::WillRedoNotify(nsITransaction *aTransaction, bool *aInterrupt)
611 nsresult result = NS_OK;
612 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
614 nsITransactionListener *listener = mListeners[i];
616 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
618 result = listener->WillRedo(this, aTransaction, aInterrupt);
620 if (NS_FAILED(result) || *aInterrupt)
621 break;
624 return result;
627 nsresult
628 nsTransactionManager::DidRedoNotify(nsITransaction *aTransaction, nsresult aRedoResult)
630 nsresult result = NS_OK;
631 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
633 nsITransactionListener *listener = mListeners[i];
635 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
637 result = listener->DidRedo(this, aTransaction, aRedoResult);
639 if (NS_FAILED(result))
640 break;
643 return result;
646 nsresult
647 nsTransactionManager::WillBeginBatchNotify(bool *aInterrupt)
649 nsresult result = NS_OK;
650 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
652 nsITransactionListener *listener = mListeners[i];
654 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
656 result = listener->WillBeginBatch(this, aInterrupt);
658 if (NS_FAILED(result) || *aInterrupt)
659 break;
662 return result;
665 nsresult
666 nsTransactionManager::DidBeginBatchNotify(nsresult aResult)
668 nsresult result = NS_OK;
669 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
671 nsITransactionListener *listener = mListeners[i];
673 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
675 result = listener->DidBeginBatch(this, aResult);
677 if (NS_FAILED(result))
678 break;
681 return result;
684 nsresult
685 nsTransactionManager::WillEndBatchNotify(bool *aInterrupt)
687 nsresult result = NS_OK;
688 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
690 nsITransactionListener *listener = mListeners[i];
692 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
694 result = listener->WillEndBatch(this, aInterrupt);
696 if (NS_FAILED(result) || *aInterrupt)
697 break;
700 return result;
703 nsresult
704 nsTransactionManager::DidEndBatchNotify(nsresult aResult)
706 nsresult result = NS_OK;
707 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
709 nsITransactionListener *listener = mListeners[i];
711 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
713 result = listener->DidEndBatch(this, aResult);
715 if (NS_FAILED(result))
716 break;
719 return result;
722 nsresult
723 nsTransactionManager::WillMergeNotify(nsITransaction *aTop, nsITransaction *aTransaction, bool *aInterrupt)
725 nsresult result = NS_OK;
726 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
728 nsITransactionListener *listener = mListeners[i];
730 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
732 result = listener->WillMerge(this, aTop, aTransaction, aInterrupt);
734 if (NS_FAILED(result) || *aInterrupt)
735 break;
738 return result;
741 nsresult
742 nsTransactionManager::DidMergeNotify(nsITransaction *aTop,
743 nsITransaction *aTransaction,
744 bool aDidMerge,
745 nsresult aMergeResult)
747 nsresult result = NS_OK;
748 for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++)
750 nsITransactionListener *listener = mListeners[i];
752 NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
754 result = listener->DidMerge(this, aTop, aTransaction, aDidMerge, aMergeResult);
756 if (NS_FAILED(result))
757 break;
760 return result;
763 nsresult
764 nsTransactionManager::BeginTransaction(nsITransaction *aTransaction,
765 nsISupports *aData)
767 nsresult result = NS_OK;
769 // XXX: POSSIBLE OPTIMIZATION
770 // We could use a factory that pre-allocates/recycles transaction items.
771 nsRefPtr<nsTransactionItem> tx = new nsTransactionItem(aTransaction);
773 if (aData) {
774 nsCOMArray<nsISupports>& data = tx->GetData();
775 data.AppendObject(aData);
778 if (!tx) {
779 return NS_ERROR_OUT_OF_MEMORY;
782 mDoStack.Push(tx);
784 result = tx->DoTransaction();
786 if (NS_FAILED(result)) {
787 tx = mDoStack.Pop();
788 return result;
791 return NS_OK;
794 nsresult
795 nsTransactionManager::EndTransaction(bool aAllowEmpty)
797 nsresult result = NS_OK;
799 nsRefPtr<nsTransactionItem> tx = mDoStack.Pop();
801 if (!tx)
802 return NS_ERROR_FAILURE;
804 nsCOMPtr<nsITransaction> tint = tx->GetTransaction();
806 if (!tint && !aAllowEmpty) {
807 int32_t nc = 0;
809 // If we get here, the transaction must be a dummy batch transaction
810 // created by BeginBatch(). If it contains no children, get rid of it!
812 tx->GetNumberOfChildren(&nc);
814 if (!nc) {
815 return result;
819 // Check if the transaction is transient. If it is, there's nothing
820 // more to do, just return.
822 bool isTransient = false;
824 if (tint)
825 result = tint->GetIsTransient(&isTransient);
827 if (NS_FAILED(result) || isTransient || !mMaxTransactionCount) {
828 // XXX: Should we be clearing the redo stack if the transaction
829 // is transient and there is nothing on the do stack?
830 return result;
833 // Check if there is a transaction on the do stack. If there is,
834 // the current transaction is a "sub" transaction, and should
835 // be added to the transaction at the top of the do stack.
837 nsRefPtr<nsTransactionItem> top = mDoStack.Peek();
838 if (top) {
839 result = top->AddChild(tx);
841 // XXX: What do we do if this fails?
843 return result;
846 // The transaction succeeded, so clear the redo stack.
848 result = ClearRedoStack();
850 if (NS_FAILED(result)) {
851 // XXX: What do we do if this fails?
854 // Check if we can coalesce this transaction with the one at the top
855 // of the undo stack.
857 top = mUndoStack.Peek();
859 if (tint && top) {
860 bool didMerge = false;
861 nsCOMPtr<nsITransaction> topTransaction = top->GetTransaction();
863 if (topTransaction) {
865 bool doInterrupt = false;
867 result = WillMergeNotify(topTransaction, tint, &doInterrupt);
869 NS_ENSURE_SUCCESS(result, result);
871 if (!doInterrupt) {
872 result = topTransaction->Merge(tint, &didMerge);
874 nsresult result2 = DidMergeNotify(topTransaction, tint, didMerge, result);
876 if (NS_SUCCEEDED(result))
877 result = result2;
879 if (NS_FAILED(result)) {
880 // XXX: What do we do if this fails?
883 if (didMerge) {
884 return result;
890 // Check to see if we've hit the max level of undo. If so,
891 // pop the bottom transaction off the undo stack and release it!
893 int32_t sz = mUndoStack.GetSize();
895 if (mMaxTransactionCount > 0 && sz >= mMaxTransactionCount) {
896 nsRefPtr<nsTransactionItem> overflow = mUndoStack.PopBottom();
899 // Push the transaction on the undo stack:
901 mUndoStack.Push(tx);
903 return NS_OK;