Bug 1423746 - Filter on root should not establish containing block for fixedpos elements. r=mstange

Teach nsDisplay{Filters,BackdropFilters} to use a style that doesn't
belong to mFrame for the root frame, and use it as needed.

Remove the BackdropFilters::CanCreateWebrenderCommands call because it
was testing for StyleSVGEffects::mFilters rather than mBackdropFilters,
so it was doing nothing.

Differential Revision: https://phabricator.services.mozilla.com/D146188
This commit is contained in:
Emilio Cobos Álvarez 2022-05-13 10:02:58 +00:00
Родитель 466753ca05
Коммит 5302cc0936
11 изменённых файлов: 98 добавлений и 59 удалений

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

@ -4172,6 +4172,35 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
set.PositionedDescendants()->AppendToTop(topLayerWrapList);
}
nsDisplayList rootResultList(aBuilder);
bool serializedList = false;
auto SerializeList = [&] {
if (!serializedList) {
serializedList = true;
set.SerializeWithCorrectZOrder(&rootResultList, mOuter->GetContent());
}
};
if (mIsRoot) {
if (nsIFrame* rootStyleFrame = GetFrameForStyle()) {
if (rootStyleFrame->StyleEffects()->HasFilters()) {
SerializeList();
rootResultList.AppendNewToTop<nsDisplayFilters>(
aBuilder, mOuter, &rootResultList, rootStyleFrame);
}
if (rootStyleFrame->StyleEffects()->HasBackdropFilters() &&
rootStyleFrame->IsVisibleForPainting()) {
SerializeList();
aBuilder->SetContainsBackdropFilter(true);
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
nsRect backdropRect = mOuter->GetRectRelativeToSelf() +
aBuilder->ToReferenceFrame(mOuter);
rootResultList.AppendNewToTop<nsDisplayBackdropFilters>(
aBuilder, mOuter, &rootResultList, backdropRect, rootStyleFrame);
}
}
}
if (willBuildAsyncZoomContainer) {
MOZ_ASSERT(mIsRoot);
@ -4181,9 +4210,7 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// it. The children have the layout viewport clip applied to them (above).
// Effectively we are double clipping to the viewport, at potentially
// different async scales.
nsDisplayList resultList(aBuilder);
set.SerializeWithCorrectZOrder(&resultList, mOuter->GetContent());
SerializeList();
if (blendCapture.CaptureContainsBlendMode()) {
// The async zoom contents contain a mix-blend mode, so let's wrap all
@ -4193,9 +4220,9 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// WebRender.
nsDisplayItem* blendContainer =
nsDisplayBlendContainer::CreateForMixBlendMode(
aBuilder, mOuter, &resultList,
aBuilder, mOuter, &rootResultList,
aBuilder->CurrentActiveScrolledRoot());
resultList.AppendToTop(blendContainer);
rootResultList.AppendToTop(blendContainer);
// Blend containers can be created or omitted during partial updates
// depending on the dirty rect. So we basically can't do partial updates
@ -4217,8 +4244,9 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// backdrop container in the async zoom container. Otherwise the
// backdrop-root container ends up outside the zoom container which
// results in blend failure for WebRender.
resultList.AppendNewToTop<nsDisplayBackdropRootContainer>(
aBuilder, mOuter, &resultList, aBuilder->CurrentActiveScrolledRoot());
rootResultList.AppendNewToTop<nsDisplayBackdropRootContainer>(
aBuilder, mOuter, &rootResultList,
aBuilder->CurrentActiveScrolledRoot());
// Backdrop root containers can be created or omitted during partial
// updates depending on the dirty rect. So we basically can't do partial
@ -4241,9 +4269,13 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
clipState.ClipContentDescendants(clipRect, haveRadii ? radii : nullptr);
set.Content()->AppendNewToTop<nsDisplayAsyncZoom>(
aBuilder, mOuter, &resultList, aBuilder->CurrentActiveScrolledRoot(),
viewID);
rootResultList.AppendNewToTop<nsDisplayAsyncZoom>(
aBuilder, mOuter, &rootResultList,
aBuilder->CurrentActiveScrolledRoot(), viewID);
}
if (serializedList) {
set.Content()->AppendToTop(&rootResultList);
}
nsDisplayListCollection scrolledContent(aBuilder);

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

@ -1779,7 +1779,7 @@ bool nsIFrame::HasOpacityInternal(float aThreshold,
EffectSet* aEffectSet) const {
MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
if (aStyleEffects->mOpacity < aThreshold ||
(aStyleDisplay->mWillChange.bits & StyleWillChangeBits::OPACITY)) {
aStyleDisplay->mWillChange.bits & StyleWillChangeBits::OPACITY) {
return true;
}
@ -2651,32 +2651,38 @@ inline static bool IsSVGContentWithCSSClip(const nsIFrame* aFrame) {
nsGkAtoms::foreignObject);
}
bool nsIFrame::FormsBackdropRoot(const nsStyleDisplay* aStyleDisplay,
const nsStyleEffects* aStyleEffects,
const nsStyleSVGReset* aStyleSVGReset) {
bool nsIFrame::FormsBackdropRoot() const {
// Check if this is a root frame.
if (!GetParent()) {
return true;
}
const auto& style = *Style();
const auto& effects = *style.StyleEffects();
// Check for filter effects.
if (aStyleEffects->HasFilters() || aStyleEffects->HasBackdropFilters() ||
aStyleEffects->HasMixBlendMode()) {
if (!style.IsRootElementStyle()) {
if (effects.HasFilters() || effects.HasBackdropFilters()) {
return true;
}
}
if (effects.HasMixBlendMode()) {
return true;
}
// Check for opacity.
if (HasOpacity(aStyleDisplay, aStyleEffects)) {
const auto& disp = *style.StyleDisplay();
if (HasOpacity(&disp, &effects)) {
return true;
}
// Check for mask or clip path.
if (aStyleSVGReset->HasMask() || aStyleSVGReset->HasClipPath()) {
const auto& svgReset = *style.StyleSVGReset();
if (svgReset.HasMask() || svgReset.HasClipPath()) {
return true;
}
// TODO(cbrewster): Check will-change attributes
return false;
}
@ -3146,8 +3152,9 @@ void nsIFrame::BuildDisplayListForStackingContext(
return;
}
const nsStyleDisplay* disp = StyleDisplay();
const nsStyleEffects* effects = StyleEffects();
const auto& style = *Style();
const nsStyleDisplay* disp = style.StyleDisplay();
const nsStyleEffects* effects = style.StyleEffects();
EffectSet* effectSetForOpacity = EffectSet::GetEffectSetForFrame(
this, nsCSSPropertyIDSet::OpacityProperties());
// We can stop right away if this is a zero-opacity stacking context and
@ -3224,10 +3231,11 @@ void nsIFrame::BuildDisplayListForStackingContext(
AutoSaveRestoreContainsBlendMode autoRestoreBlendMode(*aBuilder);
aBuilder->SetContainsBlendMode(false);
bool usingBackdropFilter =
IsVisibleForPainting() && effects->HasBackdropFilters() &&
nsDisplayBackdropFilters::CanCreateWebRenderCommands(aBuilder, this);
// NOTE: When changing this condition make sure to tweak nsGfxScrollFrame as
// well.
bool usingBackdropFilter = effects->HasBackdropFilters() &&
IsVisibleForPainting() &&
!style.IsRootElementStyle();
if (usingBackdropFilter) {
aBuilder->SetContainsBackdropFilter(true);
}
@ -3319,7 +3327,7 @@ void nsIFrame::BuildDisplayListForStackingContext(
}
}
bool usingFilter = effects->HasFilters();
bool usingFilter = effects->HasFilters() && !style.IsRootElementStyle();
bool usingMask = SVGIntegrationUtils::UsingMaskOrClipPathForFrame(this);
bool usingSVGEffects = usingFilter || usingMask;
@ -3482,8 +3490,8 @@ void nsIFrame::BuildDisplayListForStackingContext(
aBuilder->Check();
aBuilder->DisplayCaret(this, set.Outlines());
insertBackdropRoot = aBuilder->ContainsBackdropFilter() &&
FormsBackdropRoot(disp, effects, StyleSVGReset());
insertBackdropRoot =
aBuilder->ContainsBackdropFilter() && FormsBackdropRoot();
// Blend modes are a real pain for retained display lists. We build a blend
// container item if the built list contains any blend mode items within
@ -3584,7 +3592,7 @@ void nsIFrame::BuildDisplayListForStackingContext(
nsRect backdropRect =
GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
resultList.AppendNewToTop<nsDisplayBackdropFilters>(
aBuilder, this, &resultList, backdropRect);
aBuilder, this, &resultList, backdropRect, this);
createdContainer = true;
}
@ -3606,7 +3614,8 @@ void nsIFrame::BuildDisplayListForStackingContext(
// Skip all filter effects while generating glyph mask.
if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
/* List now emptied, so add the new list to the top. */
resultList.AppendNewToTop<nsDisplayFilters>(aBuilder, this, &resultList);
resultList.AppendNewToTop<nsDisplayFilters>(aBuilder, this, &resultList,
this);
createdContainer = true;
}

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

@ -1955,9 +1955,7 @@ class nsIFrame : public nsQueryFrame {
* Return true if this frame should form a backdrop root container.
* See: https://drafts.fxtf.org/filter-effects-2/#BackdropRootTriggers
*/
bool FormsBackdropRoot(const nsStyleDisplay* aStyleDisplay,
const nsStyleEffects* aStyleEffects,
const nsStyleSVGReset* aStyleSvgReset);
bool FormsBackdropRoot() const;
/**
* Returns whether this frame will attempt to extend the 3d transforms of its

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

@ -8296,19 +8296,14 @@ bool nsDisplayBackdropRootContainer::CreateWebRenderCommands(
return true;
}
/* static */
bool nsDisplayBackdropFilters::CanCreateWebRenderCommands(
nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
return SVGIntegrationUtils::CanCreateWebRenderFiltersForFrame(aFrame);
}
bool nsDisplayBackdropFilters::CreateWebRenderCommands(
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc, RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) {
WrFiltersHolder wrFilters;
Maybe<nsRect> filterClip;
auto filterChain = mFrame->StyleEffects()->mBackdropFilters.AsSpan();
const ComputedStyle& style = mStyle ? *mStyle : *mFrame->Style();
auto filterChain = style.StyleEffects()->mBackdropFilters.AsSpan();
bool initialized = true;
if (!SVGIntegrationUtils::CreateWebRenderCSSFilters(filterChain, mFrame,
wrFilters) &&
@ -8324,7 +8319,7 @@ bool nsDisplayBackdropFilters::CreateWebRenderCommands(
nsCSSRendering::ImageLayerClipState clip;
nsCSSRendering::GetImageLayerClip(
mFrame->StyleBackground()->BottomLayer(), mFrame, *mFrame->StyleBorder(),
style.StyleBackground()->BottomLayer(), mFrame, *style.StyleBorder(),
mBackdropRect, mBackdropRect, false,
mFrame->PresContext()->AppUnitsPerDevPixel(), &clip);
@ -8359,8 +8354,10 @@ void nsDisplayBackdropFilters::Paint(nsDisplayListBuilder* aBuilder,
/* static */
nsDisplayFilters::nsDisplayFilters(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList)
nsIFrame* aFrame, nsDisplayList* aList,
nsIFrame* aStyleFrame)
: nsDisplayEffectsBase(aBuilder, aFrame, aList),
mStyle(aFrame == aStyleFrame ? nullptr : aStyleFrame->Style()),
mEffectsBounds(aFrame->InkOverflowRectRelativeToSelf()) {
MOZ_COUNT_CTOR(nsDisplayFilters);
mVisibleRect = aBuilder->GetVisibleRect() +
@ -8382,7 +8379,6 @@ void nsDisplayFilters::ComputeInvalidationRegion(
const auto* geometry =
static_cast<const nsDisplayFiltersGeometry*>(aGeometry);
if (aBuilder->ShouldSyncDecodeImages() &&
geometry->ShouldInvalidateToSyncDecodeImages()) {
bool snap;
@ -8394,6 +8390,7 @@ void nsDisplayFilters::ComputeInvalidationRegion(
void nsDisplayFilters::PaintWithContentsPaintCallback(
nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
const std::function<void(gfxContext* aContext)>& aPaintChildren) {
MOZ_ASSERT(!mStyle, "Shouldn't get to this code path on the root");
imgDrawingParams imgParams(aBuilder->GetImageDecodeFlags());
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
SVGIntegrationUtils::PaintFramesParams params(
@ -8427,11 +8424,16 @@ bool nsDisplayFilters::CreateWebRenderCommands(
WrFiltersHolder wrFilters;
Maybe<nsRect> filterClip;
bool initialized = true;
auto filterChain = mFrame->StyleEffects()->mFilters.AsSpan();
auto filterChain = mStyle ? mStyle->StyleEffects()->mFilters.AsSpan()
: mFrame->StyleEffects()->mFilters.AsSpan();
if (!SVGIntegrationUtils::CreateWebRenderCSSFilters(filterChain, mFrame,
wrFilters) &&
!SVGIntegrationUtils::BuildWebRenderFilters(
mFrame, filterChain, wrFilters, filterClip, initialized)) {
if (mStyle) {
// TODO(bug 1769223): Support fallback filters in the root code-path.
return true;
}
return false;
}

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

@ -5973,8 +5973,10 @@ class nsDisplayBackdropRootContainer : public nsDisplayWrapList {
class nsDisplayBackdropFilters : public nsDisplayWrapList {
public:
nsDisplayBackdropFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, const nsRect& aBackdropRect)
nsDisplayList* aList, const nsRect& aBackdropRect,
nsIFrame* aStyleFrame)
: nsDisplayWrapList(aBuilder, aFrame, aList),
mStyle(aFrame == aStyleFrame ? nullptr : aStyleFrame->Style()),
mBackdropRect(aBackdropRect) {
MOZ_COUNT_CTOR(nsDisplayBackdropFilters);
}
@ -5990,9 +5992,6 @@ class nsDisplayBackdropFilters : public nsDisplayWrapList {
nsDisplayListBuilder* aDisplayListBuilder) override;
void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
static bool CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame);
bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
return !aBuilder->IsPaintingForWebRender();
}
@ -6000,6 +5999,7 @@ class nsDisplayBackdropFilters : public nsDisplayWrapList {
bool CreatesStackingContextHelper() override { return true; }
private:
RefPtr<ComputedStyle> mStyle;
nsRect mBackdropRect;
};
@ -6013,11 +6013,12 @@ class nsDisplayBackdropFilters : public nsDisplayWrapList {
class nsDisplayFilters : public nsDisplayEffectsBase {
public:
nsDisplayFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList);
nsDisplayList* aList, nsIFrame* aStyleFrame);
nsDisplayFilters(nsDisplayListBuilder* aBuilder,
const nsDisplayFilters& aOther)
: nsDisplayEffectsBase(aBuilder, aOther),
mStyle(aOther.mStyle),
mEffectsBounds(aOther.mEffectsBounds) {
MOZ_COUNT_CTOR(nsDisplayFilters);
}
@ -6082,6 +6083,7 @@ class nsDisplayFilters : public nsDisplayEffectsBase {
private:
NS_DISPLAY_ALLOW_CLONING()
RefPtr<ComputedStyle> mStyle;
// relative to mFrame
nsRect mEffectsBounds;
nsRect mVisibleRect;

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

@ -97,6 +97,10 @@ bool nsStyleDisplay::IsFixedPosContainingBlockForNonSVGTextFrames(
// should return FIXPOS_CB_NON_SVG for will-change.
NS_ASSERTION(aStyle.StyleDisplay() == this, "unexpected aStyle");
if (aStyle.IsRootElementStyle()) {
return false;
}
if (mWillChange.bits & mozilla::StyleWillChangeBits::FIXPOS_CB_NON_SVG) {
return true;
}

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

@ -1732,7 +1732,8 @@ already_AddRefed<nsIURI> SVGObserverUtils::GetBaseURLForLocalRef(
already_AddRefed<URLAndReferrerInfo> SVGObserverUtils::GetFilterURI(
nsIFrame* aFrame, const StyleFilter& aFilter) {
MOZ_ASSERT(!aFrame->StyleEffects()->mFilters.IsEmpty() ||
!aFrame->StyleEffects()->mBackdropFilters.IsEmpty());
!aFrame->StyleEffects()->mBackdropFilters.IsEmpty() ||
!aFrame->GetContent()->GetParent());
MOZ_ASSERT(aFilter.IsUrl());
return ResolveURLUsingLocalRef(aFrame, aFilter.AsUrl());
}

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

@ -1,2 +0,0 @@
[root-element-filter.html]
expected: FAIL

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

@ -1,2 +0,0 @@
[will-change-fixedpos-cb-003.html]
expected: FAIL

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

@ -1,3 +0,0 @@
[will-change-fixedpos-cb-006.html]
expected: FAIL
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1423746

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

@ -1,2 +0,0 @@
[filtered-html-is-not-container.html]
expected: FAIL