Bug 1442190 - Part 3: Add functionality to know whether nsDisplayOpacity::ShouldFlattenAway() applied opacity to children
MozReview-Commit-ID: Bns788u5wmM
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6404,16 +6404,17 @@ nsresult nsDisplayWrapper::WrapListsInPl
nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const ActiveScrolledRoot* aActiveScrolledRoot,
bool aForEventsAndPluginsOnly)
: nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true)
, mOpacity(aFrame->StyleEffects()->mOpacity)
, mForEventsAndPluginsOnly(aForEventsAndPluginsOnly)
+ , mOpacityAppliedToChildren(false)
{
MOZ_COUNT_CTOR(nsDisplayOpacity);
mState.mOpacity = mOpacity;
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsDisplayOpacity::~nsDisplayOpacity() {
MOZ_COUNT_DTOR(nsDisplayOpacity);
@@ -6539,37 +6540,18 @@ CollectItemsWithOpacity(nsDisplayList* a
aArray.AppendElement(i);
}
return true;
}
bool
-nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
-{
- if (mFrame->GetPrevContinuation() ||
- mFrame->GetNextContinuation()) {
- // If we've been split, then we might need to merge, so
- // don't flatten us away.
- return false;
- }
-
- if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) {
- // If our opacity is zero then we'll discard all descendant display items
- // except for layer event regions, so there's no point in doing this
- // optimization (and if we do do it, then invalidations of those descendants
- // might trigger repainting).
- return false;
- }
-
- if (mList.IsEmpty()) {
- return false;
- }
-
+nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder)
+{
// Only try folding our opacity down if we have at most kMaxChildCount
// children that don't overlap and can all apply the opacity to themselves.
static const size_t kMaxChildCount = 3;
// Iterate through the child display list and copy at most kMaxChildCount
// child display item pointers to a temporary list.
AutoTArray<nsDisplayItem*, kMaxChildCount> items;
if (!CollectItemsWithOpacity(&mList, items, kMaxChildCount)) {
@@ -6596,19 +6578,48 @@ nsDisplayOpacity::ShouldFlattenAway(nsDi
}
}
}
for (uint32_t i = 0; i < childCount; i++) {
children[i].item->ApplyOpacity(aBuilder, mOpacity, mClipChain);
}
+ mOpacityAppliedToChildren = true;
return true;
}
+bool
+nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
+{
+ // ShouldFlattenAway() should be called only once during painting.
+ MOZ_ASSERT(!mOpacityAppliedToChildren);
+
+ if (mFrame->GetPrevContinuation() ||
+ mFrame->GetNextContinuation()) {
+ // If we've been split, then we might need to merge, so
+ // don't flatten us away.
+ return false;
+ }
+
+ if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) {
+ // If our opacity is zero then we'll discard all descendant display items
+ // except for layer event regions, so there's no point in doing this
+ // optimization (and if we do do it, then invalidations of those descendants
+ // might trigger repainting).
+ return false;
+ }
+
+ if (mList.IsEmpty()) {
+ return false;
+ }
+
+ return ApplyOpacityToChildren(aBuilder);
+}
+
nsDisplayItem::LayerState
nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) {
// If we only created this item so that we'd get correct nsDisplayEventRegions for child
// frames, then force us to inactive to avoid unnecessary layerization changes for content
// that won't ever be painted.
if (mForEventsAndPluginsOnly) {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -5245,30 +5245,37 @@ protected:
* set by the stacking context root frame's 'opacity' style.
*/
class nsDisplayOpacity : public nsDisplayWrapList {
public:
nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList,
const ActiveScrolledRoot* aActiveScrolledRoot,
bool aForEventsAndPluginsOnly);
+
nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
const nsDisplayOpacity& aOther)
: nsDisplayWrapList(aBuilder, aOther)
, mOpacity(aOther.mOpacity)
, mForEventsAndPluginsOnly(aOther.mForEventsAndPluginsOnly)
- {}
+ , mOpacityAppliedToChildren(false)
+ {
+ // We should not try to merge flattened opacities.
+ MOZ_ASSERT(!aOther.mOpacityAppliedToChildren);
+ }
+
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayOpacity();
#endif
virtual void RestoreState() override
{
nsDisplayItem::RestoreState();
mOpacity = mState.mOpacity;
+ mOpacityAppliedToChildren = false;
}
virtual nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override
{
MOZ_COUNT_CTOR(nsDisplayOpacity);
return MakeDisplayItem<nsDisplayOpacity>(aBuilder, *this);
}
@@ -5307,33 +5314,42 @@ public:
}
return nsDisplayWrapList::IsInvalid(aRect);
}
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClipChain* aClip) override;
virtual bool CanApplyOpacity() const override;
virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
+
+ /**
+ * Returns true if ShouldFlattenAway() applied opacity to children.
+ */
+ bool OpacityAppliedToChildren() const { return mOpacityAppliedToChildren; }
+
static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
virtual void WriteDebugInfo(std::stringstream& aStream) override;
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) override;
float GetOpacity() { return mOpacity; }
private:
+ bool ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder);
+
float mOpacity;
bool mForEventsAndPluginsOnly;
+ bool mOpacityAppliedToChildren;
struct {
float mOpacity;
} mState;
};
class nsDisplayBlendMode : public nsDisplayWrapList {
public: