Bug 721082 - Make perspective-origin relative to the parent elements border box. r=roc

This commit is contained in:
Matt Woodrow 2012-02-15 22:28:22 +13:00
parent 6905e450dd
commit cca8fbcca8
6 changed files with 134 additions and 4 deletions

View File

@ -2449,6 +2449,8 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
"Can't get a delta for an untransformed frame!");
NS_PRECONDITION(aFrame->GetParentStyleContextFrame(),
"Can't get delta without a style parent!");
/* For both of the coordinates, if the value of -moz-perspective-origin is a
* percentage, it's relative to the size of the frame. Otherwise, if it's
@ -2457,9 +2459,10 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
//TODO: Should this be using our bounds or the parent's bounds?
// 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(aFrame));
nsDisplayTransform::GetFrameBoundsForTransform(parent));
/* Allows us to access named variables by index. */
gfxPoint3D result;
@ -2487,7 +2490,12 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
}
}
return result;
nsPoint parentOffset = aFrame->GetOffsetTo(parent);
gfxPoint3D gfxOffset(NSAppUnitsToFloatPixels(parentOffset.x, aFactor),
NSAppUnitsToFloatPixels(parentOffset.y, aFactor),
0);
return result - gfxOffset;
}
/* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
@ -2511,7 +2519,6 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
* coordinate space to the new origin.
*/
gfxPoint3D toMozOrigin = GetDeltaToMozTransformOrigin(aFrame, aFactor, aBoundsOverride);
gfxPoint3D toPerspectiveOrigin = GetDeltaToMozPerspectiveOrigin(aFrame, aFactor, aBoundsOverride);
gfxPoint3D newOrigin = gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aFactor),
NSAppUnitsToFloatPixels(aOrigin.y, aFactor),
0.0f);
@ -2552,6 +2559,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, aFactor, aBoundsOverride);
result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin - toMozOrigin, perspective);
}

View File

@ -975,6 +975,26 @@ nsIFrame::Preserves3D() const
return true;
}
bool
nsIFrame::HasPerspective() const
{
if (!IsTransformed()) {
return false;
}
const nsStyleDisplay* parentDisp = nsnull;
nsStyleContext* parentStyleContext = GetStyleContext()->GetParent();
if (parentStyleContext) {
parentDisp = parentStyleContext->GetStyleDisplay();
}
if (parentDisp &&
parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
parentDisp->mChildPerspective.GetCoordValue() > 0.0) {
return true;
}
return false;
}
nsRect
nsIFrame::GetContentRectRelativeToSelf() const
{
@ -6634,7 +6654,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsRect bounds(nsPoint(0, 0), aNewSize);
// Store the passed in overflow area if we are a preserve-3d frame,
// and it's not just the frame bounds.
if (Preserves3D() && (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
if ((Preserves3D() || HasPerspective()) && (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
!aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds))) {
nsOverflowAreas* initial =
static_cast<nsOverflowAreas*>(Properties().Get(nsIFrame::InitialOverflowProperty()));
@ -6749,6 +6769,8 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
}
if (Preserves3DChildren()) {
ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
} else if (HasPerspective()) {
RecomputePerspectiveChildrenOverflow(this, &newBounds);
}
} else {
Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
@ -6808,6 +6830,39 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
return anyOverflowChanged;
}
void
nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, const nsRect* aBounds)
{
// Children may check our size when getting our transform, make sure it's valid.
nsSize oldSize = GetSize();
if (aBounds) {
SetSize(aBounds->Size());
}
nsIFrame::ChildListIterator lists(this);
for (; !lists.IsDone(); lists.Next()) {
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
nsIFrame* child = childFrames.get();
if (child->HasPerspective()) {
nsOverflowAreas* overflow =
static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
nsRect bounds(nsPoint(0, 0), child->GetSize());
if (overflow) {
child->FinishAndStoreOverflow(*overflow, bounds.Size());
} else {
nsOverflowAreas boundsOverflow;
boundsOverflow.SetAllTo(bounds);
child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
}
} else if (child->GetParentStyleContextFrame() != aStartFrame) {
child->RecomputePerspectiveChildrenOverflow(aStartFrame, nsnull);
}
}
}
// Restore our old size just in case something depends on this elesewhere.
SetSize(oldSize);
}
/* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
* the mRect value for their parents (since we use their transform, and transform
* depends on this for transform-origin etc). These weren't necessarily correct

View File

@ -1247,9 +1247,13 @@ public:
*/
bool Preserves3D() const;
bool HasPerspective() 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);
/**
* Event handling of GUI events.
*

View File

@ -0,0 +1,31 @@
<html>
</head>
<style type="text/css">
.stage{
-moz-perspective: 100px;
-moz-perspective-origin: 30px 30px;
height:100px;
width:100px;
margin:5px;
padding:5px;
border:5px solid gray;
}
.box {
-moz-transform:rotateX(45deg);
height:70px;
width:70px;
background:green;
margin:5px;
padding:5px;
border:5px solid black;
}
</style>
</head>
<body>
<div class="stage">
<div class="box"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<html>
</head>
<style type="text/css">
.stage{
-moz-perspective: 100px;
-moz-perspective-origin: 25% 25%;
height:100px;
width:100px;
margin:5px;
padding:5px;
border:5px solid gray;
}
.box {
-moz-transform:rotateX(45deg);
height:70px;
width:70px;
background:green;
margin:5px;
padding:5px;
border:5px solid black;
}
</style>
</head>
<body>
<div class="stage">
<div class="box"></div>
</div>
</body>
</html>

View File

@ -33,6 +33,7 @@ fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == preserve3d-1a.html preser
== backface-visibility-1b.html about:blank
!= perspective-origin-1a.html rotatex-perspective-1a.html
== perspective-origin-1b.html perspective-origin-1a.html
== perspective-origin-2a.html perspective-origin-2-ref.html
!= sorting-1a.html sorting-1-ref.html
# Parallel planes, different z depth
== sorting-2a.html sorting-2-ref.html