Edit transactions should store their editor instance with strong reference

Edit transactions should store their editor instance with a strong reference, and they should be released when the editor is destroyed.
This commit is contained in:
wolfbeast 2018-02-07 21:36:37 +01:00 • committed by Roy Tam
commit fbab5890eb
23 changed files with 150 additions and 53 deletions

View file

@ -33,7 +33,7 @@ CompositionTransaction::CompositionTransaction(
, mReplaceLength(aReplaceLength) , mReplaceLength(aReplaceLength)
, mRanges(aTextRangeArray) , mRanges(aTextRangeArray)
, mStringToInsert(aStringToInsert) , mStringToInsert(aStringToInsert)
, mEditorBase(aEditorBase) , mEditorBase(&aEditorBase)
, mRangeUpdater(aRangeUpdater) , mRangeUpdater(aRangeUpdater)
, mFixed(false) , mFixed(false)
{ {
@ -45,6 +45,7 @@ CompositionTransaction::~CompositionTransaction()
} }
NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionTransaction, EditTransactionBase, NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionTransaction, EditTransactionBase,
mEditorBase,
mTextNode) mTextNode)
// mRangeList can't lead to cycles // mRangeList can't lead to cycles
@ -60,9 +61,13 @@ NS_IMPL_RELEASE_INHERITED(CompositionTransaction, EditTransactionBase)
NS_IMETHODIMP NS_IMETHODIMP
CompositionTransaction::DoTransaction() CompositionTransaction::DoTransaction()
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// Fail before making any changes if there's no selection controller // Fail before making any changes if there's no selection controller
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selCon;
mEditorBase.GetSelectionController(getter_AddRefs(selCon)); mEditorBase->GetSelectionController(getter_AddRefs(selCon));
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
// Advance caret: This requires the presentation shell to get the selection. // Advance caret: This requires the presentation shell to get the selection.
@ -108,9 +113,13 @@ CompositionTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
CompositionTransaction::UndoTransaction() CompositionTransaction::UndoTransaction()
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// Get the selection first so we'll fail before making any changes if we // Get the selection first so we'll fail before making any changes if we
// can't get it // can't get it
RefPtr<Selection> selection = mEditorBase.GetSelection(); RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
nsresult rv = mTextNode->DeleteData(mOffset, mStringToInsert.Length()); nsresult rv = mTextNode->DeleteData(mOffset, mStringToInsert.Length());
@ -171,7 +180,10 @@ CompositionTransaction::GetTxnDescription(nsAString& aString)
nsresult nsresult
CompositionTransaction::SetSelectionForRanges() CompositionTransaction::SetSelectionForRanges()
{ {
return SetIMESelection(mEditorBase, mTextNode, mOffset, if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
return SetIMESelection(*mEditorBase, mTextNode, mOffset,
mStringToInsert.Length(), mRanges); mStringToInsert.Length(), mRanges);
} }

View file

@ -90,7 +90,7 @@ private:
nsString mStringToInsert; nsString mStringToInsert;
// The editor, which is used to get the selection controller. // The editor, which is used to get the selection controller.
EditorBase& mEditorBase; RefPtr<EditorBase> mEditorBase;
RangeUpdater* mRangeUpdater; RangeUpdater* mRangeUpdater;

View file

@ -50,6 +50,7 @@ CreateElementTransaction::~CreateElementTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction, NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction,
EditTransactionBase, EditTransactionBase,
mEditorBase,
mParent, mParent,
mNewNode, mNewNode,
mRefNode) mRefNode)
@ -63,7 +64,9 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP NS_IMETHODIMP
CreateElementTransaction::DoTransaction() CreateElementTransaction::DoTransaction()
{ {
MOZ_ASSERT(mEditorBase && mTag && mParent); if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) || NS_WARN_IF(!mParent)) {
return NS_ERROR_NOT_INITIALIZED;
}
mNewNode = mEditorBase->CreateHTMLContent(mTag); mNewNode = mEditorBase->CreateHTMLContent(mTag);
NS_ENSURE_STATE(mNewNode); NS_ENSURE_STATE(mNewNode);
@ -106,7 +109,9 @@ CreateElementTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
CreateElementTransaction::UndoTransaction() CreateElementTransaction::UndoTransaction()
{ {
MOZ_ASSERT(mEditorBase && mParent); if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
return NS_ERROR_NOT_INITIALIZED;
}
ErrorResult rv; ErrorResult rv;
mParent->RemoveChild(*mNewNode, rv); mParent->RemoveChild(*mNewNode, rv);
@ -117,7 +122,9 @@ CreateElementTransaction::UndoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
CreateElementTransaction::RedoTransaction() CreateElementTransaction::RedoTransaction()
{ {
MOZ_ASSERT(mEditorBase && mParent); if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
return NS_ERROR_NOT_INITIALIZED;
}
// First, reset mNewNode so it has no attributes or content // First, reset mNewNode so it has no attributes or content
// XXX We never actually did this, we only cleared mNewNode's contents if it // XXX We never actually did this, we only cleared mNewNode's contents if it

View file

@ -57,7 +57,7 @@ protected:
virtual ~CreateElementTransaction(); virtual ~CreateElementTransaction();
// The document into which the new node will be inserted. // The document into which the new node will be inserted.
EditorBase* mEditorBase; RefPtr<EditorBase> mEditorBase;
// The tag (mapping to object type) for the new element. // The tag (mapping to object type) for the new element.
nsCOMPtr<nsIAtom> mTag; nsCOMPtr<nsIAtom> mTag;

View file

@ -23,6 +23,7 @@ DeleteNodeTransaction::~DeleteNodeTransaction()
} }
NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteNodeTransaction, EditTransactionBase, NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteNodeTransaction, EditTransactionBase,
mEditorBase,
mNode, mNode,
mParent, mParent,
mRefNode) mRefNode)

View file

@ -55,7 +55,7 @@ protected:
nsCOMPtr<nsIContent> mRefNode; nsCOMPtr<nsIContent> mRefNode;
// The editor for this transaction. // The editor for this transaction.
EditorBase* mEditorBase; RefPtr<EditorBase> mEditorBase;
// Range updater object. // Range updater object.
RangeUpdater* mRangeUpdater; RangeUpdater* mRangeUpdater;

View file

@ -33,6 +33,7 @@ DeleteRangeTransaction::DeleteRangeTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteRangeTransaction, NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteRangeTransaction,
EditAggregateTransaction, EditAggregateTransaction,
mEditorBase,
mRange) mRange)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteRangeTransaction) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteRangeTransaction)
@ -62,7 +63,9 @@ DeleteRangeTransaction::Init(EditorBase* aEditorBase,
NS_IMETHODIMP NS_IMETHODIMP
DeleteRangeTransaction::DoTransaction() DeleteRangeTransaction::DoTransaction()
{ {
MOZ_ASSERT(mRange && mEditorBase); if (NS_WARN_IF(!mRange) || NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// build the child transactions // build the child transactions
nsCOMPtr<nsINode> startParent = mRange->GetStartParent(); nsCOMPtr<nsINode> startParent = mRange->GetStartParent();
@ -111,16 +114,18 @@ DeleteRangeTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
DeleteRangeTransaction::UndoTransaction() DeleteRangeTransaction::UndoTransaction()
{ {
MOZ_ASSERT(mRange && mEditorBase); if (NS_WARN_IF(!mRange) || NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
return EditAggregateTransaction::UndoTransaction(); return EditAggregateTransaction::UndoTransaction();
} }
NS_IMETHODIMP NS_IMETHODIMP
DeleteRangeTransaction::RedoTransaction() DeleteRangeTransaction::RedoTransaction()
{ {
MOZ_ASSERT(mRange && mEditorBase); if (NS_WARN_IF(!mRange) || NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
return EditAggregateTransaction::RedoTransaction(); return EditAggregateTransaction::RedoTransaction();
} }
@ -136,6 +141,10 @@ DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
int32_t aStartOffset, int32_t aStartOffset,
int32_t aEndOffset) int32_t aEndOffset)
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// see what kind of node we have // see what kind of node we have
if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) { if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
// if the node is a chardata node, then delete chardata content // if the node is a chardata node, then delete chardata content
@ -185,6 +194,10 @@ DeleteRangeTransaction::CreateTxnsToDeleteContent(nsINode* aNode,
int32_t aOffset, int32_t aOffset,
nsIEditor::EDirection aAction) nsIEditor::EDirection aAction)
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// see what kind of node we have // see what kind of node we have
if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) { if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
// if the node is a chardata node, then delete chardata content // if the node is a chardata node, then delete chardata content
@ -217,6 +230,10 @@ DeleteRangeTransaction::CreateTxnsToDeleteContent(nsINode* aNode,
nsresult nsresult
DeleteRangeTransaction::CreateTxnsToDeleteNodesBetween() DeleteRangeTransaction::CreateTxnsToDeleteNodesBetween()
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator(); nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
nsresult rv = iter->Init(mRange); nsresult rv = iter->Init(mRange);

View file

@ -67,7 +67,7 @@ protected:
RefPtr<nsRange> mRange; RefPtr<nsRange> mRange;
// The editor for this transaction. // The editor for this transaction.
EditorBase* mEditorBase; RefPtr<EditorBase> mEditorBase;
// Range updater object. // Range updater object.
RangeUpdater* mRangeUpdater; RangeUpdater* mRangeUpdater;

View file

@ -25,7 +25,7 @@ DeleteTextTransaction::DeleteTextTransaction(
uint32_t aOffset, uint32_t aOffset,
uint32_t aNumCharsToDelete, uint32_t aNumCharsToDelete,
RangeUpdater* aRangeUpdater) RangeUpdater* aRangeUpdater)
: mEditorBase(aEditorBase) : mEditorBase(&aEditorBase)
, mCharData(&aCharData) , mCharData(&aCharData)
, mOffset(aOffset) , mOffset(aOffset)
, mNumCharsToDelete(aNumCharsToDelete) , mNumCharsToDelete(aNumCharsToDelete)
@ -36,6 +36,7 @@ DeleteTextTransaction::DeleteTextTransaction(
} }
NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteTextTransaction, EditTransactionBase, NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteTextTransaction, EditTransactionBase,
mEditorBase,
mCharData) mCharData)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteTextTransaction) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteTextTransaction)
@ -45,7 +46,7 @@ nsresult
DeleteTextTransaction::Init() DeleteTextTransaction::Init()
{ {
// Do nothing if the node is read-only // Do nothing if the node is read-only
if (!mEditorBase.IsModifiableNode(mCharData)) { if (NS_WARN_IF(!mEditorBase) || !mEditorBase->IsModifiableNode(mCharData)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -55,7 +56,9 @@ DeleteTextTransaction::Init()
NS_IMETHODIMP NS_IMETHODIMP
DeleteTextTransaction::DoTransaction() DeleteTextTransaction::DoTransaction()
{ {
MOZ_ASSERT(mCharData); if (NS_WARN_IF(!mCharData) || NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// Get the text that we're about to delete // Get the text that we're about to delete
nsresult rv = mCharData->SubstringData(mOffset, mNumCharsToDelete, nsresult rv = mCharData->SubstringData(mOffset, mNumCharsToDelete,
@ -69,8 +72,8 @@ DeleteTextTransaction::DoTransaction()
} }
// Only set selection to deletion point if editor gives permission // Only set selection to deletion point if editor gives permission
if (mEditorBase.GetShouldTxnSetSelection()) { if (mEditorBase->GetShouldTxnSetSelection()) {
RefPtr<Selection> selection = mEditorBase.GetSelection(); RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
rv = selection->Collapse(mCharData, mOffset); rv = selection->Collapse(mCharData, mOffset);
NS_ASSERTION(NS_SUCCEEDED(rv), NS_ASSERTION(NS_SUCCEEDED(rv),
@ -86,8 +89,9 @@ DeleteTextTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
DeleteTextTransaction::UndoTransaction() DeleteTextTransaction::UndoTransaction()
{ {
MOZ_ASSERT(mCharData); if (NS_WARN_IF(!mCharData)) {
return NS_ERROR_NOT_INITIALIZED;
}
return mCharData->InsertData(mOffset, mDeletedText); return mCharData->InsertData(mOffset, mDeletedText);
} }

View file

@ -53,7 +53,7 @@ public:
protected: protected:
// The provider of basic editing operations. // The provider of basic editing operations.
EditorBase& mEditorBase; RefPtr<EditorBase> mEditorBase;
// The CharacterData node to operate upon. // The CharacterData node to operate upon.
RefPtr<nsGenericDOMDataNode> mCharData; RefPtr<nsGenericDOMDataNode> mCharData;

View file

@ -466,6 +466,13 @@ EditorBase::PreDestroy(bool aDestroyingFrames)
mSpellcheckCheckboxState = eTriUnset; mSpellcheckCheckboxState = eTriUnset;
mRootElement = nullptr; mRootElement = nullptr;
// Transaction may grab this instance. Therefore, they should be released
// here for stopping the circular reference with this instance.
if (mTxnMgr) {
mTxnMgr->Clear();
mTxnMgr = nullptr;
}
mDidPreDestroy = true; mDidPreDestroy = true;
return NS_OK; return NS_OK;
} }

View file

@ -28,7 +28,7 @@ InsertNodeTransaction::InsertNodeTransaction(nsIContent& aNode,
: mNode(&aNode) : mNode(&aNode)
, mParent(&aParent) , mParent(&aParent)
, mOffset(aOffset) , mOffset(aOffset)
, mEditorBase(aEditorBase) , mEditorBase(&aEditorBase)
{ {
} }
@ -37,6 +37,7 @@ InsertNodeTransaction::~InsertNodeTransaction()
} }
NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertNodeTransaction, EditTransactionBase, NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertNodeTransaction, EditTransactionBase,
mEditorBase,
mNode, mNode,
mParent) mParent)
@ -48,7 +49,9 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP NS_IMETHODIMP
InsertNodeTransaction::DoTransaction() InsertNodeTransaction::DoTransaction()
{ {
MOZ_ASSERT(mNode && mParent); if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNode) || NS_WARN_IF(!mParent)) {
return NS_ERROR_NOT_INITIALIZED;
}
uint32_t count = mParent->GetChildCount(); uint32_t count = mParent->GetChildCount();
if (mOffset > static_cast<int32_t>(count) || mOffset == -1) { if (mOffset > static_cast<int32_t>(count) || mOffset == -1) {
@ -59,15 +62,15 @@ InsertNodeTransaction::DoTransaction()
// Note, it's ok for ref to be null. That means append. // Note, it's ok for ref to be null. That means append.
nsCOMPtr<nsIContent> ref = mParent->GetChildAt(mOffset); nsCOMPtr<nsIContent> ref = mParent->GetChildAt(mOffset);
mEditorBase.MarkNodeDirty(GetAsDOMNode(mNode)); mEditorBase->MarkNodeDirty(GetAsDOMNode(mNode));
ErrorResult rv; ErrorResult rv;
mParent->InsertBefore(*mNode, ref, rv); mParent->InsertBefore(*mNode, ref, rv);
NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult()); NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
// Only set selection to insertion point if editor gives permission // Only set selection to insertion point if editor gives permission
if (mEditorBase.GetShouldTxnSetSelection()) { if (mEditorBase->GetShouldTxnSetSelection()) {
RefPtr<Selection> selection = mEditorBase.GetSelection(); RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
// Place the selection just after the inserted element // Place the selection just after the inserted element
selection->Collapse(mParent, mOffset + 1); selection->Collapse(mParent, mOffset + 1);
@ -80,8 +83,9 @@ InsertNodeTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
InsertNodeTransaction::UndoTransaction() InsertNodeTransaction::UndoTransaction()
{ {
MOZ_ASSERT(mNode && mParent); if (NS_WARN_IF(!mNode) || NS_WARN_IF(!mParent)) {
return NS_ERROR_NOT_INITIALIZED;
}
ErrorResult rv; ErrorResult rv;
mParent->RemoveChild(*mNode, rv); mParent->RemoveChild(*mNode, rv);
return rv.StealNSResult(); return rv.StealNSResult();

View file

@ -50,7 +50,7 @@ protected:
int32_t mOffset; int32_t mOffset;
// The editor for this transaction. // The editor for this transaction.
EditorBase& mEditorBase; RefPtr<EditorBase> mEditorBase;
}; };
} // namespace mozilla } // namespace mozilla

View file

@ -26,7 +26,7 @@ InsertTextTransaction::InsertTextTransaction(Text& aTextNode,
: mTextNode(&aTextNode) : mTextNode(&aTextNode)
, mOffset(aOffset) , mOffset(aOffset)
, mStringToInsert(aStringToInsert) , mStringToInsert(aStringToInsert)
, mEditorBase(aEditorBase) , mEditorBase(&aEditorBase)
, mRangeUpdater(aRangeUpdater) , mRangeUpdater(aRangeUpdater)
{ {
} }
@ -36,6 +36,7 @@ InsertTextTransaction::~InsertTextTransaction()
} }
NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase, NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase,
mEditorBase,
mTextNode) mTextNode)
NS_IMPL_ADDREF_INHERITED(InsertTextTransaction, EditTransactionBase) NS_IMPL_ADDREF_INHERITED(InsertTextTransaction, EditTransactionBase)
@ -50,12 +51,16 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP NS_IMETHODIMP
InsertTextTransaction::DoTransaction() InsertTextTransaction::DoTransaction()
{ {
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert); nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Only set selection to insertion point if editor gives permission // Only set selection to insertion point if editor gives permission
if (mEditorBase.GetShouldTxnSetSelection()) { if (mEditorBase->GetShouldTxnSetSelection()) {
RefPtr<Selection> selection = mEditorBase.GetSelection(); RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
DebugOnly<nsresult> rv = DebugOnly<nsresult> rv =
selection->Collapse(mTextNode, mOffset + mStringToInsert.Length()); selection->Collapse(mTextNode, mOffset + mStringToInsert.Length());

View file

@ -76,7 +76,7 @@ private:
nsString mStringToInsert; nsString mStringToInsert;
// The editor, which we'll need to get the selection. // The editor, which we'll need to get the selection.
EditorBase& mEditorBase; RefPtr<EditorBase> mEditorBase;
RangeUpdater* mRangeUpdater; RangeUpdater* mRangeUpdater;
}; };

View file

@ -21,7 +21,7 @@ using namespace dom;
JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase, JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
nsINode& aLeftNode, nsINode& aLeftNode,
nsINode& aRightNode) nsINode& aRightNode)
: mEditorBase(aEditorBase) : mEditorBase(&aEditorBase)
, mLeftNode(&aLeftNode) , mLeftNode(&aLeftNode)
, mRightNode(&aRightNode) , mRightNode(&aRightNode)
, mOffset(0) , mOffset(0)
@ -29,6 +29,7 @@ JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
} }
NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase, NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase,
mEditorBase,
mLeftNode, mLeftNode,
mRightNode, mRightNode,
mParent) mParent)
@ -39,7 +40,8 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
nsresult nsresult
JoinNodeTransaction::CheckValidity() JoinNodeTransaction::CheckValidity()
{ {
if (!mEditorBase.IsModifiableNode(mLeftNode->GetParentNode())) { if (NS_WARN_IF(!mEditorBase) ||
!mEditorBase->IsModifiableNode(mLeftNode->GetParentNode())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
return NS_OK; return NS_OK;
@ -50,6 +52,12 @@ JoinNodeTransaction::CheckValidity()
NS_IMETHODIMP NS_IMETHODIMP
JoinNodeTransaction::DoTransaction() JoinNodeTransaction::DoTransaction()
{ {
if (NS_WARN_IF(!mEditorBase) ||
NS_WARN_IF(!mLeftNode) ||
NS_WARN_IF(!mRightNode)) {
return NS_ERROR_NOT_INITIALIZED;
}
// Get the parent node // Get the parent node
nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode(); nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode();
NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER);
@ -65,7 +73,7 @@ JoinNodeTransaction::DoTransaction()
mParent = leftParent; mParent = leftParent;
mOffset = mLeftNode->Length(); mOffset = mLeftNode->Length();
return mEditorBase.JoinNodesImpl(mRightNode, mLeftNode, mParent); return mEditorBase->JoinNodesImpl(mRightNode, mLeftNode, mParent);
} }
//XXX: What if instead of split, we just deleted the unneeded children of //XXX: What if instead of split, we just deleted the unneeded children of
@ -73,7 +81,11 @@ JoinNodeTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
JoinNodeTransaction::UndoTransaction() JoinNodeTransaction::UndoTransaction()
{ {
MOZ_ASSERT(mParent); if (NS_WARN_IF(!mParent) ||
NS_WARN_IF(!mRightNode) ||
NS_WARN_IF(!mLeftNode)) {
return NS_ERROR_NOT_INITIALIZED;
}
// First, massage the existing node so it is in its post-split state // First, massage the existing node so it is in its post-split state
ErrorResult rv; ErrorResult rv;

View file

@ -47,7 +47,7 @@ public:
NS_DECL_EDITTRANSACTIONBASE NS_DECL_EDITTRANSACTIONBASE
protected: protected:
EditorBase& mEditorBase; RefPtr<EditorBase> mEditorBase;
// The nodes to operate upon. After the merge, mRightNode remains and // The nodes to operate upon. After the merge, mRightNode remains and
// mLeftNode is removed from the content tree. // mLeftNode is removed from the content tree.

View file

@ -35,6 +35,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTransaction,
if (tmp->mStartSel) { if (tmp->mStartSel) {
ImplCycleCollectionUnlink(*tmp->mStartSel); ImplCycleCollectionUnlink(*tmp->mStartSel);
} }
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorBase);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel); NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -43,6 +44,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTransaction,
if (tmp->mStartSel) { if (tmp->mStartSel) {
ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0); ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0);
} }
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorBase);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -76,6 +78,10 @@ PlaceholderTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
PlaceholderTransaction::UndoTransaction() PlaceholderTransaction::UndoTransaction()
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// Undo transactions. // Undo transactions.
nsresult rv = EditAggregateTransaction::UndoTransaction(); nsresult rv = EditAggregateTransaction::UndoTransaction();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -91,6 +97,10 @@ PlaceholderTransaction::UndoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
PlaceholderTransaction::RedoTransaction() PlaceholderTransaction::RedoTransaction()
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// Redo transactions. // Redo transactions.
nsresult rv = EditAggregateTransaction::RedoTransaction(); nsresult rv = EditAggregateTransaction::RedoTransaction();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -261,6 +271,10 @@ PlaceholderTransaction::Commit()
nsresult nsresult
PlaceholderTransaction::RememberEndingSelection() PlaceholderTransaction::RememberEndingSelection()
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
RefPtr<Selection> selection = mEditorBase->GetSelection(); RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
mEndSel.SaveSelection(selection); mEndSel.SaveSelection(selection);

View file

@ -84,7 +84,7 @@ protected:
SelectionState mEndSel; SelectionState mEndSel;
// The editor for this transaction. // The editor for this transaction.
EditorBase* mEditorBase; RefPtr<EditorBase> mEditorBase;
}; };
} // namespace mozilla } // namespace mozilla

View file

@ -19,7 +19,7 @@ using namespace dom;
SplitNodeTransaction::SplitNodeTransaction(EditorBase& aEditorBase, SplitNodeTransaction::SplitNodeTransaction(EditorBase& aEditorBase,
nsIContent& aNode, nsIContent& aNode,
int32_t aOffset) int32_t aOffset)
: mEditorBase(aEditorBase) : mEditorBase(&aEditorBase)
, mExistingRightNode(&aNode) , mExistingRightNode(&aNode)
, mOffset(aOffset) , mOffset(aOffset)
{ {
@ -30,6 +30,7 @@ SplitNodeTransaction::~SplitNodeTransaction()
} }
NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitNodeTransaction, EditTransactionBase, NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitNodeTransaction, EditTransactionBase,
mEditorBase,
mParent, mParent,
mNewLeftNode) mNewLeftNode)
@ -41,6 +42,10 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP NS_IMETHODIMP
SplitNodeTransaction::DoTransaction() SplitNodeTransaction::DoTransaction()
{ {
if (NS_WARN_IF(!mEditorBase)) {
return NS_ERROR_NOT_INITIALIZED;
}
// Create a new node // Create a new node
ErrorResult rv; ErrorResult rv;
// Don't use .downcast directly because AsContent has an assertion we want // Don't use .downcast directly because AsContent has an assertion we want
@ -48,16 +53,16 @@ SplitNodeTransaction::DoTransaction()
NS_ASSERTION(!rv.Failed() && clone, "Could not create clone"); NS_ASSERTION(!rv.Failed() && clone, "Could not create clone");
NS_ENSURE_TRUE(!rv.Failed() && clone, rv.StealNSResult()); NS_ENSURE_TRUE(!rv.Failed() && clone, rv.StealNSResult());
mNewLeftNode = dont_AddRef(clone.forget().take()->AsContent()); mNewLeftNode = dont_AddRef(clone.forget().take()->AsContent());
mEditorBase.MarkNodeDirty(mExistingRightNode->AsDOMNode()); mEditorBase->MarkNodeDirty(mExistingRightNode->AsDOMNode());
// Get the parent node // Get the parent node
mParent = mExistingRightNode->GetParentNode(); mParent = mExistingRightNode->GetParentNode();
NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
// Insert the new node // Insert the new node
rv = mEditorBase.SplitNodeImpl(*mExistingRightNode, mOffset, *mNewLeftNode); rv = mEditorBase->SplitNodeImpl(*mExistingRightNode, mOffset, *mNewLeftNode);
if (mEditorBase.GetShouldTxnSetSelection()) { if (mEditorBase->GetShouldTxnSetSelection()) {
RefPtr<Selection> selection = mEditorBase.GetSelection(); RefPtr<Selection> selection = mEditorBase->GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
rv = selection->Collapse(mNewLeftNode, mOffset); rv = selection->Collapse(mNewLeftNode, mOffset);
} }
@ -67,10 +72,14 @@ SplitNodeTransaction::DoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
SplitNodeTransaction::UndoTransaction() SplitNodeTransaction::UndoTransaction()
{ {
MOZ_ASSERT(mNewLeftNode && mParent); if (NS_WARN_IF(!mEditorBase) ||
NS_WARN_IF(!mNewLeftNode) ||
NS_WARN_IF(!mParent)) {
return NS_ERROR_NOT_INITIALIZED;
}
// This assumes Do inserted the new node in front of the prior existing node // This assumes Do inserted the new node in front of the prior existing node
return mEditorBase.JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent); return mEditorBase->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
} }
/* Redo cannot simply resplit the right node, because subsequent transactions /* Redo cannot simply resplit the right node, because subsequent transactions
@ -80,7 +89,10 @@ SplitNodeTransaction::UndoTransaction()
NS_IMETHODIMP NS_IMETHODIMP
SplitNodeTransaction::RedoTransaction() SplitNodeTransaction::RedoTransaction()
{ {
MOZ_ASSERT(mNewLeftNode && mParent); if (NS_WARN_IF(!mNewLeftNode) ||
NS_WARN_IF(!mParent)) {
return NS_ERROR_NOT_INITIALIZED;
}
ErrorResult rv; ErrorResult rv;
// First, massage the existing node so it is in its post-split state // First, massage the existing node so it is in its post-split state

View file

@ -49,7 +49,7 @@ public:
protected: protected:
virtual ~SplitNodeTransaction(); virtual ~SplitNodeTransaction();
EditorBase& mEditorBase; RefPtr<EditorBase> mEditorBase;
// The node to operate upon. // The node to operate upon.
nsCOMPtr<nsIContent> mExistingRightNode; nsCOMPtr<nsIContent> mExistingRightNode;

View file

@ -57,6 +57,7 @@ AddStyleSheetTransaction::AddStyleSheetTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(AddStyleSheetTransaction, NS_IMPL_CYCLE_COLLECTION_INHERITED(AddStyleSheetTransaction,
EditTransactionBase, EditTransactionBase,
mEditor,
mSheet) mSheet)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AddStyleSheetTransaction) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AddStyleSheetTransaction)
@ -111,6 +112,7 @@ RemoveStyleSheetTransaction::RemoveStyleSheetTransaction()
NS_IMPL_CYCLE_COLLECTION_INHERITED(RemoveStyleSheetTransaction, NS_IMPL_CYCLE_COLLECTION_INHERITED(RemoveStyleSheetTransaction,
EditTransactionBase, EditTransactionBase,
mEditor,
mSheet) mSheet)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RemoveStyleSheetTransaction) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RemoveStyleSheetTransaction)

View file

@ -36,7 +36,7 @@ public:
protected: protected:
// The editor that created this transaction. // The editor that created this transaction.
nsIEditor* mEditor; nsCOMPtr<nsIEditor> mEditor;
// The style sheet to add. // The style sheet to add.
RefPtr<mozilla::StyleSheet> mSheet; RefPtr<mozilla::StyleSheet> mSheet;
}; };
@ -62,7 +62,7 @@ public:
protected: protected:
// The editor that created this transaction. // The editor that created this transaction.
nsIEditor* mEditor; nsCOMPtr<nsIEditor> mEditor;
// The style sheet to remove. // The style sheet to remove.
RefPtr<StyleSheet> mSheet; RefPtr<StyleSheet> mSheet;