Title: [105296] trunk
Revision
105296
Author
[email protected]
Date
2012-01-18 10:49:51 -0800 (Wed, 18 Jan 2012)

Log Message

[CG] Rasterized scaling of transformed SVG shapes with gradient fill and -webkit-svg-shadow applied
https://bugs.webkit.org/show_bug.cgi?id=76482
<rdar://problem/10415483>

Reviewed by Simon Fraser.

Scale the CGLayer used when filling or stroking a shadowed path or rect with
a gradient in GraphicsContextCG. Previously, the CGLayer was created and rendered
into at the untransformed size of the shape, leading to pixelation when it was
then scaled up and drawn into the destination.

Add AffineTransform::mapSize() to map a size through a transformation.

Test: svg/custom/transform-with-shadow-and-gradient.svg

* platform/graphics/cg/GraphicsContextCG.cpp:
(WebCore::GraphicsContext::fillPath):
(WebCore::GraphicsContext::strokePath):
(WebCore::GraphicsContext::fillRect):
(WebCore::GraphicsContext::strokeRect):
* platform/graphics/transforms/AffineTransform.cpp:
(WebCore::AffineTransform::mapSize): Added.
* platform/graphics/transforms/AffineTransform.h:

Add a test that ensures that SVG shapes are drawn crisply when transformed
if they have both a gradient fill and -webkit-svg-shadow applied.

* platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.png: Added.
* platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.txt: Added.
* svg/custom/transform-with-shadow-and-gradient.svg: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (105295 => 105296)


--- trunk/LayoutTests/ChangeLog	2012-01-18 18:46:41 UTC (rev 105295)
+++ trunk/LayoutTests/ChangeLog	2012-01-18 18:49:51 UTC (rev 105296)
@@ -1,3 +1,18 @@
+2012-01-18  Tim Horton  <[email protected]>
+
+        [CG] Rasterized scaling of transformed SVG shapes with gradient fill and -webkit-svg-shadow applied
+        https://bugs.webkit.org/show_bug.cgi?id=76482
+        <rdar://problem/10415483>
+
+        Reviewed by Simon Fraser.
+
+        Add a test that ensures that SVG shapes are drawn crisply when transformed
+        if they have both a gradient fill and -webkit-svg-shadow applied.
+
+        * platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.png: Added.
+        * platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.txt: Added.
+        * svg/custom/transform-with-shadow-and-gradient.svg: Added.
+
 2012-01-18  Dominic Mazzoni  <[email protected]>
 
         Accessibility: Chromium needs methods to scroll an object into view or to a specific location.

Added: trunk/LayoutTests/platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.png


(Binary files differ)
Property changes on: trunk/LayoutTests/platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.png ___________________________________________________________________

Added: svn:mime-type

Added: trunk/LayoutTests/platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.txt (0 => 105296)


--- trunk/LayoutTests/platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac/svg/custom/transform-with-shadow-and-gradient-expected.txt	2012-01-18 18:49:51 UTC (rev 105296)
@@ -0,0 +1,12 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderSVGRoot {svg} at (18,16) size 542x544
+    RenderSVGHiddenContainer {defs} at (0,0) size 0x0
+      RenderSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
+        RenderSVGGradientStop {stop} [offset=0.00] [color=#0000FF]
+        RenderSVGGradientStop {stop} [offset=1.00] [color=#008000]
+    RenderSVGPath {circle} at (20,20) size 176x176 [transform={m=((4.00,0.00)(0.00,4.00)) t=(0.00,0.00)}] [fill={[type=LINEAR-GRADIENT] [id="gradient"]}] [cx=25.00] [cy=25.00] [r=20.00]
+    RenderSVGRect {rect} at (320,16) size 288x288 [transform={m=((32.00,0.00)(0.00,32.00)) t=(0.00,0.00)}] [fill={[type=LINEAR-GRADIENT] [id="gradient"]}] [x=10.00] [y=0.50] [width=5.00] [height=5.00]
+    RenderSVGPath {circle} at (18,318) size 180x180 [transform={m=((4.00,0.00)(0.00,4.00)) t=(0.00,0.00)}] [stroke={[type=LINEAR-GRADIENT] [id="gradient"]}] [fill={[type=SOLID] [color=#00000000]}] [cx=25.00] [cy=100.00] [r=20.00]
+    RenderSVGRect {rect} at (304,304) size 320x296 [transform={m=((32.00,0.00)(0.00,32.00)) t=(0.00,0.00)}] [stroke={[type=LINEAR-GRADIENT] [id="gradient"]}] [fill={[type=SOLID] [color=#00000000]}] [x=10.00] [y=10.00] [width=5.00] [height=5.00]

Added: trunk/LayoutTests/svg/custom/transform-with-shadow-and-gradient.svg (0 => 105296)


--- trunk/LayoutTests/svg/custom/transform-with-shadow-and-gradient.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/custom/transform-with-shadow-and-gradient.svg	2012-01-18 18:49:51 UTC (rev 105296)
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+    <title>None of the shapes should be pixelated, even when zoomed.</title>
+    <defs>
+        <linearGradient id="gradient">
+            <stop offset="0%" stop-color="blue"></stop>
+            <stop offset="100%" stop-color="green"></stop>
+        </linearGradient>
+    </defs>
+    <circle transform="scale(4,4)" style="-webkit-svg-shadow: black 1px 1px 1px;" fill="url(#gradient)" cx="25" cy="25" r="20"></circle>
+    <rect transform="scale(32,32)" style="-webkit-svg-shadow: black 1px 1px 1px;" fill="url(#gradient)" x="10" y="0.5" width="5" height="5"></rect>
+    <circle transform="scale(4,4)" style="-webkit-svg-shadow: black 1px 1px 1px;" stroke="url(#gradient)" fill="transparent" cx="25" cy="100" r="20"></circle>
+    <rect transform="scale(32,32)" style="-webkit-svg-shadow: black 1px 1px 1px;" stroke="url(#gradient)" fill="transparent" x="10" y="10" width="5" height="5"></rect>
+</svg>

Modified: trunk/Source/WebCore/ChangeLog (105295 => 105296)


--- trunk/Source/WebCore/ChangeLog	2012-01-18 18:46:41 UTC (rev 105295)
+++ trunk/Source/WebCore/ChangeLog	2012-01-18 18:49:51 UTC (rev 105296)
@@ -1,3 +1,29 @@
+2012-01-18  Tim Horton  <[email protected]>
+
+        [CG] Rasterized scaling of transformed SVG shapes with gradient fill and -webkit-svg-shadow applied
+        https://bugs.webkit.org/show_bug.cgi?id=76482
+        <rdar://problem/10415483>
+
+        Reviewed by Simon Fraser.
+
+        Scale the CGLayer used when filling or stroking a shadowed path or rect with
+        a gradient in GraphicsContextCG. Previously, the CGLayer was created and rendered
+        into at the untransformed size of the shape, leading to pixelation when it was
+        then scaled up and drawn into the destination.
+
+        Add AffineTransform::mapSize() to map a size through a transformation.
+
+        Test: svg/custom/transform-with-shadow-and-gradient.svg
+
+        * platform/graphics/cg/GraphicsContextCG.cpp:
+        (WebCore::GraphicsContext::fillPath):
+        (WebCore::GraphicsContext::strokePath):
+        (WebCore::GraphicsContext::fillRect):
+        (WebCore::GraphicsContext::strokeRect):
+        * platform/graphics/transforms/AffineTransform.cpp:
+        (WebCore::AffineTransform::mapSize): Added.
+        * platform/graphics/transforms/AffineTransform.h:
+
 2012-01-18  Dominic Mazzoni  <[email protected]>
 
         Accessibility: Chromium needs methods to scroll an object into view or to a specific location.

Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp (105295 => 105296)


--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2012-01-18 18:46:41 UTC (rev 105295)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2012-01-18 18:49:51 UTC (rev 105296)
@@ -630,9 +630,12 @@
     if (m_state.fillGradient) {
         if (hasShadow()) {
             FloatRect rect = path.fastBoundingRect();
-            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0);
+            FloatSize layerSize = getCTM().mapSize(rect.size());
+
+            CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0);
             CGContextRef layerContext = CGLayerGetContext(layer);
 
+            CGContextScaleCTM(layerContext, layerSize.width() / rect.width(), layerSize.height() / rect.height());
             CGContextTranslateCTM(layerContext, -rect.x(), -rect.y());
             CGContextBeginPath(layerContext);
             CGContextAddPath(layerContext, path.platformPath());
@@ -644,7 +647,7 @@
                 CGContextClip(layerContext);
 
             m_state.fillGradient->paint(layerContext);
-            CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer);
+            CGContextDrawLayerInRect(context, rect, layer);
             CGLayerRelease(layer);
         } else {
             CGContextBeginPath(context);
@@ -687,10 +690,12 @@
             FloatRect rect = path.fastBoundingRect();
             float lineWidth = strokeThickness();
             float doubleLineWidth = lineWidth * 2;
-            float layerWidth = ceilf(rect.width() + doubleLineWidth);
-            float layerHeight = ceilf(rect.height() + doubleLineWidth);
+            float adjustedWidth = ceilf(rect.width() + doubleLineWidth);
+            float adjustedHeight = ceilf(rect.height() + doubleLineWidth);
 
-            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0);
+            FloatSize layerSize = getCTM().mapSize(FloatSize(adjustedWidth, adjustedHeight));
+
+            CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0);
             CGContextRef layerContext = CGLayerGetContext(layer);
             CGContextSetLineWidth(layerContext, lineWidth);
 
@@ -699,6 +704,7 @@
             // the layer on the left and top sides.
             float translationX = lineWidth - rect.x();
             float translationY = lineWidth - rect.y();
+            CGContextScaleCTM(layerContext, layerSize.width() / adjustedWidth, layerSize.height() / adjustedHeight);
             CGContextTranslateCTM(layerContext, translationX, translationY);
 
             CGContextAddPath(layerContext, path.platformPath());
@@ -709,7 +715,7 @@
 
             float destinationX = roundf(rect.x() - lineWidth);
             float destinationY = roundf(rect.y() - lineWidth);
-            CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer);
+            CGContextDrawLayerInRect(context, CGRectMake(destinationX, destinationY, adjustedWidth, adjustedHeight), layer);
             CGLayerRelease(layer);
         } else {
             CGContextSaveGState(context);
@@ -747,16 +753,19 @@
     if (m_state.fillGradient) {
         CGContextSaveGState(context);
         if (hasShadow()) {
-            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0);
+            FloatSize layerSize = getCTM().mapSize(rect.size());
+
+            CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0);
             CGContextRef layerContext = CGLayerGetContext(layer);
 
+            CGContextScaleCTM(layerContext, layerSize.width() / rect.width(), layerSize.height() / rect.height());
             CGContextTranslateCTM(layerContext, -rect.x(), -rect.y());
             CGContextAddRect(layerContext, rect);
             CGContextClip(layerContext);
 
             CGContextConcatCTM(layerContext, m_state.fillGradient->gradientSpaceTransform());
             m_state.fillGradient->paint(layerContext);
-            CGContextDrawLayerAtPoint(context, CGPointMake(rect.x(), rect.y()), layer);
+            CGContextDrawLayerInRect(context, rect, layer);
             CGLayerRelease(layer);
         } else {
             CGContextClipToRect(context, rect);
@@ -1088,10 +1097,12 @@
     if (m_state.strokeGradient) {
         if (hasShadow()) {
             const float doubleLineWidth = lineWidth * 2;
-            const float layerWidth = ceilf(rect.width() + doubleLineWidth);
-            const float layerHeight = ceilf(rect.height() + doubleLineWidth);
-            CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(layerWidth, layerHeight), 0);
+            float adjustedWidth = ceilf(rect.width() + doubleLineWidth);
+            float adjustedHeight = ceilf(rect.height() + doubleLineWidth);
+            FloatSize layerSize = getCTM().mapSize(FloatSize(adjustedWidth, adjustedHeight));
 
+            CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0);
+
             CGContextRef layerContext = CGLayerGetContext(layer);
             m_state.strokeThickness = lineWidth;
             CGContextSetLineWidth(layerContext, lineWidth);
@@ -1101,6 +1112,7 @@
             // the layer on the left and top sides.
             const float translationX = lineWidth - rect.x();
             const float translationY = lineWidth - rect.y();
+            CGContextScaleCTM(layerContext, layerSize.width() / adjustedWidth, layerSize.height() / adjustedHeight);
             CGContextTranslateCTM(layerContext, translationX, translationY);
 
             CGContextAddRect(layerContext, rect);
@@ -1111,7 +1123,7 @@
 
             const float destinationX = roundf(rect.x() - lineWidth);
             const float destinationY = roundf(rect.y() - lineWidth);
-            CGContextDrawLayerAtPoint(context, CGPointMake(destinationX, destinationY), layer);
+            CGContextDrawLayerInRect(context, CGRectMake(destinationX, destinationY, adjustedWidth, adjustedHeight), layer);
             CGLayerRelease(layer);
         } else {
             CGContextSaveGState(context);

Modified: trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp (105295 => 105296)


--- trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp	2012-01-18 18:46:41 UTC (rev 105295)
+++ trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp	2012-01-18 18:49:51 UTC (rev 105296)
@@ -250,6 +250,22 @@
     return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
 }
 
+IntSize AffineTransform::mapSize(const IntSize& size) const
+{
+    double width2 = size.width() * xScale();
+    double height2 = size.height() * yScale();
+
+    return IntSize(lround(width2), lround(height2));
+}
+
+FloatSize AffineTransform::mapSize(const FloatSize& size) const
+{
+    double width2 = size.width() * xScale();
+    double height2 = size.height() * yScale();
+
+    return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2));
+}
+
 IntRect AffineTransform::mapRect(const IntRect &rect) const
 {
     return enclosingIntRect(mapRect(FloatRect(rect)));

Modified: trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.h (105295 => 105296)


--- trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.h	2012-01-18 18:46:41 UTC (rev 105295)
+++ trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.h	2012-01-18 18:49:51 UTC (rev 105296)
@@ -76,6 +76,10 @@
 
     FloatPoint mapPoint(const FloatPoint&) const;
 
+    IntSize mapSize(const IntSize&) const;
+
+    FloatSize mapSize(const FloatSize&) const;
+
     // Rounds the resulting mapped rectangle out. This is helpful for bounding
     // box computations but may not be what is wanted in other contexts.
     IntRect mapRect(const IntRect&) const;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to