Bug 749075. Part 1: Refactor the nsDisplayItem API for testing whether the item needs to be rendered to a transparent surface. r=mattwoodrow

Currently we return an extra out parameter on GetOpaqueRegion. This is ugly and it's also going to be inefficient
because in a followup patch I'm going to avoid calls to GetOpaqueRegion, but we still need to know whether the item
needs a transparent surface. So this patch removes that out parameter. Instead, we rely on the fact that only
Windows' glass-window-background display item needs to force a transparent surface, and there can only be one
of those per window. So we store a reference to it in the nsDisplayListBuilder if there is one, and then we can
efficiently tell if any leaf display item is the one that forces a transparent surface. For display items that
wrap a list, we continue to store whether they need to force a transparent surface in a boolean in the list.
This commit is contained in:
Robert O'Callahan 2012-05-03 16:29:05 +12:00
parent db184efc0a
commit 1c1601b380
7 changed files with 55 additions and 71 deletions

View File

@ -1189,9 +1189,13 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
const nsIntRect& aDrawRect,
const FrameLayerBuilder::Clip& aClip)
{
if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
mForceTransparentSurface = true;
}
nscolor uniformColor;
bool isUniform = aItem->IsUniform(aState->mBuilder, &uniformColor);
/* Mark as available for conversion to image layer if this is a nsDisplayImage and
* we are the first visible item in the ThebesLayerData object.
*/
@ -1238,10 +1242,8 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
mDrawRegion.SimplifyOutward(4);
}
bool forceTransparentSurface;
bool snap;
nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap,
&forceTransparentSurface);
nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap);
if (!opaque.IsEmpty()) {
nsRegionRectIterator iter(opaque);
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
@ -1284,7 +1286,6 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
}
}
}
mForceTransparentSurface = mForceTransparentSurface || forceTransparentSurface;
}
already_AddRefed<ThebesLayer>

View File

@ -82,6 +82,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mFinalTransparentRegion(nsnull),
mCachedOffsetFrame(aReferenceFrame),
mCachedOffset(0, 0),
mGlassDisplayItem(nsnull),
mMode(aMode),
mBuildCaret(aBuildCaret),
mIgnoreSuppression(false),
@ -443,11 +444,10 @@ nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
}
static nsRegion
TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder,
bool* aTransparentBackground)
TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
{
bool snap;
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap, aTransparentBackground);
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
if (aBuilder->IsForPluginGeometry()) {
// Treat all chrome items as opaque, unless their frames are opacity:0.
// Since opacity:0 frames generate an nsDisplayOpacity, that item will
@ -535,11 +535,13 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
if (item->ComputeVisibility(aBuilder, aVisibleRegion, aAllowVisibleRegionExpansion)) {
anyVisible = true;
bool transparentBackground = false;
nsRegion opaque = TreatAsOpaque(item, aBuilder, &transparentBackground);
nsRegion opaque = TreatAsOpaque(item, aBuilder);
// Subtract opaque item from the visible region
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
forceTransparentSurface = forceTransparentSurface || transparentBackground;
if (aBuilder->NeedToForceTransparentSurfaceForItem(item) ||
(list && list->NeedsTransparentSurface())) {
forceTransparentSurface = true;
}
}
AppendToBottom(item);
}
@ -930,8 +932,7 @@ bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
if (!ComputeVisibility(aBuilder, aVisibleRegion, nsRect()))
return false;
bool forceTransparentBackground;
nsRegion opaque = TreatAsOpaque(this, aBuilder, &forceTransparentBackground);
nsRegion opaque = TreatAsOpaque(this, aBuilder);
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
return true;
}
@ -983,6 +984,9 @@ nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
if (disp->mAppearance == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
disp->mAppearance == NS_THEME_TOOLBAR) {
RegisterThemeGeometry(aBuilder, aFrame);
} else if (disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
disp->mAppearance == NS_THEME_WIN_GLASS) {
aBuilder->SetGlassDisplayItem(this);
}
} else {
// Set HasFixedItems if we construct a background-attachment:fixed item
@ -1170,18 +1174,11 @@ nsDisplayBackground::GetInsideClipRegion(nsPresContext* aPresContext,
nsRegion
nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface) {
bool* aSnap) {
nsRegion result;
*aSnap = false;
*aForceTransparentSurface = false;
// theme background overrides any other background
if (mIsThemed) {
if (aForceTransparentSurface) {
const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
*aForceTransparentSurface = disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
disp->mAppearance == NS_THEME_WIN_GLASS;
}
if (mThemeTransparency == nsITheme::eOpaque) {
result = GetBounds(aBuilder, aSnap);
}
@ -1629,9 +1626,7 @@ nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion
nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface) {
*aForceTransparentSurface = false;
bool* aSnap) {
*aSnap = false;
nsRegion result;
if (mList.IsOpaque()) {
@ -1776,9 +1771,7 @@ nsDisplayOpacity::~nsDisplayOpacity() {
#endif
nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface) {
*aForceTransparentSurface = false;
bool* aSnap) {
*aSnap = false;
// We are never opaque, if our opacity was < 1 then we wouldn't have
// been created.
@ -2213,11 +2206,9 @@ nsDisplayClipRoundedRect::~nsDisplayClipRoundedRect()
nsRegion
nsDisplayClipRoundedRect::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface)
bool* aSnap)
{
*aSnap = false;
*aForceTransparentSurface = false;
return nsRegion();
}
@ -2852,10 +2843,8 @@ nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap
* certainly contains the actual (non-axis-aligned) untransformed rect.
*/
nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
bool* aSnap,
bool* aForceTransparentSurface)
bool* aSnap)
{
*aForceTransparentSurface = false;
*aSnap = false;
nsRect untransformedVisible;
float factor = nsPresContext::AppUnitsPerCSSPixel();
@ -2868,11 +2857,9 @@ nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
nsRegion result;
gfxMatrix matrix2d;
bool tmpSnap;
bool forceTransparentSurface;
if (matrix.Is2D(&matrix2d) &&
matrix2d.PreservesAxisAlignedRectangles() &&
mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap, &forceTransparentSurface).
Contains(untransformedVisible)) {
mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) {
result = mVisibleRect;
}
return result;
@ -3032,10 +3019,8 @@ nsDisplaySVGEffects::~nsDisplaySVGEffects()
#endif
nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface)
bool* aSnap)
{
*aForceTransparentSurface = false;
*aSnap = false;
return nsRegion();
}

View File

@ -496,6 +496,20 @@ public:
const nsRegion& GetExcludedGlassRegion() {
return mExcludedGlassRegion;
}
void SetGlassDisplayItem(nsDisplayItem* aItem) {
if (mGlassDisplayItem) {
// Web pages or extensions could trigger this by using
// -moz-appearance:win-borderless-glass etc on their own elements.
// Keep the first one, since that will be the background of the root
// window
NS_WARNING("Multiple glass backgrounds found?");
} else {
mGlassDisplayItem = aItem;
}
}
bool NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem) {
return aItem == mGlassDisplayItem;
}
private:
void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
@ -529,6 +543,8 @@ private:
nsPoint mCachedOffset;
nsRect mDisplayPort;
nsRegion mExcludedGlassRegion;
// The display item for the Windows window glass background, if any
nsDisplayItem* mGlassDisplayItem;
Mode mMode;
bool mBuildCaret;
bool mIgnoreSuppression;
@ -699,11 +715,9 @@ public:
* culling.
*/
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface)
bool* aSnap)
{
*aSnap = false;
*aForceTransparentSurface = false;
return nsRegion();
}
/**
@ -1217,8 +1231,7 @@ private:
// opaque content in this list).
bool mIsOpaque;
// This is set to true by ComputeVisibility if any display item in this
// list needs to force the surface to be transparent (e.g. if the
// item "punch holes" on the surface by clearing part of its area).
// list needs to force the surface containing this list to be transparent.
bool mForceTransparentSurface;
#ifdef DEBUG
bool mDidComputeVisibility;
@ -1554,10 +1567,8 @@ public:
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aOutTransparentBackground) {
bool* aSnap) {
*aSnap = false;
*aOutTransparentBackground = false;
nsRegion result;
if (NS_GET_A(mColor) == 255) {
result = GetBounds(aBuilder, aSnap);
@ -1598,8 +1609,7 @@ public:
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion);
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface);
bool* aSnap);
virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame);
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor);
@ -1755,8 +1765,7 @@ public:
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface);
bool* aSnap);
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor);
virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame);
@ -1861,8 +1870,7 @@ public:
#endif
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface);
bool* aSnap);
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters);
@ -2068,8 +2076,7 @@ public:
#endif
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface);
bool* aSnap);
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
@ -2140,8 +2147,7 @@ public:
#endif
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface);
bool* aSnap);
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
@ -2221,8 +2227,7 @@ public:
HitTestState *aState, nsTArray<nsIFrame*> *aOutFrames);
virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap);
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
bool* aSnap,
bool* aForceTransparentSurface);
bool* aSnap);
virtual bool IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);

View File

@ -192,8 +192,7 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
}
#ifdef DEBUG
if (!list || list->DidComputeVisibility()) {
bool forceTransparentSurface;
opaque = i->GetOpaqueRegion(aBuilder, &snap, &forceTransparentSurface);
opaque = i->GetOpaqueRegion(aBuilder, &snap);
}
#endif
if (i->Painted()) {

View File

@ -170,15 +170,12 @@ public:
aAllowVisibleRegionExpansion);
}
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface)
bool* aSnap)
{
if (NS_GET_A(mExtraBackgroundColor) == 255) {
*aForceTransparentSurface = false;
return nsRegion(GetBounds(aBuilder, aSnap));
}
return nsDisplayBackground::GetOpaqueRegion(aBuilder, aSnap,
aForceTransparentSurface);
return nsDisplayBackground::GetOpaqueRegion(aBuilder, aSnap);
}
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor)
{

View File

@ -1000,10 +1000,8 @@ nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion
nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface)
bool* aSnap)
{
*aForceTransparentSurface = false;
*aSnap = false;
nsRegion result;
nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);

View File

@ -301,8 +301,7 @@ public:
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap,
bool* aForceTransparentSurface);
bool* aSnap);
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx);
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,