From 1c1601b380c3ee66480c2d976293ec413759af16 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 3 May 2012 16:29:05 +1200 Subject: [PATCH] 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. --- layout/base/FrameLayerBuilder.cpp | 11 ++++--- layout/base/nsDisplayList.cpp | 53 +++++++++++-------------------- layout/base/nsDisplayList.h | 45 ++++++++++++++------------ layout/base/nsLayoutDebugger.cpp | 3 +- layout/generic/nsCanvasFrame.h | 7 ++-- layout/generic/nsObjectFrame.cpp | 4 +-- layout/generic/nsObjectFrame.h | 3 +- 7 files changed, 55 insertions(+), 71 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index e6daff4aa6fe..31339b76c836 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -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 diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index abe35f2f32d8..8f4c718b9acf 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -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(); } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index ef09a056a103..cac0573478d3 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -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 *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 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 *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 *aOutFrames); virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { @@ -2221,8 +2227,7 @@ public: HitTestState *aState, nsTArray *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); diff --git a/layout/base/nsLayoutDebugger.cpp b/layout/base/nsLayoutDebugger.cpp index 07fe3ad972cd..d8c2fedc977c 100644 --- a/layout/base/nsLayoutDebugger.cpp +++ b/layout/base/nsLayoutDebugger.cpp @@ -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()) { diff --git a/layout/generic/nsCanvasFrame.h b/layout/generic/nsCanvasFrame.h index 00e7aed9af84..1ed9bd611a92 100644 --- a/layout/generic/nsCanvasFrame.h +++ b/layout/generic/nsCanvasFrame.h @@ -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) { diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index 7d572a043d07..cd75b12c8bf8 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -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(mFrame); diff --git a/layout/generic/nsObjectFrame.h b/layout/generic/nsObjectFrame.h index 2ff61630e0fb..d01c9da8f549 100644 --- a/layout/generic/nsObjectFrame.h +++ b/layout/generic/nsObjectFrame.h @@ -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,