diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 0eb6068b2dfd..0f2dacfd1cea 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -9350,29 +9350,34 @@ bool nsDisplayFilters::CreateWebRenderCommands( const StackingContextHelper& aSc, mozilla::layers::RenderRootStateManager* aManager, nsDisplayListBuilder* aDisplayListBuilder) { - bool snap; float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); - nsRect displayBounds = GetBounds(aDisplayListBuilder, &snap); - auto postFilterBounds = LayoutDeviceIntRect::Round( - LayoutDeviceRect::FromAppUnits(displayBounds, auPerDevPixel)); - auto preFilterBounds = LayoutDeviceIntRect::Round( - LayoutDeviceRect::FromAppUnits(mBounds, auPerDevPixel)); nsTArray wrFilters; + Maybe filterClip; if (!CreateWebRenderCSSFilters(wrFilters) && - !nsSVGIntegrationUtils::BuildWebRenderFilters( - mFrame, preFilterBounds, wrFilters, postFilterBounds)) { + !nsSVGIntegrationUtils::BuildWebRenderFilters(mFrame, wrFilters, + filterClip)) { return false; } + wr::WrStackingContextClip clip; + if (filterClip) { + auto devPxRect = LayoutDeviceRect::FromAppUnits( + filterClip.value() + ToReferenceFrame(), auPerDevPixel); + wr::WrClipId clipId = + aBuilder.DefineClip(Nothing(), wr::ToRoundedLayoutRect(devPxRect)); + clip = wr::WrStackingContextClip::ClipId(clipId); + } else { + clip = wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId()); + } + float opacity = mFrame->StyleEffects()->mOpacity; StackingContextHelper sc( aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, wrFilters, LayoutDeviceRect(), nullptr, nullptr, opacity != 1.0f && mHandleOpacity ? &opacity : nullptr, nullptr, wr::ReferenceFrameKind::Transform, gfx::CompositionOp::OP_OVER, true, - false, Nothing(), - wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId())); + false, Nothing(), clip); nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, sc, aManager, aDisplayListBuilder); diff --git a/layout/reftests/svg/filters/css-filter-chains/reftest.list b/layout/reftests/svg/filters/css-filter-chains/reftest.list index df4028c2af1b..069b1f34658f 100644 --- a/layout/reftests/svg/filters/css-filter-chains/reftest.list +++ b/layout/reftests/svg/filters/css-filter-chains/reftest.list @@ -2,6 +2,6 @@ # e.g. filter: blur(3px) grayscale(0.5) invert(0.2); # Some platforms render this complex filter chain a little differently, and that's ok. -fuzzy(0-5,0-13638) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,0-35,0-13638) fuzzy-if(webrender,4-6,12000-18853) == long-chain.html long-chain-ref.html # Win10: Bug 1258241 +fuzzy(0-5,0-13638) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,0-35,0-13638) fuzzy-if(webrender,4-6,12000-18946) == long-chain.html long-chain-ref.html # Win10: Bug 1258241 == moz-element.html moz-element-ref.html -== same-filter.html same-filter-ref.html +fuzzy-if(webrender,13-15,7682-7966) == same-filter.html same-filter-ref.html diff --git a/layout/reftests/svg/filters/css-filters/reftest.list b/layout/reftests/svg/filters/css-filters/reftest.list index 5e70f0b7b8af..efe510d99e84 100644 --- a/layout/reftests/svg/filters/css-filters/reftest.list +++ b/layout/reftests/svg/filters/css-filters/reftest.list @@ -6,7 +6,7 @@ == blur-calc.html blur-calc-ref.html == blur-calc-negative.html blur-calc-negative-ref.html fuzzy-if(cocoaWidget&&webrender,0-1,0-2) skip-if(d2d) == blur-cap-large-radius-on-software.html blur-cap-large-radius-on-software-ref.html -fails-if(webrender) == blur-clip-rect.html ../feGaussianBlur-4-ref.svg +fuzzy-if(webrender,3-4,5760-6424) == blur-clip-rect.html ../feGaussianBlur-4-ref.svg == blur-em-radius.html blur-em-radius-ref.html == blur-invalid-radius.html blur-invalid-radius-ref.html == blur-rem-radius.html blur-rem-radius-ref.html diff --git a/layout/reftests/svg/filters/css-svg-filter-chains/reftest.list b/layout/reftests/svg/filters/css-svg-filter-chains/reftest.list index dc445094c2a0..3802b358cd6d 100644 --- a/layout/reftests/svg/filters/css-svg-filter-chains/reftest.list +++ b/layout/reftests/svg/filters/css-svg-filter-chains/reftest.list @@ -3,6 +3,6 @@ # e.g. filter: url(#f1) blur(3px) url(#2) grayscale(0.5); == clip-input-css-filter.html clip-input-css-filter-ref.html -== css-filter-first.html css-filter-first-ref.html +fuzzy-if(webrender,0-1,0-288) == css-filter-first.html css-filter-first-ref.html == css-filter-last.html css-filter-last-ref.html == css-filter-middle.html css-filter-middle-ref.html diff --git a/layout/svg/nsFilterInstance.cpp b/layout/svg/nsFilterInstance.cpp index 84148a4b4764..076980263e40 100644 --- a/layout/svg/nsFilterInstance.cpp +++ b/layout/svg/nsFilterInstance.cpp @@ -93,10 +93,9 @@ void nsFilterInstance::PaintFilteredFrame( } } -bool nsFilterInstance::BuildWebRenderFilters( - nsIFrame* aFilteredFrame, const LayoutDeviceIntRect& aPreFilterBounds, - nsTArray& aWrFilters, - LayoutDeviceIntRect& aPostFilterBounds) { +bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame, + nsTArray& aWrFilters, + Maybe& aPostFilterClip) { aWrFilters.Clear(); auto& filterChain = aFilteredFrame->StyleEffects()->mFilters; @@ -121,7 +120,7 @@ bool nsFilterInstance::BuildWebRenderFilters( return false; } - Maybe finalClip; + Maybe finalClip; bool srgb = true; // We currently apply the clip on the stacking context after applying filters, // but primitive subregions imply clipping after each filter and not just the @@ -132,17 +131,7 @@ bool nsFilterInstance::BuildWebRenderFilters( // We can lift this restriction once we have added support for primitive // subregions to WebRender's filters. - // During the loop this tracks whether any of the previous filters in the - // chain affected by the primitive subregion. - bool chainIsAffectedByPrimSubregion = false; - // During the loop this tracks whether the current filter is affected by the - // primitive subregion. - bool filterIsAffectedByPrimSubregion = false; - for (const auto& primitive : instance.mFilterDescription.mPrimitives) { - chainIsAffectedByPrimSubregion |= filterIsAffectedByPrimSubregion; - filterIsAffectedByPrimSubregion = false; - bool primIsSrgb = primitive.OutputColorSpace() == gfx::ColorSpace::SRGB; if (srgb && !primIsSrgb) { aWrFilters.AppendElement(wr::FilterOp::SrgbToLinear()); @@ -153,26 +142,6 @@ bool nsFilterInstance::BuildWebRenderFilters( } const PrimitiveAttributes& attr = primitive.Attributes(); - auto subregion = LayoutDeviceIntRect::FromUnknownRect( - primitive.PrimitiveSubregion() + - aPreFilterBounds.TopLeft().ToUnknownPoint()); - - if (!subregion.Contains(aPreFilterBounds)) { - if (!aPostFilterBounds.Contains(subregion)) { - filterIsAffectedByPrimSubregion = true; - } - - subregion = subregion.Intersect(aPostFilterBounds); - - if (finalClip.isNothing()) { - finalClip = Some(subregion); - } else if (!subregion.IsEqualEdges(finalClip.value())) { - // We don't currently support rendering a chain of filters with - // different primitive subregions in WebRender so bail out in that - // situation. - return false; - } - } bool filterIsNoop = false; @@ -213,7 +182,7 @@ bool nsFilterInstance::BuildWebRenderFilters( aWrFilters.AppendElement(wr::FilterOp::ColorMatrix(matrix)); } else if (attr.is()) { - if (chainIsAffectedByPrimSubregion) { + if (finalClip) { // There's a clip that needs to apply before the blur filter, but // WebRender only lets us apply the clip at the end of the filter // chain. Clipping after a blur is not equivalent to clipping before @@ -235,7 +204,7 @@ bool nsFilterInstance::BuildWebRenderFilters( filterIsNoop = true; } } else if (attr.is()) { - if (chainIsAffectedByPrimSubregion) { + if (finalClip) { // We have to bail out for the same reason we would with a blur filter. return false; } @@ -271,18 +240,24 @@ bool nsFilterInstance::BuildWebRenderFilters( Unused << aWrFilters.PopLastElement(); srgb = !srgb; } + + if (!filterIsNoop) { + if (finalClip.isNothing()) { + finalClip = Some(primitive.PrimitiveSubregion()); + } else { + finalClip = + Some(primitive.PrimitiveSubregion().Intersect(finalClip.value())); + } + } } if (!srgb) { aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb()); } - // Only adjust the post filter clip if we are able to render this without - // fallback. - if (finalClip.isSome()) { - aPostFilterBounds = finalClip.value(); + if (finalClip) { + aPostFilterClip = Some(instance.FilterSpaceToFrameSpace(finalClip.value())); } - return true; } diff --git a/layout/svg/nsFilterInstance.h b/layout/svg/nsFilterInstance.h index 89a2dfcaecc9..481e89fe1eea 100644 --- a/layout/svg/nsFilterInstance.h +++ b/layout/svg/nsFilterInstance.h @@ -122,11 +122,9 @@ class nsFilterInstance { * Try to build WebRender filters for a frame if the filters applied to it are * supported. */ - static bool BuildWebRenderFilters( - nsIFrame* aFilteredFrame, - const mozilla::LayoutDeviceIntRect& aPreFilterBounds, - nsTArray& aWrFilters, - mozilla::LayoutDeviceIntRect& aPostFilterBounds); + static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame, + nsTArray& aWrFilters, + mozilla::Maybe& aPostFilterClip); private: /** diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index bb4e27be34db..c36007519f37 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -1086,12 +1086,10 @@ void nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams) { } bool nsSVGIntegrationUtils::BuildWebRenderFilters( - nsIFrame* aFilteredFrame, - const mozilla::LayoutDeviceIntRect& aPreFilterBounds, - nsTArray& aWrFilters, - mozilla::LayoutDeviceIntRect& aPostFilterBounds) { - return nsFilterInstance::BuildWebRenderFilters( - aFilteredFrame, aPreFilterBounds, aWrFilters, aPostFilterBounds); + nsIFrame* aFilteredFrame, nsTArray& aWrFilters, + Maybe& aPostFilterClip) { + return nsFilterInstance::BuildWebRenderFilters(aFilteredFrame, aWrFilters, + aPostFilterClip); } class PaintFrameCallback : public gfxDrawingCallback { diff --git a/layout/svg/nsSVGIntegrationUtils.h b/layout/svg/nsSVGIntegrationUtils.h index bae671bd0b85..9020f09c3dc1 100644 --- a/layout/svg/nsSVGIntegrationUtils.h +++ b/layout/svg/nsSVGIntegrationUtils.h @@ -195,11 +195,9 @@ class nsSVGIntegrationUtils final { * Try to build WebRender filters for a frame if the filters applied to it are * supported. */ - static bool BuildWebRenderFilters( - nsIFrame* aFilteredFrame, - const mozilla::LayoutDeviceIntRect& aPreFilterBounds, - nsTArray& aWrFilters, - mozilla::LayoutDeviceIntRect& aPostFilterBounds); + static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame, + nsTArray& aWrFilters, + mozilla::Maybe& aPostFilterClip); /** * @param aRenderingContext the target rendering context in which the paint