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
14namespace skottie {
15namespace internal {
16
17namespace {
18
19class GaussianBlurEffectAdapter final : public AnimatablePropertyContainer {
20public:
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
31private:
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
84sk_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