diff --git a/layout/base/nsDisplayItemTypesList.h b/layout/base/nsDisplayItemTypesList.h index 7aaa9b1df8a2..7ca0bd052f6c 100644 --- a/layout/base/nsDisplayItemTypesList.h +++ b/layout/base/nsDisplayItemTypesList.h @@ -52,6 +52,7 @@ DECLARE_DISPLAY_ITEM_TYPE(SELECTION_OVERLAY) DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR) DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT) DECLARE_DISPLAY_ITEM_TYPE(MASK) +DECLARE_DISPLAY_ITEM_TYPE(FILTER) DECLARE_DISPLAY_ITEM_TYPE(SVG_GLYPHS) DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG) DECLARE_DISPLAY_ITEM_TYPE(SVG_PATH_GEOMETRY) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 70553ce16f32..990b88453819 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -6677,22 +6677,6 @@ nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect } } -bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { - nsPoint offset = ToReferenceFrame(); - nsRect dirtyRect = - nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame, - mVisibleRect - offset) + - offset; - - // Our children may be made translucent or arbitrarily deformed so we should - // not allow them to subtract area from aVisibleRegion. - nsRegion childrenVisible(dirtyRect); - nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder)); - mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r); - return true; -} - gfxRect nsDisplaySVGEffects::BBoxInUserSpace() const { @@ -6826,6 +6810,16 @@ nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder, return LAYER_SVG_EFFECTS; } +bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) { + // Our children may be made translucent or arbitrarily deformed so we should + // not allow them to subtract area from aVisibleRegion. + nsRegion childrenVisible(mVisibleRect); + nsRect r = mVisibleRect.Intersect(mList.GetBounds(aBuilder)); + mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r); + return true; +} + void nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, @@ -6885,3 +6879,140 @@ nsDisplayMask::PrintEffects(nsACString& aTo) } #endif +nsDisplayFilter::nsDisplayFilter(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, nsDisplayList* aList, + bool aOpacityItemCreated) + : nsDisplaySVGEffects(aBuilder, aFrame, aList, aOpacityItemCreated) +{ + MOZ_COUNT_CTOR(nsDisplayFilter); +} + +#ifdef NS_BUILD_REFCNT_LOGGING +nsDisplayFilter::~nsDisplayFilter() +{ + MOZ_COUNT_DTOR(nsDisplayFilter); +} +#endif + +already_AddRefed +nsDisplayFilter::BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) +{ + if (!ValidateSVGFrame()) { + return nullptr; + } + + if (mFrame->StyleEffects()->mOpacity == 0.0f && !mOpacityItemCreated) { + return nullptr; + } + + nsIFrame* firstFrame = + nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame); + nsSVGEffects::EffectProperties effectProperties = + nsSVGEffects::GetEffectProperties(firstFrame); + + ContainerLayerParameters newContainerParameters = aContainerParameters; + if (effectProperties.HasValidFilter()) { + newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; + } + + RefPtr container = aManager->GetLayerBuilder()-> + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, + newContainerParameters, nullptr); + + return container.forget(); +} + +bool nsDisplayFilter::TryMerge(nsDisplayItem* aItem) +{ + if (aItem->GetType() != TYPE_FILTER) { + return false; + } + + // items for the same content element should be merged into a single + // compositing group. + // aItem->Frame() returns non-null because it's nsDisplayFilter + if (aItem->Frame()->GetContent() != mFrame->GetContent()) { + return false; + } + if (aItem->GetClip() != GetClip()) { + return false; + } + if (aItem->ScrollClip() != ScrollClip()) { + return false; + } + + nsDisplayFilter* other = static_cast(aItem); + MergeFromTrackingMergedFrames(other); + mEffectsBounds.UnionRect(mEffectsBounds, + other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame)); + + return true; +} + +LayerState +nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) +{ + return LAYER_SVG_EFFECTS; +} + +bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) { + nsPoint offset = ToReferenceFrame(); + nsRect dirtyRect = + nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame, + mVisibleRect - offset) + + offset; + + // Our children may be made translucent or arbitrarily deformed so we should + // not allow them to subtract area from aVisibleRegion. + nsRegion childrenVisible(dirtyRect); + nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder)); + mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r); + return true; +} + +void +nsDisplayFilter::PaintAsLayer(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx, + LayerManager* aManager) +{ + nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); + nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(), + mFrame, mVisibleRect, + borderArea, aBuilder, + aManager, mOpacityItemCreated); + + image::DrawResult result = + nsSVGIntegrationUtils::PaintFilter(params); + + nsDisplaySVGEffectsGeometry::UpdateDrawResult(this, result); +} + +#ifdef MOZ_DUMP_PAINTING +void +nsDisplayFilter::PrintEffects(nsACString& aTo) +{ + nsIFrame* firstFrame = + nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame); + nsSVGEffects::EffectProperties effectProperties = + nsSVGEffects::GetEffectProperties(firstFrame); + bool first = true; + aTo += " effects=("; + if (mFrame->StyleEffects()->mOpacity != 1.0f) { + first = false; + aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity); + } + if (effectProperties.HasValidFilter()) { + if (!first) { + aTo += ", "; + } + aTo += "filter"; + first = false; + } + aTo += ")"; +} +#endif diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index bb592d562f58..1b704800711d 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3801,8 +3801,6 @@ public: return mEffectsBounds + ToReferenceFrame(); } - virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) override; virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override { return false; } @@ -3817,7 +3815,6 @@ public: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, nsRegion* aInvalidRegion) override; - protected: bool ValidateSVGFrame(); @@ -3850,6 +3847,37 @@ public: LayerManager* aManager, const ContainerLayerParameters& aParameters) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; +#ifdef MOZ_DUMP_PAINTING + void PrintEffects(nsACString& aTo); +#endif + + void PaintAsLayer(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx, + LayerManager* aManager); +}; + +class nsDisplayFilter : public nsDisplaySVGEffects { +public: + nsDisplayFilter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, bool aOpacityItemCreated); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayFilter(); +#endif + + NS_DISPLAY_DECL_NAME("Filter", TYPE_FILTER) + + virtual bool TryMerge(nsDisplayItem* aItem) override; + virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; #ifdef MOZ_DUMP_PAINTING void PrintEffects(nsACString& aTo); #endif diff --git a/layout/base/nsLayoutDebugger.cpp b/layout/base/nsLayoutDebugger.cpp index 9becf23b5003..22c313c72b71 100644 --- a/layout/base/nsLayoutDebugger.cpp +++ b/layout/base/nsLayoutDebugger.cpp @@ -201,6 +201,12 @@ PrintDisplayItemTo(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, (static_cast(aItem))->PrintEffects(str); aStream << str.get(); } + + if (aItem->GetType() == nsDisplayItem::TYPE_FILTER) { + nsCString str; + (static_cast(aItem))->PrintEffects(str); + aStream << str.get(); + } #endif aStream << "\n"; #ifdef MOZ_DUMP_PAINTING