Bug 1664804 - Compute whether top layer content is opaque. r=miko

The default styling for a ::backdrop pseudo element results in it being fully opaque and occluding all the rest of the page.
This allows us to detect that case early, and skip doing any work for the rest of the page.

Differential Revision: https://phabricator.services.mozilla.com/D91669
This commit is contained in:
Matt Woodrow 2020-10-15 22:38:49 +00:00
parent 131e1f04be
commit 9dd8ce0730
2 changed files with 45 additions and 2 deletions

View File

@ -113,8 +113,46 @@ static void BuildDisplayListForTopLayerFrame(nsDisplayListBuilder* aBuilder,
aList->AppendToTop(&list);
}
static bool BackdropListIsOpaque(ViewportFrame* aFrame,
nsDisplayListBuilder* aBuilder,
nsDisplayList* aList) {
// The common case for ::backdrop elements on the top layer is a single
// fixed position container, holding an opaque background color covering
// the whole viewport.
if (aList->Count() != 1 ||
aList->GetTop()->GetType() != DisplayItemType::TYPE_FIXED_POSITION) {
return false;
}
// Make sure the fixed position container isn't clipped or scrollable.
nsDisplayFixedPosition* fixed =
static_cast<nsDisplayFixedPosition*>(aList->GetTop());
if (fixed->GetActiveScrolledRoot() || fixed->GetClipChain()) {
return false;
}
nsDisplayList* children = fixed->GetChildren();
if (!children->GetTop() ||
children->GetTop()->GetType() != DisplayItemType::TYPE_BACKGROUND_COLOR) {
return false;
}
nsDisplayBackgroundColor* child =
static_cast<nsDisplayBackgroundColor*>(children->GetTop());
if (child->GetActiveScrolledRoot() || child->GetClipChain()) {
return false;
}
// Check that the background color is both opaque, and covering the
// whole viewport.
bool dummy;
nsRegion opaque = child->GetOpaqueRegion(aBuilder, &dummy);
return opaque.Contains(aFrame->GetRect());
}
void ViewportFrame::BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList) {
nsDisplayList* aList,
bool* aIsOpaque) {
nsTArray<dom::Element*> topLayer = PresContext()->Document()->GetTopLayer();
for (dom::Element* elem : topLayer) {
if (nsIFrame* frame = elem->GetPrimaryFrame()) {
@ -152,6 +190,10 @@ void ViewportFrame::BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder,
static_cast<nsPlaceholderFrame*>(backdropPh)->GetOutOfFlowFrame();
MOZ_ASSERT(backdropFrame);
BuildDisplayListForTopLayerFrame(aBuilder, backdropFrame, aList);
if (aIsOpaque) {
*aIsOpaque = BackdropListIsOpaque(this, aBuilder, aList);
}
}
BuildDisplayListForTopLayerFrame(aBuilder, frame, aList);
}

View File

@ -52,7 +52,8 @@ class ViewportFrame : public nsContainerFrame {
const nsDisplayListSet& aLists) override;
void BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList);
nsDisplayList* aList,
bool* aIsOpaque = nullptr);
virtual nscoord GetMinISize(gfxContext* aRenderingContext) override;
virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;