[svg] SVGResources applied to Text with Incorrect Transformations in non-CG Implement...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Jun 2012 12:18:15 +0000 (12:18 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Jun 2012 12:18:15 +0000 (12:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=64966

Patch by Dominik Röttsches <dominik.rottsches@intel.com> on 2012-06-14
Reviewed by Nikolas Zimmermann.

Source/WebCore:

SVGInlineTextBox::paintTextWithShadows for non-CG implementations resets the scale aspect
of the currently applied CTM. This leads to patterns and gradients being incorrectly downscaled.
This way of resetting the CTM and drawing fonts "natively" scaled was introduced
in r77485 to fix a number of issues with SVG font scaling.
Unfortunately, this breaks scaling of patterns and gradients. To fix it,
we need to push the transformation back into the pattern/gradient space transformation.

Tests: svg/transforms/transformed-text-fill-gradient.html
       svg/transforms/transformed-text-fill-pattern.html

* rendering/svg/RenderSVGInlineText.cpp:
(WebCore::RenderSVGInlineText::computeNewScaledFontForStyle): Moving the scaling factor calculation out into SVGRenderingContext.
* rendering/svg/RenderSVGResourceContainer.cpp:
(WebCore::RenderSVGResourceContainer::shouldTransformOnTextPainting): Reusing the scaling factor calculation from SVGRenderingContext.
(WebCore):
* rendering/svg/RenderSVGResourceContainer.h:
(RenderSVGResourceContainer):
* rendering/svg/RenderSVGResourceGradient.cpp:
(WebCore::RenderSVGResourceGradient::applyResource): If needed, push down transformation into gradient space.
* rendering/svg/RenderSVGResourcePattern.cpp:
(WebCore::RenderSVGResourcePattern::applyResource): If needed, push transformation into pattern space.
* rendering/svg/SVGRenderingContext.cpp:
(WebCore::SVGRenderingContext::calculateScreenFontSizeScalingFactor): Common scaling factor calculation for RenderSVGInlineText and RenderSVGResourceContainer.
* rendering/svg/SVGRenderingContext.h:
(SVGRenderingContext):

LayoutTests:

For Pattern: RefTest that compare a scaled rectangle with a scaled block of Ahem characters.
The pattern or gradient should scale in the same way for the text and the rectangle.
This approach needs a clipping path hack to work around micro gaps between Ahem characters
due to rounding.
For Gradient: Scaling text at two different scale factors and adjusting font size to yield the same effective text size.
Gradient fill should be identical in both cases.

* platform/chromium/TestExpectations: Added 3 tests that need rebaselining for text gradient fills.
* svg/transforms/transformed-text-fill-gradient-expected.html: Added.
* svg/transforms/transformed-text-fill-gradient.html: Added.
* svg/transforms/transformed-text-fill-pattern-expected.html: Added.
* svg/transforms/transformed-text-fill-pattern.html: Added.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/TestExpectations
LayoutTests/svg/transforms/transformed-text-fill-gradient-expected.html [new file with mode: 0644]
LayoutTests/svg/transforms/transformed-text-fill-gradient.html [new file with mode: 0644]
LayoutTests/svg/transforms/transformed-text-fill-pattern-expected.html [new file with mode: 0644]
LayoutTests/svg/transforms/transformed-text-fill-pattern.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
Source/WebCore/rendering/svg/RenderSVGResourceContainer.h
Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
Source/WebCore/rendering/svg/SVGRenderingContext.cpp
Source/WebCore/rendering/svg/SVGRenderingContext.h

index a2d0f93..eecfb18 100644 (file)
@@ -1,3 +1,23 @@
+2012-06-14  Dominik Röttsches  <dominik.rottsches@intel.com>
+
+        [svg] SVGResources applied to Text with Incorrect Transformations in non-CG Implementations
+        https://bugs.webkit.org/show_bug.cgi?id=64966
+
+        Reviewed by Nikolas Zimmermann.
+
+        For Pattern: RefTest that compare a scaled rectangle with a scaled block of Ahem characters.
+        The pattern or gradient should scale in the same way for the text and the rectangle.
+        This approach needs a clipping path hack to work around micro gaps between Ahem characters
+        due to rounding.
+        For Gradient: Scaling text at two different scale factors and adjusting font size to yield the same effective text size.
+        Gradient fill should be identical in both cases.
+
+        * platform/chromium/TestExpectations: Added 3 tests that need rebaselining for text gradient fills.
+        * svg/transforms/transformed-text-fill-gradient-expected.html: Added.
+        * svg/transforms/transformed-text-fill-gradient.html: Added.
+        * svg/transforms/transformed-text-fill-pattern-expected.html: Added.
+        * svg/transforms/transformed-text-fill-pattern.html: Added.
+
 2012-06-14  Jan Keromnes  <janx@linux.com>
 
         Web Inspector: Implement ExtensionPanel.show() method
index fe9c9de..15f9779 100644 (file)
@@ -3725,3 +3725,8 @@ BUGWK88833 MAC DEBUG : media/track/track-cues-cuechange.html = PASS TIMEOUT
 BUGWK88832 XP : http/tests/xmlhttprequest/origin-exact-matching.html = PASS TIMEOUT
 
 BUGWK88856 : fast/events/constructors/speech-recognition-event-constructor.html = TEXT
+
+// Need rebaselining because of text gradient fill rendering fix.
+BUGWK64966 : svg/W3C-SVG-1.1/pservers-grad-08-b.svg = IMAGE
+BUGWK64966 : svg/custom/js-late-gradient-and-object-creation.svg = IMAGE
+BUGWK64966 : svg/custom/text-rotated-gradient.svg = IMAGE
\ No newline at end of file
diff --git a/LayoutTests/svg/transforms/transformed-text-fill-gradient-expected.html b/LayoutTests/svg/transforms/transformed-text-fill-gradient-expected.html
new file mode 100644 (file)
index 0000000..91f086b
--- /dev/null
@@ -0,0 +1,14 @@
+<html><body><svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+   <lineargradient x1="0" x2="1" id="gradient">
+     <stop stop-color="#f00" offset="0"></stop>
+     <stop stop-color="#0f0" offset="0.5"></stop>
+     <stop stop-color="#00f" offset="1"></stop>
+   </lineargradient>
+ </defs>
+ <g transform="scale(6)" y="50">
+   <text y="10" font-size="10" fill="url(#gradient)">Text needs to have identical gradient.</text>
+ </g>
+</svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/transformed-text-fill-gradient.html b/LayoutTests/svg/transforms/transformed-text-fill-gradient.html
new file mode 100644 (file)
index 0000000..d965944
--- /dev/null
@@ -0,0 +1,14 @@
+<html><body><svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+   <lineargradient x1="0" x2="1" id="gradient">
+     <stop stop-color="#f00" offset="0"></stop>
+     <stop stop-color="#0f0" offset="0.5"></stop>
+     <stop stop-color="#00f" offset="1"></stop>
+   </lineargradient>
+ </defs>
+ <g transform="scale(3)" y="50">
+   <text y="20" font-size="20" fill="url(#gradient)">Text needs to have identical gradient.</text>
+ </g>
+</svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/transformed-text-fill-pattern-expected.html b/LayoutTests/svg/transforms/transformed-text-fill-pattern-expected.html
new file mode 100644 (file)
index 0000000..329a4cb
--- /dev/null
@@ -0,0 +1,25 @@
+<html><body><svg width="1000" height="600" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+   <pattern id="hatch" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
+     <g style="fill:none; stroke:black; stroke-width:1">
+       <path d="M0,0 l10,10"/>
+       <path d="M10,0 l-10,10"/>
+     </g>
+   </pattern>
+   <clipPath id="clipHack">
+     <rect x="3" y="0" width="24" height="600"></rect>
+     <rect x="33" y="10" width="24" height="600"></rect>
+     <rect x="63" y="0" width="24" height="600"></rect>
+     <rect x="93" y="0" width="24" height="600"></rect>
+     <rect x="123" y="0" width="24" height="600"></rect>
+   </clipPath>
+ </defs>
+ <g transform="scale(4)" clip-path="url(#clipHack)">
+  <rect y="26" width="150" height="30" fill="url(#hatch)">
+ </g>
+ <g transform="scale(6)" clip-path="url(#clipHack)">
+  <rect y="66" x="0" width="150" height="30" fill="url(#hatch)">
+ </g>
+</svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/transformed-text-fill-pattern.html b/LayoutTests/svg/transforms/transformed-text-fill-pattern.html
new file mode 100644 (file)
index 0000000..87aa45c
--- /dev/null
@@ -0,0 +1,39 @@
+<html><body><svg width="1000" height="600" xmlns="http://www.w3.org/2000/svg">
+ <!-- The pattern needs to scale with the text in the same way it scales with rectangles. -->
+ <defs>
+   <pattern id="hatch" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10">
+     <g style="fill:none; stroke:black; stroke-width:1">
+       <path d="M0,0 l10,10"/>
+       <path d="M10,0 l-10,10"/>
+     </g>
+   </pattern>
+   <style type="text/css"><![CDATA[
+    @font-face {
+        font-family: Ahem;
+        src: url(../../resources/Ahem.ttf);
+    }
+    .ahemblock {
+        font-family: Ahem;
+        font-size: 30px;
+    }
+    ]]>
+   </style>
+   <!-- Masking away the micro-gaps between the Ahem characters that may occur due to rounding
+        which causes this test to fail on platforms that run reftests with zero tolerance. -->
+   <clipPath id="clipHack">
+     <rect x="3" y="0" width="24" height="600"></rect>
+     <rect x="33" y="10" width="24" height="600"></rect>
+     <rect x="63" y="0" width="24" height="600"></rect>
+     <rect x="93" y="0" width="24" height="600"></rect>
+     <rect x="123" y="0" width="24" height="600"></rect>
+   </clipPath>
+ </defs>
+ <g transform="scale(4)" clip-path="url(#clipHack)">
+  <text class="ahemblock"  y="50" fill="url(#hatch)">AAAAA</text>
+ </g>
+ <g transform="scale(6)" clip-path="url(#clipHack)">
+  <text class="ahemblock" y="90" x="0" fill="url(#hatch)">AAAAA</text>
+ </g>
+</svg>
+</body>
+</html>
index cae444e..4ddaf68 100644 (file)
@@ -1,3 +1,36 @@
+2012-06-14  Dominik Röttsches  <dominik.rottsches@intel.com>
+
+        [svg] SVGResources applied to Text with Incorrect Transformations in non-CG Implementations
+        https://bugs.webkit.org/show_bug.cgi?id=64966
+
+        Reviewed by Nikolas Zimmermann.
+
+        SVGInlineTextBox::paintTextWithShadows for non-CG implementations resets the scale aspect
+        of the currently applied CTM. This leads to patterns and gradients being incorrectly downscaled.
+        This way of resetting the CTM and drawing fonts "natively" scaled was introduced
+        in r77485 to fix a number of issues with SVG font scaling.
+        Unfortunately, this breaks scaling of patterns and gradients. To fix it,
+        we need to push the transformation back into the pattern/gradient space transformation.
+
+        Tests: svg/transforms/transformed-text-fill-gradient.html
+               svg/transforms/transformed-text-fill-pattern.html
+
+        * rendering/svg/RenderSVGInlineText.cpp:
+        (WebCore::RenderSVGInlineText::computeNewScaledFontForStyle): Moving the scaling factor calculation out into SVGRenderingContext.
+        * rendering/svg/RenderSVGResourceContainer.cpp:
+        (WebCore::RenderSVGResourceContainer::shouldTransformOnTextPainting): Reusing the scaling factor calculation from SVGRenderingContext.
+        (WebCore):
+        * rendering/svg/RenderSVGResourceContainer.h:
+        (RenderSVGResourceContainer):
+        * rendering/svg/RenderSVGResourceGradient.cpp:
+        (WebCore::RenderSVGResourceGradient::applyResource): If needed, push down transformation into gradient space.
+        * rendering/svg/RenderSVGResourcePattern.cpp:
+        (WebCore::RenderSVGResourcePattern::applyResource): If needed, push transformation into pattern space.
+        * rendering/svg/SVGRenderingContext.cpp:
+        (WebCore::SVGRenderingContext::calculateScreenFontSizeScalingFactor): Common scaling factor calculation for RenderSVGInlineText and RenderSVGResourceContainer.
+        * rendering/svg/SVGRenderingContext.h:
+        (SVGRenderingContext):
+
 2012-06-14  Yoshifumi Inoue  <yosin@chromium.org>
 
         [Form] Replace InputNumber type to Decimal type and drop InputNumber
index eff7077..454f7aa 100644 (file)
@@ -232,9 +232,7 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c
     ASSERT(styleResolver);
 
     // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified
-    AffineTransform ctm;
-    SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm);
-    scalingFactor = narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2));
+    scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(renderer);
     if (scalingFactor == 1 || !scalingFactor || style->fontDescription().textRenderingMode() == GeometricPrecision) {
         scalingFactor = 1;
         scaledFont = style->font();
index 80760fd..1a9eca4 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "RenderSVGRoot.h"
 #include "RenderView.h"
+#include "SVGRenderingContext.h"
 #include "SVGResourcesCache.h"
 #include "SVGStyledTransformableElement.h"
 
@@ -170,6 +171,26 @@ void RenderSVGResourceContainer::registerResource()
     }
 }
 
+bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform)
+{
+    ASSERT_UNUSED(object, object);
+#if USE(CG)
+    UNUSED_PARAM(resourceTransform);
+    return false;
+#else
+    ASSERT(object->isSVGText() || object->isSVGTextPath());
+
+    // In text drawing, the scaling part of the graphics context CTM is removed, compare SVGInlineTextBox::paintTextWithShadows.
+    // So, we use that scaling factor here, too, and then push it down to pattern or gradient space
+    // in order to keep the pattern or gradient correctly scaled.
+    float scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(object);
+    if (scalingFactor == 1)
+        return false;
+    resourceTransform.scale(scalingFactor);
+    return true;
+#endif
+}
+
 // FIXME: This does not belong here.
 AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform)
 {
index b7473d9..1e8e62d 100644 (file)
@@ -38,6 +38,7 @@ public:
     virtual bool isSVGResourceContainer() const { return true; }
     virtual RenderSVGResourceContainer* toRenderSVGResourceContainer() { return this; }
 
+    static bool shouldTransformOnTextPainting(RenderObject*, AffineTransform&);
     static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform);
 
     void idChanged();
index f8f493d..58e0079 100644 (file)
@@ -166,6 +166,13 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
         calculateGradientTransform(gradientTransform);
 
         gradientData->userspaceTransform *= gradientTransform;
+        if (isPaintingText) {
+            // Depending on font scaling factor, we may need to rescale the gradient here since
+            // text painting removes the scale factor from the context.
+            AffineTransform additionalTextTransform;
+            if (shouldTransformOnTextPainting(object, additionalTextTransform))
+                gradientData->userspaceTransform *= additionalTextTransform;
+        }
         gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform);
     }
 
index 15d6476..b4af999 100644 (file)
@@ -133,6 +133,12 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle*
         if (!patternTransform.isIdentity())
             patternData->transform = patternTransform * patternData->transform;
 
+        // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows.
+        if (resourceMode & ApplyToTextMode) {
+            AffineTransform additionalTextTransformation;
+            if (shouldTransformOnTextPainting(object, additionalTextTransformation))
+                patternData->transform *= additionalTextTransformation;
+        }
         patternData->pattern->setPatternSpaceTransform(patternData->transform);
     }
 
index 80f53ef..e2adb30 100644 (file)
@@ -167,6 +167,15 @@ static AffineTransform& currentContentTransformation()
     return s_currentContentTransformation;
 }
 
+float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObject* renderer)
+{
+    ASSERT(renderer);
+
+    AffineTransform ctm;
+    calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm);
+    return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2));
+}
+
 void SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform)
 {
     const RenderObject* current = renderer;
index 4649d9a..5d38ce4 100644 (file)
@@ -83,6 +83,7 @@ public:
     static void renderSubtreeToImageBuffer(ImageBuffer*, RenderObject*, const AffineTransform&);
     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 IntSize clampedAbsoluteSize(const IntSize&);
     static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect);