blob: 26af798c57562d2eb3843964980b423bd505672a [file] [log] [blame]
Florin Malita45dc1f02019-07-01 13:57:43 -04001/*
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
Florin Malitac6fbedc2019-10-28 13:57:12 -04008#include "modules/skottie/src/Layer.h"
Florin Malita45dc1f02019-07-01 13:57:43 -04009
Florin Malitaa3936c82020-01-06 12:17:27 -050010#include "modules/skottie/src/Camera.h"
Florin Malitac6fbedc2019-10-28 13:57:12 -040011#include "modules/skottie/src/Composition.h"
Florin Malita45dc1f02019-07-01 13:57:43 -040012#include "modules/skottie/src/SkottieJson.h"
13#include "modules/skottie/src/effects/Effects.h"
Florin Malita5f1108c2019-07-03 10:09:31 -040014#include "modules/skottie/src/effects/MotionBlurEffect.h"
Florin Malita45dc1f02019-07-01 13:57:43 -040015#include "modules/sksg/include/SkSGClipEffect.h"
16#include "modules/sksg/include/SkSGDraw.h"
17#include "modules/sksg/include/SkSGGroup.h"
18#include "modules/sksg/include/SkSGMaskEffect.h"
19#include "modules/sksg/include/SkSGMerge.h"
20#include "modules/sksg/include/SkSGPaint.h"
21#include "modules/sksg/include/SkSGPath.h"
22#include "modules/sksg/include/SkSGRect.h"
23#include "modules/sksg/include/SkSGRenderEffect.h"
24#include "modules/sksg/include/SkSGRenderNode.h"
25#include "modules/sksg/include/SkSGTransform.h"
26
Florin Malita45dc1f02019-07-01 13:57:43 -040027namespace skottie {
28namespace internal {
29
30namespace {
31
Florin Malita8b70f4d2020-04-23 18:58:21 -040032static constexpr size_t kNullLayerType = 3;
Florin Malita45dc1f02019-07-01 13:57:43 -040033
34struct MaskInfo {
35 SkBlendMode fBlendMode; // used when masking with layers/blending
36 sksg::Merge::Mode fMergeMode; // used when clipping
37 bool fInvertGeometry;
38};
39
40const MaskInfo* GetMaskInfo(char mode) {
41 static constexpr MaskInfo k_add_info =
42 { SkBlendMode::kSrcOver , sksg::Merge::Mode::kUnion , false };
43 static constexpr MaskInfo k_int_info =
44 { SkBlendMode::kSrcIn , sksg::Merge::Mode::kIntersect , false };
Florin Malita45dc1f02019-07-01 13:57:43 -040045 static constexpr MaskInfo k_sub_info =
Florin Malitaa524ea22020-07-20 10:51:07 -040046 { SkBlendMode::kDstOut , sksg::Merge::Mode::kDifference, true };
Florin Malita45dc1f02019-07-01 13:57:43 -040047 static constexpr MaskInfo k_dif_info =
Florin Malitacd11a512020-07-15 17:04:46 -040048 { SkBlendMode::kXor , sksg::Merge::Mode::kXOR , false };
Florin Malita45dc1f02019-07-01 13:57:43 -040049
50 switch (mode) {
51 case 'a': return &k_add_info;
52 case 'f': return &k_dif_info;
53 case 'i': return &k_int_info;
54 case 's': return &k_sub_info;
55 default: break;
56 }
57
58 return nullptr;
59}
60
Florin Malitaaf99f3e2020-02-03 12:09:15 -050061class MaskAdapter final : public AnimatablePropertyContainer {
62public:
63 MaskAdapter(const skjson::ObjectValue& jmask, const AnimationBuilder& abuilder, SkBlendMode bm)
Florin Malitaa524ea22020-07-20 10:51:07 -040064 : fMaskPaint(sksg::Color::Make(SK_ColorBLACK))
65 , fBlendMode(bm) {
Florin Malitaaf99f3e2020-02-03 12:09:15 -050066 fMaskPaint->setAntiAlias(true);
Florin Malitaa524ea22020-07-20 10:51:07 -040067 if (!this->requires_isolation()) {
68 // We can mask at draw time.
69 fMaskPaint->setBlendMode(bm);
70 }
Florin Malitaaf99f3e2020-02-03 12:09:15 -050071
72 this->bind(abuilder, jmask["o"], fOpacity);
73
74 if (this->bind(abuilder, jmask["f"], fFeather)) {
75 fMaskFilter = sksg::BlurImageFilter::Make();
76 }
77 }
78
79 bool hasEffect() const {
80 return !this->isStatic()
81 || fOpacity < 100
Florin Malita6509bc72020-03-12 11:11:26 -040082 || fFeather != SkV2{0,0};
Florin Malitaaf99f3e2020-02-03 12:09:15 -050083 }
84
85 sk_sp<sksg::RenderNode> makeMask(sk_sp<sksg::Path> mask_path) const {
Florin Malitaa524ea22020-07-20 10:51:07 -040086 sk_sp<sksg::RenderNode> mask = sksg::Draw::Make(std::move(mask_path), fMaskPaint);
Florin Malitaaf99f3e2020-02-03 12:09:15 -050087
88 // Optional mask blur (feather).
Florin Malitaa524ea22020-07-20 10:51:07 -040089 mask = sksg::ImageFilterEffect::Make(std::move(mask), fMaskFilter);
90
91 if (this->requires_isolation()) {
92 mask = sksg::LayerEffect::Make(std::move(mask), fBlendMode);
93 }
94
95 return mask;
Florin Malitaaf99f3e2020-02-03 12:09:15 -050096 }
97
98private:
99 void onSync() override {
100 fMaskPaint->setOpacity(fOpacity * 0.01f);
101 if (fMaskFilter) {
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500102 // Close enough to AE.
103 static constexpr SkScalar kFeatherToSigma = 0.38f;
Florin Malita6509bc72020-03-12 11:11:26 -0400104 fMaskFilter->setSigma({fFeather.x * kFeatherToSigma,
105 fFeather.y * kFeatherToSigma});
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500106 }
107 }
108
Florin Malitaa524ea22020-07-20 10:51:07 -0400109 bool requires_isolation() const {
110 SkASSERT(fBlendMode == SkBlendMode::kSrc ||
111 fBlendMode == SkBlendMode::kSrcOver ||
112 fBlendMode == SkBlendMode::kSrcIn ||
113 fBlendMode == SkBlendMode::kDstOut ||
114 fBlendMode == SkBlendMode::kXor);
115
116 // Some mask modes touch pixels outside the immediate draw geometry.
117 // These require a layer.
118 switch (fBlendMode) {
119 case (SkBlendMode::kSrcIn): return true;
120 default: return false;
121 }
122 SkUNREACHABLE;
123 }
124
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500125 const sk_sp<sksg::PaintNode> fMaskPaint;
Florin Malitaa524ea22020-07-20 10:51:07 -0400126 const SkBlendMode fBlendMode;
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500127 sk_sp<sksg::BlurImageFilter> fMaskFilter; // optional "feather"
128
Florin Malita6509bc72020-03-12 11:11:26 -0400129 Vec2Value fFeather = {0,0};
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500130 ScalarValue fOpacity = 100;
131};
132
Florin Malita45dc1f02019-07-01 13:57:43 -0400133sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
134 const AnimationBuilder* abuilder,
Florin Malita45dc1f02019-07-01 13:57:43 -0400135 sk_sp<sksg::RenderNode> childNode) {
136 if (!jmask) return childNode;
137
138 struct MaskRecord {
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500139 sk_sp<sksg::Path> mask_path; // for clipping and masking
140 sk_sp<MaskAdapter> mask_adapter; // for masking
141 sksg::Merge::Mode merge_mode; // for clipping
Florin Malita45dc1f02019-07-01 13:57:43 -0400142 };
143
144 SkSTArray<4, MaskRecord, true> mask_stack;
Florin Malita45dc1f02019-07-01 13:57:43 -0400145 bool has_effect = false;
Florin Malita45dc1f02019-07-01 13:57:43 -0400146
147 for (const skjson::ObjectValue* m : *jmask) {
148 if (!m) continue;
149
150 const skjson::StringValue* jmode = (*m)["mode"];
151 if (!jmode || jmode->size() != 1) {
152 abuilder->log(Logger::Level::kError, &(*m)["mode"], "Invalid mask mode.");
153 continue;
154 }
155
156 const auto mode = *jmode->begin();
157 if (mode == 'n') {
158 // "None" masks have no effect.
159 continue;
160 }
161
162 const auto* mask_info = GetMaskInfo(mode);
163 if (!mask_info) {
164 abuilder->log(Logger::Level::kWarning, nullptr, "Unsupported mask mode: '%c'.", mode);
165 continue;
166 }
167
Florin Malitafd91f6d2019-07-25 11:41:07 -0400168 auto mask_path = abuilder->attachPath((*m)["pt"]);
Florin Malita45dc1f02019-07-01 13:57:43 -0400169 if (!mask_path) {
170 abuilder->log(Logger::Level::kError, m, "Could not parse mask path.");
171 continue;
172 }
173
Florin Malitaa524ea22020-07-20 10:51:07 -0400174 auto mask_blend_mode = mask_info->fBlendMode;
175 auto mask_merge_mode = mask_info->fMergeMode;
176 auto mask_inverted = ParseDefault<bool>((*m)["inv"], false);
Florin Malita45dc1f02019-07-01 13:57:43 -0400177
Florin Malitaa524ea22020-07-20 10:51:07 -0400178 if (mask_stack.empty()) {
179 // First mask adjustments:
180 // - always draw in source mode
181 // - invert geometry if needed
182 mask_blend_mode = SkBlendMode::kSrc;
183 mask_merge_mode = sksg::Merge::Mode::kMerge;
184 mask_inverted = mask_inverted != mask_info->fInvertGeometry;
185 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400186
Florin Malitaa524ea22020-07-20 10:51:07 -0400187 mask_path->setFillType(mask_inverted ? SkPathFillType::kInverseWinding
188 : SkPathFillType::kWinding);
189
190 auto mask_adapter = sk_make_sp<MaskAdapter>(*m, *abuilder, mask_blend_mode);
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500191 abuilder->attachDiscardableAdapter(mask_adapter);
Florin Malita45dc1f02019-07-01 13:57:43 -0400192
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500193 has_effect |= mask_adapter->hasEffect();
Florin Malita45dc1f02019-07-01 13:57:43 -0400194
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500195 mask_stack.push_back({ std::move(mask_path),
196 std::move(mask_adapter),
Florin Malitaa524ea22020-07-20 10:51:07 -0400197 mask_merge_mode });
Florin Malita45dc1f02019-07-01 13:57:43 -0400198 }
199
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500200
Florin Malita45dc1f02019-07-01 13:57:43 -0400201 if (mask_stack.empty())
202 return childNode;
203
204 // If the masks are fully opaque, we can clip.
205 if (!has_effect) {
206 sk_sp<sksg::GeometryNode> clip_node;
207
208 if (mask_stack.count() == 1) {
209 // Single path -> just clip.
210 clip_node = std::move(mask_stack.front().mask_path);
211 } else {
212 // Multiple clip paths -> merge.
213 std::vector<sksg::Merge::Rec> merge_recs;
214 merge_recs.reserve(SkToSizeT(mask_stack.count()));
215
216 for (auto& mask : mask_stack) {
Florin Malitaa524ea22020-07-20 10:51:07 -0400217 merge_recs.push_back({std::move(mask.mask_path), mask.merge_mode });
Florin Malita45dc1f02019-07-01 13:57:43 -0400218 }
219 clip_node = sksg::Merge::Make(std::move(merge_recs));
220 }
221
222 return sksg::ClipEffect::Make(std::move(childNode), std::move(clip_node), true);
223 }
224
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500225 // Complex masks (non-opaque or blurred) turn into a mask node stack.
Florin Malita45dc1f02019-07-01 13:57:43 -0400226 sk_sp<sksg::RenderNode> maskNode;
227 if (mask_stack.count() == 1) {
228 // no group needed for single mask
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500229 const auto rec = mask_stack.front();
230 maskNode = rec.mask_adapter->makeMask(std::move(rec.mask_path));
Florin Malita45dc1f02019-07-01 13:57:43 -0400231 } else {
232 std::vector<sk_sp<sksg::RenderNode>> masks;
233 masks.reserve(SkToSizeT(mask_stack.count()));
234 for (auto& rec : mask_stack) {
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500235 masks.push_back(rec.mask_adapter->makeMask(std::move(rec.mask_path)));
Florin Malita45dc1f02019-07-01 13:57:43 -0400236 }
237
238 maskNode = sksg::Group::Make(std::move(masks));
239 }
240
241 return sksg::MaskEffect::Make(std::move(childNode), std::move(maskNode));
242}
243
Florin Malitabb7d95f2020-03-26 15:58:56 -0400244class LayerController final : public Animator {
Florin Malita5f1108c2019-07-03 10:09:31 -0400245public:
Florin Malitabb7d95f2020-03-26 15:58:56 -0400246 LayerController(AnimatorScope&& layer_animators,
Florin Malita5f1108c2019-07-03 10:09:31 -0400247 sk_sp<sksg::RenderNode> layer,
248 size_t tanim_count, float in, float out)
249 : fLayerAnimators(std::move(layer_animators))
250 , fLayerNode(std::move(layer))
251 , fTransformAnimatorsCount(tanim_count)
252 , fIn(in)
253 , fOut(out) {}
254
255protected:
Florin Malita01f2ce02020-03-31 05:44:28 -0400256 StateChanged onSeek(float t) override {
Florin Malitac4fae742020-02-27 15:50:04 -0500257 // in/out may be inverted for time-reversed layers
258 const auto active = (t >= fIn && t < fOut) || (t > fOut && t <= fIn);
Florin Malita5f1108c2019-07-03 10:09:31 -0400259
Florin Malita01f2ce02020-03-31 05:44:28 -0400260 bool changed = false;
Florin Malita5f1108c2019-07-03 10:09:31 -0400261 if (fLayerNode) {
Florin Malita01f2ce02020-03-31 05:44:28 -0400262 changed |= (fLayerNode->isVisible() != active);
Florin Malita5f1108c2019-07-03 10:09:31 -0400263 fLayerNode->setVisible(active);
264 }
265
266 // When active, dispatch ticks to all layer animators.
267 // When inactive, we must still dispatch ticks to the layer transform animators
268 // (active child layers depend on transforms being updated).
269 const auto dispatch_count = active ? fLayerAnimators.size()
270 : fTransformAnimatorsCount;
271 for (size_t i = 0; i < dispatch_count; ++i) {
Florin Malita01f2ce02020-03-31 05:44:28 -0400272 changed |= fLayerAnimators[i]->seek(t);
Florin Malita5f1108c2019-07-03 10:09:31 -0400273 }
Florin Malita0147de42020-03-27 09:49:03 -0400274
Florin Malita01f2ce02020-03-31 05:44:28 -0400275 return changed;
Florin Malita5f1108c2019-07-03 10:09:31 -0400276 }
277
278private:
Florin Malitabb7d95f2020-03-26 15:58:56 -0400279 const AnimatorScope fLayerAnimators;
Florin Malita5f1108c2019-07-03 10:09:31 -0400280 const sk_sp<sksg::RenderNode> fLayerNode;
281 const size_t fTransformAnimatorsCount;
282 const float fIn,
283 fOut;
284};
285
Florin Malitabb7d95f2020-03-26 15:58:56 -0400286class MotionBlurController final : public Animator {
Florin Malita5f1108c2019-07-03 10:09:31 -0400287public:
288 explicit MotionBlurController(sk_sp<MotionBlurEffect> mbe)
289 : fMotionBlurEffect(std::move(mbe)) {}
290
291protected:
292 // When motion blur is present, time ticks are not passed to layer animators
293 // but to the motion blur effect. The effect then drives the animators/scene-graph
294 // during reval and render phases.
Florin Malita01f2ce02020-03-31 05:44:28 -0400295 StateChanged onSeek(float t) override {
Florin Malita5f1108c2019-07-03 10:09:31 -0400296 fMotionBlurEffect->setT(t);
Florin Malita0147de42020-03-27 09:49:03 -0400297 return true;
Florin Malita5f1108c2019-07-03 10:09:31 -0400298 }
299
300private:
301 const sk_sp<MotionBlurEffect> fMotionBlurEffect;
302};
303
Florin Malita45dc1f02019-07-01 13:57:43 -0400304} // namespace
305
Florin Malitac6fbedc2019-10-28 13:57:12 -0400306LayerBuilder::LayerBuilder(const skjson::ObjectValue& jlayer)
307 : fJlayer(jlayer)
Florin Malita6a414b22020-05-25 11:46:50 -0400308 , fIndex (ParseDefault<int>(jlayer["ind" ], -1))
Florin Malitac6fbedc2019-10-28 13:57:12 -0400309 , fParentIndex(ParseDefault<int>(jlayer["parent"], -1))
Florin Malita6a414b22020-05-25 11:46:50 -0400310 , fType (ParseDefault<int>(jlayer["ty" ], -1))
311 , fAutoOrient (ParseDefault<int>(jlayer["ao" ], 0)) {
Florin Malita45dc1f02019-07-01 13:57:43 -0400312
Florin Malitac6fbedc2019-10-28 13:57:12 -0400313 if (this->isCamera() || ParseDefault<int>(jlayer["ddd"], 0)) {
314 fFlags |= Flags::kIs3D;
Florin Malita60c84fd2019-07-02 18:02:54 -0400315 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400316}
317
Florin Malitac6fbedc2019-10-28 13:57:12 -0400318LayerBuilder::~LayerBuilder() = default;
319
320bool LayerBuilder::isCamera() const {
321 static constexpr int kCameraLayerType = 13;
322
323 return fType == kCameraLayerType;
324}
325
326sk_sp<sksg::Transform> LayerBuilder::buildTransform(const AnimationBuilder& abuilder,
327 CompositionBuilder* cbuilder) {
328 // Depending on the leaf node type, we treat the whole transform chain as either 2D or 3D.
329 const auto transform_chain_type = this->is3D() ? TransformType::k3D
330 : TransformType::k2D;
331 fLayerTransform = this->getTransform(abuilder, cbuilder, transform_chain_type);
332
333 return fLayerTransform;
334}
335
336sk_sp<sksg::Transform> LayerBuilder::getTransform(const AnimationBuilder& abuilder,
337 CompositionBuilder* cbuilder,
338 TransformType ttype) {
339 const auto cache_valid_mask = (1ul << ttype);
340 if (!(fFlags & cache_valid_mask)) {
341 // Set valid flag upfront to break cycles.
342 fFlags |= cache_valid_mask;
343
344 const AnimationBuilder::AutoPropertyTracker apt(&abuilder, fJlayer);
345 AnimationBuilder::AutoScope ascope(&abuilder, std::move(fLayerScope));
346 fTransformCache[ttype] = this->doAttachTransform(abuilder, cbuilder, ttype);
347 fLayerScope = ascope.release();
348 fTransformAnimatorCount = fLayerScope.size();
Florin Malitad9e85862019-10-17 13:46:33 -0400349 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400350
Florin Malitac6fbedc2019-10-28 13:57:12 -0400351 return fTransformCache[ttype];
352}
Florin Malita45dc1f02019-07-01 13:57:43 -0400353
Florin Malitac6fbedc2019-10-28 13:57:12 -0400354sk_sp<sksg::Transform> LayerBuilder::getParentTransform(const AnimationBuilder& abuilder,
355 CompositionBuilder* cbuilder,
356 TransformType ttype) {
357 if (auto* parent_builder = cbuilder->layerBuilder(fParentIndex)) {
358 // Explicit parent layer.
359 return parent_builder->getTransform(abuilder, cbuilder, ttype);
360 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400361
Florin Malitac6fbedc2019-10-28 13:57:12 -0400362 if (ttype == TransformType::k3D) {
363 // During camera transform attachment, cbuilder->getCameraTransform() is null.
364 // This prevents camera->camera transform chain cycles.
365 SkASSERT(!this->isCamera() || !cbuilder->getCameraTransform());
366
367 // 3D transform chains are implicitly rooted onto the camera.
368 return cbuilder->getCameraTransform();
Florin Malita45dc1f02019-07-01 13:57:43 -0400369 }
370
371 return nullptr;
372}
373
Florin Malitac6fbedc2019-10-28 13:57:12 -0400374sk_sp<sksg::Transform> LayerBuilder::doAttachTransform(const AnimationBuilder& abuilder,
375 CompositionBuilder* cbuilder,
376 TransformType ttype) {
377 const skjson::ObjectValue* jtransform = fJlayer["ks"];
Florin Malita45dc1f02019-07-01 13:57:43 -0400378 if (!jtransform) {
379 return nullptr;
380 }
381
Florin Malitac6fbedc2019-10-28 13:57:12 -0400382 auto parent_transform = this->getParentTransform(abuilder, cbuilder, ttype);
Florin Malita45dc1f02019-07-01 13:57:43 -0400383
Florin Malitac6fbedc2019-10-28 13:57:12 -0400384 if (this->isCamera()) {
Florin Malita45dc1f02019-07-01 13:57:43 -0400385 // parent_transform applies to the camera itself => it pre-composes inverted to the
386 // camera/view/adapter transform.
387 //
388 // T_camera' = T_camera x Inv(parent_transform)
389 //
Florin Malitae7bd58f2020-01-27 11:58:49 -0500390 return abuilder.attachCamera(fJlayer,
391 *jtransform,
392 sksg::Transform::MakeInverse(std::move(parent_transform)),
393 cbuilder->fSize);
Florin Malita45dc1f02019-07-01 13:57:43 -0400394 }
395
Florin Malitac6fbedc2019-10-28 13:57:12 -0400396 return this->is3D()
Florin Malita6a414b22020-05-25 11:46:50 -0400397 ? abuilder.attachMatrix3D(*jtransform, std::move(parent_transform), fAutoOrient)
398 : abuilder.attachMatrix2D(*jtransform, std::move(parent_transform), fAutoOrient);
Florin Malita45dc1f02019-07-01 13:57:43 -0400399}
400
Florin Malitac6fbedc2019-10-28 13:57:12 -0400401bool LayerBuilder::hasMotionBlur(const CompositionBuilder* cbuilder) const {
402 return cbuilder->fMotionBlurSamples > 1
403 && cbuilder->fMotionBlurAngle > 0
404 && ParseDefault(fJlayer["mb"], false);
Florin Malita45dc1f02019-07-01 13:57:43 -0400405}
406
Florin Malitac6fbedc2019-10-28 13:57:12 -0400407sk_sp<sksg::RenderNode> LayerBuilder::buildRenderTree(const AnimationBuilder& abuilder,
Florin Malita46a331b2019-12-12 15:43:53 -0500408 CompositionBuilder* cbuilder,
409 const LayerBuilder* prev_layer) {
Florin Malitac6fbedc2019-10-28 13:57:12 -0400410 AnimationBuilder::LayerInfo layer_info = {
Florin Malita6cc49532019-12-05 09:06:22 -0500411 cbuilder->fSize,
Florin Malitac6fbedc2019-10-28 13:57:12 -0400412 ParseDefault<float>(fJlayer["ip"], 0.0f),
413 ParseDefault<float>(fJlayer["op"], 0.0f),
Florin Malita45dc1f02019-07-01 13:57:43 -0400414 };
Florin Malitac4fae742020-02-27 15:50:04 -0500415 if (SkScalarNearlyEqual(layer_info.fInPoint, layer_info.fOutPoint)) {
Florin Malitac6fbedc2019-10-28 13:57:12 -0400416 abuilder.log(Logger::Level::kError, nullptr,
417 "Invalid layer in/out points: %f/%f.",
418 layer_info.fInPoint, layer_info.fOutPoint);
Florin Malita45dc1f02019-07-01 13:57:43 -0400419 return nullptr;
420 }
421
Florin Malitac6fbedc2019-10-28 13:57:12 -0400422 const AnimationBuilder::AutoPropertyTracker apt(&abuilder, fJlayer);
Florin Malita45dc1f02019-07-01 13:57:43 -0400423
Florin Malitac6fbedc2019-10-28 13:57:12 -0400424 using LayerBuilder =
425 sk_sp<sksg::RenderNode> (AnimationBuilder::*)(const skjson::ObjectValue&,
426 AnimationBuilder::LayerInfo*) const;
Florin Malita45dc1f02019-07-01 13:57:43 -0400427
428 // AE is annoyingly inconsistent in how effects interact with layer transforms: depending on
429 // the layer type, effects are applied before or after the content is transformed.
430 //
431 // Empirically, pre-rendered layers (for some loose meaning of "pre-rendered") are in the
432 // former category (effects are subject to transformation), while the remaining types are in
433 // the latter.
434 enum : uint32_t {
435 kTransformEffects = 1, // The layer transform also applies to its effects.
436 };
437
438 static constexpr struct {
Florin Malita60c84fd2019-07-02 18:02:54 -0400439 LayerBuilder fBuilder;
440 uint32_t fFlags;
Florin Malita45dc1f02019-07-01 13:57:43 -0400441 } gLayerBuildInfo[] = {
Florin Malita8b70f4d2020-04-23 18:58:21 -0400442 { &AnimationBuilder::attachPrecompLayer, kTransformEffects }, // 'ty': 0 -> precomp
443 { &AnimationBuilder::attachSolidLayer , kTransformEffects }, // 'ty': 1 -> solid
Florin Malita71c31412020-05-07 16:44:18 -0400444 { &AnimationBuilder::attachFootageLayer, kTransformEffects }, // 'ty': 2 -> image
Florin Malita8b70f4d2020-04-23 18:58:21 -0400445 { &AnimationBuilder::attachNullLayer , 0 }, // 'ty': 3 -> null
446 { &AnimationBuilder::attachShapeLayer , 0 }, // 'ty': 4 -> shape
447 { &AnimationBuilder::attachTextLayer , 0 }, // 'ty': 5 -> text
448 { nullptr , 0 }, // 'ty': 6 -> audio
449 { nullptr , 0 }, // 'ty': 7 -> pholderVideo
450 { nullptr , 0 }, // 'ty': 8 -> imageSeq
Florin Malita71c31412020-05-07 16:44:18 -0400451 { &AnimationBuilder::attachFootageLayer, kTransformEffects }, // 'ty': 9 -> video
Florin Malita8b70f4d2020-04-23 18:58:21 -0400452 { nullptr , 0 }, // 'ty': 10 -> pholderStill
453 { nullptr , 0 }, // 'ty': 11 -> guide
454 { nullptr , 0 }, // 'ty': 12 -> adjustment
455 { &AnimationBuilder::attachNullLayer , 0 }, // 'ty': 13 -> camera
456 { nullptr , 0 }, // 'ty': 14 -> light
Florin Malita45dc1f02019-07-01 13:57:43 -0400457 };
458
Florin Malita8b70f4d2020-04-23 18:58:21 -0400459 // Treat all hidden layers as null.
460 const auto type = ParseDefault<bool>(fJlayer["hd"], false)
461 ? kNullLayerType
462 : SkToSizeT(fType);
463
464 if (type >= SK_ARRAY_COUNT(gLayerBuildInfo)) {
Florin Malita60c84fd2019-07-02 18:02:54 -0400465 return nullptr;
466 }
467
Florin Malita8b70f4d2020-04-23 18:58:21 -0400468 const auto& build_info = gLayerBuildInfo[type];
469
Florin Malitac6fbedc2019-10-28 13:57:12 -0400470 // Switch to the layer animator scope (which at this point holds transform-only animators).
471 AnimationBuilder::AutoScope ascope(&abuilder, std::move(fLayerScope));
Florin Malita45dc1f02019-07-01 13:57:43 -0400472
Florin Malita8b70f4d2020-04-23 18:58:21 -0400473 // Potentially null.
474 sk_sp<sksg::RenderNode> layer;
Florin Malita45dc1f02019-07-01 13:57:43 -0400475
476 // Build the layer content fragment.
Florin Malita8b70f4d2020-04-23 18:58:21 -0400477 if (build_info.fBuilder) {
478 layer = (abuilder.*(build_info.fBuilder))(fJlayer, &layer_info);
479 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400480
481 // Clip layers with explicit dimensions.
482 float w = 0, h = 0;
Florin Malitac6fbedc2019-10-28 13:57:12 -0400483 if (Parse<float>(fJlayer["w"], &w) && Parse<float>(fJlayer["h"], &h)) {
Florin Malita45dc1f02019-07-01 13:57:43 -0400484 layer = sksg::ClipEffect::Make(std::move(layer),
485 sksg::Rect::Make(SkRect::MakeWH(w, h)),
486 true);
487 }
488
489 // Optional layer mask.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400490 layer = AttachMask(fJlayer["masksProperties"], &abuilder, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400491
Florin Malita45dc1f02019-07-01 13:57:43 -0400492 // Does the transform apply to effects also?
493 // (AE quirk: it doesn't - except for solid layers)
494 const auto transform_effects = (build_info.fFlags & kTransformEffects);
495
496 // Attach the transform before effects, when needed.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400497 if (fLayerTransform && !transform_effects) {
498 layer = sksg::TransformEffect::Make(std::move(layer), fLayerTransform);
Florin Malita45dc1f02019-07-01 13:57:43 -0400499 }
500
501 // Optional layer effects.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400502 if (const skjson::ArrayValue* jeffects = fJlayer["ef"]) {
503 layer = EffectBuilder(&abuilder, layer_info.fSize).attachEffects(*jeffects,
504 std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400505 }
506
507 // Attach the transform after effects, when needed.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400508 if (fLayerTransform && transform_effects) {
509 layer = sksg::TransformEffect::Make(std::move(layer), std::move(fLayerTransform));
Florin Malita45dc1f02019-07-01 13:57:43 -0400510 }
511
Florin Malitaae581992020-03-24 21:18:42 -0400512 // Optional layer styles.
513 if (const skjson::ArrayValue* jstyles = fJlayer["sy"]) {
514 layer = EffectBuilder(&abuilder, layer_info.fSize).attachStyles(*jstyles, std::move(layer));
515 }
516
Florin Malita45dc1f02019-07-01 13:57:43 -0400517 // Optional layer opacity.
518 // TODO: de-dupe this "ks" lookup with matrix above.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400519 if (const skjson::ObjectValue* jtransform = fJlayer["ks"]) {
520 layer = abuilder.attachOpacity(*jtransform, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400521 }
522
Florin Malitac6fbedc2019-10-28 13:57:12 -0400523 const auto has_animators = !abuilder.fCurrentAnimatorScope->empty();
Florin Malita45dc1f02019-07-01 13:57:43 -0400524
Florin Malitabb7d95f2020-03-26 15:58:56 -0400525 sk_sp<Animator> controller = sk_make_sp<LayerController>(ascope.release(),
526 layer,
527 fTransformAnimatorCount,
528 layer_info.fInPoint,
529 layer_info.fOutPoint);
Florin Malita45dc1f02019-07-01 13:57:43 -0400530
Florin Malita5f1108c2019-07-03 10:09:31 -0400531 // Optional motion blur.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400532 if (layer && has_animators && this->hasMotionBlur(cbuilder)) {
Florin Malita5f1108c2019-07-03 10:09:31 -0400533 // Wrap both the layer node and the controller.
534 auto motion_blur = MotionBlurEffect::Make(std::move(controller), std::move(layer),
Florin Malitac6fbedc2019-10-28 13:57:12 -0400535 cbuilder->fMotionBlurSamples,
536 cbuilder->fMotionBlurAngle,
537 cbuilder->fMotionBlurPhase);
Florin Malita5f240182019-07-23 17:28:53 -0400538 controller = sk_make_sp<MotionBlurController>(motion_blur);
Florin Malita5f1108c2019-07-03 10:09:31 -0400539 layer = std::move(motion_blur);
540 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400541
Florin Malitac6fbedc2019-10-28 13:57:12 -0400542 abuilder.fCurrentAnimatorScope->push_back(std::move(controller));
Florin Malita60c84fd2019-07-02 18:02:54 -0400543
Florin Malita46a331b2019-12-12 15:43:53 -0500544 // Stash the content tree in case it is needed for later mattes.
545 fContentTree = layer;
546
547 if (ParseDefault<bool>(fJlayer["td"], false)) {
548 // |layer| is a track matte. We apply it as a mask to the next layer.
Florin Malita60c84fd2019-07-02 18:02:54 -0400549 return nullptr;
550 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400551
Florin Malita46a331b2019-12-12 15:43:53 -0500552 // Optional matte.
553 size_t matte_mode;
554 if (prev_layer && Parse(fJlayer["tt"], &matte_mode)) {
555 static constexpr sksg::MaskEffect::Mode gMatteModes[] = {
Florin Malita59e72b72019-10-16 08:51:09 -0400556 sksg::MaskEffect::Mode::kAlphaNormal, // tt: 1
557 sksg::MaskEffect::Mode::kAlphaInvert, // tt: 2
558 sksg::MaskEffect::Mode::kLumaNormal, // tt: 3
559 sksg::MaskEffect::Mode::kLumaInvert, // tt: 4
Florin Malita45dc1f02019-07-01 13:57:43 -0400560 };
Florin Malita45dc1f02019-07-01 13:57:43 -0400561
Florin Malita46a331b2019-12-12 15:43:53 -0500562 if (matte_mode > 0 && matte_mode <= SK_ARRAY_COUNT(gMatteModes)) {
563 // The current layer is masked with the previous layer *content*.
Florin Malita512eb942019-10-28 21:22:42 -0400564 layer = sksg::MaskEffect::Make(std::move(layer),
Florin Malita46a331b2019-12-12 15:43:53 -0500565 prev_layer->fContentTree,
566 gMatteModes[matte_mode - 1]);
567 } else {
568 abuilder.log(Logger::Level::kError, nullptr,
569 "Unknown track matte mode: %zu\n", matte_mode);
Florin Malita45dc1f02019-07-01 13:57:43 -0400570 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400571 }
572
Florin Malita46a331b2019-12-12 15:43:53 -0500573 // Finally, attach an optional blend mode.
574 // NB: blend modes are never applied to matte sources (layer content only).
575 return abuilder.attachBlendMode(fJlayer, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400576}
577
578} // namespace internal
579} // namespace skottie