Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / tools / skottie_ios_app / SkottieViewController.mm
1 // Copyright 2019 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3
4 #include "tools/skottie_ios_app/SkottieViewController.h"
5
6 #include "include/core/SkCanvas.h"
7 #include "include/core/SkPaint.h"
8 #include "include/core/SkSurface.h"
9 #include "include/core/SkTime.h"
10 #include "modules/skottie/include/Skottie.h"
11
12 #include <cmath>
13
14 ////////////////////////////////////////////////////////////////////////////////
15
16 class SkAnimationDraw {
17 public:
18     SkAnimationDraw() = default;
19     ~SkAnimationDraw() = default;
20
21     explicit operator bool() const { return fAnimation != nullptr; }
22
23     void draw(SkSize size, SkCanvas* canvas) {
24         if (size.width() != fSize.width() || size.height() != fSize.height()) {
25             // Cache the current matrix; change only if size changes.
26             if (fAnimationSize.width() > 0 && fAnimationSize.height() > 0) {
27                 float scale = std::min(size.width() / fAnimationSize.width(),
28                                        size.height() / fAnimationSize.height());
29                 fMatrix.setScaleTranslate(
30                         scale, scale,
31                         (size.width()  - fAnimationSize.width()  * scale) * 0.5f,
32                         (size.height() - fAnimationSize.height() * scale) * 0.5f);
33             } else {
34                 fMatrix = SkMatrix();
35             }
36             fSize = size;
37         }
38         canvas->concat(fMatrix);
39         SkRect rect = {0, 0, fAnimationSize.width(), fAnimationSize.height()};
40         canvas->drawRect(rect, SkPaint(SkColors::kWhite));
41         fAnimation->render(canvas);
42     }
43
44     void load(const void* data, size_t length) {
45         skottie::Animation::Builder builder;
46         fAnimation = builder.make((const char*)data, (size_t)length);
47         fSize = {0, 0};
48         fAnimationSize = fAnimation ? fAnimation->size() : SkSize{0, 0};
49     }
50
51     void seek(double time) { if (fAnimation) { fAnimation->seekFrameTime(time, nullptr); } }
52
53     float duration() { return fAnimation ? fAnimation->duration() : 0; }
54
55     SkSize size() { return fAnimationSize; }
56
57 private:
58     sk_sp<skottie::Animation> fAnimation; // owner
59     SkSize fSize;
60     SkSize fAnimationSize;
61     SkMatrix fMatrix;
62
63     SkAnimationDraw(const SkAnimationDraw&) = delete;
64     SkAnimationDraw& operator=(const SkAnimationDraw&) = delete;
65 };
66
67 ////////////////////////////////////////////////////////////////////////////////
68
69 class SkTimeKeeper {
70 private:
71     double fStartTime = 0; // used when running
72     float fAnimationMoment = 0; // when paused.
73     float fDuration = 0;
74     bool fPaused = false;
75     bool fStopAtEnd = false;
76
77 public:
78     void setStopAtEnd(bool s) { fStopAtEnd = s; }
79
80     float currentTime() {
81         if (0 == fDuration) {
82             return 0;
83         }
84         if (fPaused) {
85             return fAnimationMoment;
86         }
87         double time = 1e-9 * (SkTime::GetNSecs() - fStartTime);
88         if (fStopAtEnd && time >= fDuration) {
89             fPaused = true;
90             fAnimationMoment = fDuration;
91             return fAnimationMoment;
92         }
93         return std::fmod(time, fDuration);
94     }
95
96     void setDuration(float d) {
97         fDuration = d;
98         fStartTime = SkTime::GetNSecs();
99         fAnimationMoment = 0;
100     }
101
102     bool paused() const { return fPaused; }
103
104     float duration() const { return fDuration; }
105
106     void seek(float seconds) {
107         if (fPaused) {
108             fAnimationMoment = std::fmod(seconds, fDuration);
109         } else {
110             fStartTime = SkTime::GetNSecs() - 1e9 * seconds;
111         }
112     }
113
114     void togglePaused() {
115         if (fPaused) {
116             double offset = (fAnimationMoment >= fDuration) ? 0 : -1e9 * fAnimationMoment;
117             fStartTime = SkTime::GetNSecs() + offset;
118             fPaused = false;
119         } else {
120             fAnimationMoment = this->currentTime();
121             fPaused = true;
122         }
123     }
124 };
125
126 ////////////////////////////////////////////////////////////////////////////////
127
128 @implementation SkottieViewController {
129     SkAnimationDraw fDraw;
130     SkTimeKeeper fClock;
131 }
132
133 - (bool)loadAnimation:(NSData*) data {
134     fDraw.load((const void*)[data bytes], (size_t)[data length]);
135     fClock.setDuration(fDraw.duration());
136     return (bool)fDraw;
137 }
138
139 - (void)setStopAtEnd:(bool)stop { fClock.setStopAtEnd(stop); }
140
141 - (float)animationDurationSeconds { return fClock.duration(); }
142
143 - (float)currentTime { return fDraw ? fClock.currentTime() : 0; }
144
145 - (void)seek:(float)seconds {
146     if (fDraw) {
147         fClock.seek(seconds);
148     }
149 }
150
151 - (CGSize)size { return {(CGFloat)fDraw.size().width(), (CGFloat)fDraw.size().height()}; }
152
153 - (bool)togglePaused {
154     fClock.togglePaused();
155     return fClock.paused();
156 }
157
158 - (bool)isPaused { return fClock.paused(); }
159
160 - (void)draw:(CGRect)rect toCanvas:(SkCanvas*)canvas atSize:(CGSize)size {
161     // TODO(halcanary): Use the rect and the InvalidationController to speed up rendering.
162     if (rect.size.width > 0 && rect.size.height > 0 && fDraw && canvas) {
163         if (!fClock.paused()) {
164             fDraw.seek(fClock.currentTime());
165         }
166         fDraw.draw(SkSize{(float)size.width, (float)size.height}, canvas);
167     }
168 }
169
170 @end