mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1520652 - Clip SVG filters to the PrimitiveSubregion when using WebRender. r=mstange
This patch changes a few things: * Restores clipping to the computed clip, but just for SVG filters. * Computes the clip just from the primitive subregion, not the bounds of the filtered content. * Unconditionally clips all SVG filters using the primitive subregion * Allows clips to be combined, if they will be sharing a coordinate space * Fixes coordinate space of the clip region. Differential Revision: https://phabricator.services.mozilla.com/D16941 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
b911cbf521
commit
a79e573d49
@ -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<mozilla::wr::FilterOp> wrFilters;
|
||||
Maybe<nsRect> 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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -93,10 +93,9 @@ void nsFilterInstance::PaintFilteredFrame(
|
||||
}
|
||||
}
|
||||
|
||||
bool nsFilterInstance::BuildWebRenderFilters(
|
||||
nsIFrame* aFilteredFrame, const LayoutDeviceIntRect& aPreFilterBounds,
|
||||
nsTArray<wr::FilterOp>& aWrFilters,
|
||||
LayoutDeviceIntRect& aPostFilterBounds) {
|
||||
bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
|
||||
nsTArray<wr::FilterOp>& aWrFilters,
|
||||
Maybe<nsRect>& aPostFilterClip) {
|
||||
aWrFilters.Clear();
|
||||
|
||||
auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
|
||||
@ -121,7 +120,7 @@ bool nsFilterInstance::BuildWebRenderFilters(
|
||||
return false;
|
||||
}
|
||||
|
||||
Maybe<LayoutDeviceIntRect> finalClip;
|
||||
Maybe<IntRect> 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<GaussianBlurAttributes>()) {
|
||||
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<DropShadowAttributes>()) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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<mozilla::wr::FilterOp>& aWrFilters,
|
||||
mozilla::LayoutDeviceIntRect& aPostFilterBounds);
|
||||
static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
|
||||
nsTArray<mozilla::wr::FilterOp>& aWrFilters,
|
||||
mozilla::Maybe<nsRect>& aPostFilterClip);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -1086,12 +1086,10 @@ void nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams) {
|
||||
}
|
||||
|
||||
bool nsSVGIntegrationUtils::BuildWebRenderFilters(
|
||||
nsIFrame* aFilteredFrame,
|
||||
const mozilla::LayoutDeviceIntRect& aPreFilterBounds,
|
||||
nsTArray<mozilla::wr::FilterOp>& aWrFilters,
|
||||
mozilla::LayoutDeviceIntRect& aPostFilterBounds) {
|
||||
return nsFilterInstance::BuildWebRenderFilters(
|
||||
aFilteredFrame, aPreFilterBounds, aWrFilters, aPostFilterBounds);
|
||||
nsIFrame* aFilteredFrame, nsTArray<mozilla::wr::FilterOp>& aWrFilters,
|
||||
Maybe<nsRect>& aPostFilterClip) {
|
||||
return nsFilterInstance::BuildWebRenderFilters(aFilteredFrame, aWrFilters,
|
||||
aPostFilterClip);
|
||||
}
|
||||
|
||||
class PaintFrameCallback : public gfxDrawingCallback {
|
||||
|
@ -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<mozilla::wr::FilterOp>& aWrFilters,
|
||||
mozilla::LayoutDeviceIntRect& aPostFilterBounds);
|
||||
static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
|
||||
nsTArray<mozilla::wr::FilterOp>& aWrFilters,
|
||||
mozilla::Maybe<nsRect>& aPostFilterClip);
|
||||
|
||||
/**
|
||||
* @param aRenderingContext the target rendering context in which the paint
|
||||
|
Loading…
Reference in New Issue
Block a user