void RenderLayerFilterInfo::updateCustomFilterClients(const FilterOperations& operations) { if (!operations.size()) { removeCustomFilterClients(); return; } CustomFilterProgramList cachedCustomFilterPrograms; for (size_t i = 0; i < operations.size(); ++i) { const FilterOperation* filterOperation = operations.at(i); if (filterOperation->getOperationType() != FilterOperation::CUSTOM) continue; const CustomFilterOperation* customFilterOperation = static_cast<const CustomFilterOperation*>(filterOperation); RefPtr<CustomFilterProgram> program = customFilterOperation->program(); cachedCustomFilterPrograms.append(program); program->addClient(this); } // Remove the old clients here, after we've added the new ones, so that we don't flicker if some shaders are unchanged. removeCustomFilterClients(); m_cachedCustomFilterPrograms.swap(cachedCustomFilterPrograms); }
void FilterEffectRenderer::build(Document* document, const FilterOperations& operations) { #if !ENABLE(CSS_SHADERS) || !ENABLE(WEBGL) UNUSED_PARAM(document); #else CustomFilterProgramList cachedCustomFilterPrograms; #endif m_effects.clear(); RefPtr<FilterEffect> previousEffect; for (size_t i = 0; i < operations.operations().size(); ++i) { RefPtr<FilterEffect> effect; FilterOperation* filterOperation = operations.operations().at(i).get(); switch (filterOperation->getOperationType()) { case FilterOperation::REFERENCE: { // FIXME: Not yet implemented. // https://bugs.webkit.org/show_bug.cgi?id=72443 break; } case FilterOperation::GRAYSCALE: { BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); Vector<float> inputParameters; double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0); // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#grayscaleEquivalent // for information on parameters. inputParameters.append(narrowPrecisionToFloat(0.2126 + 0.7874 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount)); endMatrixRow(inputParameters); inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.7152 + 0.2848 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount)); endMatrixRow(inputParameters); inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.0722 + 0.9278 * oneMinusAmount)); endMatrixRow(inputParameters); lastMatrixRow(inputParameters); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters); break; } case FilterOperation::SEPIA: { BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); Vector<float> inputParameters; double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0); // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#sepiaEquivalent // for information on parameters. inputParameters.append(narrowPrecisionToFloat(0.393 + 0.607 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.769 - 0.769 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.189 - 0.189 * oneMinusAmount)); endMatrixRow(inputParameters); inputParameters.append(narrowPrecisionToFloat(0.349 - 0.349 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.686 + 0.314 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.168 - 0.168 * oneMinusAmount)); endMatrixRow(inputParameters); inputParameters.append(narrowPrecisionToFloat(0.272 - 0.272 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.534 - 0.534 * oneMinusAmount)); inputParameters.append(narrowPrecisionToFloat(0.131 + 0.869 * oneMinusAmount)); endMatrixRow(inputParameters); lastMatrixRow(inputParameters); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters); break; } case FilterOperation::SATURATE: { BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); Vector<float> inputParameters; inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount())); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters); break; } case FilterOperation::HUE_ROTATE: { BasicColorMatrixFilterOperation* colorMatrixOperation = static_cast<BasicColorMatrixFilterOperation*>(filterOperation); Vector<float> inputParameters; inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount())); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters); break; } case FilterOperation::INVERT: { BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE; Vector<float> transferParameters; transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount())); transferParameters.append(narrowPrecisionToFloat(1 - componentTransferOperation->amount())); transferFunction.tableValues = transferParameters; ComponentTransferFunction nullFunction; effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); break; } case FilterOperation::OPACITY: { BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE; Vector<float> transferParameters; transferParameters.append(0); transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount())); transferFunction.tableValues = transferParameters; ComponentTransferFunction nullFunction; effect = FEComponentTransfer::create(this, nullFunction, nullFunction, nullFunction, transferFunction); break; } case FilterOperation::BRIGHTNESS: { BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR; transferFunction.slope = 1; transferFunction.intercept = narrowPrecisionToFloat(componentTransferOperation->amount()); ComponentTransferFunction nullFunction; effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); break; } case FilterOperation::CONTRAST: { BasicComponentTransferFilterOperation* componentTransferOperation = static_cast<BasicComponentTransferFilterOperation*>(filterOperation); ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR; float amount = narrowPrecisionToFloat(componentTransferOperation->amount()); transferFunction.slope = amount; transferFunction.intercept = -0.5 * amount + 0.5; ComponentTransferFunction nullFunction; effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); break; } case FilterOperation::BLUR: { BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation); float stdDeviation = blurOperation->stdDeviation().calcFloatValue(0); effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation); break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation); effect = FEDropShadow::create(this, dropShadowOperation->stdDeviation(), dropShadowOperation->stdDeviation(), dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1); break; } #if ENABLE(CSS_SHADERS) case FilterOperation::CUSTOM: { #if ENABLE(WEBGL) if (!isCSSCustomFilterEnabled(document)) continue; CustomFilterOperation* customFilterOperation = static_cast<CustomFilterOperation*>(filterOperation); RefPtr<CustomFilterProgram> program = customFilterOperation->program(); cachedCustomFilterPrograms.append(program); program->addClient(this); if (program->isLoaded()) { effect = FECustomFilter::create(this, document, program, customFilterOperation->parameters(), customFilterOperation->meshRows(), customFilterOperation->meshColumns(), customFilterOperation->meshBoxType(), customFilterOperation->meshType()); } #endif break; } #endif default: break; } if (effect) { // Unlike SVG, filters applied here should not clip to their primitive subregions. effect->setClipsToBounds(false); if (previousEffect) effect->inputEffects().append(previousEffect); m_effects.append(effect); previousEffect = effect.release(); } } // If we didn't make a real filter, create a null-op (FEMerge with one input). if (!previousEffect) m_effects.append(FEMerge::create(this)); m_effects.first()->inputEffects().append(m_sourceGraphic); setMaxEffectRects(m_sourceDrawingRegion); #if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) removeCustomFilterClients(); m_cachedCustomFilterPrograms.swap(cachedCustomFilterPrograms); #endif }