• 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/effects/SkColorMatrix.h"
10 #include "include/effects/SkImageFilters.h"
11 #include "modules/svg/include/SkSVGFilterContext.h"
12 #include "modules/svg/include/SkSVGNode.h"
13 #include "modules/svg/include/SkSVGRenderContext.h"
14 #include "modules/svg/include/SkSVGTypes.h"
15 
16 namespace {
17 
ConvertFilterColorspace(sk_sp<SkImageFilter> && input,SkSVGColorspace src,SkSVGColorspace dst)18 sk_sp<SkImageFilter> ConvertFilterColorspace(sk_sp<SkImageFilter>&& input,
19                                              SkSVGColorspace src,
20                                              SkSVGColorspace dst) {
21     if (src == dst) {
22         return std::move(input);
23     } else if (src == SkSVGColorspace::kSRGB && dst == SkSVGColorspace::kLinearRGB) {
24         return SkImageFilters::ColorFilter(SkColorFilters::SRGBToLinearGamma(), input);
25     } else {
26         SkASSERT(src == SkSVGColorspace::kLinearRGB && dst == SkSVGColorspace::kSRGB);
27         return SkImageFilters::ColorFilter(SkColorFilters::LinearToSRGBGamma(), input);
28     }
29 }
30 
31 }  // namespace
32 
findResultById(const SkSVGStringType & id) const33 const SkSVGFilterContext::Result* SkSVGFilterContext::findResultById(
34         const SkSVGStringType& id) const {
35     return fResults.find(id);
36 }
37 
filterPrimitiveSubregion(const SkSVGFeInputType & input) const38 const SkRect& SkSVGFilterContext::filterPrimitiveSubregion(const SkSVGFeInputType& input) const {
39     const Result* res = nullptr;
40     if (input.type() == SkSVGFeInputType::Type::kFilterPrimitiveReference) {
41         res = fResults.find(input.id());
42     } else if (input.type() == SkSVGFeInputType::Type::kUnspecified) {
43         res = &fPreviousResult;
44     }
45     return res ? res->fFilterSubregion : fFilterEffectsRegion;
46 }
47 
registerResult(const SkSVGStringType & id,const sk_sp<SkImageFilter> & result,const SkRect & subregion,SkSVGColorspace resultColorspace)48 void SkSVGFilterContext::registerResult(const SkSVGStringType& id,
49                                         const sk_sp<SkImageFilter>& result,
50                                         const SkRect& subregion,
51                                         SkSVGColorspace resultColorspace) {
52     SkASSERT(!id.isEmpty());
53     fResults[id] = {result, subregion, resultColorspace};
54 }
55 
setPreviousResult(const sk_sp<SkImageFilter> & result,const SkRect & subregion,SkSVGColorspace resultColorspace)56 void SkSVGFilterContext::setPreviousResult(const sk_sp<SkImageFilter>& result,
57                                            const SkRect& subregion,
58                                            SkSVGColorspace resultColorspace) {
59     fPreviousResult = {result, subregion, resultColorspace};
60 }
61 
previousResultIsSourceGraphic() const62 bool SkSVGFilterContext::previousResultIsSourceGraphic() const {
63     return fPreviousResult.fImageFilter == nullptr;
64 }
65 
66 // https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveInAttribute
getInput(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType) const67 std::tuple<sk_sp<SkImageFilter>, SkSVGColorspace> SkSVGFilterContext::getInput(
68         const SkSVGRenderContext& ctx, const SkSVGFeInputType& inputType) const {
69     SkSVGColorspace inputCS = SkSVGColorspace::kSRGB;
70     sk_sp<SkImageFilter> result;
71     switch (inputType.type()) {
72         case SkSVGFeInputType::Type::kSourceAlpha: {
73             SkColorMatrix m;
74             m.setScale(0, 0, 0, 1.0f);
75             result = SkImageFilters::ColorFilter(SkColorFilters::Matrix(m), nullptr);
76             break;
77         }
78         case SkSVGFeInputType::Type::kSourceGraphic:
79             // Do nothing.
80             break;
81         case SkSVGFeInputType::Type::kFillPaint: {
82             const auto& fillPaint = ctx.fillPaint();
83             if (fillPaint.isValid()) {
84                 result = SkImageFilters::Paint(*fillPaint);
85             }
86             break;
87         }
88         case SkSVGFeInputType::Type::kStrokePaint: {
89             // The paint filter doesn't handle stroke paints properly, so convert to fill for
90             // simplicity.
91             // TODO: Paint filter is deprecated, but the replacement (SkShaders::*())
92             //       requires some extra work to handle all paint features (gradients, etc).
93             const auto& strokePaint = ctx.strokePaint();
94             if (strokePaint.isValid()) {
95                 SkPaint p = *strokePaint;
96                 p.setStyle(SkPaint::kFill_Style);
97                 result = SkImageFilters::Paint(p);
98             }
99             break;
100         }
101         case SkSVGFeInputType::Type::kFilterPrimitiveReference: {
102             const Result* res = findResultById(inputType.id());
103             if (res) {
104                 result = res->fImageFilter;
105                 inputCS = res->fColorspace;
106             }
107             break;
108         }
109         case SkSVGFeInputType::Type::kUnspecified: {
110             result = fPreviousResult.fImageFilter;
111             inputCS = fPreviousResult.fColorspace;
112             break;
113         }
114         default:
115             SkDebugf("unhandled filter input type %d\n", (int)inputType.type());
116             break;
117     }
118 
119     return {result, inputCS};
120 }
121 
resolveInputColorspace(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType) const122 SkSVGColorspace SkSVGFilterContext::resolveInputColorspace(
123         const SkSVGRenderContext& ctx, const SkSVGFeInputType& inputType) const {
124     return std::get<1>(this->getInput(ctx, inputType));
125 }
126 
resolveInput(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType) const127 sk_sp<SkImageFilter> SkSVGFilterContext::resolveInput(const SkSVGRenderContext& ctx,
128                                                       const SkSVGFeInputType& inputType) const {
129     return std::get<0>(this->getInput(ctx, inputType));
130 }
131 
resolveInput(const SkSVGRenderContext & ctx,const SkSVGFeInputType & inputType,SkSVGColorspace colorspace) const132 sk_sp<SkImageFilter> SkSVGFilterContext::resolveInput(const SkSVGRenderContext& ctx,
133                                                       const SkSVGFeInputType& inputType,
134                                                       SkSVGColorspace colorspace) const {
135     auto [result, inputCS] = this->getInput(ctx, inputType);
136     return ConvertFilterColorspace(std::move(result), inputCS, colorspace);
137 }
138