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
- trunk/LayoutTests/ChangeLog
- trunk/Source/WebCore/ChangeLog
- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
- trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp
- trunk/Source/WebCore/platform/graphics/transforms/AffineTransform.h
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)
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
