예제 #1
0
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);
}
예제 #2
0
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;
}
예제 #3
0
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));
}
예제 #4
0
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;
}
예제 #5
0
/* 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(&ltci, 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;
}