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