Bug 1655389 - part 1: Move `HTMLEditor::HandleDeleteCollapsedSelectionAtCurrentBlockBoundary()` into `AutoBlockElementJoiner` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 04 Aug 2020 11:42:55 +0000
changeset 543350 4e9b12c286f4738718cc510b3bf5632f76db6f46
parent 543349 ac83b0fec5119b240b4de9935e1774b8a89da5f7
child 543351 1e439a68f0e49fb2c1bec0169564a5d69222790d
push id123402
push usermasayuki@d-toybox.com
push dateWed, 05 Aug 2020 06:52:10 +0000
treeherderautoland@de60b2f1987f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1655389, 1655391
milestone81.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 1655389 - part 1: Move `HTMLEditor::HandleDeleteCollapsedSelectionAtCurrentBlockBoundary()` into `AutoBlockElementJoiner` r=m_kato Same as the patch for bug 1655391, this patch splits the method to 2 parts. One is to consider content nodes to join or a `<br>` element to delete instead. Note that this patch changes the behavior a little. That is, when the other block is not editable, it throws an exception here: https://searchfox.org/mozilla-central/rev/56bb74ea8e04bdac57c33cbe9b54d889b9262ade/editor/libeditor/HTMLEditSubActionHandler.cpp#3124 But it should just cancel the edit action. Therefore, some tests in BrowserScope are fixed by this patch. I.e., result of DOM tree in the situation isn't changed, but stops throwing unnecessary exception. Differential Revision: https://phabricator.services.mozilla.com/D85569
editor/libeditor/HTMLEditSubActionHandler.cpp
editor/libeditor/HTMLEditor.h
editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
--- a/editor/libeditor/HTMLEditSubActionHandler.cpp
+++ b/editor/libeditor/HTMLEditSubActionHandler.cpp
@@ -2591,39 +2591,42 @@ EditActionResult HTMLEditor::HandleDelet
         "HTMLEditor::HandleDeleteCollapsedSelectionAtAtomicContent() failed");
     return result;
   }
 
   if (scanFromStartPointResult.ReachedOtherBlockElement()) {
     if (NS_WARN_IF(!scanFromStartPointResult.GetContent()->IsElement())) {
       return EditActionResult(NS_ERROR_FAILURE);
     }
+    AutoBlockElementsJoiner joiner;
+    if (!joiner.PrepareToDeleteCollapsedSelectionAtOtherBlockBoundary(
+            *this, aDirectionAndAmount, *scanFromStartPointResult.ElementPtr(),
+            startPoint, wsRunScanner)) {
+      return EditActionCanceled();
+    }
     EditActionResult result =
-        HandleDeleteCollapsedSelectionAtOtherBlockBoundary(
-            aDirectionAndAmount, aStripWrappers,
-            MOZ_KnownLive(*scanFromStartPointResult.ElementPtr()), startPoint,
-            wsRunScanner);
-    NS_WARNING_ASSERTION(
-        result.Succeeded(),
-        "HTMLEditor::HandleDeleteCollapsedSelectionAtOtherBlockBoundary() "
-        "failed");
+        joiner.Run(*this, aDirectionAndAmount, aStripWrappers, startPoint);
+    NS_WARNING_ASSERTION(result.Succeeded(),
+                         "HTMLEditor::AutoBlockElementsJoiner::Run() failed "
+                         "(other block boundary)");
     return result;
   }
 
   if (scanFromStartPointResult.ReachedCurrentBlockBoundary()) {
     if (NS_WARN_IF(!scanFromStartPointResult.GetContent()->IsElement())) {
       return EditActionResult(NS_ERROR_FAILURE);
     }
     AutoBlockElementsJoiner joiner;
     if (!joiner.PrepareToDeleteCollapsedSelectionAtCurrentBlockBoundary(
             *this, aDirectionAndAmount, *scanFromStartPointResult.ElementPtr(),
             startPoint)) {
       return EditActionCanceled();
     }
-    EditActionResult result = joiner.Run(*this, startPoint);
+    EditActionResult result =
+        joiner.Run(*this, aDirectionAndAmount, aStripWrappers, startPoint);
     NS_WARNING_ASSERTION(result.Succeeded(),
                          "HTMLEditor::AutoBlockElementsJoiner::Run() failed "
                          "(current block boundary)");
     return result;
   }
 
   MOZ_ASSERT_UNREACHABLE("New type of reached content hasn't been handled yet");
   return EditActionIgnored();
@@ -3022,140 +3025,166 @@ EditActionResult HTMLEditor::HandleDelet
       EditorBase::GetStartPoint(*SelectionRefPtr()));
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rv),
       "HTMLEditor::InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary() "
       "failed");
   return EditActionHandled(rv);
 }
 
-EditActionResult HTMLEditor::HandleDeleteCollapsedSelectionAtOtherBlockBoundary(
-    nsIEditor::EDirection aDirectionAndAmount,
-    nsIEditor::EStripWrappers aStripWrappers, Element& aOtherBlockElement,
-    const EditorDOMPoint& aCaretPoint, WSRunScanner& aWSRunScannerAtCaret) {
-  MOZ_ASSERT(IsEditActionDataAvailable());
-  MOZ_ASSERT(aCaretPoint.IsSet());
+bool HTMLEditor::AutoBlockElementsJoiner::
+    PrepareToDeleteCollapsedSelectionAtOtherBlockBoundary(
+        const HTMLEditor& aHTMLEditor,
+        nsIEditor::EDirection aDirectionAndAmount, Element& aOtherBlockElement,
+        const EditorDOMPoint& aCaretPoint,
+        const WSRunScanner& aWSRunScannerAtCaret) {
+  MOZ_ASSERT(aHTMLEditor.IsEditActionDataAvailable());
+  MOZ_ASSERT(aCaretPoint.IsSetAndValid());
+
+  mMode = Mode::JoinOtherBlock;
 
   // Make sure it's not a table element.  If so, cancel the operation
   // (translation: users cannot backspace or delete across table cells)
   if (HTMLEditUtils::IsAnyTableElement(&aOtherBlockElement)) {
-    return EditActionCanceled();
+    return false;
   }
 
   // Next to a block.  See if we are between a block and a br.  If so, we
   // really want to delete the br.  Else join content at selection to the
   // block.
   WSScanResult scanFromCaretResult =
       aDirectionAndAmount == nsIEditor::eNext
           ? aWSRunScannerAtCaret.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
                 aCaretPoint)
           : aWSRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
                 aCaretPoint);
 
   // First find the adjacent node in the block
-  nsCOMPtr<nsIContent> leafNode;
-  nsCOMPtr<nsINode> leftNode, rightNode;
   if (aDirectionAndAmount == nsIEditor::ePrevious) {
-    leafNode = GetLastEditableLeaf(aOtherBlockElement);
-    leftNode = leafNode;
-    rightNode = aCaretPoint.GetContainer();
+    mLeafContentInOtherBlock =
+        aHTMLEditor.GetLastEditableLeaf(aOtherBlockElement);
+    mLeftContent = mLeafContentInOtherBlock;
+    mRightContent = aCaretPoint.GetContainerAsContent();
   } else {
-    leafNode = GetFirstEditableLeaf(aOtherBlockElement);
-    leftNode = aCaretPoint.GetContainer();
-    rightNode = leafNode;
-  }
-
-  bool didBRElementDeleted = false;
+    mLeafContentInOtherBlock =
+        aHTMLEditor.GetFirstEditableLeaf(aOtherBlockElement);
+    mLeftContent = aCaretPoint.GetContainerAsContent();
+    mRightContent = mLeafContentInOtherBlock;
+  }
+
+  // If we found a `<br>` element, we need to delete it instead of joining the
+  // contents.
   if (scanFromCaretResult.ReachedBRElement()) {
-    nsresult rv = DeleteNodeWithTransaction(
-        MOZ_KnownLive(*scanFromCaretResult.BRElementPtr()));
-    if (NS_WARN_IF(Destroyed())) {
+    mBRElement = scanFromCaretResult.BRElementPtr();
+    return true;
+  }
+
+  return mLeftContent && mRightContent;
+}
+
+EditActionResult HTMLEditor::AutoBlockElementsJoiner::
+    HandleDeleteCollapsedSelectionAtOtherBlockBoundary(
+        HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount,
+        nsIEditor::EStripWrappers aStripWrappers,
+        const EditorDOMPoint& aCaretPoint) {
+  MOZ_ASSERT(aHTMLEditor.IsEditActionDataAvailable());
+  MOZ_ASSERT(aCaretPoint.IsSetAndValid());
+
+  // If we found a `<br>` element, we should delete it instead of joinning the
+  // contents.
+  if (mBRElement) {
+    nsresult rv =
+        aHTMLEditor.DeleteNodeWithTransaction(MOZ_KnownLive(*mBRElement));
+    if (NS_WARN_IF(aHTMLEditor.Destroyed())) {
       return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
     }
     if (NS_FAILED(rv)) {
       NS_WARNING("HTMLEditor::DeleteNodeWithTransaction() failed");
       return EditActionResult(rv);
     }
-    didBRElementDeleted = true;
-  }
-
-  // Don't cross table boundaries
-  if (leftNode && rightNode &&
-      HTMLEditor::NodesInDifferentTableElements(*leftNode, *rightNode)) {
-    // If we have not deleted `<br>` element and are not called recursively,
-    // we should call `DeleteSelectionWithTransaction()` here, but we cannot
-    // detect it for now.  Therefore, we should just tell the caller of that
-    // we does nothing.
-    return didBRElementDeleted ? EditActionHandled() : EditActionIgnored();
-  }
-
-  if (didBRElementDeleted) {
+
+    if (mLeftContent && mRightContent &&
+        HTMLEditor::NodesInDifferentTableElements(*mLeftContent,
+                                                  *mRightContent)) {
+      return EditActionHandled();
+    }
+
     // Put selection at edge of block and we are done.
-    if (NS_WARN_IF(!leafNode)) {
+    if (NS_WARN_IF(!mLeafContentInOtherBlock)) {
+      // XXX This must be odd case.  The other block can be empty.
       return EditActionHandled(NS_ERROR_FAILURE);
     }
-    EditorDOMPoint newSel =
-        GetGoodCaretPointFor(*leafNode, aDirectionAndAmount);
-    if (!newSel.IsSet()) {
+    EditorDOMPoint newCaretPosition = aHTMLEditor.GetGoodCaretPointFor(
+        *mLeafContentInOtherBlock, aDirectionAndAmount);
+    if (!newCaretPosition.IsSet()) {
       NS_WARNING("HTMLEditor::GetGoodCaretPointFor() failed");
       return EditActionHandled(NS_ERROR_FAILURE);
     }
-    nsresult rv = CollapseSelectionTo(newSel);
+    rv = aHTMLEditor.CollapseSelectionTo(newCaretPosition);
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
       return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
     }
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rv),
         "HTMLEditor::CollapseSelectionTo() failed, but ignored");
     return EditActionHandled();
   }
 
+  MOZ_ASSERT(mLeftContent);
+  MOZ_ASSERT(mRightContent);
+
+  if (HTMLEditor::NodesInDifferentTableElements(*mLeftContent,
+                                                *mRightContent)) {
+    // If we have not deleted `<br>` element and are not called recursively,
+    // we should call `DeleteSelectionWithTransaction()` here, but we cannot
+    // detect it for now.  Therefore, we should just tell the caller of that
+    // we does nothing.
+    return EditActionIgnored();
+  }
+
   // Else we are joining content to block
   EditActionResult result(NS_OK);
   EditorDOMPoint pointToPutCaret(aCaretPoint);
   {
-    AutoTrackDOMPoint tracker(RangeUpdaterRef(), &pointToPutCaret);
-    if (NS_WARN_IF(!leftNode) || NS_WARN_IF(!leftNode->IsContent()) ||
-        NS_WARN_IF(!rightNode) || NS_WARN_IF(!rightNode->IsContent())) {
-      return EditActionResult(NS_ERROR_FAILURE);
-    }
-    result |=
-        TryToJoinBlocksWithTransaction(MOZ_KnownLive(*leftNode->AsContent()),
-                                       MOZ_KnownLive(*rightNode->AsContent()));
+    AutoTrackDOMPoint tracker(aHTMLEditor.RangeUpdaterRef(), &pointToPutCaret);
+    result |= aHTMLEditor.TryToJoinBlocksWithTransaction(
+        MOZ_KnownLive(*mLeftContent), MOZ_KnownLive(*mRightContent));
     if (result.Failed()) {
       NS_WARNING("HTMLEditor::TryToJoinBlocksWithTransaction() failed");
       return result;
     }
   }
 
   // If TryToJoinBlocksWithTransaction() didn't handle it and it's not
   // canceled, user may want to modify the start leaf node or the last leaf
   // node of the block.
   if (!result.Handled() && !result.Canceled() &&
-      leafNode != aCaretPoint.GetContainer()) {
-    int32_t offset = aDirectionAndAmount == nsIEditor::ePrevious
-                         ? static_cast<int32_t>(leafNode->Length())
-                         : 0;
-    nsresult rv = CollapseSelectionTo(EditorRawDOMPoint(leafNode, offset));
+      mLeafContentInOtherBlock != aCaretPoint.GetContainer()) {
+    int32_t offset =
+        aDirectionAndAmount == nsIEditor::ePrevious
+            ? static_cast<int32_t>(mLeafContentInOtherBlock->Length())
+            : 0;
+    nsresult rv = aHTMLEditor.CollapseSelectionTo(
+        EditorRawDOMPoint(mLeafContentInOtherBlock, offset));
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
       return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
     }
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rv),
         "HTMLEditor::CollapseSelectionTo() failed, but ignored");
-    EditActionResult result =
-        HandleDeleteSelectionInternal(aDirectionAndAmount, aStripWrappers);
+    EditActionResult result = aHTMLEditor.HandleDeleteSelectionInternal(
+        aDirectionAndAmount, aStripWrappers);
     NS_WARNING_ASSERTION(
         result.Succeeded(),
         "Recursive HTMLEditor::HandleDeleteSelectionInternal() failed");
     return result;
   }
 
   // Otherwise, we must have deleted the selection as user expected.
-  nsresult rv = CollapseSelectionTo(pointToPutCaret);
+  nsresult rv = aHTMLEditor.CollapseSelectionTo(pointToPutCaret);
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return result.SetResult(NS_ERROR_EDITOR_DESTROYED);
   }
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "HTMLEditor::CollapseSelectionTo() failed, but ignored");
   return result;
 }
 
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -2697,51 +2697,94 @@ class HTMLEditor final : public TextEdit
      *                                  deletion.
      */
     bool PrepareToDeleteCollapsedSelectionAtCurrentBlockBoundary(
         const HTMLEditor& aHTMLEditor,
         nsIEditor::EDirection aDirectionAndAmount,
         Element& aCurrentBlockElement, const EditorDOMPoint& aCaretPoint);
 
     /**
+     * PrepareToDeleteCollapsedSelectionAtOtherBlockBoundary() considers
+     * left content and right content which are joined for handling deletion at
+     * other block boundary (i.e., immediately before or after a block).
+     *
+     * @param aHTMLEditor               The HTML editor.
+     * @param aDirectionAndAmount       Direction of the deletion.
+     * @param aOtherBlockElement        The block element which follows the
+     *                                  caret or is followed by caret.
+     * @param aCaretPoint               The caret point (i.e., selection start
+     *                                  or end).
+     * @param aWSRunScannerAtCaret      WSRunScanner instance which was
+     *                                  initialized with the caret point.
+     * @return                          true if can continue to handle the
+     *                                  deletion.
+     */
+    bool PrepareToDeleteCollapsedSelectionAtOtherBlockBoundary(
+        const HTMLEditor& aHTMLEditor,
+        nsIEditor::EDirection aDirectionAndAmount, Element& aOtherBlockElement,
+        const EditorDOMPoint& aCaretPoint,
+        const WSRunScanner& aWSRunScannerAtCaret);
+
+    /**
      * Run() executes the joining.
      *
      * @param aHTMLEditor       The HTML editor.
      * @param aCaretPoint       The caret point (i.e., selection start or end).
      */
     [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
-    Run(HTMLEditor& aHTMLEditor, const EditorDOMPoint& aCaretPoint) {
+    Run(HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount,
+        nsIEditor::EStripWrappers aStripWrappers,
+        const EditorDOMPoint& aCaretPoint) {
       switch (mMode) {
         case Mode::JoinCurrentBlock: {
           EditActionResult result =
               HandleDeleteCollapsedSelectionAtCurrentBlockBoundary(aHTMLEditor,
                                                                    aCaretPoint);
           NS_WARNING_ASSERTION(
               result.Succeeded(),
               "AutoBlockElementsJoiner::"
               "HandleDeleteCollapsedSelectionAtCurrentBlockBoundary() failed");
           return result;
         }
+        case Mode::JoinOtherBlock: {
+          EditActionResult result =
+              HandleDeleteCollapsedSelectionAtOtherBlockBoundary(
+                  aHTMLEditor, aDirectionAndAmount, aStripWrappers,
+                  aCaretPoint);
+          NS_WARNING_ASSERTION(
+              result.Succeeded(),
+              "AutoBlockElementsJoiner::"
+              "HandleDeleteCollapsedSelectionAtOtherBlockBoundary() failed");
+          return result;
+        }
         case Mode::NotInitialized:
           return EditActionIgnored();
       }
       return EditActionResult(NS_ERROR_NOT_INITIALIZED);
     }
 
    private:
     [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
     HandleDeleteCollapsedSelectionAtCurrentBlockBoundary(
         HTMLEditor& aHTMLEditor, const EditorDOMPoint& aCaretPoint);
+    [[nodiscard]] MOZ_CAN_RUN_SCRIPT EditActionResult
+    HandleDeleteCollapsedSelectionAtOtherBlockBoundary(
+        HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount,
+        nsIEditor::EStripWrappers aStripWrappersconst,
+        const EditorDOMPoint& aCaretPoint);
 
     enum class Mode {
       NotInitialized,
       JoinCurrentBlock,
+      JoinOtherBlock,
     };
     nsCOMPtr<nsIContent> mLeftContent;
     nsCOMPtr<nsIContent> mRightContent;
+    nsCOMPtr<nsIContent> mLeafContentInOtherBlock;
+    RefPtr<dom::HTMLBRElement> mBRElement;
     Mode mMode = Mode::NotInitialized;
   };
 
   /**
    * HandleDeleteCollapsedSelectionAtOtherBlockBoundary() handles deletion at
    * other block boundary (i.e., immediately before or after a block).
    * If this does not join blocks, `WillDeleteSelection()` may be called
    * recursively.
--- a/editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
+++ b/editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
@@ -1,15 +1,15 @@
 /**
  * The current status of the test suite.
  *
  * See README.Mozilla for details on how to generate this.
  */
 const knownFailures = {
-  "value": {
+  value: {
     "A-Proposed-FS:18px_TEXT-1_SI-dM": true,
     "A-Proposed-FS:18px_TEXT-1_SI-body": true,
     "A-Proposed-FS:18px_TEXT-1_SI-div": true,
     "A-Proposed-FS:large_TEXT-1_SI-dM": true,
     "A-Proposed-FS:large_TEXT-1_SI-body": true,
     "A-Proposed-FS:large_TEXT-1_SI-div": true,
     "A-Proposed-CB:name_TEXT-1_SI-dM": true,
     "A-Proposed-CB:name_TEXT-1_SI-body": true,
@@ -214,18 +214,16 @@ const knownFailures = {
     "D-Proposed-TR3rs:3-1_SO1-div": true,
     "D-Proposed-TR3rs:3-1_SO2-dM": true,
     "D-Proposed-TR3rs:3-1_SO2-body": true,
     "D-Proposed-TR3rs:3-1_SO2-div": true,
     "D-Proposed-TR3rs:3-1_SO3-dM": true,
     "D-Proposed-TR3rs:3-1_SO3-body": true,
     "D-Proposed-TR3rs:3-1_SO3-div": true,
     "D-Proposed-DIV:ce:false-1_SB-dM": true,
-    "D-Proposed-DIV:ce:false-1_SB-body": true,
-    "D-Proposed-DIV:ce:false-1_SB-div": true,
     "D-Proposed-DIV:ce:false-1_SL-dM": true,
     "D-Proposed-DIV:ce:false-1_SL-body": true,
     "D-Proposed-DIV:ce:false-1_SL-div": true,
     "D-Proposed-DIV:ce:false-1_SR-dM": true,
     "D-Proposed-DIV:ce:false-1_SR-body": true,
     "D-Proposed-DIV:ce:false-1_SR-div": true,
     "D-Proposed-DIV:ce:false-1_SI-dM": true,
     "FD-Proposed-OL-LI-1_SW-dM": true,
@@ -457,19 +455,19 @@ const knownFailures = {
     "QV-Proposed-HC_SPANs:bc:b12-SPAN-1_SI-dM": true,
     "QV-Proposed-HC_SPANs:bc:b12-SPAN-1_SI-body": true,
     "QV-Proposed-HC_SPANs:bc:b12-SPAN-1_SI-div": true,
     "QV-Proposed-HC_SPAN.bcred-1_SI-dM": true,
     "QV-Proposed-HC_SPAN.bcred-1_SI-body": true,
     "QV-Proposed-HC_SPAN.bcred-1_SI-div": true,
     "QV-Proposed-HC_MYBCRED-1-SI-dM": true,
     "QV-Proposed-HC_MYBCRED-1-SI-body": true,
-    "QV-Proposed-HC_MYBCRED-1-SI-div": true
+    "QV-Proposed-HC_MYBCRED-1-SI-div": true,
   },
-  "select": {
+  select: {
     "S-Proposed-UNSEL_TEXT-1_SI-dM": true,
     "S-Proposed-UNSEL_TEXT-1_SI-body": true,
     "S-Proposed-UNSEL_TEXT-1_SI-div": true,
     "S-Proposed-SM:m.f.c_TEXT-1_SI-1-dM": true,
     "S-Proposed-SM:m.f.c_TEXT-1_SI-1-body": true,
     "S-Proposed-SM:m.f.c_TEXT-1_SI-1-div": true,
     "S-Proposed-SM:m.b.c_TEXT-1_SI-1-dM": true,
     "S-Proposed-SM:m.b.c_TEXT-1_SI-1-body": true,
@@ -858,18 +856,16 @@ const knownFailures = {
     "D-Proposed-TR3rs:3-1_SO1-div": true,
     "D-Proposed-TR3rs:3-1_SO2-dM": true,
     "D-Proposed-TR3rs:3-1_SO2-body": true,
     "D-Proposed-TR3rs:3-1_SO2-div": true,
     "D-Proposed-TR3rs:3-1_SO3-dM": true,
     "D-Proposed-TR3rs:3-1_SO3-body": true,
     "D-Proposed-TR3rs:3-1_SO3-div": true,
     "D-Proposed-DIV:ce:false-1_SB-dM": true,
-    "D-Proposed-DIV:ce:false-1_SB-body": true,
-    "D-Proposed-DIV:ce:false-1_SB-div": true,
     "D-Proposed-DIV:ce:false-1_SL-dM": true,
     "D-Proposed-DIV:ce:false-1_SL-body": true,
     "D-Proposed-DIV:ce:false-1_SL-div": true,
     "D-Proposed-DIV:ce:false-1_SR-dM": true,
     "D-Proposed-DIV:ce:false-1_SR-body": true,
     "D-Proposed-DIV:ce:false-1_SR-div": true,
     "D-Proposed-DIV:ce:false-1_SI-dM": true,
     "D-Proposed-SPAN:d:ib-2_SL-dM": true,
@@ -1837,11 +1833,11 @@ const knownFailures = {
     "QV-Proposed-HC_SPANs:bc:b12-SPAN-1_SI-dM": true,
     "QV-Proposed-HC_SPANs:bc:b12-SPAN-1_SI-body": true,
     "QV-Proposed-HC_SPANs:bc:b12-SPAN-1_SI-div": true,
     "QV-Proposed-HC_SPAN.bcred-1_SI-dM": true,
     "QV-Proposed-HC_SPAN.bcred-1_SI-body": true,
     "QV-Proposed-HC_SPAN.bcred-1_SI-div": true,
     "QV-Proposed-HC_MYBCRED-1-SI-dM": true,
     "QV-Proposed-HC_MYBCRED-1-SI-body": true,
-    "QV-Proposed-HC_MYBCRED-1-SI-div": true
-  }
-}
+    "QV-Proposed-HC_MYBCRED-1-SI-div": true,
+  },
+};