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 "include/core/SkPoint.h"
9 #include "include/core/SkRefCnt.h"
10 #include "include/core/SkTileMode.h"
11 #include "include/private/base/SkTPin.h"
12 #include "modules/skottie/src/SkottiePriv.h"
13 #include "modules/skottie/src/SkottieValue.h"
14 #include "modules/skottie/src/animator/Animator.h"
15 #include "modules/skottie/src/effects/Effects.h"
16 #include "modules/sksg/include/SkSGRenderEffect.h"
17 #include "modules/sksg/include/SkSGRenderNode.h"
18
19 #include <array>
20 #include <cstddef>
21 #include <utility>
22
23 namespace skjson {
24 class ArrayValue;
25 }
26
27 namespace skottie {
28 namespace internal {
29
30 namespace {
31
32 class GaussianBlurEffectAdapter final : public AnimatablePropertyContainer {
33 public:
Make(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const AnimationBuilder * abuilder)34 static sk_sp<GaussianBlurEffectAdapter> Make(const skjson::ArrayValue& jprops,
35 sk_sp<sksg::RenderNode> layer,
36 const AnimationBuilder* abuilder) {
37 return sk_sp<GaussianBlurEffectAdapter>(new GaussianBlurEffectAdapter(jprops,
38 std::move(layer),
39 abuilder));
40 }
41
node() const42 const sk_sp<sksg::RenderNode>& node() const { return fImageFilterEffect; }
43
44 private:
GaussianBlurEffectAdapter(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const AnimationBuilder * abuilder)45 GaussianBlurEffectAdapter(const skjson::ArrayValue& jprops,
46 sk_sp<sksg::RenderNode> layer,
47 const AnimationBuilder* abuilder)
48 : fBlur(sksg::BlurImageFilter::Make())
49 , fImageFilterEffect(sksg::ImageFilterEffect::Make(std::move(layer), fBlur)) {
50 enum : size_t {
51 kBlurriness_Index = 0,
52 kDimensions_Index = 1,
53 kRepeatEdge_Index = 2,
54 };
55
56 EffectBinder(jprops, *abuilder, this)
57 .bind(kBlurriness_Index, fBlurriness)
58 .bind(kDimensions_Index, fDimensions)
59 .bind(kRepeatEdge_Index, fRepeatEdge);
60 }
61
onSync()62 void onSync() override {
63 static constexpr SkVector kDimensionsMap[] = {
64 { 1, 1 }, // 1 -> horizontal and vertical
65 { 1, 0 }, // 2 -> horizontal
66 { 0, 1 }, // 3 -> vertical
67 };
68
69 const auto dim_index = SkTPin<size_t>(static_cast<size_t>(fDimensions),
70 1, std::size(kDimensionsMap)) - 1;
71
72 const auto sigma = fBlurriness * kBlurSizeToSigma;
73
74 fBlur->setSigma({ sigma * kDimensionsMap[dim_index].x(),
75 sigma * kDimensionsMap[dim_index].y() });
76
77 // 0 -> repeat edge pixels: off
78 // 1 -> repeat edge pixels: on
79 const auto repeat_edge = static_cast<bool>(fRepeatEdge);
80
81 // Repeat edge pixels implies two things:
82 // - the blur uses kClamp tiling
83 // - the output is cropped to content size
84 fBlur->setTileMode(repeat_edge
85 ? SkTileMode::kClamp
86 : SkTileMode::kDecal);
87 static_cast<sksg::ImageFilterEffect*>(fImageFilterEffect.get())->setCropping(repeat_edge
88 ? sksg::ImageFilterEffect::Cropping::kContent
89 : sksg::ImageFilterEffect::Cropping::kNone);
90 }
91
92 const sk_sp<sksg::BlurImageFilter> fBlur;
93 const sk_sp<sksg::RenderNode> fImageFilterEffect;
94
95 ScalarValue fBlurriness = 0, // Controls the blur sigma.
96 fDimensions = 1, // 1 -> horizontal & vertical, 2 -> horizontal, 3 -> vertical
97 fRepeatEdge = 0; // 0 -> clamp, 1 -> repeat
98 };
99
100 } // namespace
101
attachGaussianBlurEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const102 sk_sp<sksg::RenderNode> EffectBuilder::attachGaussianBlurEffect(
103 const skjson::ArrayValue& jprops,
104 sk_sp<sksg::RenderNode> layer) const {
105 return fBuilder->attachDiscardableAdapter<GaussianBlurEffectAdapter>(jprops,
106 std::move(layer),
107 fBuilder);
108 }
109
110 } // namespace internal
111 } // namespace skottie
112