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 "include/effects/SkColorMatrix.h"
11 #include "modules/skottie/src/SkottieAdapter.h"
12 #include "modules/skottie/src/SkottieJson.h"
13 #include "modules/skottie/src/SkottieValue.h"
14 #include "modules/sksg/include/SkSGColorFilter.h"
15 #include "src/utils/SkJSON.h"
16
17 namespace skottie {
18 namespace internal {
19
20 namespace {
21
22 class HueSaturationEffectAdapter final : public DiscardableAdaptorBase {
23 public:
Make(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const AnimationBuilder * abuilder)24 static sk_sp<HueSaturationEffectAdapter> Make(const skjson::ArrayValue& jprops,
25 sk_sp<sksg::RenderNode> layer,
26 const AnimationBuilder* abuilder) {
27 enum : size_t {
28 kChannelControl_Index = 0,
29 kChannelRange_Index = 1,
30 kMasterHue_Index = 2,
31 kMasterSat_Index = 3,
32 kMasterLightness_Index = 4,
33 kColorize_Index = 5,
34 kColorizeHue_Index = 6,
35 kColorizeSat_Index = 7,
36 kColorizeLightness_Index = 8,
37
38 kMax_Index = kColorizeLightness_Index
39 };
40
41 auto adapter = sk_sp<HueSaturationEffectAdapter>(
42 new HueSaturationEffectAdapter(std::move(layer)));
43
44 auto* raw_adapter = adapter.get();
45
46 abuilder->bindProperty<ScalarValue>(EffectBuilder::GetPropValue(jprops,
47 kChannelControl_Index),
48 [raw_adapter](const ScalarValue& c) {
49 raw_adapter->fChanCtrl = c;
50 });
51 abuilder->bindProperty<ScalarValue>(EffectBuilder::GetPropValue(jprops,
52 kMasterHue_Index),
53 [raw_adapter](const ScalarValue& h) {
54 raw_adapter->fMasterHue = h;
55 });
56 abuilder->bindProperty<ScalarValue>(EffectBuilder::GetPropValue(jprops,
57 kMasterSat_Index),
58 [raw_adapter](const ScalarValue& s) {
59 raw_adapter->fMasterSat = s;
60 });
61 abuilder->bindProperty<ScalarValue>(EffectBuilder::GetPropValue(jprops,
62 kMasterLightness_Index),
63 [raw_adapter](const ScalarValue& l) {
64 raw_adapter->fMasterLight = l;
65 });
66
67 // TODO: colorize support?
68
69 return adapter;
70 }
71
renderNode() const72 const sk_sp<sksg::ExternalColorFilter>& renderNode() const { return fColorFilter; }
73
74 protected:
onSync()75 void onSync() override {
76 fColorFilter->setColorFilter(this->makeColorFilter());
77 }
78
79 private:
HueSaturationEffectAdapter(sk_sp<sksg::RenderNode> layer)80 explicit HueSaturationEffectAdapter(sk_sp<sksg::RenderNode> layer)
81 : fColorFilter(sksg::ExternalColorFilter::Make(std::move(layer))) {}
82
makeColorFilter() const83 sk_sp<SkColorFilter> makeColorFilter() const {
84 enum : uint8_t {
85 kMaster_Chan = 0x01,
86 kReds_Chan = 0x02,
87 kYellows_Chan = 0x03,
88 kGreens_Chan = 0x04,
89 kCyans_Chan = 0x05,
90 kBlues_Chan = 0x06,
91 kMagentas_Chan = 0x07,
92 };
93
94 // We only support master channel controls at this point.
95 if (static_cast<int>(fChanCtrl) != kMaster_Chan) {
96 return nullptr;
97 }
98
99 // AE semantics:
100 //
101 // master hue [degrees] => color.H offset
102 // master sat [-100..100] => [-100..0) -> [0 .. color.S)
103 // ( 0..100] -> (color.S .. 1]
104 // master lightness [-100..100] => [-100..0) -> [0 .. color.L]
105 // ( 0..100] -> (color.L .. 1]
106 const auto h = fMasterHue / 360,
107 s = SkTPin(fMasterSat / 100, -1.0f, 1.0f),
108 l = SkTPin(fMasterLight / 100, -1.0f, 1.0f),
109 h_bias = h,
110 s_bias = std::max(s, 0.0f),
111 s_scale = 1 - std::abs(s),
112 l_bias = std::max(l, 0.0f),
113 l_scale = 1 - std::abs(l);
114
115 const float hsl_cm[20] = {
116 1, 0, 0, 0, h_bias,
117 0, s_scale, 0, 0, s_bias,
118 0, 0, l_scale, 0, l_bias,
119 0, 0, 0, 1, 0,
120 };
121
122 return SkColorFilters::HSLAMatrix(hsl_cm);
123 }
124
125 const sk_sp<sksg::ExternalColorFilter> fColorFilter;
126
127 float fChanCtrl = 0.0f,
128 fMasterHue = 0.0f,
129 fMasterSat = 0.0f,
130 fMasterLight = 0.0f;
131
132 using INHERITED = DiscardableAdaptorBase;
133 };
134
135 } // namespace
136
attachHueSaturationEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const137 sk_sp<sksg::RenderNode> EffectBuilder::attachHueSaturationEffect(
138 const skjson::ArrayValue& jprops, sk_sp<sksg::RenderNode> layer) const {
139 return fBuilder->attachDiscardableAdapter<HueSaturationEffectAdapter>(jprops,
140 std::move(layer),
141 fBuilder);
142 }
143
144 } // namespace internal
145 } // namespace skottie
146