void ArgumentCoder<FilterOperations>::encode(ArgumentEncoder& encoder, const FilterOperations& filters) { encoder << static_cast<uint64_t>(filters.size()); for (const auto& filter : filters.operations()) encodeFilterOperation(encoder, *filter); }
void CoordinatedLayerTreeHost::checkCustomFilterProgramProxies(const FilterOperations& filters) { // We need to create the WebCustomFilterProgramProxy objects before we get to serialize the // custom filters to the other process. That's because WebCustomFilterProgramProxy needs // to link back to the coordinator, so that we can send a message to the UI process when // the program is not needed anymore. // Note that the serialization will only happen at a later time in ArgumentCoder<WebCore::FilterOperations>::encode. // At that point the program will only be serialized once. All the other times it will only use the ID of the program. for (size_t i = 0; i < filters.size(); ++i) { const FilterOperation* operation = filters.at(i); if (operation->getOperationType() != FilterOperation::VALIDATED_CUSTOM) continue; const ValidatedCustomFilterOperation* customOperation = static_cast<const ValidatedCustomFilterOperation*>(operation); ASSERT(customOperation->validatedProgram()->isInitialized()); TextureMapperPlatformCompiledProgram* program = customOperation->validatedProgram()->platformCompiledProgram(); RefPtr<WebCustomFilterProgramProxy> customFilterProgramProxy; if (program->client()) customFilterProgramProxy = static_cast<WebCustomFilterProgramProxy*>(program->client()); else { customFilterProgramProxy = WebCustomFilterProgramProxy::create(); program->setClient(customFilterProgramProxy); } if (!customFilterProgramProxy->client()) { customFilterProgramProxy->setClient(this); m_customFilterPrograms.add(customFilterProgramProxy.get()); m_webPage->send(Messages::CoordinatedLayerTreeHostProxy::CreateCustomFilterProgram(customFilterProgramProxy->id(), customOperation->validatedProgram()->validatedProgramInfo())); } else { // If the client was not disconnected then this coordinator must be the client for it. ASSERT(customFilterProgramProxy->client() == this); } } }
PassRefPtr<AnimatableValue> AnimatableFilterOperations::interpolateTo(const AnimatableValue* value, double fraction) const { if (usesDefaultInterpolationWith(value)) return defaultInterpolateTo(this, value, fraction); const AnimatableFilterOperations* target = toAnimatableFilterOperations(value); FilterOperations result; size_t fromSize = operations().size(); size_t toSize = target->operations().size(); size_t size = std::max(fromSize, toSize); for (size_t i = 0; i < size; i++) { #if ENABLE(OILPAN) FilterOperation* from = (i < fromSize) ? m_operationWrapper->operations().operations()[i].get() : 0; FilterOperation* to = (i < toSize) ? target->m_operationWrapper->operations().operations()[i].get() : 0; #else FilterOperation* from = (i < fromSize) ? m_operations.operations()[i].get() : 0; FilterOperation* to = (i < toSize) ? target->m_operations.operations()[i].get() : 0; #endif RefPtrWillBeRawPtr<FilterOperation> blendedOp = FilterOperation::blend(from, to, fraction); if (blendedOp) result.operations().append(blendedOp); else ASSERT_NOT_REACHED(); } return AnimatableFilterOperations::create(result); }
static FilterOperations applyFilterAnimation(const FilterOperations* from, const FilterOperations* to, double progress, const IntSize& boxSize) { // First frame of an animation. if (!progress) return *from; // Last frame of an animation. if (progress == 1) return *to; if (!from->operationsMatch(*to)) return *to; FilterOperations result; size_t fromSize = from->operations().size(); size_t toSize = to->operations().size(); size_t size = std::max(fromSize, toSize); for (size_t i = 0; i < size; i++) { RefPtr<FilterOperation> fromOp = (i < fromSize) ? from->operations()[i].get() : 0; RefPtr<FilterOperation> toOp = (i < toSize) ? to->operations()[i].get() : 0; RefPtr<FilterOperation> blendedOp = toOp ? blendFunc(fromOp.get(), toOp.get(), progress, boxSize) : (fromOp ? blendFunc(0, fromOp.get(), progress, boxSize, true) : 0); if (blendedOp) result.operations().append(blendedOp); else { RefPtr<FilterOperation> identityOp = PassthroughFilterOperation::create(); if (progress > 0.5) result.operations().append(toOp ? toOp : identityOp); else result.operations().append(fromOp ? fromOp : identityOp); } } return result; }
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); } } }
void Internals::setBackgroundBlurOnNode(Node* node, int blurLength, ExceptionCode& ec) { if (!node) { ec = INVALID_ACCESS_ERR; return; } RenderObject* renderObject = node->renderer(); if (!renderObject) { ec = INVALID_NODE_TYPE_ERR; return; } RenderLayer* renderLayer = renderObject->enclosingLayer(); if (!renderLayer || !renderLayer->isComposited()) { ec = INVALID_STATE_ERR; return; } GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer(); if (!graphicsLayer) { ec = INVALID_NODE_TYPE_ERR; return; } PlatformLayer* platformLayer = graphicsLayer->platformLayer(); if (!platformLayer) { ec = INVALID_NODE_TYPE_ERR; return; } FilterOperations filters; filters.operations().append(BlurFilterOperation::create(Length(blurLength, Fixed), FilterOperation::BLUR)); platformLayer->setBackgroundFilters(filters); }
void CCDamageTracker::expandDamageRectWithForegroundFilters(const FilterOperations& filters) { // Filters can spread damage around in the surface. if (filters.hasFilterThatMovesPixels()) { int top, right, bottom, left; filters.getOutsets(top, right, bottom, left); m_currentDamageRect.move(-left, -top); m_currentDamageRect.expand(left + right, top + bottom); } }
bool GraphicsLayerTextureMapper::filtersCanBeComposited(const FilterOperations& filters) const { if (!filters.size()) return false; for (const auto& filterOperation : filters.operations()) { if (filterOperation->type() == FilterOperation::REFERENCE) return false; } return true; }
void LayerTreeRenderer::injectCachedCustomFilterPrograms(const FilterOperations& filters) const { for (size_t i = 0; i < filters.size(); ++i) { FilterOperation* operation = filters.operations().at(i).get(); if (operation->getOperationType() != FilterOperation::CUSTOM) continue; WebCustomFilterOperation* customOperation = static_cast<WebCustomFilterOperation*>(operation); ASSERT(!customOperation->program()); CustomFilterProgramMap::const_iterator iter = m_customFilterPrograms.find(customOperation->programID()); ASSERT(iter != m_customFilterPrograms.end()); customOperation->setProgram(iter->value.get()); } }
bool FilterOperations::operationsMatch(const FilterOperations& other) const { size_t numOperations = operations().size(); // If the sizes of the function lists don't match, the lists don't match if (numOperations != other.operations().size()) return false; // If the types of each function are not the same, the lists don't match for (size_t i = 0; i < numOperations; ++i) { if (!operations()[i]->isSameType(*other.operations()[i])) return false; } return true; }
void CoordinatedGraphicsScene::injectCachedCustomFilterPrograms(const FilterOperations& filters) const { for (size_t i = 0; i < filters.size(); ++i) { FilterOperation* operation = filters.operations().at(i).get(); if (operation->type() != FilterOperation::CUSTOM) continue; CoordinatedCustomFilterOperation* customOperation = static_cast<CoordinatedCustomFilterOperation*>(operation); ASSERT(!customOperation->program()); CustomFilterProgramMap::const_iterator iter = m_customFilterPrograms.find(customOperation->programID()); ASSERT(iter != m_customFilterPrograms.end()); customOperation->setProgram(iter->value.get()); } }
static bool shouldKeepContentTexture(const FilterOperations& filters) { for (size_t i = 0; i < filters.size(); ++i) { switch (filters.operations().at(i)->getOperationType()) { // The drop-shadow filter requires the content texture, because it needs to composite it // on top of the blurred shadow color. case FilterOperation::DROP_SHADOW: return true; default: break; } } return false; }
TEST(AnimationTranslationUtilTest, filtersWork) { FilterOperations ops; WebFilterOperationsMock outOps; EXPECT_CALL(outOps, appendSaturateFilter(0.5)); EXPECT_CALL(outOps, appendGrayscaleFilter(0.2f)); EXPECT_CALL(outOps, appendSepiaFilter(0.8f)); EXPECT_CALL(outOps, appendOpacityFilter(0.1f)); ops.operations().append(BasicColorMatrixFilterOperation::create(0.5, FilterOperation::SATURATE)); ops.operations().append(BasicColorMatrixFilterOperation::create(0.2, FilterOperation::GRAYSCALE)); ops.operations().append(BasicColorMatrixFilterOperation::create(0.8, FilterOperation::SEPIA)); ops.operations().append(BasicColorMatrixFilterOperation::create(0.1, FilterOperation::OPACITY)); toWebFilterOperations(ops, &outOps); }
bool toWebFilterOperations(const FilterOperations& inOperations, WebFilterOperations* outOperations) { SkiaImageFilterBuilder builder; FilterOutsets outsets = inOperations.outsets(); builder.setCropOffset(FloatSize(outsets.left(), outsets.top())); return builder.buildFilterOperations(inOperations, outOperations); }
static PassRefPtr<BitmapTexture> applyFilters(const FilterOperations& filters, TextureMapper* textureMapper, BitmapTexture* source, IntRect& targetRect) { if (!filters.size()) return source; RefPtr<BitmapTexture> filterSurface = shouldKeepContentTexture(filters) ? textureMapper->acquireTextureFromPool(source->size()) : source; return filterSurface->applyFilters(textureMapper, *source, filters); }
bool FilterOperations::canInterpolateWith(const FilterOperations& other) const { for (size_t i = 0; i < operations().size(); ++i) { if (!FilterOperation::canInterpolate(operations()[i]->type())) return false; } for (size_t i = 0; i < other.operations().size(); ++i) { if (!FilterOperation::canInterpolate(other.operations()[i]->type())) return false; } size_t commonSize = std::min(operations().size(), other.operations().size()); for (size_t i = 0; i < commonSize; ++i) { if (!operations()[i]->isSameType(*other.operations()[i])) return false; } return true; }
static PassRefPtr<BitmapTexture> applyFilters(const FilterOperations& filters, TextureMapper* textureMapper, BitmapTexture* source, IntRect& targetRect) { if (!filters.size()) return source; RefPtr<BitmapTexture> filterSurface(source); int leftOutset, topOutset, bottomOutset, rightOutset; if (filters.hasOutsets()) { filters.getOutsets(topOutset, rightOutset, bottomOutset, leftOutset); IntRect unfilteredTargetRect(targetRect); targetRect.move(std::max(0, -leftOutset), std::max(0, -topOutset)); targetRect.expand(leftOutset + rightOutset, topOutset + bottomOutset); targetRect.unite(unfilteredTargetRect); filterSurface = textureMapper->acquireTextureFromPool(targetRect.size()); } return filterSurface->applyFilters(*source, filters); }
void GraphicsLayer::setFilters(const FilterOperations& filters) { SkiaImageFilterBuilder builder; OwnPtr<WebFilterOperations> webFilters = adoptPtr(Platform::current()->compositorSupport()->createFilterOperations()); FilterOutsets outsets = filters.outsets(); builder.setCropOffset(FloatSize(outsets.left(), outsets.top())); builder.buildFilterOperations(filters, webFilters.get()); m_layer->layer()->setFilters(*webFilters); }
void RenderLayer::FilterInfo::updateCustomFilterClients(const FilterOperations& operations) { if (!operations.size()) { removeCustomFilterClients(); return; } Vector<RefPtr<CustomFilterProgram>> cachedCustomFilterPrograms; for (size_t i = 0, size = operations.size(); i < size; ++i) { const FilterOperation* filterOperation = operations.operations()[i].get(); if (filterOperation->getOperationType() != FilterOperation::CUSTOM) continue; const CustomFilterOperation* customFilterOperation = static_cast<const CustomFilterOperation*>(filterOperation); 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 CSSFilterListInterpolationType::apply( const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const { const InterpolableList& interpolableList = toInterpolableList(interpolableValue); const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*nonInterpolableValue); size_t length = interpolableList.length(); DCHECK_EQ(length, nonInterpolableList.length()); FilterOperations filterOperations; filterOperations.operations().reserveCapacity(length); for (size_t i = 0; i < length; i++) filterOperations.operations().push_back( FilterInterpolationFunctions::createFilter(*interpolableList.get(i), *nonInterpolableList.get(i), environment.state())); FilterListPropertyFunctions::setFilterList( cssProperty(), *environment.state().style(), std::move(filterOperations)); }
SkBitmap CCRenderSurface::applyFilters(LayerRendererChromium* layerRenderer, const FilterOperations& filters, ManagedTexture* sourceTexture) { if (filters.isEmpty()) return SkBitmap(); RefPtr<GraphicsContext3D> filterContext = CCProxy::hasImplThread() ? SharedGraphicsContext3D::getForImplThread() : SharedGraphicsContext3D::get(); if (!filterContext) return SkBitmap(); layerRenderer->context()->flush(); return CCRenderSurfaceFilters::apply(filters, sourceTexture->textureId(), sourceTexture->size(), filterContext.get()); }
bool LayerWebKitThread::filtersCanBeComposited(const FilterOperations& filters) { // There is work associated with compositing filters, even if there are zero filters, // so if there are no filters, claim we can't composite them. if (!filters.size()) return false; for (unsigned i = 0; i < filters.size(); ++i) { const FilterOperation* filterOperation = filters.at(i); switch (filterOperation->getOperationType()) { case FilterOperation::REFERENCE: #if ENABLE(CSS_SHADERS) case FilterOperation::CUSTOM: #endif return false; default: break; } } return true; }
bool ArgumentCoder<FilterOperations>::decode(ArgumentDecoder& decoder, FilterOperations& filters) { uint64_t filterCount; if (!decoder.decode(filterCount)) return false; for (uint64_t i = 0; i < filterCount; ++i) { RefPtr<FilterOperation> filter; if (!decodeFilterOperation(decoder, filter)) return false; filters.operations().append(std::move(filter)); } return true; }
bool GraphicsLayer::setFilters(const FilterOperations& filters) { SkiaImageFilterBuilder builder; OwnPtr<WebFilterOperations> webFilters = adoptPtr(Platform::current()->compositorSupport()->createFilterOperations()); FilterOutsets outsets = filters.outsets(); builder.setCropOffset(FloatSize(outsets.left(), outsets.top())); if (!builder.buildFilterOperations(filters, webFilters.get())) { // Make sure the filters are removed from the platform layer, as they are // going to fallback to software mode. webFilters->clear(); m_layer->layer()->setFilters(*webFilters); m_filters = FilterOperations(); return false; } m_layer->layer()->setFilters(*webFilters); m_filters = filters; return true; }
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 }
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; }
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); switch (filterOperation.type()) { case FilterOperation::REFERENCE: { ReferenceFilterOperation& referenceOperation = downcast<ReferenceFilterOperation>(filterOperation); effect = buildReferenceFilter(renderer, previousEffect, &referenceOperation); referenceOperation.setFilterEffect(effect); break; } case FilterOperation::GRAYSCALE: { BasicColorMatrixFilterOperation& colorMatrixOperation = downcast<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 = downcast<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 = downcast<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 = downcast<BasicColorMatrixFilterOperation>(filterOperation); Vector<float> inputParameters; inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation.amount())); effect = FEColorMatrix::create(*this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters); break; } case FilterOperation::INVERT: { BasicComponentTransferFilterOperation& componentTransferOperation = downcast<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 = downcast<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 = downcast<BasicComponentTransferFilterOperation>(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 = downcast<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 = downcast<BlurFilterOperation>(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 = downcast<DropShadowFilterOperation>(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(ColorSpaceSRGB); 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; }
bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& operations) { m_hasCustomShaderFilter = false; 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(); // FIXME: The effects now contain high dpi information, but the software path doesn't (yet) scale its backing. // When the proper dpi dependant backing size is allocated, we should remove deviceScaleFactor(...) here. float invZoom = 1.0f / ((style ? style->effectiveZoom() : 1.0f) * deviceScaleFactor(renderer->frame())); 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 = ReferenceFilterBuilder::build(this, renderer, previousEffect.get(), referenceOperation); 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 = narrowPrecisionToFloat(componentTransferOperation->amount()); transferFunction.intercept = 0; 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) * invZoom; effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation); break; } case FilterOperation::DROP_SHADOW: { DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(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; } 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); Document* document = renderer ? &renderer->document() : 0; effect = createCustomFilterEffect(this, document, customFilterOperation); if (effect) m_hasCustomShaderFilter = true; break; } default: break; } if (effect) { if (filterOperation->getOperationType() != 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 filters like FECustomFilter // 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; }
static bool copyWebCoreFilterOperationsToWebFilterOperations(const FilterOperations& filters, WebFilterOperations& webFilters) { for (size_t i = 0; i < filters.size(); ++i) { const FilterOperation& op = *filters.at(i); switch (op.getOperationType()) { case FilterOperation::REFERENCE: return false; // Not supported. case FilterOperation::GRAYSCALE: case FilterOperation::SEPIA: case FilterOperation::SATURATE: case FilterOperation::HUE_ROTATE: { float amount = static_cast<const BasicColorMatrixFilterOperation*>(&op)->amount(); switch (op.getOperationType()) { case FilterOperation::GRAYSCALE: webFilters.append(WebFilterOperation::createGrayscaleFilter(amount)); break; case FilterOperation::SEPIA: webFilters.append(WebFilterOperation::createSepiaFilter(amount)); break; case FilterOperation::SATURATE: webFilters.append(WebFilterOperation::createSaturateFilter(amount)); break; case FilterOperation::HUE_ROTATE: webFilters.append(WebFilterOperation::createHueRotateFilter(amount)); break; default: ASSERT_NOT_REACHED(); } break; } case FilterOperation::INVERT: case FilterOperation::OPACITY: case FilterOperation::BRIGHTNESS: case FilterOperation::CONTRAST: { float amount = static_cast<const BasicComponentTransferFilterOperation*>(&op)->amount(); switch (op.getOperationType()) { case FilterOperation::INVERT: webFilters.append(WebFilterOperation::createInvertFilter(amount)); break; case FilterOperation::OPACITY: webFilters.append(WebFilterOperation::createOpacityFilter(amount)); break; case FilterOperation::BRIGHTNESS: webFilters.append(WebFilterOperation::createBrightnessFilter(amount)); break; case FilterOperation::CONTRAST: webFilters.append(WebFilterOperation::createContrastFilter(amount)); break; default: ASSERT_NOT_REACHED(); } break; } case FilterOperation::BLUR: { float pixelRadius = static_cast<const BlurFilterOperation*>(&op)->stdDeviation().getFloatValue(); webFilters.append(WebFilterOperation::createBlurFilter(pixelRadius)); break; } case FilterOperation::DROP_SHADOW: { const DropShadowFilterOperation& dropShadowOp = *static_cast<const DropShadowFilterOperation*>(&op); webFilters.append(WebFilterOperation::createDropShadowFilter(WebPoint(dropShadowOp.x(), dropShadowOp.y()), dropShadowOp.stdDeviation(), dropShadowOp.color().rgb())); break; } #if ENABLE(CSS_SHADERS) case FilterOperation::CUSTOM: case FilterOperation::VALIDATED_CUSTOM: return false; // Not supported. #endif case FilterOperation::PASSTHROUGH: case FilterOperation::NONE: break; } } return true; }