Bug 1442190 - Part 4: Add FLBDisplayItemIterator
MozReview-Commit-ID: 2Xtv30VE6Ew
--- 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.
*