Commit 56ca23de authored by fmalita@chromium.org's avatar fmalita@chromium.org

[SVG] Incorrect transform-origin under zoom.

The current SVGGraphicsElement::animatedLocalTransform() tries to work
around pre-scaled CSS length values but it doesn't handle percentage
transform-origin properties correctly: the bounding box used in the CSS
transform calculation is not scaled the same way as the other lengths.

The CL addresses this case and also refactors the workaround: instead of
post-tweaking the translation components directly, compute the CSS
transform under an effective 1.0 zoom factor (as expected under SVG).

BUG=375664
R=ed@opera.com,fs@opera.com

Review URL: https://codereview.chromium.org/305603002

git-svn-id: svn://svn.chromium.org/blink/trunk@174907 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 6e7b8cc9
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" style="zoom: 2">
<rect x="100" y="100" width="100" height="100" fill="green" transform="rotate(45, 150, 150)"/>
<rect x="300" y="100" width="100" height="100" fill="green" transform="rotate(45, 350, 150)"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" style="zoom: 2">
<!-- Test for http://crbug.com/375664 -->
<rect x="101" y="101" width="98" height="98" fill="red" transform="rotate(45, 150, 150)"/>
<rect x="100" y="100" width="100" height="100" fill="green" style="
transform-origin: 150px 150px;
transform: rotate(45deg);
"/>
<rect x="301" y="101" width="98" height="98" fill="red" transform="rotate(45, 350, 150)"/>
<rect x="300" y="100" width="100" height="100" fill="green" style="
transform-origin: 50% 50%;
transform: rotate(45deg);
"/>
</svg>
......@@ -129,21 +129,29 @@ AffineTransform SVGGraphicsElement::animatedLocalTransform() const
// If CSS property was set, use that, otherwise fallback to attribute (if set).
if (style && style->hasTransform()) {
TransformationMatrix transform;
float zoom = style->effectiveZoom();
// CSS transforms operate with pre-scaled lengths. To make this work with SVG
// (which applies the zoom factor globally, at the root level) we
//
// * pre-scale the bounding box (to bring it into the same space as the other CSS values)
// * invert the zoom factor (to effectively compute the CSS transform under a 1.0 zoom)
//
// Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath.
// See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/
TransformationMatrix transform;
style->applyTransform(transform, renderer()->objectBoundingBox());
if (zoom != 1) {
FloatRect scaledBBox = renderer()->objectBoundingBox();
scaledBBox.scale(zoom);
transform.scale(1 / zoom);
style->applyTransform(transform, scaledBBox);
transform.scale(zoom);
} else {
style->applyTransform(transform, renderer()->objectBoundingBox());
}
// Flatten any 3D transform.
matrix = transform.toAffineTransform();
// CSS bakes the zoom factor into lengths, including translation components.
// In order to align CSS & SVG transforms, we need to invert this operation.
float zoom = style->effectiveZoom();
if (zoom != 1) {
matrix.setE(matrix.e() / zoom);
matrix.setF(matrix.f() / zoom);
}
} else {
m_transform->currentValue()->concatenate(matrix);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment