• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "modules/svg/include/SkSVGFilterContext.h"
8 
9 #include "include/core/SkBlendMode.h"
10 #include "include/core/SkColorFilter.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/effects/SkColorMatrix.h"
13 #include "include/effects/SkImageFilters.h"
14 #include "modules/svg/include/SkSVGNode.h"
15 #include "modules/svg/include/SkSVGRenderContext.h"
16 #include "modules/svg/include/SkSVGTypes.h"
17 
18 namespace {
19 
ConvertFilterColorspace(sk_sp<SkImageFilter> && input,SkSVGColorspace src,SkSVGColorspace dst)20 sk_sp<SkImageFilter> ConvertFilterColorspace(sk_sp<SkImageFilter>&& input,
21                                              SkSVGColorspace src,
22                                              SkSVGColorspace dst) {
23     if (src == dst) {
24         return std::move(input);
25     } else if (src == SkSVGColorspace::kSRGB && dst == SkSVGColorspace::kLinearRGB) {
26         return SkImageFilters::ColorFilter(SkColorFilters::SRGBToLinearGamma(), input);
27     } else {
28         SkASSERT(src == SkSVGColorspace::kLinearRGB && dst == SkSVGColorspace::kSRGB);
29         return SkImageFilters::ColorFilter(SkColorFilters::LinearToSRGBGamma(), input);
30     }
31 }
32 
paint_as_shader(const SkPaint & paint)33 sk_sp<SkShader> paint_as_shader(const SkPaint& paint) {
34     sk_sp<SkShader> shader = paint.refShader();
35     auto color = paint.getColor4f();
36     if (shader && color.fA < 1.f) {
37         // Multiply by paint alpha
38         shader = shader->makeWithColorFilter(
39                 SkColorFilters::Blend(color, /*colorSpace=*/nullptr, SkBlendMode::kDstIn));
40     } else if (!shader) {
41         shader = SkShaders::Color(color, /*colorSpace=*/nullptr);
42     }
43     if (paint.getColorFilter()) {
44         shader = shader->makeWithColorFilter(paint.refColorFilter());
45     }
46     return shader;
47 }
48 
49 }  // namespace
50 
findResultById(const SkSVGStringType & id) const51 const SkSVGFilterContext::Result* SkSVGFilterContext::findResultById(
52         const SkSVGStringType& id) const {
53     return fResults.find(id);
54 }
55 
filterPrimitiveSubregion(const SkSVGFeInputType & input) const56 const SkRect& SkSVGFilterContext::filterPrimitiveSubregion(const SkSVGFeInputType& input) const {
57     const Result* res = nullptr;
58     if (input.type() == SkSVGFeInputType::Type::kFilterPrimitiveReference) {
59         res = fResults.find(input.id());
60     } else if (input.type() == SkSVGFeInputType::Type::kUnspecified) {
61         res = &fPreviousResult;
62     }
63     return res ? res->fFilterSubregion : fFilterEffectsRegion;
64 }
65 
registerResult(const SkSVGStringType & id,const sk_sp<SkImageFilter> & result,const SkRect & subregion,SkSVGColorspace resultColorspace)66 void SkSVGFilterContext::registerResult(const SkSVGStringType& id,
67                                         const sk_sp<SkImageFilter>& result,
68                                         const SkRect& subregion,
69                                         SkSVGColorspace resultColorspace) {
70     SkASSERT(!id.isEmpty());
71     fResults[id] = {result, subregion, resultColorspace};
72 }
73 
setPreviousResult(const sk_sp<SkImageFilter> & result,const SkRect & subregion,SkSVGColorspace resultColorspace)74 void SkSVGFilterContext::setPreviousResult(const sk_sp<SkImageFilter>& result,
75                                            const SkRect& subregion,
76                                            SkSVGColorspace resultColorspace) {
77     fPreviousResult = {result, subregion, resultColorspace};
78 }
79 
previousResultIsSourceGraphic() const80 bool SkSVGFilterContext::previousResultIsSourceGraphic() const {
81     return fPreviousResult.fImageFilter == nullptr;
82 }
83 
84 // https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveInAttribute
getInput(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType) const85 std::tuple<sk_sp<SkImageFilter>, SkSVGColorspace> SkSVGFilterContext::getInput(
86         const SkSVGRenderContext& ctx, const SkSVGFeInputType& inputType) const {
87     SkSVGColorspace inputCS = SkSVGColorspace::kSRGB;
88     sk_sp<SkImageFilter> result;
89     switch (inputType.type()) {
90         case SkSVGFeInputType::Type::kSourceAlpha: {
91             SkColorMatrix m;
92             m.setScale(0, 0, 0, 1.0f);
93             result = SkImageFilters::ColorFilter(SkColorFilters::Matrix(m), nullptr);
94             break;
95         }
96         case SkSVGFeInputType::Type::kSourceGraphic:
97             // Do nothing.
98             break;
99         case SkSVGFeInputType::Type::kFillPaint: {
100             const auto& fillPaint = ctx.fillPaint();
101             if (fillPaint.isValid()) {
102                 auto dither = fillPaint->isDither() ? SkImageFilters::Dither::kYes
103                                                     : SkImageFilters::Dither::kNo;
104                 result = SkImageFilters::Shader(paint_as_shader(*fillPaint), dither);
105             }
106             break;
107         }
108         case SkSVGFeInputType::Type::kStrokePaint: {
109             // The paint filter doesn't apply fill/stroke styling, but use the paint settings
110             // defined for strokes.
111             const auto& strokePaint = ctx.strokePaint();
112             if (strokePaint.isValid()) {
113                 auto dither = strokePaint->isDither() ? SkImageFilters::Dither::kYes
114                                                       : SkImageFilters::Dither::kNo;
115                 result = SkImageFilters::Shader(paint_as_shader(*strokePaint), dither);
116             }
117             break;
118         }
119         case SkSVGFeInputType::Type::kFilterPrimitiveReference: {
120             const Result* res = findResultById(inputType.id());
121             if (res) {
122                 result = res->fImageFilter;
123                 inputCS = res->fColorspace;
124             }
125             break;
126         }
127         case SkSVGFeInputType::Type::kUnspecified: {
128             result = fPreviousResult.fImageFilter;
129             inputCS = fPreviousResult.fColorspace;
130             break;
131         }
132         default:
133             SkDebugf("unhandled filter input type %d\n", (int)inputType.type());
134             break;
135     }
136 
137     return {result, inputCS};
138 }
139 
resolveInputColorspace(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType) const140 SkSVGColorspace SkSVGFilterContext::resolveInputColorspace(
141         const SkSVGRenderContext& ctx, const SkSVGFeInputType& inputType) const {
142     return std::get<1>(this->getInput(ctx, inputType));
143 }
144 
resolveInput(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType) const145 sk_sp<SkImageFilter> SkSVGFilterContext::resolveInput(const SkSVGRenderContext& ctx,
146                                                       const SkSVGFeInputType& inputType) const {
147     return std::get<0>(this->getInput(ctx, inputType));
148 }
149 
resolveInput(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType,SkSVGColorspace colorspace) const150 sk_sp<SkImageFilter> SkSVGFilterContext::resolveInput(const SkSVGRenderContext& ctx,
151                                                       const SkSVGFeInputType& inputType,
152                                                       SkSVGColorspace colorspace) const {
153     auto [result, inputCS] = this->getInput(ctx, inputType);
154     return ConvertFilterColorspace(std::move(result), inputCS, colorspace);
155 }
156