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/SkottieAdapter.h"
11 #include "modules/skottie/src/SkottieValue.h"
12 #include "modules/sksg/include/SkSGRenderEffect.h"
13 #include "src/utils/SkJSON.h"
14
15 namespace skottie {
16 namespace internal {
17
18 namespace {
19
20 class GaussianBlurEffectAdapter final : public SkNVRefCnt<GaussianBlurEffectAdapter> {
21 public:
GaussianBlurEffectAdapter(sk_sp<sksg::BlurImageFilter> blur)22 explicit GaussianBlurEffectAdapter(sk_sp<sksg::BlurImageFilter> blur)
23 : fBlur(std::move(blur)) {
24 SkASSERT(fBlur);
25 }
26
27 // AE/BM model properties. These are all animatable/interpolatable.
28
29 // Controls the blur sigma.
30 ADAPTER_PROPERTY(Blurriness, SkScalar, 0)
31
32 // Enum selecting the blur dimensionality:
33 //
34 // 1 -> horizontal & vertical
35 // 2 -> horizontal
36 // 3 -> vertical
37 //
38 ADAPTER_PROPERTY(Dimensions, SkScalar, 1)
39
40 // Enum selecting edge behavior:
41 //
42 // 0 -> clamp
43 // 1 -> repeat
44 //
45 ADAPTER_PROPERTY(RepeatEdge, SkScalar, 0)
46
47 private:
apply()48 void apply() {
49 static constexpr SkVector kDimensionsMap[] = {
50 { 1, 1 }, // 1 -> horizontal and vertical
51 { 1, 0 }, // 2 -> horizontal
52 { 0, 1 }, // 3 -> vertical
53 };
54
55 const auto dim_index = SkTPin<size_t>(static_cast<size_t>(fDimensions),
56 1, SK_ARRAY_COUNT(kDimensionsMap)) - 1;
57
58 // Close enough to AE.
59 static constexpr SkScalar kBlurrinessToSigmaFactor = 0.3f;
60 const auto sigma = fBlurriness * kBlurrinessToSigmaFactor;
61
62 fBlur->setSigma({ sigma * kDimensionsMap[dim_index].x(),
63 sigma * kDimensionsMap[dim_index].y() });
64
65 static constexpr SkTileMode kRepeatEdgeMap[] = {
66 SkTileMode::kDecal, // 0 -> repeat edge pixels: off
67 SkTileMode::kClamp, // 1 -> repeat edge pixels: on
68 };
69
70 const auto repeat_index = SkTPin<size_t>(static_cast<size_t>(fRepeatEdge),
71 0, SK_ARRAY_COUNT(kRepeatEdgeMap) - 1);
72 fBlur->setTileMode(kRepeatEdgeMap[repeat_index]);
73 }
74
75 const sk_sp<sksg::BlurImageFilter> fBlur;
76 };
77
78 } // anonymous ns
79
attachGaussianBlurEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const80 sk_sp<sksg::RenderNode> EffectBuilder::attachGaussianBlurEffect(
81 const skjson::ArrayValue& jprops,
82 sk_sp<sksg::RenderNode> layer) const {
83 enum : size_t {
84 kBlurriness_Index = 0,
85 kDimensions_Index = 1,
86 kRepeatEdge_Index = 2,
87 };
88
89 auto blur_effect = sksg::BlurImageFilter::Make();
90 auto blur_addapter = sk_make_sp<GaussianBlurEffectAdapter>(blur_effect);
91
92 fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kBlurriness_Index),
93 [blur_addapter](const ScalarValue& b) {
94 blur_addapter->setBlurriness(b);
95 });
96 fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kDimensions_Index),
97 [blur_addapter](const ScalarValue& d) {
98 blur_addapter->setDimensions(d);
99 });
100 fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kRepeatEdge_Index),
101 [blur_addapter](const ScalarValue& r) {
102 blur_addapter->setRepeatEdge(r);
103 });
104
105 return sksg::ImageFilterEffect::Make(std::move(layer), std::move(blur_effect));
106 }
107
108 } // namespace internal
109 } // namespace skottie
110