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