diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp
index c2f8ead8bd7c..e6f85c03af73 100644
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -9969,6 +9969,30 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+
+ rv = PrepareToMakeElementAbsolutePosition(aHandled, address_of(mNewBlock));
+ // PrepareToMakeElementAbsolutePosition() may restore selection with
+ // AutoSelectionRestorer. Therefore, the editor might have already been
+ // destroyed now.
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ return NS_OK;
+}
+
+nsresult
+HTMLEditRules::PrepareToMakeElementAbsolutePosition(
+ bool* aHandled,
+ RefPtr* aTargetElement)
+{
+ MOZ_ASSERT(IsEditorDataAvailable());
+
+ MOZ_ASSERT(aHandled);
+ MOZ_ASSERT(aTargetElement);
+
AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
// Convert the selection ranges into "promoted" selection ranges: this
@@ -9981,8 +10005,8 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
// Use these ranges to contruct a list of nodes to act on.
nsTArray> arrayOfNodes;
- rv = GetNodesForOperation(arrayOfRanges, arrayOfNodes,
- EditAction::setAbsolutePosition);
+ nsresult rv = GetNodesForOperation(arrayOfRanges, arrayOfNodes,
+ EditAction::setAbsolutePosition);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -10009,15 +10033,21 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
RefPtr positionedDiv =
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div,
splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!positionedDiv)) {
return NS_ERROR_FAILURE;
}
// Remember our new block for postprocessing
- mNewBlock = positionedDiv;
+ *aTargetElement = positionedDiv;
// Delete anything that was in the list of nodes
while (!arrayOfNodes.IsEmpty()) {
OwningNonNull 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;
}
@@ -10025,10 +10055,14 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
}
// Put selection in new block
*aHandled = true;
- ErrorResult error;
- SelectionRef().Collapse(RawRangeBoundary(positionedDiv, 0), error);
// Don't restore the selection
selectionRestorer.Abort();
+ ErrorResult error;
+ SelectionRef().Collapse(RawRangeBoundary(positionedDiv, 0), error);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ error.SuppressException();
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
@@ -10074,15 +10108,21 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
curPositionedDiv =
HTMLEditorRef().CreateNodeWithTransaction(
*nsGkAtoms::div, splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
NS_WARNING_ASSERTION(curPositionedDiv,
"Failed to create current positioned div element");
- mNewBlock = curPositionedDiv;
+ *aTargetElement = curPositionedDiv;
}
EditorRawDOMPoint atEndOfCurPositionedDiv;
atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
curList =
HTMLEditorRef().CreateNodeWithTransaction(*containerName,
atEndOfCurPositionedDiv);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!curList)) {
return NS_ERROR_FAILURE;
}
@@ -10092,6 +10132,9 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
// 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;
}
@@ -10135,20 +10178,29 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
curPositionedDiv =
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div,
atListItemParent);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
NS_WARNING_ASSERTION(curPositionedDiv,
"Failed to create current positioned div element");
- mNewBlock = curPositionedDiv;
+ *aTargetElement = curPositionedDiv;
}
EditorRawDOMPoint atEndOfCurPositionedDiv;
atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
curList =
HTMLEditorRef().CreateNodeWithTransaction(*containerName,
atEndOfCurPositionedDiv);
+ 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;
}
@@ -10161,7 +10213,7 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
if (!curPositionedDiv) {
if (curNode->IsHTMLElement(nsGkAtoms::div)) {
curPositionedDiv = curNode->AsElement();
- mNewBlock = curPositionedDiv;
+ *aTargetElement = curPositionedDiv;
curList = nullptr;
continue;
}
@@ -10174,17 +10226,23 @@ HTMLEditRules::WillAbsolutePosition(bool* aCancel,
curPositionedDiv =
HTMLEditorRef().CreateNodeWithTransaction(*nsGkAtoms::div,
splitNodeResult.SplitPoint());
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(!curPositionedDiv)) {
return NS_ERROR_FAILURE;
}
// Remember our new block for postprocessing
- mNewBlock = curPositionedDiv;
+ *aTargetElement = curPositionedDiv;
// curPositionedDiv is now the correct thing to put curNode in
}
// Tuck the node into the end of the active blockquote
rv = HTMLEditorRef().MoveNodeToEndWithTransaction(*curNode->AsContent(),
*curPositionedDiv);
+ if (NS_WARN_IF(!CanHandleEditAction())) {
+ return NS_ERROR_EDITOR_DESTROYED;
+ }
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
diff --git a/editor/libeditor/HTMLEditRules.h b/editor/libeditor/HTMLEditRules.h
index be8f0bbfe33f..4caac1f45d27 100644
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -258,7 +258,6 @@ protected:
nsresult WillOutdent(bool* aCancel, bool* aHandled);
nsresult WillAlign(const nsAString& aAlignType,
bool* aCancel, bool* aHandled);
- nsresult WillAbsolutePosition(bool* aCancel, bool* aHandled);
/**
* Called before changing absolute positioned element to static positioned.
@@ -292,6 +291,32 @@ protected:
nsresult MakeBasicBlock(nsAtom& aBlockType);
nsresult DidMakeBasicBlock(RulesInfo* aInfo, nsresult aResult);
+ /**
+ * Called before changing an element to absolute positioned.
+ * This method only prepares the operation since DidAbsolutePosition() will
+ * change it actually later. mNewBlock is set to the target element and
+ * if necessary, some ancestor nodes of selection may be split.
+ *
+ * @param aCancel Returns true if the operation is canceled.
+ * @param aHandled Returns true if the edit action is handled.
+ */
+ MOZ_MUST_USE nsresult WillAbsolutePosition(bool* aCancel, bool* aHandled);
+
+ /**
+ * PrepareToMakeElementAbsolutePosition() is helper method of
+ * WillAbsolutePosition() since in some cases, needs to restore selection
+ * with AutoSelectionRestorer. So, all callers have to check if
+ * CanHandleEditAction() still returns true after a call of this method.
+ * XXX Should be documented outline of this method.
+ *
+ * @param aHandled Returns true if the edit action is handled.
+ * @param aTargetElement Returns target element which should be
+ * changed to absolute positioned.
+ */
+ MOZ_MUST_USE nsresult
+ PrepareToMakeElementAbsolutePosition(bool* aHandled,
+ RefPtr* aTargetElement);
+
/**
* Called if nobody handles the edit action to make an element absolute
* positioned.
@@ -596,7 +621,7 @@ protected:
RefPtr mUtilRange;
// Need to remember an int across willJoin/didJoin...
uint32_t mJoinOffset;
- nsCOMPtr mNewBlock;
+ RefPtr mNewBlock;
RefPtr mRangeItem;
// XXX In strict speaking, mCachedStyles isn't enough to cache inline styles