[SVG2] Add support for the buffered-rendering hint
authorpdr@google.com <pdr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Apr 2013 18:55:24 +0000 (18:55 +0000)
committerpdr@google.com <pdr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Apr 2013 18:55:24 +0000 (18:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104207

Reviewed by Stephen Chenney.

Source/WebCore:

This patch adds the SVG2 buffered-rendering property and implements it for the image
element. For reference, the spec can be found at:
    https://svgwg.org/svg2-draft/single-page.html#painting-BufferedRendering

The buffered-rendering hint causes our implementation to create a temporary image buffer
for caching an element's foreground rendering. This behavior has been designed to support
other graphical and container elements in followup patches (such as the use and g elements).
This patch should not affect rendering, and a test has been added showing the image
results are unchanged.

The performance aspects of this patch can be tested using the following test:
    http://philbit.com/bouncingTigers.html
Without the patch, rendering is below 1fps. With the patch, rendering is fluid.

Tests: svg/css/buffered-rendering.html
       svg/repaint/buffered-rendering-dynamic-image.html
       svg/repaint/buffered-rendering-static-image.html

Other than the changes to RenderSVGImage and SVGRenderingContext, the changes below are to
support the new buffered-rendering property:

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
* css/CSSPrimitiveValueMappings.h:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore):
(WebCore::CSSPrimitiveValue::operator EBufferedRendering):
* css/CSSProperty.cpp:
(WebCore::CSSProperty::isInheritedProperty):
* css/SVGCSSComputedStyleDeclaration.cpp:
(WebCore::CSSComputedStyleDeclaration::getSVGPropertyCSSValue):
* css/SVGCSSParser.cpp:
(WebCore::CSSParser::parseSVGValue):
* css/SVGCSSPropertyNames.in:
* css/SVGCSSStyleSelector.cpp:
(WebCore::StyleResolver::applySVGProperty):
* css/SVGCSSValueKeywords.in:
* rendering/style/SVGRenderStyle.cpp:
(WebCore::SVGRenderStyle::diff):
* rendering/style/SVGRenderStyle.h:
(WebCore::SVGRenderStyle::initialBufferedRendering):
(WebCore::SVGRenderStyle::setBufferedRendering):
(WebCore::SVGRenderStyle::bufferedRendering):
(WebCore::SVGRenderStyle::setBitDefaults):
* rendering/style/SVGRenderStyleDefs.h:
* rendering/svg/RenderSVGImage.cpp:
(WebCore::RenderSVGImage::paint):

    The foreground painting has been extracted out into a separate function. This has also
    been changed so that if the buffered-rendering hint is present, bufferForeground
    is used.

(WebCore::RenderSVGImage::paintForeground):
(WebCore):
(WebCore::RenderSVGImage::invalidateBufferedForeground):

    This function could be replaced with "m_bufferedForeground.clear()" but other renderers
    (such as container elements) will require more complex invalidation logic. To
    maintain consistency with this future code, invalidateBufferedForeground has been used.

(WebCore::RenderSVGImage::imageChanged):
* rendering/svg/RenderSVGImage.h:
(RenderSVGImage):
* rendering/svg/SVGRenderingContext.cpp:
(WebCore::SVGRenderingContext::bufferForeground):
(WebCore):
* rendering/svg/SVGRenderingContext.h:
(SVGRenderingContext):
* svg/SVGStyledElement.cpp:
(WebCore::SVGStyledElement::cssPropertyIdForSVGAttributeName):
(WebCore::cssPropertyToTypeMap):
* svg/svgattrs.in:

LayoutTests:

* svg/css/buffered-rendering-expected.txt: Added.
* svg/css/buffered-rendering.html: Added.
* svg/repaint/buffered-rendering-dynamic-image-expected.html: Added.
* svg/repaint/buffered-rendering-dynamic-image.html: Added.
* svg/repaint/buffered-rendering-static-image-expected.html: Added.
* svg/repaint/buffered-rendering-static-image.html: Added.

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

25 files changed:
LayoutTests/ChangeLog
LayoutTests/svg/css/buffered-rendering-expected.txt [new file with mode: 0644]
LayoutTests/svg/css/buffered-rendering.html [new file with mode: 0644]
LayoutTests/svg/repaint/buffered-rendering-dynamic-image-expected.html [new file with mode: 0644]
LayoutTests/svg/repaint/buffered-rendering-dynamic-image.html [new file with mode: 0644]
LayoutTests/svg/repaint/buffered-rendering-static-image-expected.html [new file with mode: 0644]
LayoutTests/svg/repaint/buffered-rendering-static-image.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSPrimitiveValueMappings.h
Source/WebCore/css/CSSProperty.cpp
Source/WebCore/css/SVGCSSComputedStyleDeclaration.cpp
Source/WebCore/css/SVGCSSParser.cpp
Source/WebCore/css/SVGCSSPropertyNames.in
Source/WebCore/css/SVGCSSStyleSelector.cpp
Source/WebCore/css/SVGCSSValueKeywords.in
Source/WebCore/rendering/style/SVGRenderStyle.cpp
Source/WebCore/rendering/style/SVGRenderStyle.h
Source/WebCore/rendering/style/SVGRenderStyleDefs.h
Source/WebCore/rendering/svg/RenderSVGImage.cpp
Source/WebCore/rendering/svg/RenderSVGImage.h
Source/WebCore/rendering/svg/SVGRenderingContext.cpp
Source/WebCore/rendering/svg/SVGRenderingContext.h
Source/WebCore/svg/SVGStyledElement.cpp
Source/WebCore/svg/svgattrs.in

index 140c842..b316b12 100644 (file)
@@ -1,3 +1,17 @@
+2013-04-01  Philip Rogers  <pdr@google.com>
+
+        [SVG2] Add support for the buffered-rendering hint
+        https://bugs.webkit.org/show_bug.cgi?id=104207
+
+        Reviewed by Stephen Chenney.
+
+        * svg/css/buffered-rendering-expected.txt: Added.
+        * svg/css/buffered-rendering.html: Added.
+        * svg/repaint/buffered-rendering-dynamic-image-expected.html: Added.
+        * svg/repaint/buffered-rendering-dynamic-image.html: Added.
+        * svg/repaint/buffered-rendering-static-image-expected.html: Added.
+        * svg/repaint/buffered-rendering-static-image.html: Added.
+
 2013-04-01  Nate Chapin  <japhet@chromium.org>
 
         Unreviewed, chromium gardening.
diff --git a/LayoutTests/svg/css/buffered-rendering-expected.txt b/LayoutTests/svg/css/buffered-rendering-expected.txt
new file mode 100644 (file)
index 0000000..2ed05ef
--- /dev/null
@@ -0,0 +1,20 @@
+Test that an SVG image accepts all buffered rendering values
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS computedStyle("buffered-rendering", "") is "auto"
+PASS computedStyle("buffered-rendering", "auto") is "auto"
+PASS computedStyle("buffered-rendering", "dynamic") is "dynamic"
+PASS computedStyle("buffered-rendering", "static") is "static"
+PASS computedStyle("buffered-rendering", "0") is "static"
+PASS computedStyle("buffered-rendering", "1") is "static"
+PASS computedStyle("buffered-rendering", "true") is "static"
+PASS computedStyle("buffered-rendering", "dynamic") is "dynamic"
+PASS computedStyle("buffered-rendering", "0") is "dynamic"
+PASS computedStyle("buffered-rendering", "1") is "dynamic"
+PASS computedStyle("buffered-rendering", "true") is "dynamic"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/svg/css/buffered-rendering.html b/LayoutTests/svg/css/buffered-rendering.html
new file mode 100644 (file)
index 0000000..3c8c69d
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<style>
+* { font-size: 16px; }
+div { font-size: 8px; }
+</style>
+<body>
+<svg><image id="image"></image></svg>
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+<script>
+description('Test that an SVG image accepts all buffered rendering values');
+
+var image = document.getElementById('image');
+
+function computedStyle(property, value) {
+    image.style.setProperty(property, value);
+    return getComputedStyle(image).getPropertyValue(property);
+}
+
+function test(property, value, expected) {
+    if (expected === null)
+        shouldBeNull('computedStyle("' + property + '", "' + value + '")');
+    else
+        shouldBeEqualToString('computedStyle("' + property + '", "' + value + '")', expected);
+}
+
+test("buffered-rendering", "", "auto");
+test("buffered-rendering", "auto", "auto");
+test("buffered-rendering", "dynamic", "dynamic");
+test("buffered-rendering", "static", "static");
+
+// negative tests
+test("buffered-rendering", "0", "static");
+test("buffered-rendering", "1", "static");
+test("buffered-rendering", "true", "static");
+
+// make sure valid values still work
+test("buffered-rendering", "dynamic", "dynamic");
+
+// more negative tests
+test("buffered-rendering", "0", "dynamic");
+test("buffered-rendering", "1", "dynamic");
+test("buffered-rendering", "true", "dynamic");
+</script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/svg/repaint/buffered-rendering-dynamic-image-expected.html b/LayoutTests/svg/repaint/buffered-rendering-dynamic-image-expected.html
new file mode 100644 (file)
index 0000000..cd10fd8
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../fast/repaint/resources/repaint.js"></script>
+    <script>
+        function repaintTest() {
+            document.getElementById('behind').setAttribute('fill', 'green');
+            document.getElementById('translate').setAttribute('x', '0');
+            document.getElementById('transform').setAttribute('transform', 'translate(0 0)');
+            document.getElementById('scale').setAttribute('transform', 'scale(1)');
+        }
+    </script>
+</head>
+<body onload="runRepaintTest()">
+Test for WK104207: This test passes if there are 4 green squares each with a smooth black circle in the top-left corner.<br/>
+    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="450">
+        <!-- Test invalidating content behind the dynamic content. -->
+        <rect id="behind" x="40" y="10" width="20" height="80" fill="red"/>
+        <image x="0" y="0" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10' y='10' width='30' height='80' fill='green'/><rect x='60' y='10' width='30' height='80' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test translating dynamic content -->
+        <rect x="20" y="140" width="30" height="30" fill="red"/>
+        <image id="translate" x="50" y="120" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test transforming dynamic content -->
+        <rect x="20" y="260" width="30" height="30" fill="red"/>
+        <image id="transform" transform="skewX(30)" x="0" y="240" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test scaling dynamic content -->
+        <rect x="20" y="380" width="30" height="30" fill="red"/>
+        <image id="scale" transform="scale(0.1)" x="0" y="360" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+    </svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/repaint/buffered-rendering-dynamic-image.html b/LayoutTests/svg/repaint/buffered-rendering-dynamic-image.html
new file mode 100644 (file)
index 0000000..d29e61e
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../fast/repaint/resources/repaint.js"></script>
+    <script>
+        function repaintTest() {
+            document.getElementById('behindDynamic').setAttribute('fill', 'green');
+            document.getElementById('translateDynamic').setAttribute('x', '0');
+            document.getElementById('transformDynamic').setAttribute('transform', 'translate(0 0)');
+            document.getElementById('scaleDynamic').setAttribute('transform', 'scale(1)');
+        }
+    </script>
+</head>
+<body onload="runRepaintTest()">
+Test for WK104207: This test passes if there are 4 green squares each with a smooth black circle in the top-left corner.<br/>
+    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="450">
+        <!-- Test invalidating content behind the dynamic content. -->
+        <rect id="behindDynamic" x="40" y="10" width="20" height="80" fill="red"/>
+        <image x="0" y="0" width="100" height="100" buffered-rendering="dynamic" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10' y='10' width='30' height='80' fill='green'/><rect x='60' y='10' width='30' height='80' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test translating dynamic content -->
+        <rect x="20" y="140" width="30" height="30" fill="red"/>
+        <image id="translateDynamic" x="50" y="120" width="100" height="100" buffered-rendering="dynamic" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test transforming dynamic content -->
+        <rect x="20" y="260" width="30" height="30" fill="red"/>
+        <image id="transformDynamic" transform="skewX(30)" x="0" y="240" width="100" height="100" buffered-rendering="dynamic" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test scaling dynamic content -->
+        <rect x="20" y="380" width="30" height="30" fill="red"/>
+        <image id="scaleDynamic" transform="scale(0.1)" x="0" y="360" width="100" height="100" buffered-rendering="dynamic" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+    </svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/repaint/buffered-rendering-static-image-expected.html b/LayoutTests/svg/repaint/buffered-rendering-static-image-expected.html
new file mode 100644 (file)
index 0000000..5abe757
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../fast/repaint/resources/repaint.js"></script>
+    <script>
+        function repaintTest() {
+            document.getElementById('behind').setAttribute('fill', 'green');
+            document.getElementById('translate').setAttribute('x', '0');
+            document.getElementById('transform').setAttribute('transform', 'translate(0 0)');
+            document.getElementById('scale').setAttribute('transform', 'scale(1)');
+        }
+    </script>
+</head>
+<body onload="runRepaintTest()">
+Test for WK104207: This test passes if there are 4 green squares each with a smooth black circle in the top-left corner.<br/>
+    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="450">
+        <!-- Test invalidating content behind the static content. -->
+        <rect id="behind" x="40" y="10" width="20" height="80" fill="red"/>
+        <image x="0" y="0" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10' y='10' width='30' height='80' fill='green'/><rect x='60' y='10' width='30' height='80' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test translating static content -->
+        <rect x="20" y="140" width="30" height="30" fill="red"/>
+        <image id="translate" x="50" y="120" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test transforming static content -->
+        <rect x="20" y="260" width="30" height="30" fill="red"/>
+        <image id="transform" transform="skewX(30)" x="0" y="240" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test scaling static content -->
+        <rect x="20" y="380" width="30" height="30" fill="red"/>
+        <image id="scale" transform="scale(0.1)" x="0" y="360" width="100" height="100" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+    </svg>
+</body>
+</html>
diff --git a/LayoutTests/svg/repaint/buffered-rendering-static-image.html b/LayoutTests/svg/repaint/buffered-rendering-static-image.html
new file mode 100644 (file)
index 0000000..4d226b0
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../fast/repaint/resources/repaint.js"></script>
+    <script>
+        function repaintTest() {
+            document.getElementById('behindStatic').setAttribute('fill', 'green');
+            document.getElementById('translateStatic').setAttribute('x', '0');
+            document.getElementById('transformStatic').setAttribute('transform', 'translate(0 0)');
+            document.getElementById('scaleStatic').setAttribute('transform', 'scale(1)');
+        }
+    </script>
+</head>
+<body onload="runRepaintTest()">
+Test for WK104207: This test passes if there are 4 green squares each with a smooth black circle in the top-left corner.<br/>
+    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="450">
+        <!-- Test invalidating content behind the static content. -->
+        <rect id="behindStatic" x="40" y="10" width="20" height="80" fill="red"/>
+        <image x="0" y="0" width="100" height="100" buffered-rendering="static" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10' y='10' width='30' height='80' fill='green'/><rect x='60' y='10' width='30' height='80' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test translating static content -->
+        <rect x="20" y="140" width="30" height="30" fill="red"/>
+        <image id="translateStatic" x="50" y="120" width="100" height="100" buffered-rendering="static" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test transforming static content -->
+        <rect x="20" y="260" width="30" height="30" fill="red"/>
+        <image id="transformStatic" transform="skewX(30)" x="0" y="240" width="100" height="100" buffered-rendering="static" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+
+        <!-- Test scaling static content -->
+        <rect x="20" y="380" width="30" height="30" fill="red"/>
+        <image id="scaleStatic" transform="scale(0.1)" x="0" y="360" width="100" height="100" buffered-rendering="static" xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100'><rect x='10%' y='10%' width='80%' height='80%' fill='green'/><circle cx='25' cy='25' r='10' fill='green' stroke='black' stroke-width='1'/></svg>"/>
+    </svg>
+</body>
+</html>
index 135a917..518ab61 100644 (file)
@@ -1,3 +1,83 @@
+2013-04-01  Philip Rogers  <pdr@google.com>
+
+        [SVG2] Add support for the buffered-rendering hint
+        https://bugs.webkit.org/show_bug.cgi?id=104207
+
+        Reviewed by Stephen Chenney.
+
+        This patch adds the SVG2 buffered-rendering property and implements it for the image
+        element. For reference, the spec can be found at:
+            https://svgwg.org/svg2-draft/single-page.html#painting-BufferedRendering
+
+        The buffered-rendering hint causes our implementation to create a temporary image buffer
+        for caching an element's foreground rendering. This behavior has been designed to support
+        other graphical and container elements in followup patches (such as the use and g elements).
+        This patch should not affect rendering, and a test has been added showing the image
+        results are unchanged. 
+
+        The performance aspects of this patch can be tested using the following test:
+            http://philbit.com/bouncingTigers.html
+        Without the patch, rendering is below 1fps. With the patch, rendering is fluid.
+
+        Tests: svg/css/buffered-rendering.html
+               svg/repaint/buffered-rendering-dynamic-image.html
+               svg/repaint/buffered-rendering-static-image.html
+
+        Other than the changes to RenderSVGImage and SVGRenderingContext, the changes below are to
+        support the new buffered-rendering property:
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
+        * css/CSSPrimitiveValueMappings.h:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+        (WebCore):
+        (WebCore::CSSPrimitiveValue::operator EBufferedRendering):
+        * css/CSSProperty.cpp:
+        (WebCore::CSSProperty::isInheritedProperty):
+        * css/SVGCSSComputedStyleDeclaration.cpp:
+        (WebCore::CSSComputedStyleDeclaration::getSVGPropertyCSSValue):
+        * css/SVGCSSParser.cpp:
+        (WebCore::CSSParser::parseSVGValue):
+        * css/SVGCSSPropertyNames.in:
+        * css/SVGCSSStyleSelector.cpp:
+        (WebCore::StyleResolver::applySVGProperty):
+        * css/SVGCSSValueKeywords.in:
+        * rendering/style/SVGRenderStyle.cpp:
+        (WebCore::SVGRenderStyle::diff):
+        * rendering/style/SVGRenderStyle.h:
+        (WebCore::SVGRenderStyle::initialBufferedRendering):
+        (WebCore::SVGRenderStyle::setBufferedRendering):
+        (WebCore::SVGRenderStyle::bufferedRendering):
+        (WebCore::SVGRenderStyle::setBitDefaults):
+        * rendering/style/SVGRenderStyleDefs.h:
+        * rendering/svg/RenderSVGImage.cpp:
+        (WebCore::RenderSVGImage::paint):
+
+            The foreground painting has been extracted out into a separate function. This has also
+            been changed so that if the buffered-rendering hint is present, bufferForeground
+            is used.
+
+        (WebCore::RenderSVGImage::paintForeground):
+        (WebCore):
+        (WebCore::RenderSVGImage::invalidateBufferedForeground):
+
+            This function could be replaced with "m_bufferedForeground.clear()" but other renderers
+            (such as container elements) will require more complex invalidation logic. To
+            maintain consistency with this future code, invalidateBufferedForeground has been used.
+
+        (WebCore::RenderSVGImage::imageChanged):
+        * rendering/svg/RenderSVGImage.h:
+        (RenderSVGImage):
+        * rendering/svg/SVGRenderingContext.cpp:
+        (WebCore::SVGRenderingContext::bufferForeground):
+        (WebCore):
+        * rendering/svg/SVGRenderingContext.h:
+        (SVGRenderingContext):
+        * svg/SVGStyledElement.cpp:
+        (WebCore::SVGStyledElement::cssPropertyIdForSVGAttributeName):
+        (WebCore::cssPropertyToTypeMap):
+        * svg/svgattrs.in:
+
 2013-04-01  Mike West  <mkwst@chromium.org>
 
         CSP 1.1: Remove 'type' parameter from CSPDirectiveList::checkSourceAndReportViolation.
index 65140f7..3f101e4 100644 (file)
@@ -382,6 +382,7 @@ static const CSSPropertyID computedProperties[] = {
     CSSPropertyWebkitWrapThrough,
 #endif
 #if ENABLE(SVG)
+    CSSPropertyBufferedRendering,
     CSSPropertyClipPath,
     CSSPropertyClipRule,
     CSSPropertyMask,
@@ -2821,6 +2822,7 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(CSSPropert
 #endif
 
 #if ENABLE(SVG)
+        case CSSPropertyBufferedRendering:
         case CSSPropertyClipPath:
         case CSSPropertyClipRule:
         case CSSPropertyMask:
index c1c5d97..66c0082 100644 (file)
@@ -4238,6 +4238,38 @@ template<int supported> Length CSSPrimitiveValue::convertToLength(RenderStyle* s
 
 #if ENABLE(SVG)
 
+template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EBufferedRendering e)
+    : CSSValue(PrimitiveClass)
+{
+    m_primitiveUnitType = CSS_IDENT;
+    switch (e) {
+    case BR_AUTO:
+        m_value.ident = CSSValueAuto;
+        break;
+    case BR_DYNAMIC:
+        m_value.ident = CSSValueDynamic;
+        break;
+    case BR_STATIC:
+        m_value.ident = CSSValueStatic;
+        break;
+    }
+}
+
+template<> inline CSSPrimitiveValue::operator EBufferedRendering() const
+{
+    switch (m_value.ident) {
+    case CSSValueAuto:
+        return BR_AUTO;
+    case CSSValueDynamic:
+        return BR_DYNAMIC;
+    case CSSValueStatic:
+        return BR_STATIC;
+    }
+
+    ASSERT_NOT_REACHED();
+    return BR_AUTO;
+}
+
 template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EColorInterpolation e)
     : CSSValue(PrimitiveClass)
 {
index 2bbbd11..77735c4 100644 (file)
@@ -691,6 +691,7 @@ bool CSSProperty::isInheritedProperty(CSSPropertyID propertyID)
     case CSSPropertyBaselineShift:
     case CSSPropertyDominantBaseline:
     case CSSPropertyVectorEffect:
+    case CSSPropertyBufferedRendering:
     case CSSPropertyWebkitSvgShadow:
 #endif
 #if ENABLE(DASHBOARD_SUPPORT)
index 271dd2b..425777c 100644 (file)
@@ -177,6 +177,8 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getSVGPropertyCSSValue(CSSProp
             ASSERT_NOT_REACHED();
             return 0;
         }
+        case CSSPropertyBufferedRendering:
+            return CSSPrimitiveValue::create(svgStyle->bufferedRendering());
         case CSSPropertyGlyphOrientationHorizontal:
             return glyphOrientationToCSSPrimitiveValue(svgStyle->glyphOrientationHorizontal());
         case CSSPropertyGlyphOrientationVertical: {
index 894d9e7..e6e115e 100644 (file)
@@ -138,6 +138,11 @@ bool CSSParser::parseSVGValue(CSSPropertyID propId, bool important)
             valid_primitive = true;
         break;
 
+    case CSSPropertyBufferedRendering: // auto | dynamic | static
+        if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic)
+            valid_primitive = true;
+        break;
+
     case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
         if (id == CSSValueAuto || id == CSSValueSrgb)
             valid_primitive = true;
index f0188f2..b342294 100644 (file)
@@ -5,6 +5,7 @@
 #if defined(ENABLE_SVG) && ENABLE_SVG
 
 // SVG style props
+buffered-rendering
 clip-path
 clip-rule
 mask
index d1e9c60..70d1ca4 100644 (file)
@@ -588,6 +588,14 @@ void StyleResolver::applySVGProperty(CSSPropertyID id, CSSValue* value)
             svgstyle->setVectorEffect(*primitiveValue);
             break;
         }
+        case CSSPropertyBufferedRendering: {
+            HANDLE_INHERIT_AND_INITIAL(bufferedRendering, BufferedRendering)
+            if (!primitiveValue)
+                break;
+
+            svgstyle->setBufferedRendering(*primitiveValue);
+            break;
+        }
         case CSSPropertyMaskType: {
             HANDLE_INHERIT_AND_INITIAL(maskType, MaskType)
             if (!primitiveValue)
index a3919c9..a578f0f 100644 (file)
@@ -264,6 +264,11 @@ reset-size
 // middle
 // end
 
+// CSS_PROP_BUFFERED_RENDERING
+// auto
+// static
+dynamic
+
 // CSS_PROP_VECTOR_EFFECT
 // none
 non-scaling-stroke
index d74019d..cbd16cd 100644 (file)
@@ -223,6 +223,9 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const
     if (svg_noninherited_flags.f._vectorEffect != other->svg_noninherited_flags.f._vectorEffect)
         return StyleDifferenceRepaint;
 
+    if (svg_noninherited_flags.f.bufferedRendering != other->svg_noninherited_flags.f.bufferedRendering)
+        return StyleDifferenceRepaint;
+
     if (svg_noninherited_flags.f.maskType != other->svg_noninherited_flags.f.maskType)
         return StyleDifferenceRepaint;
 
index ee69db6..4a224b7 100644 (file)
@@ -59,6 +59,7 @@ public:
     static EDominantBaseline initialDominantBaseline() { return DB_AUTO; }
     static EBaselineShift initialBaselineShift() { return BS_BASELINE; }
     static EVectorEffect initialVectorEffect() { return VE_NONE; }
+    static EBufferedRendering initialBufferedRendering() { return BR_AUTO; }
     static LineCap initialCapStyle() { return ButtCap; }
     static WindRule initialClipRule() { return RULE_NONZERO; }
     static EColorInterpolation initialColorInterpolation() { return CI_SRGB; }
@@ -128,6 +129,7 @@ public:
     void setDominantBaseline(EDominantBaseline val) { svg_noninherited_flags.f._dominantBaseline = val; }
     void setBaselineShift(EBaselineShift val) { svg_noninherited_flags.f._baselineShift = val; }
     void setVectorEffect(EVectorEffect val) { svg_noninherited_flags.f._vectorEffect = val; }
+    void setBufferedRendering(EBufferedRendering val) { svg_noninherited_flags.f.bufferedRendering = val; }
     void setCapStyle(LineCap val) { svg_inherited_flags._capStyle = val; }
     void setClipRule(WindRule val) { svg_inherited_flags._clipRule = val; }
     void setColorInterpolation(EColorInterpolation val) { svg_inherited_flags._colorInterpolation = val; }
@@ -305,6 +307,7 @@ public:
     EDominantBaseline dominantBaseline() const { return (EDominantBaseline) svg_noninherited_flags.f._dominantBaseline; }
     EBaselineShift baselineShift() const { return (EBaselineShift) svg_noninherited_flags.f._baselineShift; }
     EVectorEffect vectorEffect() const { return (EVectorEffect) svg_noninherited_flags.f._vectorEffect; }
+    EBufferedRendering bufferedRendering() const { return (EBufferedRendering) svg_noninherited_flags.f.bufferedRendering; }
     LineCap capStyle() const { return (LineCap) svg_inherited_flags._capStyle; }
     WindRule clipRule() const { return (WindRule) svg_inherited_flags._clipRule; }
     EColorInterpolation colorInterpolation() const { return (EColorInterpolation) svg_inherited_flags._colorInterpolation; }
@@ -412,8 +415,9 @@ protected:
                 unsigned _dominantBaseline : 4; // EDominantBaseline
                 unsigned _baselineShift : 2; // EBaselineShift
                 unsigned _vectorEffect: 1; // EVectorEffect
+                unsigned bufferedRendering: 2; // EBufferedRendering
                 unsigned maskType: 1; // EMaskType
-                // 20 bits unused
+                // 18 bits unused
             } f;
             uint32_t _niflags;
         };
@@ -458,6 +462,7 @@ private:
         svg_noninherited_flags.f._dominantBaseline = initialDominantBaseline();
         svg_noninherited_flags.f._baselineShift = initialBaselineShift();
         svg_noninherited_flags.f._vectorEffect = initialVectorEffect();
+        svg_noninherited_flags.f.bufferedRendering = initialBufferedRendering();
         svg_noninherited_flags.f.maskType = initialMaskType();
     }
 };
index e7308ca..b4c0668 100644 (file)
@@ -83,6 +83,12 @@ namespace WebCore {
         VE_NON_SCALING_STROKE
     };
 
+    enum EBufferedRendering {
+        BR_AUTO,
+        BR_DYNAMIC,
+        BR_STATIC
+    };
+
     enum EMaskType {
         MT_LUMINANCE,
         MT_ALPHA
index c964c18..6a55d2a 100644 (file)
@@ -132,14 +132,10 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&)
             SVGRenderingContext renderingContext(this, childPaintInfo);
 
             if (renderingContext.isRenderingPrepared()) {
-                RefPtr<Image> image = m_imageResource->image();
-                FloatRect destRect = m_objectBoundingBox;
-                FloatRect srcRect(0, 0, image->width(), image->height());
+                if (style()->svgStyle()->bufferedRendering() == BR_STATIC  && renderingContext.bufferForeground(m_bufferedForeground))
+                    return;
 
-                SVGImageElement* imageElement = static_cast<SVGImageElement*>(node());
-                imageElement->preserveAspectRatio().transformRect(destRect, srcRect);
-
-                childPaintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect);
+                paintForeground(childPaintInfo);
             }
         }
 
@@ -148,6 +144,23 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&)
     }
 }
 
+void RenderSVGImage::paintForeground(PaintInfo& paintInfo)
+{
+    RefPtr<Image> image = m_imageResource->image();
+    FloatRect destRect = m_objectBoundingBox;
+    FloatRect srcRect(0, 0, image->width(), image->height());
+
+    SVGImageElement* imageElement = static_cast<SVGImageElement*>(node());
+    imageElement->preserveAspectRatio().transformRect(destRect, srcRect);
+
+    paintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect);
+}
+
+void RenderSVGImage::invalidateBufferedForeground()
+{
+    m_bufferedForeground.clear();
+}
+
 bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
 {
     // We only draw in the forground phase, so we only hit-test then.
@@ -188,6 +201,8 @@ void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*)
     m_objectBoundingBox = FloatRect();
     updateImageViewport();
 
+    invalidateBufferedForeground();
+
     repaint();
 }
 
index 9e05b0a..af85b89 100644 (file)
@@ -49,9 +49,12 @@ public:
     RenderImageResource* imageResource() { return m_imageResource.get(); }
     const RenderImageResource* imageResource() const { return m_imageResource.get(); }
 
+    // Note: Assumes the PaintInfo context has had all local transforms applied.
+    void paintForeground(PaintInfo&);
+
 private:
     virtual const char* renderName() const { return "RenderSVGImage"; }
-    virtual bool isSVGImage() const { return true; }
+    virtual bool isSVGImage() const OVERRIDE { return true; }
 
     virtual const AffineTransform& localToParentTransform() const { return m_localTransform; }
 
@@ -67,6 +70,8 @@ private:
     virtual void layout();
     virtual void paint(PaintInfo&, const LayoutPoint&);
 
+    void invalidateBufferedForeground();
+
     virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
 
     virtual AffineTransform localTransform() const { return m_localTransform; }
@@ -79,6 +84,8 @@ private:
     FloatRect m_repaintBoundingBox;
     FloatRect m_repaintBoundingBoxExcludingShadow;
     OwnPtr<RenderImageResource> m_imageResource;
+
+    OwnPtr<ImageBuffer> m_bufferedForeground;
 };
 
 inline RenderSVGImage* toRenderSVGImage(RenderObject* object)
index ac7ed6b..fe06edf 100644 (file)
@@ -31,6 +31,7 @@
 #include "Frame.h"
 #include "FrameView.h"
 #include "RenderLayer.h"
+#include "RenderSVGImage.h"
 #include "RenderSVGResource.h"
 #include "RenderSVGResourceClipper.h"
 #include "RenderSVGResourceFilter.h"
@@ -324,6 +325,37 @@ void SVGRenderingContext::clear2DRotation(AffineTransform& transform)
     transform.recompose(decomposition);
 }
 
+bool SVGRenderingContext::bufferForeground(OwnPtr<ImageBuffer>& imageBuffer)
+{
+    ASSERT(m_paintInfo);
+    ASSERT(m_object->isSVGImage());
+    FloatRect boundingBox = m_object->objectBoundingBox();
+
+    // Invalidate an existing buffer if the scale is not correct.
+    if (imageBuffer) {
+        AffineTransform transform = m_paintInfo->context->getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
+        IntSize expandedBoundingBox = expandedIntSize(boundingBox.size());
+        IntSize bufferSize(static_cast<int>(ceil(expandedBoundingBox.width() * transform.xScale())), static_cast<int>(ceil(expandedBoundingBox.height() * transform.yScale())));
+        if (bufferSize != imageBuffer->internalSize())
+            imageBuffer.clear();
+    }
+
+    // Create a new buffer and paint the foreground into it.
+    if (!imageBuffer) {
+        if ((imageBuffer = m_paintInfo->context->createCompatibleBuffer(expandedIntSize(boundingBox.size()), true))) {
+            GraphicsContext* bufferedRenderingContext = imageBuffer->context();
+            bufferedRenderingContext->translate(-boundingBox.x(), -boundingBox.y());
+            PaintInfo bufferedInfo(*m_paintInfo);
+            bufferedInfo.context = bufferedRenderingContext;
+            toRenderSVGImage(m_object)->paintForeground(bufferedInfo);
+        } else
+            return false;
+    }
+
+    m_paintInfo->context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, boundingBox);
+    return true;
+}
+
 }
 
 #endif
index 7e16127..1fc3f1a 100644 (file)
@@ -93,6 +93,9 @@ public:
         return enclosingIntRect(absoluteTransform.mapRect(targetRect));
     }
 
+    // Support for the buffered-rendering hint.
+    bool bufferForeground(OwnPtr<ImageBuffer>&);
+
 private:
     // To properly revert partially successful initializtions in the destructor, we record all successful steps.
     enum RenderingFlags {
index c8598dc..f15d580 100644 (file)
@@ -139,6 +139,7 @@ CSSPropertyID SVGStyledElement::cssPropertyIdForSVGAttributeName(const Qualified
         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
+        mapAttributeToCSSProperty(propertyNameToIdMap, buffered_renderingAttr);
         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
@@ -214,6 +215,7 @@ static inline AttributeToPropertyTypeMap& cssPropertyToTypeMap()
     // Fill the map for the first use.
     s_cssPropertyMap.set(alignment_baselineAttr, AnimatedString);
     s_cssPropertyMap.set(baseline_shiftAttr, AnimatedString);
+    s_cssPropertyMap.set(buffered_renderingAttr, AnimatedString);
     s_cssPropertyMap.set(clipAttr, AnimatedRect);
     s_cssPropertyMap.set(clip_pathAttr, AnimatedString);
     s_cssPropertyMap.set(clip_ruleAttr, AnimatedString);
index d00df56..24fc5f9 100644 (file)
@@ -21,6 +21,7 @@ baseProfile
 bbox
 begin
 bias
+buffered-rendering
 by
 calcMode
 cap-height