Bug 1393816 - part2: Selection::SetBaseAndExtent() should use mCachedRange if it's available r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 26 Aug 2017 00:12:38 +0900
changeset 653803 054983a8b61484e2c428dcef467d9c031c31f029
parent 653802 180f89601b4525a372689e97b1d48306ee78dee7
child 728419 8c3e17e18175d85917bd7b60360876b0f2a5c6f1
push id76414
push usermasayuki@d-toybox.com
push dateMon, 28 Aug 2017 03:10:45 +0000
reviewerssmaug
bugs1393816
milestone57.0a1
Bug 1393816 - part2: Selection::SetBaseAndExtent() should use mCachedRange if it's available r?smaug Similar to Selection::Collapse(), if mCachedRange is available, Selection::SetBaseAndExtent() should use it rather than creating new nsRange instance. Then, it can reduce the allocation cost and may reduce some other cost, e.g., adding it to mutation observer. MozReview-Commit-ID: InQQusw2KMc
dom/base/Selection.cpp
dom/base/Selection.h
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -4074,49 +4074,54 @@ Selection::SetBaseAndExtent(nsINode& aAn
   }
 
   if (!HasSameRoot(aAnchorNode) ||
       !HasSameRoot(aFocusNode)) {
     // Return with no error
     return;
   }
 
-  // Since a range will be created, we don't need the cached range because
-  // Collapse() won't use it.
-  // TODO: We should use the cache.
-  mCachedRange = nullptr;
-
   SelectionBatcher batch(this);
 
   int32_t relativePosition =
     nsContentUtils::ComparePoints(&aAnchorNode, aAnchorOffset,
                                   &aFocusNode, aFocusOffset);
   nsINode* start = &aAnchorNode;
   nsINode* end = &aFocusNode;
   uint32_t startOffset = aAnchorOffset;
   uint32_t endOffset = aFocusOffset;
   if (relativePosition > 0) {
     start = &aFocusNode;
     end = &aAnchorNode;
     startOffset = aFocusOffset;
     endOffset = aAnchorOffset;
   }
 
-  RefPtr<nsRange> newRange;
-  nsresult rv = nsRange::CreateRange(start, startOffset, end, endOffset,
-                                     getter_AddRefs(newRange));
-  // CreateRange returns IndexSizeError if any offset is out of bounds.
+  // If there is cached range, we should reuse it for saving the allocation
+  // const (and some other cost in nsRange::DoSetRange().
+  RefPtr<nsRange> newRange = Move(mCachedRange);
+
+  nsresult rv = NS_OK;
+  if (newRange) {
+    rv = newRange->SetStartAndEnd(start, startOffset, end, endOffset);
+  } else {
+    rv = nsRange::CreateRange(start, startOffset, end, endOffset,
+                              getter_AddRefs(newRange));
+  }
+
+  // nsRange::SetStartAndEnd() and nsRange::CreateRange() returns
+  // IndexSizeError if any offset is out of bounds.
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
-  rv = RemoveAllRanges();
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
+  // Use non-virtual method instead of nsISelection::RemoveAllRanges().
+  RemoveAllRanges(aRv);
+  if (aRv.Failed()) {
     return;
   }
 
   rv = AddRange(newRange);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
--- a/dom/base/Selection.h
+++ b/dom/base/Selection.h
@@ -477,20 +477,20 @@ private:
   // two binary searches plus up to an additional 6 DOM comparisons. If this
   // proves to be a performance concern, then an interval tree may be a
   // possible solution, allowing the calculation of the overlap interval in
   // O(log n) time, though this would require rebalancing and other overhead.
   AutoTArray<RangeData, 1> mRanges;
 
   RefPtr<nsRange> mAnchorFocusRange;
   // mCachedRange is set by RemoveAllRangesTemporarily() and used by
-  // Collapse().  If there is a range which will be released by Clear(),
-  // RemoveAllRangesTemporarily() stores it with this.  If Collapse() is
-  // called without existing ranges, it'll reuse this range for saving the
-  // creating cost.
+  // Collapse() and SetBaseAndExtent().  If there is a range which will be
+  // released by Clear(), RemoveAllRangesTemporarily() stores it with this.
+  // If Collapse() is called without existing ranges, it'll reuse this range
+  // for saving the creation cost.
   RefPtr<nsRange> mCachedRange;
   RefPtr<nsFrameSelection> mFrameSelection;
   RefPtr<nsAutoScrollTimer> mAutoScrollTimer;
   FallibleTArray<nsCOMPtr<nsISelectionListener>> mSelectionListeners;
   nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;
   CachedOffsetForFrame* mCachedOffsetForFrame;
   nsDirection mDirection;
   SelectionType mSelectionType;