aboutsummaryrefslogtreecommitdiffstats
path: root/www/firefox/files
diff options
context:
space:
mode:
authormarcus <marcus@FreeBSD.org>2009-02-24 04:40:55 +0800
committermarcus <marcus@FreeBSD.org>2009-02-24 04:40:55 +0800
commit5375689c7b3bf07b65809458279f61bb18d73b83 (patch)
treef1d675586993a9b8fea83d94280d0882b786ed2a /www/firefox/files
parent0e9c237356f4ed3de80152102b5dcf475b19c152 (diff)
downloadfreebsd-ports-gnome-5375689c7b3bf07b65809458279f61bb18d73b83.tar.gz
freebsd-ports-gnome-5375689c7b3bf07b65809458279f61bb18d73b83.tar.zst
freebsd-ports-gnome-5375689c7b3bf07b65809458279f61bb18d73b83.zip
Back-port some more patches to fix CVE-2009-0352.
Obtained from: Mozilla Bugzilla Reported by: simon
Diffstat (limited to 'www/firefox/files')
-rw-r--r--www/firefox/files/patch-ff-331088154
-rw-r--r--www/firefox/files/patch-ff-40104257
-rw-r--r--www/firefox/files/patch-ff-437142116
-rw-r--r--www/firefox/files/patch-ff-4490061173
4 files changed, 1500 insertions, 0 deletions
diff --git a/www/firefox/files/patch-ff-331088 b/www/firefox/files/patch-ff-331088
new file mode 100644
index 000000000000..f121e2f90950
--- /dev/null
+++ b/www/firefox/files/patch-ff-331088
@@ -0,0 +1,154 @@
+--- .pc/331088-candidate.patch/layout/forms/nsFileControlFrame.cpp 2009-01-07 16:46:32.000000000 +0100
++++ layout/forms/nsFileControlFrame.cpp 2009-01-07 17:02:13.000000000 +0100
+@@ -257,35 +257,37 @@ nsFileControlFrame::ScrollIntoView(nsPre
+ NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
+ }
+ }
+ }
+
+ /**
+ * This is called when our browse button is clicked
+ */
+-nsresult
+-nsFileControlFrame::MouseClick(nsIDOMEvent* aMouseEvent)
++NS_IMETHODIMP
++nsFileControlFrame::MouseListener::MouseClick(nsIDOMEvent* aMouseEvent)
+ {
++ NS_ASSERTION(mFrame, "We should have been unregistered");
++
+ // only allow the left button
+ nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
+ if (mouseEvent) {
+ PRUint16 whichButton;
+ if (NS_SUCCEEDED(mouseEvent->GetButton(&whichButton))) {
+ if (whichButton != 0) {
+ return NS_OK;
+ }
+ }
+ }
+
+
+ nsresult result;
+
+ // Get parent nsIDOMWindowInternal object.
+- nsIContent* content = GetContent();
++ nsIContent* content = mFrame->GetContent();
+ if (!content)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDocument> doc = content->GetDocument();
+ if (!doc)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIDOMWindow> parentWindow =
+@@ -304,17 +306,17 @@ nsFileControlFrame::MouseClick(nsIDOMEve
+ if (NS_FAILED(result))
+ return result;
+
+ // Set filter "All Files"
+ filePicker->AppendFilters(nsIFilePicker::filterAll);
+
+ // Set default directry and filename
+ nsAutoString defaultName;
+- GetProperty(nsHTMLAtoms::value, defaultName);
++ mFrame->GetProperty(nsHTMLAtoms::value, defaultName);
+
+ nsCOMPtr<nsILocalFile> currentFile = do_CreateInstance("@mozilla.org/file/local;1");
+ if (currentFile && !defaultName.IsEmpty()) {
+ result = currentFile->InitWithPath(defaultName);
+ if (NS_SUCCEEDED(result)) {
+ nsAutoString leafName;
+ currentFile->GetLeafName(leafName);
+ if (!leafName.IsEmpty()) {
+@@ -328,46 +330,46 @@ nsFileControlFrame::MouseClick(nsIDOMEve
+ nsCOMPtr<nsILocalFile> parentLocalFile = do_QueryInterface(parentFile, &result);
+ if (parentLocalFile)
+ filePicker->SetDisplayDirectory(parentLocalFile);
+ }
+ }
+ }
+
+ // Tell our textframe to remember the currently focused value
+- mTextFrame->InitFocusedValue();
++ mFrame->mTextFrame->InitFocusedValue();
+
+ // Open dialog
+ PRInt16 mode;
+ result = filePicker->Show(&mode);
+ if (NS_FAILED(result))
+ return result;
+ if (mode == nsIFilePicker::returnCancel)
+ return NS_OK;
+
+- if (!mTextFrame) {
++ if (!mFrame) {
+ // We got destroyed while the filepicker was up. Don't do anything here.
+ return NS_OK;
+ }
+
+ // Set property
+ nsCOMPtr<nsILocalFile> localFile;
+ result = filePicker->GetFile(getter_AddRefs(localFile));
+ if (localFile) {
+ nsAutoString unicodePath;
+ result = localFile->GetPath(unicodePath);
+ if (!unicodePath.IsEmpty()) {
+- mTextFrame->SetProperty(mPresContext, nsHTMLAtoms::value, unicodePath);
+- nsCOMPtr<nsIFileControlElement> fileControl = do_QueryInterface(mContent);
++ mFrame->mTextFrame->SetProperty(mFrame->mPresContext, nsHTMLAtoms::value, unicodePath);
++ nsCOMPtr<nsIFileControlElement> fileControl = do_QueryInterface(content);
+ if (fileControl) {
+ fileControl->SetFileName(unicodePath, PR_FALSE);
+ }
+
+ // May need to fire an onchange here
+- mTextFrame->CheckFireOnChange();
++ mFrame->mTextFrame->CheckFireOnChange();
+ return NS_OK;
+ }
+ }
+
+ return NS_FAILED(result) ? result : NS_ERROR_FAILURE;
+ }
+
+
+@@ -660,18 +662,8 @@ nsFileControlFrame::OnContentReset()
+ return NS_OK;
+ }
+
+ ////////////////////////////////////////////////////////////
+ // Mouse listener implementation
+
+ NS_IMPL_ISUPPORTS1(nsFileControlFrame::MouseListener, nsIDOMMouseListener)
+
+-NS_IMETHODIMP
+-nsFileControlFrame::MouseListener::MouseClick(nsIDOMEvent* aMouseEvent)
+-{
+- if (mFrame) {
+- return mFrame->MouseClick(aMouseEvent);
+- }
+-
+- return NS_OK;
+-}
+-
+--- .pc/331088-candidate.patch/layout/forms/nsFileControlFrame.h 2009-01-07 17:18:55.000000000 +0100
++++ layout/forms/nsFileControlFrame.h 2009-01-07 17:19:00.000000000 +0100
+@@ -142,18 +142,16 @@ protected:
+ NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }
+ NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }
+ NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
+
+ private:
+ nsFileControlFrame* mFrame;
+ };
+
+- nsresult MouseClick(nsIDOMEvent* aMouseEvent);
+-
+ virtual PRIntn GetSkipSides() const;
+
+ /**
+ * The text frame (populated on initial reflow).
+ * @see nsFileControlFrame::Reflow
+ */
+ nsNewFrame* mTextFrame;
+ /**
diff --git a/www/firefox/files/patch-ff-401042 b/www/firefox/files/patch-ff-401042
new file mode 100644
index 000000000000..8a6ff7123d0f
--- /dev/null
+++ b/www/firefox/files/patch-ff-401042
@@ -0,0 +1,57 @@
+--- .pc/401042-backport.patch/layout/generic/nsInlineFrame.cpp 2009-01-05 02:55:09.000000000 +0100
++++ layout/generic/nsInlineFrame.cpp 2009-01-05 02:56:08.000000000 +0100
+@@ -576,27 +576,52 @@ nsInlineFrame::ReflowFrames(nsPresContex
+ ReparentFloatsForInlineChild(irs.mLineContainer, frame, PR_FALSE);
+ }
+ frame->SetParent(this);
+ // We also need to check if frame has a next-in-flow. It it does, then set
+ // its parent frame pointer, too. Otherwise, if we reflow frame and it's
+ // complete we'll fail when deleting its next-in-flow which is no longer
+ // needed. This scenario doesn't happen often, but it can happen
+ nsIFrame* nextInFlow = frame->GetNextInFlow();
+- while (nextInFlow) {
++ for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
+ // Since we only do lazy setting of parent pointers for the frame's
+ // initial reflow, this frame can't have a next-in-flow. That means
+ // the continuing child frame must be in our child list as well. If
+ // not, then something is wrong
+ NS_ASSERTION(mFrames.ContainsFrame(nextInFlow), "unexpected flow");
+ if (havePrevBlock) {
+ ReparentFloatsForInlineChild(irs.mLineContainer, nextInFlow, PR_FALSE);
+ }
+ nextInFlow->SetParent(this);
+- nextInFlow = nextInFlow->GetNextInFlow();
++ }
++
++ // Fix the parent pointer for ::first-letter child frame next-in-flows,
++ // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
++ nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
++ if (realFrame->GetType() == nsLayoutAtoms::letterFrame) {
++ nsIFrame* child = realFrame->GetFirstChild(nsnull);
++ if (child) {
++ nsIFrame* nextInFlow = child->GetNextInFlow();
++ for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
++ if (mFrames.ContainsFrame(nextInFlow)) {
++ nextInFlow->SetParent(this);
++ }
++ else {
++#ifdef DEBUG
++ // Once we find a next-in-flow that isn't ours none of the
++ // remaining next-in-flows should be either.
++ for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
++ NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
++ "unexpected letter frame flow");
++ }
++#endif
++ break;
++ }
++ }
++ }
+ }
+ }
+ rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
+ if (NS_FAILED(rv)) {
+ done = PR_TRUE;
+ break;
+ }
+ if (NS_INLINE_IS_BREAK(aStatus) ||
diff --git a/www/firefox/files/patch-ff-437142 b/www/firefox/files/patch-ff-437142
new file mode 100644
index 000000000000..52cf69679265
--- /dev/null
+++ b/www/firefox/files/patch-ff-437142
@@ -0,0 +1,116 @@
+--- .pc/437142_backport_att350047.patch/layout/base/nsCSSFrameConstructor.cpp 2009-01-26 12:09:32.000000000 +0100
++++ layout/base/nsCSSFrameConstructor.cpp 2009-01-26 12:10:17.000000000 +0100
+@@ -9902,17 +9902,19 @@ nsCSSFrameConstructor::ContentRemoved(ns
+ nsFrameManager *frameManager = mPresShell->FrameManager();
+ nsPresContext *presContext = mPresShell->GetPresContext();
+ nsresult rv = NS_OK;
+
+ // Find the child frame that maps the content
+ nsIFrame* childFrame;
+ mPresShell->GetPrimaryFrameFor(aChild, &childFrame);
+
+- if (! childFrame) {
++ if (!childFrame || childFrame->GetContent() != aChild) {
++ // XXXbz the GetContent() != aChild check is needed due to bug 135040.
++ // Remove it once that's fixed.
+ frameManager->ClearUndisplayedContentIn(aChild, aContainer);
+ }
+
+ // When the last item is removed from a select,
+ // we need to add a pseudo frame so select gets sized as the best it can
+ // so here we see if it is a select and then we get the number of options
+ if (aContainer && childFrame) {
+ nsCOMPtr<nsIDOMHTMLSelectElement> selectElement = do_QueryInterface(aContainer);
+@@ -9991,17 +9993,19 @@ nsCSSFrameConstructor::ContentRemoved(ns
+ // First update the containing blocks structure by removing the
+ // existing letter frames. This makes the subsequent logic
+ // simpler.
+ RemoveLetterFrames(presContext, mPresShell, frameManager,
+ containingBlock);
+
+ // Recover childFrame and parentFrame
+ mPresShell->GetPrimaryFrameFor(aChild, &childFrame);
+- if (!childFrame) {
++ if (!childFrame || childFrame->GetContent() != aChild) {
++ // XXXbz the GetContent() != aChild check is needed due to bug 135040.
++ // Remove it once that's fixed.
+ frameManager->ClearUndisplayedContentIn(aChild, aContainer);
+ return NS_OK;
+ }
+ parentFrame = childFrame->GetParent();
+
+ #ifdef NOISY_FIRST_LETTER
+ printf(" ==> revised parentFrame=");
+ nsFrame::ListTag(stdout, parentFrame);
+@@ -10502,16 +10506,24 @@ nsCSSFrameConstructor::ProcessRestyledFr
+ }
+
+ index = count;
+ while (0 <= --index) {
+ nsIFrame* frame;
+ nsIContent* content;
+ nsChangeHint hint;
+ aChangeList.ChangeAt(index, frame, content, hint);
++ if (frame && frame->GetContent() != content) {
++ // XXXbz this is due to image maps messing with the primary frame map.
++ // See bug 135040. Remove this block once that's fixed.
++ frame = nsnull;
++ if (!(hint & nsChangeHint_ReconstructFrame)) {
++ continue;
++ }
++ }
+
+ // skip any frame that has been destroyed due to a ripple effect
+ if (frame) {
+ nsresult res;
+
+ propTable->GetProperty(frame, nsLayoutAtoms::changeListProperty, &res);
+
+ if (NS_PROPTABLE_PROP_NOT_THERE == res)
+@@ -10567,16 +10579,21 @@ nsCSSFrameConstructor::ProcessRestyledFr
+ return NS_OK;
+ }
+
+ void
+ nsCSSFrameConstructor::RestyleElement(nsIContent *aContent,
+ nsIFrame *aPrimaryFrame,
+ nsChangeHint aMinHint)
+ {
++ if (aPrimaryFrame && aPrimaryFrame->GetContent() != aContent) {
++ // XXXbz this is due to image maps messing with the primary frame mapping.
++ // See bug 135040. We can remove this block once that's fixed.
++ aPrimaryFrame = nsnull;
++ }
+ #ifdef ACCESSIBILITY
+ nsIAtom *prevRenderedFrameType = nsnull;
+ if (mPresShell->IsAccessibilityActive()) {
+ prevRenderedFrameType = GetRenderedFrameType(aPrimaryFrame);
+ }
+ #endif
+ if (aMinHint & nsChangeHint_ReconstructFrame) {
+ RecreateFramesForContent(aContent);
+--- .pc/437142_backport_att350047.patch/layout/generic/nsImageMap.cpp 2009-01-26 12:09:32.000000000 +0100
++++ layout/generic/nsImageMap.cpp 2009-01-26 12:10:17.000000000 +0100
+@@ -895,16 +895,22 @@ nsImageMap::AddArea(nsIContent* aArea)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ //Add focus listener to track area focus changes
+ nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(aArea));
+ if (rec) {
+ rec->AddEventListenerByIID(this, NS_GET_IID(nsIDOMFocusListener));
+ }
+
++
++ // This is a nasty hack. It needs to go away: see bug 135040. Once this is
++ // removed, the code added to nsCSSFrameConstructor::RestyleElement,
++ // nsCSSFrameConstructor::ContentRemoved (both hacks there), and
++ // nsCSSFrameConstructor::ProcessRestyledFrames to work around this issue can
++ // be removed.
+ mPresShell->FrameManager()->SetPrimaryFrameFor(aArea, mImageFrame);
+ aArea->SetMayHaveFrame(PR_TRUE);
+ NS_ASSERTION(aArea->MayHaveFrame(), "SetMayHaveFrame failed?");
+
+ area->ParseCoords(coords);
+ mAreas.AppendElement(area);
+ return NS_OK;
+ }
diff --git a/www/firefox/files/patch-ff-449006 b/www/firefox/files/patch-ff-449006
new file mode 100644
index 000000000000..5a3862b752a4
--- /dev/null
+++ b/www/firefox/files/patch-ff-449006
@@ -0,0 +1,1173 @@
+diff --git a/editor/txmgr/src/nsTransactionItem.cpp b/editor/txmgr/src/nsTransactionItem.cpp
+--- editor/txmgr/src/nsTransactionItem.cpp
++++ editor/txmgr/src/nsTransactionItem.cpp
+@@ -35,31 +35,51 @@
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+ #include "nsITransaction.h"
+ #include "nsTransactionStack.h"
+ #include "nsTransactionManager.h"
+ #include "nsTransactionItem.h"
+ #include "nsCOMPtr.h"
++#include "nsAutoPtr.h"
+
+ nsTransactionItem::nsTransactionItem(nsITransaction *aTransaction)
+ : mTransaction(aTransaction), mUndoStack(0), mRedoStack(0)
+ {
+ }
+
+ nsTransactionItem::~nsTransactionItem()
+ {
+ if (mRedoStack)
+ delete mRedoStack;
+
+ if (mUndoStack)
+ delete mUndoStack;
++}
+
+- NS_IF_RELEASE(mTransaction);
++nsrefcnt
++nsTransactionItem::AddRef()
++{
++ ++mRefCnt;
++ NS_LOG_ADDREF(this, mRefCnt, "nsTransactionItem",
++ sizeof(nsTransactionItem));
++ return mRefCnt;
++}
++
++nsrefcnt
++nsTransactionItem::Release() {
++ --mRefCnt;
++ NS_LOG_RELEASE(this, mRefCnt, "nsTransactionItem");
++ if (mRefCnt == 0) {
++ mRefCnt = 1;
++ delete this;
++ return 0;
++ }
++ return mRefCnt;
+ }
+
+ nsresult
+ nsTransactionItem::AddChild(nsTransactionItem *aTransactionItem)
+ {
+ if (!aTransactionItem)
+ return NS_ERROR_NULL_POINTER;
+
+@@ -75,17 +95,17 @@ nsTransactionItem::AddChild(nsTransactio
+ }
+
+ nsresult
+ nsTransactionItem::GetTransaction(nsITransaction **aTransaction)
+ {
+ if (!aTransaction)
+ return NS_ERROR_NULL_POINTER;
+
+- *aTransaction = mTransaction;
++ NS_IF_ADDREF(*aTransaction = mTransaction);
+
+ return NS_OK;
+ }
+
+ nsresult
+ nsTransactionItem::GetIsBatch(PRBool *aIsBatch)
+ {
+ if (!aIsBatch)
+@@ -202,17 +222,17 @@ nsTransactionItem::UndoTransaction(nsTra
+ }
+
+ return NS_OK;
+ }
+
+ nsresult
+ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
+ {
+- nsTransactionItem *item;
++ nsRefPtr<nsTransactionItem> item;
+ nsresult result = NS_OK;
+ PRInt32 sz = 0;
+
+ if (mUndoStack) {
+ if (!mRedoStack && mUndoStack) {
+ mRedoStack = new nsTransactionRedoStack();
+ if (!mRedoStack)
+ return NS_ERROR_OUT_OF_MEMORY;
+@@ -220,25 +240,25 @@ nsTransactionItem::UndoChildren(nsTransa
+
+ /* Undo all of the transaction items children! */
+ result = mUndoStack->GetSize(&sz);
+
+ if (NS_FAILED(result))
+ return result;
+
+ while (sz-- > 0) {
+- result = mUndoStack->Peek(&item);
++ result = mUndoStack->Peek(getter_AddRefs(item));
+
+ if (NS_FAILED(result)) {
+ return result;
+ }
+
+- nsITransaction *t = 0;
++ nsCOMPtr<nsITransaction> t;
+
+- result = item->GetTransaction(&t);
++ result = item->GetTransaction(getter_AddRefs(t));
+
+ if (NS_FAILED(result)) {
+ return result;
+ }
+
+ PRBool doInterrupt = PR_FALSE;
+
+ result = aTxMgr->WillUndoNotify(t, &doInterrupt);
+@@ -249,17 +269,17 @@ nsTransactionItem::UndoChildren(nsTransa
+
+ if (doInterrupt) {
+ return NS_OK;
+ }
+
+ result = item->UndoTransaction(aTxMgr);
+
+ if (NS_SUCCEEDED(result)) {
+- result = mUndoStack->Pop(&item);
++ result = mUndoStack->Pop(getter_AddRefs(item));
+
+ if (NS_SUCCEEDED(result)) {
+ result = mRedoStack->Push(item);
+
+ /* XXX: If we got an error here, I doubt we can recover!
+ * XXX: Should we just push the item back on the undo stack?
+ */
+ }
+@@ -276,16 +296,17 @@ nsTransactionItem::UndoChildren(nsTransa
+ return result;
+ }
+
+ nsresult
+ nsTransactionItem::RedoTransaction(nsTransactionManager *aTxMgr)
+ {
+ nsresult result;
+
++ nsCOMPtr<nsITransaction> kungfuDeathGrip(mTransaction);
+ if (mTransaction) {
+ result = mTransaction->RedoTransaction();
+
+ if (NS_FAILED(result))
+ return result;
+ }
+
+ result = RedoChildren(aTxMgr);
+@@ -296,40 +317,40 @@ nsTransactionItem::RedoTransaction(nsTra
+ }
+
+ return NS_OK;
+ }
+
+ nsresult
+ nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
+ {
+- nsTransactionItem *item;
++ nsRefPtr<nsTransactionItem> item;
+ nsresult result = NS_OK;
+ PRInt32 sz = 0;
+
+ if (!mRedoStack)
+ return NS_OK;
+
+ /* Redo all of the transaction items children! */
+ result = mRedoStack->GetSize(&sz);
+
+ if (NS_FAILED(result))
+ return result;
+
+
+ while (sz-- > 0) {
+- result = mRedoStack->Peek(&item);
++ result = mRedoStack->Peek(getter_AddRefs(item));
+
+ if (NS_FAILED(result)) {
+ return result;
+ }
+
+- nsITransaction *t = 0;
++ nsCOMPtr<nsITransaction> t;
+
+- result = item->GetTransaction(&t);
++ result = item->GetTransaction(getter_AddRefs(t));
+
+ if (NS_FAILED(result)) {
+ return result;
+ }
+
+ PRBool doInterrupt = PR_FALSE;
+
+ result = aTxMgr->WillRedoNotify(t, &doInterrupt);
+@@ -340,17 +361,17 @@ nsTransactionItem::RedoChildren(nsTransa
+
+ if (doInterrupt) {
+ return NS_OK;
+ }
+
+ result = item->RedoTransaction(aTxMgr);
+
+ if (NS_SUCCEEDED(result)) {
+- result = mRedoStack->Pop(&item);
++ result = mRedoStack->Pop(getter_AddRefs(item));
+
+ if (NS_SUCCEEDED(result)) {
+ result = mUndoStack->Push(item);
+
+ // XXX: If we got an error here, I doubt we can recover!
+ // XXX: Should we just push the item back on the redo stack?
+ }
+ }
+diff --git a/editor/txmgr/src/nsTransactionItem.h b/editor/txmgr/src/nsTransactionItem.h
+--- editor/txmgr/src/nsTransactionItem.h
++++ editor/txmgr/src/nsTransactionItem.h
+@@ -33,31 +33,36 @@
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+ #ifndef nsTransactionItem_h__
+ #define nsTransactionItem_h__
+
+-class nsITransaction;
++#include "nsITransaction.h"
++#include "nsCOMPtr.h"
++
+ class nsTransactionStack;
+ class nsTransactionRedoStack;
+ class nsTransactionManager;
+
+ class nsTransactionItem
+ {
+- nsITransaction *mTransaction;
+- nsTransactionStack *mUndoStack;
+- nsTransactionRedoStack *mRedoStack;
++ nsCOMPtr<nsITransaction> mTransaction;
++ nsTransactionStack *mUndoStack;
++ nsTransactionRedoStack *mRedoStack;
++ nsAutoRefCnt mRefCnt;
+
+ public:
+
+ nsTransactionItem(nsITransaction *aTransaction);
+ virtual ~nsTransactionItem();
++ nsrefcnt AddRef();
++ nsrefcnt Release();
+
+ virtual nsresult AddChild(nsTransactionItem *aTransactionItem);
+ virtual nsresult GetTransaction(nsITransaction **aTransaction);
+ virtual nsresult GetIsBatch(PRBool *aIsBatch);
+ virtual nsresult GetNumberOfChildren(PRInt32 *aNumChildren);
+ virtual nsresult GetChild(PRInt32 aIndex, nsTransactionItem **aChild);
+
+ virtual nsresult DoTransaction(void);
+diff --git a/editor/txmgr/src/nsTransactionList.cpp b/editor/txmgr/src/nsTransactionList.cpp
+--- editor/txmgr/src/nsTransactionList.cpp
++++ editor/txmgr/src/nsTransactionList.cpp
+@@ -95,24 +95,24 @@ NS_IMETHODIMP nsTransactionList::ItemIsB
+
+ *aIsBatch = PR_FALSE;
+
+ nsCOMPtr<nsITransactionManager> txMgr = do_QueryReferent(mTxnMgr);
+
+ if (!txMgr)
+ return NS_ERROR_FAILURE;
+
+- nsTransactionItem *item = 0;
++ nsRefPtr<nsTransactionItem> item;
+
+ nsresult result = NS_ERROR_FAILURE;
+
+ if (mTxnStack)
+- result = mTxnStack->GetItem(aIndex, &item);
++ result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
+ else if (mTxnItem)
+- result = mTxnItem->GetChild(aIndex, &item);
++ result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
+
+ if (NS_FAILED(result))
+ return result;
+
+ if (!item)
+ return NS_ERROR_FAILURE;
+
+ return item->GetIsBatch(aIsBatch);
+@@ -126,62 +126,55 @@ NS_IMETHODIMP nsTransactionList::GetItem
+
+ *aItem = 0;
+
+ nsCOMPtr<nsITransactionManager> txMgr = do_QueryReferent(mTxnMgr);
+
+ if (!txMgr)
+ return NS_ERROR_FAILURE;
+
+- nsTransactionItem *item = 0;
++ nsRefPtr<nsTransactionItem> item;
+
+ nsresult result = NS_ERROR_FAILURE;
+
+ if (mTxnStack)
+- result = mTxnStack->GetItem(aIndex, &item);
++ result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
+ else if (mTxnItem)
+- result = mTxnItem->GetChild(aIndex, &item);
++ result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
+
+ if (NS_FAILED(result))
+ return result;
+
+ if (!item)
+ return NS_ERROR_FAILURE;
+
+- result = item->GetTransaction(aItem);
+-
+- if (NS_FAILED(result))
+- return result;
+-
+- NS_IF_ADDREF(*aItem);
+-
+- return NS_OK;
++ return item->GetTransaction(aItem);
+ }
+
+ /* long getNumChildrenForItem (in long aIndex); */
+ NS_IMETHODIMP nsTransactionList::GetNumChildrenForItem(PRInt32 aIndex, PRInt32 *aNumChildren)
+ {
+ if (!aNumChildren)
+ return NS_ERROR_NULL_POINTER;
+
+ *aNumChildren = 0;
+
+ nsCOMPtr<nsITransactionManager> txMgr = do_QueryReferent(mTxnMgr);
+
+ if (!txMgr)
+ return NS_ERROR_FAILURE;
+
+- nsTransactionItem *item = 0;
++ nsRefPtr<nsTransactionItem> item;
+
+ nsresult result = NS_ERROR_FAILURE;
+
+ if (mTxnStack)
+- result = mTxnStack->GetItem(aIndex, &item);
++ result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
+ else if (mTxnItem)
+- result = mTxnItem->GetChild(aIndex, &item);
++ result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
+
+ if (NS_FAILED(result))
+ return result;
+
+ if (!item)
+ return NS_ERROR_FAILURE;
+
+ return item->GetNumberOfChildren(aNumChildren);
+@@ -195,24 +188,24 @@ NS_IMETHODIMP nsTransactionList::GetChil
+
+ *aTxnList = 0;
+
+ nsCOMPtr<nsITransactionManager> txMgr = do_QueryReferent(mTxnMgr);
+
+ if (!txMgr)
+ return NS_ERROR_FAILURE;
+
+- nsTransactionItem *item = 0;
++ nsRefPtr<nsTransactionItem> item;
+
+ nsresult result = NS_ERROR_FAILURE;
+
+ if (mTxnStack)
+- result = mTxnStack->GetItem(aIndex, &item);
++ result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
+ else if (mTxnItem)
+- result = mTxnItem->GetChild(aIndex, &item);
++ result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
+
+ if (NS_FAILED(result))
+ return result;
+
+ if (!item)
+ return NS_ERROR_FAILURE;
+
+ *aTxnList = (nsITransactionList *)new nsTransactionList(txMgr, item);
+diff --git a/editor/txmgr/src/nsTransactionList.h b/editor/txmgr/src/nsTransactionList.h
+--- editor/txmgr/src/nsTransactionList.h
++++ editor/txmgr/src/nsTransactionList.h
+@@ -35,33 +35,34 @@
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+ #ifndef nsTransactionList_h__
+ #define nsTransactionList_h__
+
+ #include "nsWeakReference.h"
+ #include "nsITransactionList.h"
++#include "nsTransactionItem.h"
++#include "nsAutoPtr.h"
+
+ class nsITransaction;
+ class nsITransactionManager;
+-class nsTransactionItem;
+ class nsTransactionStack;
+ class nsTransactionRedoStack;
+
+ /** implementation of a transaction list object.
+ *
+ */
+ class nsTransactionList : public nsITransactionList
+ {
+ private:
+
+- nsWeakPtr mTxnMgr;
+- nsTransactionStack *mTxnStack;
+- nsTransactionItem *mTxnItem;
++ nsWeakPtr mTxnMgr;
++ nsTransactionStack *mTxnStack;
++ nsRefPtr<nsTransactionItem> mTxnItem;
+
+ public:
+
+ nsTransactionList(nsITransactionManager *aTxnMgr, nsTransactionStack *aTxnStack);
+ nsTransactionList(nsITransactionManager *aTxnMgr, nsTransactionItem *aTxnItem);
+
+ virtual ~nsTransactionList();
+
+diff --git a/editor/txmgr/src/nsTransactionManager.cpp b/editor/txmgr/src/nsTransactionManager.cpp
+--- editor/txmgr/src/nsTransactionManager.cpp
++++ editor/txmgr/src/nsTransactionManager.cpp
+@@ -38,17 +38,17 @@
+ #include "nsITransaction.h"
+ #include "nsITransactionListener.h"
+
+ #include "nsTransactionItem.h"
+ #include "nsTransactionStack.h"
+ #include "nsVoidArray.h"
+ #include "nsTransactionManager.h"
+ #include "nsTransactionList.h"
+-
++#include "nsAutoPtr.h"
+ #include "nsCOMPtr.h"
+
+ #define LOCK_TX_MANAGER(mgr) (mgr)->Lock()
+ #define UNLOCK_TX_MANAGER(mgr) (mgr)->Unlock()
+
+
+ nsTransactionManager::nsTransactionManager(PRInt32 aMaxTransactionCount)
+ : mMaxTransactionCount(aMaxTransactionCount), mListeners(0)
+@@ -148,54 +148,54 @@ nsTransactionManager::DoTransaction(nsIT
+
+ return result;
+ }
+
+ NS_IMETHODIMP
+ nsTransactionManager::UndoTransaction()
+ {
+ nsresult result = NS_OK;
+- nsTransactionItem *tx = 0;
++ nsRefPtr<nsTransactionItem> tx;
+
+ LOCK_TX_MANAGER(this);
+
+ // It is illegal to call UndoTransaction() while the transaction manager is
+ // executing a transaction's DoTransaction() method! If this happens,
+ // the UndoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
+
+- result = mDoStack.Peek(&tx);
++ result = mDoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ if (tx) {
+ UNLOCK_TX_MANAGER(this);
+ return NS_ERROR_FAILURE;
+ }
+
+ // Peek at the top of the undo stack. Don't remove the transaction
+ // until it has successfully completed.
+- result = mUndoStack.Peek(&tx);
++ result = mUndoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ // Bail if there's nothing on the stack.
+ if (!tx) {
+ UNLOCK_TX_MANAGER(this);
+ return NS_OK;
+ }
+
+- nsITransaction *t = 0;
++ nsCOMPtr<nsITransaction> t;
+
+- result = tx->GetTransaction(&t);
++ result = tx->GetTransaction(getter_AddRefs(t));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ PRBool doInterrupt = PR_FALSE;
+
+@@ -209,17 +209,17 @@ nsTransactionManager::UndoTransaction()
+ if (doInterrupt) {
+ UNLOCK_TX_MANAGER(this);
+ return NS_OK;
+ }
+
+ result = tx->UndoTransaction(this);
+
+ if (NS_SUCCEEDED(result)) {
+- result = mUndoStack.Pop(&tx);
++ result = mUndoStack.Pop(getter_AddRefs(tx));
+
+ if (NS_SUCCEEDED(result))
+ result = mRedoStack.Push(tx);
+ }
+
+ nsresult result2 = DidUndoNotify(t, result);
+
+ if (NS_SUCCEEDED(result))
+@@ -229,54 +229,54 @@ nsTransactionManager::UndoTransaction()
+
+ return result;
+ }
+
+ NS_IMETHODIMP
+ nsTransactionManager::RedoTransaction()
+ {
+ nsresult result = NS_OK;
+- nsTransactionItem *tx = 0;
++ nsRefPtr<nsTransactionItem> tx;
+
+ LOCK_TX_MANAGER(this);
+
+ // It is illegal to call RedoTransaction() while the transaction manager is
+ // executing a transaction's DoTransaction() method! If this happens,
+ // the RedoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
+
+- result = mDoStack.Peek(&tx);
++ result = mDoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ if (tx) {
+ UNLOCK_TX_MANAGER(this);
+ return NS_ERROR_FAILURE;
+ }
+
+ // Peek at the top of the redo stack. Don't remove the transaction
+ // until it has successfully completed.
+- result = mRedoStack.Peek(&tx);
++ result = mRedoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ // Bail if there's nothing on the stack.
+ if (!tx) {
+ UNLOCK_TX_MANAGER(this);
+ return NS_OK;
+ }
+
+- nsITransaction *t = 0;
++ nsCOMPtr<nsITransaction> t;
+
+- result = tx->GetTransaction(&t);
++ result = tx->GetTransaction(getter_AddRefs(t));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ PRBool doInterrupt = PR_FALSE;
+
+@@ -290,17 +290,17 @@ nsTransactionManager::RedoTransaction()
+ if (doInterrupt) {
+ UNLOCK_TX_MANAGER(this);
+ return NS_OK;
+ }
+
+ result = tx->RedoTransaction(this);
+
+ if (NS_SUCCEEDED(result)) {
+- result = mRedoStack.Pop(&tx);
++ result = mRedoStack.Pop(getter_AddRefs(tx));
+
+ if (NS_SUCCEEDED(result))
+ result = mUndoStack.Push(tx);
+ }
+
+ nsresult result2 = DidRedoNotify(t, result);
+
+ if (NS_SUCCEEDED(result))
+@@ -368,42 +368,42 @@ nsTransactionManager::BeginBatch()
+ UNLOCK_TX_MANAGER(this);
+
+ return result;
+ }
+
+ NS_IMETHODIMP
+ nsTransactionManager::EndBatch()
+ {
+- nsTransactionItem *tx = 0;
+- nsITransaction *ti = 0;
++ nsRefPtr<nsTransactionItem> tx;
++ nsCOMPtr<nsITransaction> ti;
+ nsresult result;
+
+ LOCK_TX_MANAGER(this);
+
+ // XXX: Need to add some mechanism to detect the case where the transaction
+ // at the top of the do stack isn't the dummy transaction, so we can
+ // throw an error!! This can happen if someone calls EndBatch() within
+ // the DoTransaction() method of a transaction.
+ //
+ // For now, we can detect this case by checking the value of the
+ // dummy transaction's mTransaction field. If it is our dummy
+ // transaction, it should be NULL. This may not be true in the
+ // future when we allow users to execute a transaction when beginning
+ // a batch!!!!
+
+- result = mDoStack.Peek(&tx);
++ result = mDoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ if (tx)
+- tx->GetTransaction(&ti);
++ tx->GetTransaction(getter_AddRefs(ti));
+
+ if (!tx || ti) {
+ UNLOCK_TX_MANAGER(this);
+ return NS_ERROR_FAILURE;
+ }
+
+ PRBool doInterrupt = PR_FALSE;
+
+@@ -467,28 +467,28 @@ nsTransactionManager::GetMaxTransactionC
+
+ return NS_OK;
+ }
+
+ NS_IMETHODIMP
+ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
+ {
+ PRInt32 numUndoItems = 0, numRedoItems = 0, total = 0;
+- nsTransactionItem *tx = 0;
++ nsRefPtr<nsTransactionItem> tx;
+ nsresult result;
+
+ LOCK_TX_MANAGER(this);
+
+ // It is illegal to call SetMaxTransactionCount() while the transaction
+ // manager is executing a transaction's DoTransaction() method because
+ // the undo and redo stacks might get pruned! If this happens, the
+ // SetMaxTransactionCount() request is ignored, and we return
+ // NS_ERROR_FAILURE.
+
+- result = mDoStack.Peek(&tx);
++ result = mDoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result)) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ if (tx) {
+ UNLOCK_TX_MANAGER(this);
+@@ -529,107 +529,97 @@ nsTransactionManager::SetMaxTransactionC
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ // Try getting rid of some transactions on the undo stack! Start at
+ // the bottom of the stack and pop towards the top.
+
+ while (numUndoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
+- tx = 0;
+- result = mUndoStack.PopBottom(&tx);
++ result = mUndoStack.PopBottom(getter_AddRefs(tx));
+
+ if (NS_FAILED(result) || !tx) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+-
+- delete tx;
+
+ --numUndoItems;
+ }
+
+ // If necessary, get rid of some transactions on the redo stack! Start at
+ // the bottom of the stack and pop towards the top.
+
+ while (numRedoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
+- tx = 0;
+- result = mRedoStack.PopBottom(&tx);
++ result = mRedoStack.PopBottom(getter_AddRefs(tx));
+
+ if (NS_FAILED(result) || !tx) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+-
+- delete tx;
+
+ --numRedoItems;
+ }
+
+ mMaxTransactionCount = aMaxCount;
+
+ UNLOCK_TX_MANAGER(this);
+
+ return result;
+ }
+
+ NS_IMETHODIMP
+ nsTransactionManager::PeekUndoStack(nsITransaction **aTransaction)
+ {
+- nsTransactionItem *tx = 0;
++ nsRefPtr<nsTransactionItem> tx;
+ nsresult result;
+
+ if (!aTransaction)
+ return NS_ERROR_NULL_POINTER;
+
+ *aTransaction = 0;
+
+ LOCK_TX_MANAGER(this);
+
+- result = mUndoStack.Peek(&tx);
++ result = mUndoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result) || !tx) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ result = tx->GetTransaction(aTransaction);
+
+ UNLOCK_TX_MANAGER(this);
+
+- NS_IF_ADDREF(*aTransaction);
+-
+ return result;
+ }
+
+ NS_IMETHODIMP
+ nsTransactionManager::PeekRedoStack(nsITransaction **aTransaction)
+ {
+- nsTransactionItem *tx = 0;
++ nsRefPtr<nsTransactionItem> tx;
+ nsresult result;
+
+ if (!aTransaction)
+ return NS_ERROR_NULL_POINTER;
+
+ *aTransaction = 0;
+
+ LOCK_TX_MANAGER(this);
+
+- result = mRedoStack.Peek(&tx);
++ result = mRedoStack.Peek(getter_AddRefs(tx));
+
+ if (NS_FAILED(result) || !tx) {
+ UNLOCK_TX_MANAGER(this);
+ return result;
+ }
+
+ result = tx->GetTransaction(aTransaction);
+
+ UNLOCK_TX_MANAGER(this);
+-
+- NS_IF_ADDREF(*aTransaction);
+
+ return result;
+ }
+
+ NS_IMETHODIMP
+ nsTransactionManager::GetUndoList(nsITransactionList **aTransactionList)
+ {
+ if (!aTransactionList)
+@@ -1039,109 +1029,101 @@ nsTransactionManager::DidMergeNotify(nsI
+ }
+
+ return result;
+ }
+
+ nsresult
+ nsTransactionManager::BeginTransaction(nsITransaction *aTransaction)
+ {
+- nsTransactionItem *tx;
+ nsresult result = NS_OK;
+
+ // No need for LOCK/UNLOCK_TX_MANAGER() calls since the calling routine
+ // should have done this already!
+
+- NS_IF_ADDREF(aTransaction);
+-
+ // XXX: POSSIBLE OPTIMIZATION
+ // We could use a factory that pre-allocates/recycles transaction items.
+- tx = new nsTransactionItem(aTransaction);
++ nsRefPtr<nsTransactionItem> tx = new nsTransactionItem(aTransaction);
+
+ if (!tx) {
+- NS_IF_RELEASE(aTransaction);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ result = mDoStack.Push(tx);
+
+ if (NS_FAILED(result)) {
+- delete tx;
+ return result;
+ }
+
+ result = tx->DoTransaction();
+
+ if (NS_FAILED(result)) {
+- mDoStack.Pop(&tx);
+- delete tx;
++ mDoStack.Pop(getter_AddRefs(tx));
+ return result;
+ }
+
+ return NS_OK;
+ }
+
+ nsresult
+ nsTransactionManager::EndTransaction()
+ {
+- nsITransaction *tint = 0;
+- nsTransactionItem *tx = 0;
++ nsCOMPtr<nsITransaction> tint;
++ nsRefPtr<nsTransactionItem> tx;
+ nsresult result = NS_OK;
+
+ // No need for LOCK/UNLOCK_TX_MANAGER() calls since the calling routine
+ // should have done this already!
+
+- result = mDoStack.Pop(&tx);
++ result = mDoStack.Pop(getter_AddRefs(tx));
+
+ if (NS_FAILED(result) || !tx)
+ return result;
+
+- result = tx->GetTransaction(&tint);
++ result = tx->GetTransaction(getter_AddRefs(tint));
+
+ if (NS_FAILED(result)) {
+ // XXX: What do we do with the transaction item at this point?
+ return result;
+ }
+
+ if (!tint) {
+ PRInt32 nc = 0;
+
+ // If we get here, the transaction must be a dummy batch transaction
+ // created by BeginBatch(). If it contains no children, get rid of it!
+
+ tx->GetNumberOfChildren(&nc);
+
+ if (!nc) {
+- delete tx;
+ return result;
+ }
+ }
+
+ // Check if the transaction is transient. If it is, there's nothing
+ // more to do, just return.
+
+ PRBool isTransient = PR_FALSE;
+
+ if (tint)
+ result = tint->GetIsTransient(&isTransient);
+
+ if (NS_FAILED(result) || isTransient || !mMaxTransactionCount) {
+ // XXX: Should we be clearing the redo stack if the transaction
+ // is transient and there is nothing on the do stack?
+- delete tx;
+ return result;
+ }
+
+- nsTransactionItem *top = 0;
++ nsRefPtr<nsTransactionItem> top;
+
+ // Check if there is a transaction on the do stack. If there is,
+ // the current transaction is a "sub" transaction, and should
+ // be added to the transaction at the top of the do stack.
+
+- result = mDoStack.Peek(&top);
++ result = mDoStack.Peek(getter_AddRefs(top));
+ if (top) {
+ result = top->AddChild(tx);
+
+ // XXX: What do we do if this fails?
+
+ return result;
+ }
+
+@@ -1152,23 +1134,23 @@ nsTransactionManager::EndTransaction()
+ if (NS_FAILED(result)) {
+ // XXX: What do we do if this fails?
+ }
+
+ // Check if we can coalesce this transaction with the one at the top
+ // of the undo stack.
+
+ top = 0;
+- result = mUndoStack.Peek(&top);
++ result = mUndoStack.Peek(getter_AddRefs(top));
+
+ if (tint && top) {
+ PRBool didMerge = PR_FALSE;
+- nsITransaction *topTransaction = 0;
++ nsCOMPtr<nsITransaction> topTransaction;
+
+- result = top->GetTransaction(&topTransaction);
++ result = top->GetTransaction(getter_AddRefs(topTransaction));
+
+ if (topTransaction) {
+
+ PRBool doInterrupt = PR_FALSE;
+
+ result = WillMergeNotify(topTransaction, tint, &doInterrupt);
+
+ if (NS_FAILED(result))
+@@ -1182,39 +1164,35 @@ nsTransactionManager::EndTransaction()
+ if (NS_SUCCEEDED(result))
+ result = result2;
+
+ if (NS_FAILED(result)) {
+ // XXX: What do we do if this fails?
+ }
+
+ if (didMerge) {
+- delete tx;
+ return result;
+ }
+ }
+ }
+ }
+
+ // Check to see if we've hit the max level of undo. If so,
+ // pop the bottom transaction off the undo stack and release it!
+
+ PRInt32 sz = 0;
+
+ result = mUndoStack.GetSize(&sz);
+
+ if (mMaxTransactionCount > 0 && sz >= mMaxTransactionCount) {
+- nsTransactionItem *overflow = 0;
++ nsRefPtr<nsTransactionItem> overflow;
+
+- result = mUndoStack.PopBottom(&overflow);
++ result = mUndoStack.PopBottom(getter_AddRefs(overflow));
+
+ // XXX: What do we do in the case where this fails?
+-
+- if (overflow)
+- delete overflow;
+ }
+
+ // Push the transaction on the undo stack:
+
+ result = mUndoStack.Push(tx);
+
+ if (NS_FAILED(result)) {
+ // XXX: What do we do in the case where a clear fails?
+diff --git a/editor/txmgr/src/nsTransactionStack.cpp b/editor/txmgr/src/nsTransactionStack.cpp
+--- editor/txmgr/src/nsTransactionStack.cpp
++++ editor/txmgr/src/nsTransactionStack.cpp
+@@ -34,38 +34,38 @@
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+ #include "nsITransaction.h"
+ #include "nsTransactionItem.h"
+ #include "nsTransactionStack.h"
+ #include "nsCOMPtr.h"
++#include "nsAutoPtr.h"
+
+ nsTransactionStack::nsTransactionStack()
+ : mQue(0)
+ {
+- nsTransactionReleaseFunctor* theFunctor=new nsTransactionReleaseFunctor();
+- mQue.SetDeallocator(theFunctor);
+ }
+
+ nsTransactionStack::~nsTransactionStack()
+ {
+ Clear();
+ }
+
+ nsresult
+ nsTransactionStack::Push(nsTransactionItem *aTransaction)
+ {
+ if (!aTransaction)
+ return NS_ERROR_NULL_POINTER;
+
+ /* nsDeque's Push() method adds new items at the back
+ * of the deque.
+ */
++ NS_ADDREF(aTransaction);
+ mQue.Push(aTransaction);
+
+ return NS_OK;
+ }
+
+ nsresult
+ nsTransactionStack::Pop(nsTransactionItem **aTransaction)
+ {
+@@ -100,52 +100,51 @@ nsTransactionStack::Peek(nsTransactionIt
+ if (!aTransaction)
+ return NS_ERROR_NULL_POINTER;
+
+ if (!mQue.GetSize()) {
+ *aTransaction = 0;
+ return NS_OK;
+ }
+
+- *aTransaction = (nsTransactionItem *)(mQue.Last());
++ NS_IF_ADDREF(*aTransaction = static_cast<nsTransactionItem*>(mQue.Last()));
+
+ return NS_OK;
+ }
+
+ nsresult
+ nsTransactionStack::GetItem(PRInt32 aIndex, nsTransactionItem **aTransaction)
+ {
+ if (!aTransaction)
+ return NS_ERROR_NULL_POINTER;
+
+ if (aIndex < 0 || aIndex >= mQue.GetSize())
+ return NS_ERROR_FAILURE;
+
+- *aTransaction = (nsTransactionItem *)(mQue.ObjectAt(aIndex));
++ NS_IF_ADDREF(*aTransaction =
++ static_cast<nsTransactionItem*>(mQue.ObjectAt(aIndex)));
+
+ return NS_OK;
+ }
+
+ nsresult
+ nsTransactionStack::Clear(void)
+ {
+- nsTransactionItem *tx = 0;
++ nsRefPtr<nsTransactionItem> tx;
+ nsresult result = NS_OK;
+
+ /* Pop all transactions off the stack and release them. */
+
+- result = Pop(&tx);
++ result = Pop(getter_AddRefs(tx));
+
+ if (NS_FAILED(result))
+ return result;
+
+ while (tx) {
+- delete tx;
+-
+- result = Pop(&tx);
++ result = Pop(getter_AddRefs(tx));
+
+ if (NS_FAILED(result))
+ return result;
+ }
+
+ return NS_OK;
+ }
+
+@@ -163,39 +162,30 @@ nsTransactionRedoStack::~nsTransactionRe
+ nsTransactionRedoStack::~nsTransactionRedoStack()
+ {
+ Clear();
+ }
+
+ nsresult
+ nsTransactionRedoStack::Clear(void)
+ {
+- nsTransactionItem *tx = 0;
++ nsRefPtr<nsTransactionItem> tx;
+ nsresult result = NS_OK;
+
+ /* When clearing a Redo stack, we have to clear from the
+ * bottom of the stack towards the top!
+ */
+
+- result = PopBottom(&tx);
++ result = PopBottom(getter_AddRefs(tx));
+
+ if (NS_FAILED(result))
+ return result;
+
+ while (tx) {
+- delete tx;
+-
+- result = PopBottom(&tx);
++ result = PopBottom(getter_AddRefs(tx));
+
+ if (NS_FAILED(result))
+ return result;
+ }
+
+ return NS_OK;
+ }
+
+-void *
+-nsTransactionReleaseFunctor::operator()(void *aObject)
+-{
+- nsTransactionItem *item = (nsTransactionItem *)aObject;
+- delete item;
+- return 0;
+-}
+diff --git a/editor/txmgr/src/nsTransactionStack.h b/editor/txmgr/src/nsTransactionStack.h
+--- editor/txmgr/src/nsTransactionStack.h
++++ editor/txmgr/src/nsTransactionStack.h
+@@ -37,25 +37,16 @@
+
+ #ifndef nsTransactionStack_h__
+ #define nsTransactionStack_h__
+
+ #include "nsDeque.h"
+
+ class nsTransactionItem;
+
+-class nsTransactionReleaseFunctor : public nsDequeFunctor
+-{
+-public:
+-
+- nsTransactionReleaseFunctor() {}
+- virtual ~nsTransactionReleaseFunctor() {}
+- virtual void *operator()(void *aObject);
+-};
+-
+ class nsTransactionStack
+ {
+ nsDeque mQue;
+
+ public:
+
+ nsTransactionStack();
+ virtual ~nsTransactionStack();