Bug 1442190 - Part 4: Add FLBDisplayItemIterator r=mattwoodrow
authorMiko Mynttinen <mikokm@gmail.com>
Wed, 21 Mar 2018 12:27:13 +0100
changeset 413040 3bb3af9020e1431b1af0b323e873949f8dec7310
parent 413039 faf8093a7fbc982e7d12e192ec7384c4099933f8
child 413041 7c3ec4cce4893c84cb6bc47d2f4c185bc66a2d83
push id33831
push userrgurzau@mozilla.com
push dateThu, 12 Apr 2018 23:07:19 +0000
treeherdermozilla-central@46615d425bcb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1442190
milestone61.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 1442190 - Part 4: Add FLBDisplayItemIterator r=mattwoodrow MozReview-Commit-ID: 2Xtv30VE6Ew
layout/painting/FrameLayerBuilder.cpp
layout/painting/FrameLayerBuilder.h
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -50,16 +50,17 @@
 #include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/Unused.h"
 #include "GeckoProfiler.h"
 #include "LayersLogging.h"
 #include "gfxPrefs.h"
 
 #include <algorithm>
 #include <functional>
+#include <list>
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 
 class PaintedDisplayItemLayerUserData;
 
@@ -113,16 +114,109 @@ static inline MaskLayerImageCache* GetMa
 {
   if (!gMaskLayerImageCache) {
     gMaskLayerImageCache = new MaskLayerImageCache();
   }
 
   return gMaskLayerImageCache;
 }
 
+struct DisplayItemEntry {
+  DisplayItemEntry(nsDisplayItem* aItem,
+                   DisplayItemEntryType aType)
+    : mItem(aItem)
+    , mType(aType)
+  {}
+
+  nsDisplayItem* mItem;
+  DisplayItemEntryType mType;
+};
+
+class FLBDisplayItemIterator : protected FlattenedDisplayItemIterator
+{
+public:
+  FLBDisplayItemIterator(nsDisplayListBuilder* aBuilder,
+                         nsDisplayList* aList,
+                         ContainerState* aState)
+    : FlattenedDisplayItemIterator(aBuilder, aList, false)
+    , mState(aState)
+  {
+    MOZ_ASSERT(mState);
+    ResolveFlattening();
+  }
+
+  DisplayItemEntry GetNextEntry()
+  {
+    if (!mMarkers.empty()) {
+      DisplayItemEntry entry = mMarkers.front();
+      mMarkers.pop_front();
+      return entry;
+    }
+
+    nsDisplayItem* next = GetNext();
+    return DisplayItemEntry { next, DisplayItemEntryType::ITEM };
+  }
+
+  nsDisplayItem* GetNext()
+  {
+    // This function is only supposed to be called if there are no markers set.
+    // Breaking this invariant can potentially break effect flattening and/or
+    // display item merging.
+    MOZ_ASSERT(mMarkers.empty());
+
+    return FlattenedDisplayItemIterator::GetNext();
+  }
+
+  bool HasNext() const
+  {
+    return FlattenedDisplayItemIterator::HasNext() || !mMarkers.empty();
+  }
+
+  nsDisplayItem* PeekNext()
+  {
+    return mNext;
+  }
+
+private:
+  bool ShouldFlattenNextItem() const override;
+
+  void StartNested(nsDisplayItem* aItem) override
+  {
+    if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) {
+      nsDisplayOpacity* opacity = static_cast<nsDisplayOpacity*> (aItem);
+
+      if (opacity->OpacityAppliedToChildren()) {
+        // If the opacity was already applied to children, there is no need to
+        // emit opacity markers.
+        return;
+      }
+
+      mMarkers.emplace_back(aItem, DisplayItemEntryType::PUSH_OPACITY);
+      mActiveMarkers.AppendElement(aItem);
+    }
+  }
+
+  void EndNested(nsDisplayItem* aItem) override
+  {
+    if (mActiveMarkers.IsEmpty() || mActiveMarkers.LastElement() != aItem) {
+      // Do not emit an end marker if this item did not emit a start marker.
+      return;
+    }
+
+    if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) {
+      mMarkers.emplace_back(aItem, DisplayItemEntryType::POP_OPACITY);
+      mActiveMarkers.RemoveLastElement();
+    }
+  }
+
+  std::list<DisplayItemEntry> mMarkers;
+  AutoTArray<nsDisplayItem*, 4> mActiveMarkers;
+  ContainerState* mState;
+};
+
 DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey,
                                  Layer* aLayer, nsIFrame* aFrame)
 
   : mRefCnt(0)
   , mParent(aParent)
   , mLayer(aLayer)
   , mDisplayItemKey(aKey)
   , mItem(nullptr)
@@ -1209,16 +1303,17 @@ public:
    * aData. Make sure that a real PaintedLayer exists for it, and set the final
    * visible region and opaque-content.
    */
   template<typename FindOpaqueBackgroundColorCallbackType>
   void FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor);
 
 protected:
   friend class PaintedLayerData;
+  friend class FLBDisplayItemIterator;
 
   LayerManager::PaintedLayerCreationHint
     GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot);
 
   /**
    * Creates a new PaintedLayer and sets up the transform on the PaintedLayer
    * to account for scrolling.
    */
@@ -1472,16 +1567,53 @@ protected:
   nsDataHashtable<nsGenericHashKey<MaskLayerKey>, RefPtr<ImageLayer>>
     mRecycledMaskImageLayers;
   // Keep display port of AGR to avoid wasting time on doing the same
   // thing repeatly.
   AnimatedGeometryRoot* mLastDisplayPortAGR;
   nsRect mLastDisplayPortRect;
 };
 
+bool
+FLBDisplayItemIterator::ShouldFlattenNextItem() const
+{
+  if (!mNext) {
+    return false;
+  }
+
+  if (!mNext->ShouldFlattenAway(mBuilder)) {
+    return false;
+  }
+
+  if (mNext->GetType() == DisplayItemType::TYPE_OPACITY) {
+    nsDisplayOpacity* opacity = static_cast<nsDisplayOpacity*>(mNext);
+
+    if (opacity->OpacityAppliedToChildren()) {
+      // This is the previous opacity flattening path, where the opacity has
+      // been applied to children.
+      return true;
+    }
+
+    if (!mState->mManager->IsWidgetLayerManager()) {
+      // Do not flatten opacity inside an inactive layer tree.
+      return false;
+    }
+
+    LayerState layerState = mNext->GetLayerState(mState->mBuilder,
+                                                 mState->mManager,
+                                                 mState->mParameters);
+
+    // Do not flatten opacity if child display items require an active layer.
+    return (layerState == LayerState::LAYER_NONE ||
+            layerState == LayerState::LAYER_INACTIVE);
+  }
+
+  return true;
+}
+
 class PaintedDisplayItemLayerUserData : public LayerUserData
 {
 public:
   PaintedDisplayItemLayerUserData()
     : mForcedBackgroundColor(NS_RGBA(0, 0, 0, 0))
     , mXScale(1.f)
     , mYScale(1.f)
     , mAppUnitsPerDevPixel(0)
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -40,16 +40,22 @@ class ImageLayer;
 } // namespace layers
 
 class FrameLayerBuilder;
 class LayerManagerData;
 class PaintedLayerData;
 class ContainerState;
 class PaintedDisplayItemLayerUserData;
 
+enum class DisplayItemEntryType {
+  ITEM,
+  PUSH_OPACITY,
+  POP_OPACITY
+};
+
 /**
   * Retained data storage:
   *
   * Each layer manager (widget, and inactive) stores a LayerManagerData object
   * that keeps a hash-set of DisplayItemData items that were drawn into it.
   * Each frame also keeps a list of DisplayItemData pointers that were
   * created for that frame. DisplayItemData objects manage these lists automatically.
   *