Bug 731777 - Correctly recompute overflow areas for frames with transform perspective applied. r=roc

This commit is contained in:
Matt Woodrow 2012-03-12 15:04:25 +13:00
parent f0d02037a5
commit 49bb21ce6d
5 changed files with 81 additions and 11 deletions

View File

@ -2451,8 +2451,7 @@ gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
*/
static
gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel,
const nsRect* aBoundsOverride)
float aAppUnitsPerPixel)
{
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
@ -2469,8 +2468,7 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
// How do we handle aBoundsOverride in the latter case?
nsIFrame* parent = aFrame->GetParentStyleContextFrame();
const nsStyleDisplay* display = aFrame->GetParent()->GetStyleDisplay();
nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
nsDisplayTransform::GetFrameBoundsForTransform(parent));
nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent);
/* Allows us to access named variables by index. */
gfxPoint3D result;
@ -2574,7 +2572,7 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
/* At the point when perspective is applied, we have been translated to the transform origin.
* The translation to the perspective origin is the difference between these values.
*/
gfxPoint3D toPerspectiveOrigin = GetDeltaToMozPerspectiveOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride);
gfxPoint3D toPerspectiveOrigin = GetDeltaToMozPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin - toMozOrigin, perspective);
}

View File

@ -185,6 +185,7 @@ _TEST_FILES = \
test_bug718809.html \
test_font_inflation_reftests.html \
test_bug725426.html \
test_bug731777.html \
$(NULL)
# Tests for bugs 441782, 467672 and 570378 don't pass reliably on Windows, because of bug 469208

View File

@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 731777</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
#container {
position: relative;
height: 300px;
width: 300px;
margin: 50px 100px;
border: 2px solid blue;
background-color: #044B0A;
-moz-perspective: 500px;
overflow:hidden;
}
#inner {
margin: 0px;
width: 480px;
border: 2px solid blue;
height: 220px;
background-color: #844BCA;
-moz-transform: rotateY(91deg) translateX(0px) translateZ(0px);
-moz-transition: 5s;
}
</style>
</head>
<body>
<div id="container">
<div id="inner"></div>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 731777 **/
is(document.elementFromPoint(325,170), document.getElementById("inner"), "Able to hit transformed object");
is(document.elementFromPoint(405,170), document.getElementById("inner"), "Able to hit transformed object");
</script>
</pre>
</body>
</html>

View File

@ -995,6 +995,18 @@ nsIFrame::HasPerspective() const
return false;
}
bool
nsIFrame::ChildrenHavePerspective() const
{
const nsStyleDisplay *disp = GetStyleContext()->GetStyleDisplay();
if (disp &&
disp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
disp->mChildPerspective.GetCoordValue() > 0.0) {
return true;
}
return false;
}
nsRect
nsIFrame::GetContentRectRelativeToSelf() const
{
@ -6771,12 +6783,17 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
}
if (Preserves3DChildren()) {
ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
} else if (HasPerspective()) {
RecomputePerspectiveChildrenOverflow(this, &newBounds);
} else if (ChildrenHavePerspective()) {
RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
}
} else {
Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
if (ChildrenHavePerspective()) {
nsRect newBounds(nsPoint(0, 0), aNewSize);
RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
}
}
bool anyOverflowChanged;
if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
@ -6833,7 +6850,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
}
void
nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, const nsRect* aBounds)
nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
{
// Children may check our size when getting our transform, make sure it's valid.
nsSize oldSize = GetSize();
@ -6856,8 +6873,11 @@ nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, cons
boundsOverflow.SetAllTo(bounds);
child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
}
} else if (child->GetParentStyleContextFrame() != aStartFrame) {
child->RecomputePerspectiveChildrenOverflow(aStartFrame, nsnull);
} else if (child->GetStyleContext()->GetParent() == aStartStyle ||
child->GetStyleContext() == aStartStyle) {
// Recurse into frames with the same style context, or a direct
// child style context.
child->RecomputePerspectiveChildrenOverflow(aStartStyle, nsnull);
}
}
}

View File

@ -1245,10 +1245,12 @@ public:
bool HasPerspective() const;
bool ChildrenHavePerspective() const;
// Calculate the overflow size of all child frames, taking preserve-3d into account
void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds);
void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, const nsRect* aBounds);
void RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds);
/**
* Event handling of GUI events.