Bug 1765525 - Fix gecko DL creation for backdrop-filters with clips r=gfx-reviewers,lsalzman

Change to derive from nsDisplayEffectsBase, since the backdrop-filter
can still have a visual bounds (and effect) even if the child
stacking context has no items. Also use the same approach to get
the bounding rect and implement GetBounds as nsDisplayFilters uses.

Differential Revision: https://phabricator.services.mozilla.com/D145295
This commit is contained in:
Glenn Watson 2022-05-04 19:08:31 +00:00
Родитель 2d73405522
Коммит 7dfd66fe8a
9 изменённых файлов: 90 добавлений и 22 удалений

Просмотреть файл

@ -2225,7 +2225,21 @@ impl<'a> SceneBuilder<'a> {
return;
}
let stacking_context = self.sc_stack.pop().unwrap();
let mut stacking_context = self.sc_stack.pop().unwrap();
// If this stacking context has requested that clip masks get applied
// to individual child elements, remove the blit reason. Since the picture
// will still exist as a pass-through with a clip-chain, that clip
// will be applied implicitly to the primitive inside the stacking
// context. It's required for correctness for backdrop-filters
// that have a clip-mask applied to them. In this case, Gecko supplies
// a surrounding stacking context with clip-mask, which WR thinks is
// the backdrop root without this optimization. In future, we should
// change the way Geck supplies clip-masks on primitives so that this
// isn't necessary.
if stacking_context.flags.contains(StackingContextFlags::APPLY_CLIPS_TO_ITEMS) {
stacking_context.blit_reason = BlitReason::empty();
}
// If the stacking context is a blend container, and if we're at the top level
// of the stacking context tree, we can make this blend container into a tile

Просмотреть файл

@ -948,6 +948,9 @@ bitflags! {
/// If true, this stacking context is a blend container than contains
/// mix-blend-mode children (and should thus be isolated).
const IS_BLEND_CONTAINER = 1 << 1;
/// If true, apply clip masks from this stacking context to individual items
/// instead of the overall stacking context
const APPLY_CLIPS_TO_ITEMS = 1 << 2;
}
}

Просмотреть файл

@ -0,0 +1,9 @@
---
root:
items:
- type: rect
bounds: 0 0 256 256
color: red
- type: rect
bounds: 64 64 128 128
color: cyan

Просмотреть файл

@ -0,0 +1,25 @@
# Ensure that a backdrop-filter enclosed by a stacking context with
# a clip-mask can select the correct backdrop root
---
root:
items:
- type: clip
bounds: [64, 64, 128, 128]
id: 2
image-mask:
image: solid-color(255,255,255,255,128,128)
rect: [64, 64, 128, 128]
repeat: false
- type: stacking-context
backdrop-root: true
items:
- type: rect
bounds: 0 0 256 256
color: red
- type: stacking-context
clip-node: 2
apply-clips-to-items: true
items:
- type: backdrop-filter
bounds: 0 0 256 256
filters: invert(1)

Просмотреть файл

@ -64,6 +64,7 @@ fuzzy(1,1) platform(linux,mac) == svg-filter-drop-shadow-perspective.yaml svg-fi
#== backdrop-filter-basic.yaml backdrop-filter-basic-ref.yaml
#platform(linux,mac) == backdrop-filter-perspective.yaml backdrop-filter-perspective.png
#== backdrop-filter-on-child-surface.yaml backdrop-filter-on-child-surface-ref.yaml
#== backdrop-filter-clip-mask.yaml backdrop-filter-clip-mask-ref.yaml
#platform(linux,mac) == backdrop-filter-across-tiles.yaml backdrop-filter-across-tiles.png
#platform(linux,mac) == backdrop-filter-chain.yaml backdrop-filter-chain.png
#platform(linux,mac) == backdrop-filter-overlap.yaml backdrop-filter-overlap.png

Просмотреть файл

@ -2026,6 +2026,7 @@ impl YamlFrameReader {
.unwrap_or(RasterSpace::Screen);
let is_backdrop_root = yaml["backdrop-root"].as_bool().unwrap_or(false);
let is_blend_container = yaml["blend-container"].as_bool().unwrap_or(false);
let apply_clips_to_items = yaml["apply-clips-to-items"].as_bool().unwrap_or(false);
if is_root {
if let Some(vector) = yaml["scroll-offset"].as_vector() {
@ -2047,6 +2048,7 @@ impl YamlFrameReader {
let mut flags = StackingContextFlags::empty();
flags.set(StackingContextFlags::IS_BACKDROP_ROOT, is_backdrop_root);
flags.set(StackingContextFlags::IS_BLEND_CONTAINER, is_blend_container);
flags.set(StackingContextFlags::APPLY_CLIPS_TO_ITEMS, apply_clips_to_items);
dl.push_stacking_context(
bounds.min,

Просмотреть файл

@ -3601,10 +3601,8 @@ void nsIFrame::BuildDisplayListForStackingContext(
if (usingBackdropFilter) {
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
nsRect backdropRect =
GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
resultList.AppendNewToTop<nsDisplayBackdropFilters>(
aBuilder, this, &resultList, backdropRect);
resultList.AppendNewToTop<nsDisplayBackdropFilters>(aBuilder, this,
&resultList);
ct.TrackContainer(resultList.GetTop());
}
@ -3646,7 +3644,7 @@ void nsIFrame::BuildDisplayListForStackingContext(
: containerItemASR;
/* List now emptied, so add the new list to the top. */
resultList.AppendNewToTop<nsDisplayMasksAndClipPaths>(
aBuilder, this, &resultList, maskASR);
aBuilder, this, &resultList, maskASR, usingBackdropFilter);
ct.TrackContainer(resultList.GetTop());
}

Просмотреть файл

@ -7853,8 +7853,9 @@ static void ComputeMaskGeometry(PaintFramesParams& aParams) {
nsDisplayMasksAndClipPaths::nsDisplayMasksAndClipPaths(
nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
const ActiveScrolledRoot* aActiveScrolledRoot)
: nsDisplayEffectsBase(aBuilder, aFrame, aList, aActiveScrolledRoot, true) {
const ActiveScrolledRoot* aActiveScrolledRoot, bool aApplyClipToChildren)
: nsDisplayEffectsBase(aBuilder, aFrame, aList, aActiveScrolledRoot, true),
mApplyClipToChildren(aApplyClipToChildren) {
MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
nsPresContext* presContext = mFrame->PresContext();
@ -8195,6 +8196,9 @@ bool nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
wr::StackingContextParams params;
params.clip = wr::WrStackingContextClip::ClipId(*clip);
params.opacity = opacity.ptrOr(nullptr);
if (mApplyClipToChildren) {
params.flags |= wr::StackingContextFlags::APPLY_CLIPS_TO_ITEMS;
}
layer.emplace(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, params,
bounds);
sc = layer.ptr();
@ -8317,20 +8321,23 @@ bool nsDisplayBackdropFilters::CreateWebRenderCommands(
return true;
}
bool snap;
nsRect bounds = GetBounds(aDisplayListBuilder, &snap);
nsCSSRendering::ImageLayerClipState clip;
nsCSSRendering::GetImageLayerClip(
mFrame->StyleBackground()->BottomLayer(), mFrame, *mFrame->StyleBorder(),
mBackdropRect, mBackdropRect, false,
mFrame->PresContext()->AppUnitsPerDevPixel(), &clip);
bounds, bounds, false, mFrame->PresContext()->AppUnitsPerDevPixel(),
&clip);
LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
mBackdropRect, mFrame->PresContext()->AppUnitsPerDevPixel());
LayoutDeviceRect deviceBounds = LayoutDeviceRect::FromAppUnits(
bounds, mFrame->PresContext()->AppUnitsPerDevPixel());
wr::ComplexClipRegion region =
wr::ToComplexClipRegion(clip.mBGClipArea, clip.mRadii,
mFrame->PresContext()->AppUnitsPerDevPixel());
aBuilder.PushBackdropFilter(wr::ToLayoutRect(bounds), region,
aBuilder.PushBackdropFilter(wr::ToLayoutRect(deviceBounds), region,
wrFilters.filters, wrFilters.filter_datas,
!BackfaceIsHidden());
@ -8340,8 +8347,8 @@ bool nsDisplayBackdropFilters::CreateWebRenderCommands(
StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
params);
nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
aDisplayListBuilder);
nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, sc,
aManager, aDisplayListBuilder);
return true;
}

Просмотреть файл

@ -5871,11 +5871,13 @@ class nsDisplayMasksAndClipPaths : public nsDisplayEffectsBase {
public:
nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList,
const ActiveScrolledRoot* aActiveScrolledRoot);
const ActiveScrolledRoot* aActiveScrolledRoot,
bool aApplyClipToChildren);
nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder,
const nsDisplayMasksAndClipPaths& aOther)
: nsDisplayEffectsBase(aBuilder, aOther),
mDestRects(aOther.mDestRects.Clone()) {
mDestRects(aOther.mDestRects.Clone()),
mApplyClipToChildren(aOther.mApplyClipToChildren) {
MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
}
@ -5940,6 +5942,7 @@ class nsDisplayMasksAndClipPaths : public nsDisplayEffectsBase {
NS_DISPLAY_ALLOW_CLONING()
nsTArray<nsRect> mDestRects;
bool mApplyClipToChildren;
};
class nsDisplayBackdropRootContainer : public nsDisplayWrapList {
@ -5970,12 +5973,12 @@ class nsDisplayBackdropRootContainer : public nsDisplayWrapList {
bool CreatesStackingContextHelper() override { return true; }
};
class nsDisplayBackdropFilters : public nsDisplayWrapList {
class nsDisplayBackdropFilters : public nsDisplayEffectsBase {
public:
nsDisplayBackdropFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, const nsRect& aBackdropRect)
: nsDisplayWrapList(aBuilder, aFrame, aList),
mBackdropRect(aBackdropRect) {
nsDisplayList* aList)
: nsDisplayEffectsBase(aBuilder, aFrame, aList),
mBounds(aFrame->GetPaddingRectRelativeToSelf()) {
MOZ_COUNT_CTOR(nsDisplayBackdropFilters);
}
@ -5997,10 +6000,16 @@ class nsDisplayBackdropFilters : public nsDisplayWrapList {
return !aBuilder->IsPaintingForWebRender();
}
nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
*aSnap = false;
return mBounds + ToReferenceFrame();
}
bool CreatesStackingContextHelper() override { return true; }
private:
nsRect mBackdropRect;
nsRect mBounds;
};
/**