From 42c32fd19a1a4155ffe00ce3a76ea125ba4dab3e Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 11 Aug 2020 02:02:19 +0000 Subject: [PATCH] Bug 1657270 - part 1: Move `HTMLEditor::MaybeDeleteTopMostEmptyAncestor()` into new stack only class r=m_kato Differential Revision: https://phabricator.services.mozilla.com/D85995 --- editor/libeditor/HTMLEditSubActionHandler.cpp | 56 +++++++++--------- editor/libeditor/HTMLEditor.h | 57 ++++++++++--------- 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/editor/libeditor/HTMLEditSubActionHandler.cpp b/editor/libeditor/HTMLEditSubActionHandler.cpp index 71746db84eed..19e7a716b4e0 100644 --- a/editor/libeditor/HTMLEditSubActionHandler.cpp +++ b/editor/libeditor/HTMLEditSubActionHandler.cpp @@ -2462,13 +2462,13 @@ EditActionResult HTMLEditor::HandleDeleteSelectionInternal( if (startPoint.GetContainerAsContent()) { AutoEditorDOMPointChildInvalidator lockOffset(startPoint); - EditActionResult result = MaybeDeleteTopMostEmptyAncestor( - MOZ_KnownLive(*startPoint.GetContainerAsContent()), *editingHost, - aDirectionAndAmount); + AutoEmptyBlockAncestorDeleter deleter; + EditActionResult result = + deleter.Run(*this, MOZ_KnownLive(*startPoint.GetContainerAsContent()), + *editingHost, aDirectionAndAmount); if (result.Failed() || result.Handled()) { - NS_WARNING_ASSERTION( - result.Succeeded(), - "HTMLEditor::MaybeDeleteTopMostEmptyAncestor() failed"); + NS_WARNING_ASSERTION(result.Succeeded(), + "AutoEmptyBlockAncestorDeleter::Run() failed"); return result; } } @@ -7859,10 +7859,10 @@ nsresult HTMLEditor::AlignBlockContentsWithDivElement( return NS_OK; } -EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( - nsIContent& aStartContent, Element& aEditingHostElement, - nsIEditor::EDirection aDirectionAndAmount) { - MOZ_ASSERT(IsEditActionDataAvailable()); +EditActionResult HTMLEditor::AutoEmptyBlockAncestorDeleter::Run( + HTMLEditor& aHTMLEditor, nsIContent& aStartContent, + Element& aEditingHostElement, nsIEditor::EDirection aDirectionAndAmount) { + MOZ_ASSERT(aHTMLEditor.IsEditActionDataAvailable()); // If the editing host is an inline element, bail out early. if (HTMLEditUtils::IsInlineElement(aEditingHostElement)) { @@ -7876,7 +7876,7 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( RefPtr topMostEmptyBlockElement; while (blockElement && blockElement != &aEditingHostElement && !HTMLEditUtils::IsAnyTableElement(blockElement) && - IsEmptyNode(*blockElement, true, false)) { + aHTMLEditor.IsEmptyNode(*blockElement, true, false)) { topMostEmptyBlockElement = blockElement; blockElement = HTMLEditUtils::GetAncestorBlockElement(*topMostEmptyBlockElement); @@ -7906,7 +7906,7 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( // last list item is deleted. We should follow it since current // behavior is annoying when you type new list item with selecting // all list items. - if (IsFirstEditableChild(topMostEmptyBlockElement)) { + if (aHTMLEditor.IsFirstEditableChild(topMostEmptyBlockElement)) { EditorDOMPoint atParentOfEmptyBlock(parentOfEmptyBlockElement); if (NS_WARN_IF(!atParentOfEmptyBlock.IsSet())) { return EditActionResult(NS_ERROR_FAILURE); @@ -7916,15 +7916,16 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( if (!HTMLEditUtils::IsAnyListElement( atParentOfEmptyBlock.GetContainer())) { RefPtr brElement = - InsertBRElementWithTransaction(atParentOfEmptyBlock); - if (NS_WARN_IF(Destroyed())) { + aHTMLEditor.InsertBRElementWithTransaction(atParentOfEmptyBlock); + if (NS_WARN_IF(aHTMLEditor.Destroyed())) { return EditActionResult(NS_ERROR_EDITOR_DESTROYED); } if (!brElement) { NS_WARNING("HTMLEditor::InsertBRElementWithTransaction() failed"); return EditActionResult(NS_ERROR_FAILURE); } - nsresult rv = CollapseSelectionTo(EditorRawDOMPoint(brElement)); + nsresult rv = + aHTMLEditor.CollapseSelectionTo(EditorRawDOMPoint(brElement)); if (NS_FAILED(rv)) { NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::CollapseSelectionTo() failed"); @@ -7945,14 +7946,14 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( advancedFromEmptyBlock, "Failed to set selection to the after the empty block"); nsCOMPtr nextContentOfEmptyBlock = - GetNextNode(afterEmptyBlock); + aHTMLEditor.GetNextNode(afterEmptyBlock); if (nextContentOfEmptyBlock) { - EditorDOMPoint pt = GetGoodCaretPointFor(*nextContentOfEmptyBlock, - aDirectionAndAmount); + EditorDOMPoint pt = aHTMLEditor.GetGoodCaretPointFor( + *nextContentOfEmptyBlock, aDirectionAndAmount); NS_WARNING_ASSERTION( pt.IsSet(), "HTMLEditor::GetGoodCaretPointFor() failed, but ignored"); - nsresult rv = CollapseSelectionTo(pt); + nsresult rv = aHTMLEditor.CollapseSelectionTo(pt); if (NS_FAILED(rv)) { NS_WARNING("HTMLEditor::CollapseSelectionTo() failed"); return EditActionResult(rv); @@ -7962,7 +7963,7 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( if (NS_WARN_IF(!advancedFromEmptyBlock)) { return EditActionResult(NS_ERROR_FAILURE); } - nsresult rv = CollapseSelectionTo(afterEmptyBlock); + nsresult rv = aHTMLEditor.CollapseSelectionTo(afterEmptyBlock); if (NS_FAILED(rv)) { NS_WARNING("HTMLEditor::CollapseSelectionTo() failed"); return EditActionResult(rv); @@ -7976,14 +7977,14 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( // if there is. Otherwise, to after the empty block. EditorRawDOMPoint atEmptyBlock(topMostEmptyBlockElement); nsCOMPtr previousContentOfEmptyBlock = - GetPreviousEditableNode(atEmptyBlock); + aHTMLEditor.GetPreviousEditableNode(atEmptyBlock); if (previousContentOfEmptyBlock) { - EditorDOMPoint pt = GetGoodCaretPointFor(*previousContentOfEmptyBlock, - aDirectionAndAmount); + EditorDOMPoint pt = aHTMLEditor.GetGoodCaretPointFor( + *previousContentOfEmptyBlock, aDirectionAndAmount); NS_WARNING_ASSERTION( pt.IsSet(), "HTMLEditor::GetGoodCaretPointFor() failed, but ignored"); - nsresult rv = CollapseSelectionTo(pt); + nsresult rv = aHTMLEditor.CollapseSelectionTo(pt); if (NS_FAILED(rv)) { NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::CollapseSelectionTo() failed"); @@ -7996,7 +7997,7 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( if (NS_WARN_IF(!afterEmptyBlock.IsSet())) { return EditActionResult(NS_ERROR_FAILURE); } - nsresult rv = CollapseSelectionTo(afterEmptyBlock); + nsresult rv = aHTMLEditor.CollapseSelectionTo(afterEmptyBlock); if (NS_FAILED(rv)) { NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::CollapseSelectionTo() failed"); @@ -8010,8 +8011,9 @@ EditActionResult HTMLEditor::MaybeDeleteTopMostEmptyAncestor( MOZ_CRASH("CheckForEmptyBlock doesn't support this action yet"); } } - nsresult rv = DeleteNodeWithTransaction(*topMostEmptyBlockElement); - if (NS_WARN_IF(Destroyed())) { + nsresult rv = + aHTMLEditor.DeleteNodeWithTransaction(*topMostEmptyBlockElement); + if (NS_WARN_IF(aHTMLEditor.Destroyed())) { return EditActionResult(NS_ERROR_EDITOR_DESTROYED); } if (NS_FAILED(rv)) { diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index 52bbe0964033..78206ce88718 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -2423,32 +2423,6 @@ class HTMLEditor final : public TextEditor, [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveEmptyInclusiveAncestorInlineElements(nsIContent& aContent); - /** - * MaybeDeleteTopMostEmptyAncestor() looks for top most empty block ancestor - * of aStartContent in aEditingHostElement. - * If found empty ancestor is a list item element, inserts a
element - * before its parent element if grand parent is a list element. Then, - * collapse Selection to after the empty block. - * If found empty ancestor is not a list item element, collapse Selection to - * somewhere depending on aAction. - * Finally, removes the empty block ancestor. - * - * @param aStartContent Start content to look for empty ancestors. - * @param aEditingHostElement Current editing host. - * @param aDirectionAndAmount If found empty ancestor block is a list item - * element, this is ignored. Otherwise: - * - If eNext, eNextWord or eToEndOfLine, collapse - * Selection to after found empty ancestor. - * - If ePrevious, ePreviousWord or - * eToBeginningOfLine, collapse Selection to - * end of previous editable node. - * Otherwise, eNone is allowed but does nothing. - */ - [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult - MaybeDeleteTopMostEmptyAncestor(nsIContent& aStartContent, - Element& aEditingHostElement, - nsIEditor::EDirection aDirectionAndAmount); - /** * ExtendRangeToIncludeInvisibleNodes() extends aRange if there are some * invisible nodes around it. @@ -2684,6 +2658,37 @@ class HTMLEditor final : public TextEditor, nsIEditor::EStripWrappers aStripWrappers, nsIContent& aAtomicContent, const EditorDOMPoint& aCaretPoint, WSRunScanner& aWSRunScannerAtCaret); + class MOZ_STACK_CLASS AutoEmptyBlockAncestorDeleter final { + public: + /** + * Look for topmost empty block ancestor of aStartContent in + * aEditingHostElement. If found empty ancestor is a list item element, + * inserts a
element before its parent element if grand parent is a + * list element. Then, collapse Selection to after the empty block. If + * found empty ancestor is not a list item element, collapse Selection to + * somewhere depending on aAction. + * Finally, removes the empty block ancestor. + * + * @param aHTMLEditor The HTMLEditor. + * @param aStartContent Start content to look for empty ancestors. + * @param aEditingHostElement Current editing host. + * @param aDirectionAndAmount If found empty ancestor block is a list item + * element, this is ignored. Otherwise: + * - If eNext, eNextWord or eToEndOfLine, + * collapse Selection to after found empty + * ancestor. + * - If ePrevious, ePreviousWord or + * eToBeginningOfLine, collapse Selection to + * end of previous editable node. + * - Otherwise, eNone is allowed but does + * nothing. + */ + [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult + Run(HTMLEditor& aHTMLEditor, nsIContent& aStartContent, + Element& aEditingHostElement, + nsIEditor::EDirection aDirectionAndAmount); + }; + class MOZ_STACK_CLASS AutoBlockElementsJoiner final { public: /**