CSS Shaders: Repainting the FECustomFilter requires full source image
authorachicu@adobe.com <achicu@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Apr 2012 23:55:50 +0000 (23:55 +0000)
committerachicu@adobe.com <achicu@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Apr 2012 23:55:50 +0000 (23:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=76689

Source/WebCore:

Reviewed by Dean Jackson..

When a pixel of a filtered layer changes we need to update the whole bounding box of the layer and
not just the dirty rectangle. That's because the shader might change the color of any of the pixels inside the box.

Added tests where a shader is moving and rotating the contents and the actual
dirty box of the source image is not the same as the output dirty rectangle.

Tests: css3/filters/custom/filter-repaint-custom-clipped.html
       css3/filters/custom/filter-repaint-custom-rotated.html
       css3/filters/custom/filter-repaint-custom.html

* rendering/FilterEffectRenderer.cpp:
(WebCore::FilterEffectRenderer::FilterEffectRenderer):
(WebCore::FilterEffectRenderer::build):
(WebCore::FilterEffectRenderer::computeSourceImageRectForDirtyRect):
* rendering/FilterEffectRenderer.h:
(FilterEffectRenderer):
(WebCore::FilterEffectRenderer::hasCustomShaderFilter):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::setFilterBackendNeedsRepaintingInRect):

LayoutTests:

Reviewed by Dean Jackson.

* css3/filters/custom/filter-repaint-custom-clipped-expected.png: Added.
* css3/filters/custom/filter-repaint-custom-clipped-expected.txt: Added.
* css3/filters/custom/filter-repaint-custom-clipped.html: Added.
* css3/filters/custom/filter-repaint-custom-expected.png: Added.
* css3/filters/custom/filter-repaint-custom-expected.txt: Added.
* css3/filters/custom/filter-repaint-custom-rotated-expected.png: Added.
* css3/filters/custom/filter-repaint-custom-rotated-expected.txt: Added.
* css3/filters/custom/filter-repaint-custom-rotated.html: Added.
* css3/filters/custom/filter-repaint-custom.html: Added.
* css3/filters/resources/color-add.fs: Added.
* css3/filters/resources/vertex-horizontal-offset.vs: Added.
* css3/filters/resources/vertex-rotate.vs: Added.
* platform/chromium-mac/css3/filters/custom/filter-repaint-custom-clipped-expected.png: Added.
* platform/chromium-mac/css3/filters/custom/filter-repaint-custom-expected.png: Added.
* platform/chromium-mac/css3/filters/custom/filter-repaint-custom-rotated-expected.png: Added.
* platform/chromium/test_expectations.txt:

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

21 files changed:
LayoutTests/ChangeLog
LayoutTests/css3/filters/custom/filter-repaint-custom-clipped-expected.png [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom-clipped-expected.txt [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom-clipped.html [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom-expected.png [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom-expected.txt [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom-rotated-expected.png [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom-rotated-expected.txt [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom-rotated.html [new file with mode: 0644]
LayoutTests/css3/filters/custom/filter-repaint-custom.html [new file with mode: 0644]
LayoutTests/css3/filters/resources/color-add.fs [new file with mode: 0644]
LayoutTests/css3/filters/resources/vertex-horizontal-offset.vs [new file with mode: 0644]
LayoutTests/css3/filters/resources/vertex-rotate.vs [new file with mode: 0644]
LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-clipped-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-rotated-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium/test_expectations.txt
Source/WebCore/ChangeLog
Source/WebCore/rendering/FilterEffectRenderer.cpp
Source/WebCore/rendering/FilterEffectRenderer.h
Source/WebCore/rendering/RenderLayer.cpp

index a814e96..1b18480 100644 (file)
@@ -1,3 +1,27 @@
+2012-04-24  Alexandru Chiculita  <achicu@adobe.com>
+
+        CSS Shaders: Repainting the FECustomFilter requires full source image
+        https://bugs.webkit.org/show_bug.cgi?id=76689
+
+        Reviewed by Dean Jackson.
+
+        * css3/filters/custom/filter-repaint-custom-clipped-expected.png: Added.
+        * css3/filters/custom/filter-repaint-custom-clipped-expected.txt: Added.
+        * css3/filters/custom/filter-repaint-custom-clipped.html: Added.
+        * css3/filters/custom/filter-repaint-custom-expected.png: Added.
+        * css3/filters/custom/filter-repaint-custom-expected.txt: Added.
+        * css3/filters/custom/filter-repaint-custom-rotated-expected.png: Added.
+        * css3/filters/custom/filter-repaint-custom-rotated-expected.txt: Added.
+        * css3/filters/custom/filter-repaint-custom-rotated.html: Added.
+        * css3/filters/custom/filter-repaint-custom.html: Added.
+        * css3/filters/resources/color-add.fs: Added.
+        * css3/filters/resources/vertex-horizontal-offset.vs: Added.
+        * css3/filters/resources/vertex-rotate.vs: Added.
+        * platform/chromium-mac/css3/filters/custom/filter-repaint-custom-clipped-expected.png: Added.
+        * platform/chromium-mac/css3/filters/custom/filter-repaint-custom-expected.png: Added.
+        * platform/chromium-mac/css3/filters/custom/filter-repaint-custom-rotated-expected.png: Added.
+        * platform/chromium/test_expectations.txt:
+
 2012-04-24  Alpha Lam  <hclam@chromium.org>
 
         [chromium] Unreviewed test expectations update.
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-clipped-expected.png b/LayoutTests/css3/filters/custom/filter-repaint-custom-clipped-expected.png
new file mode 100644 (file)
index 0000000..a582125
Binary files /dev/null and b/LayoutTests/css3/filters/custom/filter-repaint-custom-clipped-expected.png differ
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-clipped-expected.txt b/LayoutTests/css3/filters/custom/filter-repaint-custom-clipped-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-clipped.html b/LayoutTests/css3/filters/custom/filter-repaint-custom-clipped.html
new file mode 100644 (file)
index 0000000..b93f461
--- /dev/null
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<!-- 
+    This tests verifies that shader filter is repainted using the full source image of the element instead of just the dirty area.
+    Also it tests that the clipping rectangle of the box is not affecting the filter.
+    There should be one light green box on the screen. No red should be visible.
+-->
+<html>
+<head>
+    <script>
+        if (window.layoutTestController) {
+            window.layoutTestController.overridePreference("WebKitCSSCustomFilterEnabled", "1");
+            window.layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+            window.layoutTestController.dumpAsText(true);
+        }
+        function repaintTest()
+        {
+            document.querySelector(".before").classList.remove("before");
+        }
+    </script>
+    <style>
+        .clipping_box {
+            margin: 20px;
+            width: 100px;
+            height: 100px;
+            overflow: hidden;
+            background: red;
+        }
+        
+        .empty_box {
+            height: 50px;
+        }
+        
+        .box {
+            height: 150px;
+            width: 100px;
+            background-color: green;
+        }
+        
+        .before {
+            background-color: transparent;
+        }
+
+        .shader {
+            -webkit-filter: custom(url(../resources/vertex-horizontal-offset.vs) url(../resources/color-add.fs), offset -0.5, add 0.1);
+        }
+    </style>
+
+    <script src="../../../fast/repaint/resources/repaint.js"></script>
+</head>
+
+<body onload="runRepaintTest()">
+
+    <div class="clipping_box">
+        <div class="shader">
+            <div class="empty_box"></div>
+            <div class="box before"></div>
+        </div>
+    </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-expected.png b/LayoutTests/css3/filters/custom/filter-repaint-custom-expected.png
new file mode 100644 (file)
index 0000000..4e054d8
Binary files /dev/null and b/LayoutTests/css3/filters/custom/filter-repaint-custom-expected.png differ
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-expected.txt b/LayoutTests/css3/filters/custom/filter-repaint-custom-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-rotated-expected.png b/LayoutTests/css3/filters/custom/filter-repaint-custom-rotated-expected.png
new file mode 100644 (file)
index 0000000..d3b8592
Binary files /dev/null and b/LayoutTests/css3/filters/custom/filter-repaint-custom-rotated-expected.png differ
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-rotated-expected.txt b/LayoutTests/css3/filters/custom/filter-repaint-custom-rotated-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom-rotated.html b/LayoutTests/css3/filters/custom/filter-repaint-custom-rotated.html
new file mode 100644 (file)
index 0000000..65cbdf6
--- /dev/null
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<!-- 
+    This tests verifies that filter shader is repainted using the full source image of the element instead of just the dirty area.
+    Also it tests that the clipping or the transform rectangle of the box is not affecting the filter.
+    There should be one light green boxes on the screen. No red should be visible.
+-->
+<html>
+<head>
+    <script>
+        if (window.layoutTestController) {
+            window.layoutTestController.overridePreference("WebKitCSSCustomFilterEnabled", "1");
+            window.layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+            window.layoutTestController.dumpAsText(true);
+        }
+        function repaintTest()
+        {
+            document.querySelector(".before").classList.remove("before");
+        }
+    </script>
+    <style>
+        .clipping_box {
+            margin: 100px;
+            width: 100px;
+            height: 100px;
+            overflow: hidden;
+            background: red;
+        }
+        
+        .empty_box {
+            height: 50px;
+        }
+        
+        .box {
+            height: 150px;
+            width: 100px;
+            background-color: green;
+        }
+        
+        .before {
+            background-color: transparent;
+        }
+
+        .shader {
+            -webkit-filter: custom(url(../resources/vertex-horizontal-offset.vs) url(../resources/color-add.fs), offset -0.5, add 0.1);
+            -webkit-transform-origin: 50px 50px;
+            -webkit-transform: rotate(90deg);
+        }
+    </style>
+
+    <script src="../../../fast/repaint/resources/repaint.js"></script>
+</head>
+
+<body onload="runRepaintTest()">
+
+    <div class="clipping_box">
+        <div class="shader">
+            <div class="empty_box"></div>
+            <div class="box before"></div>
+        </div>
+    </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/filters/custom/filter-repaint-custom.html b/LayoutTests/css3/filters/custom/filter-repaint-custom.html
new file mode 100644 (file)
index 0000000..36392b7
--- /dev/null
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!-- 
+    This tests verifies that the shader filter is repainted using the full source image of the element instead of just the dirty area. 
+    There should be 4 boxes of same size. 3 of them are green and the last one on the right is blue.
+-->
+<html>
+<head>
+    <script>
+        if (window.layoutTestController) {
+            window.layoutTestController.overridePreference("WebKitCSSCustomFilterEnabled", "1");
+            window.layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+            window.layoutTestController.dumpAsText(true);
+        }
+        function repaintTest()
+        {
+            document.querySelector(".before").classList.remove("before");
+        }
+    </script>
+    <style>
+        .box {
+            margin-top: 10px;
+            margin-bottom: 10px;
+            height: 50px;
+            width: 50px;
+            background-color: green;
+        }
+
+        .before {
+            background-color: red;
+        }
+
+        .shader {
+            border-top: 50px solid blue;
+            width: 50px;
+            -webkit-filter: custom(url(../resources/vertex-rotate.vs) url(../resources/color-add.fs), rotateBy 90, add 0.1);
+        }
+    </style>
+
+    <script src="../../../fast/repaint/resources/repaint.js"></script>
+</head>
+
+<body onload="runRepaintTest()">
+
+    <div class="shader">
+        <div class="box"></div>
+        <div class="box before"></div>
+        <div class="box"></div>
+    </div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/css3/filters/resources/color-add.fs b/LayoutTests/css3/filters/resources/color-add.fs
new file mode 100644 (file)
index 0000000..1935ac9
--- /dev/null
@@ -0,0 +1,10 @@
+precision mediump float;
+varying vec2 v_texCoord;
+uniform sampler2D s_texture;
+uniform float add;
+
+void main()
+{
+    // Offset the color value with "add" on each color channel.
+    gl_FragColor = texture2D(s_texture, v_texCoord) + add;
+}
\ No newline at end of file
diff --git a/LayoutTests/css3/filters/resources/vertex-horizontal-offset.vs b/LayoutTests/css3/filters/resources/vertex-horizontal-offset.vs
new file mode 100644 (file)
index 0000000..97458ac
--- /dev/null
@@ -0,0 +1,15 @@
+precision mediump float;
+
+attribute vec4 a_position;
+attribute vec2 a_texCoord;
+
+uniform mat4 u_projectionMatrix;
+uniform float offset;
+
+varying vec2 v_texCoord;
+
+void main()
+{
+    gl_Position = u_projectionMatrix * (a_position + vec4(0.0, offset, 0.0, 0.0));
+    v_texCoord = a_texCoord;
+}
\ No newline at end of file
diff --git a/LayoutTests/css3/filters/resources/vertex-rotate.vs b/LayoutTests/css3/filters/resources/vertex-rotate.vs
new file mode 100644 (file)
index 0000000..eb54784
--- /dev/null
@@ -0,0 +1,22 @@
+precision mediump float;
+
+attribute vec4 a_position;
+attribute vec2 a_texCoord;
+
+uniform mat4 u_projectionMatrix;
+uniform float rotateBy;
+
+varying vec2 v_texCoord;
+
+mat4 rotateZMatrix(float f) {
+    return mat4(cos(f), sin(f), 0.0, 0.0,
+                -sin(f), cos(f), 0.0, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                0.0, 0.0, 0.0, 1.0);
+}
+
+void main()
+{
+    gl_Position = u_projectionMatrix * rotateZMatrix(rotateBy * 3.14 / 180.0) * a_position;
+    v_texCoord = a_texCoord;
+}
\ No newline at end of file
diff --git a/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-clipped-expected.png b/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-clipped-expected.png
new file mode 100644 (file)
index 0000000..4213bb9
Binary files /dev/null and b/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-clipped-expected.png differ
diff --git a/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-expected.png b/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-expected.png
new file mode 100644 (file)
index 0000000..2afdc45
Binary files /dev/null and b/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-expected.png differ
diff --git a/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-rotated-expected.png b/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-rotated-expected.png
new file mode 100644 (file)
index 0000000..d8e1681
Binary files /dev/null and b/LayoutTests/platform/chromium-mac/css3/filters/custom/filter-repaint-custom-rotated-expected.png differ
index 6f4c72f..b349419 100644 (file)
@@ -2805,6 +2805,11 @@ BUGWK82783 SKIP : css3/filters/nested-filter.html = FAIL
 
 BUGWK84067 : css3/filters/custom/custom-filter-property-computed-style.html = TEXT
 
+// Following tests need baselines on Win and Linux
+BUGWK84800 SKIP WIN LINUX : css3/filters/custom/filter-repaint-custom-clipped.html = FAIL
+BUGWK84800 SKIP WIN LINUX : css3/filters/custom/filter-repaint-custom-rotated.html = FAIL
+BUGWK84800 SKIP WIN LINUX : css3/filters/custom/filter-repaint-custom.html = FAIL
+
 // <style scoped> not yet enabled.
 BUGWK49142 SKIP : fast/css/style-scoped = PASS
 // CSS Regions tests for region styling and scoped styles
index 9ec7f62..64d2578 100644 (file)
@@ -1,3 +1,30 @@
+2012-04-24  Alexandru Chiculita  <achicu@adobe.com>
+
+        CSS Shaders: Repainting the FECustomFilter requires full source image
+        https://bugs.webkit.org/show_bug.cgi?id=76689
+
+        Reviewed by Dean Jackson..
+
+        When a pixel of a filtered layer changes we need to update the whole bounding box of the layer and
+        not just the dirty rectangle. That's because the shader might change the color of any of the pixels inside the box.
+
+        Added tests where a shader is moving and rotating the contents and the actual
+        dirty box of the source image is not the same as the output dirty rectangle.
+
+        Tests: css3/filters/custom/filter-repaint-custom-clipped.html
+               css3/filters/custom/filter-repaint-custom-rotated.html
+               css3/filters/custom/filter-repaint-custom.html
+
+        * rendering/FilterEffectRenderer.cpp:
+        (WebCore::FilterEffectRenderer::FilterEffectRenderer):
+        (WebCore::FilterEffectRenderer::build):
+        (WebCore::FilterEffectRenderer::computeSourceImageRectForDirtyRect):
+        * rendering/FilterEffectRenderer.h:
+        (FilterEffectRenderer):
+        (WebCore::FilterEffectRenderer::hasCustomShaderFilter):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::setFilterBackendNeedsRepaintingInRect):
+
 2012-04-24  Alexis Menard  <alexis.menard@openbossa.org>
 
         Replace occurences of style selector from variables and methods names by style resolver.
index 89befeb..54e8c1c 100644 (file)
@@ -90,6 +90,9 @@ FilterEffectRenderer::FilterEffectRenderer()
     , m_leftOutset(0)
     , m_graphicsBufferAttached(false)
     , m_hasFilterThatMovesPixels(false)
+#if ENABLE(CSS_SHADERS)
+    , m_hasCustomShaderFilter(false)
+#endif
 {
     setFilterResolution(FloatSize(1, 1));
     m_sourceGraphic = SourceGraphic::create(this);
@@ -110,6 +113,9 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope
     UNUSED_PARAM(document);
 #endif
 
+#if ENABLE(CSS_SHADERS)
+    m_hasCustomShaderFilter = false;
+#endif
     m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels();
     if (m_hasFilterThatMovesPixels)
         operations.getOutsets(m_topOutset, m_rightOutset, m_bottomOutset, m_leftOutset);
@@ -268,6 +274,7 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope
                 effect = FECustomFilter::create(this, document->view()->root()->hostWindow(), program, customFilterOperation->parameters(),
                                                 customFilterOperation->meshRows(), customFilterOperation->meshColumns(),
                                                 customFilterOperation->meshBoxType(), customFilterOperation->meshType());
+                m_hasCustomShaderFilter = true;
             }
 #endif
             break;
@@ -337,6 +344,13 @@ void FilterEffectRenderer::apply()
 
 LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect)
 {
+#if ENABLE(CSS_SHADERS)
+    if (hasCustomShaderFilter()) {
+        // When we have at least a custom shader in the chain, we need to compute the whole source image, because the shader can
+        // reference any pixel and we cannot control that.
+        return filterBoxRect;
+    }
+#endif
     // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect".
     LayoutRect rectForRepaint = dirtyRect;
     if (hasFilterThatMovesPixels()) {
index 869759b..c6266f6 100644 (file)
@@ -110,6 +110,9 @@ public:
     bool hasFilterThatMovesPixels() const { return m_hasFilterThatMovesPixels; }
     LayoutRect computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect);
 
+#if ENABLE(CSS_SHADERS)
+    bool hasCustomShaderFilter() const { return m_hasCustomShaderFilter; }
+#endif
 private:
     void setMaxEffectRects(const FloatRect& effectRect)
     {
@@ -141,6 +144,9 @@ private:
     
     bool m_graphicsBufferAttached;
     bool m_hasFilterThatMovesPixels;
+#if ENABLE(CSS_SHADERS)
+    bool m_hasCustomShaderFilter;
+#endif
 };
 
 } // namespace WebCore
index 6c10e1e..9795fda 100644 (file)
@@ -1019,6 +1019,16 @@ void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect,
     ASSERT(filterInfo);
     filterInfo->expandDirtySourceRect(rectForRepaint);
     
+#if ENABLE(CSS_SHADERS)
+    ASSERT(filterInfo->renderer());
+    if (filterInfo->renderer()->hasCustomShaderFilter()) {
+        // If we have at least one custom shader, we need to update the whole bounding box of the layer, because the
+        // shader can address any ouput pixel.
+        // Note: This is only for output rect, so there's no need to expand the dirty source rect.
+        rectForRepaint.unite(calculateLayerBounds(this, this));
+    }
+#endif
+    
     RenderLayer* parentLayer = enclosingFilterRepaintLayer();
     ASSERT(parentLayer);
     FloatQuad repaintQuad(rectForRepaint);