| 1 | /* |
| 2 | * Copyright 2019 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 "modules/skottie/src/effects/Effects.h" |
| 9 | |
| 10 | #include "modules/skottie/src/SkottieValue.h" |
| 11 | #include "modules/sksg/include/SkSGRenderEffect.h" |
| 12 | #include "src/utils/SkJSON.h" |
| 13 | |
| 14 | namespace skottie { |
| 15 | namespace internal { |
| 16 | |
| 17 | namespace { |
| 18 | |
| 19 | class GaussianBlurEffectAdapter final : public AnimatablePropertyContainer { |
| 20 | public: |
| 21 | static sk_sp<GaussianBlurEffectAdapter> Make(const skjson::ArrayValue& jprops, |
| 22 | sk_sp<sksg::RenderNode> layer, |
| 23 | const AnimationBuilder* abuilder) { |
| 24 | return sk_sp<GaussianBlurEffectAdapter>(new GaussianBlurEffectAdapter(jprops, |
| 25 | std::move(layer), |
| 26 | abuilder)); |
| 27 | } |
| 28 | |
| 29 | const sk_sp<sksg::RenderNode>& node() const { return fImageFilterEffect; } |
| 30 | |
| 31 | private: |
| 32 | GaussianBlurEffectAdapter(const skjson::ArrayValue& jprops, |
| 33 | sk_sp<sksg::RenderNode> layer, |
| 34 | const AnimationBuilder* abuilder) |
| 35 | : fBlur(sksg::BlurImageFilter::Make()) |
| 36 | , fImageFilterEffect(sksg::ImageFilterEffect::Make(std::move(layer), fBlur)) { |
| 37 | enum : size_t { |
| 38 | kBlurriness_Index = 0, |
| 39 | kDimensions_Index = 1, |
| 40 | kRepeatEdge_Index = 2, |
| 41 | }; |
| 42 | |
| 43 | EffectBinder(jprops, *abuilder, this) |
| 44 | .bind(kBlurriness_Index, fBlurriness) |
| 45 | .bind(kDimensions_Index, fDimensions) |
| 46 | .bind(kRepeatEdge_Index, fRepeatEdge); |
| 47 | } |
| 48 | |
| 49 | void onSync() override { |
| 50 | static constexpr SkVector kDimensionsMap[] = { |
| 51 | { 1, 1 }, // 1 -> horizontal and vertical |
| 52 | { 1, 0 }, // 2 -> horizontal |
| 53 | { 0, 1 }, // 3 -> vertical |
| 54 | }; |
| 55 | |
| 56 | const auto dim_index = SkTPin<size_t>(static_cast<size_t>(fDimensions), |
| 57 | 1, SK_ARRAY_COUNT(kDimensionsMap)) - 1; |
| 58 | |
| 59 | const auto sigma = fBlurriness * kBlurSizeToSigma; |
| 60 | |
| 61 | fBlur->setSigma({ sigma * kDimensionsMap[dim_index].x(), |
| 62 | sigma * kDimensionsMap[dim_index].y() }); |
| 63 | |
| 64 | static constexpr SkTileMode kRepeatEdgeMap[] = { |
| 65 | SkTileMode::kDecal, // 0 -> repeat edge pixels: off |
| 66 | SkTileMode::kClamp, // 1 -> repeat edge pixels: on |
| 67 | }; |
| 68 | |
| 69 | const auto repeat_index = SkTPin<size_t>(static_cast<size_t>(fRepeatEdge), |
| 70 | 0, SK_ARRAY_COUNT(kRepeatEdgeMap) - 1); |
| 71 | fBlur->setTileMode(kRepeatEdgeMap[repeat_index]); |
| 72 | } |
| 73 | |
| 74 | const sk_sp<sksg::BlurImageFilter> fBlur; |
| 75 | const sk_sp<sksg::RenderNode> fImageFilterEffect; |
| 76 | |
| 77 | ScalarValue fBlurriness = 0, // Controls the blur sigma. |
| 78 | fDimensions = 1, // 1 -> horizontal & vertical, 2 -> horizontal, 3 -> vertical |
| 79 | fRepeatEdge = 0; // 0 -> clamp, 1 -> repeat |
| 80 | }; |
| 81 | |
| 82 | } // anonymous ns |
| 83 | |
| 84 | sk_sp<sksg::RenderNode> EffectBuilder::attachGaussianBlurEffect( |
| 85 | const skjson::ArrayValue& jprops, |
| 86 | sk_sp<sksg::RenderNode> layer) const { |
| 87 | return fBuilder->attachDiscardableAdapter<GaussianBlurEffectAdapter>(jprops, |
| 88 | std::move(layer), |
| 89 | fBuilder); |
| 90 | } |
| 91 | |
| 92 | } // namespace internal |
| 93 | } // namespace skottie |
| 94 | |