[CSS Shaders] Implement normal blend mode and source-atop compositing mode
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Aug 2012 00:34:58 +0000 (00:34 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Aug 2012 00:34:58 +0000 (00:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=93869

Patch by Max Vujovic <mvujovic@adobe.com> on 2012-08-30
Reviewed by Dean Jackson.

Source/WebCore:

Instead of allowing direct texture access in an author's shader via u_texture, CSS
Shaders blends special symbols in the author's shader (css_MixColor and
css_ColorMatrix) with the DOM element texture.

The author specifies the blend mode and composite operator via the CSS mix
function like this:
-webkit-filter: custom(none mix(shader.fs normal source-atop));

This patch implements the normal blend mode and the source-atop composite
operator. The other blend modes and composite operators will come in later
patches.

This patch introduces a new class, CustomFilterValidatedProgram, which validates
the shader using ANGLE. If the shader uses blending and compositing,
CustomFilterValidatedProgram uses ANGLE's SH_CSS_SHADERS_SPEC flag. This allows
the author's shader to compile successfully with special symbols like
"css_MixColor". ANGLE also reserves the "css_" prefix. If the shader doesn't use
blending and compositing, CustomFilterValidatedProgram validates the shader using
ANGLE's SH_WEBGL_SPEC flag.

After validation, CustomFilterValidatedProgram adds blending, compositing, and
texture access shader code to the author's original shaders. The definitions for
css_MixColor and css_ColorMatrix are added before the author's fragment shader
code so that the author code can access them. The blending, compositing, and
texture access code is added after the author code and is thus inaccessible to the
author code. Since ANGLE reserves the "css_" prefix during the validation phase,
no collisions are possible between the author's code and the code that WebKit adds.

The CustomFilterGlobalContext now caches CustomFilterValidatedProgram instead
of CustomFilterCompiledProgram. CustomFilterValidatedProgram owns a
CustomFilterCompiledProgram. This way, we can use the platform-independent
CustomFilterValidatedProgram to validate and rewrite the shaders, regardless of
the platform representation of the program (e.g. CustomFilterCompiledProgram).

Tests: css3/filters/custom/custom-filter-color-matrix.html
       css3/filters/custom/custom-filter-composite-source-atop.html

* GNUmakefile.list.am:
* Target.pri:
* WebCore.gyp/WebCore.gyp:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/ANGLEWebKitBridge.cpp:
(WebCore::ANGLEWebKitBridge::ANGLEWebKitBridge):
    Add a shader spec parameter, since sometimes we want to validate the shader
    against the CSS Shaders spec and other times we want to validate the shader
    against the WebGL spec. Note that the CSS Shaders spec is treated as a subset
    of the WebGL spec in ANGLE.
(WebCore::ANGLEWebKitBridge::validateShaderSource):
* platform/graphics/ANGLEWebKitBridge.h:
(ANGLEWebKitBridge):
* platform/graphics/filters/CustomFilterCompiledProgram.cpp:
(WebCore::CustomFilterCompiledProgram::CustomFilterCompiledProgram):
(WebCore::CustomFilterCompiledProgram::compileShader):
(WebCore::CustomFilterCompiledProgram::initializeParameterLocations):
(WebCore::CustomFilterCompiledProgram::~CustomFilterCompiledProgram):
* platform/graphics/filters/CustomFilterCompiledProgram.h:
(WebCore):
* platform/graphics/filters/CustomFilterGlobalContext.cpp:
(WebCore::CustomFilterGlobalContext::~CustomFilterGlobalContext):
(WebCore::CustomFilterGlobalContext::webglShaderValidator):
(WebCore):
(WebCore::CustomFilterGlobalContext::mixShaderValidator):
(WebCore::CustomFilterGlobalContext::createShaderValidator):
(WebCore::CustomFilterGlobalContext::getValidatedProgram):
(WebCore::CustomFilterGlobalContext::removeValidatedProgram):
* platform/graphics/filters/CustomFilterGlobalContext.h:
(WebCore):
(CustomFilterGlobalContext):
* platform/graphics/filters/CustomFilterProgramInfo.h:
(WebCore::CustomFilterProgramInfo::mixSettings):
* platform/graphics/filters/CustomFilterValidatedProgram.cpp: Added.
(WebCore):
(WebCore::CustomFilterValidatedProgram::defaultVertexShaderString):
(WebCore::CustomFilterValidatedProgram::defaultFragmentShaderString):
(WebCore::CustomFilterValidatedProgram::CustomFilterValidatedProgram):
(WebCore::CustomFilterValidatedProgram::compiledProgram):
(WebCore::CustomFilterValidatedProgram::rewriteMixVertexShader):
(WebCore::CustomFilterValidatedProgram::rewriteMixFragmentShader):
(WebCore::CustomFilterValidatedProgram::blendFunctionString):
(WebCore::CustomFilterValidatedProgram::compositeFunctionString):
(WebCore::CustomFilterValidatedProgram::~CustomFilterValidatedProgram):
* platform/graphics/filters/CustomFilterValidatedProgram.h: Added.
(WebCore):
(CustomFilterValidatedProgram):
(WebCore::CustomFilterValidatedProgram::create):
(WebCore::CustomFilterValidatedProgram::programInfo):
(WebCore::CustomFilterValidatedProgram::isInitialized):
(WebCore::CustomFilterValidatedProgram::detachFromGlobalContext):
* platform/graphics/filters/FECustomFilter.cpp:
(WebCore::FECustomFilter::FECustomFilter):
    Accept a CustomFilterValidatedProgram instead of CustomFilterProgram.
(WebCore::FECustomFilter::create):
(WebCore::FECustomFilter::initializeContext):
(WebCore::FECustomFilter::bindVertexAttribute):
(WebCore::FECustomFilter::bindProgramAndBuffers):
* platform/graphics/filters/FECustomFilter.h:
(WebCore):
(FECustomFilter):
* rendering/FilterEffectRenderer.cpp:
(WebCore):
(WebCore::createCustomFilterEffect):
(WebCore::FilterEffectRenderer::build):
    Only create an FECustomFilter if the program validates.
* rendering/FilterEffectRenderer.h:
(WebCore):
(FilterEffectRenderer):

LayoutTests:

We've added two new special built-in symbols in CSS Shaders, css_MixColor and
css_ColorMatrix.

This change adds custom-filter-composite-source-atop.html, a new test that uses css_MixColor
in a shader with the normal blend mode and the source-atop compositing operator.

This change also adds custom-filter-color-matrix.html, a new test that uses css_ColorMatrix
in the shader.

Authors can read and write to these special built-ins in their shader code. WebKit will
premultiply the DOM element texture with css_ColorMatrix. Additionally, WebKit will blend
and composite css_MixColor with the DOM element texture, according to the blend mode and
compositing operator that the author specifies in CSS.

For example, the following line of CSS tells WebKit how to blend and composite the
css_MixColor from shader.fs:
-webkit-filter: custom(none mix(shader.fs normal source-atop));

* css3/filters/custom/custom-filter-color-matrix-expected.png: Added.
* css3/filters/custom/custom-filter-color-matrix-expected.txt: Added.
* css3/filters/custom/custom-filter-color-matrix.html: Added.
* css3/filters/custom/custom-filter-composite-source-atop-expected.png: Added.
* css3/filters/custom/custom-filter-composite-source-atop-expected.txt: Added.
* css3/filters/custom/custom-filter-composite-source-atop.html: Added.
* css3/filters/custom/custom-filter-shader-cache.html:
* css3/filters/custom/effect-color-check.html:
    Use pass-tex-coord.vs now. Since v_texCoord in not automatically passed in the default
    shaders anymore, we have to pass it in our own vertex shader. After we implement more
    blending and compositing modes, we will be able to convert most of the tests to use the
    CSS mix function. Then, we won't be sampling the DOM element texture directly, so we
    won't need a tex coord, so we won't need this shader anymore.
* css3/filters/custom/effect-custom.html:
    The default CSS value for <fragmentShader> needs to be specified explicitly until we
    change it from its current default. This will be fixed in:
    https://bugs.webkit.org/show_bug.cgi?id=94020
* css3/filters/custom/effect-custom-transform-parameters.html:
    Ditto.
* css3/filters/custom/filter-fallback-to-software.html:
    Ditto.
* css3/filters/custom/invalid-custom-filter-shader-expected.html:
    These tests will not attempt to apply a filter because the programs do not validate.
    This means we don't need to trigger FilterEffectRenderer with grayscale(0) in
    the reference file anymore.
* css3/filters/resources/composite.fs: Added.
* css3/filters/resources/empty-shader.fs: Added.
* css3/filters/resources/grayscale-color-matrix.fs: Added.
* css3/filters/resources/pass-tex-coord.vs: Added.
* platform/chromium/css3/filters/custom/custom-filter-color-matrix-expected.png: Added.
* platform/chromium/css3/filters/custom/custom-filter-composite-source-atop-expected.png: Added.
* platform/chromium/TestExpectations:
* platform/mac-snowleopard/css3/filters/custom/effect-custom-expected.png: Removed.
    We should use the generic expectation, because this expectation does not show the
    shaders applied.
* platform/mac-snowleopard/css3/filters/custom/effect-custom-parameters-expected.png: Removed.
    Ditto.

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

43 files changed:
LayoutTests/ChangeLog
LayoutTests/css3/filters/custom/custom-filter-color-matrix-expected.png [new file with mode: 0644]
LayoutTests/css3/filters/custom/custom-filter-color-matrix-expected.txt [new file with mode: 0644]
LayoutTests/css3/filters/custom/custom-filter-color-matrix.html [new file with mode: 0644]
LayoutTests/css3/filters/custom/custom-filter-composite-source-atop-expected.png [new file with mode: 0644]
LayoutTests/css3/filters/custom/custom-filter-composite-source-atop-expected.txt [new file with mode: 0644]
LayoutTests/css3/filters/custom/custom-filter-composite-source-atop.html [new file with mode: 0644]
LayoutTests/css3/filters/custom/custom-filter-shader-cache.html
LayoutTests/css3/filters/custom/effect-color-check.html
LayoutTests/css3/filters/custom/effect-custom-transform-parameters.html
LayoutTests/css3/filters/custom/effect-custom.html
LayoutTests/css3/filters/custom/filter-fallback-to-software.html
LayoutTests/css3/filters/custom/invalid-custom-filter-shader-expected.html
LayoutTests/css3/filters/resources/composite.fs [new file with mode: 0644]
LayoutTests/css3/filters/resources/empty-shader.fs [new file with mode: 0644]
LayoutTests/css3/filters/resources/grayscale-color-matrix.fs [new file with mode: 0644]
LayoutTests/css3/filters/resources/pass-tex-coord.vs [new file with mode: 0644]
LayoutTests/css3/filters/resources/vertex-transform-parameter.vs
LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-color-matrix-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-composite-source-atop-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium/TestExpectations
LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-expected.png [deleted file]
LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-parameters-expected.png [deleted file]
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.gyp/WebCore.gyp
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp
Source/WebCore/platform/graphics/ANGLEWebKitBridge.h
Source/WebCore/platform/graphics/filters/CustomFilterCompiledProgram.cpp
Source/WebCore/platform/graphics/filters/CustomFilterCompiledProgram.h
Source/WebCore/platform/graphics/filters/CustomFilterGlobalContext.cpp
Source/WebCore/platform/graphics/filters/CustomFilterGlobalContext.h
Source/WebCore/platform/graphics/filters/CustomFilterProgramInfo.h
Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.h [new file with mode: 0644]
Source/WebCore/platform/graphics/filters/FECustomFilter.cpp
Source/WebCore/platform/graphics/filters/FECustomFilter.h
Source/WebCore/rendering/FilterEffectRenderer.cpp
Source/WebCore/rendering/FilterEffectRenderer.h

index f5ea1ba..1a1495b 100644 (file)
@@ -1,3 +1,66 @@
+2012-08-30  Max Vujovic  <mvujovic@adobe.com>
+
+        [CSS Shaders] Implement normal blend mode and source-atop compositing mode
+        https://bugs.webkit.org/show_bug.cgi?id=93869
+
+        Reviewed by Dean Jackson.
+
+        We've added two new special built-in symbols in CSS Shaders, css_MixColor and
+        css_ColorMatrix.
+
+        This change adds custom-filter-composite-source-atop.html, a new test that uses css_MixColor
+        in a shader with the normal blend mode and the source-atop compositing operator.
+
+        This change also adds custom-filter-color-matrix.html, a new test that uses css_ColorMatrix
+        in the shader.
+
+        Authors can read and write to these special built-ins in their shader code. WebKit will
+        premultiply the DOM element texture with css_ColorMatrix. Additionally, WebKit will blend
+        and composite css_MixColor with the DOM element texture, according to the blend mode and
+        compositing operator that the author specifies in CSS.
+
+        For example, the following line of CSS tells WebKit how to blend and composite the
+        css_MixColor from shader.fs:
+        -webkit-filter: custom(none mix(shader.fs normal source-atop));
+
+        * css3/filters/custom/custom-filter-color-matrix-expected.png: Added.
+        * css3/filters/custom/custom-filter-color-matrix-expected.txt: Added.
+        * css3/filters/custom/custom-filter-color-matrix.html: Added.
+        * css3/filters/custom/custom-filter-composite-source-atop-expected.png: Added.
+        * css3/filters/custom/custom-filter-composite-source-atop-expected.txt: Added.
+        * css3/filters/custom/custom-filter-composite-source-atop.html: Added.
+        * css3/filters/custom/custom-filter-shader-cache.html:
+        * css3/filters/custom/effect-color-check.html:
+            Use pass-tex-coord.vs now. Since v_texCoord in not automatically passed in the default
+            shaders anymore, we have to pass it in our own vertex shader. After we implement more
+            blending and compositing modes, we will be able to convert most of the tests to use the
+            CSS mix function. Then, we won't be sampling the DOM element texture directly, so we
+            won't need a tex coord, so we won't need this shader anymore.
+        * css3/filters/custom/effect-custom.html:
+            The default CSS value for <fragmentShader> needs to be specified explicitly until we
+            change it from its current default. This will be fixed in:
+            https://bugs.webkit.org/show_bug.cgi?id=94020
+        * css3/filters/custom/effect-custom-transform-parameters.html:
+            Ditto.
+        * css3/filters/custom/filter-fallback-to-software.html:
+            Ditto.
+        * css3/filters/custom/invalid-custom-filter-shader-expected.html:
+            These tests will not attempt to apply a filter because the programs do not validate.
+            This means we don't need to trigger FilterEffectRenderer with grayscale(0) in
+            the reference file anymore.
+        * css3/filters/resources/composite.fs: Added.
+        * css3/filters/resources/empty-shader.fs: Added.
+        * css3/filters/resources/grayscale-color-matrix.fs: Added.
+        * css3/filters/resources/pass-tex-coord.vs: Added.
+        * platform/chromium/css3/filters/custom/custom-filter-color-matrix-expected.png: Added.
+        * platform/chromium/css3/filters/custom/custom-filter-composite-source-atop-expected.png: Added.
+        * platform/chromium/TestExpectations:
+        * platform/mac-snowleopard/css3/filters/custom/effect-custom-expected.png: Removed.
+            We should use the generic expectation, because this expectation does not show the
+            shaders applied.
+        * platform/mac-snowleopard/css3/filters/custom/effect-custom-parameters-expected.png: Removed.
+            Ditto.
+
 2012-08-30  Jessie Berlin  <jberlin@apple.com>
 
         Remove the failing expectation from some tests that are no longer failing on Lion.
diff --git a/LayoutTests/css3/filters/custom/custom-filter-color-matrix-expected.png b/LayoutTests/css3/filters/custom/custom-filter-color-matrix-expected.png
new file mode 100644 (file)
index 0000000..53cd8f5
Binary files /dev/null and b/LayoutTests/css3/filters/custom/custom-filter-color-matrix-expected.png differ
diff --git a/LayoutTests/css3/filters/custom/custom-filter-color-matrix-expected.txt b/LayoutTests/css3/filters/custom/custom-filter-color-matrix-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/css3/filters/custom/custom-filter-color-matrix.html b/LayoutTests/css3/filters/custom/custom-filter-color-matrix.html
new file mode 100644 (file)
index 0000000..cc85a10
--- /dev/null
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+<head>
+    <title>Test css_ColorMatrix.</title>
+    <!-- If the test passes, you should see the reference image as grayscale. -->
+    <script>
+        if (window.testRunner) {
+            window.testRunner.overridePreference("WebKitCSSCustomFilterEnabled", "1");
+            window.testRunner.overridePreference("WebKitWebGLEnabled", "1");
+            window.testRunner.dumpAsText(true);
+            window.testRunner.waitUntilDone();
+        }
+        
+        function runTest()
+        {
+            // Run the test after the image loads.
+            if (window.testRunner)
+                window.testRunner.notifyDone();
+        }
+    </script>
+</head>
+<body onload="runTest()">
+    <img style="-webkit-filter: custom(none mix(url('../resources/grayscale-color-matrix.fs') normal source-atop))" src="../resources/reference.png">
+</body>
+</html>
diff --git a/LayoutTests/css3/filters/custom/custom-filter-composite-source-atop-expected.png b/LayoutTests/css3/filters/custom/custom-filter-composite-source-atop-expected.png
new file mode 100644 (file)
index 0000000..3a1b001
Binary files /dev/null and b/LayoutTests/css3/filters/custom/custom-filter-composite-source-atop-expected.png differ
diff --git a/LayoutTests/css3/filters/custom/custom-filter-composite-source-atop-expected.txt b/LayoutTests/css3/filters/custom/custom-filter-composite-source-atop-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/css3/filters/custom/custom-filter-composite-source-atop.html b/LayoutTests/css3/filters/custom/custom-filter-composite-source-atop.html
new file mode 100644 (file)
index 0000000..6a6c696
--- /dev/null
@@ -0,0 +1,51 @@
+<!doctype html>
+<html>
+<head>
+    <title>Tests the source-atop composite operator with the normal blend mode.</title>
+    <!--
+        This test mimics the source-atop example image in the Compositing and Blending spec:
+        https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#porterduffcompositingoperators_srcatop
+
+        If it passes, you should see a yellow square with a blue square in its lower right corner.
+        This should be in the upper left corner of a white box with a black border.
+    -->
+    <script>
+        if (window.testRunner) {
+            window.testRunner.overridePreference("WebKitCSSCustomFilterEnabled", "1");
+            window.testRunner.overridePreference("WebKitWebGLEnabled", "1");
+            window.testRunner.dumpAsText(true);
+        }
+    </script>
+    <style>
+    /* Draws a black border around the shaded destination div. */
+    #border-container {
+        width: 200px;
+        height: 200px;
+        border: 1px solid black;
+    }
+    /* The shaded div. */
+    #destination {
+        width: 100%;
+        height: 100%;
+        /* The fragment shader writes a blue square to css_MixColor in the lower right corner of the destination div. */
+        /* It writes transparent elsewhere. */
+        -webkit-filter: custom(url('../resources/pass-tex-coord.vs') mix(url('../resources/composite.fs') normal source-atop));
+    }
+    /* Draws a yellow square in the upper left corner of the destination div. */
+    /* The rest of the destination div is transparent. */
+    #destination-opaque-child {
+        width: 67%;
+        height: 67%;
+        background-color: yellow;
+    }
+    </style>
+</head>
+<body>
+    <div id="border-container">
+        <div id="destination">
+            <div id="destination-opaque-child">
+            </div>
+        </div>
+    </div>
+</body>
+</html>
index f4a38be..f3cc6f9 100644 (file)
         <style>
             .vertex_shader
             {
-                -webkit-filter: custom(url('../resources/vertex-offset.vs'));
+                -webkit-filter: custom(url('../resources/vertex-offset.vs') mix(url('../resources/empty-shader.fs') normal source-atop));
             }
             .fragment_shader
             {
-                -webkit-filter: custom(none url('../resources/color-offset.fs'));
+                -webkit-filter: custom(url('../resources/pass-tex-coord.vs') url('../resources/color-offset.fs'));
             }
             .both_shaders
             {
index 4272fad..01499fa 100644 (file)
@@ -19,9 +19,9 @@
         </script>
     </head>
     <body onload="runTest()">
-        <img style="-webkit-filter: custom(none url('../resources/color-fill.fs'), color 1 0 0 1)" src="../../../compositing/resources/thiswayup.png">
-        <img style="-webkit-filter: custom(none url('../resources/color-fill.fs'), color 0 1 0 1)" src="../../../compositing/resources/thiswayup.png">
-        <img style="-webkit-filter: custom(none url('../resources/color-fill.fs'), color 0 0 1 1)" src="../../../compositing/resources/thiswayup.png">
+        <img style="-webkit-filter: custom(url('../resources/pass-tex-coord.vs') url('../resources/color-fill.fs'), color 1 0 0 1)" src="../../../compositing/resources/thiswayup.png">
+        <img style="-webkit-filter: custom(url('../resources/pass-tex-coord.vs') url('../resources/color-fill.fs'), color 0 1 0 1)" src="../../../compositing/resources/thiswayup.png">
+        <img style="-webkit-filter: custom(url('../resources/pass-tex-coord.vs') url('../resources/color-fill.fs'), color 0 0 1 1)" src="../../../compositing/resources/thiswayup.png">
         <!--
             Testing that the color channels are specified correctly. You should see 3 boxes filled with red, green and blue. The arrow should
             point upside and the text should be written from left to right (no mirror). Also the gradient starts from up - transparent to down - full color.
index 1b8feea..70903e2 100644 (file)
@@ -25,7 +25,8 @@
         }
         /* Testing parameters of type transform in vertex-transform-parameter.vs. */
         .filter {
-            -webkit-filter: custom(url('../resources/vertex-transform-parameter.vs'), 
+            -webkit-filter: custom(url('../resources/vertex-transform-parameter.vs')
+                                    mix(url('../resources/empty-shader.fs') normal source-atop), 
                                     transform translate(10px, 20px)
                                   );
             background-color: green;
index 21a74d1..a5c5554 100644 (file)
     </head>
     <body onload="runTest()">
         <img style="-webkit-filter: custom(url('../resources/vertex-offset.vs') url('../resources/color-offset.fs'))" src="../resources/reference.png">
-        <img style="-webkit-filter: custom(url('../resources/vertex-offset.vs'), 6 11)" src="../resources/reference.png">
-        <img style="-webkit-filter: custom(url('../resources/vertex-explode-detached.vs'), 3 3 detached)" src="../resources/reference.png">
+        <img style="-webkit-filter: custom(url('../resources/vertex-offset.vs') mix(url('../resources/empty-shader.fs') normal source-atop), 6 11)" src="../resources/reference.png">
+        <img style="-webkit-filter: custom(url('../resources/vertex-explode-detached.vs') mix(url('../resources/empty-shader.fs') normal source-atop), 3 3 detached)" src="../resources/reference.png">
         <img style="-webkit-filter: custom(url('../resources/vertex-explode-detached.vs') url('../resources/color-offset.fs'), 3 3 detached)" src="../resources/reference.png">
-        <img style="-webkit-filter: custom(none url('../resources/color-offset.fs'))" src="../resources/reference.png">
+        <img style="-webkit-filter: custom(url('../resources/pass-tex-coord.vs') url('../resources/color-offset.fs'))" src="../resources/reference.png">
         <!--
             Testing that simple custom filters work in software mode. You should see 5 blocks of colored bars with different effects applied, from left to right: 
             offset to the right with washed out colors, just offset to the right with normal colors, 4 smaller blocks attached to the corners, 4 smaller blocks 
index 2880875..723fc37 100644 (file)
@@ -30,7 +30,7 @@
         }
 
         .shader {
-            -webkit-filter: custom(url('../resources/vertex-offset.vs')) drop-shadow(10px 10px 10px blue);
+            -webkit-filter: custom(url('../resources/vertex-offset.vs') mix(url('../resources/empty-shader.fs') normal source-atop)) drop-shadow(10px 10px 10px blue);
         }
 
         .before {
index 067f6fc..92ac06e 100644 (file)
                     window.testRunner.notifyDone();
             }
         </script>
-        <style>
-            img
-            {
-                /* Note that we use grayscale(0) just to make sure that it triggers the whole FilterEffectRenderer on the images, 
-                otherwise the result will be slightly different because of the precision errors. Having another filter like grayscale(0) 
-                will trigger the same precission errors and will act as a similar pass-through filter. */
-                -webkit-filter: grayscale(0);
-            }
-        </style>
     </head>
     <body onload="notifyDone()">
         <img src="../resources/reference.png" />
diff --git a/LayoutTests/css3/filters/resources/composite.fs b/LayoutTests/css3/filters/resources/composite.fs
new file mode 100644 (file)
index 0000000..babb66c
--- /dev/null
@@ -0,0 +1,9 @@
+precision mediump float;
+
+varying vec2 v_texCoord;
+
+void main()
+{
+    // Produce a blue square in the lower right-hand part of the image.
+    css_MixColor = vec4(0.0, 0.0, 1.0, float(v_texCoord.x > 0.33 && v_texCoord.y > 0.33));
+}
diff --git a/LayoutTests/css3/filters/resources/empty-shader.fs b/LayoutTests/css3/filters/resources/empty-shader.fs
new file mode 100644 (file)
index 0000000..9198103
--- /dev/null
@@ -0,0 +1,3 @@
+void main()
+{
+}
diff --git a/LayoutTests/css3/filters/resources/grayscale-color-matrix.fs b/LayoutTests/css3/filters/resources/grayscale-color-matrix.fs
new file mode 100644 (file)
index 0000000..b03d85d
--- /dev/null
@@ -0,0 +1,9 @@
+void main()
+{
+    css_ColorMatrix = mat4(
+        0.333, 0.333, 0.333, 0.000,
+        0.333, 0.333, 0.333, 0.000,
+        0.333, 0.333, 0.333, 0.000,
+        0.000, 0.000, 0.000, 1.000
+    );
+}
diff --git a/LayoutTests/css3/filters/resources/pass-tex-coord.vs b/LayoutTests/css3/filters/resources/pass-tex-coord.vs
new file mode 100644 (file)
index 0000000..4ffd27b
--- /dev/null
@@ -0,0 +1,12 @@
+precision mediump float;
+
+attribute vec4 a_position;
+attribute vec2 a_texCoord;
+uniform mat4 u_projectionMatrix;
+varying vec2 v_texCoord;
+
+void main()
+{
+    v_texCoord = a_texCoord;
+    gl_Position = u_projectionMatrix * a_position;
+}
index 0f368e5..28c16a6 100644 (file)
@@ -1,14 +1,11 @@
 precision mediump float;
 
 attribute vec4 a_position;
-attribute vec2 a_texCoord;
 
 uniform mat4 u_projectionMatrix;
 uniform mat4 transform;
-varying vec2 v_texCoord;
 
 void main()
 {
     gl_Position = u_projectionMatrix * transform * a_position;
-    v_texCoord = a_texCoord;
 }
diff --git a/LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-color-matrix-expected.png b/LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-color-matrix-expected.png
new file mode 100644 (file)
index 0000000..5fa1b00
Binary files /dev/null and b/LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-color-matrix-expected.png differ
diff --git a/LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-composite-source-atop-expected.png b/LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-composite-source-atop-expected.png
new file mode 100644 (file)
index 0000000..02b815e
Binary files /dev/null and b/LayoutTests/platform/chromium-mac/css3/filters/custom/custom-filter-composite-source-atop-expected.png differ
index 8f3274d..1719ccf 100644 (file)
@@ -3491,6 +3491,10 @@ BUGWK94078 WIN RELEASE : http/tests/inspector/web-socket-frame-error.html = PASS
 
 BUGWK94256 DEBUG : fast/block/inline-children-root-linebox-crash.html = PASS CRASH
 
+// Following tests need baselines on Win and Linux 
+BUGWK94492 WIN LINUX : css3/filters/custom/custom-filter-color-matrix.html = PASS IMAGE IMAGE+TEXT TEXT MISSING
+BUGWK94492 WIN LINUX : css3/filters/custom/custom-filter-composite-source-atop.html = PASS IMAGE IMAGE+TEXT TEXT MISSING
+
 // Flaky
 BUGWK95246 : http/tests/security/mixedContent/filesystem-url-in-iframe.html = PASS TEXT
 
diff --git a/LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-expected.png b/LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-expected.png
deleted file mode 100644 (file)
index c33260f..0000000
Binary files a/LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-expected.png and /dev/null differ
diff --git a/LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-parameters-expected.png b/LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-parameters-expected.png
deleted file mode 100644 (file)
index 9503f13..0000000
Binary files a/LayoutTests/platform/mac-snowleopard/css3/filters/custom/effect-custom-parameters-expected.png and /dev/null differ
index 0615726..185938a 100644 (file)
@@ -1,3 +1,119 @@
+2012-08-30  Max Vujovic  <mvujovic@adobe.com>
+
+        [CSS Shaders] Implement normal blend mode and source-atop compositing mode
+        https://bugs.webkit.org/show_bug.cgi?id=93869
+
+        Reviewed by Dean Jackson.
+
+        Instead of allowing direct texture access in an author's shader via u_texture, CSS
+        Shaders blends special symbols in the author's shader (css_MixColor and
+        css_ColorMatrix) with the DOM element texture.
+
+        The author specifies the blend mode and composite operator via the CSS mix
+        function like this:
+        -webkit-filter: custom(none mix(shader.fs normal source-atop));
+
+        This patch implements the normal blend mode and the source-atop composite
+        operator. The other blend modes and composite operators will come in later
+        patches.
+
+        This patch introduces a new class, CustomFilterValidatedProgram, which validates
+        the shader using ANGLE. If the shader uses blending and compositing,
+        CustomFilterValidatedProgram uses ANGLE's SH_CSS_SHADERS_SPEC flag. This allows
+        the author's shader to compile successfully with special symbols like
+        "css_MixColor". ANGLE also reserves the "css_" prefix. If the shader doesn't use
+        blending and compositing, CustomFilterValidatedProgram validates the shader using
+        ANGLE's SH_WEBGL_SPEC flag.
+
+        After validation, CustomFilterValidatedProgram adds blending, compositing, and
+        texture access shader code to the author's original shaders. The definitions for
+        css_MixColor and css_ColorMatrix are added before the author's fragment shader
+        code so that the author code can access them. The blending, compositing, and
+        texture access code is added after the author code and is thus inaccessible to the
+        author code. Since ANGLE reserves the "css_" prefix during the validation phase,
+        no collisions are possible between the author's code and the code that WebKit adds.
+
+        The CustomFilterGlobalContext now caches CustomFilterValidatedProgram instead
+        of CustomFilterCompiledProgram. CustomFilterValidatedProgram owns a
+        CustomFilterCompiledProgram. This way, we can use the platform-independent
+        CustomFilterValidatedProgram to validate and rewrite the shaders, regardless of
+        the platform representation of the program (e.g. CustomFilterCompiledProgram).
+
+        Tests: css3/filters/custom/custom-filter-color-matrix.html
+               css3/filters/custom/custom-filter-composite-source-atop.html
+
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.gyp/WebCore.gyp:
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/ANGLEWebKitBridge.cpp:
+        (WebCore::ANGLEWebKitBridge::ANGLEWebKitBridge):
+            Add a shader spec parameter, since sometimes we want to validate the shader
+            against the CSS Shaders spec and other times we want to validate the shader
+            against the WebGL spec. Note that the CSS Shaders spec is treated as a subset
+            of the WebGL spec in ANGLE.
+        (WebCore::ANGLEWebKitBridge::validateShaderSource):
+        * platform/graphics/ANGLEWebKitBridge.h:
+        (ANGLEWebKitBridge):
+        * platform/graphics/filters/CustomFilterCompiledProgram.cpp:
+        (WebCore::CustomFilterCompiledProgram::CustomFilterCompiledProgram):
+        (WebCore::CustomFilterCompiledProgram::compileShader):
+        (WebCore::CustomFilterCompiledProgram::initializeParameterLocations):
+        (WebCore::CustomFilterCompiledProgram::~CustomFilterCompiledProgram):
+        * platform/graphics/filters/CustomFilterCompiledProgram.h:
+        (WebCore):
+        * platform/graphics/filters/CustomFilterGlobalContext.cpp:
+        (WebCore::CustomFilterGlobalContext::~CustomFilterGlobalContext):
+        (WebCore::CustomFilterGlobalContext::webglShaderValidator):
+        (WebCore):
+        (WebCore::CustomFilterGlobalContext::mixShaderValidator):
+        (WebCore::CustomFilterGlobalContext::createShaderValidator):
+        (WebCore::CustomFilterGlobalContext::getValidatedProgram):
+        (WebCore::CustomFilterGlobalContext::removeValidatedProgram):
+        * platform/graphics/filters/CustomFilterGlobalContext.h:
+        (WebCore):
+        (CustomFilterGlobalContext):
+        * platform/graphics/filters/CustomFilterProgramInfo.h:
+        (WebCore::CustomFilterProgramInfo::mixSettings):
+        * platform/graphics/filters/CustomFilterValidatedProgram.cpp: Added.
+        (WebCore):
+        (WebCore::CustomFilterValidatedProgram::defaultVertexShaderString):
+        (WebCore::CustomFilterValidatedProgram::defaultFragmentShaderString):
+        (WebCore::CustomFilterValidatedProgram::CustomFilterValidatedProgram):
+        (WebCore::CustomFilterValidatedProgram::compiledProgram):
+        (WebCore::CustomFilterValidatedProgram::rewriteMixVertexShader):
+        (WebCore::CustomFilterValidatedProgram::rewriteMixFragmentShader):
+        (WebCore::CustomFilterValidatedProgram::blendFunctionString):
+        (WebCore::CustomFilterValidatedProgram::compositeFunctionString):
+        (WebCore::CustomFilterValidatedProgram::~CustomFilterValidatedProgram):
+        * platform/graphics/filters/CustomFilterValidatedProgram.h: Added.
+        (WebCore):
+        (CustomFilterValidatedProgram):
+        (WebCore::CustomFilterValidatedProgram::create):
+        (WebCore::CustomFilterValidatedProgram::programInfo):
+        (WebCore::CustomFilterValidatedProgram::isInitialized):
+        (WebCore::CustomFilterValidatedProgram::detachFromGlobalContext):
+        * platform/graphics/filters/FECustomFilter.cpp:
+        (WebCore::FECustomFilter::FECustomFilter):
+            Accept a CustomFilterValidatedProgram instead of CustomFilterProgram.
+        (WebCore::FECustomFilter::create):
+        (WebCore::FECustomFilter::initializeContext):
+        (WebCore::FECustomFilter::bindVertexAttribute):
+        (WebCore::FECustomFilter::bindProgramAndBuffers):
+        * platform/graphics/filters/FECustomFilter.h:
+        (WebCore):
+        (FECustomFilter):
+        * rendering/FilterEffectRenderer.cpp:
+        (WebCore):
+        (WebCore::createCustomFilterEffect):
+        (WebCore::FilterEffectRenderer::build):
+            Only create an FECustomFilter if the program validates.
+        * rendering/FilterEffectRenderer.h:
+        (WebCore):
+        (FilterEffectRenderer):
+
 2012-08-30  Julien Chaffraix  <jchaffraix@webkit.org>
 
         Crash in RenderTable::calcBorderEnd
index 7ef4307..80c636f 100644 (file)
@@ -4242,6 +4242,8 @@ webcore_sources += \
        Source/WebCore/platform/graphics/filters/CustomFilterCompiledProgram.cpp \
        Source/WebCore/platform/graphics/filters/CustomFilterCompiledProgram.h \
        Source/WebCore/platform/graphics/filters/CustomFilterTransformParameter.h \
+       Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.cpp \
+       Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.h \
        Source/WebCore/platform/graphics/filters/DistantLightSource.cpp \
        Source/WebCore/platform/graphics/filters/DistantLightSource.h \
        Source/WebCore/platform/graphics/filters/FEBlend.cpp \
index 6396a66..f7359af 100644 (file)
@@ -2045,6 +2045,7 @@ HEADERS += \
     platform/graphics/filters/CustomFilterParameter.h \
     platform/graphics/filters/CustomFilterProgram.h \
     platform/graphics/filters/CustomFilterTransformParameter.h \
+    platform/graphics/filters/CustomFilterValidatedProgram.h \
     platform/graphics/filters/FEBlend.h \
     platform/graphics/filters/FEColorMatrix.h \
     platform/graphics/filters/FEComponentTransfer.h \
@@ -3440,6 +3441,7 @@ contains(DEFINES, ENABLE_FILTERS=1) {
         platform/graphics/filters/CustomFilterProgram.cpp \
         platform/graphics/filters/CustomFilterCompiledProgram.cpp \
         platform/graphics/filters/CustomFilterMesh.cpp \
+        platform/graphics/filters/CustomFilterValidatedProgram.cpp \
         platform/graphics/filters/DistantLightSource.cpp \
         platform/graphics/filters/FEBlend.cpp \
         platform/graphics/filters/FEColorMatrix.cpp \
index 4082d85..fc0f6dc 100644 (file)
         ['exclude', 'platform/LinkHash\\.cpp$'],
         ['exclude', 'platform/MIMETypeRegistry\\.cpp$'],
         ['exclude', 'platform/Theme\\.cpp$'],
-        ['exclude', 'platform/graphics/ANGLEWebKitBridge\\.(cpp|h)$'],
         # *NEON.cpp files need special compile options.
         # They are moved to the webcore_arm_neon target.
         ['exclude', 'platform/graphics/filters/arm/.*NEON\\.(cpp|h)'],
index 9d0dc34..c30d8fb 100644 (file)
             'platform/graphics/filters/CustomFilterProgramInfo.h',
             'platform/graphics/filters/CustomFilterCompiledProgram.cpp',
             'platform/graphics/filters/CustomFilterCompiledProgram.h',
+            'platform/graphics/filters/CustomFilterValidatedProgram.cpp',
+            'platform/graphics/filters/CustomFilterValidatedProgram.h',
             'platform/graphics/filters/CustomFilterMesh.cpp',
             'platform/graphics/filters/CustomFilterTransformParameter.h',
             'platform/graphics/filters/DistantLightSource.cpp',
index 894037c..f04940b 100755 (executable)
                                                >
                                        </File>
                                        <File
+                                               RelativePath="..\platform\graphics\filters\CustomFilterValidatedProgram.cpp"
+                                               >
+                                       </File>
+                                       <File
+                                               RelativePath="..\platform\graphics\filters\CustomFilterValidatedProgram.h"
+                                               >
+                                       </File>
+                                       <File
                                                RelativePath="..\platform\graphics\filters\DistantLightSource.cpp"
                                                >
                                        </File>
index 6810e35..8a4243f 100644 (file)
                A1E1154813015C5D0054AC8C /* SpotLightSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1E1154713015C5D0054AC8C /* SpotLightSource.cpp */; };
                A24BF77B15CC3BAF003191F2 /* WebKitCSSMixFunctionValue.h in Headers */ = {isa = PBXBuildFile; fileRef = A24BF77915CC3BAF003191F2 /* WebKitCSSMixFunctionValue.h */; };
                A24BF77C15CC3BAF003191F2 /* WebKitCSSMixFunctionValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A24BF77A15CC3BAF003191F2 /* WebKitCSSMixFunctionValue.cpp */; };
+               A29532CF15DD5E1700469EBC /* CustomFilterValidatedProgram.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A29532CD15DD5E1700469EBC /* CustomFilterValidatedProgram.cpp */; };
+               A29532D015DD5E1700469EBC /* CustomFilterValidatedProgram.h in Headers */ = {isa = PBXBuildFile; fileRef = A29532CE15DD5E1700469EBC /* CustomFilterValidatedProgram.h */; };
                A3BB59F31457A40D00AC56FE /* DocumentEventQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3BB59F11457A40D00AC56FE /* DocumentEventQueue.cpp */; };
                A3BB59F41457A40D00AC56FE /* DocumentEventQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = A3BB59F21457A40D00AC56FE /* DocumentEventQueue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A3E2643014748991005A8588 /* WorkerEventQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3E2642E14748991005A8588 /* WorkerEventQueue.cpp */; };
                A1E1154713015C5D0054AC8C /* SpotLightSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SpotLightSource.cpp; path = filters/SpotLightSource.cpp; sourceTree = "<group>"; };
                A24BF77915CC3BAF003191F2 /* WebKitCSSMixFunctionValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitCSSMixFunctionValue.h; sourceTree = "<group>"; };
                A24BF77A15CC3BAF003191F2 /* WebKitCSSMixFunctionValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebKitCSSMixFunctionValue.cpp; sourceTree = "<group>"; };
+               A29532CD15DD5E1700469EBC /* CustomFilterValidatedProgram.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CustomFilterValidatedProgram.cpp; path = filters/CustomFilterValidatedProgram.cpp; sourceTree = "<group>"; };
+               A29532CE15DD5E1700469EBC /* CustomFilterValidatedProgram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomFilterValidatedProgram.h; path = filters/CustomFilterValidatedProgram.h; sourceTree = "<group>"; };
                A3BB59F11457A40D00AC56FE /* DocumentEventQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentEventQueue.cpp; sourceTree = "<group>"; };
                A3BB59F21457A40D00AC56FE /* DocumentEventQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentEventQueue.h; sourceTree = "<group>"; };
                A3E2642E14748991005A8588 /* WorkerEventQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WorkerEventQueue.cpp; path = workers/WorkerEventQueue.cpp; sourceTree = "<group>"; };
                                503D0CA914B5B08700F32F57 /* CustomFilterProgramClient.h */,
                                50D88CB315BDFDAA001809F4 /* CustomFilterProgramInfo.cpp */,
                                50D88CB415BDFDAA001809F4 /* CustomFilterProgramInfo.h */,
+                               A29532CD15DD5E1700469EBC /* CustomFilterValidatedProgram.cpp */,
+                               A29532CE15DD5E1700469EBC /* CustomFilterValidatedProgram.h */,
                                A1E1154313015C3D0054AC8C /* DistantLightSource.cpp */,
                                84730D5A1248F0B300D3A9C9 /* DistantLightSource.h */,
                                A75E8B800E1DE2D6007F2481 /* FEBlend.cpp */,
                                503D0CAB14B5B08700F32F57 /* CustomFilterProgram.h in Headers */,
                                503D0CAC14B5B08700F32F57 /* CustomFilterProgramClient.h in Headers */,
                                50D88CB615BDFDAA001809F4 /* CustomFilterProgramInfo.h in Headers */,
+                               A29532D015DD5E1700469EBC /* CustomFilterValidatedProgram.h in Headers */,
                                A8CB413E0E8633FD0032C4F0 /* DashArray.h in Headers */,
                                A80E6D0B0A1989CA007FB8C5 /* DashboardRegion.h in Headers */,
                                97BC6A211505F081001B74AC /* Database.h in Headers */,
                                50CC0A3914C6F5B10017AB51 /* CustomFilterOperation.cpp in Sources */,
                                503D0CAA14B5B08700F32F57 /* CustomFilterProgram.cpp in Sources */,
                                50D88CB515BDFDAA001809F4 /* CustomFilterProgramInfo.cpp in Sources */,
+                               A29532CF15DD5E1700469EBC /* CustomFilterValidatedProgram.cpp in Sources */,
                                97BC6A201505F081001B74AC /* Database.cpp in Sources */,
                                97BC6A231505F081001B74AC /* DatabaseAuthorizer.cpp in Sources */,
                                97BC6A271505F081001B74AC /* DatabaseContext.cpp in Sources */,
index 78a0de4..5c528cf 100644 (file)
 
 namespace WebCore {
 
-ANGLEWebKitBridge::ANGLEWebKitBridge(ShShaderOutput shaderOutput) :
-    builtCompilers(false),
-    m_fragmentCompiler(0),
-    m_vertexCompiler(0),
-    m_shaderOutput(shaderOutput)
+ANGLEWebKitBridge::ANGLEWebKitBridge(ShShaderOutput shaderOutput, ShShaderSpec shaderSpec)
+    : builtCompilers(false)
+    , m_fragmentCompiler(0)
+    , m_vertexCompiler(0)
+    , m_shaderOutput(shaderOutput)
+    , m_shaderSpec(shaderSpec)
 {
+    // This is a no-op if it's already initialized.
     ShInitialize();
 }
 
@@ -69,8 +71,8 @@ void ANGLEWebKitBridge::setResources(ShBuiltInResources resources)
 bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog, int extraCompileOptions)
 {
     if (!builtCompilers) {
-        m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_WEBGL_SPEC, m_shaderOutput, &m_resources);
-        m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_WEBGL_SPEC, m_shaderOutput, &m_resources);
+        m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
+        m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, m_shaderSpec, m_shaderOutput, &m_resources);
         if (!m_fragmentCompiler || !m_vertexCompiler) {
             cleanupCompilers();
             return false;
index 834dcc9..05b0c38 100644 (file)
@@ -31,7 +31,7 @@
 
 #if PLATFORM(QT)
 #include "ANGLE/include/GLSLANG/ShaderLang.h"
-#elif !PLATFORM(GTK) && !PLATFORM(EFL) && !PLATFORM(BLACKBERRY)
+#elif !PLATFORM(GTK) && !PLATFORM(EFL) && !PLATFORM(BLACKBERRY) && !PLATFORM(CHROMIUM)
 #include "ANGLE/ShaderLang.h"
 #else
 #include "ShaderLang.h"
@@ -47,13 +47,13 @@ enum ANGLEShaderType {
 class ANGLEWebKitBridge {
 public:
 
-    ANGLEWebKitBridge(ShShaderOutput = SH_GLSL_OUTPUT);
+    ANGLEWebKitBridge(ShShaderOutput = SH_GLSL_OUTPUT, ShShaderSpec = SH_WEBGL_SPEC);
     ~ANGLEWebKitBridge();
     
     ShBuiltInResources getResources() { return m_resources; }
     void setResources(ShBuiltInResources);
     
-    bool validateShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog, int extraCompileOptions);
+    bool validateShaderSource(const char* shaderSource, ANGLEShaderType, String& translatedShaderSource, String& shaderValidationLog, int extraCompileOptions = 0);
 
 private:
 
@@ -65,6 +65,7 @@ private:
     ShHandle m_vertexCompiler;
 
     ShShaderOutput m_shaderOutput;
+    ShShaderSpec m_shaderSpec;
 
     ShBuiltInResources m_resources;
 };
index 106f34f..3c6959b 100644 (file)
 #include "CustomFilterCompiledProgram.h"
  
 #include "CustomFilterGlobalContext.h"
-#include "CustomFilterProgramInfo.h"
-#include "GraphicsContext3D.h"
 
 namespace WebCore {
 
-#define SHADER(Src) (ASCIILiteral(#Src))
-
-String CustomFilterCompiledProgram::defaultVertexShaderString()
-{
-    DEFINE_STATIC_LOCAL(String, vertexShaderString, SHADER(
-        precision mediump float;
-        attribute vec4 a_position;
-        attribute vec2 a_texCoord;
-        uniform mat4 u_projectionMatrix;
-        varying vec2 v_texCoord;
-        void main()
-        {
-            gl_Position = u_projectionMatrix * a_position;
-            v_texCoord = a_texCoord;
-        }
-    ));
-    return vertexShaderString;
-}
-
-String CustomFilterCompiledProgram::defaultFragmentShaderString()
-{
-    DEFINE_STATIC_LOCAL(String, fragmentShaderString, SHADER(
-        precision mediump float;
-        varying vec2 v_texCoord;
-        uniform sampler2D u_texture;
-        void main()
-        {
-            gl_FragColor = texture2D(u_texture, v_texCoord);
-        }
-    ));
-    return fragmentShaderString;
-}
-
-CustomFilterCompiledProgram::CustomFilterCompiledProgram(CustomFilterGlobalContext* globalContext, const CustomFilterProgramInfo& programInfo)
-    : m_globalContext(globalContext)
-    , m_context(globalContext->context())
-    , m_programInfo(programInfo)
+CustomFilterCompiledProgram::CustomFilterCompiledProgram(PassRefPtr<GraphicsContext3D> context, const String& validatedVertexShader, const String& validatedFragmentShader)
+    : m_context(context)
     , m_program(0)
     , m_positionAttribLocation(-1)
     , m_texAttribLocation(-1)
@@ -87,15 +50,16 @@ CustomFilterCompiledProgram::CustomFilterCompiledProgram(CustomFilterGlobalConte
     , m_samplerLocation(-1)
     , m_samplerSizeLocation(-1)
     , m_contentSamplerLocation(-1)
+    , m_internalTexCoordAttribLocation(-1)
     , m_isInitialized(false)
 {
     m_context->makeContextCurrent();
-    
-    Platform3DObject vertexShader = compileShader(GraphicsContext3D::VERTEX_SHADER, programInfo.vertexShaderString());
+
+    Platform3DObject vertexShader = compileShader(GraphicsContext3D::VERTEX_SHADER, validatedVertexShader);
     if (!vertexShader)
         return;
     
-    Platform3DObject fragmentShader = compileShader(GraphicsContext3D::FRAGMENT_SHADER, programInfo.fragmentShaderString());
+    Platform3DObject fragmentShader = compileShader(GraphicsContext3D::FRAGMENT_SHADER, validatedFragmentShader);
     if (!fragmentShader) {
         m_context->deleteShader(vertexShader);
         return;
@@ -114,26 +78,12 @@ CustomFilterCompiledProgram::CustomFilterCompiledProgram(CustomFilterGlobalConte
     m_isInitialized = true;
 }
 
-String CustomFilterCompiledProgram::getDefaultShaderString(GC3Denum shaderType)
-{
-    switch (shaderType) {
-    case GraphicsContext3D::VERTEX_SHADER:
-        return defaultVertexShaderString();
-    case GraphicsContext3D::FRAGMENT_SHADER:
-        return defaultFragmentShaderString();
-    default:
-        ASSERT_NOT_REACHED();
-        return String();
-    }
-}
-
 Platform3DObject CustomFilterCompiledProgram::compileShader(GC3Denum shaderType, const String& shaderString)
 {
+    ASSERT(!shaderString.isNull());
+
     Platform3DObject shader = m_context->createShader(shaderType);
-    if (shaderString.isNull())
-        m_context->shaderSource(shader, getDefaultShaderString(shaderType));
-    else
-        m_context->shaderSource(shader, shaderString);
+    m_context->shaderSource(shader, shaderString);
     m_context->compileShader(shader);
     
     int compiled = 0;
@@ -177,9 +127,14 @@ void CustomFilterCompiledProgram::initializeParameterLocations()
     m_tileSizeLocation = m_context->getUniformLocation(m_program, "u_tileSize");
     m_meshSizeLocation = m_context->getUniformLocation(m_program, "u_meshSize");
     m_projectionMatrixLocation = m_context->getUniformLocation(m_program, "u_projectionMatrix");
-    m_samplerLocation = m_context->getUniformLocation(m_program, "u_texture");
     m_samplerSizeLocation = m_context->getUniformLocation(m_program, "u_textureSize");
     m_contentSamplerLocation = m_context->getUniformLocation(m_program, "u_contentTexture");
+    m_internalTexCoordAttribLocation = m_context->getAttribLocation(m_program, "css_a_texCoord");
+    m_samplerLocation = m_context->getUniformLocation(m_program, "css_u_texture");
+    // FIXME: Remove texture access via u_texture and change the tests to use blending and compositing.
+    // https://bugs.webkit.org/show_bug.cgi?id=93871
+    if (m_samplerLocation == -1)
+        m_samplerLocation = m_context->getUniformLocation(m_program, "u_texture");
 }
 
 int CustomFilterCompiledProgram::uniformLocationByName(const String& name)
@@ -191,8 +146,6 @@ int CustomFilterCompiledProgram::uniformLocationByName(const String& name)
     
 CustomFilterCompiledProgram::~CustomFilterCompiledProgram()
 {
-    if (m_globalContext)
-        m_globalContext->removeCompiledProgram(this);
     if (m_program) {
         m_context->makeContextCurrent();
         m_context->deleteProgram(m_program);
index 44f3777..ad945f6 100644 (file)
 
 #if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
 
-#include "CustomFilterProgramInfo.h"
-#include "GraphicsTypes3D.h"
+#include "GraphicsContext3D.h"
 #include <wtf/RefCounted.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
 class CustomFilterGlobalContext;
-class GraphicsContext3D;
 
-// A specific combination of vertex / fragment shader is only going to be compiled once. The CustomFilterGlobalContext is 
-// caching the compiled programs. CustomFilterGlobalContext has a weak reference to the CustomFilterCompiledProgram, so the 
-// CustomFilterCompiledProgram destructor needs to notify the CustomFilterGlobalContext to remove the program from the cache.
-// FECustomFilter is the reference owner of the CustomFilterCompiledProgram, so a compiled shader is only kept alive as 
-// long as there is at least one visible layer that applies the shader.
 class CustomFilterCompiledProgram: public RefCounted<CustomFilterCompiledProgram> {
 public:
-    static PassRefPtr<CustomFilterCompiledProgram> create(CustomFilterGlobalContext* globalContext, const CustomFilterProgramInfo& programInfo)
+    static PassRefPtr<CustomFilterCompiledProgram> create(PassRefPtr<GraphicsContext3D> context, const String& validatedVertexShader, const String& validatedFragmentShader)
     {
-        return adoptRef(new CustomFilterCompiledProgram(globalContext, programInfo));
+        return adoptRef(new CustomFilterCompiledProgram(context, validatedVertexShader, validatedFragmentShader));
     }
     
     ~CustomFilterCompiledProgram();
-
-    const CustomFilterProgramInfo& programInfo() const { return m_programInfo; }
     
     int positionAttribLocation() const { return m_positionAttribLocation; }
     int texAttribLocation() const { return m_texAttribLocation; }
@@ -69,32 +60,26 @@ public:
     int samplerLocation() const { return m_samplerLocation; }
     int contentSamplerLocation() const { return m_contentSamplerLocation; }
     int samplerSizeLocation() const { return m_samplerSizeLocation; }
+    // FIXME: Get rid of the internal tex coord attribute "css_a_texCoord".
+    // If the author defined "a_texCoord", we should leverage that.
+    // If not, we should write "a_texCoord" in the shader.
+    // This requires us to first get the list of attributes from the vertex shader using ANGLE.
+    // https://bugs.webkit.org/show_bug.cgi?id=94358
+    int internalTexCoordAttribLocation() const { return m_internalTexCoordAttribLocation; }
 
     int uniformLocationByName(const String&);
     
     bool isInitialized() const { return m_isInitialized; }
     
     Platform3DObject program() const { return m_program; }
-
-    // 'detachGlobalContext' is called when the CustomFilterGlobalContext is deleted
-    // and there's no need for the callback anymore. 
-    // Note that CustomFilterGlobalContext doesn't not keep a strong reference to 
-    // the CustomFilterCompiledProgram.
-    void detachFromGlobalContext() { m_globalContext = 0; }
 private:
-    CustomFilterCompiledProgram(CustomFilterGlobalContext*, const CustomFilterProgramInfo&);
+    CustomFilterCompiledProgram(PassRefPtr<GraphicsContext3D>, const String& validatedVertexShader, const String& validatedFragmentShader);
     
     Platform3DObject compileShader(GC3Denum shaderType, const String& shaderString);
     Platform3DObject linkProgram(Platform3DObject vertexShader, Platform3DObject fragmentShader);
     void initializeParameterLocations();
     
-    static String defaultVertexShaderString();
-    static String defaultFragmentShaderString();
-    String getDefaultShaderString(GC3Denum shaderType);
-    
-    CustomFilterGlobalContext* m_globalContext;
     RefPtr<GraphicsContext3D> m_context;
-    CustomFilterProgramInfo m_programInfo;
     Platform3DObject m_program;
     
     int m_positionAttribLocation;
@@ -108,6 +93,9 @@ private:
     int m_samplerLocation;
     int m_samplerSizeLocation;
     int m_contentSamplerLocation;
+    // FIXME: Get rid of the internal tex coord attribute "css_a_texCoord".
+    // https://bugs.webkit.org/show_bug.cgi?id=94358
+    int m_internalTexCoordAttribLocation;
     
     bool m_isInitialized;
 };
index 382c278..e0144b9 100644 (file)
@@ -32,7 +32,7 @@
 #if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
 #include "CustomFilterGlobalContext.h"
 
-#include "CustomFilterCompiledProgram.h"
+#include "CustomFilterValidatedProgram.h"
 #include "GraphicsContext3D.h"
 
 namespace WebCore {
@@ -43,10 +43,33 @@ CustomFilterGlobalContext::CustomFilterGlobalContext()
 
 CustomFilterGlobalContext::~CustomFilterGlobalContext()
 {
-    for (CustomFilterCompiledProgramsMap::iterator iter = m_programs.begin(); iter != m_programs.end(); ++iter)
+    for (CustomFilterValidatedProgramsMap::iterator iter = m_programs.begin(); iter != m_programs.end(); ++iter)
         iter->second->detachFromGlobalContext();
 }
 
+ANGLEWebKitBridge* CustomFilterGlobalContext::webglShaderValidator()
+{
+    if (!m_webglShaderValidator)
+        m_webglShaderValidator = createShaderValidator(SH_WEBGL_SPEC);
+    return m_webglShaderValidator.get();
+}
+
+ANGLEWebKitBridge* CustomFilterGlobalContext::mixShaderValidator()
+{
+    if (!m_mixShaderValidator)
+        m_mixShaderValidator = createShaderValidator(SH_CSS_SHADERS_SPEC);
+    return m_mixShaderValidator.get();
+}
+
+PassOwnPtr<ANGLEWebKitBridge> CustomFilterGlobalContext::createShaderValidator(ShShaderSpec shaderSpec)
+{
+    OwnPtr<ANGLEWebKitBridge> validator = adoptPtr(new ANGLEWebKitBridge(SH_ESSL_OUTPUT, shaderSpec));
+    ShBuiltInResources resources;
+    ShInitBuiltInResources(&resources);
+    validator->setResources(resources);
+    return validator.release();
+}
+
 void CustomFilterGlobalContext::prepareContextIfNeeded(HostWindow* hostWindow)
 {
     if (m_context.get())
@@ -62,23 +85,23 @@ void CustomFilterGlobalContext::prepareContextIfNeeded(HostWindow* hostWindow)
     m_context->enable(GraphicsContext3D::DEPTH_TEST);
 }
 
-PassRefPtr<CustomFilterCompiledProgram> CustomFilterGlobalContext::getCompiledProgram(const CustomFilterProgramInfo& programInfo)
+PassRefPtr<CustomFilterValidatedProgram> CustomFilterGlobalContext::getValidatedProgram(const CustomFilterProgramInfo& programInfo)
 {
     // Check that the context is already prepared.
     ASSERT(m_context);
 
-    CustomFilterCompiledProgramsMap::iterator iter = m_programs.find(programInfo);
+    CustomFilterValidatedProgramsMap::iterator iter = m_programs.find(programInfo);
     if (iter != m_programs.end())
         return iter->second;
 
-    RefPtr<CustomFilterCompiledProgram> compiledProgram = CustomFilterCompiledProgram::create(this, programInfo);
-    m_programs.set(programInfo, compiledProgram.get());
-    return compiledProgram.release();
+    RefPtr<CustomFilterValidatedProgram> validatedProgram = CustomFilterValidatedProgram::create(this, programInfo);
+    m_programs.set(programInfo, validatedProgram.get());
+    return validatedProgram.release();
 }
 
-void CustomFilterGlobalContext::removeCompiledProgram(const CustomFilterCompiledProgram* program)
+void CustomFilterGlobalContext::removeValidatedProgram(const CustomFilterValidatedProgram* program)
 {
-    CustomFilterCompiledProgramsMap::iterator iter = m_programs.find(program->programInfo());
+    CustomFilterValidatedProgramsMap::iterator iter = m_programs.find(program->programInfo());
     ASSERT(iter != m_programs.end());
     m_programs.remove(iter);
 
index 8dc85f2..ae0271f 100644 (file)
 #define CustomFilterGlobalContext_h
 
 #if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
+#include "ANGLEWebKitBridge.h"
 #include "CustomFilterProgramInfo.h"
 #include <wtf/HashMap.h>
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
 
-class CustomFilterCompiledProgram;
+class CustomFilterValidatedProgram;
 class HostWindow;
 class GraphicsContext3D;
 
-typedef HashMap<CustomFilterProgramInfo, CustomFilterCompiledProgram*> CustomFilterCompiledProgramsMap;
+typedef HashMap<CustomFilterProgramInfo, CustomFilterValidatedProgram*> CustomFilterValidatedProgramsMap;
 
 class CustomFilterGlobalContext {
 public:
@@ -49,14 +50,32 @@ public:
     ~CustomFilterGlobalContext();
     
     GraphicsContext3D* context() const { return m_context.get(); }
+
+    // CSS shaders not referenced from the CSS mix function should be validated just like regular WebGL shaders.
+    // This ANGLE validator uses the SH_WEBGL_SPEC flag.
+    ANGLEWebKitBridge* webglShaderValidator();
+
+    // CSS shaders referenced from the CSS mix function should be validated slightly differently than WebGL shaders.
+    // This ANGLE validator uses the SH_CSS_SHADERS_SPEC flag.
+    // Under this flag, most notably:
+    // - The "gl_FragColor" built-in is not available.
+    // - Instead, the "css_MixColor" and "css_ColorMatrix" built-ins are available.
+    // - The "css_" prefix is reserved.
+    // - In the translated source that ANGLE returns, ANGLE renames the author's "main" function to "css_main".
+    // The complete details are documented in ANGLE/ShaderLang.h.
+    ANGLEWebKitBridge* mixShaderValidator();
     
     void prepareContextIfNeeded(HostWindow*);
 
-    PassRefPtr<CustomFilterCompiledProgram> getCompiledProgram(const CustomFilterProgramInfo&);
-    void removeCompiledProgram(const CustomFilterCompiledProgram*);
+    PassRefPtr<CustomFilterValidatedProgram> getValidatedProgram(const CustomFilterProgramInfo&);
+    void removeValidatedProgram(const CustomFilterValidatedProgram*);
 private:
+    static PassOwnPtr<ANGLEWebKitBridge> createShaderValidator(ShShaderSpec);
+
     RefPtr<GraphicsContext3D> m_context;
-    CustomFilterCompiledProgramsMap m_programs;
+    OwnPtr<ANGLEWebKitBridge> m_webglShaderValidator;
+    OwnPtr<ANGLEWebKitBridge> m_mixShaderValidator;
+    CustomFilterValidatedProgramsMap m_programs;
 };
 
 } // namespace WebCore
index e1f4559..7c6e1f4 100644 (file)
@@ -75,6 +75,7 @@ public:
 
     const String& vertexShaderString() const { return m_vertexShaderString; }
     const String& fragmentShaderString() const { return m_fragmentShaderString; }
+    const CustomFilterProgramMixSettings& mixSettings() const { return m_mixSettings; }
 private:
     String m_vertexShaderString;
     String m_fragmentShaderString;
diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.cpp b/Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.cpp
new file mode 100644 (file)
index 0000000..9964c5c
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(CSS_SHADERS)
+
+#include "CustomFilterValidatedProgram.h"
+
+#include "ANGLEWebKitBridge.h"
+#include "CustomFilterGlobalContext.h"
+#include "CustomFilterProgramInfo.h"
+#include "NotImplemented.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+#define SHADER(Src) (#Src) 
+
+String CustomFilterValidatedProgram::defaultVertexShaderString()
+{
+    DEFINE_STATIC_LOCAL(String, vertexShaderString, (ASCIILiteral(SHADER(
+        attribute mediump vec4 a_position;
+        uniform mediump mat4 u_projectionMatrix;
+
+        void main()
+        {
+            gl_Position = u_projectionMatrix * a_position;
+        }
+    ))));
+    return vertexShaderString;
+}
+
+String CustomFilterValidatedProgram::defaultFragmentShaderString()
+{
+    DEFINE_STATIC_LOCAL(String, fragmentShaderString, (ASCIILiteral(SHADER(
+        void main()
+        {
+        }
+    ))));
+    return fragmentShaderString;
+}
+
+CustomFilterValidatedProgram::CustomFilterValidatedProgram(CustomFilterGlobalContext* globalContext, const CustomFilterProgramInfo& programInfo)
+    : m_globalContext(globalContext)
+    , m_programInfo(programInfo)
+    , m_isInitialized(false)
+{
+    String originalVertexShader = programInfo.vertexShaderString();
+    if (originalVertexShader.isNull())
+        originalVertexShader = defaultVertexShaderString();
+
+    String originalFragmentShader = programInfo.fragmentShaderString();
+    if (originalFragmentShader.isNull())
+        originalFragmentShader = defaultFragmentShaderString();
+
+    // Shaders referenced from the CSS mix function use a different validator than regular WebGL shaders. See CustomFilterGlobalContext.h for more details.
+    ANGLEWebKitBridge* validator = programInfo.mixSettings().enabled ? m_globalContext->mixShaderValidator() : m_globalContext->webglShaderValidator();
+    String vertexShaderLog, fragmentShaderLog;
+    bool vertexShaderValid = validator->validateShaderSource(originalVertexShader.utf8().data(), SHADER_TYPE_VERTEX, m_validatedVertexShader, vertexShaderLog);
+    bool fragmentShaderValid = validator->validateShaderSource(originalFragmentShader.utf8().data(), SHADER_TYPE_FRAGMENT, m_validatedFragmentShader, fragmentShaderLog);
+    if (!vertexShaderValid || !fragmentShaderValid) {
+        // FIXME: Report the validation errors.
+        // https://bugs.webkit.org/show_bug.cgi?id=74416
+        return;
+    }
+
+    // We need to add texture access, blending, and compositing code to shaders that are referenced from the CSS mix function.
+    if (programInfo.mixSettings().enabled) {
+        rewriteMixVertexShader();
+        rewriteMixFragmentShader();
+    }
+
+    m_isInitialized = true;
+}
+
+PassRefPtr<CustomFilterCompiledProgram> CustomFilterValidatedProgram::compiledProgram()
+{
+    ASSERT(m_isInitialized && !m_validatedVertexShader.isNull() && !m_validatedFragmentShader.isNull());
+    if (!m_compiledProgram)
+        m_compiledProgram = CustomFilterCompiledProgram::create(m_globalContext->context(), m_validatedVertexShader, m_validatedFragmentShader);
+    return m_compiledProgram;
+}
+
+void CustomFilterValidatedProgram::rewriteMixVertexShader()
+{
+    ASSERT(m_programInfo.mixSettings().enabled);
+
+    // During validation, ANGLE renamed the author's "main" function to "css_main".
+    // We write our own "main" function and call "css_main" from it.
+    // This makes rewriting easy and ensures that our code runs after all author code.
+    m_validatedVertexShader += SHADER(
+        attribute mediump vec2 css_a_texCoord;
+        varying mediump vec2 css_v_texCoord;
+
+        void main()
+        {
+            css_main();
+            css_v_texCoord = css_a_texCoord;
+        }
+    );
+}
+
+void CustomFilterValidatedProgram::rewriteMixFragmentShader()
+{
+    ASSERT(m_programInfo.mixSettings().enabled);
+
+    StringBuilder builder;
+    // ANGLE considered these symbols as built-ins during validation under the SH_CSS_SHADERS_SPEC flag.
+    // Now, we have to define these symbols in order to make this shader valid GLSL.
+    // We define these symbols before the author's shader code, which makes them accessible to author code.
+    builder.append(SHADER(
+        mediump vec4 css_MixColor = vec4(0.0);
+        mediump mat4 css_ColorMatrix = mat4(1.0);
+    ));
+    builder.append(m_validatedFragmentShader);
+    builder.append(blendFunctionString(m_programInfo.mixSettings().blendMode));
+    builder.append(compositeFunctionString(m_programInfo.mixSettings().compositeOperator));
+    // We define symbols like "css_u_texture" after the author's shader code, which makes them inaccessible to author code.
+    // In particular, "css_u_texture" represents the DOM element texture, so it's important to keep it inaccessible to
+    // author code for security reasons.
+    builder.append(SHADER(
+        uniform sampler2D css_u_texture;
+        varying mediump vec2 css_v_texCoord;
+
+        void main()
+        {
+            css_main();
+            mediump vec4 originalColor = texture2D(css_u_texture, css_v_texCoord);
+            mediump vec4 multipliedColor = css_ColorMatrix * originalColor;
+            mediump vec3 blendedColor = css_Blend(multipliedColor.rgb, css_MixColor.rgb);
+            gl_FragColor = css_Composite(multipliedColor.rgb, multipliedColor.a, blendedColor.rgb, css_MixColor.a);
+        }
+    ));
+    m_validatedFragmentShader = builder.toString();
+}
+
+String CustomFilterValidatedProgram::blendFunctionString(BlendMode blendMode)
+{
+    // Implemented using the same symbol names as the Compositing and Blending spec:
+    // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnormal
+    // Cs: is the source color
+    // Cb: is the backdrop color
+    const char* expression = 0;
+    switch (blendMode) {
+    case BlendModeNormal:
+        expression = "Cs";
+        break;
+    case BlendModeMultiply:
+    case BlendModeScreen:
+    case BlendModeOverlay:
+    case BlendModeDarken:
+    case BlendModeLighten:
+    case BlendModeColorDodge:
+    case BlendModeColorBurn:
+    case BlendModeHardLight:
+    case BlendModeSoftLight:
+    case BlendModeDifference:
+    case BlendModeExclusion:
+    case BlendModeHue:
+    case BlendModeSaturation:
+    case BlendModeColor:
+    case BlendModeLuminosity:
+        notImplemented();
+        return String();
+    }
+
+    ASSERT(expression);
+    return String::format(SHADER(
+        mediump vec3 css_Blend(mediump vec3 Cb, mediump vec3 Cs)
+        {
+            return %s;
+        }
+    ), expression);
+}
+
+String CustomFilterValidatedProgram::compositeFunctionString(CompositeOperator compositeOperator)
+{
+    // Use the same symbol names as the Compositing and Blending spec:
+    // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnormal
+    // Cs: is the source color
+    // Cb: is the backdrop color
+    // as: is the source alpha
+    // ab: is the backdrop alpha
+    // Fa: is defined by the Porter Duff operator in use
+    // Fb: is defined by the Porter Duff operator in use
+    const char* Fa = 0;
+    const char* Fb = 0;
+    switch (compositeOperator) {
+    case CompositeSourceAtop:
+        Fa = "ab";
+        Fb = "1.0 - as";
+        break;
+    case CompositeClear:
+    case CompositeCopy:
+    case CompositeSourceOver:
+    case CompositeSourceIn:
+    case CompositeSourceOut:
+    case CompositeDestinationOver:
+    case CompositeDestinationIn:
+    case CompositeDestinationOut:
+    case CompositeDestinationAtop:
+    case CompositeXOR:
+    case CompositePlusLighter:
+        notImplemented();
+        return String();
+    default:
+        // The CSS parser should not have accepted any other composite operators.
+        ASSERT_NOT_REACHED();
+        return String();
+    }
+
+    ASSERT(Fa && Fb);
+    // Use the general formula for compositing, lifted from the spec:
+    // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#generalformula
+    return String::format(SHADER(
+        mediump vec4 css_Composite(mediump vec3 Cb, mediump float ab, mediump vec3 Cs, mediump float as)
+        {
+            mediump float Fa = %s;
+            mediump float Fb = %s;
+            return vec4(as * Fa * Cs + ab * Fb * Cb, as * Fa + ab * Fb); 
+        }
+    ), Fa, Fb);
+}
+    
+CustomFilterValidatedProgram::~CustomFilterValidatedProgram()
+{
+    if (m_globalContext)
+        m_globalContext->removeValidatedProgram(this);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SHADERS)
diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.h b/Source/WebCore/platform/graphics/filters/CustomFilterValidatedProgram.h
new file mode 100644 (file)
index 0000000..3a9e0f1
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CustomFilterValidatedProgram_h
+#define CustomFilterValidatedProgram_h
+
+#if ENABLE(CSS_SHADERS)
+
+#include "CustomFilterCompiledProgram.h"
+#include "CustomFilterProgramInfo.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class ANGLEWebKitBridge;
+class CustomFilterCompiledProgram;
+class CustomFilterGlobalContext;
+
+//
+// A unique combination of vertex shader and fragment shader is only validated and compiled once.
+// All shaders are validated through ANGLE in CustomFilterValidatedProgram before being compiled by the GraphicsContext3D in CustomFilterCompiledProgram.
+// For shaders that use the CSS mix function, CustomFilterValidatedProgram adds shader code to perform DOM texture access, blending, and compositing.
+//
+// The CustomFilterGlobalContext caches the validated programs.
+// CustomFilterValidatedProgram owns a CustomFilterCompiledProgram if validation and compilation succeeds.
+// Thus, compiled programs are cached via their validated program owners.
+//
+// CustomFilterGlobalContext has a weak reference to the CustomFilterValidatedProgram.
+// Thus, the CustomFilterValidatedProgram destructor needs to notify the CustomFilterGlobalContext to remove the program from the cache.
+// FECustomFilter is the reference owner of the CustomFilterValidatedProgram.
+// Thus, a validated and compiled shader is only kept alive as long as there is at least one visible layer that applies the shader.
+//
+class CustomFilterValidatedProgram : public RefCounted<CustomFilterValidatedProgram> {
+public:
+    static PassRefPtr<CustomFilterValidatedProgram> create(CustomFilterGlobalContext* globalContext, const CustomFilterProgramInfo& programInfo)
+    {
+        return adoptRef(new CustomFilterValidatedProgram(globalContext, programInfo));
+    }
+
+    ~CustomFilterValidatedProgram();
+
+    const CustomFilterProgramInfo& programInfo() const { return m_programInfo; }
+    PassRefPtr<CustomFilterCompiledProgram> compiledProgram();
+
+    bool isInitialized() const { return m_isInitialized; }
+
+    // 'detachFromGlobalContext' is called when the CustomFilterGlobalContext is deleted, and there's no need for the callback anymore. 
+    // Note that CustomFilterGlobalContext does not keep a strong reference to the CustomFilterValidatedProgram.
+    void detachFromGlobalContext() { m_globalContext = 0; }
+private:
+    CustomFilterValidatedProgram(CustomFilterGlobalContext*, const CustomFilterProgramInfo&);
+
+    static String defaultVertexShaderString();
+    static String defaultFragmentShaderString();
+
+    static String blendFunctionString(BlendMode);
+    static String compositeFunctionString(CompositeOperator);
+
+    void rewriteMixVertexShader();
+    void rewriteMixFragmentShader();
+
+    CustomFilterGlobalContext* m_globalContext;
+    CustomFilterProgramInfo m_programInfo;
+
+    String m_validatedVertexShader;
+    String m_validatedFragmentShader;
+
+    RefPtr<CustomFilterCompiledProgram> m_compiledProgram;
+
+    bool m_isInitialized;
+};
+
+}
+
+#endif // ENABLE(CSS_SHADERS)
+
+#endif
index dfc279b..fb67e22 100644 (file)
@@ -39,6 +39,7 @@
 #include "CustomFilterParameter.h"
 #include "CustomFilterProgram.h"
 #include "CustomFilterTransformParameter.h"
+#include "CustomFilterValidatedProgram.h"
 #include "DrawingBuffer.h"
 #include "GraphicsContext3D.h"
 #include "ImageData.h"
@@ -75,27 +76,30 @@ static void orthogonalProjectionMatrix(TransformationMatrix& matrix, float left,
     matrix.setM44(1.0f);
 }
 
-FECustomFilter::FECustomFilter(Filter* filter, CustomFilterGlobalContext* customFilterGlobalContext, PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& parameters,
+FECustomFilter::FECustomFilter(Filter* filter, CustomFilterGlobalContext* customFilterGlobalContext, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters,
                                unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType,
                                CustomFilterOperation::MeshType meshType)
     : FilterEffect(filter)
     , m_globalContext(customFilterGlobalContext)
+    , m_validatedProgram(validatedProgram)
+    , m_compiledProgram(0) // Don't compile the program unless we need to paint.
     , m_frameBuffer(0)
     , m_depthBuffer(0)
     , m_destTexture(0)
-    , m_program(program)
     , m_parameters(parameters)
     , m_meshRows(meshRows)
     , m_meshColumns(meshColumns)
     , m_meshType(meshType)
 {
+    // An FECustomFilter shouldn't have been created unless the program passed validation.
+    ASSERT(m_validatedProgram->isInitialized());
 }
 
-PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, CustomFilterGlobalContext* customFilterGlobalContext, PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& parameters,
+PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, CustomFilterGlobalContext* customFilterGlobalContext, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters,
                                            unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType meshBoxType,
                                            CustomFilterOperation::MeshType meshType)
 {
-    return adoptRef(new FECustomFilter(filter, customFilterGlobalContext, program, parameters, meshRows, meshColumns, meshBoxType, meshType));
+    return adoptRef(new FECustomFilter(filter, customFilterGlobalContext, validatedProgram, parameters, meshRows, meshColumns, meshBoxType, meshType));
 }
 
 FECustomFilter::~FECustomFilter()
@@ -196,7 +200,7 @@ bool FECustomFilter::initializeContext()
     if (!m_context)
         return false;
     m_context->makeContextCurrent();
-    m_compiledProgram = m_globalContext->getCompiledProgram(m_program->programInfo());
+    m_compiledProgram = m_validatedProgram->compiledProgram();
 
     // FIXME: Sharing the mesh would just save the time needed to upload it to the GPU, so I assume we could
     // benchmark that for performance.
@@ -241,13 +245,12 @@ void FECustomFilter::resizeContext(const IntSize& newContextSize)
     m_contextSize = newContextSize;
 }
 
-void FECustomFilter::bindVertexAttribute(int attributeLocation, unsigned size, unsigned& offset)
+void FECustomFilter::bindVertexAttribute(int attributeLocation, unsigned size, unsigned offset)
 {
     if (attributeLocation != -1) {
         m_context->vertexAttribPointer(attributeLocation, size, GraphicsContext3D::FLOAT, false, m_mesh->bytesPerVertex(), offset);
         m_context->enableVertexAttribArray(attributeLocation);
     }
-    offset += size * sizeof(float);
 }
 
 void FECustomFilter::bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter* numberParameter)
@@ -313,6 +316,8 @@ void FECustomFilter::bindProgramParameters()
 
 void FECustomFilter::bindProgramAndBuffers(Uint8ClampedArray* srcPixelArray)
 {
+    ASSERT(m_compiledProgram->isInitialized());
+
     m_context->useProgram(m_compiledProgram->program());
     
     if (m_compiledProgram->samplerLocation() != -1) {
@@ -337,12 +342,26 @@ void FECustomFilter::bindProgramAndBuffers(Uint8ClampedArray* srcPixelArray)
     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_mesh->verticesBufferObject());
     m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject());
 
-    unsigned offset = 0;
-    bindVertexAttribute(m_compiledProgram->positionAttribLocation(), 4, offset);
-    bindVertexAttribute(m_compiledProgram->texAttribLocation(), 2, offset);
-    bindVertexAttribute(m_compiledProgram->meshAttribLocation(), 2, offset);
+    // FIXME: Ideally, these should be public members of CustomFilterMesh.
+    // https://bugs.webkit.org/show_bug.cgi?id=94755
+    static const unsigned PositionAttribSize = 4;
+    static const unsigned TexAttribSize = 2;
+    static const unsigned MeshAttribSize = 2;
+    static const unsigned TriangleAttribSize = 3;
+
+    static const unsigned PositionAttribOffset = 0;
+    static const unsigned TexAttribOffset = PositionAttribOffset + PositionAttribSize * sizeof(float);
+    static const unsigned MeshAttribOffset = TexAttribOffset + TexAttribSize * sizeof(float);
+    static const unsigned TriangleAttribOffset = MeshAttribOffset + MeshAttribSize * sizeof(float);
+
+    bindVertexAttribute(m_compiledProgram->positionAttribLocation(), PositionAttribSize, PositionAttribOffset);
+    bindVertexAttribute(m_compiledProgram->texAttribLocation(), TexAttribSize, TexAttribOffset);
+    // FIXME: Get rid of the internal tex coord attribute "css_a_texCoord". 
+    // https://bugs.webkit.org/show_bug.cgi?id=94358
+    bindVertexAttribute(m_compiledProgram->internalTexCoordAttribLocation(), TexAttribSize, TexAttribOffset);
+    bindVertexAttribute(m_compiledProgram->meshAttribLocation(), MeshAttribSize, MeshAttribOffset);
     if (m_meshType == CustomFilterOperation::DETACHED)
-        bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), 3, offset);
+        bindVertexAttribute(m_compiledProgram->triangleAttribLocation(), TriangleAttribSize, TriangleAttribOffset);
     
     bindProgramParameters();
 }
index 8687bcf..506a538 100644 (file)
@@ -51,6 +51,7 @@ class CustomFilterMesh;
 class CustomFilterNumberParameter;
 class CustomFilterProgram;
 class CustomFilterTransformParameter;
+class CustomFilterValidatedProgram;
 class DrawingBuffer;
 class GraphicsContext3D;
 class IntSize;
@@ -58,7 +59,7 @@ class Texture;
 
 class FECustomFilter : public FilterEffect {
 public:
-    static PassRefPtr<FECustomFilter> create(Filter*, CustomFilterGlobalContext*, PassRefPtr<CustomFilterProgram>, const CustomFilterParameterList&,
+    static PassRefPtr<FECustomFilter> create(Filter*, CustomFilterGlobalContext*, PassRefPtr<CustomFilterValidatedProgram>, const CustomFilterParameterList&,
                    unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType, 
                    CustomFilterOperation::MeshType);
 
@@ -68,7 +69,7 @@ public:
     virtual TextStream& externalRepresentation(TextStream&, int indention) const;
 
 private:
-    FECustomFilter(Filter*, CustomFilterGlobalContext*, PassRefPtr<CustomFilterProgram>, const CustomFilterParameterList&,
+    FECustomFilter(Filter*, CustomFilterGlobalContext*, PassRefPtr<CustomFilterValidatedProgram>, const CustomFilterParameterList&,
                    unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType, 
                    CustomFilterOperation::MeshType);
     ~FECustomFilter();
@@ -78,7 +79,7 @@ private:
     bool initializeContext();
     void deleteRenderBuffers();
     void resizeContext(const IntSize& newContextSize);
-    void bindVertexAttribute(int attributeLocation, unsigned size, unsigned& offset);
+    void bindVertexAttribute(int attributeLocation, unsigned size, unsigned offset);
     void bindProgramNumberParameters(int uniformLocation, CustomFilterNumberParameter*);
     void bindProgramTransformParameter(int uniformLocation, CustomFilterTransformParameter*);
     void bindProgramParameters();
@@ -89,6 +90,7 @@ private:
     
     RefPtr<GraphicsContext3D> m_context;
     RefPtr<Texture> m_inputTexture;
+    RefPtr<CustomFilterValidatedProgram> m_validatedProgram;
     RefPtr<CustomFilterCompiledProgram> m_compiledProgram;
     RefPtr<CustomFilterMesh> m_mesh;
     IntSize m_contextSize;
index f551380..78ed248 100644 (file)
@@ -46,6 +46,7 @@
 #include "CustomFilterGlobalContext.h"
 #include "CustomFilterProgram.h"
 #include "CustomFilterOperation.h"
+#include "CustomFilterValidatedProgram.h"
 #include "FECustomFilter.h"
 #include "RenderView.h"
 #include "Settings.h"
@@ -90,6 +91,26 @@ static bool isCSSCustomFilterEnabled(Document* document)
     Settings* settings = document->settings();
     return settings && settings->isCSSCustomFilterEnabled() && settings->webGLEnabled();
 }
+
+static PassRefPtr<FECustomFilter> createCustomFilterEffect(Filter* filter, Document* document, CustomFilterOperation* operation)
+{
+    if (!isCSSCustomFilterEnabled(document))
+        return 0;
+    
+    RefPtr<CustomFilterProgram> program = operation->program();
+    if (!program->isLoaded())
+        return 0;
+
+    CustomFilterGlobalContext* globalContext = document->renderView()->customFilterGlobalContext();
+    globalContext->prepareContextIfNeeded(document->view()->hostWindow());
+    RefPtr<CustomFilterValidatedProgram> validatedProgram = globalContext->getValidatedProgram(program->programInfo());
+    if (!validatedProgram->isInitialized())
+        return 0;
+
+    return FECustomFilter::create(filter, globalContext, validatedProgram, operation->parameters(),
+                                  operation->meshRows(), operation->meshColumns(),
+                                  operation->meshBoxType(), operation->meshType());
+}
 #endif
 
 FilterEffectRenderer::FilterEffectRenderer()
@@ -323,23 +344,12 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope
                                                 dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1);
             break;
         }
-#if ENABLE(CSS_SHADERS)
+#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
         case FilterOperation::CUSTOM: {
-#if ENABLE(WEBGL)
-            if (!isCSSCustomFilterEnabled(document))
-                continue;
-            
             CustomFilterOperation* customFilterOperation = static_cast<CustomFilterOperation*>(filterOperation);
-            RefPtr<CustomFilterProgram> program = customFilterOperation->program();
-            if (program->isLoaded()) {
-                CustomFilterGlobalContext* globalContext = document->renderView()->customFilterGlobalContext();
-                globalContext->prepareContextIfNeeded(document->view()->hostWindow());
-                effect = FECustomFilter::create(this, globalContext, program, customFilterOperation->parameters(),
-                                                customFilterOperation->meshRows(), customFilterOperation->meshColumns(),
-                                                customFilterOperation->meshBoxType(), customFilterOperation->meshType());
+            effect = createCustomFilterEffect(this, document, customFilterOperation);
+            if (effect)
                 m_hasCustomShaderFilter = true;
-            }
-#endif
             break;
         }
 #endif
index 5c92c51..caeeda9 100644 (file)
@@ -112,7 +112,7 @@ public:
     bool hasFilterThatMovesPixels() const { return m_hasFilterThatMovesPixels; }
     LayoutRect computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect);
 
-#if ENABLE(CSS_SHADERS)
+#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL)
     bool hasCustomShaderFilter() const { return m_hasCustomShaderFilter; }
 #endif
 private: