Bug 1460509 - part 65: Make HTMLEditRules::WillHTMLIndent() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato
MozReview-Commit-ID: 2jZh8GtC7BA
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -4801,30 +4801,49 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
*aCancel = false;
*aHandled = true;
rv = NormalizeSelection();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+ // IndentAroundSelectionWithHTML() creates AutoSelectionRestorer.
+ // Therefore, even if it returns NS_OK, editor might have been destroyed
+ // at restoring Selection.
+ rv = IndentAroundSelectionWithHTML();
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
+}
+
+nsresult
+HTMLEditRules::IndentAroundSelectionWithHTML()
+{
+ MOZ_ASSERT(IsEditorDataAvailable());
+
AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
nsTArray<RefPtr<nsRange>> arrayOfRanges;
GetPromotedRanges(arrayOfRanges, EditAction::indent);
// use these ranges to contruct a list of nodes to act on.
nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
- rv = GetNodesForOperation(arrayOfRanges, arrayOfNodes, EditAction::indent,
- TouchContent::yes);
+ nsresult rv =
+ GetNodesForOperation(arrayOfRanges, arrayOfNodes, EditAction::indent,
+ TouchContent::yes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// if nothing visible in list, make an empty block
if (ListIsEmptyLine(arrayOfNodes)) {
nsRange* firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
@@ -4841,37 +4860,45 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
atStartOfSelection);
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
}
RefPtr<Element> theBlock =
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::blockquote,
splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
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 = 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);
}
- // put selection in new block
- *aHandled = true;
EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
+ // Don't restore the selection
+ selectionRestorer.Abort();
ErrorResult error;
SelectionRef().Collapse(atStartOfTheBlock, 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;
}
// Ok, now go through all the nodes and put them in a blockquote,
// or whatever is appropriate. Wohoo!
@@ -4898,16 +4925,19 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
if (sibling && HTMLEditUtils::IsList(sibling) &&
atCurNode.GetContainer()->NodeInfo()->NameAtom() ==
sibling->NodeInfo()->NameAtom() &&
atCurNode.GetContainer()->NodeInfo()->NamespaceID() ==
sibling->NodeInfo()->NamespaceID()) {
rv = HTMLEditorRef().MoveNodeWithTransaction(
*curNode->AsContent(),
EditorRawDOMPoint(sibling, 0));
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
continue;
}
// Check for whether we should join a list that preceeds curNode.
// We do this if the previous element is a list, and the list is of
@@ -4915,16 +4945,19 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
sibling = HTMLEditorRef().GetPriorHTMLSibling(curNode);
if (sibling && HTMLEditUtils::IsList(sibling) &&
atCurNode.GetContainer()->NodeInfo()->NameAtom() ==
sibling->NodeInfo()->NameAtom() &&
atCurNode.GetContainer()->NodeInfo()->NamespaceID() ==
sibling->NodeInfo()->NamespaceID()) {
rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*curNode->AsContent(),
*sibling);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
continue;
}
// check to see if curList is still appropriate. Which it is if
// curNode is still right after it in the same list.
@@ -4941,26 +4974,32 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
MaybeSplitAncestorsForInsertWithTransaction(*containerName,
atCurNode);
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
}
curList =
HTMLEditorRef().CreateNodeWithTransaction(
*containerName, splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!curList)) {
return NS_ERROR_FAILURE;
}
// curList is now the correct thing to put curNode in
// remember our new block for postprocessing
mNewBlock = curList;
}
// tuck the node into the end of the active list
rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*curNode->AsContent(),
*curList);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// forget curQuote, if any
curQuote = nullptr;
continue;
}
@@ -4997,22 +5036,28 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
MaybeSplitAncestorsForInsertWithTransaction(*containerName,
atListItem);
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
}
curList =
HTMLEditorRef().CreateNodeWithTransaction(
*containerName, splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!curList)) {
return NS_ERROR_FAILURE;
}
}
rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*listItem, *curList);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// remember we indented this li
indentedLI = listItem;
continue;
@@ -5037,27 +5082,33 @@ HTMLEditRules::WillHTMLIndent(bool* aCan
MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
atCurNode);
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
}
curQuote =
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::blockquote,
splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!curQuote)) {
return NS_ERROR_FAILURE;
}
// remember our new block for postprocessing
mNewBlock = curQuote;
// curQuote is now the correct thing to put curNode in
}
// tuck the node into the end of the active blockquote
rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*curNode->AsContent(),
*curQuote);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// forget curList, if any
curList = nullptr;
}
return NS_OK;
}
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -324,17 +324,25 @@ protected:
nsresult WillMakeList(const nsAString* aListType,
bool aEntireList,
const nsAString* aBulletType,
bool* aCancel, bool* aHandled,
const nsAString* aItemType = nullptr);
nsresult WillRemoveList(bool aOrdered, bool* aCancel, bool* aHandled);
nsresult WillIndent(bool* aCancel, bool* aHandled);
nsresult WillCSSIndent(bool* aCancel, bool* aHandled);
- nsresult WillHTMLIndent(bool* aCancel, bool* aHandled);
+
+ /**
+ * Called before indenting around Selection and it's not in CSS mode.
+ * This method actually tries to indent the contents.
+ *
+ * @param aCancel Returns true if the operation is canceled.
+ * @param aHandled Returns true if the edit action is handled.
+ */
+ MOZ_MUST_USE nsresult WillHTMLIndent(bool* aCancel, bool* aHandled);
/**
* Called before outdenting around Selection. This method actually tries
* to indent the contents.
*
* @param aCancel Returns true if the operation is canceled.
* @param aHandled Returns true if the edit action is handled.
*/
@@ -533,16 +541,24 @@ protected:
/**
* Called after handling edit action. This may adjust Selection, remove
* unnecessary empty nodes, create <br> elements if needed, etc.
*/
MOZ_MUST_USE nsresult
AfterEditInner(EditAction action, nsIEditor::EDirection aDirection);
/**
+ * IndentAroundSelectionWithHTML() indents around Selection with HTML.
+ * This method creates AutoSelectionRestorer. Therefore, each caller
+ * need to check if the editor is still available even if this returns
+ * NS_OK.
+ */
+ MOZ_MUST_USE nsresult IndentAroundSelectionWithHTML();
+
+ /**
* OutdentAroundSelection() outdents contents around Selection.
* This method creates AutoSelectionRestorer. Therefore, each caller
* need to check if the editor is still available even if this returns
* NS_OK.
*
* @return The left content is left content of last
* outdented element.
* The right content is right content of last