From 8c5f9ef801793ec8a95918ad25729de847b119eb Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Wed, 20 Jun 2018 11:19:53 -0400 Subject: [skottie] Fix start-time/stretch-time handling We currently apply start-time/stretch-time adjustments to the referenced composition AND to the referencing layer local properties. That last part is incorrect: the adjustment should only apply to the referenced composition. Introduce a specialized composition time mapper to handle t adjustments, and push the logic down to AttachCompLayer (and out of the generic AttachLayer). TBR= Change-Id: I0ddb86232010a8e7cdac6524aef2eea5823e306d Reviewed-on: https://skia-review.googlesource.com/136166 Reviewed-by: Florin Malita Commit-Queue: Florin Malita --- modules/skottie/src/Skottie.cpp | 87 ++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 40 deletions(-) (limited to 'modules') diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp index 71521c6691..a5b4bc8648 100644 --- a/modules/skottie/src/Skottie.cpp +++ b/modules/skottie/src/Skottie.cpp @@ -777,22 +777,49 @@ sk_sp AttachAssetRef(const skjson::ObjectValue& jlayer, Attach return asset; } -sk_sp AttachCompLayer(const skjson::ObjectValue& jlayer, AttachContext* ctx, - float* time_bias, float* time_scale) { +sk_sp AttachCompLayer(const skjson::ObjectValue& jlayer, AttachContext* ctx) { const auto start_time = ParseDefault(jlayer["st"], 0.0f), stretch_time = ParseDefault(jlayer["sr"], 1.0f); + const auto requires_time_mapping = !SkScalarNearlyEqual(start_time , 0) || + !SkScalarNearlyEqual(stretch_time, 1); - *time_bias = -start_time; - *time_scale = sk_ieee_float_divide(1, stretch_time); - if (SkScalarIsNaN(*time_scale)) { - *time_scale = 1; + sksg::AnimatorList local_animators; + AttachContext local_ctx = { ctx->fResources, + ctx->fAssets, + ctx->fDuration, + requires_time_mapping ? local_animators : ctx->fAnimators }; + + auto comp_layer = AttachAssetRef(jlayer, &local_ctx, AttachComposition); + + // Applies a bias/scale t-adjustment to child animators. + class CompTimeMapper final : public sksg::GroupAnimator { + public: + CompTimeMapper(sksg::AnimatorList&& layer_animators, float time_bias, float time_scale) + : INHERITED(std::move(layer_animators)) + , fTimeBias(time_bias) + , fTimeScale(time_scale) {} + + void onTick(float t) override { + this->INHERITED::onTick((t + fTimeBias) * fTimeScale); + } + private: + const float fTimeBias, + fTimeScale; + + using INHERITED = sksg::GroupAnimator; + }; + + if (requires_time_mapping) { + const auto t_bias = -start_time, + t_scale = sk_ieee_float_divide(1, stretch_time); + ctx->fAnimators.push_back(skstd::make_unique(std::move(local_animators), + t_bias, t_scale)); } - return AttachAssetRef(jlayer, ctx, AttachComposition); + return comp_layer; } -sk_sp AttachSolidLayer(const skjson::ObjectValue& jlayer, AttachContext*, - float*, float*) { +sk_sp AttachSolidLayer(const skjson::ObjectValue& jlayer, AttachContext*) { const auto size = SkSize::Make(ParseDefault(jlayer["sw"], 0.0f), ParseDefault(jlayer["sh"], 0.0f)); const auto hex = ParseDefault(jlayer["sc"], SkString()); @@ -829,20 +856,17 @@ sk_sp AttachImageAsset(const skjson::ObjectValue& jimage, Atta SkImage::MakeFromEncoded(SkData::MakeFromStream(resStream.get(), resStream->getLength()))); } -sk_sp AttachImageLayer(const skjson::ObjectValue& jlayer, AttachContext* ctx, - float*, float*) { +sk_sp AttachImageLayer(const skjson::ObjectValue& jlayer, AttachContext* ctx) { return AttachAssetRef(jlayer, ctx, AttachImageAsset); } -sk_sp AttachNullLayer(const skjson::ObjectValue& layer, AttachContext*, - float*, float*) { +sk_sp AttachNullLayer(const skjson::ObjectValue& layer, AttachContext*) { // Null layers are used solely to drive dependent transforms, // but we use free-floating sksg::Matrices for that purpose. return nullptr; } -sk_sp AttachShapeLayer(const skjson::ObjectValue& layer, AttachContext* ctx, - float*, float*) { +sk_sp AttachShapeLayer(const skjson::ObjectValue& layer, AttachContext* ctx) { std::vector> geometryStack; std::vector geometryEffectStack; AttachShapeContext shapeCtx(ctx, &geometryStack, &geometryEffectStack, ctx->fAnimators.size()); @@ -858,8 +882,7 @@ sk_sp AttachShapeLayer(const skjson::ObjectValue& layer, Attac return shapeNode; } -sk_sp AttachTextLayer(const skjson::ObjectValue& layer, AttachContext*, - float*, float*) { +sk_sp AttachTextLayer(const skjson::ObjectValue& layer, AttachContext*) { LOG("?? Text layer stub\n"); return nullptr; } @@ -1007,8 +1030,7 @@ sk_sp AttachLayer(const skjson::ObjectValue* jlayer, AttachLayerContext* layerCtx) { if (!jlayer) return nullptr; - using LayerAttacher = sk_sp (*)(const skjson::ObjectValue&, AttachContext*, - float* time_bias, float* time_scale); + using LayerAttacher = sk_sp (*)(const skjson::ObjectValue&, AttachContext*); static constexpr LayerAttacher gLayerAttachers[] = { AttachCompLayer, // 'ty': 0 AttachSolidLayer, // 'ty': 1 @@ -1029,12 +1051,8 @@ sk_sp AttachLayer(const skjson::ObjectValue* jlayer, layerCtx->fCtx->fDuration, layer_animators}; - // Layer attachers may adjust these. - float time_bias = 0, - time_scale = 1; - // Layer content. - auto layer = gLayerAttachers[type](*jlayer, &local_ctx, &time_bias, &time_scale); + auto layer = gLayerAttachers[type](*jlayer, &local_ctx); // Clip layers with explicit dimensions. float w = 0, h = 0; @@ -1062,14 +1080,11 @@ sk_sp AttachLayer(const skjson::ObjectValue* jlayer, public: LayerController(sksg::AnimatorList&& layer_animators, sk_sp controlNode, - float in, float out, - float time_bias, float time_scale) + float in, float out) : INHERITED(std::move(layer_animators)) , fControlNode(std::move(controlNode)) , fIn(in) - , fOut(out) - , fTimeBias(time_bias) - , fTimeScale(time_scale) {} + , fOut(out) {} void onTick(float t) override { const auto active = (t >= fIn && t <= fOut); @@ -1079,16 +1094,13 @@ sk_sp AttachLayer(const skjson::ObjectValue* jlayer, fControlNode->setOpacity(active ? 1 : 0); // Dispatch ticks only while active. - if (active) - this->INHERITED::onTick((t + fTimeBias) * fTimeScale); + if (active) this->INHERITED::onTick(t); } private: const sk_sp fControlNode; const float fIn, - fOut, - fTimeBias, - fTimeScale; + fOut; using INHERITED = sksg::GroupAnimator; }; @@ -1105,12 +1117,7 @@ sk_sp AttachLayer(const skjson::ObjectValue* jlayer, return nullptr; layerCtx->fCtx->fAnimators.push_back( - skstd::make_unique(std::move(layer_animators), - controller_node, - in, - out, - time_bias, - time_scale)); + skstd::make_unique(std::move(layer_animators), controller_node, in, out)); if (ParseDefault((*jlayer)["td"], false)) { // This layer is a matte. We apply it as a mask to the next layer. -- cgit v1.2.3