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