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/effects/SkImageFilters.h"
9 #include "modules/svg/include/SkSVGAttributeParser.h"
10 #include "modules/svg/include/SkSVGFe.h"
11 #include "modules/svg/include/SkSVGFilterContext.h"
12 #include "modules/svg/include/SkSVGRenderContext.h"
13
makeImageFilter(const SkSVGRenderContext & ctx,const SkSVGFilterContext & fctx) const14 sk_sp<SkImageFilter> SkSVGFe::makeImageFilter(const SkSVGRenderContext& ctx,
15 const SkSVGFilterContext& fctx) const {
16 return this->onMakeImageFilter(ctx, fctx);
17 }
18
resolveBoundaries(const SkSVGRenderContext & ctx,const SkSVGFilterContext & fctx) const19 SkRect SkSVGFe::resolveBoundaries(const SkSVGRenderContext& ctx,
20 const SkSVGFilterContext& fctx) const {
21 const auto x = fX.isValid() ? *fX : SkSVGLength(0, SkSVGLength::Unit::kPercentage);
22 const auto y = fY.isValid() ? *fY : SkSVGLength(0, SkSVGLength::Unit::kPercentage);
23 const auto w = fWidth.isValid() ? *fWidth : SkSVGLength(100, SkSVGLength::Unit::kPercentage);
24 const auto h = fHeight.isValid() ? *fHeight : SkSVGLength(100, SkSVGLength::Unit::kPercentage);
25
26 return ctx.resolveOBBRect(x, y, w, h, fctx.primitiveUnits());
27 }
28
AnyIsStandardInput(const SkSVGFilterContext & fctx,const std::vector<SkSVGFeInputType> & inputs)29 static bool AnyIsStandardInput(const SkSVGFilterContext& fctx,
30 const std::vector<SkSVGFeInputType>& inputs) {
31 for (const auto& in : inputs) {
32 switch (in.type()) {
33 case SkSVGFeInputType::Type::kFilterPrimitiveReference:
34 break;
35 case SkSVGFeInputType::Type::kSourceGraphic:
36 case SkSVGFeInputType::Type::kSourceAlpha:
37 case SkSVGFeInputType::Type::kBackgroundImage:
38 case SkSVGFeInputType::Type::kBackgroundAlpha:
39 case SkSVGFeInputType::Type::kFillPaint:
40 case SkSVGFeInputType::Type::kStrokePaint:
41 return true;
42 case SkSVGFeInputType::Type::kUnspecified:
43 // Unspecified means previous result (which may be SourceGraphic).
44 if (fctx.previousResultIsSourceGraphic()) {
45 return true;
46 }
47 break;
48 }
49 }
50
51 return false;
52 }
53
resolveFilterSubregion(const SkSVGRenderContext & ctx,const SkSVGFilterContext & fctx) const54 SkRect SkSVGFe::resolveFilterSubregion(const SkSVGRenderContext& ctx,
55 const SkSVGFilterContext& fctx) const {
56 // From https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveSubRegion,
57 // the default filter effect subregion is equal to the union of the subregions defined
58 // for all "referenced nodes" (filter effect inputs). If there are no inputs, the
59 // default subregion is equal to the filter effects region
60 // (https://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion).
61 const std::vector<SkSVGFeInputType> inputs = this->getInputs();
62 SkRect defaultSubregion;
63 if (inputs.empty() || AnyIsStandardInput(fctx, inputs)) {
64 defaultSubregion = fctx.filterEffectsRegion();
65 } else {
66 defaultSubregion = fctx.filterPrimitiveSubregion(inputs[0]);
67 for (size_t i = 1; i < inputs.size(); i++) {
68 defaultSubregion.join(fctx.filterPrimitiveSubregion(inputs[i]));
69 }
70 }
71
72 // Next resolve the rect specified by the x, y, width, height attributes on this filter effect.
73 // If those attributes were given, they override the corresponding attribute of the default
74 // filter effect subregion calculated above.
75 const SkRect boundaries = this->resolveBoundaries(ctx, fctx);
76
77 // Compute and return the fully resolved subregion.
78 return SkRect::MakeXYWH(fX.isValid() ? boundaries.fLeft : defaultSubregion.fLeft,
79 fY.isValid() ? boundaries.fTop : defaultSubregion.fTop,
80 fWidth.isValid() ? boundaries.width() : defaultSubregion.width(),
81 fHeight.isValid() ? boundaries.height() : defaultSubregion.height());
82 }
83
resolveColorspace(const SkSVGRenderContext & ctx,const SkSVGFilterContext &) const84 SkSVGColorspace SkSVGFe::resolveColorspace(const SkSVGRenderContext& ctx,
85 const SkSVGFilterContext&) const {
86 constexpr SkSVGColorspace kDefaultCS = SkSVGColorspace::kSRGB;
87 const SkSVGColorspace cs = *ctx.presentationContext().fInherited.fColorInterpolationFilters;
88 return cs == SkSVGColorspace::kAuto ? kDefaultCS : cs;
89 }
90
applyProperties(SkSVGRenderContext * ctx) const91 void SkSVGFe::applyProperties(SkSVGRenderContext* ctx) const { this->onPrepareToRender(ctx); }
92
parseAndSetAttribute(const char * name,const char * value)93 bool SkSVGFe::parseAndSetAttribute(const char* name, const char* value) {
94 return INHERITED::parseAndSetAttribute(name, value) ||
95 this->setIn(SkSVGAttributeParser::parse<SkSVGFeInputType>("in", name, value)) ||
96 this->setResult(SkSVGAttributeParser::parse<SkSVGStringType>("result", name, value)) ||
97 this->setX(SkSVGAttributeParser::parse<SkSVGLength>("x", name, value)) ||
98 this->setY(SkSVGAttributeParser::parse<SkSVGLength>("y", name, value)) ||
99 this->setWidth(SkSVGAttributeParser::parse<SkSVGLength>("width", name, value)) ||
100 this->setHeight(SkSVGAttributeParser::parse<SkSVGLength>("height", name, value));
101 }
102
parse(SkSVGFeInputType * type)103 template <> bool SkSVGAttributeParser::parse(SkSVGFeInputType* type) {
104 static constexpr std::tuple<const char*, SkSVGFeInputType::Type> gTypeMap[] = {
105 {"SourceGraphic", SkSVGFeInputType::Type::kSourceGraphic},
106 {"SourceAlpha", SkSVGFeInputType::Type::kSourceAlpha},
107 {"BackgroundImage", SkSVGFeInputType::Type::kBackgroundImage},
108 {"BackgroundAlpha", SkSVGFeInputType::Type::kBackgroundAlpha},
109 {"FillPaint", SkSVGFeInputType::Type::kFillPaint},
110 {"StrokePaint", SkSVGFeInputType::Type::kStrokePaint},
111 };
112
113 SkSVGStringType resultId;
114 SkSVGFeInputType::Type t;
115 bool parsedValue = false;
116 if (this->parseEnumMap(gTypeMap, &t)) {
117 *type = SkSVGFeInputType(t);
118 parsedValue = true;
119 } else if (parse(&resultId)) {
120 *type = SkSVGFeInputType(resultId);
121 parsedValue = true;
122 }
123
124 return parsedValue && this->parseEOSToken();
125 }
126