SVG getScreenCTM does not account for CSS transforms

RESOLVED FIXED in Firefox 68

Status

()

defect
RESOLVED FIXED
6 years ago
3 months ago

People

(Reporter: dojo, Assigned: violet.bugreport)

Tracking

27 Branch
mozilla68
x86
macOS
Points:
---

Firefox Tracking Flags

(firefox68 fixed)

Details

Attachments

(2 attachments)

Posted file coords.html
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:27.0) Gecko/20100101 Firefox/27.0 (Beta/Release)
Build ID: 20140127194636

Steps to reproduce:

SVG elements offer the getScreenCTM() function which is documented to return the transformation matrix from user units to the browser's notion of a pixel.  This can be used, for example, when working with coordinates of mouse events.

When SVG elements are contained within HTML elements that have their own CSS transforms specified, the getScreenCTM() does not behave predictably.  Not only do the coordinates no longer transform properly, but the actual matrix returned now varies between browsers.  Without a containing HTML element that has CSS transformations, browsers return the same results.

I believe there is some kind of bug here... so I've created a reduced test case. This file is a reduction from Dungeoneers, an HTML5 game written with a mixture of HTML and SVG.

The test file is linked here - compare the numbers in Firefox and Safari.

http://www.dungeoneers.com/bugs/coords/coords.html



Actual results:

On Firefox 27 and Safari 7, with no CSS transformation applied, the matrix is 0.75; 0; 0; 0.75; 198; 78.  This part is good.
On Firefox 27, with CSS transform applied to the containing field div, the matrix is still 0.75; 0; 0; 0.75; 198; 78 (this seems wrong, it should change.)
On Safari 7, with CSS transform applied, the matrix becomes 0.75; 0; 0; 0.75; 298.625; 169.5.




Expected results:

The bottom line is that getScreenCTM should produce a matrix that maps between SVG coordinate space and mouse space, as specced, regardless of CSS properties on parent html elements.

Note, I'm not sure if Safari's numbers are right or not, but at least they do change in response to external transforms, as would be expected.
Component: Untriaged → SVG
Product: Firefox → Core
I can confirm this occurrence. Safari and Chrome both scale the getScreenCTM() values in accordance with the given (-prefix-)transform: scale(amount); while FireFox does not. On a related note the reason I encountered this to begin with was due to jQuery's offset() returning the wrong value.
This is indeed happening. Here's a Fiddle that demonstrates the issue: http://jsfiddle.net/danschultz/gRTcF/
The "border" of SVG element also seems to make this problem occur.
http://jsfiddle.net/gRTcF/8/
(In reply to AnSeki.aff from comment #3)
> The "border" of SVG element also seems to make this problem occur.
> http://jsfiddle.net/gRTcF/8/

Probably worth raising that as a separate bug.
Yes, I think that `border` differs from `transform`. But I found that `transform` of SVG element also makes this problem occur. And `padding` too.

- http://jsfiddle.net/3v4e0Lnx/
- http://jsfiddle.net/ehy1zkL6/

These may be related, getScreenCTM seems to ignore some CSS properties that changes position.

CSS properties below didn't make this problem:
- `margin`
- `position: absolute`, `left` and `top`
- `overflow: auto` (or `hidden`) of parent and scrolled SVG element
- negative margin
- `padding` of parent
Please make these comments in a new bug. This one is about transform.
Ok, I'm sorry that I didn't understand the rule.
Summary: SVG getScreenCTM inconsistent when parent div has CSS transform → SVG getScreenCTM does not account for CSS transforms
I know this bug report is old but it's still not fixed.
https://github.com/d3/d3/issues/2771
We have the same problem in svg.js. All svg libraries kinda depend on this.

I also think that the webkit behavior is incorrect, too.
A rotate or skew of the html element should not only result in `e` and `f` changing.
Assignee: nobody → violet.bugreport
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
See Also: → 1073207

Robert, do you know what is the correct behavior of getCTM() for element inside a display:none?

For example:

<svg id="svg" width="300" height="300">
  <g style="display:none">
    <rect transform="scale(3,3)" id="rec" width="10" height="10"/>
  </g>
</svg>

What should be the return of rec.getCTM()?

The spec says https://svgwg.org/svg2-draft/types.html#__svg__SVGGraphicsElement__getCTM:

If the current element is a non-rendered element, and the UA is not able to resolve the style of the element, then return null.

I'm not sure what the second half means.

FYI, our transform code heavily relies on the present of a frame, but display:none subtree has no frame. It'd be quite awkward if we need to return the CSS matrix for display:none.

Chrome return CSS matrix for element inside display:none subtree but itself not being display:none.

Flags: needinfo?(longsonr)

We've always basically given up with DOM methods in the face of display:none. bug 376027 covers trying to change that but it's rather hard given you can have a display:none container containing SVG content.

Flags: needinfo?(longsonr)

We use nsSVGUtils::GetTransformMatrixInUserSpace to support
CSS transform in getCTM.

Pushed by violet.bugreport@gmail.com:
https://hg.mozilla.org/integration/autoland/rev/bbd172d048d7
getCTM should account for CSS transform r=longsonr
Status: ASSIGNED → RESOLVED
Closed: 3 months ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla68
You need to log in before you can comment on or make changes to this bug.