Tyler Denniston | df208a3 | 2020-10-30 16:01:54 -0400 | [diff] [blame] | 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" |
Tyler Denniston | b25caae | 2020-11-09 12:46:02 -0500 | [diff] [blame] | 9 | #include "modules/svg/include/SkSVGAttributeParser.h" |
Tyler Denniston | df208a3 | 2020-10-30 16:01:54 -0400 | [diff] [blame] | 10 | #include "modules/svg/include/SkSVGFe.h" |
Tyler Denniston | 62a683e | 2020-12-11 11:47:55 -0500 | [diff] [blame] | 11 | #include "modules/svg/include/SkSVGFilterContext.h" |
Tyler Denniston | 0a145b7 | 2021-01-11 10:51:41 -0500 | [diff] [blame] | 12 | #include "modules/svg/include/SkSVGRenderContext.h" |
Tyler Denniston | df208a3 | 2020-10-30 16:01:54 -0400 | [diff] [blame] | 13 | |
| 14 | sk_sp<SkImageFilter> SkSVGFe::makeImageFilter(const SkSVGRenderContext& ctx, |
Tyler Denniston | b25caae | 2020-11-09 12:46:02 -0500 | [diff] [blame] | 15 | const SkSVGFilterContext& fctx) const { |
| 16 | return this->onMakeImageFilter(ctx, fctx); |
| 17 | } |
| 18 | |
Tyler Denniston | 0a145b7 | 2021-01-11 10:51:41 -0500 | [diff] [blame] | 19 | 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 | // Resolve the x/y/w/h boundary rect depending on primitiveUnits setting |
| 27 | SkRect boundaries; |
| 28 | switch (fctx.primitiveUnits().type()) { |
| 29 | case SkSVGObjectBoundingBoxUnits::Type::kUserSpaceOnUse: |
| 30 | boundaries = ctx.lengthContext().resolveRect(x, y, w, h); |
| 31 | break; |
| 32 | case SkSVGObjectBoundingBoxUnits::Type::kObjectBoundingBox: { |
| 33 | SkASSERT(ctx.node()); |
| 34 | const SkRect objBounds = ctx.node()->objectBoundingBox(ctx); |
| 35 | boundaries = SkSVGLengthContext({1, 1}).resolveRect(x, y, w, h); |
| 36 | boundaries = SkRect::MakeXYWH(objBounds.fLeft + boundaries.fLeft * objBounds.width(), |
| 37 | objBounds.fTop + boundaries.fTop * objBounds.height(), |
| 38 | boundaries.width() * objBounds.width(), |
| 39 | boundaries.height() * objBounds.height()); |
| 40 | |
| 41 | break; |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | return boundaries; |
| 46 | } |
| 47 | |
Tyler Denniston | bd91660 | 2021-01-22 13:00:31 -0500 | [diff] [blame] | 48 | static bool AnyIsStandardInput(const SkSVGFilterContext& fctx, |
| 49 | const std::vector<SkSVGFeInputType>& inputs) { |
Tyler Denniston | 94730fe | 2021-01-14 15:53:32 -0500 | [diff] [blame] | 50 | for (const auto& in : inputs) { |
Tyler Denniston | bd91660 | 2021-01-22 13:00:31 -0500 | [diff] [blame] | 51 | switch (in.type()) { |
| 52 | case SkSVGFeInputType::Type::kFilterPrimitiveReference: |
| 53 | break; |
| 54 | case SkSVGFeInputType::Type::kSourceGraphic: |
| 55 | case SkSVGFeInputType::Type::kSourceAlpha: |
| 56 | case SkSVGFeInputType::Type::kBackgroundImage: |
| 57 | case SkSVGFeInputType::Type::kBackgroundAlpha: |
| 58 | case SkSVGFeInputType::Type::kFillPaint: |
| 59 | case SkSVGFeInputType::Type::kStrokePaint: |
| 60 | return true; |
| 61 | case SkSVGFeInputType::Type::kUnspecified: |
| 62 | // Unspecified means previous result (which may be SourceGraphic). |
| 63 | if (fctx.previousResultIsSourceGraphic()) { |
| 64 | return true; |
| 65 | } |
| 66 | break; |
Tyler Denniston | 94730fe | 2021-01-14 15:53:32 -0500 | [diff] [blame] | 67 | } |
| 68 | } |
Tyler Denniston | bd91660 | 2021-01-22 13:00:31 -0500 | [diff] [blame] | 69 | |
Tyler Denniston | 94730fe | 2021-01-14 15:53:32 -0500 | [diff] [blame] | 70 | return false; |
| 71 | } |
| 72 | |
Tyler Denniston | 62a683e | 2020-12-11 11:47:55 -0500 | [diff] [blame] | 73 | SkRect SkSVGFe::resolveFilterSubregion(const SkSVGRenderContext& ctx, |
| 74 | const SkSVGFilterContext& fctx) const { |
Tyler Denniston | 0a145b7 | 2021-01-11 10:51:41 -0500 | [diff] [blame] | 75 | // From https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveSubRegion, |
| 76 | // the default filter effect subregion is equal to the union of the subregions defined |
| 77 | // for all "referenced nodes" (filter effect inputs). If there are no inputs, the |
| 78 | // default subregion is equal to the filter effects region |
| 79 | // (https://www.w3.org/TR/SVG11/filters.html#FilterEffectsRegion). |
| 80 | const std::vector<SkSVGFeInputType> inputs = this->getInputs(); |
| 81 | SkRect subregion; |
Tyler Denniston | bd91660 | 2021-01-22 13:00:31 -0500 | [diff] [blame] | 82 | if (inputs.empty() || AnyIsStandardInput(fctx, inputs)) { |
Tyler Denniston | 0a145b7 | 2021-01-11 10:51:41 -0500 | [diff] [blame] | 83 | subregion = fctx.filterEffectsRegion(); |
| 84 | } else { |
| 85 | subregion = fctx.filterPrimitiveSubregion(inputs[0]); |
| 86 | for (size_t i = 1; i < inputs.size(); i++) { |
| 87 | subregion.join(fctx.filterPrimitiveSubregion(inputs[i])); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | // Next resolve the rect specified by the x, y, width, height attributes on this filter effect. |
| 92 | // If those attributes were given, they override the corresponding attribute of the default |
| 93 | // filter effect subregion calculated above. |
| 94 | const SkRect boundaries = this->resolveBoundaries(ctx, fctx); |
| 95 | if (fX.isValid()) { |
| 96 | subregion.fLeft = boundaries.fLeft; |
| 97 | } |
| 98 | if (fY.isValid()) { |
| 99 | subregion.fTop = boundaries.fTop; |
| 100 | } |
| 101 | if (fWidth.isValid()) { |
| 102 | subregion.fRight = subregion.fLeft + boundaries.width(); |
| 103 | } |
| 104 | if (fHeight.isValid()) { |
| 105 | subregion.fBottom = subregion.fTop + boundaries.height(); |
| 106 | } |
| 107 | |
| 108 | return subregion; |
Tyler Denniston | 62a683e | 2020-12-11 11:47:55 -0500 | [diff] [blame] | 109 | } |
| 110 | |
Tyler Denniston | c7e4824 | 2021-01-20 17:31:36 -0500 | [diff] [blame] | 111 | SkSVGColorspace SkSVGFe::resolveColorspace(const SkSVGRenderContext& ctx, |
| 112 | const SkSVGFilterContext&) const { |
Tyler Denniston | 8f78d55 | 2021-01-14 14:23:13 +0000 | [diff] [blame] | 113 | constexpr SkSVGColorspace kDefaultCS = SkSVGColorspace::kSRGB; |
| 114 | const SkSVGColorspace cs = *ctx.presentationContext().fInherited.fColorInterpolationFilters; |
| 115 | return cs == SkSVGColorspace::kAuto ? kDefaultCS : cs; |
Tyler Denniston | 7bb85db | 2021-01-13 12:08:04 -0500 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | void SkSVGFe::applyProperties(SkSVGRenderContext* ctx) const { this->onPrepareToRender(ctx); } |
| 119 | |
Tyler Denniston | b25caae | 2020-11-09 12:46:02 -0500 | [diff] [blame] | 120 | bool SkSVGFe::parseAndSetAttribute(const char* name, const char* value) { |
| 121 | return INHERITED::parseAndSetAttribute(name, value) || |
| 122 | this->setIn(SkSVGAttributeParser::parse<SkSVGFeInputType>("in", name, value)) || |
Tyler Denniston | 62a683e | 2020-12-11 11:47:55 -0500 | [diff] [blame] | 123 | this->setResult(SkSVGAttributeParser::parse<SkSVGStringType>("result", name, value)) || |
| 124 | this->setX(SkSVGAttributeParser::parse<SkSVGLength>("x", name, value)) || |
| 125 | this->setY(SkSVGAttributeParser::parse<SkSVGLength>("y", name, value)) || |
| 126 | this->setWidth(SkSVGAttributeParser::parse<SkSVGLength>("width", name, value)) || |
| 127 | this->setHeight(SkSVGAttributeParser::parse<SkSVGLength>("height", name, value)); |
Tyler Denniston | b25caae | 2020-11-09 12:46:02 -0500 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | template <> bool SkSVGAttributeParser::parse(SkSVGFeInputType* type) { |
| 131 | static constexpr std::tuple<const char*, SkSVGFeInputType::Type> gTypeMap[] = { |
| 132 | {"SourceGraphic", SkSVGFeInputType::Type::kSourceGraphic}, |
| 133 | {"SourceAlpha", SkSVGFeInputType::Type::kSourceAlpha}, |
| 134 | {"BackgroundImage", SkSVGFeInputType::Type::kBackgroundImage}, |
| 135 | {"BackgroundAlpha", SkSVGFeInputType::Type::kBackgroundAlpha}, |
| 136 | {"FillPaint", SkSVGFeInputType::Type::kFillPaint}, |
| 137 | {"StrokePaint", SkSVGFeInputType::Type::kStrokePaint}, |
| 138 | }; |
| 139 | |
| 140 | SkSVGStringType resultId; |
| 141 | SkSVGFeInputType::Type t; |
| 142 | bool parsedValue = false; |
| 143 | if (this->parseEnumMap(gTypeMap, &t)) { |
| 144 | *type = SkSVGFeInputType(t); |
| 145 | parsedValue = true; |
| 146 | } else if (parse(&resultId)) { |
| 147 | *type = SkSVGFeInputType(resultId); |
| 148 | parsedValue = true; |
| 149 | } |
| 150 | |
| 151 | return parsedValue && this->parseEOSToken(); |
Tyler Denniston | df208a3 | 2020-10-30 16:01:54 -0400 | [diff] [blame] | 152 | } |