void RenderLayer::FilterInfo::updateReferenceFilterClients(const FilterOperations& operations) { removeReferenceFilterClients(); for (size_t i = 0, size = operations.size(); i < size; ++i) { FilterOperation* filterOperation = operations.operations()[i].get(); if (filterOperation->getOperationType() != FilterOperation::REFERENCE) continue; ReferenceFilterOperation* referenceFilterOperation = static_cast<ReferenceFilterOperation*>(filterOperation); CachedSVGDocumentReference* documentReference = referenceFilterOperation->cachedSVGDocumentReference(); CachedSVGDocument* cachedSVGDocument = documentReference ? documentReference->document() : 0; if (cachedSVGDocument) { // Reference is external; wait for notifyFinished(). cachedSVGDocument->addClient(this); m_externalSVGReferences.append(cachedSVGDocument); } else { // Reference is internal; add layer as a client so we can trigger // filter repaint on SVG attribute change. Element* filter = m_layer.renderer().node()->document().getElementById(referenceFilterOperation->fragment()); if (!filter || !filter->renderer() || !filter->renderer()->isSVGResourceFilter()) continue; filter->renderer()->toRenderSVGResourceContainer()->addClientRenderLayer(&m_layer); m_internalSVGReferences.append(filter); } } }
void RenderLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& operations) { removeReferenceFilterClients(); for (size_t i = 0; i < operations.size(); ++i) { RefPtr<FilterOperation> filterOperation = operations.operations().at(i); if (filterOperation->type() != FilterOperation::REFERENCE) continue; ReferenceFilterOperation* referenceFilterOperation = toReferenceFilterOperation(filterOperation.get()); DocumentResourceReference* documentReference = ReferenceFilterBuilder::documentResourceReference(referenceFilterOperation); DocumentResource* cachedSVGDocument = documentReference ? documentReference->document() : 0; if (cachedSVGDocument) { // Reference is external; wait for notifyFinished(). cachedSVGDocument->addClient(this); m_externalSVGReferences.append(cachedSVGDocument); } else { // Reference is internal; add layer as a client so we can trigger // filter paint invalidation on SVG attribute change. Element* filter = m_layer->renderer()->node()->document().getElementById(referenceFilterOperation->fragment()); if (!isSVGFilterElement(filter)) continue; if (filter->renderer()) toRenderSVGResourceContainer(filter->renderer())->addClientRenderLayer(m_layer); else toSVGFilterElement(filter)->addClient(m_layer->renderer()->node()); m_internalSVGReferences.append(filter); } } }
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; }
void StyleResourceLoader::loadPendingSVGDocuments(RenderStyle* renderStyle, const ElementStyleResources& elementStyleResources) { if (!renderStyle->hasFilter() || elementStyleResources.pendingSVGDocuments().isEmpty()) return; Vector<RefPtr<FilterOperation> >& filterOperations = renderStyle->mutableFilter().operations(); for (unsigned i = 0; i < filterOperations.size(); ++i) { RefPtr<FilterOperation> filterOperation = filterOperations.at(i); if (filterOperation->getOperationType() == FilterOperation::REFERENCE) { ReferenceFilterOperation* referenceFilter = static_cast<ReferenceFilterOperation*>(filterOperation.get()); CSSSVGDocumentValue* value = elementStyleResources.pendingSVGDocuments().get(referenceFilter); if (!value) continue; DocumentResource* resource = value->load(m_fetcher); if (!resource) continue; // Stash the DocumentResource on the reference filter. referenceFilter->setDocumentResourceReference(adoptPtr(new DocumentResourceReference(resource))); } } }
bool FilterEffectRenderer::build(Document* document, const FilterOperations& operations) { #if !ENABLE(CSS_SHADERS) || !USE(3D_GRAPHICS) UNUSED_PARAM(document); #endif #if ENABLE(CSS_SHADERS) m_hasCustomShaderFilter = false; #endif m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); if (m_hasFilterThatMovesPixels) operations.getOutsets(m_topOutset, m_rightOutset, m_bottomOutset, m_leftOutset); // Keep the old effects on the stack until we've created the new effects. // New FECustomFilters can reuse cached resources from old FECustomFilters. FilterEffectList oldEffects; m_effects.swap(oldEffects); 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->getOperationType()) { case FilterOperation::REFERENCE: { ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation); effect = buildReferenceFilter(document, previousEffect, referenceOperation); referenceOperation->setFilterEffect(effect); 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 = floatValueForLength(blurOperation->stdDeviation(), 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) && USE(3D_GRAPHICS) case FilterOperation::CUSTOM: // CUSTOM operations are always converted to VALIDATED_CUSTOM before getting here. // The conversion happens in RenderLayer::computeFilterOperations. ASSERT_NOT_REACHED(); break; case FilterOperation::VALIDATED_CUSTOM: { ValidatedCustomFilterOperation* customFilterOperation = static_cast<ValidatedCustomFilterOperation*>(filterOperation); effect = createCustomFilterEffect(this, document, customFilterOperation); if (effect) m_hasCustomShaderFilter = true; break; } #endif default: break; } if (effect) { // Unlike SVG, filters applied here should not clip to their primitive subregions. effect->setClipsToBounds(false); effect->setColorSpace(ColorSpaceDeviceRGB); if (filterOperation->getOperationType() != 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; }
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; }