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