[skottie] External logger support
Add a skottie::Logger interface, allowing clients to register for log events
from the animation builder.
Convert existing log messages to the new machinery.
Change-Id: If9083f89b27f197bfc0d8d81860bbacb6b764be3
Reviewed-on: https://skia-review.googlesource.com/c/158580
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/modules/skottie/include/Skottie.h b/modules/skottie/include/Skottie.h
index a4a052d..9c6599d 100644
--- a/modules/skottie/include/Skottie.h
+++ b/modules/skottie/include/Skottie.h
@@ -22,6 +22,7 @@
class SkStream;
namespace skjson { class ObjectValue; }
+
namespace sksg { class Scene; }
namespace skottie {
@@ -62,6 +63,24 @@
virtual sk_sp<SkData> loadFont(const char name[], const char url[]) const;
};
+/**
+ * A Logger subclass can be used to receive Animation::Builder parsing errors and warnings.
+ */
+class SK_API Logger : public SkRefCnt {
+public:
+ Logger() = default;
+ virtual ~Logger() = default;
+ Logger(const Logger&) = delete;
+ Logger& operator=(const Logger&) = delete;
+
+ enum class Level {
+ kWarning,
+ kError,
+ };
+
+ virtual void log(Level, const char message[], const char* json = nullptr);
+};
+
class SK_API Animation : public SkRefCnt {
public:
@@ -104,6 +123,11 @@
Builder& setPropertyObserver(sk_sp<PropertyObserver>);
/**
+ * Register a Logger with this builder.
+ */
+ Builder& setLogger(sk_sp<Logger>);
+
+ /**
* Animation factories.
*/
sk_sp<Animation> make(SkStream*);
@@ -114,6 +138,7 @@
sk_sp<ResourceProvider> fResourceProvider;
sk_sp<SkFontMgr> fFontMgr;
sk_sp<PropertyObserver> fPropertyObserver;
+ sk_sp<Logger> fLogger;
Stats fStats;
};
diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp
index 296f563..41ece92 100644
--- a/modules/skottie/src/Skottie.cpp
+++ b/modules/skottie/src/Skottie.cpp
@@ -38,9 +38,26 @@
namespace internal {
-void LogJSON(const skjson::Value& json, const char msg[]) {
- const auto dump = json.toString();
- LOG("%s: %s\n", msg, dump.c_str());
+void AnimationBuilder::log(Logger::Level lvl, const skjson::Value* json,
+ const char fmt[], ...) const {
+ if (!fLogger) {
+ return;
+ }
+
+ char buff[1024];
+ va_list va;
+ va_start(va, fmt);
+ const auto len = vsprintf(buff, fmt, va);
+ va_end(va);
+
+ if (len < 0 || len >= SkToInt(sizeof(buff))) {
+ SkDebugf("!! Could not format log message !!\n");
+ return;
+ }
+
+ SkString jsonstr = json ? json->toString() : SkString();
+
+ fLogger->log(lvl, buff, jsonstr.c_str());
}
sk_sp<sksg::Matrix> AnimationBuilder::attachMatrix(const skjson::ObjectValue& t,
@@ -137,12 +154,13 @@
}
AnimationBuilder::AnimationBuilder(sk_sp<ResourceProvider> rp, sk_sp<SkFontMgr> fontmgr,
- sk_sp<PropertyObserver> pobserver,
+ sk_sp<PropertyObserver> pobserver, sk_sp<Logger> logger,
Animation::Builder::Stats* stats,
float duration, float framerate)
: fResourceProvider(std::move(rp))
, fLazyFontMgr(std::move(fontmgr))
, fPropertyObserver(std::move(pobserver))
+ , fLogger(std::move(logger))
, fStats(stats)
, fDuration(duration)
, fFrameRate(framerate) {}
@@ -231,6 +249,8 @@
return nullptr;
}
+void Logger::log(Level, const char[], const char*) {}
+
Animation::Builder::Builder() = default;
Animation::Builder::~Builder() = default;
@@ -249,16 +269,25 @@
return *this;
}
+Animation::Builder& Animation::Builder::setLogger(sk_sp<Logger> logger) {
+ fLogger = std::move(logger);
+ return *this;
+}
+
sk_sp<Animation> Animation::Builder::make(SkStream* stream) {
if (!stream->hasLength()) {
// TODO: handle explicit buffering?
- LOG("!! cannot parse streaming content\n");
+ if (fLogger) {
+ fLogger->log(Logger::Level::kError, "Cannot parse streaming content.\n");
+ }
return nullptr;
}
auto data = SkData::MakeFromStream(stream, stream->getLength());
if (!data) {
- SkDebugf("!! Failed to read the input stream.\n");
+ if (fLogger) {
+ fLogger->log(Logger::Level::kError, "Failed to read the input stream.\n");
+ }
return nullptr;
}
@@ -281,7 +310,9 @@
const skjson::DOM dom(data, data_len);
if (!dom.root().is<skjson::ObjectValue>()) {
// TODO: more error info.
- SkDebugf("!! Failed to parse JSON input.\n");
+ if (fLogger) {
+ fLogger->log(Logger::Level::kError, "Failed to parse JSON input.\n");
+ }
return nullptr;
}
const auto& json = dom.root().as<skjson::ObjectValue>();
@@ -299,23 +330,29 @@
if (size.isEmpty() || version.isEmpty() || fps <= 0 ||
!SkScalarIsFinite(inPoint) || !SkScalarIsFinite(outPoint) || !SkScalarIsFinite(duration)) {
- LOG("!! invalid animation params (version: %s, size: [%f %f], frame rate: %f, "
- "in-point: %f, out-point: %f)\n",
- version.c_str(), size.width(), size.height(), fps, inPoint, outPoint);
+ if (fLogger) {
+ const auto msg = SkStringPrintf(
+ "Invalid animation params (version: %s, size: [%f %f], frame rate: %f, "
+ "in-point: %f, out-point: %f)\n",
+ version.c_str(), size.width(), size.height(), fps, inPoint, outPoint);
+ fLogger->log(Logger::Level::kError, msg.c_str());
+ }
return nullptr;
}
SkASSERT(resolvedProvider);
internal::AnimationBuilder builder(std::move(resolvedProvider), fFontMgr,
- std::move(fPropertyObserver), &fStats, duration, fps);
+ std::move(fPropertyObserver),
+ std::move(fLogger),
+ &fStats, duration, fps);
auto scene = builder.parse(json);
const auto t2 = SkTime::GetMSecs();
fStats.fSceneParseTimeMS = t2 - t1;
fStats.fTotalLoadTimeMS = t2 - t0;
- if (!scene) {
- LOG("!! could not parse animation.\n");
+ if (!scene && fLogger) {
+ fLogger->log(Logger::Level::kError, "Could not parse animation.\n");
}
return sk_sp<Animation>(
diff --git a/modules/skottie/src/SkottieAnimator.cpp b/modules/skottie/src/SkottieAnimator.cpp
index 463beda..eb75212 100644
--- a/modules/skottie/src/SkottieAnimator.cpp
+++ b/modules/skottie/src/SkottieAnimator.cpp
@@ -20,14 +20,6 @@
namespace {
-#define LOG SkDebugf
-
-bool LogFail(const skjson::Value& json, const char* msg) {
- const auto dump = json.toString();
- LOG("!! %s: %s\n", msg, dump.c_str());
- return false;
-}
-
class KeyframeAnimatorBase : public sksg::Animator {
public:
size_t count() const { return fRecs.size(); }
@@ -80,7 +72,9 @@
if (!fRecs.empty()) {
if (fRecs.back().t1 >= t0) {
- LOG("!! Ignoring out-of-order key frame (t:%f < t:%f)\n", t0, fRecs.back().t1);
+ abuilder->log(Logger::Level::kWarning, nullptr,
+ "Ignoring out-of-order key frame (t:%f < t:%f).",
+ t0, fRecs.back().t1);
continue;
}
// Back-fill t1 in prev interval. Note: we do this even if we end up discarding
@@ -272,7 +266,7 @@
const auto& jpropK = (*jprop)["k"];
if (!(*jprop)["x"].is<skjson::NullValue>()) {
- LOG("?? Unsupported expression.\n");
+ abuilder->log(Logger::Level::kWarning, nullptr, "Unsupported expression.");
}
// Older Json versions don't have an "a" animation marker.
@@ -289,7 +283,9 @@
}
if (!jpropA.is<skjson::NullValue>()) {
- return LogFail(*jprop, "Could not parse (explicit) static property");
+ abuilder->log(Logger::Level::kError, jprop,
+ "Could not parse (explicit) static property.");
+ return false;
}
}
@@ -297,7 +293,8 @@
auto animator = KeyframeAnimator<T>::Make(jpropK, abuilder, std::move(apply));
if (!animator) {
- return LogFail(*jprop, "Could not parse keyframed property");
+ abuilder->log(Logger::Level::kError, jprop, "Could not parse keyframed property.");
+ return false;
}
ascope->push_back(std::move(animator));
@@ -324,7 +321,7 @@
[split_animator_ptr](const ScalarValue& x) { split_animator_ptr->setX(x); }) ||
!BindPropertyImpl<ScalarValue>((*jprop)["y"], abuilder, &split_animator->fAnimators,
[split_animator_ptr](const ScalarValue& y) { split_animator_ptr->setY(y); })) {
- LogFail(*jprop, "Could not parse split property");
+ abuilder->log(Logger::Level::kError, jprop, "Could not parse split property.");
return nullptr;
}
diff --git a/modules/skottie/src/SkottieLayer.cpp b/modules/skottie/src/SkottieLayer.cpp
index 5924356..1928ed1 100644
--- a/modules/skottie/src/SkottieLayer.cpp
+++ b/modules/skottie/src/SkottieLayer.cpp
@@ -85,7 +85,7 @@
const skjson::StringValue* jmode = (*m)["mode"];
if (!jmode || jmode->size() != 1) {
- LogJSON((*m)["mode"], "!! Invalid mask mode");
+ abuilder->log(Logger::Level::kError, &(*m)["mode"], "Invalid mask mode.");
continue;
}
@@ -97,13 +97,13 @@
const auto* mask_info = GetMaskInfo(mode);
if (!mask_info) {
- LOG("?? Unsupported mask mode: '%c'\n", mode);
+ abuilder->log(Logger::Level::kWarning, nullptr, "Unsupported mask mode: '%c'.", mode);
continue;
}
auto mask_path = abuilder->attachPath((*m)["pt"], ascope);
if (!mask_path) {
- LogJSON(*m, "!! Could not parse mask path");
+ abuilder->log(Logger::Level::kError, m, "Could not parse mask path.");
continue;
}
@@ -218,7 +218,7 @@
const auto data = fResourceProvider->load("", name);
if (!data) {
- LOG("!! Could not load: %s\n", name);
+ this->log(Logger::Level::kError, nullptr, "Could not load: %s.", name);
return nullptr;
}
@@ -227,7 +227,7 @@
.setFontManager(fLazyFontMgr.getMaybeNull())
.make(static_cast<const char*>(data->data()), data->size());
if (!animation) {
- LOG("!! Could not parse nested animation: %s\n", name);
+ this->log(Logger::Level::kError, nullptr, "Could not parse nested animation: %s.", name);
return nullptr;
}
@@ -244,7 +244,7 @@
const auto refId = ParseDefault<SkString>(jlayer["refId"], SkString());
if (refId.isEmpty()) {
- LOG("!! Layer missing refId\n");
+ this->log(Logger::Level::kError, nullptr, "Layer missing refId.");
return nullptr;
}
@@ -254,12 +254,13 @@
const auto* asset_info = fAssets.find(refId);
if (!asset_info) {
- LOG("!! Asset not found: '%s'\n", refId.c_str());
+ this->log(Logger::Level::kError, nullptr, "Asset not found: '%s'.", refId.c_str());
return nullptr;
}
if (asset_info->fIsAttaching) {
- LOG("!! Asset cycle detected for: '%s'\n", refId.c_str());
+ this->log(Logger::Level::kError, nullptr,
+ "Asset cycle detected for: '%s'", refId.c_str());
return nullptr;
}
@@ -280,7 +281,7 @@
!hex_str ||
*hex_str->begin() != '#' ||
!SkParse::FindHex(hex_str->begin() + 1, &c)) {
- LogJSON(jlayer, "!! Could not parse solid layer");
+ this->log(Logger::Level::kError, &jlayer, "Could not parse solid layer.");
return nullptr;
}
@@ -307,7 +308,8 @@
const auto data = fResourceProvider->load(path_cstr, name_cstr);
if (!data) {
- LOG("!! Could not load image resource: %s/%s\n", path_cstr, name_cstr);
+ this->log(Logger::Level::kError, nullptr,
+ "Could not load image resource: %s/%s.", path_cstr, name_cstr);
return nullptr;
}
diff --git a/modules/skottie/src/SkottieLayerEffect.cpp b/modules/skottie/src/SkottieLayerEffect.cpp
index f2743a3..e66ab7f 100644
--- a/modules/skottie/src/SkottieLayerEffect.cpp
+++ b/modules/skottie/src/SkottieLayerEffect.cpp
@@ -33,7 +33,8 @@
color_node = abuilder->attachColor(*jprop, ascope, "v");
break;
default:
- LOG("?? Ignoring unsupported fill effect poperty type: %d\n", ty);
+ abuilder->log(Logger::Level::kWarning, nullptr,
+ "Ignoring unsupported fill effect poperty type: %d.", ty);
break;
}
}
@@ -56,7 +57,7 @@
layer = AttachFillLayerEffect((*jeffect)["ef"], this, ascope, std::move(layer));
break;
default:
- LOG("?? Unsupported layer effect type: %d\n", ty);
+ this->log(Logger::Level::kWarning, nullptr, "Unsupported layer effect type: %d.", ty);
break;
}
}
diff --git a/modules/skottie/src/SkottiePriv.h b/modules/skottie/src/SkottiePriv.h
index b8c69b4..97ca6a3 100644
--- a/modules/skottie/src/SkottiePriv.h
+++ b/modules/skottie/src/SkottiePriv.h
@@ -18,8 +18,6 @@
#include "SkTypeface.h"
#include "SkUTF.h"
-#define LOG SkDebugf
-
class SkFontMgr;
namespace skjson {
@@ -39,14 +37,12 @@
namespace internal {
-void LogJSON(const skjson::Value&, const char[]);
-
using AnimatorScope = sksg::AnimatorList;
class AnimationBuilder final : public SkNoncopyable {
public:
AnimationBuilder(sk_sp<ResourceProvider>, sk_sp<SkFontMgr>, sk_sp<PropertyObserver>,
- Animation::Builder::Stats*, float duration, float framerate);
+ sk_sp<Logger>, Animation::Builder::Stats*, float duration, float framerate);
std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&);
@@ -68,6 +64,8 @@
return this->bindProperty(jv, ascope, std::move(apply), &default_ignore);
}
+ void log(Logger::Level, const skjson::Value*, const char fmt[], ...) const;
+
sk_sp<sksg::Color> attachColor(const skjson::ObjectValue&, AnimatorScope*,
const char prop_name[]) const;
sk_sp<sksg::Matrix> attachMatrix(const skjson::ObjectValue&, AnimatorScope*,
@@ -151,6 +149,7 @@
sk_sp<ResourceProvider> fResourceProvider;
LazyResolveFontMgr fLazyFontMgr;
sk_sp<PropertyObserver> fPropertyObserver;
+ sk_sp<Logger> fLogger;
Animation::Builder::Stats* fStats;
const float fDuration,
fFrameRate;
diff --git a/modules/skottie/src/SkottieShapeLayer.cpp b/modules/skottie/src/SkottieShapeLayer.cpp
index 12f2695..dd37620 100644
--- a/modules/skottie/src/SkottieShapeLayer.cpp
+++ b/modules/skottie/src/SkottieShapeLayer.cpp
@@ -98,7 +98,7 @@
const auto type = ParseDefault<size_t>(jstar["sy"], 0) - 1;
if (type >= SK_ARRAY_COUNT(gTypes)) {
- LogJSON(jstar, "!! Unknown polystar type");
+ abuilder->log(Logger::Level::kError, &jstar, "Unknown polystar type.");
return nullptr;
}
@@ -475,7 +475,7 @@
const auto* info = FindShapeInfo(*shape);
if (!info) {
- LogJSON((*shape)["ty"], "!! Unknown shape");
+ this->log(Logger::Level::kError, &(*shape)["ty"], "Unknown shape.");
continue;
}
diff --git a/modules/skottie/src/SkottieTextLayer.cpp b/modules/skottie/src/SkottieTextLayer.cpp
index 9538d56..1f043b9 100644
--- a/modules/skottie/src/SkottieTextLayer.cpp
+++ b/modules/skottie/src/SkottieTextLayer.cpp
@@ -26,7 +26,7 @@
namespace {
-SkFontStyle FontStyle(const char* style) {
+SkFontStyle FontStyle(const AnimationBuilder* abuilder, const char* style) {
static constexpr struct {
const char* fName;
const SkFontStyle::Weight fWeight;
@@ -70,7 +70,7 @@
}
if (*style != '\0') {
- LOG("?? Unknown font style: %s\n", style);
+ abuilder->log(Logger::Level::kWarning, nullptr, "Unknown font style: %s.", style);
}
return SkFontStyle(weight, SkFontStyle::kNormal_Width, slant);
@@ -116,7 +116,7 @@
if (!jname || !jname->size() ||
!jfamily || !jfamily->size() ||
!jstyle || !jstyle->size()) {
- LogJSON(*jfont, "!! Ignoring invalid font");
+ this->log(Logger::Level::kError, jfont, "Invalid font.");
continue;
}
@@ -133,14 +133,16 @@
: nullptr));
if (!tf) {
- tf.reset(fmgr->matchFamilyStyle(jfamily->begin(), FontStyle(jstyle->begin())));
+ tf.reset(fmgr->matchFamilyStyle(jfamily->begin(),
+ FontStyle(this, jstyle->begin())));
}
if (!tf) {
- LOG("!! Could not create typeface for %s|%s\n",
- jfamily->begin(), jstyle->begin());
+ this->log(Logger::Level::kError, nullptr,
+ "Could not create typeface for %s|%s.",
+ jfamily->begin(), jstyle->begin());
// Last resort.
- tf = fmgr->legacyMakeTypeface(nullptr, FontStyle(jstyle->begin()));
+ tf = fmgr->legacyMakeTypeface(nullptr, FontStyle(this, jstyle->begin()));
if (!tf) {
continue;
}
@@ -190,7 +192,7 @@
const auto ch_len = jch->size();
if (!jfamily || !jstyle || (SkUTF::CountUTF8(ch_ptr, ch_len) != 1)) {
- LogJSON(*jchar, "!! Invalid glyph");
+ this->log(Logger::Level::kError, jchar, "Invalid glyph.");
continue;
}
@@ -213,7 +215,8 @@
}
});
if (!current_font) {
- LOG("!! Font not found for codepoint (%d, %s, %s)\n", uni, family, style);
+ this->log(Logger::Level::kError, nullptr,
+ "Font not found for codepoint (%d, %s, %s).", uni, family, style);
continue;
}
}
@@ -228,7 +231,7 @@
return font->fTypeface;
}
- LOG("!! Unknown font: \"%s\"\n", font_name.c_str());
+ this->log(Logger::Level::kError, nullptr, "Unknown font: \"%s\".", font_name.c_str());
return nullptr;
}
@@ -263,13 +266,13 @@
// },
const skjson::ObjectValue* jt = layer["t"];
if (!jt) {
- LogJSON(layer, "!! Missing text layer \"t\" property");
+ this->log(Logger::Level::kError, &layer, "Missing text layer \"t\" property.");
return nullptr;
}
const skjson::ArrayValue* animated_props = (*jt)["a"];
if (animated_props && animated_props->size() > 0) {
- LOG("?? Unsupported animated text properties.\n");
+ this->log(Logger::Level::kWarning, nullptr, "Unsupported animated text properties.");
}
const skjson::ObjectValue* jd = (*jt)["d"];
diff --git a/modules/skottie/src/SkottieTool.cpp b/modules/skottie/src/SkottieTool.cpp
index b62102a..ed394e1 100644
--- a/modules/skottie/src/SkottieTool.cpp
+++ b/modules/skottie/src/SkottieTool.cpp
@@ -11,13 +11,12 @@
#include "SkMakeUnique.h"
#include "SkOSFile.h"
#include "SkOSPath.h"
+#include "Skottie.h"
#include "SkPictureRecorder.h"
#include "SkStream.h"
#include "SkSurface.h"
-#if defined(SK_ENABLE_SKOTTIE)
-#include "Skottie.h"
-#endif
+#include <vector>
DEFINE_string2(input , i, nullptr, "Input .json file.");
DEFINE_string2(writePath, w, nullptr, "Output directory. Frames are names [0-9]{6}.png.");
@@ -121,6 +120,39 @@
using INHERITED = Sink;
};
+class Logger final : public skottie::Logger {
+public:
+ struct LogEntry {
+ SkString fMessage,
+ fJSON;
+ };
+
+ void log(skottie::Logger::Level lvl, const char message[], const char json[]) override {
+ auto& log = lvl == skottie::Logger::Level::kError ? fErrors : fWarnings;
+ log.push_back({ SkString(message), json ? SkString(json) : SkString() });
+ }
+
+ void report() const {
+ SkDebugf("Animation loaded with %lu error%s, %lu warning%s.\n",
+ fErrors.size(), fErrors.size() == 1 ? "" : "s",
+ fWarnings.size(), fWarnings.size() == 1 ? "" : "s");
+
+ const auto& show = [](const LogEntry& log, const char prefix[]) {
+ SkDebugf("%s%s", prefix, log.fMessage.c_str());
+ if (!log.fJSON.isEmpty())
+ SkDebugf(" : %s", log.fJSON.c_str());
+ SkDebugf("\n");
+ };
+
+ for (const auto& err : fErrors) show(err, " !! ");
+ for (const auto& wrn : fWarnings) show(wrn, " ?? ");
+ }
+
+private:
+ std::vector<LogEntry> fErrors,
+ fWarnings;
+};
+
} // namespace
int main(int argc, char** argv) {
@@ -151,12 +183,18 @@
return 1;
}
- auto anim = skottie::Animation::MakeFromFile(FLAGS_input[0]);
+ auto logger = sk_make_sp<Logger>();
+
+ auto anim = skottie::Animation::Builder()
+ .setLogger(logger)
+ .makeFromFile(FLAGS_input[0]);
if (!anim) {
SkDebugf("Could not load animation: '%s'.\n", FLAGS_input[0]);
return 1;
}
+ logger->report();
+
static constexpr double kMaxFrames = 10000;
const auto t0 = SkTPin(FLAGS_t0, 0.0, 1.0),
t1 = SkTPin(FLAGS_t1, t0, 1.0),
diff --git a/tools/viewer/SkottieSlide.cpp b/tools/viewer/SkottieSlide.cpp
index 51b0311..251faaa 100644
--- a/tools/viewer/SkottieSlide.cpp
+++ b/tools/viewer/SkottieSlide.cpp
@@ -59,18 +59,54 @@
}
void SkottieSlide::load(SkScalar w, SkScalar h) {
+ class Logger final : public skottie::Logger {
+ public:
+ struct LogEntry {
+ SkString fMessage,
+ fJSON;
+ };
+
+ void log(skottie::Logger::Level lvl, const char message[], const char json[]) override {
+ auto& log = lvl == skottie::Logger::Level::kError ? fErrors : fWarnings;
+ log.push_back({ SkString(message), json ? SkString(json) : SkString() });
+ }
+
+ void report() const {
+ SkDebugf("Animation loaded with %lu error%s, %lu warning%s.\n",
+ fErrors.size(), fErrors.size() == 1 ? "" : "s",
+ fWarnings.size(), fWarnings.size() == 1 ? "" : "s");
+
+ const auto& show = [](const LogEntry& log, const char prefix[]) {
+ SkDebugf("%s%s", prefix, log.fMessage.c_str());
+ if (!log.fJSON.isEmpty())
+ SkDebugf(" : %s", log.fJSON.c_str());
+ SkDebugf("\n");
+ };
+
+ for (const auto& err : fErrors) show(err, " !! ");
+ for (const auto& wrn : fWarnings) show(wrn, " ?? ");
+ }
+
+ private:
+ std::vector<LogEntry> fErrors,
+ fWarnings;
+ };
+
+ auto logger = sk_make_sp<Logger>();
skottie::Animation::Builder builder;
- fAnimation = builder.makeFromFile(fPath.c_str());
+
+ fAnimation = builder.setLogger(logger).makeFromFile(fPath.c_str());
fAnimationStats = builder.getStats();
fWinSize = SkSize::Make(w, h);
fTimeBase = 0; // force a time reset
if (fAnimation) {
fAnimation->setShowInval(fShowAnimationInval);
- SkDebugf("loaded Bodymovin animation v: %s, size: [%f %f]\n",
+ SkDebugf("Loaded Bodymovin animation v: %s, size: [%f %f]\n",
fAnimation->version().c_str(),
fAnimation->size().width(),
fAnimation->size().height());
+ logger->report();
} else {
SkDebugf("failed to load Bodymovin animation: %s\n", fPath.c_str());
}