Skottie.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /*
  2. * Copyright 2017 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. #include "modules/skottie/include/Skottie.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkData.h"
  10. #include "include/core/SkFontMgr.h"
  11. #include "include/core/SkImage.h"
  12. #include "include/core/SkPaint.h"
  13. #include "include/core/SkPoint.h"
  14. #include "include/core/SkStream.h"
  15. #include "include/private/SkTArray.h"
  16. #include "include/private/SkTo.h"
  17. #include "modules/skottie/include/SkottieProperty.h"
  18. #include "modules/skottie/src/SkottieAdapter.h"
  19. #include "modules/skottie/src/SkottieJson.h"
  20. #include "modules/skottie/src/SkottiePriv.h"
  21. #include "modules/skottie/src/SkottieValue.h"
  22. #include "modules/sksg/include/SkSGInvalidationController.h"
  23. #include "modules/sksg/include/SkSGOpacityEffect.h"
  24. #include "modules/sksg/include/SkSGPaint.h"
  25. #include "modules/sksg/include/SkSGPath.h"
  26. #include "modules/sksg/include/SkSGRenderEffect.h"
  27. #include "modules/sksg/include/SkSGScene.h"
  28. #include "modules/sksg/include/SkSGTransform.h"
  29. #include "src/core/SkTraceEvent.h"
  30. #include <chrono>
  31. #include <cmath>
  32. #include "stdlib.h"
  33. namespace skottie {
  34. namespace internal {
  35. void AnimationBuilder::log(Logger::Level lvl, const skjson::Value* json,
  36. const char fmt[], ...) const {
  37. if (!fLogger) {
  38. return;
  39. }
  40. char buff[1024];
  41. va_list va;
  42. va_start(va, fmt);
  43. const auto len = vsnprintf(buff, sizeof(buff), fmt, va);
  44. va_end(va);
  45. if (len < 0) {
  46. SkDebugf("!! Could not format log message !!\n");
  47. return;
  48. }
  49. if (len >= SkToInt(sizeof(buff))) {
  50. static constexpr char kEllipsesStr[] = "...";
  51. strcpy(buff + sizeof(buff) - sizeof(kEllipsesStr), kEllipsesStr);
  52. }
  53. SkString jsonstr = json ? json->toString() : SkString();
  54. fLogger->log(lvl, buff, jsonstr.c_str());
  55. }
  56. sk_sp<sksg::Transform> AnimationBuilder::attachMatrix2D(const skjson::ObjectValue& t,
  57. AnimatorScope* ascope,
  58. sk_sp<sksg::Transform> parent) const {
  59. static const VectorValue g_default_vec_0 = { 0, 0},
  60. g_default_vec_100 = {100, 100};
  61. auto matrix = sksg::Matrix<SkMatrix>::Make(SkMatrix::I());
  62. auto adapter = sk_make_sp<TransformAdapter2D>(matrix);
  63. auto bound = this->bindProperty<VectorValue>(t["a"], ascope,
  64. [adapter](const VectorValue& a) {
  65. adapter->setAnchorPoint(ValueTraits<VectorValue>::As<SkPoint>(a));
  66. }, g_default_vec_0);
  67. bound |= this->bindProperty<VectorValue>(t["p"], ascope,
  68. [adapter](const VectorValue& p) {
  69. adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
  70. }, g_default_vec_0);
  71. bound |= this->bindProperty<VectorValue>(t["s"], ascope,
  72. [adapter](const VectorValue& s) {
  73. adapter->setScale(ValueTraits<VectorValue>::As<SkVector>(s));
  74. }, g_default_vec_100);
  75. const auto* jrotation = &t["r"];
  76. if (jrotation->is<skjson::NullValue>()) {
  77. // 3d rotations have separate rx,ry,rz components. While we don't fully support them,
  78. // we can still make use of rz.
  79. jrotation = &t["rz"];
  80. }
  81. bound |= this->bindProperty<ScalarValue>(*jrotation, ascope,
  82. [adapter](const ScalarValue& r) {
  83. adapter->setRotation(r);
  84. }, 0.0f);
  85. bound |= this->bindProperty<ScalarValue>(t["sk"], ascope,
  86. [adapter](const ScalarValue& sk) {
  87. adapter->setSkew(sk);
  88. }, 0.0f);
  89. bound |= this->bindProperty<ScalarValue>(t["sa"], ascope,
  90. [adapter](const ScalarValue& sa) {
  91. adapter->setSkewAxis(sa);
  92. }, 0.0f);
  93. const auto dispatched = this->dispatchTransformProperty(adapter);
  94. return (bound || dispatched)
  95. ? sksg::Transform::MakeConcat(std::move(parent), std::move(matrix))
  96. : parent;
  97. }
  98. sk_sp<sksg::Transform> AnimationBuilder::attachMatrix3D(const skjson::ObjectValue& t,
  99. AnimatorScope* ascope,
  100. sk_sp<sksg::Transform> parent,
  101. sk_sp<TransformAdapter3D> adapter,
  102. bool precompose_parent) const {
  103. static const VectorValue g_default_vec_0 = { 0, 0, 0},
  104. g_default_vec_100 = {100, 100, 100};
  105. if (!adapter) {
  106. // Default to TransformAdapter3D (we only use external adapters for cameras).
  107. adapter = sk_make_sp<TransformAdapter3D>();
  108. }
  109. auto bound = this->bindProperty<VectorValue>(t["a"], ascope,
  110. [adapter](const VectorValue& a) {
  111. adapter->setAnchorPoint(TransformAdapter3D::Vec3(a));
  112. }, g_default_vec_0);
  113. bound |= this->bindProperty<VectorValue>(t["p"], ascope,
  114. [adapter](const VectorValue& p) {
  115. adapter->setPosition(TransformAdapter3D::Vec3(p));
  116. }, g_default_vec_0);
  117. bound |= this->bindProperty<VectorValue>(t["s"], ascope,
  118. [adapter](const VectorValue& s) {
  119. adapter->setScale(TransformAdapter3D::Vec3(s));
  120. }, g_default_vec_100);
  121. // Orientation and rx/ry/rz are mapped to the same rotation property -- the difference is
  122. // in how they get interpolated (vector vs. scalar/decomposed interpolation).
  123. bound |= this->bindProperty<VectorValue>(t["or"], ascope,
  124. [adapter](const VectorValue& o) {
  125. adapter->setRotation(TransformAdapter3D::Vec3(o));
  126. }, g_default_vec_0);
  127. bound |= this->bindProperty<ScalarValue>(t["rx"], ascope,
  128. [adapter](const ScalarValue& rx) {
  129. const auto& r = adapter->getRotation();
  130. adapter->setRotation(TransformAdapter3D::Vec3({rx, r.fY, r.fZ}));
  131. }, 0.0f);
  132. bound |= this->bindProperty<ScalarValue>(t["ry"], ascope,
  133. [adapter](const ScalarValue& ry) {
  134. const auto& r = adapter->getRotation();
  135. adapter->setRotation(TransformAdapter3D::Vec3({r.fX, ry, r.fZ}));
  136. }, 0.0f);
  137. bound |= this->bindProperty<ScalarValue>(t["rz"], ascope,
  138. [adapter](const ScalarValue& rz) {
  139. const auto& r = adapter->getRotation();
  140. adapter->setRotation(TransformAdapter3D::Vec3({r.fX, r.fY, rz}));
  141. }, 0.0f);
  142. // TODO: dispatch 3D transform properties
  143. if (!bound) {
  144. return parent;
  145. }
  146. return precompose_parent
  147. ? sksg::Transform::MakeConcat(adapter->refTransform(), std::move(parent))
  148. : sksg::Transform::MakeConcat(std::move(parent), adapter->refTransform());
  149. }
  150. sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValue& jtransform,
  151. AnimatorScope* ascope,
  152. sk_sp<sksg::RenderNode> childNode) const {
  153. if (!childNode)
  154. return nullptr;
  155. auto opacityNode = sksg::OpacityEffect::Make(childNode);
  156. const auto bound = this->bindProperty<ScalarValue>(jtransform["o"], ascope,
  157. [opacityNode](const ScalarValue& o) {
  158. // BM opacity is [0..100]
  159. opacityNode->setOpacity(o * 0.01f);
  160. }, 100.0f);
  161. const auto dispatched = this->dispatchOpacityProperty(opacityNode);
  162. // We can ignore constant full opacity.
  163. return (bound || dispatched) ? std::move(opacityNode) : childNode;
  164. }
  165. namespace {
  166. static SkBlendMode GetBlendMode(const skjson::ObjectValue& jobject,
  167. const AnimationBuilder* abuilder) {
  168. static constexpr SkBlendMode kBlendModeMap[] = {
  169. SkBlendMode::kSrcOver, // 0:'normal'
  170. SkBlendMode::kMultiply, // 1:'multiply'
  171. SkBlendMode::kScreen, // 2:'screen'
  172. SkBlendMode::kOverlay, // 3:'overlay
  173. SkBlendMode::kDarken, // 4:'darken'
  174. SkBlendMode::kLighten, // 5:'lighten'
  175. SkBlendMode::kColorDodge, // 6:'color-dodge'
  176. SkBlendMode::kColorBurn, // 7:'color-burn'
  177. SkBlendMode::kHardLight, // 8:'hard-light'
  178. SkBlendMode::kSoftLight, // 9:'soft-light'
  179. SkBlendMode::kDifference, // 10:'difference'
  180. SkBlendMode::kExclusion, // 11:'exclusion'
  181. SkBlendMode::kHue, // 12:'hue'
  182. SkBlendMode::kSaturation, // 13:'saturation'
  183. SkBlendMode::kColor, // 14:'color'
  184. SkBlendMode::kLuminosity, // 15:'luminosity'
  185. SkBlendMode::kPlus, // 16:'add'
  186. };
  187. const auto bm_index = ParseDefault<size_t>(jobject["bm"], 0);
  188. if (bm_index >= SK_ARRAY_COUNT(kBlendModeMap)) {
  189. abuilder->log(Logger::Level::kWarning, &jobject,
  190. "Unsupported blend mode %lu\n", bm_index);
  191. return SkBlendMode::kSrcOver;
  192. }
  193. return kBlendModeMap[bm_index];
  194. }
  195. } // namespace
  196. sk_sp<sksg::RenderNode> AnimationBuilder::attachBlendMode(const skjson::ObjectValue& jobject,
  197. sk_sp<sksg::RenderNode> child) const {
  198. const auto bm = GetBlendMode(jobject, this);
  199. if (bm != SkBlendMode::kSrcOver) {
  200. fHasNontrivialBlending = true;
  201. child = sksg::BlendModeEffect::Make(std::move(child), bm);
  202. }
  203. return child;
  204. }
  205. sk_sp<sksg::Path> AnimationBuilder::attachPath(const skjson::Value& jpath,
  206. AnimatorScope* ascope) const {
  207. auto path_node = sksg::Path::Make();
  208. return this->bindProperty<ShapeValue>(jpath, ascope,
  209. [path_node](const ShapeValue& p) {
  210. // FillType is tracked in the SG node, not in keyframes -- make sure we preserve it.
  211. auto path = ValueTraits<ShapeValue>::As<SkPath>(p);
  212. path.setFillType(path_node->getFillType());
  213. path_node->setPath(path);
  214. })
  215. ? path_node
  216. : nullptr;
  217. }
  218. sk_sp<sksg::Color> AnimationBuilder::attachColor(const skjson::ObjectValue& jcolor,
  219. AnimatorScope* ascope,
  220. const char prop_name[]) const {
  221. auto color_node = sksg::Color::Make(SK_ColorBLACK);
  222. this->bindProperty<VectorValue>(jcolor[prop_name], ascope,
  223. [color_node](const VectorValue& c) {
  224. color_node->setColor(ValueTraits<VectorValue>::As<SkColor>(c));
  225. });
  226. this->dispatchColorProperty(color_node);
  227. return color_node;
  228. }
  229. AnimationBuilder::AnimationBuilder(sk_sp<ResourceProvider> rp, sk_sp<SkFontMgr> fontmgr,
  230. sk_sp<PropertyObserver> pobserver, sk_sp<Logger> logger,
  231. sk_sp<MarkerObserver> mobserver,
  232. Animation::Builder::Stats* stats,
  233. const SkSize& size, float duration, float framerate)
  234. : fResourceProvider(std::move(rp))
  235. , fLazyFontMgr(std::move(fontmgr))
  236. , fPropertyObserver(std::move(pobserver))
  237. , fLogger(std::move(logger))
  238. , fMarkerObserver(std::move(mobserver))
  239. , fStats(stats)
  240. , fSize(size)
  241. , fDuration(duration)
  242. , fFrameRate(framerate)
  243. , fHasNontrivialBlending(false) {}
  244. std::unique_ptr<sksg::Scene> AnimationBuilder::parse(const skjson::ObjectValue& jroot) {
  245. this->dispatchMarkers(jroot["markers"]);
  246. this->parseAssets(jroot["assets"]);
  247. this->parseFonts(jroot["fonts"], jroot["chars"]);
  248. AnimatorScope animators;
  249. auto root = this->attachComposition(jroot, &animators);
  250. fStats->fAnimatorCount = animators.size();
  251. return sksg::Scene::Make(std::move(root), std::move(animators));
  252. }
  253. void AnimationBuilder::parseAssets(const skjson::ArrayValue* jassets) {
  254. if (!jassets) {
  255. return;
  256. }
  257. for (const skjson::ObjectValue* asset : *jassets) {
  258. if (asset) {
  259. fAssets.set(ParseDefault<SkString>((*asset)["id"], SkString()), { asset, false });
  260. }
  261. }
  262. }
  263. void AnimationBuilder::dispatchMarkers(const skjson::ArrayValue* jmarkers) const {
  264. if (!fMarkerObserver || !jmarkers) {
  265. return;
  266. }
  267. // For frame-number -> t conversions.
  268. const auto frameRatio = 1 / (fFrameRate * fDuration);
  269. for (const skjson::ObjectValue* m : *jmarkers) {
  270. if (!m) continue;
  271. const skjson::StringValue* name = (*m)["cm"];
  272. const auto time = ParseDefault((*m)["tm"], -1.0f),
  273. duration = ParseDefault((*m)["dr"], -1.0f);
  274. if (name && time >= 0 && duration >= 0) {
  275. fMarkerObserver->onMarker(
  276. name->begin(),
  277. // "tm" is in frames
  278. time * frameRatio,
  279. // ... as is "dr"
  280. (time + duration) * frameRatio
  281. );
  282. } else {
  283. this->log(Logger::Level::kWarning, m, "Ignoring unexpected marker.");
  284. }
  285. }
  286. }
  287. bool AnimationBuilder::dispatchColorProperty(const sk_sp<sksg::Color>& c) const {
  288. bool dispatched = false;
  289. if (fPropertyObserver) {
  290. fPropertyObserver->onColorProperty(fPropertyObserverContext,
  291. [&]() {
  292. dispatched = true;
  293. return std::unique_ptr<ColorPropertyHandle>(new ColorPropertyHandle(c));
  294. });
  295. }
  296. return dispatched;
  297. }
  298. bool AnimationBuilder::dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>& o) const {
  299. bool dispatched = false;
  300. if (fPropertyObserver) {
  301. fPropertyObserver->onOpacityProperty(fPropertyObserverContext,
  302. [&]() {
  303. dispatched = true;
  304. return std::unique_ptr<OpacityPropertyHandle>(new OpacityPropertyHandle(o));
  305. });
  306. }
  307. return dispatched;
  308. }
  309. bool AnimationBuilder::dispatchTransformProperty(const sk_sp<TransformAdapter2D>& t) const {
  310. bool dispatched = false;
  311. if (fPropertyObserver) {
  312. fPropertyObserver->onTransformProperty(fPropertyObserverContext,
  313. [&]() {
  314. dispatched = true;
  315. return std::unique_ptr<TransformPropertyHandle>(new TransformPropertyHandle(t));
  316. });
  317. }
  318. return dispatched;
  319. }
  320. void AnimationBuilder::AutoPropertyTracker::updateContext(PropertyObserver* observer,
  321. const skjson::ObjectValue& obj) {
  322. const skjson::StringValue* name = obj["nm"];
  323. fBuilder->fPropertyObserverContext = name ? name->begin() : nullptr;
  324. }
  325. } // namespace internal
  326. sk_sp<SkData> ResourceProvider::load(const char[], const char[]) const {
  327. return nullptr;
  328. }
  329. sk_sp<ImageAsset> ResourceProvider::loadImageAsset(const char path[], const char name[],
  330. const char id[]) const {
  331. return nullptr;
  332. }
  333. sk_sp<SkData> ResourceProvider::loadFont(const char[], const char[]) const {
  334. return nullptr;
  335. }
  336. void Logger::log(Level, const char[], const char*) {}
  337. Animation::Builder::Builder() = default;
  338. Animation::Builder::~Builder() = default;
  339. Animation::Builder& Animation::Builder::setResourceProvider(sk_sp<ResourceProvider> rp) {
  340. fResourceProvider = std::move(rp);
  341. return *this;
  342. }
  343. Animation::Builder& Animation::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
  344. fFontMgr = std::move(fmgr);
  345. return *this;
  346. }
  347. Animation::Builder& Animation::Builder::setPropertyObserver(sk_sp<PropertyObserver> pobserver) {
  348. fPropertyObserver = std::move(pobserver);
  349. return *this;
  350. }
  351. Animation::Builder& Animation::Builder::setLogger(sk_sp<Logger> logger) {
  352. fLogger = std::move(logger);
  353. return *this;
  354. }
  355. Animation::Builder& Animation::Builder::setMarkerObserver(sk_sp<MarkerObserver> mobserver) {
  356. fMarkerObserver = std::move(mobserver);
  357. return *this;
  358. }
  359. sk_sp<Animation> Animation::Builder::make(SkStream* stream) {
  360. if (!stream->hasLength()) {
  361. // TODO: handle explicit buffering?
  362. if (fLogger) {
  363. fLogger->log(Logger::Level::kError, "Cannot parse streaming content.\n");
  364. }
  365. return nullptr;
  366. }
  367. auto data = SkData::MakeFromStream(stream, stream->getLength());
  368. if (!data) {
  369. if (fLogger) {
  370. fLogger->log(Logger::Level::kError, "Failed to read the input stream.\n");
  371. }
  372. return nullptr;
  373. }
  374. return this->make(static_cast<const char*>(data->data()), data->size());
  375. }
  376. sk_sp<Animation> Animation::Builder::make(const char* data, size_t data_len) {
  377. TRACE_EVENT0("skottie", TRACE_FUNC);
  378. // Sanitize factory args.
  379. class NullResourceProvider final : public ResourceProvider {
  380. sk_sp<SkData> load(const char[], const char[]) const override { return nullptr; }
  381. };
  382. auto resolvedProvider = fResourceProvider
  383. ? fResourceProvider : sk_make_sp<NullResourceProvider>();
  384. memset(&fStats, 0, sizeof(struct Stats));
  385. fStats.fJsonSize = data_len;
  386. const auto t0 = std::chrono::steady_clock::now();
  387. const skjson::DOM dom(data, data_len);
  388. if (!dom.root().is<skjson::ObjectValue>()) {
  389. // TODO: more error info.
  390. if (fLogger) {
  391. fLogger->log(Logger::Level::kError, "Failed to parse JSON input.\n");
  392. }
  393. return nullptr;
  394. }
  395. const auto& json = dom.root().as<skjson::ObjectValue>();
  396. const auto t1 = std::chrono::steady_clock::now();
  397. fStats.fJsonParseTimeMS = std::chrono::duration<float, std::milli>{t1-t0}.count();
  398. const auto version = ParseDefault<SkString>(json["v"], SkString());
  399. const auto size = SkSize::Make(ParseDefault<float>(json["w"], 0.0f),
  400. ParseDefault<float>(json["h"], 0.0f));
  401. const auto fps = ParseDefault<float>(json["fr"], -1.0f),
  402. inPoint = ParseDefault<float>(json["ip"], 0.0f),
  403. outPoint = SkTMax(ParseDefault<float>(json["op"], SK_ScalarMax), inPoint),
  404. duration = sk_ieee_float_divide(outPoint - inPoint, fps);
  405. if (size.isEmpty() || version.isEmpty() || fps <= 0 ||
  406. !SkScalarIsFinite(inPoint) || !SkScalarIsFinite(outPoint) || !SkScalarIsFinite(duration)) {
  407. if (fLogger) {
  408. const auto msg = SkStringPrintf(
  409. "Invalid animation params (version: %s, size: [%f %f], frame rate: %f, "
  410. "in-point: %f, out-point: %f)\n",
  411. version.c_str(), size.width(), size.height(), fps, inPoint, outPoint);
  412. fLogger->log(Logger::Level::kError, msg.c_str());
  413. }
  414. return nullptr;
  415. }
  416. SkASSERT(resolvedProvider);
  417. internal::AnimationBuilder builder(std::move(resolvedProvider), fFontMgr,
  418. std::move(fPropertyObserver),
  419. std::move(fLogger),
  420. std::move(fMarkerObserver),
  421. &fStats, size, duration, fps);
  422. auto scene = builder.parse(json);
  423. const auto t2 = std::chrono::steady_clock::now();
  424. fStats.fSceneParseTimeMS = std::chrono::duration<float, std::milli>{t2-t1}.count();
  425. fStats.fTotalLoadTimeMS = std::chrono::duration<float, std::milli>{t2-t0}.count();
  426. if (!scene && fLogger) {
  427. fLogger->log(Logger::Level::kError, "Could not parse animation.\n");
  428. }
  429. uint32_t flags = 0;
  430. if (builder.hasNontrivialBlending()) {
  431. flags |= Flags::kRequiresTopLevelIsolation;
  432. }
  433. return sk_sp<Animation>(new Animation(std::move(scene),
  434. std::move(version),
  435. size,
  436. inPoint,
  437. outPoint,
  438. duration,
  439. flags));
  440. }
  441. sk_sp<Animation> Animation::Builder::makeFromFile(const char path[]) {
  442. const auto data = SkData::MakeFromFileName(path);
  443. return data ? this->make(static_cast<const char*>(data->data()), data->size())
  444. : nullptr;
  445. }
  446. Animation::Animation(std::unique_ptr<sksg::Scene> scene, SkString version, const SkSize& size,
  447. SkScalar inPoint, SkScalar outPoint, SkScalar duration, uint32_t flags)
  448. : fScene(std::move(scene))
  449. , fVersion(std::move(version))
  450. , fSize(size)
  451. , fInPoint(inPoint)
  452. , fOutPoint(outPoint)
  453. , fDuration(duration)
  454. , fFlags(flags) {
  455. // In case the client calls render before the first tick.
  456. this->seek(0);
  457. }
  458. Animation::~Animation() = default;
  459. void Animation::render(SkCanvas* canvas, const SkRect* dstR) const {
  460. this->render(canvas, dstR, 0);
  461. }
  462. void Animation::render(SkCanvas* canvas, const SkRect* dstR, RenderFlags renderFlags) const {
  463. TRACE_EVENT0("skottie", TRACE_FUNC);
  464. if (!fScene)
  465. return;
  466. SkAutoCanvasRestore restore(canvas, true);
  467. const SkRect srcR = SkRect::MakeSize(this->size());
  468. if (dstR) {
  469. canvas->concat(SkMatrix::MakeRectToRect(srcR, *dstR, SkMatrix::kCenter_ScaleToFit));
  470. }
  471. if ((fFlags & Flags::kRequiresTopLevelIsolation) &&
  472. !(renderFlags & RenderFlag::kSkipTopLevelIsolation)) {
  473. // The animation uses non-trivial blending, and needs
  474. // to be rendered into a separate/transparent layer.
  475. canvas->saveLayer(srcR, nullptr);
  476. }
  477. canvas->clipRect(srcR);
  478. fScene->render(canvas);
  479. }
  480. void Animation::seek(SkScalar t, sksg::InvalidationController* ic) {
  481. TRACE_EVENT0("skottie", TRACE_FUNC);
  482. if (!fScene)
  483. return;
  484. // Per AE/Lottie semantics out_point is exclusive.
  485. const auto kLastValidFrame = std::nextafter(fOutPoint, fInPoint);
  486. fScene->animate(SkTPin(fInPoint + t * (fOutPoint - fInPoint), fInPoint, kLastValidFrame), ic);
  487. }
  488. void Animation::seekFrameTime(double t, sksg::InvalidationController* ic) {
  489. if (double dur = this->duration()) {
  490. this->seek((SkScalar)(t / dur), ic);
  491. }
  492. }
  493. sk_sp<Animation> Animation::Make(const char* data, size_t length) {
  494. return Builder().make(data, length);
  495. }
  496. sk_sp<Animation> Animation::Make(SkStream* stream) {
  497. return Builder().make(stream);
  498. }
  499. sk_sp<Animation> Animation::MakeFromFile(const char path[]) {
  500. return Builder().makeFromFile(path);
  501. }
  502. } // namespace skottie