Closed Bug 626359 Opened 13 years ago Closed 8 years ago

Expose functionality to retrieve detailed post-transform geometry

Categories

(Core :: DOM: CSS Object Model, enhancement)

enhancement
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: sebo, Unassigned)

References

(Blocks 1 open bug)

Details

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 6.1; en; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13
Build Identifier: 

getComputedStyle() gives you the possibility to get the currently computed value of a CSS property.
Unfortunately in some cases this value is sometimes not what is needed in order to determine the actual value of a property.
The W3C already defines four stages of values at http://www.w3.org/TR/CSS2/cascade.html#value-stages .
Considering that value stage definitions I'd expect two functions exposing the used and actual value of a property.
According to the currently defined getComputedStyle() these functions should be called getUsedStyle() and getActualStyle().

Reproducible: Always




One use case for this is the Firebug Inspector, which is currently not able to mark transformed elements correctly.
See therefore http://code.google.com/p/fbug/issues/detail?id=2273
A test case for this is attached there.
getComputedStyle actually returns the CSS2 computed value, which is a weird mix of CSS2.1 computed and used values.

But it's not clear to me why this affects Firebug's inspector.  Isn't the issue it's having more a matter of transforms not affecting getBoundingClientRect?

In any case, there have been some proposals for this on www-style...  I do think we should consider implementing something here; the question is what.
From Firebugs perspective our highlighter needs to be able to match the same shape and position as any element under it and there is currently no way to do that for hierarchical css transforms because each ancestor can have a different transform origin.

In my eyes the ideal solution would be use a layer to display some kind of customizeable highlighting over a page element in XUL. We would also need the ability to display the elements's box model. Anything in that direction would be great but I am not sure how workable it would be.
It's not clear what "box model" even means in the case of transforms... ;)

You may be interested in the discussion in bug 591718.  If you have some ideas of the sort of API that would help you, putting those in that bug or here would be good.
> But it's not clear to me why this affects Firebug's inspector.  Isn't the issue
> it's having more a matter of transforms not affecting getBoundingClientRect?

That describes another issue. Mike already explained our problem, but here's a more detailed description of the current problem we are facing:
For the inspector frame we could achieve the transformations of the underlying element by adding all transformations done to the element itself plus each transformation done to its ancestors. So this means reading all the related -moz-transform values and applying them to the inspector div. Though -moz-transform-origin can just hold one origin and not several ones for different transformations.
That's why I thought of being able to get the actual value of these properties would be useful here.

This is just one example of a use case. There were already several occasions, in which the computed value was not really helpful to me.

Simple example:
Execute "window.getComputedStyle(document.getElementById('comment_text_3'), '').left" on this issue's page. You'll get "auto". Wouldn't it be useful to be able to get the actual value here?

See also bug 473576 and bug 573967 for related test cases, in which getActualStyle() (and getUsedStyle()) would be useful.
I think you misunderstand how used and actual values work...

The actual value of transform is not the composition of all ancestor transforms.  

The actual value of "left" for the element you mention is in fact "auto".

So again, what are you _really_ trying to do?  For Firebug, it sounds like you need to get the actual geometry of the element on the page (which in the general case is a set of parallelograms), right?
> I think you misunderstand how used and actual values work...

From the specification for used values:
"For example, if the width of an element is set to be a certain percentage of its containing block, the width cannot be determined until the width of the containing block has been determined. The used value is the result of taking the computed value and resolving any remaining dependencies into an absolute value."

I read "absolute value", which in my understanding is not "auto" for numeric values, but a value with an absolute unit.

The "actual value" then is what the user agent actually uses. So the user agent can still overwrite these calculations with another value. In the case of bug 573967 this would be the minimum font size specified in the browser settings. In the words of the specification it is "the used value after any approximations have been applied."

> So again, what are you _really_ trying to do?  For Firebug, it sounds like 
> you need to get the actual geometry of the element on the page (which in the
> general case is a set of parallelograms), right?

Right. That's why my initial thought was, that used and actual values would represent these (of course they would). Though thinking about it again, this even isn't necessary in this case. What should actually be done is the following:
Change "MozTransform" and "MozTransformOrigin" returned by getComputedStyle() to really contain the _computed_ value. Currently it is actually just containing the _specified_ value.
Example: You specify for the parent element width = 1000px and -moz-transform = rotate(60deg) and for the element you want to get the computed values for width = 60% and -moz-transform = rotate(30deg) (margin and padding for both = 0). When you now call getComputedStyle() for the element, the width will be 600px, but MozTransform will give you matrix(0.866025, 0.5, -0.5, 0.866025, 0px, 0px), which is equal to a rotation by 30° instead of matrix(0, 1, -1, 0, 0px, 0px) (=90°).
What you quote is correct for the 'width' property.  But for 'left', it's not even looked at unless the element is positioned, so there is no meaningful "used" value of left for non-positioned elements.

> Change "MozTransform" and "MozTransformOrigin" returned by getComputedStyle()
> to really contain the _computed_ value.

It does!  At http://www.w3.org/TR/css3-2d-transforms/#transform-property we have:

  Computed value: 	Same as specified value. 

and at http://www.w3.org/TR/css3-2d-transforms/#transform-origin we have:

  Computed value: 	For <length> the absolute value, otherwise a percentage 

That's what we return from computed style.  In particular, in CSS2.1 and later computed values NEVER depend on the layout.

What you seem to want here is the used value of transform/transform-origin.  But again, I'm not clear on why you want it.  Don't you _really_ want something like getClientRects() but returning a list of parallelograms in client coordinates?  Or am I totally missing something?
The mathematics of transformations becomes complex when parents have transform origins that are not 50% 50% and this then becomes much more complex when you consider that each transformed child element can be offset within it's transformed parent.

What Sebastian is asking for is that the MozTransform and MozTransformOrigin for an element that also has ancestors that have been transformed and may be offset (both using a transformed offset and are possibly relatively positioned from their transformed parents, affecting the final transform) will return a value that will ultimately produce the same transform when applied to an element outside of the documents flow.

Although this is probably what users would expect from getComputedStyle of transformed elements I am not sure that it is what we actually need for Firebug's inspector. In my eyes Boris really hit the nail on the head in Comment 1 ... getBoundingClientRect does not take rotation, skew, scale etc. into account. If it did we could get the inspector to work with them without any problems.
> The mathematics of transformations becomes complex when parents have transform
> origins that are not 50% 50%

Do they?  They're still affine transforms representable by a 6-element matrix (in the 2d case).  In any case, why is that relevant?

> will return a value that will ultimately produce the same transform when
> applied to an element outside of the documents flow.

So you just want to know the overall transformation matrix.  That's fine, and could be done, but it's not any of the used/actual/etc CSS values.  SVG explicitly exposes the CTM; we could do the same for other cases.

But again, it seems like you don't want the transformation matrix; you want the set of parallelograms and you want a way to "highlight" a particular parallelogram (that is, style an element so its box matches that parallelogram), right?
roc, how do you feel about adding a getClientParallelograms method?  And would that play ok with 3d transforms?  I haven't looked at that much yet...
>> The mathematics of transformations becomes complex when parents have transform
>> origins that are not 50% 50%
>
>Do they?  They're still affine transforms representable by a 6-element matrix
>(in the 2d case).  In any case, why is that relevant?
You are right, it is not relevant from your perspective.

> But again, it seems like you don't want the transformation matrix; you want the
> set of parallelograms and you want a way to "highlight" a particular
> parallelogram (that is, style an element so its box matches that
> parallelogram), right?

Yes, this is exactly what we need. In fact, I would always use getClientParallelograms instead of getBoundingClientRect unless I wanted something specifically related to the elements box model as this is what we are now actually seeing on screen. That is assuming that it would work on all elements.
We want quads (quadrilaterals) here, not parallelograms, to support 3D.

How about element.getQuads(relativeTo), returning a QuadList which is a list of Quads, which contains fields x0,y0,x1,y1,x2,y2,x3,y3? Where each value is in CSS pixels relative to the top-left of the border-box of the first CSS box of relativeTo? If relativeTo has no CSS boxes, return a zero-length list. As for getClientRects, there would be one quad per CSS box for the element.
Summary: Expose functionality to retrieve used and actual CSS property values → Expose functionality to retrieve detailed post-transform geometry
I guess we should also guarantee that the points in the quads correspond to the top-left, top-right, bottom-left and bottom-right corners of the border-box of each CSS box for the element, in that order.

For other use-cases I guess we should have a general transformation method, say element.transformPoint(relativeTo, x, y).
Sounds perfect to me, especially if it will be implemented the same way on webkit.
Also sounds good to me regarding transformations.

It is now far away from my initial thought of exposing used and actual values though. And I still believe, that in some cases (e. g. the issues mentioned in comment #4) these values could be useful.
Would it not make more sense to call this method element.getClientQuads() the same as webkit?
Michael, that's a lot less powerful than roc's proposal.  In particular, while getting relative rects with client rects is easy (just subtract the top/left coordinates of the other thing and you're done) doing the same with quads or even parallelograms is quite difficult (you basically have to solve for the two transformation matrices, then multiply one by the inverse of the other, then apply to you untransformed geometry).  Note also comment 14.

roc, would we want to list the vertices in left-to-right followed by top-to-bottom order as you propose, or in fixed direction (clockwise or counterclockwise) order starting at a particular vertex?  Are there existing conventions for this?
getClientQuads also loses information if the transform to the document root is not invertible. Also, "client" is an unintuitive name when you think about it; we use getClientRects/getBoundingClientRect for legacy reasons.

Anyway, Sam (the author of that not-landed Webkit patch) seemed fine with my suggestsions.

I guess we should start at top-left and go clockwise like CSS borders etc.
Tab wrote a good summary of the issues:
http://lists.w3.org/Archives/Public/www-style/2011May/0395.html
I think the main thing that's missing from my proposal in comment #12 is discriminating between content, border, padding and margin boxes.

So we could make getQuads deal in border-boxes and extend comment #12 with getContentQuads(relativeTo), getPaddingQuads(relativeTo), and getMarginQuads(relativeTo), making them all return coordinates relative to the border-box of relativeTo.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Version: unspecified → Trunk
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #12)
> We want quads (quadrilaterals) here, not parallelograms, to support 3D.

Are quads enough if you have excessively small perspectives?  E.g., if you have

<div style="height:100px;width:100px;background:blue;
-moz-transform:perspective(10px) rotate3d(1,-1,0,45deg)">

the result is . . . interesting.  What would you return for that?  See bug 726766.
I don't think we should complicate the API just to handle that case.
Blocks: 663778
No longer blocks: 663778
This got fixed via getBoxQuads.
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
You're right, thanks! Unfortunately they are still not enabled by default yet. For reference, that's tracked in bug 1107559.

Sebastian
See Also: → 1107559
You need to log in before you can comment on or make changes to this bug.