void FEImage::platformApplySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; SVGFilter* svgFilter = static_cast<SVGFilter*>(filter()); FloatRect destRect = svgFilter->absoluteTransform().mapRect(filterPrimitiveSubregion()); FloatRect srcRect; if (renderer) srcRect = svgFilter->absoluteTransform().mapRect(renderer->repaintRectInLocalCoordinates()); else { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio.transformRect(destRect, srcRect); } IntPoint paintLocation = absolutePaintRect().location(); destRect.move(-paintLocation.x(), -paintLocation.y()); // FEImage results are always in ColorSpaceDeviceRGB setResultColorSpace(ColorSpaceDeviceRGB); if (renderer) { const AffineTransform& absoluteTransform = svgFilter->absoluteTransform(); resultImage->context()->concatCTM(absoluteTransform); SVGElement* contextNode = static_cast<SVGElement*>(renderer->node()); if (contextNode->isStyled() && static_cast<SVGStyledElement*>(contextNode)->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); float width = 0; float height = 0; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(width, height)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(0, 0, width, height), destRect)); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtreeToImageBuffer(resultImage, renderer, contentTransformation); return; } resultImage->context()->drawImage(m_image.get(), ColorSpaceDeviceRGB, destRect, srcRect); }
std::unique_ptr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter& filter) const { static const unsigned maxCountChildNodes = 200; if (filterElement().countChildNodes() > maxCountChildNodes) return nullptr; FloatRect targetBoundingBox = filter.targetBoundingBox(); // Add effects to the builder auto builder = std::make_unique<SVGFilterBuilder>(SourceGraphic::create(filter)); for (auto& element : childrenOfType<SVGFilterPrimitiveStandardAttributes>(filterElement())) { RefPtr<FilterEffect> effect = element.build(builder.get(), filter); if (!effect) { builder->clearEffects(); return nullptr; } builder->appendEffectToEffectReferences(effect.copyRef(), element.renderer()); element.setStandardAttributes(effect.get()); effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(&element, filterElement().primitiveUnits(), targetBoundingBox)); if (element.renderer()) effect->setOperatingColorSpace(element.renderer()->style().svgStyle().colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceSRGB); builder->add(element.result(), WTFMove(effect)); } return builder; }
void FEImage::determineAbsolutePaintRect() { SVGFilter* svgFilter = static_cast<SVGFilter*>(filter()); FloatRect paintRect = svgFilter->absoluteTransform().mapRect(filterPrimitiveSubregion()); FloatRect srcRect; if (m_image) { srcRect.setSize(m_image->size()); m_preserveAspectRatio.transformRect(paintRect, srcRect); } else if (RenderObject* renderer = referencedRenderer()) srcRect = svgFilter->absoluteTransform().mapRect(renderer->repaintRectInLocalCoordinates()); if (clipsToBounds()) paintRect.intersect(maxEffectRect()); else paintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(paintRect)); }
FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect) { SVGFilter* filter = static_cast<SVGFilter*>(effect->filter()); ASSERT(filter); // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect. FloatRect subregion; if (unsigned numberOfInputEffects = effect->inputEffects().size()) { subregion = determineFilterPrimitiveSubregion(effect->inputEffect(0)); for (unsigned i = 1; i < numberOfInputEffects; ++i) subregion.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i))); } else subregion = filter->filterRegionInUserSpace(); // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>. if (effect->filterEffectType() == FilterEffectTypeTile) subregion = filter->filterRegionInUserSpace(); FloatRect effectBoundaries = effect->effectBoundaries(); if (effect->hasX()) subregion.setX(effectBoundaries.x()); if (effect->hasY()) subregion.setY(effectBoundaries.y()); if (effect->hasWidth()) subregion.setWidth(effectBoundaries.width()); if (effect->hasHeight()) subregion.setHeight(effectBoundaries.height()); effect->setFilterPrimitiveSubregion(subregion); FloatRect absoluteSubregion = filter->absoluteTransform().mapRect(subregion); FloatSize filterResolution = filter->filterResolution(); absoluteSubregion.scale(filterResolution.width(), filterResolution.height()); // Clip every filter effect to the filter region. FloatRect absoluteScaledFilterRegion = filter->filterRegion(); absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height()); absoluteSubregion.intersect(absoluteScaledFilterRegion); effect->setMaxEffectRect(absoluteSubregion); return subregion; }
/* static */ OP_STATUS SVGFilter::Create(HTML_Element* filter_elm, HTML_Element* filter_target_elm, const SVGValueContext& vcxt, SVGElementResolver* resolver, SVGDocumentContext* doc_ctx, SVGCanvas* canvas, SVGBoundingBox* override_targetbbox, SVGFilter** outfilter) { OP_ASSERT(outfilter); SVGFilter* filter = OP_NEW(SVGFilter, (filter_target_elm)); *outfilter = filter; if (!filter) return OpStatus::ERR_NO_MEMORY; RETURN_IF_ERROR(FetchValues(filter, filter_elm, resolver, doc_ctx, filter_target_elm, vcxt, override_targetbbox)); // Determine limits (consider doing this based on painting // context, rt-size, instead). int max_width = INT_MAX; int max_height = INT_MAX; SVGUtils::LimitCanvasSize(doc_ctx->GetDocument(), doc_ctx->GetVisualDevice(), max_width, max_height); filter->m_max_res_width = max_width; filter->m_max_res_height = max_height; // Need these for <feImage> filter->m_doc_ctx = doc_ctx; filter->m_resolver = resolver; // Setup the input nodes filter->SetupInputNodes(); SVGLogicalTreeChildIterator ltci; SVGFilterTraversalObject filter_object(<ci, filter); filter_object.SetupResolver(resolver); filter_object.SetDocumentContext(doc_ctx); SVGNumberPair vp(vcxt.viewport_width, vcxt.viewport_height); filter_object.SetCurrentViewport(vp); // This traversal object should be able to do it's job without a canvas filter_object.SetCanvas(NULL); RETURN_IF_ERROR(SVGTraverser::Traverse(&filter_object, filter->GetChildRoot(), NULL)); // Transfer state from the canvas if needed if (filter->ReferencesInputNode(INPUTNODE_FILLPAINT)) { SVGPaintDesc fillpaint; fillpaint.color = canvas->GetActualFillColor(); fillpaint.opacity = canvas->GetFillOpacity(); fillpaint.pserver = canvas->GetFillPaintServer(); filter->m_input_nodes[INPUTNODE_FILLPAINT].SetPaint(fillpaint); } if (filter->ReferencesInputNode(INPUTNODE_STROKEPAINT)) { SVGPaintDesc strokepaint; strokepaint.color = canvas->GetActualStrokeColor(); strokepaint.opacity = canvas->GetStrokeOpacity(); strokepaint.pserver = canvas->GetStrokePaintServer(); filter->m_input_nodes[INPUTNODE_STROKEPAINT].SetPaint(strokepaint); } if (filter->ReferencesInputNode(INPUTNODE_BACKGROUNDIMAGE) || filter->ReferencesInputNode(INPUTNODE_BACKGROUNDALPHA)) { doc_ctx->SetNeedsBackgroundLayers(); } return OpStatus::OK; }
FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect) { FloatRect uniteRect; FloatRect subregionBoundingBox = effect->effectBoundaries(); FloatRect subregion = subregionBoundingBox; SVGFilter* filter = static_cast<SVGFilter*>(effect->filter()); ASSERT(filter); if (effect->filterEffectType() != FilterEffectTypeTile) { // FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect. if (unsigned numberOfInputEffects = effect->inputEffects().size()) { for (unsigned i = 0; i < numberOfInputEffects; ++i) uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i))); } else uniteRect = filter->filterRegionInUserSpace(); } else { determineFilterPrimitiveSubregion(effect->inputEffect(0)); uniteRect = filter->filterRegionInUserSpace(); } if (filter->effectBoundingBoxMode()) { subregion = uniteRect; // Avoid the calling of a virtual method several times. FloatRect targetBoundingBox = filter->targetBoundingBox(); if (effect->hasX()) subregion.setX(targetBoundingBox.x() + subregionBoundingBox.x() * targetBoundingBox.width()); if (effect->hasY()) subregion.setY(targetBoundingBox.y() + subregionBoundingBox.y() * targetBoundingBox.height()); if (effect->hasWidth()) subregion.setWidth(subregionBoundingBox.width() * targetBoundingBox.width()); if (effect->hasHeight()) subregion.setHeight(subregionBoundingBox.height() * targetBoundingBox.height()); } else { if (!effect->hasX()) subregion.setX(uniteRect.x()); if (!effect->hasY()) subregion.setY(uniteRect.y()); if (!effect->hasWidth()) subregion.setWidth(uniteRect.width()); if (!effect->hasHeight()) subregion.setHeight(uniteRect.height()); } effect->setFilterPrimitiveSubregion(subregion); FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion); FloatSize filterResolution = filter->filterResolution(); absoluteSubregion.scale(filterResolution.width(), filterResolution.height()); // FEImage needs the unclipped subregion in absolute coordinates to determine the correct // destination rect in combination with preserveAspectRatio. if (effect->filterEffectType() == FilterEffectTypeImage) static_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion); // Clip every filter effect to the filter region. FloatRect absoluteScaledFilterRegion = filter->filterRegion(); absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height()); absoluteSubregion.intersect(absoluteScaledFilterRegion); effect->setMaxEffectRect(enclosingIntRect(absoluteSubregion)); return subregion; }