Bug 1574852 - part 28: Make methods collecting event target nodes take additional argument which can specify whether `aOutArrayOfNodes` includes non-editable nodes or not r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Sun, 25 Aug 2019 04:11:06 +0000
changeset 489803 65b324e800761e957ac3c523040a51b39fb3a835
parent 489802 ada62f7a976092ecc9ed1ab4eed4eb9e809b91ab
child 489804 65a9f716e652ba5d0a261727aafa7ac96f9c17ff
push id93574
push usermasayuki@d-toybox.com
push dateSun, 25 Aug 2019 13:00:15 +0000
treeherderautoland@65b324e80076 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1574852
milestone70.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 28: Make methods collecting event target nodes take additional argument which can specify whether `aOutArrayOfNodes` includes non-editable nodes or not r=m_kato `HTMLEditRules::GetListActionNodes()` removes non-editable element. However, this should've been done by collector methods. Differential Revision: https://phabricator.services.mozilla.com/D43026
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -885,17 +885,18 @@ nsresult HTMLEditRules::GetListState(boo
   if (NS_WARN_IF(!CanHandleEditAction())) {
     return NS_ERROR_EDITOR_DESTROYED;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor);
 
   AutoTArray<OwningNonNull<nsINode>, 64> arrayOfNodes;
   nsresult rv = HTMLEditorRef().CollectEditTargetNodesInExtendedSelectionRanges(
-      arrayOfNodes, EditSubAction::eCreateOrChangeList);
+      arrayOfNodes, EditSubAction::eCreateOrChangeList,
+      HTMLEditor::CollectNonEditableNodes::No);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   rv = GetListActionNodes(arrayOfNodes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -943,17 +944,18 @@ nsresult HTMLEditRules::GetListItemState
   if (NS_WARN_IF(!CanHandleEditAction())) {
     return NS_ERROR_EDITOR_DESTROYED;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor);
 
   AutoTArray<OwningNonNull<nsINode>, 64> arrayOfNodes;
   nsresult rv = HTMLEditorRef().CollectEditTargetNodesInExtendedSelectionRanges(
-      arrayOfNodes, EditSubAction::eCreateOrChangeList);
+      arrayOfNodes, EditSubAction::eCreateOrChangeList,
+      HTMLEditor::CollectNonEditableNodes::No);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   rv = GetListActionNodes(arrayOfNodes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -1049,17 +1051,18 @@ nsresult HTMLEditRules::GetAlignment(boo
   } else {
     AutoTArray<RefPtr<nsRange>, 4> arrayOfRanges;
     HTMLEditorRef().GetSelectionRangesExtendedToHardLineStartAndEnd(
         arrayOfRanges, EditSubAction::eSetOrClearAlignment);
 
     // Use these ranges to construct a list of nodes to act on.
     nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
     nsresult rv = HTMLEditorRef().CollectEditTargetNodes(
-        arrayOfRanges, arrayOfNodes, EditSubAction::eSetOrClearAlignment);
+        arrayOfRanges, arrayOfNodes, EditSubAction::eSetOrClearAlignment,
+        HTMLEditor::CollectNonEditableNodes::Yes);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     nodeToExamine = arrayOfNodes.SafeElementAt(0);
     if (NS_WARN_IF(!nodeToExamine)) {
       return NS_ERROR_FAILURE;
     }
   }
@@ -3726,17 +3729,18 @@ EditActionResult HTMLEditRules::MoveBloc
                                           int32_t aLeftOffset,
                                           int32_t aRightOffset) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   AutoTArray<OwningNonNull<nsINode>, 64> arrayOfNodes;
   nsresult rv = MOZ_KnownLive(HTMLEditorRef())
                     .SplitInlinesAndCollectEditTargetNodesInOneHardLine(
                         EditorDOMPoint(&aRightBlock, aRightOffset),
-                        arrayOfNodes, EditSubAction::eCreateOrChangeList);
+                        arrayOfNodes, EditSubAction::eCreateOrChangeList,
+                        HTMLEditor::CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return EditActionIgnored(rv);
   }
 
   EditActionResult ret(NS_OK);
   for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) {
     // get the node to act on
     if (HTMLEditor::NodeIsBlockStatic(arrayOfNodes[i])) {
@@ -4014,17 +4018,18 @@ nsresult HTMLEditRules::MakeList(nsAtom&
   if (parentListElement) {
     arrayOfNodes.AppendElement(OwningNonNull<nsINode>(*parentListElement));
   } else {
     {
       AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
       nsresult rv =
           MOZ_KnownLive(HTMLEditorRef())
               .SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
-                  arrayOfNodes, EditSubAction::eCreateOrChangeList);
+                  arrayOfNodes, EditSubAction::eCreateOrChangeList,
+                  HTMLEditor::CollectNonEditableNodes::No);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
     nsresult rv = GetListActionNodes(arrayOfNodes);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
@@ -4123,20 +4128,21 @@ nsresult HTMLEditRules::MakeList(nsAtom&
   if (arrayOfNodes.Length() == 1) {
     if (Element* deepestDivBlockquoteOrListElement =
             HTMLEditorRef()
                 .GetDeepestEditableOnlyChildDivBlockquoteOrListElement(
                     arrayOfNodes[0])) {
       if (deepestDivBlockquoteOrListElement->IsAnyOfHTMLElements(
               nsGkAtoms::div, nsGkAtoms::blockquote)) {
         arrayOfNodes.Clear();
-        HTMLEditorRef().CollectChildren(*deepestDivBlockquoteOrListElement,
-                                        arrayOfNodes, 0,
-                                        HTMLEditor::CollectListChildren::No,
-                                        HTMLEditor::CollectTableChildren::No);
+        HTMLEditorRef().CollectChildren(
+            *deepestDivBlockquoteOrListElement, arrayOfNodes, 0,
+            HTMLEditor::CollectListChildren::No,
+            HTMLEditor::CollectTableChildren::No,
+            HTMLEditor::CollectNonEditableNodes::Yes);
       } else {
         arrayOfNodes.ReplaceElementAt(
             0, OwningNonNull<nsINode>(*deepestDivBlockquoteOrListElement));
       }
     }
   }
 
   // Ok, now go through all the nodes and put then in the list,
@@ -4333,17 +4339,20 @@ nsresult HTMLEditRules::MakeList(nsAtom&
       }
       continue;
     }
 
     // if we hit a div clear our prevListItem, insert divs contents
     // into our node array, and remove the div
     if (curNode->IsHTMLElement(nsGkAtoms::div)) {
       prevListItem = nullptr;
-      HTMLEditorRef().CollectChildren(*curNode, arrayOfNodes, i + 1);
+      HTMLEditorRef().CollectChildren(*curNode, arrayOfNodes, i + 1,
+                                      HTMLEditor::CollectListChildren::Yes,
+                                      HTMLEditor::CollectTableChildren::Yes,
+                                      HTMLEditor::CollectNonEditableNodes::Yes);
       nsresult rv = MOZ_KnownLive(HTMLEditorRef())
                         .RemoveContainerWithTransaction(
                             MOZ_KnownLive(*curNode->AsElement()));
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
@@ -4460,17 +4469,18 @@ nsresult HTMLEditRules::WillRemoveList(b
   AutoSelectionRestorer restoreSelectionLater(HTMLEditorRef());
 
   AutoTArray<OwningNonNull<nsINode>, 64> arrayOfNodes;
   {
     AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
     nsresult rv =
         MOZ_KnownLive(HTMLEditorRef())
             .SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
-                arrayOfNodes, EditSubAction::eCreateOrChangeList);
+                arrayOfNodes, EditSubAction::eCreateOrChangeList,
+                HTMLEditor::CollectNonEditableNodes::No);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
   rv = GetListActionNodes(arrayOfNodes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -4561,17 +4571,18 @@ nsresult HTMLEditRules::MakeBasicBlock(n
   }
 
   AutoSelectionRestorer restoreSelectionLater(HTMLEditorRef());
   AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
 
   AutoTArray<OwningNonNull<nsINode>, 64> arrayOfNodes;
   rv = MOZ_KnownLive(HTMLEditorRef())
            .SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
-               arrayOfNodes, EditSubAction::eCreateOrRemoveBlock);
+               arrayOfNodes, EditSubAction::eCreateOrRemoveBlock,
+               HTMLEditor::CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // If nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes)) {
     nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
@@ -4825,17 +4836,18 @@ nsresult HTMLEditRules::IndentAroundSele
   }
 
   if (liNode) {
     arrayOfNodes.AppendElement(*liNode);
   } else {
     nsresult rv =
         MOZ_KnownLive(HTMLEditorRef())
             .SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
-                arrayOfNodes, EditSubAction::eIndent);
+                arrayOfNodes, EditSubAction::eIndent,
+                HTMLEditor::CollectNonEditableNodes::Yes);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes)) {
     // get selection location
@@ -5114,17 +5126,18 @@ nsresult HTMLEditRules::IndentAroundSele
   AutoTArray<RefPtr<nsRange>, 4> arrayOfRanges;
   HTMLEditorRef().GetSelectionRangesExtendedToHardLineStartAndEnd(
       arrayOfRanges, EditSubAction::eIndent);
 
   // 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::eIndent);
+                        arrayOfRanges, arrayOfNodes, EditSubAction::eIndent,
+                        HTMLEditor::CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // if nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes)) {
     nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
@@ -5495,17 +5508,18 @@ SplitRangeOffFromNodeResult HTMLEditRule
   // Convert the selection ranges into "promoted" selection ranges: this
   // basically just expands the range to include the immediate block parent,
   // and then further expands to include any ancestors whose children are all
   // in the range
   AutoTArray<OwningNonNull<nsINode>, 64> arrayOfNodes;
   nsresult rv =
       MOZ_KnownLive(HTMLEditorRef())
           .SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
-              arrayOfNodes, EditSubAction::eOutdent);
+              arrayOfNodes, EditSubAction::eOutdent,
+              HTMLEditor::CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return SplitRangeOffFromNodeResult(rv);
   }
 
   // Okay, now go through all the nodes and remove a level of blockquoting,
   // or whatever is appropriate.  Wohoo!
 
   nsCOMPtr<nsIContent> leftContentOfLastOutdented;
@@ -6113,17 +6127,18 @@ nsresult HTMLEditRules::AlignContentsAtS
   // Convert the selection ranges into "promoted" selection ranges: This
   // basically just expands the range to include the immediate block parent,
   // and then further expands to include any ancestors whose children are all
   // in the range
   AutoTArray<OwningNonNull<nsINode>, 64> nodeArray;
   nsresult rv =
       MOZ_KnownLive(HTMLEditorRef())
           .SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
-              nodeArray, EditSubAction::eSetOrClearAlignment);
+              nodeArray, EditSubAction::eSetOrClearAlignment,
+              HTMLEditor::CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // If we don't have any nodes, or we have only a single br, then we are
   // creating an empty alignment div.  We have to do some different things for
   // these.
   bool emptyDiv = nodeArray.IsEmpty();
@@ -6686,35 +6701,35 @@ Element* HTMLEditRules::CheckForInvisibl
     return wsTester.mStartReasonNode->AsElement();
   }
 
   return nullptr;
 }
 
 size_t HTMLEditor::CollectChildren(
     nsINode& aNode, nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-    size_t aIndexToInsertChildren,
-    CollectListChildren aCollectListChildren /* = CollectListChildren::Yes */,
-    CollectTableChildren
-        aCollectTableChildren /* = CollectTableChildren::Yes */) const {
+    size_t aIndexToInsertChildren, CollectListChildren aCollectListChildren,
+    CollectTableChildren aCollectTableChildren,
+    CollectNonEditableNodes aCollectNonEditableNodes) const {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   size_t numberOfFoundChildren = 0;
   for (nsIContent* content = GetFirstEditableChild(aNode); content;
        content = content->GetNextSibling()) {
     if ((aCollectListChildren == CollectListChildren::Yes &&
          (HTMLEditUtils::IsList(content) ||
           HTMLEditUtils::IsListItem(content))) ||
         (aCollectTableChildren == CollectTableChildren::Yes &&
          HTMLEditUtils::IsTableElement(content))) {
-      numberOfFoundChildren +=
-          CollectChildren(*content, aOutArrayOfNodes,
-                          aIndexToInsertChildren + numberOfFoundChildren,
-                          aCollectListChildren, aCollectTableChildren);
-    } else {
+      numberOfFoundChildren += CollectChildren(
+          *content, aOutArrayOfNodes,
+          aIndexToInsertChildren + numberOfFoundChildren, aCollectListChildren,
+          aCollectTableChildren, aCollectNonEditableNodes);
+    } else if (aCollectNonEditableNodes == CollectNonEditableNodes::Yes ||
+               IsEditable(content)) {
       aOutArrayOfNodes.InsertElementAt(
           aIndexToInsertChildren + numberOfFoundChildren++, *content);
     }
   }
   return numberOfFoundChildren;
 }
 
 nsresult HTMLEditRules::ExpandSelectionForDeletion() {
@@ -7402,29 +7417,31 @@ class UniqueFunctor final : public BoolD
 
  private:
   nsTArray<OwningNonNull<nsINode>>& mArray;
 };
 
 nsresult HTMLEditor::SplitInlinesAndCollectEditTargetNodes(
     nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
     nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-    EditSubAction aEditSubAction) {
+    EditSubAction aEditSubAction,
+    CollectNonEditableNodes aCollectNonEditableNodes) {
   nsresult rv = SplitTextNodesAtRangeEnd(aArrayOfRanges);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SplitTextNodesAtRangeEnd() failed");
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = SplitParentInlineElementsAtRangeEdges(aArrayOfRanges);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "SplitParentInlineElementsAtRangeEdges() failed");
   if (NS_FAILED(rv)) {
     return rv;
   }
-  rv = CollectEditTargetNodes(aArrayOfRanges, aOutArrayOfNodes, aEditSubAction);
+  rv = CollectEditTargetNodes(aArrayOfRanges, aOutArrayOfNodes, aEditSubAction,
+                              aCollectNonEditableNodes);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "CollectEditTargetNodes() failed");
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = MaybeSplitElementsAtEveryBRElement(aOutArrayOfNodes, aEditSubAction);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "MaybeSplitElementsAtEveryBRElement() failed");
   return rv;
@@ -7498,17 +7515,18 @@ nsresult HTMLEditor::SplitParentInlineEl
     return NS_ERROR_EDITOR_DESTROYED;
   }
   return NS_OK;
 }
 
 nsresult HTMLEditor::CollectEditTargetNodes(
     nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
     nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-    EditSubAction aEditSubAction) const {
+    EditSubAction aEditSubAction,
+    CollectNonEditableNodes aCollectNonEditableNodes) const {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   // Gather up a list of all the nodes
   for (auto& range : aArrayOfRanges) {
     DOMSubtreeIterator iter;
     nsresult rv = iter.Init(*range);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -7518,27 +7536,35 @@ nsresult HTMLEditor::CollectEditTargetNo
     } else {
       // We don't want duplicates in aOutArrayOfNodes, so we use an
       // iterator/functor that only return nodes that are not already in
       // aOutArrayOfNodes.
       nsTArray<OwningNonNull<nsINode>> nodes;
       iter.AppendList(UniqueFunctor(aOutArrayOfNodes), nodes);
       aOutArrayOfNodes.AppendElements(nodes);
     }
+    if (aCollectNonEditableNodes == CollectNonEditableNodes::No) {
+      for (size_t i = aOutArrayOfNodes.Length(); i > 0; --i) {
+        if (!IsEditable(aOutArrayOfNodes[i - 1])) {
+          aOutArrayOfNodes.RemoveElementAt(i - 1);
+        }
+      }
+    }
   }
 
   switch (aEditSubAction) {
     case EditSubAction::eCreateOrRemoveBlock:
       // Certain operations should not act on li's and td's, but rather inside
       // them.  Alter the list as needed.
       for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
         OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
         if (HTMLEditUtils::IsListItem(node)) {
           aOutArrayOfNodes.RemoveElementAt(i);
-          CollectChildren(*node, aOutArrayOfNodes, i);
+          CollectChildren(*node, aOutArrayOfNodes, i, CollectListChildren::Yes,
+                          CollectTableChildren::Yes, aCollectNonEditableNodes);
         }
       }
       // Empty text node shouldn't be selected if unnecessary
       for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
         if (Text* text = aOutArrayOfNodes[i]->GetAsText()) {
           // Don't select empty text except to empty block
           if (!IsVisibleTextNode(*text)) {
             aOutArrayOfNodes.RemoveElementAt(i);
@@ -7550,32 +7576,33 @@ nsresult HTMLEditor::CollectEditTargetNo
     case EditSubAction::eIndent:
     case EditSubAction::eSetPositionToAbsolute:
       // Indent/outdent already do something special for list items, but we
       // still need to make sure we don't act on table elements
       for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
         OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
         if (HTMLEditUtils::IsTableElementButNotTable(node)) {
           aOutArrayOfNodes.RemoveElementAt(i);
-          CollectChildren(*node, aOutArrayOfNodes, i);
+          CollectChildren(*node, aOutArrayOfNodes, i, CollectListChildren::Yes,
+                          CollectTableChildren::Yes, aCollectNonEditableNodes);
         }
       }
       break;
     default:
       break;
   }
 
   // Outdent should look inside of divs.
   if (aEditSubAction == EditSubAction::eOutdent && !IsCSSEnabled()) {
     for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
       OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
       if (node->IsHTMLElement(nsGkAtoms::div)) {
         aOutArrayOfNodes.RemoveElementAt(i);
         CollectChildren(*node, aOutArrayOfNodes, i, CollectListChildren::No,
-                        CollectTableChildren::No);
+                        CollectTableChildren::No, aCollectNonEditableNodes);
       }
     }
   }
 
   return NS_OK;
 }
 
 nsresult HTMLEditor::MaybeSplitElementsAtEveryBRElement(
@@ -7630,28 +7657,26 @@ Element* HTMLEditor::GetParentListElemen
 nsresult HTMLEditRules::GetListActionNodes(
     nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes) const {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   // Pre-process our list of nodes
   for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
     OwningNonNull<nsINode> testNode = aOutArrayOfNodes[i];
 
-    // Remove all non-editable nodes.  Leave them be.
-    if (!HTMLEditorRef().IsEditable(testNode)) {
-      aOutArrayOfNodes.RemoveElementAt(i);
-      continue;
-    }
-
     // Scan for table elements and divs.  If we find table elements other than
     // table, replace it with a list of any editable non-table content.
     if (HTMLEditUtils::IsTableElementButNotTable(testNode)) {
+      // XXX Before we're called, non-editable nodes are ignored.  However,
+      //     we may append non-editable nodes in table elements here.
       aOutArrayOfNodes.RemoveElementAt(i);
       HTMLEditorRef().CollectChildren(*testNode, aOutArrayOfNodes, i,
-                                      HTMLEditor::CollectListChildren::No);
+                                      HTMLEditor::CollectListChildren::No,
+                                      HTMLEditor::CollectTableChildren::Yes,
+                                      HTMLEditor::CollectNonEditableNodes::Yes);
     }
   }
 
   // If there is only one node in the array, and it is a list, div, or
   // blockquote, then look inside of it until we find inner list or content.
   if (aOutArrayOfNodes.Length() != 1) {
     return NS_OK;
   }
@@ -7661,20 +7686,23 @@ nsresult HTMLEditRules::GetListActionNod
           aOutArrayOfNodes[0]);
   if (!deepestDivBlockquoteOrListElement) {
     return NS_OK;
   }
 
   if (deepestDivBlockquoteOrListElement->IsAnyOfHTMLElements(
           nsGkAtoms::div, nsGkAtoms::blockquote)) {
     aOutArrayOfNodes.Clear();
+    // XXX Before we're called, non-editable nodes are ignored.  However,
+    //     we may append non-editable nodes here.
     HTMLEditorRef().CollectChildren(*deepestDivBlockquoteOrListElement,
                                     aOutArrayOfNodes, 0,
                                     HTMLEditor::CollectListChildren::No,
-                                    HTMLEditor::CollectTableChildren::No);
+                                    HTMLEditor::CollectTableChildren::No,
+                                    HTMLEditor::CollectNonEditableNodes::Yes);
     return NS_OK;
   }
 
   aOutArrayOfNodes.ReplaceElementAt(
       0, OwningNonNull<nsINode>(*deepestDivBlockquoteOrListElement));
   return NS_OK;
 }
 
@@ -7716,17 +7744,18 @@ void HTMLEditRules::GetDefinitionListIte
   }
 }
 
 nsresult HTMLEditRules::GetParagraphFormatNodes(
     nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   nsresult rv = HTMLEditorRef().CollectEditTargetNodesInExtendedSelectionRanges(
-      outArrayOfNodes, EditSubAction::eCreateOrRemoveBlock);
+      outArrayOfNodes, EditSubAction::eCreateOrRemoveBlock,
+      HTMLEditor::CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Pre-process our list of nodes
   for (int32_t i = outArrayOfNodes.Length() - 1; i >= 0; i--) {
     OwningNonNull<nsINode> testNode = outArrayOfNodes[i];
 
@@ -7738,17 +7767,20 @@ nsresult HTMLEditRules::GetParagraphForm
 
     // Scan for table elements.  If we find table elements other than table,
     // replace it with a list of any editable non-table content.  Ditto for
     // list elements.
     if (HTMLEditUtils::IsTableElement(testNode) ||
         HTMLEditUtils::IsList(testNode) ||
         HTMLEditUtils::IsListItem(testNode)) {
       outArrayOfNodes.RemoveElementAt(i);
-      HTMLEditorRef().CollectChildren(testNode, outArrayOfNodes, i);
+      HTMLEditorRef().CollectChildren(testNode, outArrayOfNodes, i,
+                                      HTMLEditor::CollectListChildren::Yes,
+                                      HTMLEditor::CollectTableChildren::Yes,
+                                      HTMLEditor::CollectNonEditableNodes::Yes);
     }
   }
   return NS_OK;
 }
 
 nsresult HTMLEditor::SplitParentInlineElementsAtRangeEdges(
     RangeItem& aRangeItem) {
   MOZ_ASSERT(IsEditActionDataAvailable());
@@ -10851,17 +10883,18 @@ nsresult HTMLEditRules::PrepareToMakeEle
   HTMLEditorRef().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);
+                        EditSubAction::eSetPositionToAbsolute,
+                        HTMLEditor::CollectNonEditableNodes::Yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // If nothing visible in list, make an empty block
   if (ListIsEmptyLine(arrayOfNodes)) {
     nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -1275,42 +1275,45 @@ class HTMLEditor final : public TextEdit
    * @param aOutArrayOfNodes    [out] This method will inserts found children
    *                            into this array.
    * @param aIndexToInsertChildren      Starting from this index, found
    *                                    children will be inserted to the array.
    * @param aCollectListChildren        If Yes, will collect children of list
    *                                    and list-item elements recursively.
    * @param aCollectTableChildren       If Yes, will collect children of table
    *                                    related elements recursively.
+   * @param aCollectNonEditableNodes    If Yes, will collect found children
+   *                                    even if they are not editable.
    * @return                    Number of found children.
    */
   enum class CollectListChildren { No, Yes };
   enum class CollectTableChildren { No, Yes };
+  enum class CollectNonEditableNodes { No, Yes };
   size_t CollectChildren(
       nsINode& aNode, nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-      size_t aIndexToInsertChildren,
-      CollectListChildren aCollectListChildren = CollectListChildren::Yes,
-      CollectTableChildren aCollectTableChildren =
-          CollectTableChildren::Yes) const;
+      size_t aIndexToInsertChildren, CollectListChildren aCollectListChildren,
+      CollectTableChildren aCollectTableChildren,
+      CollectNonEditableNodes aCollectNonEditableNodes) const;
 
   /**
    * SplitInlinessAndCollectEditTargetNodes() splits text nodes and inline
    * elements around aArrayOfRanges.  Then, collects edit target nodes to
    * aOutArrayOfNodes.  Finally, each edit target nodes is split at every
    * <br> element in it.
    * FYI: You can use SplitInlinesAndCollectEditTargetNodesInOneHardLine()
    *      or SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges()
    *      instead if you want to call this with a hard line including
    *      specific DOM point or extended selection ranges.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
   SplitInlinesAndCollectEditTargetNodes(
       nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
       nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-      EditSubAction aEditSubAction);
+      EditSubAction aEditSubAction,
+      CollectNonEditableNodes aCollectNonEditableNodes);
 
   /**
    * SplitTextNodesAtRangeEnd() splits text nodes if each range end is in
    * middle of a text node.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
   SplitTextNodesAtRangeEnd(nsTArray<RefPtr<nsRange>>& aArrayOfRanges);
 
@@ -1319,17 +1322,18 @@ class HTMLEditor final : public TextEdit
    * First, this collects all nodes in given ranges, then, modifies the
    * result for specific edit sub-actions.
    * FYI: You can use CollectEditTargetNodesInExtendedSelectionRanges() instead
    *      if you want to call this with extended selection ranges.
    */
   nsresult CollectEditTargetNodes(
       nsTArray<RefPtr<nsRange>>& aArrayOfRanges,
       nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-      EditSubAction aEditSubAction) const;
+      EditSubAction aEditSubAction,
+      CollectNonEditableNodes aCollectNonEditableNodes) const;
 
   /**
    * GetWhiteSpaceEndPoint() returns point at first or last ASCII whitespace
    * or non-breakable space starting from aPoint.  I.e., this returns next or
    * previous point whether the character is neither ASCII whitespace nor
    * non-brekable space.
    */
   enum class ScanDirection { Backward, Forward };
@@ -1416,22 +1420,24 @@ class HTMLEditor final : public TextEdit
    * SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges() calls
    * SplitInlinesAndCollectEditTargetNodes() with result of
    * GetSelectionRangesExtendedToHardLineStartAndEnd().  See comments for these
    * methods for the detail.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
   SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
       nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-      EditSubAction aEditSubAction) {
+      EditSubAction aEditSubAction,
+      CollectNonEditableNodes aCollectNonEditableNodes) {
     AutoTArray<RefPtr<nsRange>, 4> extendedSelectionRanges;
     GetSelectionRangesExtendedToHardLineStartAndEnd(extendedSelectionRanges,
                                                     aEditSubAction);
     nsresult rv = SplitInlinesAndCollectEditTargetNodes(
-        extendedSelectionRanges, aOutArrayOfNodes, aEditSubAction);
+        extendedSelectionRanges, aOutArrayOfNodes, aEditSubAction,
+        aCollectNonEditableNodes);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "SplitInlinesAndCollectEditTargetNodes() failed");
     return rv;
   }
 
   /**
    * SplitInlinesAndCollectEditTargetNodesInOneHardLine() just calls
    * SplitInlinesAndCollectEditTargetNodes() with result of calling
@@ -1439,17 +1445,18 @@ class HTMLEditor final : public TextEdit
    * In other words, returns nodes in the hard line including
    * `aPointInOneHardLine`.  See the comments for these methods for the
    * detail.
    */
   MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
   SplitInlinesAndCollectEditTargetNodesInOneHardLine(
       const EditorDOMPoint& aPointInOneHardLine,
       nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-      EditSubAction aEditSubAction) {
+      EditSubAction aEditSubAction,
+      CollectNonEditableNodes aCollectNonEditableNodes) {
     if (NS_WARN_IF(!aPointInOneHardLine.IsSet())) {
       return NS_ERROR_INVALID_ARG;
     }
     RefPtr<nsRange> oneLineRange = CreateRangeExtendedToHardLineStartAndEnd(
         aPointInOneHardLine.ToRawRangeBoundary(),
         aPointInOneHardLine.ToRawRangeBoundary(), aEditSubAction);
     if (!oneLineRange) {
       // XXX It seems odd to create collapsed range for one line range...
@@ -1459,36 +1466,39 @@ class HTMLEditor final : public TextEdit
                           aPointInOneHardLine.ToRawRangeBoundary(), error);
       if (NS_WARN_IF(error.Failed())) {
         return error.StealNSResult();
       }
     }
     AutoTArray<RefPtr<nsRange>, 1> arrayOfLineRanges;
     arrayOfLineRanges.AppendElement(oneLineRange);
     nsresult rv = SplitInlinesAndCollectEditTargetNodes(
-        arrayOfLineRanges, aOutArrayOfNodes, aEditSubAction);
+        arrayOfLineRanges, aOutArrayOfNodes, aEditSubAction,
+        aCollectNonEditableNodes);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "SplitInlinesAndCollectEditTargetNodes() failed");
     return rv;
   }
 
   /**
    * CollectEditTargetNodesInExtendedSelectionRanges() calls
    * CollectEditTargetNodes() with result of
    * GetSelectionRangesExtendedToHardLineStartAndEnd().  See comments for these
    * methods for the detail.
    */
   nsresult CollectEditTargetNodesInExtendedSelectionRanges(
       nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes,
-      EditSubAction aEditSubAction) {
+      EditSubAction aEditSubAction,
+      CollectNonEditableNodes aCollectNonEditableNodes) {
     AutoTArray<RefPtr<nsRange>, 4> extendedSelectionRanges;
     GetSelectionRangesExtendedToHardLineStartAndEnd(extendedSelectionRanges,
                                                     aEditSubAction);
-    nsresult rv = CollectEditTargetNodes(extendedSelectionRanges,
-                                         aOutArrayOfNodes, aEditSubAction);
+    nsresult rv =
+        CollectEditTargetNodes(extendedSelectionRanges, aOutArrayOfNodes,
+                               aEditSubAction, aCollectNonEditableNodes);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "CollectEditTargetNodes() failed");
     return rv;
   }
 
   /**
    * SelectBRElementIfCollapsedInEmptyBlock() helper method for
    * CreateRangeIncludingAdjuscentWhiteSpaces() and
    * CreateRangeExtendedToLineStartAndEnd().  If the given range is collapsed