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);
}
SkImageFilter* CanvasRenderingContext2DState::getFilter(Element* styleResolutionHost, const Font& font) const
{
    if (!m_filterValue)
        return nullptr;

    if (!m_resolvedFilter) {
        RefPtr<ComputedStyle> filterStyle = ComputedStyle::create();
        // Must set font in case the filter uses any font-relative units (em, ex)
        filterStyle->setFont(font);

        StyleResolverState resolverState(styleResolutionHost->document(), styleResolutionHost, filterStyle.get());
        resolverState.setStyle(filterStyle);

        // TODO(junov): crbug.com/502877 Feed m_fillStyle and m_strokeStyle into FillPaint and
        // StrokePaint respectively for filters that reference SVG.
        StyleBuilder::applyProperty(CSSPropertyWebkitFilter, resolverState, m_filterValue.get());
        RefPtrWillBeRawPtr<FilterEffectBuilder> filterEffectBuilder = FilterEffectBuilder::create();
        const float effectiveZoom = 1.0f; // Deliberately ignore zoom on the canvas element
        filterEffectBuilder->build(styleResolutionHost, filterStyle->filter(), effectiveZoom);

        SkiaImageFilterBuilder imageFilterBuilder;
        RefPtrWillBeRawPtr<FilterEffect> lastEffect = filterEffectBuilder->lastEffect();
        m_resolvedFilter = imageFilterBuilder.build(lastEffect.get(), ColorSpaceDeviceRGB);
    }

    return m_resolvedFilter.get();
}
SkImageFilter* CanvasRenderingContext2DState::getFilter(Element* styleResolutionHost, const Font& font, IntSize canvasSize) const
{
    if (!m_filterValue)
        return nullptr;

    if (!m_resolvedFilter) {
        RefPtr<ComputedStyle> filterStyle = ComputedStyle::create();
        // Must set font in case the filter uses any font-relative units (em, ex)
        filterStyle->setFont(font);

        StyleResolverState resolverState(styleResolutionHost->document(), styleResolutionHost, filterStyle.get());
        resolverState.setStyle(filterStyle);

        StyleBuilder::applyProperty(CSSPropertyWebkitFilter, resolverState, m_filterValue.get());
        RefPtrWillBeRawPtr<FilterEffectBuilder> filterEffectBuilder = FilterEffectBuilder::create();

        // We can't reuse m_fillPaint and m_strokePaint for the filter, since these incorporate
        // the global alpha, which isn't applicable here.
        SkPaint fillPaintForFilter;
        SkPaint strokePaintForFilter;
        m_fillStyle->applyToPaint(fillPaintForFilter);
        m_strokeStyle->applyToPaint(strokePaintForFilter);
        fillPaintForFilter.setColor(m_fillStyle->paintColor());
        strokePaintForFilter.setColor(m_strokeStyle->paintColor());
        FloatSize floatCanvasSize(canvasSize);
        const double effectiveZoom = 1.0; // Deliberately ignore zoom on the canvas element
        filterEffectBuilder->build(styleResolutionHost, filterStyle->filter(), effectiveZoom, &floatCanvasSize, &fillPaintForFilter, &strokePaintForFilter);

        SkiaImageFilterBuilder imageFilterBuilder;
        RefPtrWillBeRawPtr<FilterEffect> lastEffect = filterEffectBuilder->lastEffect();
        m_resolvedFilter = imageFilterBuilder.build(lastEffect.get(), ColorSpaceDeviceRGB);
    }

    return m_resolvedFilter.get();
}
예제 #4
0
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);
}
예제 #5
0
FilterPainter::FilterPainter(DeprecatedPaintLayer& layer, GraphicsContext* context, const LayoutPoint& offsetFromRoot, const ClipRect& clipRect, DeprecatedPaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags,
    LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed)
    : m_filterInProgress(false)
    , m_context(context)
    , m_layoutObject(layer.layoutObject())
{
    if (!layer.filterEffectBuilder() || !layer.paintsWithFilters())
        return;

    ASSERT(layer.filterInfo());

    SkiaImageFilterBuilder builder;
    RefPtrWillBeRawPtr<FilterEffect> lastEffect = layer.filterEffectBuilder()->lastEffect();
    lastEffect->determineFilterPrimitiveSubregion(MapRectForward);
    RefPtr<SkImageFilter> imageFilter = builder.build(lastEffect.get(), ColorSpaceDeviceRGB);
    if (!imageFilter)
        return;

    if (!rootRelativeBoundsComputed) {
        rootRelativeBounds = layer.physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot);
        rootRelativeBoundsComputed = true;
    }

    // We'll handle clipping to the dirty rect before filter rasterization.
    // Filter processing will automatically expand the clip rect and the offscreen to accommodate any filter outsets.
    // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.

    // Subsequent code should not clip to the dirty rect, since we've already
    // done it above, and doing it later will defeat the outsets.
    paintingInfo.clipToDirtyRect = false;

    if (clipRect.rect() != paintingInfo.paintDirtyRect || clipRect.hasRadius()) {
        m_clipRecorder = adoptPtr(new LayerClipRecorder(*context, *layer.layoutObject(), DisplayItem::ClipLayerFilter, clipRect, &paintingInfo, LayoutPoint(), paintFlags));
    }

    ASSERT(m_layoutObject);
    if (RuntimeEnabledFeatures::slimmingPaintEnabled()) {
        ASSERT(context->displayItemList());
        if (!context->displayItemList()->displayItemConstructionIsDisabled()) {
            FilterOperations filterOperations(layer.computeFilterOperations(m_layoutObject->styleRef()));
            OwnPtr<WebFilterOperations> webFilterOperations = adoptPtr(Platform::current()->compositorSupport()->createFilterOperations());
            builder.buildFilterOperations(filterOperations, webFilterOperations.get());
            // FIXME: It's possible to have empty WebFilterOperations here even
            // though the SkImageFilter produced above is non-null, since the
            // layer's FilterEffectBuilder can have a stale representation of
            // the layer's filter. See crbug.com/502026.
            if (webFilterOperations->isEmpty())
                return;
            context->displayItemList()->createAndAppend<BeginFilterDisplayItem>(*m_layoutObject, imageFilter, rootRelativeBounds, webFilterOperations.release());
        }
    } else {
        BeginFilterDisplayItem filterDisplayItem(*m_layoutObject, imageFilter, rootRelativeBounds);
        filterDisplayItem.replay(*context);
    }

    m_filterInProgress = true;
}
예제 #6
0
PassRefPtr<SkImageFilter> FEMorphology::createImageFilter(SkiaImageFilterBuilder& builder)
{
    RefPtr<SkImageFilter> input(builder.build(inputEffect(0), operatingColorSpace()));
    SkScalar radiusX = SkFloatToScalar(filter()->applyHorizontalScale(m_radiusX));
    SkScalar radiusY = SkFloatToScalar(filter()->applyVerticalScale(m_radiusY));
    SkImageFilter::CropRect rect = getCropRect(builder.cropOffset());
    if (m_type == FEMORPHOLOGY_OPERATOR_DILATE)
        return adoptRef(SkDilateImageFilter::Create(radiusX, radiusY, input.get(), &rect));
    return adoptRef(SkErodeImageFilter::Create(radiusX, radiusY, input.get(), &rect));
}
PassRefPtr<SkImageFilter> FEComponentTransfer::createImageFilter(SkiaImageFilterBuilder& builder)
{
    RefPtr<SkImageFilter> input(builder.build(inputEffect(0), operatingColorSpace()));

    unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
    getValues(rValues, gValues, bValues, aValues);

    SkAutoTUnref<SkColorFilter> colorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues));

    SkImageFilter::CropRect cropRect = getCropRect(builder.cropOffset());
    return adoptRef(SkColorFilterImageFilter::Create(colorFilter, input.get(), &cropRect));
}
예제 #8
0
PassRefPtr<SkImageFilter> FEMerge::createImageFilter(SkiaImageFilterBuilder& builder)
{
    unsigned size = numberOfEffectInputs();

    OwnPtr<RefPtr<SkImageFilter>[]> inputRefs = adoptArrayPtr(new RefPtr<SkImageFilter>[size]);
    OwnPtr<SkImageFilter*[]> inputs = adoptArrayPtr(new SkImageFilter*[size]);
    for (unsigned i = 0; i < size; ++i) {
        inputRefs[i] = builder.build(inputEffect(i), operatingColorSpace());
        inputs[i] = inputRefs[i].get();
    }
    SkImageFilter::CropRect rect = getCropRect(builder.cropOffset());
    return adoptRef(SkMergeImageFilter::Create(inputs.get(), size, 0, &rect));
}
PassRefPtr<SkImageFilter> FEBlend::createImageFilter(SkiaImageFilterBuilder& builder)
{
    RefPtr<SkImageFilter> foreground(builder.build(inputEffect(0), operatingColorSpace()));
    RefPtr<SkImageFilter> background(builder.build(inputEffect(1), operatingColorSpace()));
    sk_sp<SkXfermode> mode(SkXfermode::Make(WebCoreCompositeToSkiaComposite(CompositeSourceOver, m_mode)));
    SkImageFilter::CropRect cropRect = getCropRect();
    return fromSkSp(SkXfermodeImageFilter::Make(std::move(mode), background.get(), foreground.get(), &cropRect));
}
예제 #10
0
PassRefPtr<SkImageFilter> FELighting::createImageFilter(SkiaImageFilterBuilder& builder)
{
    if (!m_lightSource)
        return createTransparentBlack(builder);

    SkImageFilter::CropRect rect = getCropRect(builder.cropOffset());
    Color lightColor = adaptColorToOperatingColorSpace(m_lightingColor);
    RefPtr<SkImageFilter> input(builder.build(inputEffect(0), operatingColorSpace()));
    switch (m_lightSource->type()) {
    case LS_DISTANT: {
        DistantLightSource* distantLightSource = static_cast<DistantLightSource*>(m_lightSource.get());
        float azimuthRad = deg2rad(distantLightSource->azimuth());
        float elevationRad = deg2rad(distantLightSource->elevation());
        const SkPoint3 direction = SkPoint3::Make(cosf(azimuthRad) * cosf(elevationRad), sinf(azimuthRad) * cosf(elevationRad), sinf(elevationRad));
        if (m_specularConstant > 0)
            return adoptRef(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect));
        return adoptRef(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect));
    }
    case LS_POINT: {
        PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get());
        const FloatPoint3D position = pointLightSource->position();
        const SkPoint3 skPosition = SkPoint3::Make(position.x(), position.y(), position.z());
        if (m_specularConstant > 0)
            return adoptRef(SkLightingImageFilter::CreatePointLitSpecular(skPosition, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect));
        return adoptRef(SkLightingImageFilter::CreatePointLitDiffuse(skPosition, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect));
    }
    case LS_SPOT: {
        SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get());
        const SkPoint3 location = SkPoint3::Make(spotLightSource->position().x(), spotLightSource->position().y(), spotLightSource->position().z());
        const SkPoint3 target = SkPoint3::Make(spotLightSource->direction().x(), spotLightSource->direction().y(), spotLightSource->direction().z());
        float specularExponent = spotLightSource->specularExponent();
        float limitingConeAngle = spotLightSource->limitingConeAngle();
        if (!limitingConeAngle || limitingConeAngle > 90 || limitingConeAngle < -90)
            limitingConeAngle = 90;
        if (m_specularConstant > 0)
            return adoptRef(SkLightingImageFilter::CreateSpotLitSpecular(location, target, specularExponent, limitingConeAngle, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect));
        return adoptRef(SkLightingImageFilter::CreateSpotLitDiffuse(location, target, specularExponent, limitingConeAngle, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect));
    }
    default:
        ASSERT_NOT_REACHED();
        return nullptr;
    }
}
예제 #11
0
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;
}
예제 #12
0
PassRefPtr<SkImageFilter> FEConvolveMatrix::createImageFilter(SkiaImageFilterBuilder& builder)
{
    if (!parametersValid())
        return createTransparentBlack(builder);

    RefPtr<SkImageFilter> input(builder.build(inputEffect(0), operatingColorSpace()));
    SkISize kernelSize(SkISize::Make(m_kernelSize.width(), m_kernelSize.height()));
    // parametersValid() above checks that the kernel area fits in int.
    int numElements = safeCast<int>(m_kernelSize.area());
    SkScalar gain = SkFloatToScalar(1.0f / m_divisor);
    SkScalar bias = SkFloatToScalar(m_bias * 255);
    SkIPoint target = SkIPoint::Make(m_targetOffset.x(), m_targetOffset.y());
    SkMatrixConvolutionImageFilter::TileMode tileMode = toSkiaTileMode(m_edgeMode);
    bool convolveAlpha = !m_preserveAlpha;
    OwnPtr<SkScalar[]> kernel = adoptArrayPtr(new SkScalar[numElements]);
    for (int i = 0; i < numElements; ++i)
        kernel[i] = SkFloatToScalar(m_kernelMatrix[numElements - 1 - i]);
    SkImageFilter::CropRect cropRect = getCropRect(builder.cropOffset());
    return adoptRef(SkMatrixConvolutionImageFilter::Create(kernelSize, kernel.get(), gain, bias, target, tileMode, convolveAlpha, input.get(), &cropRect));
}
예제 #13
0
static void paintFilteredContent(const LayoutObject& object, GraphicsContext& context, FilterData* filterData)
{
    ASSERT(filterData->m_state == FilterData::ReadyToPaint);
    ASSERT(filterData->filter->sourceGraphic());

    filterData->m_state = FilterData::PaintingFilter;

    SkiaImageFilterBuilder builder;
    RefPtr<SkImageFilter> imageFilter = builder.build(filterData->filter->lastEffect(), ColorSpaceDeviceRGB);
    FloatRect boundaries = filterData->filter->filterRegion();
    context.save();

    // Clip drawing of filtered image to the minimum required paint rect.
    FilterEffect* lastEffect = filterData->filter->lastEffect();
    context.clipRect(lastEffect->determineAbsolutePaintRect(lastEffect->maxEffectRect()));

#ifdef CHECK_CTM_FOR_TRANSFORMED_IMAGEFILTER
    // TODO: Remove this workaround once skew/rotation support is added in Skia
    // (https://code.google.com/p/skia/issues/detail?id=3288, crbug.com/446935).
    // If the CTM contains rotation or shearing, apply the filter to
    // the unsheared/unrotated matrix, and do the shearing/rotation
    // as a final pass.
    AffineTransform ctm = SVGLayoutSupport::deprecatedCalculateTransformToLayer(&object);
    if (ctm.b() || ctm.c()) {
        AffineTransform scaleAndTranslate;
        scaleAndTranslate.translate(ctm.e(), ctm.f());
        scaleAndTranslate.scale(ctm.xScale(), ctm.yScale());
        ASSERT(scaleAndTranslate.isInvertible());
        AffineTransform shearAndRotate = scaleAndTranslate.inverse();
        shearAndRotate.multiply(ctm);
        context.concatCTM(shearAndRotate.inverse());
        imageFilter = builder.buildTransform(shearAndRotate, imageFilter.get());
    }
#endif

    context.beginLayer(1, SkXfermode::kSrcOver_Mode, &boundaries, ColorFilterNone, imageFilter.get());
    context.endLayer();
    context.restore();

    filterData->m_state = FilterData::ReadyToPaint;
}
예제 #14
0
PassRefPtr<SkImageFilter> SourceAlpha::createImageFilter(SkiaImageFilterBuilder& builder)
{
    RefPtr<SkImageFilter> sourceGraphic(builder.build(inputEffect(0), operatingColorSpace()));
    SkScalar matrix[20] = {
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, SK_Scalar1, 0
    };
    RefPtr<SkColorFilter> colorFilter(adoptRef(SkColorMatrixFilter::Create(matrix)));
    return adoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), sourceGraphic.get()));
}
PassRefPtr<SkImageFilter> FEBoxReflect::createImageFilter(SkiaImageFilterBuilder& builder)
{
    RefPtr<SkImageFilter> input(builder.build(inputEffect(0), operatingColorSpace()));
    return builder.buildBoxReflectFilter(m_reflectionDirection, m_offset, nullptr, input.get());
}
예제 #16
0
PassRefPtr<SkImageFilter> FilterEffect::createTransparentBlack(SkiaImageFilterBuilder& builder) const
{
    SkAutoTUnref<SkColorFilter> filter(SkColorFilter::CreateModeFilter(0, SkXfermode::kClear_Mode));
    SkImageFilter::CropRect rect = getCropRect(builder.cropOffset());
    return adoptRef(SkColorFilterImageFilter::Create(filter, nullptr, &rect));
}
예제 #17
0
    void colorSpaceTest()
    {
        // Build filter tree
        RefPtr<ReferenceFilter> referenceFilter = ReferenceFilter::create();

        // Add a dummy source graphic input
        RefPtr<FilterEffect> sourceEffect = referenceFilter->sourceGraphic();
        sourceEffect->setOperatingColorSpace(ColorSpaceDeviceRGB);

        // Add a blur effect (with input : source)
        RefPtr<FilterEffect> blurEffect =
            FEGaussianBlur::create(referenceFilter.get(), 3.0f, 3.0f);
        blurEffect->setOperatingColorSpace(ColorSpaceLinearRGB);
        blurEffect->inputEffects().append(sourceEffect);

        // Add a blend effect (with inputs : blur, source)
        RefPtr<FilterEffect> blendEffect =
            FEBlend::create(referenceFilter.get(), FEBLEND_MODE_NORMAL);
        blendEffect->setOperatingColorSpace(ColorSpaceDeviceRGB);
        FilterEffectVector& blendInputs = blendEffect->inputEffects();
        blendInputs.reserveCapacity(2);
        blendInputs.append(sourceEffect);
        blendInputs.append(blurEffect);

        // Add a merge effect (with inputs : blur, blend)
        RefPtr<FilterEffect> mergeEffect = FEMerge::create(referenceFilter.get());
        mergeEffect->setOperatingColorSpace(ColorSpaceLinearRGB);
        FilterEffectVector& mergeInputs = mergeEffect->inputEffects();
        mergeInputs.reserveCapacity(2);
        mergeInputs.append(blurEffect);
        mergeInputs.append(blendEffect);
        referenceFilter->setLastEffect(mergeEffect);

        // Get SkImageFilter resulting tree
        SkiaImageFilterBuilder builder;
        RefPtr<SkImageFilter> filter = builder.build(referenceFilter->lastEffect(), ColorSpaceDeviceRGB);

        // Let's check that the resulting tree looks like this :
        //      ColorSpace (Linear->Device) : CS (L->D)
        //                |
        //             Merge (L)
        //              |     |
        //              |    CS (D->L)
        //              |          |
        //              |      Blend (D)
        //              |       /    |
        //              |  CS (L->D) |
        //              |  /         |
        //             Blur (L)      |
        //                 \         |
        //               CS (D->L)   |
        //                   \       |
        //                 Source Graphic (D)

        EXPECT_EQ(filter->countInputs(), 1); // Should be CS (L->D)
        SkImageFilter* child = filter->getInput(0); // Should be Merge
        EXPECT_EQ(child->asColorFilter(0), false);
        EXPECT_EQ(child->countInputs(), 2);
        child = child->getInput(1); // Should be CS (D->L)
        EXPECT_EQ(child->asColorFilter(0), true);
        EXPECT_EQ(child->countInputs(), 1);
        child = child->getInput(0); // Should be Blend
        EXPECT_EQ(child->asColorFilter(0), false);
        EXPECT_EQ(child->countInputs(), 2);
        child = child->getInput(0); // Should be CS (L->D)
        EXPECT_EQ(child->asColorFilter(0), true);
        EXPECT_EQ(child->countInputs(), 1);
        child = child->getInput(0); // Should be Blur
        EXPECT_EQ(child->asColorFilter(0), false);
        EXPECT_EQ(child->countInputs(), 1);
        child = child->getInput(0); // Should be CS (D->L)
        EXPECT_EQ(child->asColorFilter(0), true);
        EXPECT_EQ(child->countInputs(), 1);
    }