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

This commit is contained in:
Robert O'Callahan 2009-07-22 12:45:14 +12:00
parent 933f110f1a
commit 0ed9805957
11 changed files with 131 additions and 11 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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));
}

View File

@ -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)

View File

@ -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]]);

View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins in Transforms">
<head>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
embed { width:300px; height:200px; display:block; }
</style>
</head>
<body>
<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
<hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox style="width:100px;"></hbox><hbox id="h2"/>
</hbox>
<div style="width:200px; position:absolute; top:0; left:0; -moz-transform:rotate(90deg)">
<embed id="p1" type="application/x-test" wmode="window"></embed>
</div>
<svg xmlns="http://www.w3.org/2000/svg" style="width:200px; position:absolute; top:200px; left:0;">
<foreignObject width="200" height="200">
<embed xmlns="http://www.w3.org/1999/xhtml" id="p2" type="application/x-test" wmode="window"></embed>
</foreignObject>
</svg>
<script src="plugin_clipping_lib.js"></script>
<script class="testbody" type="application/javascript">
<![CDATA[
function runTests() {
// p1 and p2 are both in a transformed context so they should be hidden.
checkClipRegionNoBounds("p1", []);
checkClipRegionNoBounds("p2", []);
}
]]>
</script>
</body>
</html>

View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins in Transforms">
<head>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<script class="testbody" type="application/javascript">
<![CDATA[
if (navigator.platform.indexOf("Mac") == 0) {
todo(false, "Mac plugins do not run in windowed mode");
} else {
window.open("plugin_clipping_helper_transformed.xhtml", "", "width=620,height=320");
SimpleTest.waitForExplicitFinish();
}
]]>
</script>
</body>
</html>

View File

@ -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();