Bug 1574852 - part 97: Move `HTMLEditRules::PrepareToMakeElementAbsolutePosition()` to `HTMLEditor` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 12 Sep 2019 04:07:30 +0000
changeset 492753 663df481fcbff090b06c1d8f0736396567e77609
parent 492752 404c6f03dfc702836e6b50721f6409c7a179ed79
child 492754 5cd1006427c7853f4a64b44693af276a88f8c66f
child 492794 18f2c53f2f71500f7df9306c7b1e729abd8fba22
push id114072
push userncsoregi@mozilla.com
push dateThu, 12 Sep 2019 09:53:02 +0000
treeherdermozilla-inbound@5cd1006427c7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1574852
milestone71.0a1
first release with
nightly linux32
663df481fcbf / 71.0a1 / 20190912094122 / files
nightly linux64
663df481fcbf / 71.0a1 / 20190912094122 / files
nightly mac
663df481fcbf / 71.0a1 / 20190912094122 / files
nightly win32
663df481fcbf / 71.0a1 / 20190912094122 / files
nightly win64
663df481fcbf / 71.0a1 / 20190912094122 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1574852 - part 97: Move `HTMLEditRules::PrepareToMakeElementAbsolutePosition()` to `HTMLEditor` r=m_kato Only caller of it is `WillRemoveAbsolutePosition()` and it always sets `*aHandled` to true before calling it. Therefore, it does not need to take it as an argument. Differential Revision: https://phabricator.services.mozilla.com/D45291
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
editor/libeditor/HTMLEditor.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -10897,23 +10897,23 @@ nsresult HTMLEditRules::WillAbsolutePosi
   if (!SelectionRefPtr()->IsCollapsed()) {
     nsresult rv = MOZ_KnownLive(HTMLEditorRef())
                       .MaybeExtendSelectionToHardLineEdgesForBlockEditAction();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  rv = PrepareToMakeElementAbsolutePosition(
-      aHandled,
-      address_of(
-          HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement));
-  // PrepareToMakeElementAbsolutePosition() may restore selection with
-  // AutoSelectionRestorer.  Therefore, the editor might have already been
-  // destroyed now.
+  rv =
+      MOZ_KnownLive(HTMLEditorRef())
+          .MoveSelectedContentsToDivElementToMakeItAbsolutePosition(address_of(
+              HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement));
+  // MoveSelectedContentsToDivElementToMakeItAbsolutePosition() 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;
   }
 
   rv = MOZ_KnownLive(HTMLEditorRef())
@@ -10933,295 +10933,275 @@ nsresult HTMLEditRules::WillAbsolutePosi
   if (NS_WARN_IF(!CanHandleEditAction())) {
     return NS_ERROR_EDITOR_DESTROYED;
   }
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "SetPositionToAbsoluteOrStatic() failed");
   return rv;
 }
 
-nsresult HTMLEditRules::PrepareToMakeElementAbsolutePosition(
-    bool* aHandled, RefPtr<Element>* aTargetElement) {
-  MOZ_ASSERT(IsEditorDataAvailable());
-
-  MOZ_ASSERT(aHandled);
+nsresult HTMLEditor::MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
+    RefPtr<Element>* aTargetElement) {
+  MOZ_ASSERT(IsEditActionDataAvailable());
   MOZ_ASSERT(aTargetElement);
 
-  AutoSelectionRestorer restoreSelectionLater(HTMLEditorRef());
+  AutoSelectionRestorer restoreSelectionLater(*this);
 
   AutoTArray<RefPtr<nsRange>, 4> arrayOfRanges;
-  HTMLEditorRef().GetSelectionRangesExtendedToHardLineStartAndEnd(
+  GetSelectionRangesExtendedToHardLineStartAndEnd(
       arrayOfRanges, EditSubAction::eSetPositionToAbsolute);
 
   // Use these ranges to contruct a list of nodes to act on.
-  nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
-  nsresult rv = MOZ_KnownLive(HTMLEditorRef())
-                    .SplitInlinesAndCollectEditTargetNodes(
-                        arrayOfRanges, arrayOfNodes,
-                        EditSubAction::eSetPositionToAbsolute,
-                        HTMLEditor::CollectNonEditableNodes::Yes);
+  AutoTArray<OwningNonNull<nsINode>, 64> arrayOfNodes;
+  nsresult rv = SplitInlinesAndCollectEditTargetNodes(
+      arrayOfRanges, arrayOfNodes, EditSubAction::eSetPositionToAbsolute,
+      CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // If there is no visible and editable nodes in the edit targets, make an
   // empty block.
   // XXX Isn't this odd if there are only non-editable visible nodes?
-  if (HTMLEditorRef().IsEmptyOneHardLine(arrayOfNodes)) {
+  if (IsEmptyOneHardLine(arrayOfNodes)) {
     nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
 
-    EditorDOMPoint atStartOfSelection(firstRange->StartRef());
-    if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
+    EditorDOMPoint atCaret(firstRange->StartRef());
+    if (NS_WARN_IF(!atCaret.IsSet())) {
       return NS_ERROR_FAILURE;
     }
 
     // Make sure we can put a block here.
     SplitNodeResult splitNodeResult =
-        MOZ_KnownLive(HTMLEditorRef())
-            .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                         atStartOfSelection);
+        MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div, atCaret);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
-    RefPtr<Element> positionedDiv =
-        MOZ_KnownLive(HTMLEditorRef())
-            .CreateNodeWithTransaction(*nsGkAtoms::div,
-                                       splitNodeResult.SplitPoint());
-    if (NS_WARN_IF(!CanHandleEditAction())) {
+    RefPtr<Element> newDivElement = CreateNodeWithTransaction(
+        *nsGkAtoms::div, splitNodeResult.SplitPoint());
+    if (NS_WARN_IF(Destroyed())) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
-    if (NS_WARN_IF(!positionedDiv)) {
+    if (NS_WARN_IF(!newDivElement)) {
       return NS_ERROR_FAILURE;
     }
-    // Remember our new block for postprocessing
-    *aTargetElement = positionedDiv;
     // Delete anything that was in the list of nodes
+    // XXX We don't need to remove items from the array.
     while (!arrayOfNodes.IsEmpty()) {
       OwningNonNull<nsINode> curNode = arrayOfNodes[0];
-      rv = MOZ_KnownLive(HTMLEditorRef()).DeleteNodeWithTransaction(*curNode);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      rv = DeleteNodeWithTransaction(*curNode);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       arrayOfNodes.RemoveElementAt(0);
     }
-    // Put selection in new block
-    *aHandled = true;
     // Don't restore the selection
     restoreSelectionLater.Abort();
     ErrorResult error;
-    SelectionRefPtr()->Collapse(RawRangeBoundary(positionedDiv, 0), error);
-    if (NS_WARN_IF(!CanHandleEditAction())) {
+    SelectionRefPtr()->Collapse(RawRangeBoundary(newDivElement, 0), error);
+    if (NS_WARN_IF(Destroyed())) {
       error.SuppressException();
       return NS_ERROR_EDITOR_DESTROYED;
     }
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-    return NS_OK;
-  }
-
-  // Okay, now go through all the nodes and put them in a blockquote, or
-  // whatever is appropriate.  Woohoo!
-  nsCOMPtr<Element> curList, curPositionedDiv, indentedLI;
+    *aTargetElement = std::move(newDivElement);
+    NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
+    return error.StealNSResult();
+  }
+
+  // `<div>` element to be positioned absolutely.  This may have already
+  // existed or newly created by this method.
+  RefPtr<Element> targetDivElement;
+  // Newly created list element for moving selected list item elements into
+  // targetDivElement.  I.e., this is created in the `<div>` element.
+  RefPtr<Element> createdListElement;
+  // If we handle a parent list item element, this is set to it.  In such case,
+  // we should handle its children again.
+  RefPtr<Element> handledListItemElement;
   for (OwningNonNull<nsINode>& curNode : arrayOfNodes) {
     // Here's where we actually figure out what to do.
     EditorDOMPoint atCurNode(curNode);
     if (NS_WARN_IF(!atCurNode.IsSet())) {
       return NS_ERROR_FAILURE;  // XXX not continue??
     }
 
     // Ignore all non-editable nodes.  Leave them be.
-    if (!HTMLEditorRef().IsEditable(curNode)) {
+    if (!IsEditable(curNode)) {
       continue;
     }
 
-    nsCOMPtr<nsIContent> sibling;
-
-    // Some logic for putting list items into nested lists...
+    // If current node is a child of a list element, we need another list
+    // element in absolute-positioned `<div>` element to avoid non-selected
+    // list items are moved into the `<div>` element.
     if (HTMLEditUtils::IsList(atCurNode.GetContainer())) {
-      // Check to see if curList is still appropriate.  Which it is if curNode
-      // is still right after it in the same list.
-      if (curList) {
-        sibling = HTMLEditorRef().GetPriorHTMLSibling(curNode);
-      }
-
-      if (!curList || (sibling && sibling != curList)) {
-        nsAtom* containerName =
+      // If we cannot move current node to created list element, we need a
+      // list element in the target `<div>` element for the destination.
+      // Therefore, duplicate same list element into the target `<div>`
+      // element.
+      nsIContent* previousEditableContent =
+          createdListElement ? GetPriorHTMLSibling(curNode) : nullptr;
+      if (!createdListElement ||
+          (previousEditableContent &&
+           previousEditableContent != createdListElement)) {
+        nsAtom* ULOrOLOrDLTagName =
             atCurNode.GetContainer()->NodeInfo()->NameAtom();
-        // Create a new nested list of correct type.
         SplitNodeResult splitNodeResult =
-            MOZ_KnownLive(HTMLEditorRef())
-                .MaybeSplitAncestorsForInsertWithTransaction(
-                    MOZ_KnownLive(*containerName), atCurNode);
+            MaybeSplitAncestorsForInsertWithTransaction(
+                MOZ_KnownLive(*ULOrOLOrDLTagName), atCurNode);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
-        if (!curPositionedDiv) {
-          curPositionedDiv =
-              MOZ_KnownLive(HTMLEditorRef())
-                  .CreateNodeWithTransaction(*nsGkAtoms::div,
-                                             splitNodeResult.SplitPoint());
-          if (NS_WARN_IF(!CanHandleEditAction())) {
+        if (!targetDivElement) {
+          targetDivElement = CreateNodeWithTransaction(
+              *nsGkAtoms::div, splitNodeResult.SplitPoint());
+          if (NS_WARN_IF(Destroyed())) {
             return NS_ERROR_EDITOR_DESTROYED;
           }
-          NS_WARNING_ASSERTION(
-              curPositionedDiv,
-              "Failed to create current positioned div element");
-          *aTargetElement = curPositionedDiv;
-        }
-        EditorDOMPoint atEndOfCurPositionedDiv;
-        atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
-        curList = MOZ_KnownLive(HTMLEditorRef())
-                      .CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
-                                                 atEndOfCurPositionedDiv);
-        if (NS_WARN_IF(!CanHandleEditAction())) {
+          if (NS_WARN_IF(!targetDivElement)) {
+            return NS_ERROR_FAILURE;
+          }
+        }
+        createdListElement = CreateNodeWithTransaction(
+            MOZ_KnownLive(*ULOrOLOrDLTagName),
+            EditorDOMPoint::AtEndOf(*targetDivElement));
+        if (NS_WARN_IF(Destroyed())) {
           return NS_ERROR_EDITOR_DESTROYED;
         }
-        if (NS_WARN_IF(!curList)) {
+        if (NS_WARN_IF(!createdListElement)) {
           return NS_ERROR_FAILURE;
         }
-        // curList is now the correct thing to put curNode in.  Remember our
-        // new block for postprocessing.
-      }
-      // Tuck the node into the end of the active list
-      rv = MOZ_KnownLive(HTMLEditorRef())
-               .MoveNodeToEndWithTransaction(
-                   MOZ_KnownLive(*curNode->AsContent()), *curList);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      }
+      // Move current node (maybe, assumed as a list item element) into the
+      // new list element in the target `<div>` element to be positioned
+      // absolutely.
+      rv = MoveNodeToEndWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
+                                        *createdListElement);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       continue;
     }
 
-    // Not a list item, use blockquote?  If we are inside a list item, we
-    // don't want to blockquote, we want to sublist the list item.  We may
-    // have several nodes listed in the array of nodes to act on, that are in
-    // the same list item.  Since we only want to indent that li once, we
-    // must keep track of the most recent indented list item, and not indent
-    // it if we find another node to act on that is still inside the same li.
-    RefPtr<Element> listItem =
-        curNode->IsContent()
-            ? HTMLEditorRef().GetNearestAncestorListItemElement(
-                  *curNode->AsContent())
-            : nullptr;
-    if (listItem) {
-      if (indentedLI == listItem) {
-        // Already indented this list item
+    // If contents in a list item element is selected, we should move current
+    // node into the target `<div>` element with the list item element itself
+    // because we want to keep indent level of the contents.
+    if (RefPtr<Element> listItemElement =
+            curNode->IsContent()
+                ? GetNearestAncestorListItemElement(*curNode->AsContent())
+                : nullptr) {
+      if (handledListItemElement == listItemElement) {
+        // Current node has already been moved into the `<div>` element.
         continue;
       }
-      // Check to see if curList is still appropriate.  Which it is if
-      // curNode is still right after it in the same list.
-      if (curList) {
-        sibling = HTMLEditorRef().GetPriorHTMLSibling(listItem);
-      }
-
-      if (!curList || (sibling && sibling != curList)) {
-        EditorDOMPoint atListItem(listItem);
+      // If we cannot move the list item element into created list element,
+      // we need another list element in the target `<div>` element.
+      nsIContent* previousEditableContent =
+          createdListElement ? GetPriorHTMLSibling(listItemElement) : nullptr;
+      if (!createdListElement ||
+          (previousEditableContent &&
+           previousEditableContent != createdListElement)) {
+        EditorDOMPoint atListItem(listItemElement);
         if (NS_WARN_IF(!atListItem.IsSet())) {
           return NS_ERROR_FAILURE;
         }
+        // XXX If curNode is the listItemElement and not in a list element,
+        //     we duplicate wrong element into the target `<div>` element.
         nsAtom* containerName =
             atListItem.GetContainer()->NodeInfo()->NameAtom();
-        // Create a new nested list of correct type
         SplitNodeResult splitNodeResult =
-            MOZ_KnownLive(HTMLEditorRef())
-                .MaybeSplitAncestorsForInsertWithTransaction(
-                    MOZ_KnownLive(*containerName), atListItem);
+            MaybeSplitAncestorsForInsertWithTransaction(
+                MOZ_KnownLive(*containerName), atListItem);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
-        if (!curPositionedDiv) {
-          curPositionedDiv = MOZ_KnownLive(HTMLEditorRef())
-                                 .CreateNodeWithTransaction(
-                                     *nsGkAtoms::div,
-                                     EditorDOMPoint(atListItem.GetContainer()));
-          if (NS_WARN_IF(!CanHandleEditAction())) {
+        if (!targetDivElement) {
+          targetDivElement = CreateNodeWithTransaction(
+              *nsGkAtoms::div, EditorDOMPoint(atListItem.GetContainer()));
+          if (NS_WARN_IF(Destroyed())) {
             return NS_ERROR_EDITOR_DESTROYED;
           }
-          NS_WARNING_ASSERTION(
-              curPositionedDiv,
-              "Failed to create current positioned div element");
-          *aTargetElement = curPositionedDiv;
-        }
-        EditorDOMPoint atEndOfCurPositionedDiv;
-        atEndOfCurPositionedDiv.SetToEndOf(curPositionedDiv);
-        curList = MOZ_KnownLive(HTMLEditorRef())
-                      .CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
-                                                 atEndOfCurPositionedDiv);
-        if (NS_WARN_IF(!CanHandleEditAction())) {
+          if (NS_WARN_IF(!targetDivElement)) {
+            return NS_ERROR_FAILURE;
+          }
+        }
+        // XXX So, createdListElement may be set to a non-list element.
+        createdListElement = CreateNodeWithTransaction(
+            MOZ_KnownLive(*containerName),
+            EditorDOMPoint::AtEndOf(*targetDivElement));
+        if (NS_WARN_IF(Destroyed())) {
           return NS_ERROR_EDITOR_DESTROYED;
         }
-        if (NS_WARN_IF(!curList)) {
+        if (NS_WARN_IF(!createdListElement)) {
           return NS_ERROR_FAILURE;
         }
       }
-      rv = MOZ_KnownLive(HTMLEditorRef())
-               .MoveNodeToEndWithTransaction(*listItem, *curList);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      // Move current list item element into the createdListElement (could be
+      // non-list element due to the above bug) in a candidate `<div>` element
+      // to be positioned absolutely.
+      rv = MoveNodeToEndWithTransaction(*listItemElement, *createdListElement);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-      // Remember we indented this li
-      indentedLI = listItem;
+      handledListItemElement = std::move(listItemElement);
       continue;
     }
 
-    // Need to make a div to put things in if we haven't already
-    if (!curPositionedDiv) {
+    if (!targetDivElement) {
+      // If we meet a `<div>` element, use it as the absolute-position
+      // container.
+      // XXX This looks odd.  If there are 2 or more `<div>` elements are
+      //     selected, first found `<div>` element will have all other
+      //     selected nodes.
       if (curNode->IsHTMLElement(nsGkAtoms::div)) {
-        curPositionedDiv = curNode->AsElement();
-        *aTargetElement = curPositionedDiv;
-        curList = nullptr;
+        targetDivElement = curNode->AsElement();
+        MOZ_ASSERT(!createdListElement);
+        MOZ_ASSERT(!handledListItemElement);
         continue;
       }
+      // Otherwise, create new `<div>` element to be positioned absolutely
+      // and to contain all selected nodes.
       SplitNodeResult splitNodeResult =
-          MOZ_KnownLive(HTMLEditorRef())
-              .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                           atCurNode);
+          MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
+                                                      atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
-      curPositionedDiv = MOZ_KnownLive(HTMLEditorRef())
-                             .CreateNodeWithTransaction(
-                                 *nsGkAtoms::div, splitNodeResult.SplitPoint());
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      targetDivElement = CreateNodeWithTransaction(
+          *nsGkAtoms::div, splitNodeResult.SplitPoint());
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
-      if (NS_WARN_IF(!curPositionedDiv)) {
+      if (NS_WARN_IF(!targetDivElement)) {
         return NS_ERROR_FAILURE;
       }
-      // Remember our new block for postprocessing
-      *aTargetElement = curPositionedDiv;
-      // curPositionedDiv is now the correct thing to put curNode in
-    }
-
-    // Tuck the node into the end of the active blockquote
-    rv = MOZ_KnownLive(HTMLEditorRef())
-             .MoveNodeToEndWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
-                                           *curPositionedDiv);
-    if (NS_WARN_IF(!CanHandleEditAction())) {
+    }
+
+    rv = MoveNodeToEndWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
+                                      *targetDivElement);
+    if (NS_WARN_IF(Destroyed())) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
-    // Forget curList, if any
-    curList = nullptr;
-  }
+    // Forget createdListElement, if any
+    createdListElement = nullptr;
+  }
+  *aTargetElement = std::move(targetDivElement);
   return NS_OK;
 }
 
 nsresult HTMLEditRules::WillRemoveAbsolutePosition(bool* aCancel,
                                                    bool* aHandled) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -146,31 +146,16 @@ class HTMLEditRules : public TextEditRul
    * 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_CAN_RUN_SCRIPT
   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_CAN_RUN_SCRIPT
-  MOZ_MUST_USE nsresult PrepareToMakeElementAbsolutePosition(
-      bool* aHandled, RefPtr<Element>* aTargetElement);
-
   nsresult AppendInnerFormatNodes(nsTArray<OwningNonNull<nsINode>>& aArray,
                                   nsINode* aNode);
   nsresult GetFormatString(nsINode* aNode, nsAString& outFormat);
 
   MOZ_CAN_RUN_SCRIPT
   nsresult GetParagraphFormatNodes(
       nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes);
 
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -2650,16 +2650,31 @@ class HTMLEditor final : public TextEdit
 
   /**
    * Called by `HTMLEditRules::AfterEdit()`.  This may adjust Selection, remove
    * unnecessary empty nodes, create `<br>` elements if needed, etc.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
   OnEndHandlingTopLevelEditSubActionInternal();
 
+  /**
+   * MoveSelectedContentsToDivElementToMakeItAbsolutePosition() looks for
+   * a `<div>` element in selection first.  If not, creates new `<div>`
+   * element.  Then, move all selected contents into the target `<div>`
+   * element.
+   * Note that this creates AutoSelectionRestorer.  Therefore, callers need
+   * to check whether we have been destroyed even when this returns NS_OK.
+   *
+   * @param aTargetElement      Returns target `<div>` element which should be
+   *                            changed to absolute positioned.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
+  MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
+      RefPtr<Element>* aTargetElement);
+
  protected:  // Called by helper classes.
   virtual void OnStartToHandleTopLevelEditSubAction(
       EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
   MOZ_CAN_RUN_SCRIPT
   virtual void OnEndHandlingTopLevelEditSubAction() override;
 
  protected:  // Shouldn't be used by friend classes
   virtual ~HTMLEditor();