From 50f59c86bf6019f9d8f0f0c12a9009856bbbef05 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 8 Nov 2010 22:06:14 +1300 Subject: [PATCH] Bug 598470. Treat all chrome display items as opaque when we're computing plugin visibility regions; this ensures translucent chrome content is visible above windowed plugins. r=tnikkel,a=blocker --- layout/base/nsDisplayList.cpp | 24 +++++-- layout/base/nsDisplayList.h | 18 ++++-- layout/base/nsLayoutUtils.cpp | 6 +- layout/base/nsPresContext.cpp | 3 +- layout/base/nsPresShell.cpp | 2 +- layout/base/tests/chrome/Makefile.in | 2 + .../chrome/chrome_over_plugin_window.xul | 62 +++++++++++++++++++ .../tests/chrome/test_chrome_over_plugin.xul | 25 ++++++++ layout/generic/nsGfxScrollFrame.cpp | 2 +- layout/generic/nsObjectFrame.cpp | 16 +++++ xpcom/glue/nsTArray.h | 6 ++ 11 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 layout/base/tests/chrome/chrome_over_plugin_window.xul create mode 100644 layout/base/tests/chrome/test_chrome_over_plugin.xul diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 003acafe998..31147b70cdf 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -68,12 +68,12 @@ using namespace mozilla; using namespace mozilla::layers; nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, - PRBool aIsForEvents, PRBool aBuildCaret) + Mode aMode, PRBool aBuildCaret) : mReferenceFrame(aReferenceFrame), mIgnoreScrollFrame(nsnull), mCurrentTableItem(nsnull), mBuildCaret(aBuildCaret), - mEventDelivery(aIsForEvents), + mMode(aMode), mIgnoreSuppression(PR_FALSE), mHadToIgnoreSuppression(PR_FALSE), mIsAtRootOfPseudoStackingContext(PR_FALSE), @@ -307,6 +307,21 @@ nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder, return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds()); } +static PRBool +TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder, + PRBool* aTransparentBackground) +{ + if (aItem->IsOpaque(aBuilder, aTransparentBackground)) + return PR_TRUE; + if (aBuilder->IsForPluginGeometry()) { + // Treat all chrome items as opaque + nsIFrame* f = aItem->GetUnderlyingFrame(); + if (f && f->PresContext()->IsChrome()) + return PR_TRUE; + } + return PR_FALSE; +} + PRBool nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion, @@ -345,7 +360,7 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, anyVisible = PR_TRUE; nsIFrame* f = item->GetUnderlyingFrame(); PRBool transparentBackground = PR_FALSE; - if (item->IsOpaque(aBuilder, &transparentBackground) && f) { + if (TreatAsOpaque(item, aBuilder, &transparentBackground) && f) { // Subtract opaque item from the visible region aBuilder->SubtractFromVisibleRegion(aVisibleRegion, nsRegion(bounds)); } @@ -650,7 +665,8 @@ PRBool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, if (!ComputeVisibility(aBuilder, aVisibleRegion)) return PR_FALSE; - if (IsOpaque(aBuilder)) { + PRBool forceTransparentBackground; + if (TreatAsOpaque(this, aBuilder, &forceTransparentBackground)) { aVisibleRegion->Sub(*aVisibleRegion, bounds); } return PR_TRUE; diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 84cbf1e0f0c..d2090f61076 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -136,15 +136,25 @@ public: * @param aBuildCaret whether or not we should include the caret in any * display lists that we make. */ - nsDisplayListBuilder(nsIFrame* aReferenceFrame, PRBool aIsForEvents, - PRBool aBuildCaret); + enum Mode { + PAINTING, + EVENT_DELIVERY, + PLUGIN_GEOMETRY, + OTHER + }; + nsDisplayListBuilder(nsIFrame* aReferenceFrame, Mode aMode, PRBool aBuildCaret); ~nsDisplayListBuilder(); /** * @return PR_TRUE if the display is being built in order to determine which * frame is under the mouse position. */ - PRBool IsForEventDelivery() { return mEventDelivery; } + PRBool IsForEventDelivery() { return mMode == EVENT_DELIVERY; } + /** + * @return PR_TRUE if the display list is being build to compute geometry + * for plugins. + */ + PRBool IsForPluginGeometry() { return mMode == PLUGIN_GEOMETRY; } /** * @return PR_TRUE if "painting is suppressed" during page load and we * should paint only the background of the document. @@ -393,8 +403,8 @@ private: nsAutoTArray mPresShellStates; nsAutoTArray mFramesMarkedForDisplay; nsDisplayTableItem* mCurrentTableItem; + Mode mMode; PRPackedBool mBuildCaret; - PRPackedBool mEventDelivery; PRPackedBool mIgnoreSuppression; PRPackedBool mHadToIgnoreSuppression; PRPackedBool mIsAtRootOfPseudoStackingContext; diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index dd05d7847be..15650ca43ac 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1093,7 +1093,8 @@ nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect, PRBool aShouldIgnoreSuppression, PRBool aIgnoreRootScrollFrame) { - nsDisplayListBuilder builder(aFrame, PR_TRUE, PR_FALSE); + nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::EVENT_DELIVERY, + PR_FALSE); nsDisplayList list; nsRect target(aRect); @@ -1266,7 +1267,8 @@ nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFra // *and after* we draw. PRBool willFlushRetainedLayers = (aFlags & PAINT_HIDE_CARET) != 0; - nsDisplayListBuilder builder(aFrame, PR_FALSE, !(aFlags & PAINT_HIDE_CARET)); + nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::PAINTING, + !(aFlags & PAINT_HIDE_CARET)); nsDisplayList list; if (aFlags & PAINT_IN_TRANSFORM) { builder.SetInTransform(PR_TRUE); diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 37bc60f6f08..968beab8fba 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2520,7 +2520,8 @@ nsRootPresContext::GetPluginGeometryUpdates(nsIFrame* aChangedSubtree, nsRect bounds; if (bounds.IntersectRect(closure.mAffectedPluginBounds, closure.mRootFrame->GetRect())) { - nsDisplayListBuilder builder(closure.mRootFrame, PR_FALSE, PR_FALSE); + nsDisplayListBuilder builder(closure.mRootFrame, + nsDisplayListBuilder::PLUGIN_GEOMETRY, PR_FALSE); builder.SetAccurateVisibleRegions(); nsDisplayList list; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 992ac9567c0..22ab07570f4 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -271,7 +271,7 @@ struct RangePaintInfo { nsPoint mRootOffset; RangePaintInfo(nsIRange* aRange, nsIFrame* aFrame) - : mRange(aRange), mBuilder(aFrame, PR_FALSE, PR_FALSE) + : mRange(aRange), mBuilder(aFrame, nsDisplayListBuilder::PAINTING, PR_FALSE) { MOZ_COUNT_CTOR(RangePaintInfo); } diff --git a/layout/base/tests/chrome/Makefile.in b/layout/base/tests/chrome/Makefile.in index e6d8fe32591..6167e6c4c59 100644 --- a/layout/base/tests/chrome/Makefile.in +++ b/layout/base/tests/chrome/Makefile.in @@ -53,6 +53,8 @@ _CHROME_FILES = \ bug551434_childframe.html \ test_chrome_content_integration.xul \ chrome_content_integration_window.xul \ + test_chrome_over_plugin.xul \ + chrome_over_plugin_window.xul \ test_default_background.xul \ default_background_window.xul \ test_printpreview.xul \ diff --git a/layout/base/tests/chrome/chrome_over_plugin_window.xul b/layout/base/tests/chrome/chrome_over_plugin_window.xul new file mode 100644 index 00000000000..b9792447c8b --- /dev/null +++ b/layout/base/tests/chrome/chrome_over_plugin_window.xul @@ -0,0 +1,62 @@ + + +\ + + +