• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "include/core/SkImage.h"
11 #include "modules/skottie/src/SkottieJson.h"
12 #include "modules/sksg/include/SkSGImage.h"
13 #include "modules/sksg/include/SkSGTransform.h"
14 
15 namespace skottie {
16 namespace internal {
17 
18 const AnimationBuilder::ImageAssetInfo*
loadImageAsset(const skjson::ObjectValue & jimage) const19 AnimationBuilder::loadImageAsset(const skjson::ObjectValue& jimage) const {
20     const skjson::StringValue* name = jimage["p"];
21     const skjson::StringValue* path = jimage["u"];
22     const skjson::StringValue* id   = jimage["id"];
23     if (!name || !path || !id) {
24         return nullptr;
25     }
26 
27     const SkString res_id(id->begin());
28     if (auto* cached_info = fImageAssetCache.find(res_id)) {
29         return cached_info;
30     }
31 
32     auto asset = fResourceProvider->loadImageAsset(path->begin(), name->begin(), id->begin());
33     if (!asset) {
34         this->log(Logger::Level::kError, nullptr, "Could not load image asset: %s/%s (id: '%s').",
35                   path->begin(), name->begin(), id->begin());
36         return nullptr;
37     }
38 
39     const auto size = SkISize::Make(ParseDefault<int>(jimage["w"], 0),
40                                     ParseDefault<int>(jimage["h"], 0));
41     return fImageAssetCache.set(res_id, { std::move(asset), size });
42 }
43 
attachImageAsset(const skjson::ObjectValue & jimage,LayerInfo * layer_info) const44 sk_sp<sksg::RenderNode> AnimationBuilder::attachImageAsset(const skjson::ObjectValue& jimage,
45                                                            LayerInfo* layer_info) const {
46     const auto* asset_info = this->loadImageAsset(jimage);
47     if (!asset_info) {
48         return nullptr;
49     }
50     SkASSERT(asset_info->fAsset);
51 
52     auto image = asset_info->fAsset->getFrame(0);
53     if (!image) {
54         this->log(Logger::Level::kError, nullptr, "Could not load first image asset frame.");
55         return nullptr;
56     }
57 
58     auto image_node = sksg::Image::Make(image);
59     image_node->setQuality(kMedium_SkFilterQuality);
60 
61     if (asset_info->fAsset->isMultiFrame()) {
62         class MultiFrameAnimator final : public sksg::Animator {
63         public:
64             MultiFrameAnimator(sk_sp<ImageAsset> asset, sk_sp<sksg::Image> image_node,
65                                float time_bias, float time_scale)
66                 : fAsset(std::move(asset))
67                 , fImageNode(std::move(image_node))
68                 , fTimeBias(time_bias)
69                 , fTimeScale(time_scale) {}
70 
71             void onTick(float t) override {
72                 fImageNode->setImage(fAsset->getFrame((t + fTimeBias) * fTimeScale));
73             }
74 
75         private:
76             sk_sp<ImageAsset>     fAsset;
77             sk_sp<sksg::Image>    fImageNode;
78             float                 fTimeBias,
79                                   fTimeScale;
80         };
81 
82         fCurrentAnimatorScope->push_back(sk_make_sp<MultiFrameAnimator>(asset_info->fAsset,
83                                                                         image_node,
84                                                                         -layer_info->fInPoint,
85                                                                         1 / fFrameRate));
86     }
87 
88     const auto asset_size = SkISize::Make(
89             asset_info->fSize.width()  > 0 ? asset_info->fSize.width()  : image->width(),
90             asset_info->fSize.height() > 0 ? asset_info->fSize.height() : image->height());
91 
92     // Image layers are sized explicitly.
93     layer_info->fSize = asset_size;
94 
95     if (asset_size == image->bounds().size()) {
96         // No resize needed.
97         return image_node;
98     }
99 
100     return sksg::TransformEffect::Make(std::move(image_node),
101         SkMatrix::MakeRectToRect(SkRect::Make(image->bounds()),
102                                  SkRect::Make(asset_size),
103                                  SkMatrix::kCenter_ScaleToFit));
104 }
105 
attachImageLayer(const skjson::ObjectValue & jlayer,LayerInfo * layer_info) const106 sk_sp<sksg::RenderNode> AnimationBuilder::attachImageLayer(const skjson::ObjectValue& jlayer,
107                                                            LayerInfo* layer_info) const {
108     return this->attachAssetRef(jlayer,
109         [this, &layer_info] (const skjson::ObjectValue& jimage) {
110             return this->attachImageAsset(jimage, layer_info);
111         });
112 }
113 
114 } // namespace internal
115 } // namespace skottie
116