SVG Pattern pixelated on inline SVG with CSS transforms
authorfmalita@chromium.org <fmalita@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Mar 2013 14:38:48 +0000 (14:38 +0000)
committerfmalita@chromium.org <fmalita@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Mar 2013 14:38:48 +0000 (14:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=111587

Reviewed by Dirk Schulze.

Source/WebCore:

When calculating the resolution for resource image buffers, we need to also consider CSS
transforms. This patch updates calculateTransformationToOutermostSVGCoordinateSystem()
(renamed to calculateTransformationToOutermostCoordinateSystem) to include the affine
component from CSS transforms by walking the parent layer tree.

Test: svg/custom/resources-css-scaled.html

* rendering/svg/RenderSVGResourceClipper.cpp:
(WebCore::RenderSVGResourceClipper::applyClippingToContext):
* rendering/svg/RenderSVGResourceFilter.cpp:
(WebCore::RenderSVGResourceFilter::applyResource):
* rendering/svg/RenderSVGResourceGradient.cpp:
(WebCore::createMaskAndSwapContextForTextGradient):
(WebCore::clipToTextMask):
* rendering/svg/RenderSVGResourceMasker.cpp:
(WebCore::RenderSVGResourceMasker::applyResource):
* rendering/svg/RenderSVGResourcePattern.cpp:
(WebCore::RenderSVGResourcePattern::buildPattern):
* rendering/svg/SVGRenderingContext.cpp:
(WebCore::SVGRenderingContext::calculateScreenFontSizeScalingFactor):
(WebCore::SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem):
* rendering/svg/SVGRenderingContext.h:
(SVGRenderingContext):

LayoutTests:

* svg/custom/resources-css-scaled-expected.html: Added.
* svg/custom/resources-css-scaled.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@145541 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/svg/custom/resources-css-scaled-expected.html [new file with mode: 0644]
LayoutTests/svg/custom/resources-css-scaled.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
Source/WebCore/rendering/svg/SVGRenderingContext.cpp
Source/WebCore/rendering/svg/SVGRenderingContext.h

index 83fae9b..ad3369c 100644 (file)
@@ -1,3 +1,13 @@
+2013-03-12  Florin Malita  <fmalita@chromium.org>
+
+        SVG Pattern pixelated on inline SVG with CSS transforms
+        https://bugs.webkit.org/show_bug.cgi?id=111587
+
+        Reviewed by Dirk Schulze.
+
+        * svg/custom/resources-css-scaled-expected.html: Added.
+        * svg/custom/resources-css-scaled.html: Added.
+
 2013-03-12  Vsevolod Vlasov  <vsevik@chromium.org>
 
         Web Inspector: ResourceScriptFile diverged state should be correctly reset after debugger reset.
diff --git a/LayoutTests/svg/custom/resources-css-scaled-expected.html b/LayoutTests/svg/custom/resources-css-scaled-expected.html
new file mode 100644 (file)
index 0000000..18f0cfd
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+<div style="position: relative; left: 27px; width: 100px;">
+<div style="width: 50px;">
+  <svg width="600" height="400" xmlns="http://www.w3.org/2000/svg">
+    <defs>
+      <pattern id="pattern" width="100" height="100" patternUnits="userSpaceOnUse">
+        <circle cx="50" cy="50" r="50" fill="green"/>
+      </pattern>
+
+      <mask id="mask">
+        <circle cx="50" cy="50" r="50" fill="white"/>
+      </mask>
+
+      <clipPath id="clip">
+        <circle cx="50" cy="50" r="50"/>
+        <circle cx="50" cy="50" r="50"/>
+      </clipPath>
+
+      <filter id="filter">
+        <feOffset dx="0" dy="0"/>
+      </filter>
+    </defs>
+
+    <circle cx="50" cy="50" r="50" fill="green"/>
+
+    <g transform="translate(300)">
+      <rect width="100" height="100" fill="url(#pattern)"></rect>
+    </g>
+
+    <g transform="translate(150 150)">
+      <rect width="100" height="100" fill="green" mask="url(#mask)"/>
+    </g>
+
+    <g transform="translate(0 300)">
+      <rect width="100" height="100" fill="green" clip-path="url(#clip)"/>
+    </g>
+
+    <g transform="translate(300 300)">
+      <circle cx="50" cy="50" r="50" fill="green" filter="url(#filter)"/>
+    </g>
+  </svg>
+</div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/svg/custom/resources-css-scaled.html b/LayoutTests/svg/custom/resources-css-scaled.html
new file mode 100644 (file)
index 0000000..6cab308
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+<!-- Test for https://bugs.webkit.org/show_bug.cgi?id=111587 -->
+<!-- Passes if all circles are drawn at high resolution, without pixelation -->
+
+<div style="position: relative; left: 27px; -webkit-transform: scale(5); -webkit-transform-origin: 0 0; width: 100px;">
+<div style="-webkit-transform: scale(2); -webkit-transform-origin: 0 0; width: 50px;">
+  <svg width="40" height="40" xmlns="http://www.w3.org/2000/svg">
+    <defs>
+      <pattern id="pattern" width="10" height="10" patternUnits="userSpaceOnUse">
+        <circle cx="5" cy="5" r="5" fill="green"/>
+      </pattern>
+
+      <mask id="mask">
+        <circle cx="5" cy="5" r="5" fill="white"/>
+      </mask>
+
+      <clipPath id="clip">
+        <circle cx="5" cy="5" r="5"/>
+        <!-- multiple shapes to force mask-based clipping -->
+        <circle cx="5" cy="5" r="5"/>
+      </clipPath>
+
+      <filter id="filter">
+        <feOffset dx="0" dy="0"/>
+      </filter>
+    </defs>
+
+    <circle cx="5" cy="5" r="5" fill="green"/>
+
+    <g transform="translate(30)">
+      <rect width="10" height="10" fill="url(#pattern)"></rect>
+    </g>
+
+    <g transform="translate(15 15)">
+      <rect width="10" height="10" fill="green" mask="url(#mask)"/>
+    </g>
+
+    <g transform="translate(0 30)">
+      <rect width="10" height="10" fill="green" clip-path="url(#clip)"/>
+    </g>
+
+    <g transform="translate(30 30)">
+      <circle cx="5" cy="5" r="5" fill="green" filter="url(#filter)"/>
+    </g>
+  </svg>
+</div>
+</div>
+</body>
+</html>
index 95c875b..b516b80 100644 (file)
@@ -1,3 +1,34 @@
+2013-03-12  Florin Malita  <fmalita@chromium.org>
+
+        SVG Pattern pixelated on inline SVG with CSS transforms
+        https://bugs.webkit.org/show_bug.cgi?id=111587
+
+        Reviewed by Dirk Schulze.
+
+        When calculating the resolution for resource image buffers, we need to also consider CSS
+        transforms. This patch updates calculateTransformationToOutermostSVGCoordinateSystem()
+        (renamed to calculateTransformationToOutermostCoordinateSystem) to include the affine
+        component from CSS transforms by walking the parent layer tree.        
+
+        Test: svg/custom/resources-css-scaled.html
+
+        * rendering/svg/RenderSVGResourceClipper.cpp:
+        (WebCore::RenderSVGResourceClipper::applyClippingToContext):
+        * rendering/svg/RenderSVGResourceFilter.cpp:
+        (WebCore::RenderSVGResourceFilter::applyResource):
+        * rendering/svg/RenderSVGResourceGradient.cpp:
+        (WebCore::createMaskAndSwapContextForTextGradient):
+        (WebCore::clipToTextMask):
+        * rendering/svg/RenderSVGResourceMasker.cpp:
+        (WebCore::RenderSVGResourceMasker::applyResource):
+        * rendering/svg/RenderSVGResourcePattern.cpp:
+        (WebCore::RenderSVGResourcePattern::buildPattern):
+        * rendering/svg/SVGRenderingContext.cpp:
+        (WebCore::SVGRenderingContext::calculateScreenFontSizeScalingFactor):
+        (WebCore::SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem):
+        * rendering/svg/SVGRenderingContext.h:
+        (SVGRenderingContext):
+
 2013-03-12  Yury Semikhatsky  <yurys@chromium.org>
 
         Web Inspector: add html canvas memory details to the native memory overview
index 05237cd..8db0d7e 100644 (file)
@@ -169,7 +169,7 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, cons
     }
 
     AffineTransform absoluteTransform;
-    SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+    SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
 
     if (shouldCreateClipData && !repaintRect.isEmpty()) {
         if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, clipperData->clipMaskImage, ColorSpaceDeviceRGB, Unaccelerated))
index d09ef00..8d33720 100644 (file)
@@ -166,7 +166,7 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
 
     // Determine absolute transformation matrix for filter. 
     AffineTransform absoluteTransform;
-    SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+    SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
     if (!absoluteTransform.isInvertible())
         return false;
 
index 32a7290..b80cb52 100644 (file)
@@ -68,7 +68,7 @@ static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& con
     ASSERT(textRootBlock);
 
     AffineTransform absoluteTransform;
-    SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
+    SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(textRootBlock, absoluteTransform);
 
     FloatRect repaintRect = textRootBlock->repaintRectInLocalCoordinates();
     OwnPtr<ImageBuffer> maskImage;
@@ -95,7 +95,7 @@ static inline AffineTransform clipToTextMask(GraphicsContext* context,
     ASSERT(textRootBlock);
 
     AffineTransform absoluteTransform;
-    SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
+    SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(textRootBlock, absoluteTransform);
 
     targetRect = textRootBlock->repaintRectInLocalCoordinates();
     SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, targetRect, imageBuffer, false);
index 03e1901..f3d7128 100644 (file)
@@ -92,7 +92,7 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
     MaskerData* maskerData = m_masker.get(object);
 
     AffineTransform absoluteTransform;
-    SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
+    SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
 
     FloatRect repaintRect = object->repaintRectInLocalCoordinates();
 
index b87ca29..110dce4 100644 (file)
@@ -84,7 +84,7 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign
         return 0;
 
     AffineTransform absoluteTransformIgnoringRotation;
-    SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation);
+    SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransformIgnoringRotation);
 
     // Ignore 2D rotation, as it doesn't affect the size of the tile.
     SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation);
index e275932..e8904c8 100644 (file)
@@ -30,6 +30,7 @@
 #include "BasicShapes.h"
 #include "Frame.h"
 #include "FrameView.h"
+#include "RenderLayer.h"
 #include "RenderSVGResource.h"
 #include "RenderSVGResourceClipper.h"
 #include "RenderSVGResourceFilter.h"
@@ -188,21 +189,34 @@ float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObje
     ASSERT(renderer);
 
     AffineTransform ctm;
-    calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm);
+    calculateTransformationToOutermostCoordinateSystem(renderer, ctm);
     return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2));
 }
 
-void SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform)
+void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform)
 {
-    const RenderObject* current = renderer;
-    ASSERT(current);
-
+    ASSERT(renderer);
     absoluteTransform = currentContentTransformation();
-    while (current) {
-        absoluteTransform = current->localToParentTransform() * absoluteTransform;
-        if (current->isSVGRoot())
+
+    // Walk up the render tree, accumulating SVG transforms.
+    while (renderer) {
+        absoluteTransform = renderer->localToParentTransform() * absoluteTransform;
+        if (renderer->isSVGRoot())
+            break;
+        renderer = renderer->parent();
+    }
+
+    // Continue walking up the layer tree, accumulating CSS transforms.
+    RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
+    while (layer) {
+        if (TransformationMatrix* layerTransform = layer->transform())
+            absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform;
+
+        // We can stop at compositing layers, to match the backing resolution.
+        if (layer->isComposited())
             break;
-        current = current->parent();
+
+        layer = layer->parent();
     }
 }
 
index 4eb9c25..7e16127 100644 (file)
@@ -83,7 +83,7 @@ public:
     static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& targetRect, OwnPtr<ImageBuffer>&, bool safeToClear);
 
     static float calculateScreenFontSizeScalingFactor(const RenderObject*);
-    static void calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform);
+    static void calculateTransformationToOutermostCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform);
     static IntSize clampedAbsoluteSize(const IntSize&);
     static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect);
     static void clear2DRotation(AffineTransform&);