Last Comment Bug 626359 - Expose functionality to retrieve detailed post-transform geometry
: Expose functionality to retrieve detailed post-transform geometry
Status: RESOLVED FIXED
:
Product: Core
Classification: Components
Component: DOM: CSS Object Model (show other bugs)
: Trunk
: All All
: -- enhancement with 2 votes (vote)
: ---
Assigned To: Nobody; OK to take it and work on it
:
Mentors:
: 684869 (view as bug list)
Depends on:
Blocks: 714738
  Show dependency treegraph
 
Reported: 2011-01-17 02:29 PST by Sebastian Zartner
Modified: 2016-02-29 22:37 PST (History)
22 users (show)
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments

Description Sebastian Zartner 2011-01-17 02:29:57 PST
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.
Comment 1 Boris Zbarsky [:bz] 2011-01-17 07:32:29 PST
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.
Comment 2 Michael Ratcliffe [:miker] [:mratcliffe] 2011-01-17 12:49:59 PST
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.
Comment 3 Boris Zbarsky [:bz] 2011-01-17 13:22:15 PST
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.
Comment 4 Sebastian Zartner 2011-01-19 15:00:53 PST
> 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.
Comment 5 Boris Zbarsky [:bz] 2011-01-19 18:48:31 PST
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?
Comment 6 Sebastian Zartner 2011-01-19 23:53:55 PST
> 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°).
Comment 7 Boris Zbarsky [:bz] 2011-01-20 06:34:20 PST
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?
Comment 8 Michael Ratcliffe [:miker] [:mratcliffe] 2011-01-20 08:09:01 PST
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.
Comment 9 Boris Zbarsky [:bz] 2011-01-20 08:24:30 PST
> 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?
Comment 10 Boris Zbarsky [:bz] 2011-01-20 08:25:16 PST
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...
Comment 11 Michael Ratcliffe [:miker] [:mratcliffe] 2011-01-20 09:05:27 PST
>> 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.
Comment 12 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2011-01-23 14:28:45 PST
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.
Comment 13 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2011-01-23 14:30:52 PST
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).
Comment 14 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2011-01-23 14:52:58 PST
See also https://bugs.webkit.org/show_bug.cgi?id=29795. Sam Weinig seemed OK with the suggestion in comment #12.
Comment 15 Michael Ratcliffe [:miker] [:mratcliffe] 2011-01-23 14:59:55 PST
Sounds perfect to me, especially if it will be implemented the same way on webkit.
Comment 16 Sebastian Zartner 2011-01-24 02:20:37 PST
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.
Comment 17 Michael Ratcliffe [:miker] [:mratcliffe] 2011-01-25 04:20:44 PST
Would it not make more sense to call this method element.getClientQuads() the same as webkit?
Comment 18 Boris Zbarsky [:bz] 2011-01-25 09:30:27 PST
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?
Comment 19 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2011-01-25 12:01:02 PST
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.
Comment 20 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2011-09-06 17:44:17 PDT
*** Bug 684869 has been marked as a duplicate of this bug. ***
Comment 21 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2011-09-06 17:55:40 PDT
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.
Comment 22 :Aryeh Gregor (away until August 15) 2012-02-14 10:36:05 PST
(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.
Comment 23 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2012-02-14 19:32:06 PST
I don't think we should complicate the API just to handle that case.
Comment 24 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2016-02-29 15:48:25 PST
This got fixed via getBoxQuads.
Comment 25 Sebastian Zartner [:sebo] 2016-02-29 22:37:37 PST
You're right, thanks! Unfortunately they are still not enabled by default yet. For reference, that's tracked in bug 1107559.

Sebastian

Note You need to log in before you can comment on or make changes to this bug.