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