Closed Bug 721082 Opened 12 years ago Closed 12 years ago

Percentages in -moz-perspective-origin aren't relative to element's border box

Categories

(Core :: Layout, defect)

x86
Linux
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla13

People

(Reporter: ayg, Assigned: mattwoodrow)

References

Details

Attachments

(2 files, 1 obsolete file)

These two look identical in Firefox 12.0a1 (2012-01-24), where the only difference is the value of -moz-perspective-origin:

data:text/html,<!DOCTYPE html>
<div style="-moz-perspective:100px;
-moz-perspective-origin:25% 25%;
height:100px;width:100px">
<div style="height:70px;width:70px;background:green;
margin:5px;padding:5px;border:5px solid black;
-moz-transform:rotateX(45deg)"></div>
</div>

data:text/html,<!DOCTYPE html>
<div style="-moz-perspective:100px;
-moz-perspective-origin:22.5px 22.5px;
height:100px;width:100px">
<div style="height:70px;width:70px;background:green;
margin:5px;padding:5px;border:5px solid black;
-moz-transform:rotateX(45deg)"></div>
</div>

This means 25% somehow evaluates to 22.5px here.  The only way I can see that happening is if it's evaluated relative to the *child's* border box, since that's the only thing that's 90px tall/wide.  This is unexpected -- I'd expect it to evaluate relative to the border box of the element itself, like transform-origin.

I was not able to test what IE10 or WebKit does.  The spec currently says:

"Percentages:	 refer to the size of the elemen's box"
http://dev.w3.org/csswg/css3-3d-transforms/#perspective-origin-property

It doesn't say whether it's the element's content, padding, border, or margin box.  Probably the intent is border box (https://www.w3.org/Bugs/Public/show_bug.cgi?id=15708).  But it should be relative to *some* box of the element it's specified on, not a box of its child.

Is there a reason for this behavior, or is it just a bug?
I was finally able to test in Chrome 17 dev, and it looks identical in that test-case if I give 25px, not 22.5px.  If I modify the test-case to add some margin/border/padding to the outer box too

data:text/html,<!DOCTYPE html>
<div style="-webkit-perspective:100px;
-webkit-perspective-origin:25% 25%;
height:100px;width:100px;
margin:5px;padding:5px;
border:5px solid gray">
<div style="height:70px;width:70px;background:green;
margin:5px;padding:5px;border:5px solid black;
-webkit-transform:rotateX(45deg)"></div>
</div>

it looks the same in WebKit if I replace "25%" with "30px", so it is indeed relative to the border box of the element that perspective-origin is specified on.
Well, that was an adventure :)
Attachment #595580 - Flags: review?(roc)
Comment on attachment 595580 [details] [diff] [review]
Make perspective origin use the parents border box

Review of attachment 595580 [details] [diff] [review]:
-----------------------------------------------------------------

A separate patch for constifying GetParentStyleContextFrame would be good.

::: layout/generic/nsFrame.cpp
@@ +976,5 @@
>  }
>  
> +bool
> +nsIFrame::HasPerspective() const
> +{

Can we check IsTransformed here?

@@ +6763,5 @@
>      }
>      if (Preserves3DChildren()) {
>        ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
> +    } else if (HasPerspective()) {
> +      RecomputePerspectiveChildrenOverflow(this, &newBounds);

Could we fold RecomputePerspectiveChildrenOverflow into ComputePreserve3DChildrenOverflow?
I get a segfault at this line

-                         nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
+                         nsDisplayTransform::GetFrameBoundsForTransform(aFrame->GetParentStyleContextFrame()));

when loading this: data:text/html,<html style=-moz-transform:scale(-1)>
Attachment #595580 - Attachment is obsolete: true
Attachment #595580 - Flags: review?(roc)
Attachment #595868 - Flags: review?(roc)
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #3)
> Can we check IsTransformed here?

Definitely.

> 
> @@ +6763,5 @@
> >      }
> >      if (Preserves3DChildren()) {
> >        ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
> > +    } else if (HasPerspective()) {
> > +      RecomputePerspectiveChildrenOverflow(this, &newBounds);
> 
> Could we fold RecomputePerspectiveChildrenOverflow into
> ComputePreserve3DChildrenOverflow?

I can't see an easy way to do this. All 3 (includes RecomputePreserve3DChildrenOverflow) loop over the child frames, but they take different actions and have different termination conditions. It would be a fairly complex set of flags passed in to handle all the cases within a single loop.
Attachment #595869 - Flags: review?(roc)
(In reply to Aryeh Gregor from comment #4)
> I get a segfault at this line
> 
> -                        
> nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
> +                        
> nsDisplayTransform::GetFrameBoundsForTransform(aFrame-
> >GetParentStyleContextFrame()));
> 
> when loading this: data:text/html,<html style=-moz-transform:scale(-1)>

Er yeah, that needs a null check.
Fixed that already, moved calculation of the perspective origin offset so that it only runs when we have perspective.
https://hg.mozilla.org/mozilla-central/rev/1158b09686b7
https://hg.mozilla.org/mozilla-central/rev/b736157e56f6
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla13
Blocks: 731777
Depends on: 729955
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: