Home | History | Annotate | Download | only in custom
      1 /*
      2  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1. Redistributions of source code must retain the above
      9  *    copyright notice, this list of conditions and the following
     10  *    disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above
     12  *    copyright notice, this list of conditions and the following
     13  *    disclaimer in the documentation and/or other materials
     14  *    provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AS IS AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
     20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
     21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
     25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
     26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 #include "config.h"
     31 #include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h"
     32 
     33 #include "platform/NotImplemented.h"
     34 #include "platform/graphics/angle/ANGLEPlatformBridge.h"
     35 #include "platform/graphics/filters/custom/CustomFilterConstants.h"
     36 #include "platform/graphics/filters/custom/CustomFilterGlobalContext.h"
     37 #include "wtf/HashMap.h"
     38 #include "wtf/Vector.h"
     39 #include "wtf/text/StringBuilder.h"
     40 #include "wtf/text/StringHash.h"
     41 
     42 namespace WebCore {
     43 
     44 #define SHADER(Src) (#Src)
     45 
     46 typedef HashMap<String, ShDataType> SymbolNameToTypeMap;
     47 
     48 static SymbolNameToTypeMap* builtInAttributeNameToTypeMap()
     49 {
     50     static SymbolNameToTypeMap* nameToTypeMap = 0;
     51     if (!nameToTypeMap) {
     52         nameToTypeMap = new SymbolNameToTypeMap;
     53         nameToTypeMap->set("a_meshCoord", SH_FLOAT_VEC2);
     54         nameToTypeMap->set("a_position", SH_FLOAT_VEC4);
     55         nameToTypeMap->set("a_texCoord", SH_FLOAT_VEC2);
     56         nameToTypeMap->set("a_triangleCoord", SH_FLOAT_VEC3);
     57     }
     58     return nameToTypeMap;
     59 }
     60 
     61 static SymbolNameToTypeMap* builtInUniformNameToTypeMap()
     62 {
     63     static SymbolNameToTypeMap* nameToTypeMap = 0;
     64     if (!nameToTypeMap) {
     65         nameToTypeMap = new SymbolNameToTypeMap;
     66         nameToTypeMap->set("u_meshBox", SH_FLOAT_VEC4);
     67         nameToTypeMap->set("u_meshSize", SH_FLOAT_VEC2);
     68         nameToTypeMap->set("u_projectionMatrix", SH_FLOAT_MAT4);
     69         nameToTypeMap->set("u_textureSize", SH_FLOAT_VEC2);
     70         nameToTypeMap->set("u_tileSize", SH_FLOAT_VEC2);
     71     }
     72     return nameToTypeMap;
     73 }
     74 
     75 static bool validateSymbols(const Vector<ANGLEShaderSymbol>& symbols, CustomFilterMeshType meshType)
     76 {
     77     for (size_t i = 0; i < symbols.size(); ++i) {
     78         const ANGLEShaderSymbol& symbol = symbols[i];
     79         switch (symbol.symbolType) {
     80         case SHADER_SYMBOL_TYPE_ATTRIBUTE: {
     81             SymbolNameToTypeMap* attributeNameToTypeMap = builtInAttributeNameToTypeMap();
     82             SymbolNameToTypeMap::iterator builtInAttribute = attributeNameToTypeMap->find(symbol.name);
     83             if (builtInAttribute == attributeNameToTypeMap->end()) {
     84                 // The author defined a custom attribute.
     85                 // FIXME: Report the validation error.
     86                 // https://bugs.webkit.org/show_bug.cgi?id=74416
     87                 return false;
     88             }
     89             if (meshType == MeshTypeAttached && symbol.name == "a_triangleCoord") {
     90                 // a_triangleCoord is only available for detached meshes.
     91                 // FIXME: Report the validation error.
     92                 // https://bugs.webkit.org/show_bug.cgi?id=74416
     93                 return false;
     94             }
     95             if (symbol.dataType != builtInAttribute->value) {
     96                 // The author defined one of the built-in attributes with the wrong type.
     97                 // FIXME: Report the validation error.
     98                 // https://bugs.webkit.org/show_bug.cgi?id=74416
     99                 return false;
    100             }
    101             break;
    102         }
    103         case SHADER_SYMBOL_TYPE_UNIFORM: {
    104             if (symbol.isSampler()) {
    105                 // FIXME: For now, we restrict shaders with any sampler defined.
    106                 // When we implement texture parameters, we will allow shaders whose samplers are bound to valid textures.
    107                 // We must not allow OpenGL to give unbound samplers a default value of 0 because that references the element texture,
    108                 // which should be inaccessible to the author's shader code.
    109                 // https://bugs.webkit.org/show_bug.cgi?id=96230
    110                 return false;
    111             }
    112 
    113             SymbolNameToTypeMap* uniformNameToTypeMap = builtInUniformNameToTypeMap();
    114             SymbolNameToTypeMap::iterator builtInUniform = uniformNameToTypeMap->find(symbol.name);
    115             if (builtInUniform != uniformNameToTypeMap->end() && (symbol.isArray || symbol.dataType != builtInUniform->value)) {
    116                 // The author defined one of the built-in uniforms with the wrong type.
    117                 // FIXME: Report the validation error.
    118                 // https://bugs.webkit.org/show_bug.cgi?id=74416
    119                 return false;
    120             }
    121             break;
    122         }
    123         default:
    124             ASSERT_NOT_REACHED();
    125             break;
    126         }
    127     }
    128 
    129     return true;
    130 }
    131 
    132 String CustomFilterValidatedProgram::defaultVertexShaderString()
    133 {
    134     DEFINE_STATIC_LOCAL(String, vertexShaderString, (SHADER(
    135         attribute mediump vec4 a_position;
    136         uniform mediump mat4 u_projectionMatrix;
    137 
    138         void main()
    139         {
    140             gl_Position = u_projectionMatrix * a_position;
    141         }
    142     )));
    143     return vertexShaderString;
    144 }
    145 
    146 String CustomFilterValidatedProgram::defaultFragmentShaderString()
    147 {
    148     DEFINE_STATIC_LOCAL(String, fragmentShaderString, (SHADER(
    149         void main()
    150         {
    151         }
    152     )));
    153     return fragmentShaderString;
    154 }
    155 
    156 CustomFilterValidatedProgram::CustomFilterValidatedProgram(CustomFilterGlobalContext* globalContext, const CustomFilterProgramInfo& programInfo)
    157     : m_globalContext(globalContext)
    158     , m_programInfo(programInfo)
    159     , m_isInitialized(false)
    160 {
    161     platformInit();
    162 
    163     String originalVertexShader = programInfo.vertexShaderString();
    164     if (originalVertexShader.isNull())
    165         originalVertexShader = defaultVertexShaderString();
    166 
    167     String originalFragmentShader = programInfo.fragmentShaderString();
    168     if (originalFragmentShader.isNull())
    169         originalFragmentShader = defaultFragmentShaderString();
    170 
    171     // Shaders referenced from the CSS mix function use a different validator than regular WebGL shaders. See core/platform/graphics/filters/custom/CustomFilterGlobalContext.h for more details.
    172     bool blendsElementTexture = (programInfo.programType() == ProgramTypeBlendsElementTexture);
    173     ANGLEPlatformBridge* validator = blendsElementTexture ? m_globalContext->mixShaderValidator() : m_globalContext->webglShaderValidator();
    174     String vertexShaderLog, fragmentShaderLog;
    175     Vector<ANGLEShaderSymbol> symbols;
    176     bool vertexShaderValid = validator->compileShaderSource(originalVertexShader.utf8().data(), SHADER_TYPE_VERTEX, m_validatedVertexShader, vertexShaderLog, symbols);
    177     bool fragmentShaderValid = validator->compileShaderSource(originalFragmentShader.utf8().data(), SHADER_TYPE_FRAGMENT, m_validatedFragmentShader, fragmentShaderLog, symbols);
    178     if (!vertexShaderValid || !fragmentShaderValid) {
    179         // FIXME: Report the validation errors.
    180         // https://bugs.webkit.org/show_bug.cgi?id=74416
    181         return;
    182     }
    183 
    184     if (!validateSymbols(symbols, m_programInfo.meshType())) {
    185         // FIXME: Report validation errors.
    186         // https://bugs.webkit.org/show_bug.cgi?id=74416
    187         return;
    188     }
    189 
    190     // We need to add texture access, blending, and compositing code to shaders that are referenced from the CSS mix function.
    191     if (blendsElementTexture) {
    192         rewriteMixVertexShader(symbols);
    193         rewriteMixFragmentShader();
    194     }
    195 
    196     m_isInitialized = true;
    197 }
    198 
    199 PassRefPtr<CustomFilterCompiledProgram> CustomFilterValidatedProgram::compiledProgram()
    200 {
    201     ASSERT(m_isInitialized && m_globalContext && !m_validatedVertexShader.isNull() && !m_validatedFragmentShader.isNull());
    202     if (!m_compiledProgram) {
    203         m_compiledProgram = CustomFilterCompiledProgram::create(m_globalContext->context(), m_validatedVertexShader, m_validatedFragmentShader, m_programInfo.programType());
    204         ASSERT(m_compiledProgram->isInitialized());
    205         ASSERT(m_compiledProgram->samplerLocation() != -1 || !needsInputTexture());
    206     }
    207     return m_compiledProgram;
    208 }
    209 
    210 bool CustomFilterValidatedProgram::needsInputTexture() const
    211 {
    212     return m_programInfo.programType() == ProgramTypeBlendsElementTexture
    213         && m_programInfo.mixSettings().compositeOperator != CompositeClear
    214         && m_programInfo.mixSettings().compositeOperator != CompositeCopy;
    215 }
    216 
    217 void CustomFilterValidatedProgram::rewriteMixVertexShader(const Vector<ANGLEShaderSymbol>& symbols)
    218 {
    219     ASSERT(m_programInfo.programType() == ProgramTypeBlendsElementTexture);
    220 
    221     // If the author defined a_texCoord, we can use it to shuttle the texture coordinate to the fragment shader.
    222     // Note that vertex attributes are read-only in GLSL, so the author could not have changed a_texCoord's value.
    223     // Also, note that we would have already rejected the shader if the author defined a_texCoord with the wrong type.
    224     bool texCoordAttributeDefined = false;
    225     for (size_t i = 0; i < symbols.size(); ++i) {
    226         if (symbols[i].name == "a_texCoord")
    227             texCoordAttributeDefined = true;
    228     }
    229 
    230     if (!texCoordAttributeDefined)
    231         m_validatedVertexShader.append("attribute mediump vec2 a_texCoord;");
    232 
    233     // During validation, ANGLE renamed the author's "main" function to "css_main".
    234     // We write our own "main" function and call "css_main" from it.
    235     // This makes rewriting easy and ensures that our code runs after all author code.
    236     m_validatedVertexShader.append(SHADER(
    237         varying mediump vec2 css_v_texCoord;
    238 
    239         void main()
    240         {
    241             css_main();
    242             css_v_texCoord = a_texCoord;
    243         }
    244     ));
    245 }
    246 
    247 void CustomFilterValidatedProgram::rewriteMixFragmentShader()
    248 {
    249     ASSERT(m_programInfo.programType() == ProgramTypeBlendsElementTexture);
    250 
    251     StringBuilder builder;
    252     // ANGLE considered these symbols as built-ins during validation under the SH_CSS_SHADERS_SPEC flag.
    253     // Now, we have to define these symbols in order to make this shader valid GLSL.
    254     // We define these symbols before the author's shader code, which makes them accessible to author code.
    255     builder.append(SHADER(
    256         mediump vec4 css_MixColor = vec4(0.0);
    257         mediump mat4 css_ColorMatrix = mat4(1.0);
    258     ));
    259     builder.append(m_validatedFragmentShader);
    260     builder.append(blendFunctionString(m_programInfo.mixSettings().blendMode));
    261     builder.append(compositeFunctionString(m_programInfo.mixSettings().compositeOperator));
    262     // We define symbols like "css_u_texture" after the author's shader code, which makes them inaccessible to author code.
    263     // In particular, "css_u_texture" represents the DOM element texture, so it's important to keep it inaccessible to
    264     // author code for security reasons.
    265     builder.append(SHADER(
    266         uniform sampler2D css_u_texture;
    267         varying mediump vec2 css_v_texCoord;
    268 
    269         void main()
    270         {
    271             css_main();
    272             mediump vec4 originalColor = texture2D(css_u_texture, css_v_texCoord);
    273             mediump vec4 multipliedColor = clamp(css_ColorMatrix * originalColor, 0.0, 1.0);
    274             mediump vec4 clampedMixColor = clamp(css_MixColor, 0.0, 1.0);
    275             mediump vec3 blendedColor = css_BlendColor(multipliedColor.rgb, clampedMixColor.rgb);
    276             mediump vec3 weightedColor = (1.0 - multipliedColor.a) * clampedMixColor.rgb + multipliedColor.a * blendedColor;
    277             gl_FragColor = css_Composite(multipliedColor.rgb, multipliedColor.a, weightedColor.rgb, clampedMixColor.a);
    278         }
    279     ));
    280     m_validatedFragmentShader = builder.toString();
    281 }
    282 
    283 String CustomFilterValidatedProgram::blendFunctionString(blink::WebBlendMode blendMode)
    284 {
    285     // Implemented using the same symbol names as the Compositing and Blending spec:
    286     // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnormal
    287     // Cs: is the source color in css_BlendColor() and the source color component in css_BlendComponent()
    288     // Cb: is the backdrop color in css_BlendColor() and the backdrop color component in css_BlendComponent()
    289     const char* blendColorExpression = "vec3(css_BlendComponent(Cb.r, Cs.r), css_BlendComponent(Cb.g, Cs.g), css_BlendComponent(Cb.b, Cs.b))";
    290     const char* blendComponentExpression = "Co = 0.0;";
    291     bool needsLuminosityHelperFunctions = false;
    292     bool needsSaturationHelperFunctions = false;
    293     String blendFunctionString;
    294     switch (blendMode) {
    295     case blink::WebBlendModeNormal:
    296         blendColorExpression = "Cs";
    297         break;
    298     case blink::WebBlendModeMultiply:
    299         blendColorExpression = "Cs * Cb";
    300         break;
    301     case blink::WebBlendModeScreen:
    302         blendColorExpression = "Cb + Cs - (Cb * Cs)";
    303         break;
    304     case blink::WebBlendModeDarken:
    305         blendColorExpression = "min(Cb, Cs)";
    306         break;
    307     case blink::WebBlendModeLighten:
    308         blendColorExpression = "max(Cb, Cs)";
    309         break;
    310     case blink::WebBlendModeDifference:
    311         blendColorExpression = "abs(Cb - Cs)";
    312         break;
    313     case blink::WebBlendModeExclusion:
    314         blendColorExpression = "Cb + Cs - 2.0 * Cb * Cs";
    315         break;
    316     case blink::WebBlendModeOverlay:
    317         /*
    318             Co = HardLight(Cs, Cb)
    319                = if(Cb <= 0.5)
    320                      Multiply(Cs, 2 x Cb)
    321                  else
    322                      Screen(Cs, 2 x Cb - 1)
    323                = if(Cb <= 0.5)
    324                      Cs x (2 x Cb)
    325                  else
    326                      Cs + (2 x Cb - 1) - (Cs x (2 x Cb - 1))
    327         */
    328         blendComponentExpression = SHADER(
    329             if (Cb <= 0.5)
    330                 Co = Cs * (2.0 * Cb);
    331             else
    332                 Co = Cs + (2.0 * Cb - 1.0) - (Cs * (2.0 * Cb - 1.0));
    333         );
    334         break;
    335     case blink::WebBlendModeColorDodge:
    336         /*
    337             Co = if(Cs < 1)
    338                      min(1, Cb / (1 - Cs))
    339                  else
    340                      1
    341         */
    342         blendComponentExpression = SHADER(
    343             if (Cs < 1.0)
    344                 Co = min(1.0, Cb / (1.0 - Cs));
    345             else
    346                 Co = 1.0;
    347         );
    348         break;
    349     case blink::WebBlendModeColorBurn:
    350         /*
    351             Co = if(Cs > 0)
    352                      1 - min(1, (1 - Cb) / Cs)
    353                  else
    354                      0
    355         */
    356         blendComponentExpression = SHADER(
    357             if (Cs > 0.0)
    358                 Co = 1.0 - min(1.0, (1.0 - Cb) / Cs);
    359             else
    360                 Co = 0.0;
    361         );
    362         break;
    363     case blink::WebBlendModeHardLight:
    364         /*
    365             Co = if(Cs <= 0.5)
    366                      Multiply(Cb, 2 x Cs)
    367                  else
    368                      Screen(Cb, 2 x Cs -1)
    369                = if(Cs <= 0.5)
    370                      Cb x (2 x Cs)
    371                  else
    372                      Cb + (2 x Cs - 1) - (Cb x (2 x Cs - 1))
    373         */
    374         blendComponentExpression = SHADER(
    375             if (Cs <= 0.5)
    376                 Co = Cb * (2.0 * Cs);
    377             else
    378                 Co = Cb + (2.0 * Cs - 1.0) - (Cb * (2.0 * Cs - 1.0));
    379         );
    380         break;
    381     case blink::WebBlendModeSoftLight:
    382         /*
    383             Co = if(Cs <= 0.5)
    384                      Cb - (1 - 2 x Cs) x Cb x (1 - Cb)
    385                  else
    386                      Cb + (2 x Cs - 1) x (D(Cb) - Cb)
    387 
    388             with
    389 
    390             D(Cb) = if(Cb <= 0.25)
    391                         (16 * Cb - 12) x Cb + 4) x Cb
    392                     else
    393                         sqrt(Cb)
    394         */
    395         blendComponentExpression = SHADER(
    396             mediump float D;
    397             if (Cb <= 0.25)
    398                 D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb;
    399             else
    400                 D = sqrt(Cb);
    401 
    402             if (Cs <= 0.5)
    403                 Co = Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb);
    404             else
    405                 Co = Cb + (2.0 * Cs - 1.0) * (D - Cb);
    406         );
    407         break;
    408     case blink::WebBlendModeColor:
    409         needsLuminosityHelperFunctions = true;
    410         blendColorExpression = "css_SetLum(Cs, css_Lum(Cb))";
    411         break;
    412     case blink::WebBlendModeLuminosity:
    413         needsLuminosityHelperFunctions = true;
    414         blendColorExpression = "css_SetLum(Cb, css_Lum(Cs))";
    415         break;
    416     case blink::WebBlendModeHue:
    417         needsLuminosityHelperFunctions = true;
    418         needsSaturationHelperFunctions = true;
    419         blendColorExpression = "css_SetLum(css_SetSat(Cs, css_Sat(Cb)), css_Lum(Cb))";
    420         break;
    421     case blink::WebBlendModeSaturation:
    422         needsLuminosityHelperFunctions = true;
    423         needsSaturationHelperFunctions = true;
    424         blendColorExpression = "css_SetLum(css_SetSat(Cb, css_Sat(Cs)), css_Lum(Cb))";
    425         break;
    426     default:
    427         ASSERT_NOT_REACHED();
    428     }
    429 
    430     if (needsLuminosityHelperFunctions) {
    431         blendFunctionString.append(SHADER(
    432             mediump float css_Lum(mediump vec3 C)
    433             {
    434                 return 0.3 * C.r + 0.59 * C.g + 0.11 * C.b;
    435             }
    436             mediump vec3 css_ClipColor(mediump vec3 C)
    437             {
    438                 mediump float L = css_Lum(C);
    439                 mediump float n = min(min(C.r, C.g), C.b);
    440                 mediump float x = max(max(C.r, C.g), C.b);
    441                 if (n < 0.0)
    442                     C = L + (((C - L) * L) / (L - n));
    443                 if (x > 1.0)
    444                     C = L + (((C - L) * (1.0 - L) / (x - L)));
    445                 return C;
    446             }
    447             mediump vec3 css_SetLum(mediump vec3 C, mediump float l)
    448             {
    449                 C += l - css_Lum(C);
    450                 return css_ClipColor(C);
    451             }
    452         ));
    453     }
    454 
    455     if (needsSaturationHelperFunctions) {
    456         blendFunctionString.append(SHADER(
    457             mediump float css_Sat(mediump vec3 C)
    458             {
    459                 mediump float cMin = min(min(C.r, C.g), C.b);
    460                 mediump float cMax = max(max(C.r, C.g), C.b);
    461                 return cMax - cMin;
    462             }
    463             void css_SetSatHelper(inout mediump float cMin, inout mediump float cMid, inout mediump float cMax, mediump float s)
    464             {
    465                 if (cMax > cMin) {
    466                     cMid = (((cMid - cMin) * s) / (cMax - cMin));
    467                     cMax = s;
    468                 } else {
    469                     cMid = cMax = 0.0;
    470                 }
    471                 cMin = 0.0;
    472             }
    473             mediump vec3 css_SetSat(mediump vec3 C, mediump float s)
    474             {
    475                 if (C.r <= C.g) {
    476                     if (C.g <= C.b) {
    477                         css_SetSatHelper(C.r, C.g, C.b, s);
    478                     } else {
    479                         if (C.r <= C.b)
    480                             css_SetSatHelper(C.r, C.b, C.g, s);
    481                         else
    482                             css_SetSatHelper(C.b, C.r, C.g, s);
    483                     }
    484                 } else {
    485                     if (C.r <= C.b) {
    486                         css_SetSatHelper(C.g, C.r, C.b, s);
    487                     } else {
    488                         if (C.g <= C.b)
    489                             css_SetSatHelper(C.g, C.b, C.r, s);
    490                         else
    491                             css_SetSatHelper(C.b, C.g, C.r, s);
    492                     }
    493                 }
    494                 return C;
    495             }
    496         ));
    497     }
    498 
    499     blendFunctionString.append(String::format(SHADER(
    500         mediump float css_BlendComponent(mediump float Cb, mediump float Cs)
    501         {
    502             mediump float Co;
    503             %s
    504             return Co;
    505         }
    506         mediump vec3 css_BlendColor(mediump vec3 Cb, mediump vec3 Cs)
    507         {
    508             return %s;
    509         }
    510     ), blendComponentExpression, blendColorExpression));
    511 
    512     return blendFunctionString;
    513 }
    514 
    515 String CustomFilterValidatedProgram::compositeFunctionString(CompositeOperator compositeOperator)
    516 {
    517     // Use the same symbol names as the Compositing and Blending spec:
    518     // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnormal
    519     // Cs: is the source color
    520     // Cb: is the backdrop color
    521     // as: is the source alpha
    522     // ab: is the backdrop alpha
    523     // Fa: is defined by the Porter Duff operator in use
    524     // Fb: is defined by the Porter Duff operator in use
    525     const char* Fa = 0;
    526     const char* Fb = 0;
    527     switch (compositeOperator) {
    528     case CompositeSourceAtop:
    529         Fa = "ab";
    530         Fb = "1.0 - as";
    531         break;
    532     case CompositeClear:
    533         Fa = "0.0";
    534         Fb = "0.0";
    535         break;
    536     case CompositeCopy:
    537         Fa = "1.0";
    538         Fb = "0.0";
    539         break;
    540     case CompositeSourceOver:
    541         Fa = "1.0";
    542         Fb = "1.0 - as";
    543         break;
    544     case CompositeSourceIn:
    545         Fa = "ab";
    546         Fb = "0.0";
    547         break;
    548     case CompositeSourceOut:
    549         Fa = "1.0 - ab";
    550         Fb = "0.0";
    551         break;
    552     case CompositeDestinationOver:
    553         Fa = "1.0 - ab";
    554         Fb = "1.0";
    555         break;
    556     case CompositeDestinationIn:
    557         Fa = "0.0";
    558         Fb = "as";
    559         break;
    560     case CompositeDestinationOut:
    561         Fa = "0.0";
    562         Fb = "1.0 - as";
    563         break;
    564     case CompositeDestinationAtop:
    565         Fa = "1.0 - ab";
    566         Fb = "as";
    567         break;
    568     case CompositeXOR:
    569         Fa = "1.0 - ab";
    570         Fb = "1.0 - as";
    571         break;
    572     case CompositePlusLighter:
    573         notImplemented();
    574         return String();
    575     default:
    576         // The CSS parser should not have accepted any other composite operators.
    577         ASSERT_NOT_REACHED();
    578         return String();
    579     }
    580 
    581     ASSERT(Fa && Fb);
    582     // Use the general formula for compositing, lifted from the spec:
    583     // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#generalformula
    584     return String::format(SHADER(
    585         mediump vec4 css_Composite(mediump vec3 Cb, mediump float ab, mediump vec3 Cs, mediump float as)
    586         {
    587             mediump float Fa = %s;
    588             mediump float Fb = %s;
    589             return vec4(as * Fa * Cs + ab * Fb * Cb, as * Fa + ab * Fb);
    590         }
    591     ), Fa, Fb);
    592 }
    593 
    594 CustomFilterValidatedProgram::~CustomFilterValidatedProgram()
    595 {
    596     platformDestroy();
    597 
    598     if (m_globalContext)
    599         m_globalContext->removeValidatedProgram(this);
    600 }
    601 
    602 CustomFilterProgramInfo CustomFilterValidatedProgram::validatedProgramInfo() const
    603 {
    604     ASSERT(m_isInitialized);
    605     return CustomFilterProgramInfo(m_validatedVertexShader, m_validatedFragmentShader, m_programInfo.programType(), m_programInfo.mixSettings(), m_programInfo.meshType());
    606 }
    607 
    608 void CustomFilterValidatedProgram::platformInit()
    609 {
    610 }
    611 
    612 void CustomFilterValidatedProgram::platformDestroy()
    613 {
    614 }
    615 
    616 } // namespace WebCore
    617 
    618