Bug 1574852 - part 110: Split `HTMLEditor::WillInsert()` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 17 Sep 2019 02:21:53 +0000
changeset 493473 28c561e18cab23dbd54920c1cbfc0f451f69d301
parent 493472 e6c2a63934fbb3ec4cb9eafcc231ea4ecf570bb8
child 493474 ef4bc62d1776e595fa5507f8d300bb651e50e866
push id36582
push userrgurzau@mozilla.com
push dateTue, 17 Sep 2019 09:36:29 +0000
treeherdermozilla-central@04da00a61c6d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1574852
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1574852 - part 110: Split `HTMLEditor::WillInsert()` r=m_kato It does 4 different things so that it looks like a black-box from the callers. First, only `HTMLEditRules::WillDoAction()` refers `aCancel` out argument. Therefore, it should check whether it's cancelled or not directly. Next, `EnsureNoPaddingBRElementForEmptyEditor()` should be called by each caller directly. Then, the renaming part can be split to 2 methods. One is adjusting caret position and the other preparing inline style for new content. Unfortunately, this patch makes each caller messy. I think that for the 3rd job (i.e., adjusting caret position), each caller should retrieve the adjusted caret position and use it directly instead of handling with `Selection` in the future. Differential Revision: https://phabricator.services.mozilla.com/D45493
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -768,21 +768,44 @@ nsresult HTMLEditRules::WillDoAction(Edi
     }
     *aCancel = true;
     return NS_OK;
   }
 
   switch (aInfo.mEditSubAction) {
     case EditSubAction::eInsertElement:
     case EditSubAction::eInsertQuotedText: {
-      nsresult rv = MOZ_KnownLive(HTMLEditorRef()).WillInsert(aCancel);
+      *aCancel = IsReadonly() || IsDisabled();
+      nsresult rv = MOZ_KnownLive(HTMLEditorRef())
+                        .EnsureNoPaddingBRElementForEmptyEditor();
       if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
-      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+      if (NS_FAILED(rv)) {
+        NS_WARNING(
+            "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+        return NS_OK;
+      }
+      if (!SelectionRefPtr()->IsCollapsed()) {
+        return NS_OK;
+      }
+      rv = MOZ_KnownLive(HTMLEditorRef()).EnsureCaretNotAfterPaddingBRElement();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
+      if (NS_FAILED(rv)) {
+        NS_WARNING("EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+        return NS_OK;
+      }
+      rv = MOZ_KnownLive(HTMLEditorRef()).PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
       return NS_OK;
     }
     case EditSubAction::eComputeTextToOutput:
     case EditSubAction::eCreateOrChangeDefinitionListItem:
     case EditSubAction::eCreateOrChangeList:
     case EditSubAction::eCreateOrRemoveBlock:
     case EditSubAction::eDecreaseZIndex:
     case EditSubAction::eDeleteSelectedContent:
@@ -1278,75 +1301,73 @@ nsresult HTMLEditRules::GetFormatString(
   if (HTMLEditUtils::IsFormatNode(aNode)) {
     aNode->NodeInfo()->NameAtom()->ToString(outFormat);
   } else {
     outFormat.Truncate();
   }
   return NS_OK;
 }
 
-nsresult HTMLEditor::WillInsert(bool* aCancel) {
-  MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
-
-  // XXX Why don't we stop handling this call if we're readonly or disabled?
-  if (aCancel && (IsReadonly() || IsDisabled())) {
-    *aCancel = true;
-  }
-
-  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  // Adjust selection to prevent insertion after a padding <br> element for
-  // empty last line.  This next only works for collapsed selections right
-  // now, because selection is a pain to work with when not collapsed.  (no
-  // good way to extend start or end of selection), so we ignore those types
-  // of selections.
-  if (!SelectionRefPtr()->IsCollapsed()) {
-    return NS_OK;
-  }
-
-  // If we are after a padding <br> element for empty last line in the same
+nsresult HTMLEditor::EnsureCaretNotAfterPaddingBRElement() {
+  MOZ_ASSERT(IsEditActionDataAvailable());
+  MOZ_ASSERT(SelectionRefPtr()->IsCollapsed());
+
+  // If we are after a padding `<br>` element for empty last line in the same
   // block, then move selection to be before it
   nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
   if (NS_WARN_IF(!firstRange)) {
     return NS_ERROR_FAILURE;
   }
 
-  EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
-  if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
+  EditorRawDOMPoint atSelectionStart(firstRange->StartRef());
+  if (NS_WARN_IF(!atSelectionStart.IsSet())) {
     return NS_ERROR_FAILURE;
   }
-  MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
-
-  // Get prior node
-  nsCOMPtr<nsIContent> priorNode =
-      GetPreviousEditableHTMLNode(atStartOfSelection);
-  if (priorNode && EditorBase::IsPaddingBRElementForEmptyLastLine(*priorNode)) {
-    RefPtr<Element> block1 = GetBlock(*atStartOfSelection.GetContainer());
-    RefPtr<Element> block2 = GetBlockNodeParent(priorNode);
-
-    if (block1 && block1 == block2) {
-      // If we are here then the selection is right after a padding <br>
-      // element for empty last line that is in the same block as the
-      // selection.  We need to move the selection start to be before the
-      // padding <br> element.
-      EditorRawDOMPoint point(priorNode);
-      ErrorResult error;
-      SelectionRefPtr()->Collapse(point, error);
-      if (NS_WARN_IF(Destroyed())) {
-        error.SuppressException();
-        return NS_ERROR_EDITOR_DESTROYED;
-      }
-      if (NS_WARN_IF(error.Failed())) {
-        return error.StealNSResult();
-      }
-    }
-  }
+  MOZ_ASSERT(atSelectionStart.IsSetAndValid());
+
+  nsCOMPtr<nsIContent> previousEditableContent =
+      GetPreviousEditableHTMLNode(atSelectionStart);
+  if (!previousEditableContent ||
+      !EditorBase::IsPaddingBRElementForEmptyLastLine(
+          *previousEditableContent)) {
+    return NS_OK;
+  }
+
+  RefPtr<Element> blockElementAtSelectionStart =
+      GetBlock(*atSelectionStart.GetContainer());
+  RefPtr<Element> parentBlockElementOfPreviousEditableContent =
+      GetBlockNodeParent(previousEditableContent);
+
+  if (!blockElementAtSelectionStart ||
+      blockElementAtSelectionStart !=
+          parentBlockElementOfPreviousEditableContent) {
+    return NS_OK;
+  }
+
+  // If we are here then the selection is right after a padding <br>
+  // element for empty last line that is in the same block as the
+  // selection.  We need to move the selection start to be before the
+  // padding <br> element.
+  EditorRawDOMPoint atPreviousEditableContent(previousEditableContent);
+  ErrorResult error;
+  SelectionRefPtr()->Collapse(atPreviousEditableContent, error);
+  if (NS_WARN_IF(Destroyed())) {
+    error.SuppressException();
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
+  NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
+  return error.StealNSResult();
+}
+
+nsresult HTMLEditor::PrepareInlineStylesForCaret() {
+  MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
+  MOZ_ASSERT(SelectionRefPtr()->IsCollapsed());
+
+  // XXX This method works with the top level edit sub-action, but this
+  //     must be wrong if we are handling nested edit action.
 
   if (TopLevelEditSubActionDataRef().mDidDeleteSelection) {
     switch (GetTopLevelEditSubAction()) {
       case EditSubAction::eInsertText:
       case EditSubAction::eInsertTextComingFromIME:
       case EditSubAction::eDeleteSelectedContent: {
         nsresult rv = ReapplyCachedStyles();
         if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1384,22 +1405,41 @@ EditActionResult HTMLEditor::HandleInser
   if (!SelectionRefPtr()->IsCollapsed()) {
     nsresult rv =
         DeleteSelectionAsSubAction(nsIEditor::eNone, nsIEditor::eNoStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditActionHandled(rv);
     }
   }
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   RefPtr<Document> document = GetDocument();
   if (NS_WARN_IF(!document)) {
     return EditActionHandled(NS_ERROR_FAILURE);
   }
 
   RefPtr<nsRange> firstRange = SelectionRefPtr()->GetRangeAt(0);
   if (NS_WARN_IF(!firstRange)) {
@@ -1733,22 +1773,41 @@ EditActionResult HTMLEditor::InsertParag
   if (!SelectionRefPtr()->IsCollapsed()) {
     nsresult rv =
         DeleteSelectionAsSubAction(nsIEditor::eNone, nsIEditor::eStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditActionIgnored(rv);
     }
   }
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   // Split any mailcites in the way.  Should we abort this if we encounter
   // table cell boundaries?
   if (IsMailEditor()) {
     EditorDOMPoint pointToSplit(EditorBase::GetStartPoint(*SelectionRefPtr()));
     if (NS_WARN_IF(!pointToSplit.IsSet())) {
       return EditActionIgnored(NS_ERROR_FAILURE);
     }
@@ -1956,17 +2015,18 @@ EditActionResult HTMLEditor::InsertParag
       // may have less children than its offset.  For avoiding warnings of
       // validation of EditorDOMPoint, we should not touch it anymore.
       lockOffset.Cancel();
       return result;
     }
     // Fall through, if HandleInsertParagraphInParagraph() didn't handle it.
     MOZ_ASSERT(!result.Canceled(),
                "HandleInsertParagraphInParagraph() canceled this edit action, "
-               "WillInsertBreak() needs to handle such case");
+               "InsertParagraphSeparatorAsSubAction() needs to handle this "
+               "action instead");
   }
 
   // If nobody handles this edit action, let's insert new <br> at the selection.
   rv = InsertBRElement(atStartOfSelection);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return EditActionIgnored(rv);
   }
   return EditActionHandled();
@@ -4167,22 +4227,41 @@ EditActionResult HTMLEditor::MakeOrChang
   AutoEditSubActionNotifier startToHandleEditSubAction(
       *this,
       &aListElementOrListItemElementTagName == nsGkAtoms::dd ||
               &aListElementOrListItemElementTagName == nsGkAtoms::dt
           ? EditSubAction::eCreateOrChangeDefinitionListItem
           : EditSubAction::eCreateOrChangeList,
       nsIEditor::eNext);
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   nsAtom* listTagName = nullptr;
   nsAtom* listItemTagName = nullptr;
   if (&aListElementOrListItemElementTagName == nsGkAtoms::ul ||
       &aListElementOrListItemElementTagName == nsGkAtoms::ol) {
     listTagName = &aListElementOrListItemElementTagName;
     listItemTagName = nsGkAtoms::li;
   } else if (&aListElementOrListItemElementTagName == nsGkAtoms::dl) {
@@ -4953,22 +5032,41 @@ EditActionResult HTMLEditor::IndentAsSub
       NS_SUCCEEDED(rv),
       "MaybeInsertPaddingBRElementForEmptyLastLineAtSelection() failed");
   return result.SetResult(rv);
 }
 
 EditActionResult HTMLEditor::HandleIndentAtSelection() {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   if (IsCSSEnabled()) {
     nsresult rv = HandleCSSIndentAtSelection();
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "HandleCSSIndentAtSelection() failed");
     return EditActionHandled(rv);
   }
   rv = HandleHTMLIndentAtSelection();
@@ -6286,22 +6384,41 @@ EditActionResult HTMLEditor::AlignAsSubA
   AutoEditSubActionNotifier startToHandleEditSubAction(
       *this, EditSubAction::eSetOrClearAlignment, nsIEditor::eNext);
 
   EditActionResult result = CanHandleHTMLEditSubAction();
   if (NS_WARN_IF(result.Failed()) || result.Canceled()) {
     return result;
   }
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   if (!SelectionRefPtr()->IsCollapsed()) {
     nsresult rv = MaybeExtendSelectionToHardLineEdgesForBlockEditAction();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditActionResult(rv);
     }
   }
 
@@ -10896,22 +11013,41 @@ EditActionResult HTMLEditor::SetSelectio
   AutoEditSubActionNotifier startToHandleEditSubAction(
       *this, EditSubAction::eSetPositionToAbsolute, nsIEditor::eNext);
 
   EditActionResult result = CanHandleHTMLEditSubAction();
   if (NS_WARN_IF(result.Failed()) || result.Canceled()) {
     return result;
   }
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   RefPtr<Element> focusElement = GetSelectionContainerElement();
   if (focusElement && HTMLEditUtils::IsImage(focusElement)) {
     TopLevelEditSubActionDataRef().mNewBlockElement = std::move(focusElement);
     return EditActionHandled();
   }
 
   if (!SelectionRefPtr()->IsCollapsed()) {
@@ -11226,22 +11362,41 @@ EditActionResult HTMLEditor::SetSelectio
   AutoEditSubActionNotifier startToHandleEditSubAction(
       *this, EditSubAction::eSetPositionToStatic, nsIEditor::eNext);
 
   EditActionResult result = CanHandleHTMLEditSubAction();
   if (NS_WARN_IF(result.Failed()) || result.Canceled()) {
     return result;
   }
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   RefPtr<Element> element = GetAbsolutelyPositionedSelectionContainer();
   if (NS_WARN_IF(!element)) {
     return EditActionHandled(NS_ERROR_FAILURE);
   }
 
   {
     AutoSelectionRestorer restoreSelectionLater(*this);
@@ -11270,22 +11425,41 @@ EditActionResult HTMLEditor::AddZIndexAs
                   : EditSubAction::eIncreaseZIndex,
       nsIEditor::eNext);
 
   EditActionResult result = CanHandleHTMLEditSubAction();
   if (NS_WARN_IF(result.Failed()) || result.Canceled()) {
     return result;
   }
 
-  // FYI: Ignore cancel result of WillInsert().
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   RefPtr<Element> absolutelyPositionedElement =
       GetAbsolutelyPositionedSelectionContainer();
   if (NS_WARN_IF(!absolutelyPositionedElement)) {
     return EditActionHandled(NS_ERROR_FAILURE);
   }
 
   {
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -2110,23 +2110,41 @@ nsresult HTMLEditor::FormatBlockContaine
   AutoEditSubActionNotifier startToHandleEditSubAction(
       *this, EditSubAction::eCreateOrRemoveBlock, nsIEditor::eNext);
 
   EditActionResult result = CanHandleHTMLEditSubAction();
   if (result.Canceled() || NS_WARN_IF(result.Failed())) {
     return result.Rv();
   }
 
-  // FYI: Ignore cancel result of WillInsert() since we've already checked
-  //      whether we can or cannot edit current selection range.
-  nsresult rv = WillInsert();
+  nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return NS_ERROR_EDITOR_DESTROYED;
   }
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
+  NS_WARNING_ASSERTION(
+      NS_SUCCEEDED(rv),
+      "EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
+
+  if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
+    nsresult rv = EnsureCaretNotAfterPaddingBRElement();
+    if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
+    NS_WARNING_ASSERTION(
+        NS_SUCCEEDED(rv),
+        "EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
+    if (NS_SUCCEEDED(rv)) {
+      nsresult rv = PrepareInlineStylesForCaret();
+      if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
+        return NS_ERROR_EDITOR_DESTROYED;
+      }
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                           "PrepareInlineStylesForCaret() failed, but ignored");
+    }
+  }
 
   // FormatBlockContainerWithTransaction() creates AutoSelectionRestorer.
   // Therefore, even if it returns NS_OK, editor might have been destroyed
   // at restoring Selection.
   rv = FormatBlockContainerWithTransaction(aTagName);
   if (NS_WARN_IF(Destroyed())) {
     return NS_ERROR_EDITOR_DESTROYED;
   }
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -1151,24 +1151,34 @@ class HTMLEditor final : public TextEdit
    * If `Selection` is in odd situation, returns an error.
    *
    * XXX I think that `IsSelectionEditable()` is better name, but it's already
    *     in `EditorBase`...
    */
   EditActionResult CanHandleHTMLEditSubAction() const;
 
   /**
-   * Called before inserting something into the editor.
-   * This method may removes mPaddingBRElementForEmptyEditor if there is.
-   * Therefore, this method might cause destroying the editor.
-   *
-   * @param aCancel             Returns true if the operation is canceled.
-   *                            This can be nullptr.
-   */
-  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult WillInsert(bool* aCancel = nullptr);
+   * EnsureCaretNotAfterPaddingBRElement() makes sure that caret is NOT after
+   * padding `<br>` element for preventing insertion after padding `<br>`
+   * element at empty last line.
+   * NOTE: This method should be called only when `Selection` is collapsed
+   *       because `Selection` is a pain to work with when not collapsed.
+   *       (no good way to extend start or end of selection), so we need to
+   *       ignore those types of selections.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
+  EnsureCaretNotAfterPaddingBRElement();
+
+  /**
+   * PrepareInlineStylesForCaret() consider inline styles from top level edit
+   * sub-action and setting it to `mTypeInState` and clear inline style cache
+   * if necessary.
+   * NOTE: This method should be called only when `Selection` is collapsed.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult PrepareInlineStylesForCaret();
 
   /**
    * HandleInsertText() handles inserting text at selection.
    *
    * @param aEditSubAction      Must be EditSubAction::eInsertText or
    *                            EditSubAction::eInsertTextComingFromIME.
    * @param aInsertionString    String to be inserted at selection.
    */