blob: 4fdcf6836889a20848a7174b077154be0372863c [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
8#include "modules/skottie/src/SkottiePriv.h"
9
10#include "modules/skottie/src/SkottieAdapter.h"
11#include "modules/skottie/src/SkottieJson.h"
12#include "modules/skottie/src/effects/Effects.h"
Florin Malita5f1108c2019-07-03 10:09:31 -040013#include "modules/skottie/src/effects/MotionBlurEffect.h"
Florin Malita45dc1f02019-07-01 13:57:43 -040014#include "modules/sksg/include/SkSGClipEffect.h"
15#include "modules/sksg/include/SkSGDraw.h"
16#include "modules/sksg/include/SkSGGroup.h"
17#include "modules/sksg/include/SkSGMaskEffect.h"
18#include "modules/sksg/include/SkSGMerge.h"
19#include "modules/sksg/include/SkSGPaint.h"
20#include "modules/sksg/include/SkSGPath.h"
21#include "modules/sksg/include/SkSGRect.h"
22#include "modules/sksg/include/SkSGRenderEffect.h"
23#include "modules/sksg/include/SkSGRenderNode.h"
24#include "modules/sksg/include/SkSGTransform.h"
25
Florin Malita45dc1f02019-07-01 13:57:43 -040026namespace skottie {
27namespace internal {
28
29namespace {
30
Florin Malita60c84fd2019-07-02 18:02:54 -040031static constexpr int kNullLayerType = 3;
Florin Malita45dc1f02019-07-01 13:57:43 -040032static constexpr int kCameraLayerType = 13;
33
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 };
45 // AE 'subtract' is the same as 'intersect' + inverted geometry
46 // (draws the opacity-adjusted paint *outside* the shape).
47 static constexpr MaskInfo k_sub_info =
48 { SkBlendMode::kSrcIn , sksg::Merge::Mode::kIntersect , true };
49 static constexpr MaskInfo k_dif_info =
50 { SkBlendMode::kDifference, sksg::Merge::Mode::kDifference, false };
51
52 switch (mode) {
53 case 'a': return &k_add_info;
54 case 'f': return &k_dif_info;
55 case 'i': return &k_int_info;
56 case 's': return &k_sub_info;
57 default: break;
58 }
59
60 return nullptr;
61}
62
63sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
64 const AnimationBuilder* abuilder,
Florin Malita45dc1f02019-07-01 13:57:43 -040065 sk_sp<sksg::RenderNode> childNode) {
66 if (!jmask) return childNode;
67
68 struct MaskRecord {
69 sk_sp<sksg::Path> mask_path; // for clipping and masking
70 sk_sp<sksg::Color> mask_paint; // for masking
71 sk_sp<sksg::BlurImageFilter> mask_blur; // for masking
72 sksg::Merge::Mode merge_mode; // for clipping
73 };
74
75 SkSTArray<4, MaskRecord, true> mask_stack;
76
77 bool has_effect = false;
78 auto blur_effect = sksg::BlurImageFilter::Make();
79
80 for (const skjson::ObjectValue* m : *jmask) {
81 if (!m) continue;
82
83 const skjson::StringValue* jmode = (*m)["mode"];
84 if (!jmode || jmode->size() != 1) {
85 abuilder->log(Logger::Level::kError, &(*m)["mode"], "Invalid mask mode.");
86 continue;
87 }
88
89 const auto mode = *jmode->begin();
90 if (mode == 'n') {
91 // "None" masks have no effect.
92 continue;
93 }
94
95 const auto* mask_info = GetMaskInfo(mode);
96 if (!mask_info) {
97 abuilder->log(Logger::Level::kWarning, nullptr, "Unsupported mask mode: '%c'.", mode);
98 continue;
99 }
100
Florin Malitafd91f6d2019-07-25 11:41:07 -0400101 auto mask_path = abuilder->attachPath((*m)["pt"]);
Florin Malita45dc1f02019-07-01 13:57:43 -0400102 if (!mask_path) {
103 abuilder->log(Logger::Level::kError, m, "Could not parse mask path.");
104 continue;
105 }
106
107 // "inv" is cumulative with mask info fInvertGeometry
108 const auto inverted =
109 (mask_info->fInvertGeometry != ParseDefault<bool>((*m)["inv"], false));
110 mask_path->setFillType(inverted ? SkPath::kInverseWinding_FillType
111 : SkPath::kWinding_FillType);
112
113 auto mask_paint = sksg::Color::Make(SK_ColorBLACK);
114 mask_paint->setAntiAlias(true);
115 // First mask in the stack initializes the mask buffer.
116 mask_paint->setBlendMode(mask_stack.empty() ? SkBlendMode::kSrc
117 : mask_info->fBlendMode);
118
Florin Malitafd91f6d2019-07-25 11:41:07 -0400119 has_effect |= abuilder->bindProperty<ScalarValue>((*m)["o"],
Florin Malita45dc1f02019-07-01 13:57:43 -0400120 [mask_paint](const ScalarValue& o) {
121 mask_paint->setOpacity(o * 0.01f);
122 }, 100.0f);
123
124 static const VectorValue default_feather = { 0, 0 };
Florin Malitafd91f6d2019-07-25 11:41:07 -0400125 if (abuilder->bindProperty<VectorValue>((*m)["f"],
Florin Malita45dc1f02019-07-01 13:57:43 -0400126 [blur_effect](const VectorValue& feather) {
127 // Close enough to AE.
128 static constexpr SkScalar kFeatherToSigma = 0.38f;
129 auto sX = feather.size() > 0 ? feather[0] * kFeatherToSigma : 0,
130 sY = feather.size() > 1 ? feather[1] * kFeatherToSigma : 0;
131 blur_effect->setSigma({ sX, sY });
132 }, default_feather)) {
133
134 has_effect = true;
135 mask_stack.push_back({ mask_path,
136 mask_paint,
137 std::move(blur_effect),
138 mask_info->fMergeMode});
139 blur_effect = sksg::BlurImageFilter::Make();
140 } else {
141 mask_stack.push_back({mask_path, mask_paint, nullptr, mask_info->fMergeMode});
142 }
143 }
144
145 if (mask_stack.empty())
146 return childNode;
147
148 // If the masks are fully opaque, we can clip.
149 if (!has_effect) {
150 sk_sp<sksg::GeometryNode> clip_node;
151
152 if (mask_stack.count() == 1) {
153 // Single path -> just clip.
154 clip_node = std::move(mask_stack.front().mask_path);
155 } else {
156 // Multiple clip paths -> merge.
157 std::vector<sksg::Merge::Rec> merge_recs;
158 merge_recs.reserve(SkToSizeT(mask_stack.count()));
159
160 for (auto& mask : mask_stack) {
161 const auto mode = merge_recs.empty() ? sksg::Merge::Mode::kMerge : mask.merge_mode;
162 merge_recs.push_back({std::move(mask.mask_path), mode});
163 }
164 clip_node = sksg::Merge::Make(std::move(merge_recs));
165 }
166
167 return sksg::ClipEffect::Make(std::move(childNode), std::move(clip_node), true);
168 }
169
170 const auto make_mask = [](const MaskRecord& rec) {
171 auto mask = sksg::Draw::Make(std::move(rec.mask_path),
172 std::move(rec.mask_paint));
173 // Optional mask blur (feather).
174 return sksg::ImageFilterEffect::Make(std::move(mask), std::move(rec.mask_blur));
175 };
176
177 sk_sp<sksg::RenderNode> maskNode;
178 if (mask_stack.count() == 1) {
179 // no group needed for single mask
180 maskNode = make_mask(mask_stack.front());
181 } else {
182 std::vector<sk_sp<sksg::RenderNode>> masks;
183 masks.reserve(SkToSizeT(mask_stack.count()));
184 for (auto& rec : mask_stack) {
185 masks.push_back(make_mask(rec));
186 }
187
188 maskNode = sksg::Group::Make(std::move(masks));
189 }
190
191 return sksg::MaskEffect::Make(std::move(childNode), std::move(maskNode));
192}
193
Florin Malita5f1108c2019-07-03 10:09:31 -0400194class LayerController final : public sksg::Animator {
195public:
196 LayerController(sksg::AnimatorList&& layer_animators,
197 sk_sp<sksg::RenderNode> layer,
198 size_t tanim_count, float in, float out)
199 : fLayerAnimators(std::move(layer_animators))
200 , fLayerNode(std::move(layer))
201 , fTransformAnimatorsCount(tanim_count)
202 , fIn(in)
203 , fOut(out) {}
204
205protected:
206 void onTick(float t) override {
207 const auto active = (t >= fIn && t < fOut);
208
209 if (fLayerNode) {
210 fLayerNode->setVisible(active);
211 }
212
213 // When active, dispatch ticks to all layer animators.
214 // When inactive, we must still dispatch ticks to the layer transform animators
215 // (active child layers depend on transforms being updated).
216 const auto dispatch_count = active ? fLayerAnimators.size()
217 : fTransformAnimatorsCount;
218 for (size_t i = 0; i < dispatch_count; ++i) {
219 fLayerAnimators[i]->tick(t);
220 }
221 }
222
223private:
224 const sksg::AnimatorList fLayerAnimators;
225 const sk_sp<sksg::RenderNode> fLayerNode;
226 const size_t fTransformAnimatorsCount;
227 const float fIn,
228 fOut;
229};
230
231class MotionBlurController final : public sksg::Animator {
232public:
233 explicit MotionBlurController(sk_sp<MotionBlurEffect> mbe)
234 : fMotionBlurEffect(std::move(mbe)) {}
235
236protected:
237 // When motion blur is present, time ticks are not passed to layer animators
238 // but to the motion blur effect. The effect then drives the animators/scene-graph
239 // during reval and render phases.
240 void onTick(float t) override {
241 fMotionBlurEffect->setT(t);
242 }
243
244private:
245 const sk_sp<MotionBlurEffect> fMotionBlurEffect;
246};
247
Florin Malita45dc1f02019-07-01 13:57:43 -0400248} // namespace
249
Florin Malita60c84fd2019-07-02 18:02:54 -0400250AnimationBuilder::AttachLayerContext::AttachLayerContext(const skjson::ArrayValue& jlayers)
251 : fLayerList(jlayers) {}
Florin Malita45dc1f02019-07-01 13:57:43 -0400252
253AnimationBuilder::AttachLayerContext::~AttachLayerContext() = default;
254
Florin Malita60c84fd2019-07-02 18:02:54 -0400255AnimationBuilder::AttachLayerContext::TransformRec
Florin Malita45dc1f02019-07-01 13:57:43 -0400256AnimationBuilder::AttachLayerContext::attachLayerTransform(const skjson::ObjectValue& jlayer,
257 const AnimationBuilder* abuilder,
258 TransformType type) {
Florin Malita60c84fd2019-07-02 18:02:54 -0400259 TransformRec result;
260
Florin Malita45dc1f02019-07-01 13:57:43 -0400261 const auto layer_index = ParseDefault<int>(jlayer["ind"], -1);
Florin Malita60c84fd2019-07-02 18:02:54 -0400262 if (layer_index >= 0) {
263 auto* rec = fLayerTransformMap.find(layer_index);
264 if (!rec) {
265 rec = this->attachLayerTransformImpl(jlayer, abuilder, type, layer_index);
266 }
267 SkASSERT(rec);
Florin Malita45dc1f02019-07-01 13:57:43 -0400268
Florin Malita60c84fd2019-07-02 18:02:54 -0400269 // Note: the transform animator scope is *moved* to the result, because
270 // we want the animators transferred to the LayerController.
271 //
272 // This is safe because a) the scope is not used internally, and
273 // b) there is exactly one attachLayerTransform call per layer.
274 // The transform node OTOH may be used at a later time for parenting.
275 result.fTransformNode = rec->fTransformNode;
276 result.fTransformScope = std::move(rec->fTransformScope);
277 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400278
Florin Malita60c84fd2019-07-02 18:02:54 -0400279 return result;
Florin Malita45dc1f02019-07-01 13:57:43 -0400280}
281
282sk_sp<sksg::Transform>
283AnimationBuilder::AttachLayerContext::attachParentLayerTransform(const skjson::ObjectValue& jlayer,
284 const AnimationBuilder* abuilder,
285 int layer_index) {
286 const auto parent_index = ParseDefault<int>(jlayer["parent"], -1);
287 if (parent_index < 0 || parent_index == layer_index)
288 return nullptr;
289
Florin Malita60c84fd2019-07-02 18:02:54 -0400290 if (const auto* rec = fLayerTransformMap.find(parent_index))
291 return rec->fTransformNode;
Florin Malita45dc1f02019-07-01 13:57:43 -0400292
293 for (const skjson::ObjectValue* l : fLayerList) {
294 if (!l) continue;
295
296 if (ParseDefault<int>((*l)["ind"], -1) == parent_index) {
297 const auto parent_type = ParseDefault<int>((*l)["ty"], -1) == kCameraLayerType
298 ? TransformType::kCamera
299 : TransformType::kLayer;
Florin Malita60c84fd2019-07-02 18:02:54 -0400300 return this->attachLayerTransformImpl(*l,
301 abuilder,
302 parent_type,
303 parent_index)->fTransformNode;
Florin Malita45dc1f02019-07-01 13:57:43 -0400304 }
305 }
306
307 return nullptr;
308}
309
310sk_sp<sksg::Transform>
311AnimationBuilder::AttachLayerContext::attachTransformNode(const skjson::ObjectValue& jlayer,
312 const AnimationBuilder* abuilder,
313 sk_sp<sksg::Transform> parent_transform,
314 TransformType type) const {
315 const skjson::ObjectValue* jtransform = jlayer["ks"];
316 if (!jtransform) {
317 return nullptr;
318 }
319
320 if (type == TransformType::kCamera) {
321 auto camera_adapter = sk_make_sp<CameraAdapter>(abuilder->fSize);
322
Florin Malitafd91f6d2019-07-25 11:41:07 -0400323 abuilder->bindProperty<ScalarValue>(jlayer["pe"],
Florin Malita45dc1f02019-07-01 13:57:43 -0400324 [camera_adapter] (const ScalarValue& pe) {
325 // 'pe' (perspective?) corresponds to AE's "zoom" camera property.
326 camera_adapter->setZoom(pe);
327 });
328
329 // parent_transform applies to the camera itself => it pre-composes inverted to the
330 // camera/view/adapter transform.
331 //
332 // T_camera' = T_camera x Inv(parent_transform)
333 //
334 parent_transform = sksg::Transform::MakeInverse(std::move(parent_transform));
335
Florin Malitafd91f6d2019-07-25 11:41:07 -0400336 return abuilder->attachMatrix3D(*jtransform,
Florin Malita45dc1f02019-07-01 13:57:43 -0400337 std::move(parent_transform),
338 std::move(camera_adapter),
339 true); // pre-compose parent
340 }
341
342 return (ParseDefault<int>(jlayer["ddd"], 0) == 0)
Florin Malitafd91f6d2019-07-25 11:41:07 -0400343 ? abuilder->attachMatrix2D(*jtransform, std::move(parent_transform))
344 : abuilder->attachMatrix3D(*jtransform, std::move(parent_transform));
Florin Malita45dc1f02019-07-01 13:57:43 -0400345}
346
Florin Malita60c84fd2019-07-02 18:02:54 -0400347AnimationBuilder::AttachLayerContext::TransformRec*
Florin Malita45dc1f02019-07-01 13:57:43 -0400348AnimationBuilder::AttachLayerContext::attachLayerTransformImpl(const skjson::ObjectValue& jlayer,
349 const AnimationBuilder* abuilder,
350 TransformType type,
351 int layer_index) {
Florin Malita60c84fd2019-07-02 18:02:54 -0400352 SkASSERT(!fLayerTransformMap.find(layer_index));
Florin Malita45dc1f02019-07-01 13:57:43 -0400353
354 // Add a stub entry to break recursion cycles.
Florin Malita60c84fd2019-07-02 18:02:54 -0400355 fLayerTransformMap.set(layer_index, { nullptr, {} });
Florin Malita45dc1f02019-07-01 13:57:43 -0400356
357 auto parent_matrix = this->attachParentLayerTransform(jlayer, abuilder, layer_index);
358
Florin Malitafd91f6d2019-07-25 11:41:07 -0400359 AutoScope ascope(abuilder);
Florin Malita60c84fd2019-07-02 18:02:54 -0400360 auto transform = this->attachTransformNode(jlayer,
361 abuilder,
Florin Malita60c84fd2019-07-02 18:02:54 -0400362 std::move(parent_matrix),
363 type);
364
Florin Malitafd91f6d2019-07-25 11:41:07 -0400365 return fLayerTransformMap.set(layer_index, { std::move(transform), ascope.release() });
Florin Malita45dc1f02019-07-01 13:57:43 -0400366}
367
Florin Malita5f1108c2019-07-03 10:09:31 -0400368bool AnimationBuilder::AttachLayerContext::hasMotionBlur(const skjson::ObjectValue& jlayer) const {
369 return fMotionBlurSamples > 1
370 && fMotionBlurAngle > 0
371 && ParseDefault(jlayer["mb"], false);
372}
373
Florin Malita45dc1f02019-07-01 13:57:43 -0400374sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue* jlayer,
375 AttachLayerContext* layerCtx) const {
Florin Malita60c84fd2019-07-02 18:02:54 -0400376 if (!jlayer) {
Florin Malita45dc1f02019-07-01 13:57:43 -0400377 return nullptr;
378 }
379
380 LayerInfo layer_info = {
381 fSize,
382 ParseDefault<float>((*jlayer)["ip"], 0.0f),
383 ParseDefault<float>((*jlayer)["op"], 0.0f),
384 };
385 if (layer_info.fInPoint >= layer_info.fOutPoint) {
386 this->log(Logger::Level::kError, nullptr,
387 "Invalid layer in/out points: %f/%f.", layer_info.fInPoint, layer_info.fOutPoint);
388 return nullptr;
389 }
390
391 const AutoPropertyTracker apt(this, *jlayer);
392
393 using LayerBuilder = sk_sp<sksg::RenderNode> (AnimationBuilder::*)(const skjson::ObjectValue&,
Florin Malitafd91f6d2019-07-25 11:41:07 -0400394 LayerInfo*) const;
Florin Malita45dc1f02019-07-01 13:57:43 -0400395
396 // AE is annoyingly inconsistent in how effects interact with layer transforms: depending on
397 // the layer type, effects are applied before or after the content is transformed.
398 //
399 // Empirically, pre-rendered layers (for some loose meaning of "pre-rendered") are in the
400 // former category (effects are subject to transformation), while the remaining types are in
401 // the latter.
402 enum : uint32_t {
403 kTransformEffects = 1, // The layer transform also applies to its effects.
404 };
405
406 static constexpr struct {
Florin Malita60c84fd2019-07-02 18:02:54 -0400407 LayerBuilder fBuilder;
408 uint32_t fFlags;
Florin Malita45dc1f02019-07-01 13:57:43 -0400409 } gLayerBuildInfo[] = {
410 { &AnimationBuilder::attachPrecompLayer, kTransformEffects }, // 'ty': 0 -> precomp
411 { &AnimationBuilder::attachSolidLayer , kTransformEffects }, // 'ty': 1 -> solid
412 { &AnimationBuilder::attachImageLayer , kTransformEffects }, // 'ty': 2 -> image
413 { &AnimationBuilder::attachNullLayer , 0 }, // 'ty': 3 -> null
414 { &AnimationBuilder::attachShapeLayer , 0 }, // 'ty': 4 -> shape
415 { &AnimationBuilder::attachTextLayer , 0 }, // 'ty': 5 -> text
416 };
417
418 const auto type = ParseDefault<int>((*jlayer)["ty"], -1);
Florin Malita60c84fd2019-07-02 18:02:54 -0400419 if ((type < 0) ||
420 (type >= SkTo<int>(SK_ARRAY_COUNT(gLayerBuildInfo)) && type != kCameraLayerType)) {
421 return nullptr;
422 }
423
424 // Optional layer transform.
425 const auto transform_type = (type == kCameraLayerType)
426 ? AttachLayerContext::TransformType::kCamera
427 : AttachLayerContext::TransformType::kLayer;
428 auto layer_transform_rec = layerCtx->attachLayerTransform(*jlayer, this, transform_type);
Florin Malita45dc1f02019-07-01 13:57:43 -0400429
430 if (type == kCameraLayerType) {
431 // Camera layers are special: they don't build normal SG fragments, but drive a root-level
432 // transform.
433 if (layerCtx->fCameraTransform) {
434 this->log(Logger::Level::kWarning, jlayer, "Ignoring duplicate camera layer.");
Florin Malita60c84fd2019-07-02 18:02:54 -0400435 return nullptr;
Florin Malita45dc1f02019-07-01 13:57:43 -0400436 }
Florin Malita60c84fd2019-07-02 18:02:54 -0400437
438 layerCtx->fCameraTransform = layer_transform_rec.fTransformNode;
Florin Malita45dc1f02019-07-01 13:57:43 -0400439 }
440
Florin Malitafd91f6d2019-07-25 11:41:07 -0400441 AutoScope ascope(this, std::move(layer_transform_rec.fTransformScope));
442 const auto transform_animator_count = fCurrentAnimatorScope->size();
Florin Malita45dc1f02019-07-01 13:57:43 -0400443
Florin Malita60c84fd2019-07-02 18:02:54 -0400444 const auto is_hidden = ParseDefault<bool>((*jlayer)["hd"], false) || type == kCameraLayerType;
445 const auto& build_info = gLayerBuildInfo[is_hidden ? kNullLayerType : type];
Florin Malita45dc1f02019-07-01 13:57:43 -0400446
447 // Build the layer content fragment.
Florin Malitafd91f6d2019-07-25 11:41:07 -0400448 auto layer = (this->*(build_info.fBuilder))(*jlayer, &layer_info);
Florin Malita45dc1f02019-07-01 13:57:43 -0400449
450 // Clip layers with explicit dimensions.
451 float w = 0, h = 0;
452 if (Parse<float>((*jlayer)["w"], &w) && Parse<float>((*jlayer)["h"], &h)) {
453 layer = sksg::ClipEffect::Make(std::move(layer),
454 sksg::Rect::Make(SkRect::MakeWH(w, h)),
455 true);
456 }
457
458 // Optional layer mask.
Florin Malitafd91f6d2019-07-25 11:41:07 -0400459 layer = AttachMask((*jlayer)["masksProperties"], this, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400460
Florin Malita45dc1f02019-07-01 13:57:43 -0400461 // Does the transform apply to effects also?
462 // (AE quirk: it doesn't - except for solid layers)
463 const auto transform_effects = (build_info.fFlags & kTransformEffects);
464
465 // Attach the transform before effects, when needed.
Florin Malita60c84fd2019-07-02 18:02:54 -0400466 if (layer_transform_rec.fTransformNode && !transform_effects) {
467 layer = sksg::TransformEffect::Make(std::move(layer), layer_transform_rec.fTransformNode);
Florin Malita45dc1f02019-07-01 13:57:43 -0400468 }
469
470 // Optional layer effects.
471 if (const skjson::ArrayValue* jeffects = (*jlayer)["ef"]) {
Florin Malitafd91f6d2019-07-25 11:41:07 -0400472 layer = EffectBuilder(this, layer_info.fSize).attachEffects(*jeffects, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400473 }
474
475 // Attach the transform after effects, when needed.
Florin Malita60c84fd2019-07-02 18:02:54 -0400476 if (layer_transform_rec.fTransformNode && transform_effects) {
477 layer = sksg::TransformEffect::Make(std::move(layer),
478 std::move(layer_transform_rec.fTransformNode));
Florin Malita45dc1f02019-07-01 13:57:43 -0400479 }
480
481 // Optional layer opacity.
482 // TODO: de-dupe this "ks" lookup with matrix above.
483 if (const skjson::ObjectValue* jtransform = (*jlayer)["ks"]) {
Florin Malitafd91f6d2019-07-25 11:41:07 -0400484 layer = this->attachOpacity(*jtransform, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400485 }
486
487 // Optional blend mode.
488 layer = this->attachBlendMode(*jlayer, std::move(layer));
489
Florin Malitafd91f6d2019-07-25 11:41:07 -0400490 const auto has_animators = !fCurrentAnimatorScope->empty();
Florin Malita45dc1f02019-07-01 13:57:43 -0400491
Florin Malitafd91f6d2019-07-25 11:41:07 -0400492 sk_sp<sksg::Animator> controller = sk_make_sp<LayerController>(ascope.release(),
Florin Malita5f240182019-07-23 17:28:53 -0400493 layer,
494 transform_animator_count,
495 layer_info.fInPoint,
496 layer_info.fOutPoint);
Florin Malita45dc1f02019-07-01 13:57:43 -0400497
Florin Malita5f1108c2019-07-03 10:09:31 -0400498 // Optional motion blur.
Florin Malita3c8f9cb2019-08-26 19:44:41 -0400499 if (layer && has_animators && layerCtx->hasMotionBlur(*jlayer)) {
Florin Malita5f1108c2019-07-03 10:09:31 -0400500 SkASSERT(layerCtx->fMotionBlurAngle >= 0);
Florin Malita45dc1f02019-07-01 13:57:43 -0400501
Florin Malita5f1108c2019-07-03 10:09:31 -0400502 // Wrap both the layer node and the controller.
503 auto motion_blur = MotionBlurEffect::Make(std::move(controller), std::move(layer),
504 layerCtx->fMotionBlurSamples,
505 layerCtx->fMotionBlurAngle,
506 layerCtx->fMotionBlurPhase);
Florin Malita5f240182019-07-23 17:28:53 -0400507 controller = sk_make_sp<MotionBlurController>(motion_blur);
Florin Malita5f1108c2019-07-03 10:09:31 -0400508 layer = std::move(motion_blur);
509 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400510
Florin Malitafd91f6d2019-07-25 11:41:07 -0400511 fCurrentAnimatorScope->push_back(std::move(controller));
Florin Malita60c84fd2019-07-02 18:02:54 -0400512
513 if (!layer) {
514 return nullptr;
515 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400516
517 if (ParseDefault<bool>((*jlayer)["td"], false)) {
518 // This layer is a matte. We apply it as a mask to the next layer.
519 layerCtx->fCurrentMatte = std::move(layer);
520 return nullptr;
521 }
522
523 if (layerCtx->fCurrentMatte) {
524 // There is a pending matte. Apply and reset.
525 static constexpr sksg::MaskEffect::Mode gMaskModes[] = {
Florin Malita59e72b72019-10-16 08:51:09 -0400526 sksg::MaskEffect::Mode::kAlphaNormal, // tt: 1
527 sksg::MaskEffect::Mode::kAlphaInvert, // tt: 2
528 sksg::MaskEffect::Mode::kLumaNormal, // tt: 3
529 sksg::MaskEffect::Mode::kLumaInvert, // tt: 4
Florin Malita45dc1f02019-07-01 13:57:43 -0400530 };
531 const auto matteType = ParseDefault<size_t>((*jlayer)["tt"], 1) - 1;
532
533 if (matteType < SK_ARRAY_COUNT(gMaskModes)) {
534 return sksg::MaskEffect::Make(std::move(layer),
535 std::move(layerCtx->fCurrentMatte),
536 gMaskModes[matteType]);
537 }
538 layerCtx->fCurrentMatte.reset();
539 }
540
541 return layer;
542}
543
544} // namespace internal
545} // namespace skottie