Bug 1460509 - part 69: Make HTMLEditRules::MakeBasicBlock() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato
MozReview-Commit-ID: Gfnai2runLs
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1913,17 +1913,24 @@ HTMLEditRules::WillInsertBreak(bool* aCa
*aHandled = true;
return NS_OK;
}
if (host == blockParent && separator != ParagraphSeparator::br) {
// Insert a new block first
MOZ_ASSERT(separator == ParagraphSeparator::div ||
separator == ParagraphSeparator::p);
+ // MakeBasicBlock() creates AutoSelectionRestorer.
+ // Therefore, even if it returns NS_OK, editor might have been destroyed
+ // at restoring Selection.
nsresult rv = MakeBasicBlock(ParagraphSeparatorElement(separator));
+ if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED) ||
+ NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
// We warn on failure, but don't handle it, because it might be harmless.
// Instead we just check that a new block was actually created.
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditRules::MakeBasicBlock() failed");
firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
@@ -4322,32 +4329,39 @@ HTMLEditRules::WillMakeBasicBlock(const
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return NS_ERROR_EDITOR_DESTROYED;
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
*aCancel = false;
*aHandled = true;
+ // MakeBasicBlock() creates AutoSelectionRestorer.
+ // Therefore, even if it returns NS_OK, editor might have been destroyed
+ // at restoring Selection.
rv = MakeBasicBlock(blockType);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
HTMLEditRules::MakeBasicBlock(nsAtom& blockType)
{
MOZ_ASSERT(IsEditorDataAvailable());
nsresult rv = NormalizeSelection();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+
AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
// Contruct a list of nodes to act on.
nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
rv = GetNodesFromSelection(EditAction::makeBasicBlock, arrayOfNodes,
TouchContent::yes);
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -4377,88 +4391,113 @@ HTMLEditRules::MakeBasicBlock(nsAtom& bl
// 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> brContent =
HTMLEditorRef().GetNextEditableHTMLNode(pointToInsertBlock);
if (brContent && brContent->IsHTMLElement(nsGkAtoms::br)) {
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock);
rv = HTMLEditorRef().DeleteNodeWithTransaction(*brContent);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// Do the splits!
SplitNodeResult splitNodeResult =
HTMLEditorRef().SplitNodeDeepWithTransaction(
*curBlock, pointToInsertBlock,
SplitAtEdges::eDoNotCreateEmptyContainer);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
}
EditorRawDOMPoint pointToInsertBrNode(splitNodeResult.SplitPoint());
// Put a <br> element at the split point
brContent =
HTMLEditorRef().InsertBrElementWithTransaction(SelectionRef(),
pointToInsertBrNode);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!brContent)) {
return NS_ERROR_FAILURE;
}
// Put selection at the split point
EditorRawDOMPoint atBrNode(brContent);
+ // Don't restore the selection
+ selectionRestorer.Abort();
ErrorResult error;
SelectionRef().Collapse(atBrNode, error);
- // Don't restore the selection
- selectionRestorer.Abort();
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ error.SuppressException();
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
return NS_OK;
}
// We are making a block. Consume a br, if needed.
nsCOMPtr<nsIContent> brNode =
HTMLEditorRef().GetNextEditableHTMLNodeInBlock(pointToInsertBlock);
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock);
rv = HTMLEditorRef().DeleteNodeWithTransaction(*brNode);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
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())) {
return splitNodeResult.Rv();
}
RefPtr<Element> block =
HTMLEditorRef().CreateNodeWithTransaction(blockType,
splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
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 = HTMLEditorRef().DeleteNodeWithTransaction(*curNode);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
arrayOfNodes.RemoveElementAt(0);
}
+ // Don't restore the selection
+ selectionRestorer.Abort();
// Put selection in new block
rv = SelectionRef().Collapse(block, 0);
- // Don't restore the selection
- selectionRestorer.Abort();
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
// Okay, now go through all the nodes and make the right kind of blocks, or
// whatever is approriate. Woohoo! Note: blockquote is handled a little
// differently.
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -400,17 +400,31 @@ protected:
*/
MOZ_MUST_USE nsresult
WillRelativeChangeZIndex(int32_t aChange, bool* aCancel, bool* aHandled);
nsresult WillMakeDefListItem(const nsAString* aBlockType, bool aEntireList,
bool* aCancel, bool* aHandled);
nsresult WillMakeBasicBlock(const nsAString& aBlockType,
bool* aCancel, bool* aHandled);
- nsresult MakeBasicBlock(nsAtom& aBlockType);
+
+ /**
+ * MakeBasicBlock() applies or clears block style around Selection.
+ * This method creates AutoSelectionRestorer. Therefore, each caller
+ * need to check if the editor is still available even if this returns
+ * NS_OK.
+ *
+ * @param aBlockType New block tag name.
+ * If nsGkAtoms::normal or nsGkAtoms::_empty,
+ * RemoveBlockStyle() will be called.
+ * If nsGkAtoms::blockquote, MakeBlockquote()
+ * will be called.
+ * Otherwise, ApplyBlockStyle() will be called.
+ */
+ MOZ_MUST_USE nsresult MakeBasicBlock(nsAtom& aBlockType);
/**
* Called after creating a basic block, indenting, outdenting or aligning
* contents. This method inserts moz-<br> element if start container of
* Selection needs it.
*/
MOZ_MUST_USE nsresult DidMakeBasicBlock();