bool DropShadowFilterOperation::operator==(const FilterOperation& o) const { if (!isSameType(o)) return false; const DropShadowFilterOperation& other = toDropShadowFilterOperation(o); return m_location == other.m_location && m_stdDeviation == other.m_stdDeviation && m_color == other.m_color; }
FilterOutsets FilterOperations::outsets() const { FilterOutsets totalOutsets; for (size_t i = 0; i < m_operations.size(); ++i) { FilterOperation* filterOperation = m_operations.at(i).get(); switch (filterOperation->type()) { case FilterOperation::BLUR: { BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation); float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); IntSize outsetSize = outsetSizeForBlur(stdDeviation); FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width()); totalOutsets += outsets; break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation); IntSize outsetSize = outsetSizeForBlur(dropShadowOperation->stdDeviation()); FilterOutsets outsets( std::max(0, outsetSize.height() - dropShadowOperation->y()), std::max(0, outsetSize.width() + dropShadowOperation->x()), std::max(0, outsetSize.height() + dropShadowOperation->y()), std::max(0, outsetSize.width() - dropShadowOperation->x()) ); totalOutsets += outsets; break; } default: break; } } return totalOutsets; }
InterpolationValue FilterInterpolationFunctions::maybeConvertFilter( const FilterOperation& filter, double zoom) { InterpolationValue result = nullptr; switch (filter.type()) { case FilterOperation::GRAYSCALE: case FilterOperation::HUE_ROTATE: case FilterOperation::SATURATE: case FilterOperation::SEPIA: result.interpolableValue = InterpolableNumber::create( toBasicColorMatrixFilterOperation(filter).amount()); break; case FilterOperation::BRIGHTNESS: case FilterOperation::CONTRAST: case FilterOperation::INVERT: case FilterOperation::OPACITY: result.interpolableValue = InterpolableNumber::create( toBasicComponentTransferFilterOperation(filter).amount()); break; case FilterOperation::BLUR: result = LengthInterpolationFunctions::maybeConvertLength( toBlurFilterOperation(filter).stdDeviation(), zoom); break; case FilterOperation::DROP_SHADOW: { const DropShadowFilterOperation& blurFilter = toDropShadowFilterOperation(filter); ShadowData shadowData(blurFilter.location(), blurFilter.stdDeviation(), 0, Normal, blurFilter.getColor()); result = ShadowInterpolationFunctions::convertShadowData(shadowData, zoom); break; } case FilterOperation::REFERENCE: return nullptr; default: NOTREACHED(); return nullptr; } if (!result) return nullptr; result.nonInterpolableValue = FilterNonInterpolableValue::create( filter.type(), result.nonInterpolableValue.release()); return result; }
RawPtr<FilterOperation> DropShadowFilterOperation::blend(const FilterOperation* from, double progress) const { if (!from) { return DropShadowFilterOperation::create( blink::blend(IntPoint(), m_location, progress), blink::blend(0, m_stdDeviation, progress), blink::blend(Color(Color::transparent), m_color, progress)); } const DropShadowFilterOperation* fromOp = toDropShadowFilterOperation(from); return DropShadowFilterOperation::create( blink::blend(fromOp->location(), m_location, progress), blink::blend(fromOp->stdDeviation(), m_stdDeviation, progress), blink::blend(fromOp->getColor(), m_color, progress)); }
FilterOutsets FilterOperations::outsets() const { FilterOutsets totalOutsets; for (size_t i = 0; i < m_operations.size(); ++i) { FilterOperation* filterOperation = m_operations.at(i).get(); switch (filterOperation->type()) { case FilterOperation::BLUR: { BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation); float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); IntSize outsetSize = outsetSizeForBlur(stdDeviation); FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width()); totalOutsets += outsets; break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation); IntSize outsetSize = outsetSizeForBlur(dropShadowOperation->stdDeviation()); FilterOutsets outsets( std::max(0, outsetSize.height() - dropShadowOperation->y()), std::max(0, outsetSize.width() + dropShadowOperation->x()), std::max(0, outsetSize.height() + dropShadowOperation->y()), std::max(0, outsetSize.width() - dropShadowOperation->x()) ); totalOutsets += outsets; break; } case FilterOperation::REFERENCE: { ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation); if (referenceOperation->filter() && referenceOperation->filter()->lastEffect()) { FloatRect outsetRect(0, 0, 1, 1); outsetRect = referenceOperation->filter()->lastEffect()->mapRectRecursive(outsetRect); FilterOutsets outsets( std::max(0.0f, -outsetRect.y()), std::max(0.0f, outsetRect.x() + outsetRect.width() - 1), std::max(0.0f, outsetRect.y() + outsetRect.height() - 1), std::max(0.0f, -outsetRect.x()) ); totalOutsets += outsets; } break; } default: break; } } return totalOutsets; }
PassRefPtr<FilterOperation> DropShadowFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough) { if (from && !from->isSameType(*this)) return this; if (blendToPassthrough) return DropShadowFilterOperation::create( WebCore::blend(m_location, IntPoint(), progress), WebCore::blend(m_stdDeviation, 0, progress), WebCore::blend(m_color, Color(Color::transparent), progress)); const DropShadowFilterOperation* fromOp = toDropShadowFilterOperation(from); IntPoint fromLocation = fromOp ? fromOp->location() : IntPoint(); int fromStdDeviation = fromOp ? fromOp->stdDeviation() : 0; Color fromColor = fromOp ? fromOp->color() : Color(Color::transparent); return DropShadowFilterOperation::create( WebCore::blend(fromLocation, m_location, progress), WebCore::blend(fromStdDeviation, m_stdDeviation, progress), WebCore::blend(fromColor, m_color, progress)); }
bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& operations) { m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); // Inverse zoom the pre-zoomed CSS shorthand filters, so that they are in the same zoom as the unzoomed reference filters. const RenderStyle* style = renderer->style(); float invZoom = style ? 1.0f / style->effectiveZoom() : 1.0f; RefPtr<FilterEffect> previousEffect = m_sourceGraphic; for (size_t i = 0; i < operations.operations().size(); ++i) { RefPtr<FilterEffect> effect; FilterOperation* filterOperation = operations.operations().at(i).get(); switch (filterOperation->type()) { case FilterOperation::REFERENCE: { effect = ReferenceFilterBuilder::build(this, renderer, previousEffect.get(), toReferenceFilterOperation(filterOperation)); break; } case FilterOperation::GRAYSCALE: { Vector<float> inputParameters; double oneMinusAmount = clampTo(1 - toBasicColorMatrixFilterOperation(filterOperation)->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: { Vector<float> inputParameters; double oneMinusAmount = clampTo(1 - toBasicColorMatrixFilterOperation(filterOperation)->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: { Vector<float> inputParameters; inputParameters.append(narrowPrecisionToFloat(toBasicColorMatrixFilterOperation(filterOperation)->amount())); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters); break; } case FilterOperation::HUE_ROTATE: { Vector<float> inputParameters; inputParameters.append(narrowPrecisionToFloat(toBasicColorMatrixFilterOperation(filterOperation)->amount())); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters); break; } case FilterOperation::INVERT: { BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(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: { ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE; Vector<float> transferParameters; transferParameters.append(0); transferParameters.append(narrowPrecisionToFloat(toBasicComponentTransferFilterOperation(filterOperation)->amount())); transferFunction.tableValues = transferParameters; ComponentTransferFunction nullFunction; effect = FEComponentTransfer::create(this, nullFunction, nullFunction, nullFunction, transferFunction); break; } case FilterOperation::BRIGHTNESS: { ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR; transferFunction.slope = narrowPrecisionToFloat(toBasicComponentTransferFilterOperation(filterOperation)->amount()); transferFunction.intercept = 0; ComponentTransferFunction nullFunction; effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); break; } case FilterOperation::CONTRAST: { ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR; float amount = narrowPrecisionToFloat(toBasicComponentTransferFilterOperation(filterOperation)->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: { float stdDeviation = floatValueForLength(toBlurFilterOperation(filterOperation)->stdDeviation(), 0) * invZoom; effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation); break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation); float stdDeviation = dropShadowOperation->stdDeviation() * invZoom; float x = dropShadowOperation->x() * invZoom; float y = dropShadowOperation->y() * invZoom; effect = FEDropShadow::create(this, stdDeviation, stdDeviation, x, y, dropShadowOperation->color(), 1); break; } default: break; } if (effect) { if (filterOperation->type() != FilterOperation::REFERENCE) { // Unlike SVG, filters applied here should not clip to their primitive subregions. effect->setClipsToBounds(false); effect->setOperatingColorSpace(ColorSpaceDeviceRGB); effect->inputEffects().append(previousEffect); } previousEffect = effect.release(); } } // We need to keep the old effects alive until this point, so that SVG reference filters // can share cached resources across frames. m_lastEffect = previousEffect; // If we didn't make any effects, tell our caller we are not valid if (!m_lastEffect.get()) return false; return true; }
void SkiaImageFilterBuilder::buildFilterOperations(const FilterOperations& operations, WebFilterOperations* filters) { ColorSpace currentColorSpace = ColorSpaceDeviceRGB; SkImageFilter* const nullFilter = 0; for (size_t i = 0; i < operations.size(); ++i) { const FilterOperation& op = *operations.at(i); switch (op.type()) { case FilterOperation::REFERENCE: { RefPtr<SkImageFilter> filter; ReferenceFilter* referenceFilter = toReferenceFilterOperation(op).filter(); if (referenceFilter && referenceFilter->lastEffect()) { FilterEffect* filterEffect = referenceFilter->lastEffect(); // Prepopulate SourceGraphic with two image filters: one with a null image // filter, and the other with a colorspace conversion filter. // We don't know what color space the interior nodes will request, so we have to // initialize SourceGraphic with both options. // Since we know SourceGraphic is always PM-valid, we also use // these for the PM-validated options. RefPtr<SkImageFilter> deviceFilter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceDeviceRGB); RefPtr<SkImageFilter> linearFilter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceLinearRGB); FilterEffect* sourceGraphic = referenceFilter->sourceGraphic(); sourceGraphic->setImageFilter(ColorSpaceDeviceRGB, false, deviceFilter.get()); sourceGraphic->setImageFilter(ColorSpaceLinearRGB, false, linearFilter.get()); sourceGraphic->setImageFilter(ColorSpaceDeviceRGB, true, deviceFilter.get()); sourceGraphic->setImageFilter(ColorSpaceLinearRGB, true, linearFilter.get()); currentColorSpace = filterEffect->operatingColorSpace(); filter = SkiaImageFilterBuilder::build(filterEffect, currentColorSpace); filters->appendReferenceFilter(filter.get()); } break; } case FilterOperation::GRAYSCALE: case FilterOperation::SEPIA: case FilterOperation::SATURATE: case FilterOperation::HUE_ROTATE: { float amount = toBasicColorMatrixFilterOperation(op).amount(); switch (op.type()) { case FilterOperation::GRAYSCALE: filters->appendGrayscaleFilter(amount); break; case FilterOperation::SEPIA: filters->appendSepiaFilter(amount); break; case FilterOperation::SATURATE: filters->appendSaturateFilter(amount); break; case FilterOperation::HUE_ROTATE: filters->appendHueRotateFilter(amount); break; default: ASSERT_NOT_REACHED(); } break; } case FilterOperation::INVERT: case FilterOperation::OPACITY: case FilterOperation::BRIGHTNESS: case FilterOperation::CONTRAST: { float amount = toBasicComponentTransferFilterOperation(op).amount(); switch (op.type()) { case FilterOperation::INVERT: filters->appendInvertFilter(amount); break; case FilterOperation::OPACITY: filters->appendOpacityFilter(amount); break; case FilterOperation::BRIGHTNESS: filters->appendBrightnessFilter(amount); break; case FilterOperation::CONTRAST: filters->appendContrastFilter(amount); break; default: ASSERT_NOT_REACHED(); } break; } case FilterOperation::BLUR: { float pixelRadius = toBlurFilterOperation(op).stdDeviation().getFloatValue(); filters->appendBlurFilter(pixelRadius); break; } case FilterOperation::DROP_SHADOW: { const DropShadowFilterOperation& drop = toDropShadowFilterOperation(op); filters->appendDropShadowFilter(WebPoint(drop.x(), drop.y()), drop.stdDeviation(), drop.color().rgb()); break; } case FilterOperation::NONE: break; } } if (currentColorSpace != ColorSpaceDeviceRGB) { // Transform to device color space at the end of processing, if required RefPtr<SkImageFilter> filter = transformColorSpace(nullFilter, currentColorSpace, ColorSpaceDeviceRGB); filters->appendReferenceFilter(filter.get()); } }
bool FilterEffectRenderer::build(RenderElement* renderer, const FilterOperations& operations, FilterConsumer consumer) { m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); if (m_hasFilterThatMovesPixels) m_outsets = operations.outsets(); m_effects.clear(); RefPtr<FilterEffect> previousEffect = m_sourceGraphic; for (size_t i = 0; i < operations.operations().size(); ++i) { RefPtr<FilterEffect> effect; FilterOperation* filterOperation = operations.operations().at(i).get(); switch (filterOperation->type()) { case FilterOperation::REFERENCE: { ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation); effect = buildReferenceFilter(renderer, previousEffect, referenceOperation); referenceOperation->setFilterEffect(effect); break; } case FilterOperation::GRAYSCALE: { BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(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 = toBasicColorMatrixFilterOperation(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 = toBasicColorMatrixFilterOperation(filterOperation); Vector<float> inputParameters; inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount())); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters); break; } case FilterOperation::HUE_ROTATE: { BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation); Vector<float> inputParameters; inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount())); effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters); break; } case FilterOperation::INVERT: { BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(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 = toBasicComponentTransferFilterOperation(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 = toBasicComponentTransferFilterOperation(filterOperation); ComponentTransferFunction transferFunction; transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR; transferFunction.slope = narrowPrecisionToFloat(componentTransferOperation->amount()); transferFunction.intercept = 0; ComponentTransferFunction nullFunction; effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); break; } case FilterOperation::CONTRAST: { BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(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 = toBlurFilterOperation(filterOperation); float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation, consumer == FilterProperty ? EDGEMODE_NONE : EDGEMODE_DUPLICATE); break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation); effect = FEDropShadow::create(this, dropShadowOperation->stdDeviation(), dropShadowOperation->stdDeviation(), dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1); break; } default: break; } if (effect) { // Unlike SVG Filters and CSSFilterImages, filter functions on the filter // property applied here should not clip to their primitive subregions. effect->setClipsToBounds(consumer == FilterFunction); effect->setOperatingColorSpace(ColorSpaceDeviceRGB); if (filterOperation->type() != FilterOperation::REFERENCE) { effect->inputEffects().append(previousEffect); m_effects.append(effect); } previousEffect = effect.release(); } } // If we didn't make any effects, tell our caller we are not valid if (!m_effects.size()) return false; setMaxEffectRects(m_sourceDrawingRegion); return true; }