blob: c738e24903b91a3de3a716440693ba6ade484fc0 [file] [log] [blame]
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "modules/skottie/src/SkottieJson.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/skottie/src/animator/KeyframeAnimator.h"
#include "modules/skottie/src/text/TextValue.h"
namespace skottie::internal {
namespace {
class TextKeyframeAnimator final : public KeyframeAnimator {
public:
TextKeyframeAnimator(std::vector<Keyframe> kfs, std::vector<SkCubicMap> cms,
std::vector<TextValue> vs, TextValue* target_value)
: INHERITED(std::move(kfs), std::move(cms))
, fValues(std::move(vs))
, fTarget(target_value) {}
private:
StateChanged onSeek(float t) override {
const auto& lerp_info = this->getLERPInfo(t);
// Text value keyframes are treated as selectors, not as interpolated values.
if (*fTarget != fValues[SkToSizeT(lerp_info.vrec0.idx)]) {
*fTarget = fValues[SkToSizeT(lerp_info.vrec0.idx)];
return true;
}
return false;
}
const std::vector<TextValue> fValues;
TextValue* fTarget;
using INHERITED = KeyframeAnimator;
};
class TextExpressionAnimator final : public Animator {
public:
TextExpressionAnimator(sk_sp<ExpressionEvaluator<SkString>> expression_evaluator,
TextValue* target_value)
: fExpressionEvaluator(std::move(expression_evaluator))
, fTarget(target_value) {}
private:
StateChanged onSeek(float t) override {
SkString old_value = fTarget->fText;
fTarget->fText = fExpressionEvaluator->evaluate(t);
return fTarget->fText != old_value;
}
sk_sp<ExpressionEvaluator<SkString>> fExpressionEvaluator;
TextValue* fTarget;
};
class TextAnimatorBuilder final : public AnimatorBuilder {
public:
explicit TextAnimatorBuilder(TextValue* target)
: INHERITED(Keyframe::Value::Type::kIndex)
, fTarget(target) {}
sk_sp<KeyframeAnimator> makeFromKeyframes(const AnimationBuilder& abuilder,
const skjson::ArrayValue& jkfs) override {
SkASSERT(jkfs.size() > 0);
fValues.reserve(jkfs.size());
if (!this->parseKeyframes(abuilder, jkfs)) {
return nullptr;
}
fValues.shrink_to_fit();
return sk_sp<TextKeyframeAnimator>(
new TextKeyframeAnimator(std::move(fKFs),
std::move(fCMs),
std::move(fValues),
fTarget));
}
sk_sp<Animator> makeFromExpression(ExpressionManager& em, const char* expr) override {
sk_sp<ExpressionEvaluator<SkString>> expression_evaluator =
em.createStringExpressionEvaluator(expr);
return sk_make_sp<TextExpressionAnimator>(expression_evaluator, fTarget);
}
bool parseValue(const AnimationBuilder& abuilder, const skjson::Value& jv) const override {
return Parse(jv, abuilder, fTarget);
}
private:
bool parseKFValue(const AnimationBuilder& abuilder,
const skjson::ObjectValue&,
const skjson::Value& jv,
Keyframe::Value* v) override {
TextValue val;
if (!Parse(jv, abuilder, &val)) {
return false;
}
// TODO: full deduping?
if (fValues.empty() || val != fValues.back()) {
fValues.push_back(std::move(val));
}
v->idx = SkToU32(fValues.size() - 1);
return true;
}
std::vector<TextValue> fValues;
TextValue* fTarget;
using INHERITED = AnimatorBuilder;
};
} // namespace
template <>
bool AnimatablePropertyContainer::bind<TextValue>(const AnimationBuilder& abuilder,
const skjson::ObjectValue* jprop,
TextValue* v) {
TextAnimatorBuilder builder(v);
return this->bindImpl(abuilder, jprop, builder);
}
} // namespace skottie::internal