Bug 1377329 - Part 2. Entend the capacity of mFramesMarkedForDisplay only when need. draft
authorcku <cku@mozilla.com>
Fri, 14 Jul 2017 01:47:34 +0800
changeset 608743 900ac68d9a8d183403caea4f71bab1546c3d676f
parent 608742 3ff95ff1c6776ea080962e2de35bc18f526f3f92
child 637415 e9df490288e0af0955111ef8606a66b6ff33b586
push id68404
push userbmo:cku@mozilla.com
push dateFri, 14 Jul 2017 06:08:54 +0000
bugs1377329
milestone56.0a1
Bug 1377329 - Part 2. Entend the capacity of mFramesMarkedForDisplay only when need. There patch did two things: 1. Enlarge default capacity size of mFramesMarkedForDisplay from 200 to 400. For gmail, 200 is too small, we always need to enlarge capaicty of this array in nsDisplayListBuilder::MarkFramesForDisplayList. 2. Enlarge the capacity of mFramesMarkedForDisplay when need to prevent unnecessary calls of nsFrameList::GetLength(). Although we cache frame length in Part 1, nsFrameList::GetLength is still costly while using for the first time. MozReview-Commit-ID: 5zSxyakZ5O9
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1274,30 +1274,37 @@ nsDisplayListBuilder::ResetMarkedFramesF
   }
   mFramesMarkedForDisplay.SetLength(firstFrameForShell);
 }
 
 void
 nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
                                                const nsFrameList& aFrames,
                                                const nsRect& aDirtyRect) {
-  mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength());
+  int count = 0;
   for (nsIFrame* e : aFrames) {
     // Skip the AccessibleCaret frame when building no caret.
     if (!IsBuildingCaret()) {
       nsIContent* content = e->GetContent();
       if (content && content->IsInNativeAnonymousSubtree() && content->IsElement()) {
         auto classList = content->AsElement()->ClassList();
         if (classList->Contains(NS_LITERAL_STRING("moz-accessiblecaret"))) {
           continue;
         }
       }
     }
+
+    if (mFramesMarkedForDisplay.Length() == mFramesMarkedForDisplay.Capacity()) {
+      // nsFrameList::GetLength() is O(N), use it only when we have to.
+      mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength() - count);
+    }
+
     mFramesMarkedForDisplay.AppendElement(e);
     MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, aDirtyRect);
+    count++;
   }
 
   if (!aDirtyFrame->GetParent()) {
     // This is the viewport frame of aDirtyFrame's presshell.
     // Store the current display data so that it can be used for fixed
     // background images.
     NS_ASSERTION(CurrentPresShellState()->mPresShell ==
         aDirtyFrame->PresContext()->PresShell(),
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1475,17 +1475,17 @@ private:
   nsDisplayLayerEventRegions*    mLayerEventRegions;
 
   static const size_t kArenaAlignment =
       mozilla::tl::Max<NS_ALIGNMENT_OF(void*), NS_ALIGNMENT_OF(double)>::value;
   mozilla::ArenaAllocator<4096, kArenaAlignment> mPool;
 
   nsCOMPtr<nsISelection>         mBoundingSelection;
   AutoTArray<PresShellState,8> mPresShellStates;
-  AutoTArray<nsIFrame*,100>    mFramesMarkedForDisplay;
+  AutoTArray<nsIFrame*,400>    mFramesMarkedForDisplay;
   AutoTArray<ThemeGeometry,2>  mThemeGeometries;
   nsDisplayTableItem*            mCurrentTableItem;
   DisplayListClipState           mClipState;
   const ActiveScrolledRoot*      mCurrentActiveScrolledRoot;
   const ActiveScrolledRoot*      mCurrentContainerASR;
   // mCurrentFrame is the frame that we're currently calling (or about to call)
   // BuildDisplayList on.
   const nsIFrame*                mCurrentFrame;