From 0ed9805957b2424a87061851a6b5fcdcf972e552 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 22 Jul 2009 12:45:14 +1200 Subject: [PATCH] Bug 339548. Part 14: hide windowed plugins in CSS transforms and SVG foreignObject contexts; we can't display them properly, so let's not display them at all. r=dbaron --- layout/base/nsDisplayList.cpp | 3 +- layout/base/nsDisplayList.h | 36 +++++++++++++++- layout/base/nsLayoutUtils.cpp | 7 +++- layout/base/nsLayoutUtils.h | 6 ++- layout/generic/nsFrame.cpp | 9 +++- layout/generic/nsObjectFrame.cpp | 11 ++++- layout/generic/test/Makefile.in | 2 + .../test/plugin_clipping_helper2.xhtml | 1 - .../plugin_clipping_helper_transformed.xhtml | 42 +++++++++++++++++++ .../test_plugin_clipping_transformed.xhtml | 22 ++++++++++ .../svg/base/src/nsSVGForeignObjectFrame.cpp | 3 +- 11 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 layout/generic/test/plugin_clipping_helper_transformed.xhtml create mode 100644 layout/generic/test/test_plugin_clipping_transformed.xhtml diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 6d31da6138e7..683841bb6b9b 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -71,7 +71,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mEventDelivery(aIsForEvents), mIsAtRootOfPseudoStackingContext(PR_FALSE), mPaintAllFrames(PR_FALSE), - mAccurateVisibleRegions(PR_FALSE) { + mAccurateVisibleRegions(PR_FALSE), + mInTransform(PR_FALSE) { PL_InitArenaPool(&mPool, "displayListArena", 1024, sizeof(void*)-1); nsPresContext* pc = aReferenceFrame->PresContext(); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 310e712860bd..ff9b8ec9a5a5 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -263,7 +263,19 @@ public: * Notify the display list builder that we're leaving a presshell. */ void LeavePresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect); - + + /** + * Returns true if we're currently building a display list that's + * directly or indirectly under an nsDisplayTransform or SVG + * foreignObject. + */ + PRBool IsInTransform() { return mInTransform; } + /** + * Indicate whether or not we're directly or indirectly under and + * nsDisplayTransform or SVG foreignObject. + */ + void SetInTransform(PRBool aInTransform) { mInTransform = aInTransform; } + /** * Mark aFrames and its (next) siblings to be displayed if they * intersect aDirtyRect (which is relative to aDirtyFrame). If the @@ -301,6 +313,25 @@ public: nsDisplayListBuilder* mBuilder; PRPackedBool mOldValue; }; + + /** + * A helper class to temporarily set the value of mInTransform. + */ + class AutoInTransformSetter; + friend class AutoInTransformSetter; + class AutoInTransformSetter { + public: + AutoInTransformSetter(nsDisplayListBuilder* aBuilder, PRBool aInTransform) + : mBuilder(aBuilder), mOldValue(aBuilder->mInTransform) { + aBuilder->mInTransform = aInTransform; + } + ~AutoInTransformSetter() { + mBuilder->mInTransform = mOldValue; + } + private: + nsDisplayListBuilder* mBuilder; + PRPackedBool mOldValue; + }; // Helpers for tables nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; } @@ -337,6 +368,9 @@ private: PRPackedBool mIsAtRootOfPseudoStackingContext; PRPackedBool mPaintAllFrames; PRPackedBool mAccurateVisibleRegions; + // True when we're building a display list that's directly or indirectly + // under an nsDisplayTransform + PRPackedBool mInTransform; }; class nsDisplayItem; diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 88242bd6c3cd..0e7cf16b47cb 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1048,14 +1048,17 @@ GetNextPage(nsIFrame* aPageContentFrame) nsresult nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame, - const nsRegion& aDirtyRegion, nscolor aBackstop) + const nsRegion& aDirtyRegion, nscolor aBackstop, + PRUint32 aFlags) { nsAutoDisableGetUsedXAssertions disableAssert; nsDisplayListBuilder builder(aFrame, PR_FALSE, PR_TRUE); nsDisplayList list; nsRect dirtyRect = aDirtyRegion.GetBounds(); - + if (aFlags & PAINT_IN_TRANSFORM) { + builder.SetInTransform(PR_TRUE); + } nsresult rv; builder.EnterPresShell(aFrame, dirtyRect); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 00120b63c7dc..b270c80adb56 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -476,6 +476,7 @@ public: static nsRect RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor); + enum { PAINT_IN_TRANSFORM = 0x01 }; /** * Given aFrame, the root frame of a stacking context, paint it and its * descendants to aRenderingContext. @@ -486,9 +487,12 @@ public: * of aFrame * @param aBackstop paint the dirty area with this color before drawing * the actual content; pass NS_RGBA(0,0,0,0) to draw no background + * @param aFlags if PAINT_IN_TRANSFORM is set, then we assume + * this is inside a transform or SVG foreignObject. */ static nsresult PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame, - const nsRegion& aDirtyRegion, nscolor aBackstop); + const nsRegion& aDirtyRegion, nscolor aBackstop, + PRUint32 aFlags = 0); /** * @param aRootFrame the root frame of the tree to be displayed diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 82fdf64687d9..dbaf2e06c296 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1253,13 +1253,16 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, ApplyAbsPosClipping(aBuilder, disp, this, &absPosClip); nsRect dirtyRect = aDirtyRect; + PRBool inTransform = aBuilder->IsInTransform(); /* If we're being transformed, we need to invert the matrix transform so that we don't * grab points in the wrong coordinate system! */ if ((mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) && - disp->HasTransform()) + disp->HasTransform()) { dirtyRect = nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0)); - + inTransform = PR_TRUE; + } + if (applyAbsPosClipping) { dirtyRect.IntersectRect(dirtyRect, absPosClip - aBuilder->ToReferenceFrame(this)); @@ -1277,6 +1280,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, nsresult rv; { nsDisplayListBuilder::AutoIsRootSetter rootSetter(aBuilder, PR_TRUE); + nsDisplayListBuilder::AutoInTransformSetter + inTransformSetter(aBuilder, inTransform); rv = BuildDisplayList(aBuilder, dirtyRect, set); } NS_ENSURE_SUCCESS(rv, rv); diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index f96684100a84..0936741f5a2b 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -1233,12 +1233,19 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return NS_OK; DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame"); - + +#ifndef XP_MACOSX + if (mWidget && aBuilder->IsInTransform()) { + // Windowed plugins should not be rendered inside a transform. + return NS_OK; + } +#endif + // determine if we are printing if (type == nsPresContext::eContext_Print) return aLists.Content()->AppendNewToTop(new (aBuilder) nsDisplayGeneric(this, PaintPrintPlugin, "PrintPlugin")); - + return aLists.Content()->AppendNewToTop(new (aBuilder) nsDisplayPlugin(this)); } diff --git a/layout/generic/test/Makefile.in b/layout/generic/test/Makefile.in index ae73e00ded8a..1fff5db6517d 100644 --- a/layout/generic/test/Makefile.in +++ b/layout/generic/test/Makefile.in @@ -53,6 +53,7 @@ _TEST_FILES = \ frame_selection_underline.css \ plugin_clipping_helper.xhtml \ plugin_clipping_helper2.xhtml \ + plugin_clipping_helper_transformed.xhtml \ plugin_clipping_lib.js \ test_backspace_delete.xul \ test_bug263683.html \ @@ -86,6 +87,7 @@ _TEST_FILES = \ test_movement_by_words.html \ test_plugin_clipping.xhtml \ test_plugin_clipping2.xhtml \ + test_plugin_clipping_transformed.xhtml \ test_plugin_position.xhtml \ test_selection_underline.html \ $(NULL) diff --git a/layout/generic/test/plugin_clipping_helper2.xhtml b/layout/generic/test/plugin_clipping_helper2.xhtml index 20599255faaf..a12194263eb3 100644 --- a/layout/generic/test/plugin_clipping_helper2.xhtml +++ b/layout/generic/test/plugin_clipping_helper2.xhtml @@ -40,7 +40,6 @@ function runTests() { var zbox = document.getElementById("zbox"); var sbox = document.getElementById("sbox"); var p1 = document.getElementById("p1"); - var d1 = document.getElementById("d1"); var d2 = document.getElementById("d2"); checkClipRegion("p1", [[0, 0, 200, 100]]); diff --git a/layout/generic/test/plugin_clipping_helper_transformed.xhtml b/layout/generic/test/plugin_clipping_helper_transformed.xhtml new file mode 100644 index 000000000000..5a82f900aee0 --- /dev/null +++ b/layout/generic/test/plugin_clipping_helper_transformed.xhtml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + diff --git a/layout/generic/test/test_plugin_clipping_transformed.xhtml b/layout/generic/test/test_plugin_clipping_transformed.xhtml new file mode 100644 index 000000000000..bbb03261596c --- /dev/null +++ b/layout/generic/test/test_plugin_clipping_transformed.xhtml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index 4346d4d1d3c5..fe668911d911 100644 --- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -237,7 +237,8 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext, gfx->Multiply(matrix); nsresult rv = nsLayoutUtils::PaintFrame(ctx, kid, nsRegion(kid->GetRect()), - NS_RGBA(0,0,0,0)); + NS_RGBA(0,0,0,0), + nsLayoutUtils::PAINT_IN_TRANSFORM); gfx->Restore();