Bug 1460509 - part 66: Make HTMLEditRules::WillCSSIndent() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato
MozReview-Commit-ID: nnnC5VDpk8
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -4547,16 +4547,35 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
*aCancel = false;
*aHandled = true;
rv = NormalizeSelection();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+
+ // IndentAroundSelectionWithCSS() creates AutoSelectionRestorer.
+ // Therefore, even if it returns NS_OK, editor might have been destroyed
+ // at restoring Selection.
+ rv = IndentAroundSelectionWithCSS();
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
+}
+
+nsresult
+HTMLEditRules::IndentAroundSelectionWithCSS()
+{
+ MOZ_ASSERT(IsEditorDataAvailable());
+
AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
nsTArray<OwningNonNull<nsRange>> arrayOfRanges;
nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
// short circuit: detect case of collapsed selection inside an <li>.
// just sublist that <li>. This prevents bug 97797.
nsCOMPtr<Element> liNode;
@@ -4575,18 +4594,19 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
if (liNode) {
arrayOfNodes.AppendElement(*liNode);
} else {
// 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
- rv = GetNodesFromSelection(EditAction::indent, arrayOfNodes,
- TouchContent::yes);
+ nsresult rv =
+ GetNodesFromSelection(EditAction::indent, arrayOfNodes,
+ TouchContent::yes);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// if nothing visible in list, make an empty block
if (ListIsEmptyLine(arrayOfNodes)) {
// get selection location
@@ -4605,42 +4625,51 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
atStartOfSelection);
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
}
RefPtr<Element> theBlock =
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div,
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;
nsresult rv = IncreaseMarginToIndent(*theBlock);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_EDITOR_DESTROYED;
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to increase indentation");
// 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!
@@ -4664,36 +4693,44 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
// We do this if the next element is a list, and the list is of the
// same type (li/ol) as curNode was a part it.
sibling = HTMLEditorRef().GetNextHTMLSibling(curNode);
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));
+ nsresult 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
// the same type (li/ol) as curNode was a part of.
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);
+ nsresult 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.
@@ -4710,26 +4747,33 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
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);
+ nsresult 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;
}
continue;
}
// Not a list item.
@@ -4753,32 +4797,39 @@ HTMLEditRules::WillCSSIndent(bool* aCanc
SplitNodeResult splitNodeResult =
MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div, atCurNode);
if (NS_WARN_IF(splitNodeResult.Failed())) {
return splitNodeResult.Rv();
}
curQuote =
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div,
splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!curQuote)) {
return NS_ERROR_FAILURE;
}
nsresult rv = IncreaseMarginToIndent(*curQuote);
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return NS_ERROR_EDITOR_DESTROYED;
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to increase indentation");
// 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);
+ nsresult 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;
}
}
return NS_OK;
}
nsresult
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -323,17 +323,25 @@ protected:
nsresult DeleteNonTableElements(nsINode* aNode);
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);
+
+ /**
+ * Called before indenting around Selection and it's 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 WillCSSIndent(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.
*/
@@ -541,16 +549,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);
/**
+ * IndentAroundSelectionWithCSS() indents around Selection with CSS.
+ * 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 IndentAroundSelectionWithCSS();
+
+ /**
* 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();
/**