Bug 1460509 - part 47: Make HTMLEditRules::ExpandSelectionForDeletion() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 15 May 2018 19:15:56 +0900
changeset 798765 fbc062e17ec7663cf7ec23aa7c610af427b4d955
parent 798764 5f0c37e2f604b38cd2700fc881f00e982dfad088
child 798766 cbe591df0fc84b8ea8024f018da458a55008bd6b
push id110840
push usermasayuki@d-toybox.com
push dateWed, 23 May 2018 13:41:58 +0000
reviewersm_kato
bugs1460509
milestone62.0a1
Bug 1460509 - part 47: Make HTMLEditRules::ExpandSelectionForDeletion() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r?m_kato MozReview-Commit-ID: BdumFS7Rluv
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditRules.h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -6106,19 +6106,16 @@ HTMLEditRules::GetInnerContent(
       GetInnerContent(*node, aOutArrayOfNodes, aIndex, aLists, aTables);
     } else {
       aOutArrayOfNodes.InsertElementAt(*aIndex, *node);
       (*aIndex)++;
     }
   }
 }
 
-/**
- * Promotes selection to include blocks that have all their children selected.
- */
 nsresult
 HTMLEditRules::ExpandSelectionForDeletion()
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   // Don't need to touch collapsed selections
   if (SelectionRef().IsCollapsed()) {
     return NS_OK;
@@ -6137,33 +6134,33 @@ HTMLEditRules::ExpandSelectionForDeletio
   }
 
   nsCOMPtr<nsINode> selStartNode = firstRange->GetStartContainer();
   int32_t selStartOffset = firstRange->StartOffset();
   nsCOMPtr<nsINode> selEndNode = firstRange->GetEndContainer();
   int32_t selEndOffset = firstRange->EndOffset();
 
   // Find current selection common block parent
-  nsCOMPtr<Element> selCommon =
+  RefPtr<Element> selCommon =
     HTMLEditor::GetBlock(*firstRange->GetCommonAncestor());
   if (NS_WARN_IF(!selCommon)) {
     return NS_ERROR_FAILURE;
   }
 
   // Set up for loops and cache our root element
   nsCOMPtr<nsINode> firstBRParent;
   nsCOMPtr<nsINode> unused;
   int32_t visOffset = 0, firstBROffset = 0;
   WSType wsType;
   RefPtr<Element> root = HTMLEditorRef().GetActiveEditingHost();
   if (NS_WARN_IF(!root)) {
     return NS_ERROR_FAILURE;
   }
 
-  // Find previous visible thingy before start of selection
+  // Find previous visible things before start of selection
   if (selStartNode != selCommon && selStartNode != root) {
     while (true) {
       WSRunObject wsObj(&HTMLEditorRef(), selStartNode, selStartOffset);
       wsObj.PriorVisibleNode(EditorRawDOMPoint(selStartNode, selStartOffset),
                              address_of(unused), &visOffset, &wsType);
       if (wsType != WSType::thisBlock) {
         break;
       }
@@ -6175,17 +6172,17 @@ HTMLEditRules::ExpandSelectionForDeletio
         break;
       }
       selStartNode = wsObj.mStartReasonNode->GetParentNode();
       selStartOffset = selStartNode ?
         selStartNode->ComputeIndexOf(wsObj.mStartReasonNode) : -1;
     }
   }
 
-  // Find next visible thingy after end of selection
+  // Find next visible things after end of selection
   if (selEndNode != selCommon && selEndNode != root) {
     for (;;) {
       WSRunObject wsObj(&HTMLEditorRef(), selEndNode, selEndOffset);
       wsObj.NextVisibleNode(EditorRawDOMPoint(selEndNode, selEndOffset),
                             address_of(unused), &visOffset, &wsType);
       if (wsType == WSType::br) {
         if (HTMLEditorRef().IsVisibleBRElement(wsObj.mEndReasonNode)) {
           break;
@@ -6210,52 +6207,61 @@ HTMLEditRules::ExpandSelectionForDeletio
       } else {
         break;
       }
     }
   }
   // Now set the selection to the new range
   DebugOnly<nsresult> rv =
     SelectionRef().Collapse(selStartNode, selStartOffset);
+  if (NS_WARN_IF(!CanHandleEditAction())) {
+    return NS_ERROR_EDITOR_DESTROYED;
+  }
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to collapse selection");
 
-  // Expand selection endpoint only if we didn't pass a br, or if we really
-  // needed to pass that br (i.e., its block is now totally selected)
+  // Expand selection endpoint only if we didn't pass a <br>, or if we really
+  // needed to pass that <br> (i.e., its block is now totally selected).
   bool doEndExpansion = true;
   if (firstBRParent) {
-    // Find block node containing br
+    // Find block node containing <br>.
     nsCOMPtr<Element> brBlock = HTMLEditor::GetBlock(*firstBRParent);
     bool nodeBefore = false, nodeAfter = false;
 
     // Create a range that represents expanded selection
     RefPtr<nsRange> range = new nsRange(selStartNode);
     nsresult rv = range->SetStartAndEnd(selStartNode, selStartOffset,
                                         selEndNode, selEndOffset);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     // Check if block is entirely inside range
     if (brBlock) {
       nsRange::CompareNodeToRange(brBlock, range, &nodeBefore, &nodeAfter);
     }
 
-    // If block isn't contained, forgo grabbing the br in expanded selection
+    // If block isn't contained, forgo grabbing the <br> in expanded selection.
     if (nodeBefore || nodeAfter) {
       doEndExpansion = false;
     }
   }
   if (doEndExpansion) {
     nsresult rv = SelectionRef().Extend(selEndNode, selEndOffset);
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
-    // Only expand to just before br
+    // Only expand to just before <br>.
     nsresult rv = SelectionRef().Extend(firstBRParent, firstBROffset);
+    if (NS_WARN_IF(!CanHandleEditAction())) {
+      return NS_ERROR_EDITOR_DESTROYED;
+    }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   return NS_OK;
 }
 
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -464,17 +464,24 @@ protected:
   bool IsEmptyBlockElement(Element& aElement,
                            IgnoreSingleBR aIgnoreSingleBR);
 
   nsresult CheckForEmptyBlock(nsINode* aStartNode, Element* aBodyNode,
                               nsIEditor::EDirection aAction, bool* aHandled);
   enum class BRLocation { beforeBlock, blockEnd };
   Element* CheckForInvisibleBR(Element& aBlock, BRLocation aWhere,
                                int32_t aOffset = 0);
-  nsresult ExpandSelectionForDeletion();
+
+  /**
+   * ExpandSelectionForDeletion() may expand Selection range if it's not
+   * collapsed and there is only one range.  This may expand to include
+   * invisible <br> element for preventing delete action handler to keep
+   * unexpected nodes.
+   */
+  MOZ_MUST_USE nsresult ExpandSelectionForDeletion();
 
   /**
    * NormalizeSelection() adjust Selection if it's not collapsed and there is
    * only one range.  If range start and/or end point is <br> node or something
    * non-editable point, they should be moved to nearest text node or something
    * where the other methods easier to handle edit action.
    */
   MOZ_MUST_USE nsresult NormalizeSelection();