Bug 1395936 - Avoid child index usage in HTMLEditor::DoContentInserted. r=masayuki
☠☠ backed out by c8b7472de17b ☠ ☠
authorCatalin Badea <catalin.badea392@gmail.com>
Fri, 01 Sep 2017 13:29:47 +0100
changeset 428794 dbb4fb7aa5bb28d19623297c03bdfb23d73019cf
parent 428793 6375aa5b3aabb78f7b8a86e75b200d8191905e87
child 428795 bb932a1656cd4f8850457d85f4916030afbdcdc8
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1395936
milestone57.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 1395936 - Avoid child index usage in HTMLEditor::DoContentInserted. r=masayuki
dom/base/nsRange.cpp
dom/base/nsRange.h
editor/libeditor/HTMLEditor.cpp
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -1482,16 +1482,32 @@ nsRange::SetEnd(nsINode* aContainer, uin
   }
 
   RawRangeBoundary newEnd(aContainer, aOffset);
   DoSetRange(mStart.AsRaw(), newEnd, mRoot);
 
   return NS_OK;
 }
 
+void
+nsRange::SelectNodesInContainer(nsINode* aContainer,
+                                nsIContent* aStartContent,
+                                nsIContent* aEndContent)
+{
+  MOZ_ASSERT(aContainer);
+  MOZ_ASSERT(aContainer->IndexOf(aStartContent) <=
+             aContainer->IndexOf(aEndContent));
+  MOZ_ASSERT(aStartContent && aContainer->IndexOf(aStartContent) != -1);
+  MOZ_ASSERT(aEndContent && aContainer->IndexOf(aEndContent) != -1);
+
+  RawRangeBoundary start(aContainer, aStartContent->GetPreviousSibling());
+  RawRangeBoundary end(aContainer, aEndContent);
+  DoSetRange(start, end, mRoot);
+}
+
 nsresult
 nsRange::SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
                         nsINode* aEndContainer, uint32_t aEndOffset)
 {
   if (NS_WARN_IF(!aStartContainer) || NS_WARN_IF(!aEndContainer)) {
     return NS_ERROR_INVALID_ARG;
   }
 
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -168,16 +168,28 @@ public:
    * If the specified start point is after the end point, the range will be
    * collapsed at the end point.  Similarly, if they are in different root,
    * the range will be collapsed at the end point.
    */
   nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
                           nsINode* aEndContainer, uint32_t aEndOffset);
 
   /**
+   * Adds all nodes between |aStartContent| and |aEndContent| to the range.
+   * The start offset will be set before |aStartContent|,
+   * while the end offset will be set immediately after |aEndContent|.
+   *
+   * Caller must guarantee both nodes are non null and
+   * children of |aContainer| and that |aEndContent| is after |aStartContent|.
+   */
+  void SelectNodesInContainer(nsINode* aContainer,
+                              nsIContent* aStartContent,
+                              nsIContent* aEndContent);
+
+  /**
    * CollapseTo() works similar to call both SetStart() and SetEnd() with
    * same node and offset.  This just calls SetStartAndParent() to set
    * collapsed range at aContainer and aOffset.
    */
   nsresult CollapseTo(nsINode* aContainer, uint32_t aOffset)
   {
     return SetStartAndEnd(aContainer, aOffset, aContainer, aOffset);
   }
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3188,19 +3188,22 @@ HTMLEditor::IsInObservedSubtree(nsIDocum
 
   return !aChild->ChromeOnlyAccess() && !aChild->GetBindingParent();
 }
 
 void
 HTMLEditor::DoContentInserted(nsIDocument* aDocument,
                               nsIContent* aContainer,
                               nsIContent* aChild,
-                              int32_t aIndexInContainer,
+                              int32_t /* aIndexInContainer */,
                               InsertedOrAppended aInsertedOrAppended)
 {
+  MOZ_DIAGNOSTIC_ASSERT(aContainer);
+  MOZ_DIAGNOSTIC_ASSERT(aChild);
+
   if (!IsInObservedSubtree(aDocument, aContainer, aChild)) {
     return;
   }
 
   // XXX Why do we need this? This method is a helper of mutation observer.
   //     So, the callers of mutation observer should guarantee that this won't
   //     be deleted at least during the call.
   RefPtr<HTMLEditor> kungFuDeathGrip(this);
@@ -3220,30 +3223,23 @@ HTMLEditor::DoContentInserted(nsIDocumen
     }
     // Protect the edit rules object from dying
     nsCOMPtr<nsIEditRules> rules(mRules);
     rules->DocumentModified();
 
     // Update spellcheck for only the newly-inserted node (bug 743819)
     if (mInlineSpellChecker) {
       RefPtr<nsRange> range = new nsRange(aChild);
-      int32_t endIndex = aIndexInContainer + 1;
+      nsIContent* endContent = aChild;
       if (aInsertedOrAppended == eAppended) {
-        // Count all the appended nodes
-        nsIContent* sibling = aChild->GetNextSibling();
-        while (sibling) {
-          endIndex++;
-          sibling = sibling->GetNextSibling();
-        }
+        // Maybe more than 1 child was appended.
+        endContent = aContainer->GetLastChild();
       }
-      nsresult rv = range->SetStartAndEnd(aContainer, aIndexInContainer,
-                                          aContainer, endIndex);
-      if (NS_SUCCEEDED(rv)) {
-        mInlineSpellChecker->SpellCheckRange(range);
-      }
+      range->SelectNodesInContainer(aContainer, aChild, endContent);
+      mInlineSpellChecker->SpellCheckRange(range);
     }
   }
 }
 
 void
 HTMLEditor::ContentRemoved(nsIDocument* aDocument,
                            nsIContent* aContainer,
                            nsIContent* aChild,