--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1604,49 +1604,49 @@ EditorBase::JoinNodesWithTransaction(nsI
return rv;
}
NS_IMETHODIMP
EditorBase::DeleteNode(nsIDOMNode* aNode)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
- NS_ENSURE_STATE(node);
- return DeleteNode(node);
+ if (NS_WARN_IF(!node)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ return DeleteNodeWithTransaction(*node);
}
nsresult
-EditorBase::DeleteNode(nsINode* aNode)
-{
- if (NS_WARN_IF(!aNode)) {
- return NS_ERROR_INVALID_ARG;
- }
-
+EditorBase::DeleteNodeWithTransaction(nsINode& aNode)
+{
AutoRules beginRulesSniffing(this, EditAction::createNode,
nsIEditor::ePrevious);
if (mRules && mRules->AsHTMLEditRules()) {
RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
- htmlEditRules->WillDeleteNode(aNode);
- }
-
+ htmlEditRules->WillDeleteNode(&aNode);
+ }
+
+ // FYI: DeleteNodeTransaction grabs aNode while it's alive. So, it's safe
+ // to refer aNode even after calling DoTransaction().
RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
- DeleteNodeTransaction::MaybeCreate(*this, *aNode);
+ DeleteNodeTransaction::MaybeCreate(*this, aNode);
nsresult rv = deleteNodeTransaction ? DoTransaction(deleteNodeTransaction) :
NS_ERROR_FAILURE;
if (mTextServicesDocument && NS_SUCCEEDED(rv)) {
RefPtr<TextServicesDocument> textServicesDocument = mTextServicesDocument;
- textServicesDocument->DidDeleteNode(aNode);
+ textServicesDocument->DidDeleteNode(&aNode);
}
if (!mActionListeners.IsEmpty()) {
AutoActionListenerArray listeners(mActionListeners);
for (auto& listener : listeners) {
- listener->DidDeleteNode(aNode->AsDOMNode(), rv);
+ listener->DidDeleteNode(aNode.AsDOMNode(), rv);
}
}
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/**
@@ -1690,18 +1690,20 @@ EditorBase::ReplaceContainer(Element* aO
// to initialize mRangeUpdater.
AutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, aOldContainer,
newContainer);
{
AutoTransactionsConserveSelection conserveSelection(this);
// Move all children from the old container to the new container.
while (aOldContainer->HasChildren()) {
nsCOMPtr<nsIContent> child = aOldContainer->GetFirstChild();
-
- nsresult rv = DeleteNode(child);
+ if (NS_WARN_IF(!child)) {
+ return nullptr;
+ }
+ nsresult rv = DeleteNodeWithTransaction(*child);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
rv = InsertNodeWithTransaction(*child,
EditorRawDOMPoint(newContainer,
newContainer->Length()));
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1714,17 +1716,17 @@ EditorBase::ReplaceContainer(Element* aO
NS_WARNING_ASSERTION(atOldContainer.IsSetAndValid(),
"The old container might be moved by mutation observer");
nsresult rv = InsertNodeWithTransaction(*newContainer, atOldContainer);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
// Delete old container.
- rv = DeleteNode(aOldContainer);
+ rv = DeleteNodeWithTransaction(*aOldContainer);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return newContainer.forget();
}
/**
@@ -1745,34 +1747,41 @@ EditorBase::RemoveContainer(nsIContent*
AutoRemoveContainerSelNotify selNotify(mRangeUpdater, aNode,
pointToInsertChildren.GetContainer(),
pointToInsertChildren.Offset(),
aNode->GetChildCount());
// Move all children from aNode to its parent.
while (aNode->HasChildren()) {
nsCOMPtr<nsIContent> child = aNode->GetLastChild();
- nsresult rv = DeleteNode(child);
+ if (NS_WARN_IF(!child)) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = DeleteNodeWithTransaction(*child);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Insert the last child before the previous last child. So, we need to
// use offset here because previous child might have been moved to
// container.
rv = InsertNodeWithTransaction(*child,
EditorRawDOMPoint(
pointToInsertChildren.GetContainer(),
pointToInsertChildren.Offset()));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
- return DeleteNode(aNode);
+ nsresult rv = DeleteNodeWithTransaction(*aNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
}
/**
* InsertContainerAbove() inserts a new parent for inNode, which is contructed
* to be of type aNodeType. outNode becomes a child of inNode's earlier
* parent. Caller's responsibility to make sure inNode's can be child of
* outNode, and outNode can be child of old parent.
*/
@@ -1809,17 +1818,17 @@ EditorBase::InsertContainerAbove(nsICont
return nullptr;
}
}
// Notify our internal selection state listener
AutoInsertContainerSelNotify selNotify(mRangeUpdater);
// Put aNode in the new container, first.
- nsresult rv = DeleteNode(aNode);
+ nsresult rv = DeleteNodeWithTransaction(*aNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
{
AutoTransactionsConserveSelection conserveSelection(this);
rv = InsertNodeWithTransaction(*aNode, EditorRawDOMPoint(newContainer, 0));
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1872,24 +1881,24 @@ EditorBase::MoveNode(nsIContent* aNode,
// Need to adjust aOffset if we're moving aNode later in its current parent
if (aParent == oldParent && oldOffset < aOffset) {
// When we delete aNode, it will make the offsets after it off by one
aOffset--;
}
// Hold a reference so aNode doesn't go away when we remove it (bug 772282)
- nsCOMPtr<nsINode> kungFuDeathGrip = aNode;
-
- nsresult rv = DeleteNode(aNode);
+ nsCOMPtr<nsIContent> nodeToBeMoved(aNode);
+ nsresult rv = DeleteNodeWithTransaction(*nodeToBeMoved);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- rv = InsertNodeWithTransaction(*aNode, EditorRawDOMPoint(aParent, aOffset));
+ rv = InsertNodeWithTransaction(*nodeToBeMoved,
+ EditorRawDOMPoint(aParent, aOffset));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void
EditorBase::MoveAllChildren(nsINode& aContainer,
@@ -2870,17 +2879,17 @@ EditorBase::InsertTextIntoTextNodeImpl(c
// longer in the document. This does not break undo/redo, because all these
// txns are wrapped in a parent PlaceHolder txn, and placeholder txns are
// already savvy to having multiple ime txns inside them.
// Delete empty IME text node if there is one
if (isIMETransaction && mComposition) {
Text* textNode = mComposition->GetContainerTextNode();
if (textNode && !textNode->Length()) {
- DeleteNode(textNode);
+ DeleteNodeWithTransaction(*textNode);
mComposition->OnTextNodeRemoved();
static_cast<CompositionTransaction*>(transaction.get())->MarkFixed();
}
}
return rv;
}
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -330,19 +330,21 @@ public:
Text& aTextNode);
NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
EStripWrappers aStripWrappers);
already_AddRefed<Element> DeleteSelectionAndCreateElement(nsAtom& aTag);
/**
- * Helper routines for node/parent manipulations.
+ * DeleteNodeWithTransaction() removes aNode from the DOM tree.
+ *
+ * @param aNode The node which will be removed form the DOM tree.
*/
- nsresult DeleteNode(nsINode* aNode);
+ nsresult DeleteNodeWithTransaction(nsINode& aNode);
/**
* InsertNodeWithTransaction() inserts aContentToInsert before the child
* specified by aPointToInsert.
*
* @param aContentToInsert The node to be inserted.
* @param aPointToInsert The insertion point of aContentToInsert.
* If this refers end of the container, the
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1569,17 +1569,20 @@ HTMLEditRules::WillLoadHTML(Selection* a
// Delete mBogusNode if it exists. If we really need one,
// it will be added during post-processing in AfterEditInner().
if (mBogusNode) {
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_UNEXPECTED;
}
- mHTMLEditor->DeleteNode(mBogusNode);
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+ DebugOnly<nsresult> rv = htmlEditor->DeleteNodeWithTransaction(*mBogusNode);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "Failed to remove the bogus node");
mBogusNode = nullptr;
}
return NS_OK;
}
bool
HTMLEditRules::CanContainParagraph(Element& aElement) const
@@ -2127,30 +2130,30 @@ HTMLEditRules::SplitMailCites(Selection*
if (previousNodeOfSplitPoint) {
nsresult rv =
htmlEditor->IsEmptyNode(previousNodeOfSplitPoint, &bEmptyCite,
true, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (bEmptyCite) {
- rv = htmlEditor->DeleteNode(previousNodeOfSplitPoint);
+ rv = htmlEditor->DeleteNodeWithTransaction(*previousNodeOfSplitPoint);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
if (citeNode) {
nsresult rv = htmlEditor->IsEmptyNode(citeNode, &bEmptyCite, true, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (bEmptyCite) {
- rv = htmlEditor->DeleteNode(citeNode);
+ rv = htmlEditor->DeleteNodeWithTransaction(*citeNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
*aHandled = true;
return NS_OK;
@@ -2362,19 +2365,24 @@ HTMLEditRules::WillDeleteSelection(Selec
return NS_OK;
}
if (wsType == WSType::special || wsType == WSType::br ||
visNode->IsHTMLElement(nsGkAtoms::hr)) {
// Short circuit for invisible breaks. delete them and recurse.
if (visNode->IsHTMLElement(nsGkAtoms::br) &&
(!mHTMLEditor || !mHTMLEditor->IsVisibleBRElement(visNode))) {
- NS_ENSURE_STATE(mHTMLEditor);
- rv = mHTMLEditor->DeleteNode(visNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return NS_ERROR_FAILURE;
+ }
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+ rv = htmlEditor->DeleteNodeWithTransaction(*visNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
return WillDeleteSelection(aSelection, aAction, aStripWrappers,
aCancel, aHandled);
}
// Special handling for backspace when positioned after <hr>
if (aAction == nsIEditor::ePrevious &&
visNode->IsHTMLElement(nsGkAtoms::hr)) {
// Only if the caret is positioned at the end-of-hr-line position, we
@@ -2425,50 +2433,60 @@ HTMLEditRules::WillDeleteSelection(Selec
int32_t otherOffset;
wsObj.NextVisibleNode(EditorRawDOMPoint(startNode, startOffset),
address_of(otherNode),
&otherOffset, &otherWSType);
if (otherWSType == WSType::br) {
// Delete the <br>
-
- NS_ENSURE_STATE(mHTMLEditor);
- nsCOMPtr<nsIContent> otherContent(do_QueryInterface(otherNode));
- rv = WSRunObject::PrepareToDeleteNode(mHTMLEditor, otherContent);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_STATE(mHTMLEditor);
- rv = mHTMLEditor->DeleteNode(otherNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_WARN_IF(!mHTMLEditor) ||
+ NS_WARN_IF(!otherNode->IsContent())) {
+ return NS_ERROR_FAILURE;
+ }
+ nsIContent* otherContent = otherNode->AsContent();
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+ rv = WSRunObject::PrepareToDeleteNode(htmlEditor, otherContent);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ rv = htmlEditor->DeleteNodeWithTransaction(*otherContent);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
return NS_OK;
}
// Else continue with normal delete code
}
+ if (NS_WARN_IF(!mHTMLEditor) ||
+ NS_WARN_IF(!visNode->IsContent())) {
+ return NS_ERROR_FAILURE;
+ }
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
// Found break or image, or hr.
- NS_ENSURE_STATE(mHTMLEditor);
- NS_ENSURE_STATE(visNode->IsContent());
- rv = WSRunObject::PrepareToDeleteNode(mHTMLEditor, visNode->AsContent());
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = WSRunObject::PrepareToDeleteNode(htmlEditor, visNode->AsContent());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// Remember sibling to visnode, if any
- NS_ENSURE_STATE(mHTMLEditor);
- nsCOMPtr<nsIContent> sibling = mHTMLEditor->GetPriorHTMLSibling(visNode);
+ nsCOMPtr<nsIContent> sibling = htmlEditor->GetPriorHTMLSibling(visNode);
// Delete the node, and join like nodes if appropriate
- NS_ENSURE_STATE(mHTMLEditor);
- rv = mHTMLEditor->DeleteNode(visNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*visNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// We did something, so let's say so.
*aHandled = true;
// Is there a prior node and are they siblings?
nsCOMPtr<nsINode> stepbrother;
if (sibling) {
- NS_ENSURE_STATE(mHTMLEditor);
- stepbrother = mHTMLEditor->GetNextHTMLSibling(sibling);
+ stepbrother = htmlEditor->GetNextHTMLSibling(sibling);
}
// Are they both text nodes? If so, join them!
if (startNode == stepbrother && startNode->GetAsText() &&
sibling->GetAsText()) {
EditorDOMPoint pt =
JoinNearestEditableNodesWithTransaction(*sibling,
*startNode->AsContent());
if (NS_WARN_IF(!pt.IsSet())) {
@@ -2524,19 +2542,24 @@ HTMLEditRules::WillDeleteSelection(Selec
} else {
NS_ENSURE_STATE(mHTMLEditor);
leafNode = mHTMLEditor->GetFirstEditableLeaf(*visNode);
leftNode = startNode;
rightNode = leafNode;
}
if (otherNode->IsHTMLElement(nsGkAtoms::br)) {
- NS_ENSURE_STATE(mHTMLEditor);
- rv = mHTMLEditor->DeleteNode(otherNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return NS_ERROR_FAILURE;
+ }
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+ rv = htmlEditor->DeleteNodeWithTransaction(*otherNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// XXX Only in this case, setting "handled" to true only when it
// succeeds?
*aHandled = true;
bDeletedBR = true;
}
// Don't cross table boundaries
if (leftNode && rightNode &&
@@ -2880,17 +2903,18 @@ HTMLEditRules::DeleteNodeIfCollapsedText
}
if (NS_WARN_IF(!mHTMLEditor)) {
return;
}
if (!mHTMLEditor->IsVisibleTextNode(*text)) {
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
- htmlEditor->DeleteNode(&aNode);
+ DebugOnly<nsresult> rv = htmlEditor->DeleteNodeWithTransaction(aNode);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove aNode");
}
}
/**
* InsertBRIfNeeded() determines if a br is needed for current selection to not
* be spastic. If so, it inserts one. Callers responsibility to only call
* with collapsed selection.
@@ -3104,17 +3128,17 @@ HTMLEditRules::TryToJoinBlocksWithTransa
if (NS_WARN_IF(!atRightBlockChild.GetContainer()->GetParentElement())) {
return EditActionIgnored(NS_ERROR_UNEXPECTED);
}
rightBlock = atRightBlockChild.GetContainer()->GetParentElement();
}
}
// Do br adjustment.
- nsCOMPtr<Element> brNode =
+ RefPtr<Element> brNode =
CheckForInvisibleBR(*leftBlock, BRLocation::blockEnd);
EditActionResult ret(NS_OK);
if (NS_WARN_IF(mergeLists)) {
// Since 2002, here was the following comment:
// > The idea here is to take all children in rightList that are past
// > offset, and pull them into leftlist.
// However, this has never been performed because we are here only when
// neither left list nor right list is a descendant of the other but
@@ -3136,17 +3160,18 @@ HTMLEditRules::TryToJoinBlocksWithTransa
-1, atRightBlockChild.Offset());
if (retMoveBlock.Handled()) {
ret.MarkAsHandled();
}
// Now, all children of rightBlock were moved to leftBlock. So,
// atRightBlockChild is now invalid.
atRightBlockChild.Clear();
}
- if (brNode && NS_SUCCEEDED(htmlEditor->DeleteNode(brNode))) {
+ if (brNode &&
+ NS_SUCCEEDED(htmlEditor->DeleteNodeWithTransaction(*brNode))) {
ret.MarkAsHandled();
}
return ret;
}
MOZ_DIAGNOSTIC_ASSERT(!atRightBlockChild.IsSet());
// Offset below is where you find yourself in leftBlock when you traverse
@@ -3180,17 +3205,17 @@ HTMLEditRules::TryToJoinBlocksWithTransa
} else {
if (NS_WARN_IF(!leftBlockChild.GetContainer()->GetParentElement())) {
return EditActionIgnored(NS_ERROR_UNEXPECTED);
}
leftBlock = leftBlockChild.GetContainer()->GetParentElement();
}
}
// Do br adjustment.
- nsCOMPtr<Element> brNode =
+ RefPtr<Element> brNode =
CheckForInvisibleBR(*leftBlock, BRLocation::beforeBlock,
leftBlockChild.Offset());
EditActionResult ret(NS_OK);
if (mergeLists) {
// XXX Why do we ignore the result of MoveContents()?
int32_t offset = leftBlockChild.Offset();
EditActionResult retMoveContents =
MoveContents(*rightList, *leftList, &offset);
@@ -3256,17 +3281,18 @@ HTMLEditRules::TryToJoinBlocksWithTransa
}
ret |= MoveBlock(*previousContent.GetContainerAsElement(), *rightBlock,
previousContent.Offset(), 0);
if (NS_WARN_IF(ret.Failed())) {
return ret;
}
}
- if (brNode && NS_SUCCEEDED(htmlEditor->DeleteNode(brNode))) {
+ if (brNode &&
+ NS_SUCCEEDED(htmlEditor->DeleteNodeWithTransaction(*brNode))) {
ret.MarkAsHandled();
}
return ret;
}
MOZ_DIAGNOSTIC_ASSERT(!atRightBlockChild.IsSet());
MOZ_DIAGNOSTIC_ASSERT(!leftBlockChild.IsSet());
@@ -3298,19 +3324,20 @@ HTMLEditRules::TryToJoinBlocksWithTransa
} else {
// Nodes are dissimilar types.
ret |= MoveBlock(*leftBlock, *rightBlock, -1, 0);
if (NS_WARN_IF(ret.Failed())) {
return ret;
}
}
if (brNode) {
- rv = htmlEditor->DeleteNode(brNode);
- // XXX In other top level if blocks, the result of DeleteNode()
- // is ignored. Why does only this result is respected?
+ rv = htmlEditor->DeleteNodeWithTransaction(*brNode);
+ // XXX In other top level if blocks, the result of
+ // DeleteNodeWithTransaction() is ignored. Why does only this result
+ // is respected?
if (NS_WARN_IF(NS_FAILED(rv))) {
return ret.SetResult(rv);
}
ret.MarkAsHandled();
}
return ret;
}
@@ -3324,30 +3351,36 @@ HTMLEditRules::MoveBlock(Element& aLeftB
// GetNodesFromPoint is the workhorse that figures out what we wnat to move.
nsresult rv = GetNodesFromPoint(EditorDOMPoint(&aRightBlock, aRightOffset),
EditAction::makeList, arrayOfNodes,
TouchContent::yes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionIgnored(rv);
}
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return EditActionIgnored(NS_ERROR_NOT_AVAILABLE);
+ }
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
EditActionResult ret(NS_OK);
for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) {
// get the node to act on
if (IsBlockNode(arrayOfNodes[i])) {
// For block nodes, move their contents only, then delete block.
ret |=
MoveContents(*arrayOfNodes[i]->AsElement(), aLeftBlock, &aLeftOffset);
if (NS_WARN_IF(ret.Failed())) {
return ret;
}
if (NS_WARN_IF(!mHTMLEditor)) {
return ret.SetResult(NS_ERROR_UNEXPECTED);
}
- rv = mHTMLEditor->DeleteNode(arrayOfNodes[i]);
+ rv = htmlEditor->DeleteNodeWithTransaction(*arrayOfNodes[i]);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "Failed to remove a block node");
ret.MarkAsHandled();
} else {
// Otherwise move the content as is, checking against the DTD.
ret |=
MoveNodeSmart(*arrayOfNodes[i]->AsContent(), aLeftBlock, &aLeftOffset);
}
}
@@ -3391,17 +3424,17 @@ HTMLEditRules::MoveNodeSmart(nsIContent&
EditActionResult ret(NS_OK);
if (aNode.IsElement()) {
ret = MoveContents(*aNode.AsElement(), aDestElement, aInOutDestOffset);
if (NS_WARN_IF(ret.Failed())) {
return ret;
}
}
- nsresult rv = htmlEditor->DeleteNode(&aNode);
+ nsresult rv = htmlEditor->DeleteNodeWithTransaction(aNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return ret.SetResult(rv);
}
return ret.MarkAsHandled();
}
EditActionResult
HTMLEditRules::MoveContents(Element& aElement,
@@ -3426,18 +3459,25 @@ HTMLEditRules::MoveContents(Element& aEl
}
nsresult
HTMLEditRules::DeleteNonTableElements(nsINode* aNode)
{
MOZ_ASSERT(aNode);
if (!HTMLEditUtils::IsTableElementButNotTable(aNode)) {
- NS_ENSURE_STATE(mHTMLEditor);
- return mHTMLEditor->DeleteNode(aNode);
+ if (NS_WARN_IF(!mHTMLEditor)) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+ nsresult rv = htmlEditor->DeleteNodeWithTransaction(*aNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
}
AutoTArray<nsCOMPtr<nsIContent>, 10> childList;
for (nsIContent* child = aNode->GetFirstChild();
child; child = child->GetNextSibling()) {
childList.AppendElement(child);
}
@@ -3464,27 +3504,27 @@ HTMLEditRules::DidDeleteSelection(Select
// find where we are
EditorDOMPoint atStartOfSelection(EditorBase::GetStartPoint(aSelection));
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
return NS_ERROR_FAILURE;
}
// find any enclosing mailcite
- nsCOMPtr<Element> citeNode =
+ RefPtr<Element> citeNode =
GetTopEnclosingMailCite(*atStartOfSelection.GetContainer());
if (citeNode) {
bool isEmpty = true, seenBR = false;
htmlEditor->IsEmptyNodeImpl(citeNode, &isEmpty, true, true, false,
&seenBR);
if (isEmpty) {
EditorDOMPoint atCiteNode(citeNode);
{
AutoEditorDOMPointChildInvalidator lockOffset(atCiteNode);
- nsresult rv = htmlEditor->DeleteNode(citeNode);
+ nsresult rv = htmlEditor->DeleteNodeWithTransaction(*citeNode);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
if (atCiteNode.IsSet() && seenBR) {
RefPtr<Element> brNode = htmlEditor->CreateBR(atCiteNode);
if (NS_WARN_IF(!brNode)) {
return NS_ERROR_FAILURE;
@@ -3567,18 +3607,20 @@ HTMLEditRules::WillMakeList(Selection* a
}
// if no nodes, we make empty list. Ditto if the user tried to make a list
// of some # of breaks.
if (arrayOfNodes.IsEmpty() || bOnlyBreaks) {
// if only breaks, delete them
if (bOnlyBreaks) {
for (auto& node : arrayOfNodes) {
- rv = htmlEditor->DeleteNode(node);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*node);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
nsRange* firstRange = aSelection->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
}
@@ -3652,17 +3694,17 @@ HTMLEditRules::WillMakeList(Selection* a
curList = nullptr;
}
// If curNode is a break, delete it, and quit remembering prev list item.
// If an empty inline container, delete it, but still remember the previous
// item.
if (htmlEditor->IsEditable(curNode) && (TextEditUtils::IsBreak(curNode) ||
IsEmptyInline(curNode))) {
- rv = htmlEditor->DeleteNode(curNode);
+ rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
NS_ENSURE_SUCCESS(rv, rv);
if (TextEditUtils::IsBreak(curNode)) {
prevListItem = nullptr;
}
continue;
}
if (HTMLEditUtils::IsList(curNode)) {
@@ -3960,18 +4002,20 @@ HTMLEditRules::MakeBasicBlock(Selection&
// If the first editable node after selection is a br, consume it.
// Otherwise it gets pushed into a following block after the split,
// which is visually bad.
nsCOMPtr<nsIContent> brNode =
htmlEditor->GetNextEditableHTMLNode(pointToInsertBlock);
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock);
- rv = htmlEditor->DeleteNode(brNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*brNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
// Do the splits!
SplitNodeResult splitNodeResult =
htmlEditor->SplitNodeDeepWithTransaction(
*curBlock, pointToInsertBlock,
SplitAtEdges::eDoNotCreateEmptyContainer);
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
@@ -3992,18 +4036,20 @@ HTMLEditRules::MakeBasicBlock(Selection&
return NS_OK;
}
// We are making a block. Consume a br, if needed.
nsCOMPtr<nsIContent> brNode =
htmlEditor->GetNextEditableHTMLNodeInBlock(pointToInsertBlock);
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock);
- rv = htmlEditor->DeleteNode(brNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*brNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// We don't need to act on this node any more
arrayOfNodes.RemoveElement(brNode);
}
// Make sure we can put a block here.
SplitNodeResult splitNodeResult =
MaybeSplitAncestorsForInsertWithTransaction(blockType,
pointToInsertBlock);
if (NS_WARN_IF(splitNodeResult.Failed())) {
@@ -4015,18 +4061,20 @@ HTMLEditRules::MakeBasicBlock(Selection&
if (NS_WARN_IF(!block)) {
return NS_ERROR_FAILURE;
}
// Remember our new block for postprocessing
mNewBlock = block;
// Delete anything that was in the list of nodes
while (!arrayOfNodes.IsEmpty()) {
OwningNonNull<nsINode> curNode = arrayOfNodes[0];
- rv = htmlEditor->DeleteNode(curNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
arrayOfNodes.RemoveElementAt(0);
}
// Put selection in new block
rv = aSelection.Collapse(block, 0);
// Don't restore the selection
selectionRestorer.Abort();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@@ -4169,18 +4217,20 @@ HTMLEditRules::WillCSSIndent(Selection*
return NS_ERROR_FAILURE;
}
// remember our new block for postprocessing
mNewBlock = theBlock;
ChangeIndentation(*theBlock, Change::plus);
// delete anything that was in the list of nodes
while (!arrayOfNodes.IsEmpty()) {
OwningNonNull<nsINode> curNode = arrayOfNodes[0];
- rv = htmlEditor->DeleteNode(curNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
arrayOfNodes.RemoveElementAt(0);
}
// put selection in new block
*aHandled = true;
EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
ErrorResult error;
aSelection->Collapse(atStartOfTheBlock, error);
// Don't restore the selection
@@ -4376,18 +4426,20 @@ HTMLEditRules::WillHTMLIndent(Selection*
if (NS_WARN_IF(!theBlock)) {
return NS_ERROR_FAILURE;
}
// remember our new block for postprocessing
mNewBlock = theBlock;
// delete anything that was in the list of nodes
while (!arrayOfNodes.IsEmpty()) {
OwningNonNull<nsINode> curNode = arrayOfNodes[0];
- rv = htmlEditor->DeleteNode(curNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
arrayOfNodes.RemoveElementAt(0);
}
// put selection in new block
*aHandled = true;
EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
ErrorResult error;
aSelection->Collapse(atStartOfTheBlock, error);
// Don't restore the selection
@@ -4754,18 +4806,20 @@ HTMLEditRules::WillOutdent(Selection& aS
// We have an embedded list, so move it out from under the parent
// list. Be sure to put it after the parent list because this
// loop iterates backwards through the parent's list of children.
rv = htmlEditor->MoveNode(child, curParent, offset + 1);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// Delete any non-list items for now
- rv = htmlEditor->DeleteNode(child);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*child);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
child = curNode->GetLastChild();
}
// Delete the now-empty list
rv = htmlEditor->RemoveBlockContainer(curNode);
NS_ENSURE_SUCCESS(rv, rv);
} else if (useCSS) {
nsCOMPtr<Element> element;
@@ -5180,18 +5234,20 @@ HTMLEditRules::WillAlign(Selection& aSel
// putting our div is not a block, then the br we found is in same block
// we are, so it's safe to consume it.
nsCOMPtr<nsIContent> sibling;
if (pointToInsertDiv.GetChild()) {
sibling = htmlEditor->GetNextHTMLSibling(pointToInsertDiv.GetChild());
}
if (sibling && !IsBlockNode(*sibling)) {
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertDiv);
- rv = htmlEditor->DeleteNode(brContent);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*brContent);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
RefPtr<Element> div =
htmlEditor->CreateNodeWithTransaction(*nsGkAtoms::div, pointToInsertDiv);
if (NS_WARN_IF(!div)) {
return NS_ERROR_FAILURE;
}
// Remember our new block for postprocessing
@@ -5422,19 +5478,19 @@ HTMLEditRules::CheckForEmptyBlock(nsINod
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
// If we are inside an empty block, delete it. Note: do NOT delete table
// elements this way.
- nsCOMPtr<Element> block = htmlEditor->GetBlock(*aStartNode);
+ RefPtr<Element> block = htmlEditor->GetBlock(*aStartNode);
bool bIsEmptyNode;
- nsCOMPtr<Element> emptyBlock;
+ RefPtr<Element> emptyBlock;
if (block && block != aBodyNode) {
// Efficiency hack, avoiding IsEmptyNode() call when in body
nsresult rv = htmlEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
NS_ENSURE_SUCCESS(rv, rv);
while (block && bIsEmptyNode && !HTMLEditUtils::IsTableElement(block) &&
block != aBodyNode) {
emptyBlock = block;
block = htmlEditor->GetBlockNodeParent(emptyBlock);
@@ -5521,18 +5577,20 @@ HTMLEditRules::CheckForEmptyBlock(nsINod
nsresult rv = aSelection->Collapse(afterEmptyBlock);
NS_ENSURE_SUCCESS(rv, rv);
}
} else if (aAction != nsIEditor::eNone) {
MOZ_CRASH("CheckForEmptyBlock doesn't support this action yet");
}
}
*aHandled = true;
- nsresult rv = htmlEditor->DeleteNode(emptyBlock);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsresult rv = htmlEditor->DeleteNodeWithTransaction(*emptyBlock);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
return NS_OK;
}
Element*
HTMLEditRules::CheckForInvisibleBR(Element& aBlock,
BRLocation aWhere,
int32_t aOffset)
@@ -6919,18 +6977,20 @@ HTMLEditRules::ReturnInHeader(Selection&
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
}
}
}
// If the new (righthand) header node is empty, delete it
if (IsEmptyBlockElement(aHeader, IgnoreSingleBR::eYes)) {
- rv = htmlEditor->DeleteNode(&aHeader);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(aHeader);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// Layout tells the caret to blink in a weird place if we don't place a
// break after the header.
nsCOMPtr<nsIContent> sibling;
if (aHeader.GetNextSibling()) {
sibling = htmlEditor->GetNextHTMLSibling(aHeader.GetNextSibling());
}
if (!sibling || !sibling->IsHTMLElement(nsGkAtoms::br)) {
ClearCachedStyles();
@@ -7208,18 +7268,20 @@ HTMLEditRules::SplitParagraph(
}
if (NS_WARN_IF(!splitDivOrPResult.DidSplit())) {
return NS_ERROR_FAILURE;
}
// Get rid of the break, if it is visible (otherwise it may be needed to
// prevent an empty p).
if (aNextBRNode && htmlEditor->IsVisibleBRElement(aNextBRNode)) {
- rv = htmlEditor->DeleteNode(aNextBRNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*aNextBRNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
// Remove ID attribute on the paragraph from the existing right node.
rv = htmlEditor->RemoveAttribute(aParentDivOrP.AsElement(), nsGkAtoms::id);
NS_ENSURE_SUCCESS(rv, rv);
// We need to ensure to both paragraphs visible even if they are empty.
// However, moz-<br> element isn't useful in this case because moz-<br>
@@ -7299,18 +7361,20 @@ HTMLEditRules::ReturnInListItem(Selectio
htmlEditor->MoveNode(&aListItem,
atNextSiblingOfLeftList.GetContainer(),
atNextSiblingOfLeftList.Offset());
NS_ENSURE_SUCCESS(rv, rv);
rv = aSelection.Collapse(&aListItem, 0);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// Otherwise kill this item
- nsresult rv = htmlEditor->DeleteNode(&aListItem);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsresult rv = htmlEditor->DeleteNodeWithTransaction(aListItem);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// Time to insert a paragraph
nsAtom& paraAtom = DefaultParagraphSeparator();
// We want a wrapper even if we separate with <br>
RefPtr<Element> pNode =
htmlEditor->CreateNodeWithTransaction(¶Atom == nsGkAtoms::br ?
*nsGkAtoms::p : paraAtom,
atNextSiblingOfLeftList);
@@ -7381,21 +7445,25 @@ HTMLEditRules::ReturnInListItem(Selectio
MOZ_DIAGNOSTIC_ASSERT(itemOffset != -1);
EditorRawDOMPoint atNextListItem(list, aListItem.GetNextSibling(),
itemOffset + 1);
RefPtr<Element> newListItem =
htmlEditor->CreateNodeWithTransaction(*listAtom, atNextListItem);
if (NS_WARN_IF(!newListItem)) {
return NS_ERROR_FAILURE;
}
- rv = htmlEditor->DeleteNode(&aListItem);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = aSelection.Collapse(newListItem, 0);
- NS_ENSURE_SUCCESS(rv, rv);
-
+ rv = htmlEditor->DeleteNodeWithTransaction(aListItem);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ ErrorResult error;
+ aSelection.Collapse(EditorRawDOMPoint(newListItem, 0), error);
+ if (NS_WARN_IF(error.Failed())) {
+ return error.StealNSResult();
+ }
return NS_OK;
}
nsCOMPtr<Element> brNode;
rv = htmlEditor->CopyLastEditableChildStyles(prevItem,
&aListItem,
getter_AddRefs(brNode));
NS_ENSURE_SUCCESS(rv, rv);
@@ -7694,18 +7762,20 @@ HTMLEditRules::ApplyBlockStyle(nsTArray<
}
if (curNode->IsHTMLElement(nsGkAtoms::br)) {
// If the node is a break, we honor it by putting further nodes in a new
// parent
if (curBlock) {
// Forget any previous block used for previous inline nodes
curBlock = nullptr;
- nsresult rv = htmlEditor->DeleteNode(curNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsresult rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
continue;
}
// The break is the first (or even only) node we encountered. Create a
// block for it.
SplitNodeResult splitNodeResult =
MaybeSplitAncestorsForInsertWithTransaction(aBlockTag, atCurNode);
if (NS_WARN_IF(splitNodeResult.Failed())) {
@@ -8573,18 +8643,20 @@ HTMLEditRules::RemoveEmptyNodes()
}
iter->Next();
}
// now delete the empty nodes
for (OwningNonNull<nsINode>& delNode : arrayOfEmptyNodes) {
if (htmlEditor->IsModifiableNode(delNode)) {
- rv = htmlEditor->DeleteNode(delNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*delNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
// Now delete the empty mailcites. This is a separate step because we want
// to pull out any br's and preserve them.
for (OwningNonNull<nsINode>& delNode : arrayOfEmptyCites) {
bool bIsEmptyNode;
rv = htmlEditor->IsEmptyNode(delNode, &bIsEmptyNode, false, true);
@@ -8592,18 +8664,20 @@ HTMLEditRules::RemoveEmptyNodes()
if (!bIsEmptyNode) {
// We are deleting a cite that has just a br. We want to delete cite,
// but preserve br.
RefPtr<Element> br = htmlEditor->CreateBR(EditorRawDOMPoint(delNode));
if (NS_WARN_IF(!br)) {
return NS_ERROR_FAILURE;
}
}
- rv = htmlEditor->DeleteNode(delNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*delNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
return NS_OK;
}
nsresult
HTMLEditRules::SelectionEndpointInNode(nsINode* aNode,
bool* aResult)
@@ -8798,18 +8872,20 @@ HTMLEditRules::RemoveListStructure(Eleme
nsresult rv = PopListItem(child, &isOutOfList);
NS_ENSURE_SUCCESS(rv, rv);
} while (!isOutOfList);
} else if (HTMLEditUtils::IsList(child)) {
nsresult rv = RemoveListStructure(*child->AsElement());
NS_ENSURE_SUCCESS(rv, rv);
} else {
// Delete any non-list items for now
- nsresult rv = htmlEditor->DeleteNode(child);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsresult rv = htmlEditor->DeleteNodeWithTransaction(*child);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
// Delete the now-empty list
nsresult rv = htmlEditor->RemoveBlockContainer(aList);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@@ -9428,18 +9504,20 @@ HTMLEditRules::WillAbsolutePosition(Sele
if (NS_WARN_IF(!positionedDiv)) {
return NS_ERROR_FAILURE;
}
// Remember our new block for postprocessing
mNewBlock = positionedDiv;
// Delete anything that was in the list of nodes
while (!arrayOfNodes.IsEmpty()) {
OwningNonNull<nsINode> curNode = arrayOfNodes[0];
- rv = htmlEditor->DeleteNode(curNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
arrayOfNodes.RemoveElementAt(0);
}
// Put selection in new block
*aHandled = true;
rv = aSelection.Collapse(positionedDiv, 0);
// Don't restore the selection
selectionRestorer.Abort();
NS_ENSURE_SUCCESS(rv, rv);
@@ -9687,29 +9765,32 @@ HTMLEditRules::DocumentModified()
void
HTMLEditRules::DocumentModifiedWorker()
{
if (!mHTMLEditor) {
return;
}
- // DeleteNode below may cause a flush, which could destroy the editor
+ // DeleteNodeWithTransaction() below may cause a flush, which could destroy
+ // the editor
nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
RefPtr<Selection> selection = htmlEditor->GetSelection();
if (!selection) {
return;
}
// Delete our bogus node, if we have one, since the document might not be
// empty any more.
if (mBogusNode) {
- htmlEditor->DeleteNode(mBogusNode);
+ DebugOnly<nsresult> rv = htmlEditor->DeleteNodeWithTransaction(*mBogusNode);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "Failed to remove the bogus node");
mBogusNode = nullptr;
}
// Try to recreate the bogus node if needed.
CreateBogusNodeIfNeeded(selection);
}
} // namespace mozilla
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1251,17 +1251,17 @@ HTMLEditor::ReplaceHeadContentsWithHTML(
err.ErrorCodeAsInt());
#endif
return err.StealNSResult();
}
NS_ENSURE_TRUE(docfrag, NS_ERROR_NULL_POINTER);
// First delete all children in head
while (nsCOMPtr<nsIContent> child = headNode->GetFirstChild()) {
- nsresult rv = DeleteNode(child);
+ nsresult rv = DeleteNodeWithTransaction(*child);
NS_ENSURE_SUCCESS(rv, rv);
}
// Now insert the new nodes
int32_t offsetOfNewNode = 0;
// Loop over the contents of the fragment and move into the document
while (nsCOMPtr<nsIContent> child = docfrag->GetFirstChild()) {
@@ -3184,40 +3184,55 @@ HTMLEditor::DeleteSelectionImpl(EDirecti
if (content && !IsBlockNode(content) && !content->Length() &&
content->IsEditable() && content != content->GetEditingHost()) {
while (content->GetParent() && !IsBlockNode(content->GetParent()) &&
content->GetParent()->Length() == 1 &&
content->GetParent()->IsEditable() &&
content->GetParent() != content->GetEditingHost()) {
content = content->GetParent();
}
- rv = DeleteNode(content);
+ rv = DeleteNodeWithTransaction(*content);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult
-HTMLEditor::DeleteNode(nsINode* aNode)
+HTMLEditor::DeleteNodeWithTransaction(nsINode& aNode)
{
- return DeleteNode(aNode->AsDOMNode());
+ if (NS_WARN_IF(!aNode.IsContent())) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ // Do nothing if the node is read-only.
+ // XXX This is not a override method of EditorBase's method. This might
+ // cause not called accidentally. We need to investigate this issue.
+ if (NS_WARN_IF(!IsModifiableNode(aNode.AsContent()) &&
+ !IsMozEditorBogusNode(aNode.AsContent()))) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = EditorBase::DeleteNodeWithTransaction(aNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
}
NS_IMETHODIMP
-HTMLEditor::DeleteNode(nsIDOMNode* aNode)
+HTMLEditor::DeleteNode(nsIDOMNode* aDOMNode)
{
- // do nothing if the node is read-only
- nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
- if (NS_WARN_IF(!IsModifiableNode(content) &&
- !IsMozEditorBogusNode(content))) {
- return NS_ERROR_FAILURE;
- }
-
- return EditorBase::DeleteNode(aNode);
+ nsCOMPtr<nsINode> node = do_QueryInterface(aDOMNode);
+ if (NS_WARN_IF(!node)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ nsresult rv = DeleteNodeWithTransaction(*node);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
}
nsresult
HTMLEditor::DeleteText(CharacterData& aCharData,
uint32_t aOffset,
uint32_t aLength)
{
// Do nothing if the node is read-only
@@ -4463,30 +4478,34 @@ HTMLEditor::AreNodesSameType(nsIContent*
aNode2->AsElement());
}
nsresult
HTMLEditor::CopyLastEditableChildStyles(nsINode* aPreviousBlock,
nsINode* aNewBlock,
Element** aOutBrNode)
{
- nsCOMPtr<nsINode> newBlock = do_QueryInterface(aNewBlock);
- NS_ENSURE_STATE(newBlock || !aNewBlock);
+ if (NS_WARN_IF(!aNewBlock)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ nsCOMPtr<nsINode> newBlock(aNewBlock);
*aOutBrNode = nullptr;
- nsCOMPtr<nsINode> child, tmp;
- // first, clear out aNewBlock. Contract is that we want only the styles from previousBlock.
- child = aNewBlock->GetFirstChild();
- while (child) {
- nsresult rv = DeleteNode(child);
- NS_ENSURE_SUCCESS(rv, rv);
- child = aNewBlock->GetFirstChild();
+ // First, clear out aNewBlock. Contract is that we want only the styles
+ // from aPreviousBlock.
+ for (nsCOMPtr<nsINode> child = aNewBlock->GetFirstChild();
+ child;
+ child = aNewBlock->GetFirstChild()) {
+ nsresult rv = DeleteNodeWithTransaction(*child);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
// now find and clone the styles
- child = aPreviousBlock;
- tmp = aPreviousBlock;
+ nsCOMPtr<nsINode> child = aPreviousBlock;
+ nsCOMPtr<nsINode> tmp = aPreviousBlock;
while (tmp) {
child = tmp;
tmp = GetLastEditableChild(*child);
}
while (child && TextEditUtils::IsBreak(child)) {
child = GetPreviousEditableHTMLNode(*child);
}
nsCOMPtr<Element> newStyles, deepestStyle;
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -380,18 +380,28 @@ public:
*/
nsresult CollapseAdjacentTextNodes(nsRange* aRange);
virtual bool AreNodesSameType(nsIContent* aNode1,
nsIContent* aNode2) override;
NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
EStripWrappers aStripWrappers) override;
- nsresult DeleteNode(nsINode* aNode);
+
+ /**
+ * DeleteNodeWithTransaction() removes aNode from the DOM tree if it's
+ * modifiable. Note that this is not an override of same method of
+ * EditorBase.
+ *
+ * @param aNode The node to be removed from the DOM tree.
+ */
+ nsresult DeleteNodeWithTransaction(nsINode& aNode);
+
NS_IMETHOD DeleteNode(nsIDOMNode* aNode) override;
+
nsresult DeleteText(dom::CharacterData& aTextNode, uint32_t aOffset,
uint32_t aLength);
virtual nsresult
InsertTextImpl(nsIDocument& aDocument,
const nsAString& aStringToInsert,
const EditorRawDOMPoint& aPointToInsert,
EditorRawDOMPoint* aPointAfterInsertedString =
nullptr) override;
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -351,18 +351,20 @@ HTMLEditor::DoInsertHTMLWithContext(cons
// if there are any invisible br's after our insertion point, remove them.
// this is because if there is a br at end of what we paste, it will make
// the invisible br visible.
WSRunObject wsObj(this, pointToInsert);
if (wsObj.mEndReasonNode &&
TextEditUtils::IsBreak(wsObj.mEndReasonNode) &&
!IsVisibleBRElement(wsObj.mEndReasonNode)) {
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert);
- rv = DeleteNode(wsObj.mEndReasonNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = DeleteNodeWithTransaction(*wsObj.mEndReasonNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
// Remember if we are in a link.
bool bStartedInLink = IsInLink(pointToInsert.GetContainer());
// Are we in a text node? If so, split it.
if (pointToInsert.IsInTextNode()) {
SplitNodeResult splitNodeResult =
@@ -486,17 +488,17 @@ HTMLEditor::DoInsertHTMLWithContext(cons
if (HTMLEditUtils::IsListItem(pointToInsert.GetContainer())) {
bool isEmpty;
rv = IsEmptyNode(pointToInsert.GetContainer(), &isEmpty, true);
if (NS_SUCCEEDED(rv) && isEmpty) {
if (NS_WARN_IF(!pointToInsert.GetContainer()->
GetParentNode())) {
// Is it an orphan node?
} else {
- DeleteNode(pointToInsert.GetContainer());
+ DeleteNodeWithTransaction(*pointToInsert.GetContainer());
pointToInsert.Set(pointToInsert.GetContainer());
}
}
}
EditorDOMPoint insertedPoint =
InsertNodeIntoProperAncestor(
*firstChild, pointToInsert,
SplitAtEdges::eDoNotCreateEmptyContainer);
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -591,18 +591,20 @@ HTMLEditor::ClearStyle(nsCOMPtr<nsINode>
getter_AddRefs(rightNode));
NS_ENSURE_SUCCESS(rv, rv);
if (leftNode) {
bool bIsEmptyNode;
IsEmptyNode(leftNode, &bIsEmptyNode, false, true);
if (bIsEmptyNode) {
// delete leftNode if it became empty
- rv = DeleteNode(leftNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = DeleteNodeWithTransaction(*leftNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
if (rightNode) {
nsCOMPtr<nsINode> secondSplitParent = GetLeftmostChild(rightNode);
// don't try to split non-containers (br's, images, hr's, etc.)
if (!secondSplitParent) {
secondSplitParent = rightNode;
}
@@ -622,18 +624,20 @@ HTMLEditor::ClearStyle(nsCOMPtr<nsINode>
getter_AddRefs(rightNode));
NS_ENSURE_SUCCESS(rv, rv);
if (rightNode) {
bool bIsEmptyNode;
IsEmptyNode(rightNode, &bIsEmptyNode, false, true);
if (bIsEmptyNode) {
// delete rightNode if it became empty
- rv = DeleteNode(rightNode);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = DeleteNodeWithTransaction(*rightNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
if (!leftNode) {
return NS_OK;
}
// should be impossible to not get a new leftnode here
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -833,18 +833,24 @@ HTMLEditor::DeleteTableCell(int32_t aNum
}
if (!deleteCol) {
// First get the next cell to delete
nsCOMPtr<nsIDOMElement> nextCell;
rv = GetNextSelectedCell(nullptr, getter_AddRefs(nextCell));
NS_ENSURE_SUCCESS(rv, rv);
// Then delete the cell
- rv = DeleteNode(cell);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsINode> cellToBeRemoved = do_QueryInterface(cell);
+ if (NS_WARN_IF(!cellToBeRemoved)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = DeleteNodeWithTransaction(*cellToBeRemoved);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
// The next cell to delete
cell = nextCell;
if (cell) {
rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
NS_ENSURE_SUCCESS(rv, rv);
}
}
@@ -886,20 +892,25 @@ HTMLEditor::DeleteTableCell(int32_t aNum
// More than 1 cell in the row
// The setCaret object will call AutoSelectionSetterAfterTableEdit in its
// destructor
AutoSelectionSetterAfterTableEdit setCaret(*this, table, startRowIndex,
startColIndex, ePreviousColumn,
false);
AutoTransactionsConserveSelection dontChangeSelection(this);
-
- rv = DeleteNode(cell);
+ nsCOMPtr<nsINode> cellToBeRemoved = do_QueryInterface(cell);
+ if (NS_WARN_IF(!cellToBeRemoved)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = DeleteNodeWithTransaction(*cellToBeRemoved);
// If we fail, don't try to delete any more cells???
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
}
return NS_OK;
}
NS_IMETHODIMP
HTMLEditor::DeleteTableCellContents()
@@ -958,18 +969,20 @@ HTMLEditor::DeleteCellContents(nsIDOMEle
{
nsCOMPtr<Element> cell = do_QueryInterface(aCell);
NS_ENSURE_TRUE(cell, NS_ERROR_NULL_POINTER);
// Prevent rules testing until we're done
AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
while (nsCOMPtr<nsINode> child = cell->GetLastChild()) {
- nsresult rv = DeleteNode(child);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsresult rv = DeleteNodeWithTransaction(*child);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
return NS_OK;
}
NS_IMETHODIMP
HTMLEditor::DeleteTableColumn(int32_t aNumber)
{
RefPtr<Selection> selection;
@@ -1116,18 +1129,24 @@ HTMLEditor::DeleteColumn(nsIDOMElement*
rv = DeleteRow(aTable, startRowIndex);
NS_ENSURE_SUCCESS(rv, rv);
// Note that we don't incremenet rowIndex
// since a row was deleted and "next"
// row now has current rowIndex
} else {
// A more "normal" deletion
- rv = DeleteNode(cell);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsINode> cellToBeRemoved = do_QueryInterface(cell);
+ if (NS_WARN_IF(!cellToBeRemoved)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = DeleteNodeWithTransaction(*cellToBeRemoved);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
//Skip over any rows spanned by this cell
rowIndex += actualRowSpan;
}
}
}
} while (cell);
@@ -1307,18 +1326,24 @@ HTMLEditor::DeleteRow(nsIDOMElement* aTa
// Delete the entire row
nsCOMPtr<nsIDOMElement> parentRow;
rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cellInDeleteRow,
getter_AddRefs(parentRow));
NS_ENSURE_SUCCESS(rv, rv);
if (parentRow) {
- rv = DeleteNode(parentRow);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsINode> rowToBeRemoved = do_QueryInterface(parentRow);
+ if (NS_WARN_IF(!rowToBeRemoved)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = DeleteNodeWithTransaction(*rowToBeRemoved);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
// Now we can set new rowspans for cells stored above
for (uint32_t i = 0, n = spanCellList.Length(); i < n; i++) {
nsIDOMElement *cellPtr = spanCellList[i];
if (cellPtr) {
rv = SetRowSpan(cellPtr, newSpanList[i]);
NS_ENSURE_SUCCESS(rv, rv);
@@ -2164,19 +2189,24 @@ HTMLEditor::JoinTableCells(bool aMergeNo
// All cell contents are merged. Delete the empty cells we accumulated
// Prevent rules testing until we're done
AutoRules beginRulesSniffing(this, EditAction::deleteNode,
nsIEditor::eNext);
for (uint32_t i = 0, n = deleteList.Length(); i < n; i++) {
nsIDOMElement *elementPtr = deleteList[i];
if (elementPtr) {
- nsCOMPtr<nsIDOMNode> node = do_QueryInterface(elementPtr);
- rv = DeleteNode(node);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsINode> nodeToBeRemoved = do_QueryInterface(elementPtr);
+ if (NS_WARN_IF(!nodeToBeRemoved)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = DeleteNodeWithTransaction(*nodeToBeRemoved);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
}
}
// Cleanup selection: remove ranges where cells were deleted
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
uint32_t rangeCount = selection->RangeCount();
@@ -2288,44 +2318,60 @@ HTMLEditor::MergeCells(nsCOMPtr<nsIDOMEl
// we insert at index 0
int32_t insertIndex = 0;
// Start inserting just after last child
uint32_t len = targetCell->GetChildCount();
if (len == 1 && IsEmptyCell(targetCell)) {
// Delete the empty node
nsIContent* cellChild = targetCell->GetFirstChild();
- nsresult rv = DeleteNode(cellChild->AsDOMNode());
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_WARN_IF(!cellChild)) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = DeleteNodeWithTransaction(*cellChild);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
insertIndex = 0;
} else {
insertIndex = (int32_t)len;
}
// Move the contents
while (cellToMerge->HasChildren()) {
nsCOMPtr<nsIContent> cellChild = cellToMerge->GetLastChild();
- // XXX We need HTMLEditor::DeleteNode(nsINode&).
- nsresult rv = DeleteNode(cellChild->AsDOMNode());
- NS_ENSURE_SUCCESS(rv, rv);
-
+ if (NS_WARN_IF(!cellChild)) {
+ return NS_ERROR_FAILURE;
+ }
+ nsresult rv = DeleteNodeWithTransaction(*cellChild);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
rv = InsertNodeWithTransaction(*cellChild,
EditorRawDOMPoint(aTargetCell,
insertIndex));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
- // Delete cells whose contents were moved
- if (aDeleteCellToMerge) {
- return DeleteNode(aCellToMerge);
+ if (!aDeleteCellToMerge) {
+ return NS_OK;
}
+ // Delete cells whose contents were moved.
+ nsCOMPtr<nsIContent> cellToBeRemoved = do_QueryInterface(aCellToMerge);
+ if (NS_WARN_IF(!cellToBeRemoved)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ nsresult rv = DeleteNodeWithTransaction(*cellToBeRemoved);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
return NS_OK;
}
nsresult
HTMLEditor::FixBadRowSpan(nsIDOMElement* aTable,
int32_t aRowIndex,
int32_t& aNewRowCount)
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -382,18 +382,23 @@ TextEditRules::WillInsert(Selection& aSe
return;
}
// initialize out param
*aCancel = false;
// check for the magic content node and delete it if it exists
if (mBogusNode) {
- NS_ENSURE_TRUE_VOID(mTextEditor);
- mTextEditor->DeleteNode(mBogusNode);
+ if (NS_WARN_IF(!mTextEditor)) {
+ return; // XXX Shouldn't we release mBogusNode now?
+ }
+ RefPtr<TextEditor> textEditor(mTextEditor);
+ DebugOnly<nsresult> rv = textEditor->DeleteNodeWithTransaction(*mBogusNode);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "Failed to remove the bogus node");
mBogusNode = nullptr;
}
}
nsresult
TextEditRules::DidInsert(Selection* aSelection,
nsresult aResult)
{
@@ -1083,17 +1088,19 @@ TextEditRules::DidDeleteSelection(Select
// Delete empty text nodes at selection.
if (selectionStartPoint.IsInTextNode() &&
!selectionStartPoint.GetContainer()->Length()) {
if (NS_WARN_IF(!mTextEditor)) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<TextEditor> textEditor(mTextEditor);
- nsresult rv = textEditor->DeleteNode(selectionStartPoint.GetContainer());
+ nsresult rv =
+ textEditor->DeleteNodeWithTransaction(
+ *selectionStartPoint.GetContainer());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Be aware, mTextEditor may be nullptr here.
}
if (mDidExplicitlySetInterline) {
return NS_OK;
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -1357,21 +1357,24 @@ WSRunObject::DeleteRange(const EditorDOM
// MOOSE: this routine needs to be modified to preserve the integrity of the
// wsFragment info.
if (aStartPoint == aEndPoint) {
// Nothing to delete
return NS_OK;
}
+ MOZ_ASSERT(mHTMLEditor);
+ RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+
if (aStartPoint.GetContainer() == aEndPoint.GetContainer() &&
aStartPoint.IsInTextNode()) {
- return mHTMLEditor->DeleteText(*aStartPoint.GetContainerAsText(),
- aStartPoint.Offset(),
- aEndPoint.Offset() - aStartPoint.Offset());
+ return htmlEditor->DeleteText(*aStartPoint.GetContainerAsText(),
+ aStartPoint.Offset(),
+ aEndPoint.Offset() - aStartPoint.Offset());
}
RefPtr<nsRange> range;
int32_t count = mNodeArray.Length();
int32_t idx = mNodeArray.IndexOf(aStartPoint.GetContainer());
if (idx == -1) {
// If our starting point wasn't one of our ws text nodes, then just go
// through them from the beginning.
@@ -1381,26 +1384,26 @@ WSRunObject::DeleteRange(const EditorDOM
RefPtr<Text> node = mNodeArray[idx];
if (!node) {
// We ran out of ws nodes; must have been deleting to end
return NS_OK;
}
if (node == aStartPoint.GetContainer()) {
if (!aStartPoint.IsEndOfContainer()) {
nsresult rv =
- mHTMLEditor->DeleteText(*node, aStartPoint.Offset(),
- aStartPoint.GetContainer()->Length() -
- aStartPoint.Offset());
+ htmlEditor->DeleteText(*node, aStartPoint.Offset(),
+ aStartPoint.GetContainer()->Length() -
+ aStartPoint.Offset());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
} else if (node == aEndPoint.GetContainer()) {
if (!aEndPoint.IsStartOfContainer()) {
- nsresult rv = mHTMLEditor->DeleteText(*node, 0, aEndPoint.Offset());
+ nsresult rv = htmlEditor->DeleteText(*node, 0, aEndPoint.Offset());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
break;
} else {
if (!range) {
range = new nsRange(aStartPoint.GetContainer());
@@ -1414,17 +1417,17 @@ WSRunObject::DeleteRange(const EditorDOM
nsRange::CompareNodeToRange(node, range, &nodeBefore, &nodeAfter);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (nodeAfter) {
break;
}
if (!nodeBefore) {
- rv = mHTMLEditor->DeleteNode(node);
+ rv = htmlEditor->DeleteNodeWithTransaction(*node);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mNodeArray.RemoveElement(node);
--count;
--idx;
}
}