Bug 1547624 - Start inactive Layer building during ProcessDisplayItems so that any contained hit-test info gets propagated to the outer Layer before we add the next item. r=miko a=jcristau
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 27 May 2019 04:28:37 +0000
changeset 537092 af24c9d1390f50ef1e5eff3ade5fcc7ca633b440
parent 537091 00c027a75c1cb7eff3d58b029f6764019abbb8ac
child 537093 4ae8f7ba99880f6693f5281c76dbb8e41bab11ff
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmiko, jcristau
bugs1547624
milestone68.0
Bug 1547624 - Start inactive Layer building during ProcessDisplayItems so that any contained hit-test info gets propagated to the outer Layer before we add the next item. r=miko a=jcristau Differential Revision: https://phabricator.services.mozilla.com/D32261
layout/painting/FrameLayerBuilder.cpp
layout/painting/FrameLayerBuilder.h
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -563,16 +563,18 @@ class PaintedLayerData {
         mNewChildLayersIndex(-1)
 #ifdef DEBUG
         ,
         mTransformLevel(0)
 #endif
   {
   }
 
+  PaintedLayerData(PaintedLayerData&& aRhs) = default;
+
   ~PaintedLayerData() { MOZ_ASSERT(mTransformLevel == 0); }
 
 #ifdef MOZ_DUMP_PAINTING
   /**
    * Keep track of important decisions for debugging.
    */
   nsCString mLog;
 
@@ -603,16 +605,20 @@ class PaintedLayerData {
    */
   void Accumulate(ContainerState* aState, nsPaintedDisplayItem* aItem,
                   const nsIntRect& aVisibleRect, const nsRect& aContentRect,
                   const DisplayItemClip& aClip, LayerState aLayerState,
                   nsDisplayList* aList, DisplayItemEntryType aType,
                   nsTArray<size_t>& aOpacityIndices,
                   const RefPtr<TransformClipNode>& aTransform);
 
+  UniquePtr<InactiveLayerData> CreateInactiveLayerData(
+      ContainerState* aState, nsPaintedDisplayItem* aItem,
+      DisplayItemData* aData);
+
   /**
    * Updates the status of |mTransform| and |aOpacityIndices|, based on |aType|.
    */
   void UpdateEffectStatus(DisplayItemEntryType aType,
                           nsTArray<size_t>& aOpacityIndices);
 
   AnimatedGeometryRoot* GetAnimatedGeometryRoot() {
     return mAnimatedGeometryRoot;
@@ -1306,16 +1312,17 @@ class ContainerState {
       return ScaleRegionToNearestPixels(aRegion);
     }
     return aRegion.ScaleToOutsidePixels(
         mParameters.mXScale, mParameters.mYScale, mAppUnitsPerDevPixel);
   }
 
   nsIFrame* GetContainerFrame() const { return mContainerFrame; }
   nsDisplayListBuilder* Builder() const { return mBuilder; }
+  FrameLayerBuilder* LayerBuilder() const { return mLayerBuilder; }
 
   /**
    * Check if we are currently inside an inactive layer.
    */
   bool IsInInactiveLayer() const {
     return mLayerBuilder->GetContainingPaintedLayerData();
   }
 
@@ -3462,17 +3469,17 @@ void ContainerState::FinishPaintedLayerD
                DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO);
 
     if (IsEffectEndMarker(item.mType)) {
       // Do not invalidate for end markers.
       continue;
     }
 
     InvalidateForLayerChange(item.mItem, data->mLayer, item.mDisplayItemData);
-    mLayerBuilder->AddPaintedDisplayItem(data, item, *this, layer);
+    mLayerBuilder->AddPaintedDisplayItem(data, item, layer);
     item.mDisplayItemData = nullptr;
   }
 
   if (mLayerBuilder->IsBuildingRetainedLayers()) {
     newLayerEntry->mVisibleRegion = data->mVisibleRegion;
     newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
     newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
     newLayerEntry->mOpaqueForAnimatedGeometryRootParent =
@@ -3729,16 +3736,44 @@ bool PaintedLayerData::SetupComponentAlp
       aItem->DisableComponentAlpha();
       return false;
     }
   }
 
   return true;
 }
 
+UniquePtr<InactiveLayerData> PaintedLayerData::CreateInactiveLayerData(
+    ContainerState* aState, nsPaintedDisplayItem* aItem,
+    DisplayItemData* aData) {
+  RefPtr<BasicLayerManager> tempManager;
+  if (aData) {
+    tempManager = aData->InactiveManager();
+  }
+  if (!tempManager) {
+    tempManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
+  }
+  UniquePtr<InactiveLayerData> data = MakeUnique<InactiveLayerData>();
+  data->mLayerManager = tempManager;
+
+  data->mLayerBuilder = new FrameLayerBuilder();
+  data->mLayerBuilder->Init(aState->Builder(), tempManager, this, true,
+                            &aItem->GetClip());
+
+  tempManager->BeginTransaction();
+  if (aState->LayerBuilder()->GetRetainingLayerManager()) {
+    data->mLayerBuilder->DidBeginRetainedLayerTransaction(tempManager);
+  }
+
+  data->mProps = LayerProperties::CloneFrom(tempManager->GetRoot());
+  data->mLayer = aItem->BuildLayer(aState->Builder(), tempManager,
+                                   ContainerLayerParameters());
+  return data;
+}
+
 void PaintedLayerData::Accumulate(
     ContainerState* aState, nsPaintedDisplayItem* aItem,
     const nsIntRect& aVisibleRect, const nsRect& aContentRect,
     const DisplayItemClip& aClip, LayerState aLayerState, nsDisplayList* aList,
     DisplayItemEntryType aType, nsTArray<size_t>& aOpacityIndices,
     const RefPtr<TransformClipNode>& aTransform) {
   // If aItem is nullptr, the cast to nsPaintedDisplayItem failed.
   MOZ_ASSERT(aItem, "Can only accumulate display items that are painted!");
@@ -3771,16 +3806,23 @@ void PaintedLayerData::Accumulate(
 
   DisplayItemData* oldData = aState->mLayerBuilder->GetOldLayerForFrame(
       aItem->Frame(), aItem->GetPerFrameKey(), currentData,
       aItem->GetDisplayItemDataLayerManager());
 
   mAssignedDisplayItems.emplace_back(aItem, aLayerState, oldData, aContentRect,
                                      aType, hasOpacity, aTransform, isMerged);
 
+  if (aLayerState != LayerState::LAYER_NONE) {
+    FLB_LOG_PAINTED_LAYER_DECISION(this, "Creating nested FLB for item %p\n",
+                                   aItem);
+    mAssignedDisplayItems.back().mInactiveLayerData =
+        CreateInactiveLayerData(aState, aItem, oldData);
+  }
+
   if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
     mForceTransparentSurface = true;
   }
 
   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
     // Disable component alpha.
     // Note that the transform (if any) on the PaintedLayer is always an integer
     // translation so we don't have to factor that in here.
@@ -5289,87 +5331,55 @@ void FrameLayerBuilder::ComputeGeometryC
                                   layerData->mTranslation);
   }
 
   aData->EndUpdate(geometry);
 }
 
 void FrameLayerBuilder::AddPaintedDisplayItem(PaintedLayerData* aLayerData,
                                               AssignedDisplayItem& aItem,
-                                              ContainerState& aContainerState,
                                               Layer* aLayer) {
   PaintedLayer* layer = aLayerData->mLayer;
   PaintedDisplayItemLayerUserData* paintedData =
       static_cast<PaintedDisplayItemLayerUserData*>(
           layer->GetUserData(&gPaintedDisplayItemLayerUserData));
-  RefPtr<BasicLayerManager> tempManager;
-  nsIntRect intClip;
-  if (aItem.mLayerState != LayerState::LAYER_NONE) {
-    if (aItem.mDisplayItemData) {
-      tempManager = aItem.mDisplayItemData->mInactiveManager;
-
-      // We need to grab these before updating the DisplayItemData because it
-      // will overwrite them.
-      nsRegion clip;
-      if (aItem.mItem->GetClip().ComputeRegionInClips(
-              &aItem.mDisplayItemData->GetClip(),
-              aLayerData->mAnimatedGeometryRootOffset -
-                  paintedData->mLastAnimatedGeometryRootOrigin,
-              &clip)) {
-        intClip = clip.GetBounds().ScaleToOutsidePixels(
-            paintedData->mXScale, paintedData->mYScale,
-            paintedData->mAppUnitsPerDevPixel);
-      }
-    }
-    if (!tempManager) {
-      tempManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
-    }
-  }
 
   if (layer->Manager() == mRetainingManager) {
     DisplayItemData* data = aItem.mDisplayItemData;
     if (data && !data->mUsed) {
       data->BeginUpdate(layer, aItem.mLayerState, aItem.mItem, aItem.mReused,
                         aItem.mMerged);
     } else {
       if (data && data->mUsed) {
         // If the DID has already been used (by a previously merged frame,
         // which is not merged this paint) we must create a new DID for the
         // item.
         aItem.mItem->SetDisplayItemData(nullptr, nullptr);
       }
       data = StoreDataForFrame(aItem.mItem, layer, aItem.mLayerState, nullptr);
     }
-    data->mInactiveManager = tempManager;
+    data->mInactiveManager = aItem.mInactiveLayerData
+                                 ? aItem.mInactiveLayerData->mLayerManager
+                                 : nullptr;
     // We optimized this PaintedLayer into a ColorLayer/ImageLayer. Store the
     // optimized layer here.
     if (aLayer != layer) {
       data->mOptLayer = aLayer;
     }
 
     data->mOldTransform = data->mTransform;
     data->mTransform = aItem.mTransform;
   }
 
-  if (tempManager) {
-    FLB_LOG_PAINTED_LAYER_DECISION(
-        aLayerData, "Creating nested FLB for item %p\n", aItem.mItem);
-    FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
-    layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData, true,
-                       &aItem.mItem->GetClip());
-
-    tempManager->BeginTransaction();
-    if (mRetainingManager) {
-      layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
-    }
-
-    UniquePtr<LayerProperties> props(
-        LayerProperties::CloneFrom(tempManager->GetRoot()));
-    RefPtr<Layer> tmpLayer = aItem.mItem->BuildLayer(
-        mDisplayListBuilder, tempManager, ContainerLayerParameters());
+  if (aItem.mInactiveLayerData) {
+    RefPtr<BasicLayerManager> tempManager =
+        aItem.mInactiveLayerData->mLayerManager;
+    FrameLayerBuilder* layerBuilder = aItem.mInactiveLayerData->mLayerBuilder;
+    Layer* tmpLayer = aItem.mInactiveLayerData->mLayer;
+
     // We have no easy way of detecting if this transaction will ever actually
     // get finished. For now, I've just silenced the warning with nested
     // transactions in BasicLayers.cpp
     if (!tmpLayer) {
       tempManager->EndTransaction(nullptr, nullptr);
       tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
       aItem.mItem = nullptr;
       return;
@@ -5423,21 +5433,22 @@ void FrameLayerBuilder::AddPaintedDispla
       tempManager->Dump(stream, "", gfxEnv::DumpPaintToFile());
       fprint_stderr(
           gfxUtils::sDumpPaintFile,
           stream);  // not a typo, fprint_stderr declared in LayersLogging.h
     }
 
     nsIntPoint offset =
         GetLastPaintOffset(layer) - GetTranslationForPaintedLayer(layer);
-    props->MoveBy(-offset);
+    aItem.mInactiveLayerData->mProps->MoveBy(-offset);
     // Effective transforms are needed by ComputeDifferences().
     tmpLayer->ComputeEffectiveTransforms(Matrix4x4());
     nsIntRegion invalid;
-    if (!props->ComputeDifferences(tmpLayer, invalid, nullptr)) {
+    if (!aItem.mInactiveLayerData->mProps->ComputeDifferences(tmpLayer, invalid,
+                                                              nullptr)) {
       nsRect visible = aItem.mItem->Frame()->GetVisualOverflowRect();
       invalid = visible.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel);
     }
     if (aItem.mLayerState == LayerState::LAYER_SVG_EFFECTS) {
       invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(
           aItem.mItem->Frame(), aItem.mItem->ToReferenceFrame(), invalid);
     }
     if (!invalid.IsEmpty()) {
@@ -5456,17 +5467,16 @@ void FrameLayerBuilder::AddPaintedDispla
       }
 
       invalid.ScaleRoundOut(paintedData->mXScale, paintedData->mYScale);
 
       InvalidatePostTransformRegion(layer, invalid,
                                     GetTranslationForPaintedLayer(layer));
     }
   }
-  aItem.mInactiveLayerManager = tempManager;
 }
 
 DisplayItemData* FrameLayerBuilder::StoreDataForFrame(
     nsPaintedDisplayItem* aItem, Layer* aLayer, LayerState aState,
     DisplayItemData* aData) {
   MOZ_ASSERT(aItem);
 
   if (aData) {
@@ -5519,19 +5529,19 @@ AssignedDisplayItem::AssignedDisplayItem
       mContentRect(aContentRect),
       mLayerState(aLayerState),
       mType(aType),
       mReused(aItem->IsReused()),
       mMerged(aIsMerged),
       mHasOpacity(aHasOpacity),
       mHasPaintRect(aItem->HasPaintRect()) {}
 
-AssignedDisplayItem::~AssignedDisplayItem() {
-  if (mInactiveLayerManager) {
-    mInactiveLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
+InactiveLayerData::~InactiveLayerData() {
+  if (mLayerManager) {
+    mLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
   }
 }
 
 nsIntPoint FrameLayerBuilder::GetLastPaintOffset(PaintedLayer* aLayer) {
   PaintedDisplayItemLayerUserData* layerData =
       GetPaintedDisplayItemLayerUserData(aLayer);
   MOZ_ASSERT(layerData);
   if (layerData->mHasExplicitLastPaintOffset) {
@@ -7016,17 +7026,17 @@ void FrameLayerBuilder::PaintItems(std::
     if (cdi.mType != DisplayItemEntryType::Item) {
 #ifdef DEBUG
       UpdateEffectTracking(opacityLevel, transformLevel, cdi.mType);
 #endif
       // Nothing more to do with effect markers.
       continue;
     }
 
-    const bool paintAsLayer = cdi.mInactiveLayerManager;
+    const bool paintAsLayer = cdi.mInactiveLayerData.get();
     nsPaintedDisplayItem* paintedItem = item->AsPaintedDisplayItem();
     MOZ_ASSERT(paintAsLayer || paintedItem,
                "The display item does not support painting");
 
     const DisplayItemClip* itemClip = GetItemClip(item, temporaryClip);
     bool itemPaintsOwnClip = false;
 
     if (itemClip && !itemClipTracker.HasClip(itemClip)) {
@@ -7045,18 +7055,18 @@ void FrameLayerBuilder::PaintItems(std::
 
     if (!itemClip) {
       // Item does not need clipping, remove the clip if there is one.
       itemClipTracker.Restore();
     }
 
     if (paintAsLayer) {
       bool saved = aDrawTarget.GetPermitSubpixelAA();
-      PaintInactiveLayer(aBuilder, cdi.mInactiveLayerManager, item, aContext,
-                         aContext);
+      PaintInactiveLayer(aBuilder, cdi.mInactiveLayerData->mLayerManager, item,
+                         aContext, aContext);
       aDrawTarget.SetPermitSubpixelAA(saved);
       continue;
     }
 
     nsIFrame* frame = item->Frame();
     if (aBuilder->IsPaintingToWindow()) {
       frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
     }
@@ -7274,26 +7284,37 @@ void FrameLayerBuilder::DumpRetainedLaye
   aManager->Dump(aStream, "", aDumpHtml);
 }
 
 nsDisplayItemGeometry* FrameLayerBuilder::GetMostRecentGeometry(
     nsDisplayItem* aItem) {
   typedef SmallPointerArray<DisplayItemData> DataArray;
 
   // Retrieve the array of DisplayItemData associated with our frame.
-  const DataArray& dataArray = aItem->Frame()->DisplayItemData();
+  DataArray& dataArray = aItem->Frame()->DisplayItemData();
 
   // Find our display item data, if it exists, and return its geometry.
+  // We first check for ones with an inactive manager, since items that
+  // create inactive layers will create two DisplayItemData entries,
+  // and we want the outer one.
+  DisplayItemData* firstMatching = nullptr;
   uint32_t itemPerFrameKey = aItem->GetPerFrameKey();
-  for (uint32_t i = 0; i < dataArray.Length(); i++) {
-    DisplayItemData* data =
-        DisplayItemData::AssertDisplayItemData(dataArray.ElementAt(i));
+  for (DisplayItemData* data : dataArray) {
+    DisplayItemData::AssertDisplayItemData(data);
     if (data->GetDisplayItemKey() == itemPerFrameKey) {
-      return data->GetGeometry();
-    }
+      if (data->InactiveManager()) {
+        return data->GetGeometry();
+      }
+      if (!firstMatching) {
+        firstMatching = data;
+      }
+    }
+  }
+  if (firstMatching) {
+    return firstMatching->GetGeometry();
   }
   if (RefPtr<WebRenderFallbackData> data =
           GetWebRenderUserData<WebRenderFallbackData>(aItem->Frame(),
                                                       itemPerFrameKey)) {
     return data->GetGeometry();
   }
 
   return nullptr;
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -35,16 +35,17 @@ namespace mozilla {
 struct ActiveScrolledRoot;
 struct DisplayItemClipChain;
 namespace layers {
 class ContainerLayer;
 class LayerManager;
 class BasicLayerManager;
 class PaintedLayer;
 class ImageLayer;
+struct LayerProperties;
 }  // namespace layers
 
 class FrameLayerBuilder;
 class LayerManagerData;
 class PaintedLayerData;
 class ContainerState;
 class PaintedDisplayItemLayerUserData;
 
@@ -84,16 +85,19 @@ class DisplayItemData final {
   layers::Layer* GetLayer() const { return mLayer; }
   nsDisplayItemGeometry* GetGeometry() const { return mGeometry.get(); }
   const DisplayItemClip& GetClip() const { return mClip; }
   void Invalidate() { mIsInvalid = true; }
   void ClearAnimationCompositorState();
   void SetItem(nsPaintedDisplayItem* aItem) { mItem = aItem; }
   nsPaintedDisplayItem* GetItem() const { return mItem; }
   nsIFrame* FirstFrame() const { return mFrameList[0]; }
+  layers::BasicLayerManager* InactiveManager() const {
+    return mInactiveManager;
+  }
 
   bool HasMergedFrames() const { return mFrameList.Length() > 1; }
 
   static DisplayItemData* AssertDisplayItemData(DisplayItemData* aData);
 
   void* operator new(size_t sz, nsPresContext* aPresContext) {
     // Check the recycle list first.
     return aPresContext->PresShell()->AllocateByObjectID(
@@ -218,37 +222,46 @@ class RefCountedRegion {
  public:
   NS_INLINE_DECL_REFCOUNTING(RefCountedRegion)
 
   RefCountedRegion() : mIsInfinite(false) {}
   nsRegion mRegion;
   bool mIsInfinite;
 };
 
+struct InactiveLayerData {
+  RefPtr<layers::BasicLayerManager> mLayerManager;
+  FrameLayerBuilder* mLayerBuilder;
+  RefPtr<layers::Layer> mLayer;
+  UniquePtr<layers::LayerProperties> mProps;
+
+  ~InactiveLayerData();
+};
+
 struct AssignedDisplayItem {
   AssignedDisplayItem(nsPaintedDisplayItem* aItem, LayerState aLayerState,
                       DisplayItemData* aData, const nsRect& aContentRect,
                       DisplayItemEntryType aType, const bool aHasOpacity,
                       const RefPtr<TransformClipNode>& aTransform,
                       const bool aIsMerged);
-  ~AssignedDisplayItem();
+  AssignedDisplayItem(AssignedDisplayItem&& aRhs) = default;
 
   bool HasOpacity() const { return mHasOpacity; }
 
   bool HasTransform() const { return mTransform; }
 
   nsPaintedDisplayItem* mItem;
   DisplayItemData* mDisplayItemData;
 
   /**
    * If the display item is being rendered as an inactive
    * layer, then this stores the layer manager being
    * used for the inactive transaction.
    */
-  RefPtr<layers::LayerManager> mInactiveLayerManager;
+  UniquePtr<InactiveLayerData> mInactiveLayerData;
   RefPtr<TransformClipNode> mTransform;
 
   nsRect mContentRect;
   LayerState mLayerState;
   DisplayItemEntryType mType;
 
   bool mReused;
   bool mMerged;
@@ -538,17 +551,17 @@ class FrameLayerBuilder : public layers:
    * Record aItem as a display item that is rendered by the PaintedLayer
    * aLayer, with aClipRect, where aContainerLayerFrame is the frame
    * for the container layer this ThebesItem belongs to.
    * aItem must have an underlying frame.
    * @param aTopLeft offset from active scrolled root to reference frame
    */
   void AddPaintedDisplayItem(PaintedLayerData* aLayerData,
                              AssignedDisplayItem& aAssignedDisplayItem,
-                             ContainerState& aContainerState, Layer* aLayer);
+                             Layer* aLayer);
 
   /**
    * Calls GetOldLayerForFrame on the underlying frame of the display item,
    * and each subsequent merged frame if no layer is found for the underlying
    * frame.
    */
   Layer* GetOldLayerFor(nsDisplayItem* aItem,
                         nsDisplayItemGeometry** aOldGeometry = nullptr,