1 /*
2  * Copyright 2018 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 "include/android/SkAnimatedImage.h"
9 #include "include/codec/SkAndroidCodec.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPictureRecorder.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkString.h"
17 #include "tools/timer/TimeUtils.h"
18 
19 #include "samplecode/Sample.h"
20 #include "tools/Resources.h"
21 
22 static constexpr char kPauseKey = 'p';
23 static constexpr char kResetKey = 'r';
24 
25 class SampleAnimatedImage : public Sample {
26     sk_sp<SkAnimatedImage>  fImage;
27     sk_sp<SkDrawable>       fDrawable;
28     SkScalar                fYOffset = 0;
29     bool                    fRunning = false;
30     double                  fCurrentTime = 0.0;
31     double                  fLastWallTime = 0.0;
32     double                  fTimeToShowNextFrame = 0.0;
33 
onDrawBackground(SkCanvas * canvas)34     void onDrawBackground(SkCanvas* canvas) override {
35         SkFont font;
36         font.setSize(20);
37 
38         SkString str = SkStringPrintf("Press '%c' to start/pause; '%c' to reset.",
39                 kPauseKey, kResetKey);
40         const char* text = str.c_str();
41         SkRect bounds;
42         font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
43         fYOffset = bounds.height();
44 
45         canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, 5, fYOffset, font, SkPaint());
46         fYOffset *= 2;
47     }
48 
onDrawContent(SkCanvas * canvas)49     void onDrawContent(SkCanvas* canvas) override {
50         if (!fImage) {
51             return;
52         }
53 
54         canvas->translate(0, fYOffset);
55 
56         canvas->drawDrawable(fImage.get());
57         canvas->drawDrawable(fDrawable.get(), fImage->getBounds().width(), 0);
58     }
59 
onAnimate(double nanos)60     bool onAnimate(double nanos) override {
61         if (!fImage) {
62             return false;
63         }
64 
65         const double lastWallTime = fLastWallTime;
66         fLastWallTime = TimeUtils::NanosToMSec(nanos);
67 
68         if (fRunning) {
69             fCurrentTime += fLastWallTime - lastWallTime;
70             if (fCurrentTime > fTimeToShowNextFrame) {
71                 fTimeToShowNextFrame += fImage->decodeNextFrame();
72                 if (fImage->isFinished()) {
73                     fRunning = false;
74                 }
75             }
76         }
77 
78         return true;
79     }
80 
onOnceBeforeDraw()81     void onOnceBeforeDraw() override {
82         sk_sp<SkData> file(GetResourceAsData("images/alphabetAnim.gif"));
83         std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(file));
84         if (!codec) {
85             return;
86         }
87 
88         fImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(std::move(codec)));
89         if (!fImage) {
90             return;
91         }
92 
93         fTimeToShowNextFrame = fImage->currentFrameDuration();
94         SkPictureRecorder recorder;
95         auto canvas = recorder.beginRecording(fImage->getBounds());
96         canvas->drawDrawable(fImage.get());
97         fDrawable = recorder.finishRecordingAsDrawable();
98     }
99 
name()100     SkString name() override { return SkString("AnimatedImage"); }
101 
onChar(SkUnichar uni)102     bool onChar(SkUnichar uni) override {
103         if (fImage) {
104             switch (uni) {
105                 case kPauseKey:
106                     fRunning = !fRunning;
107                     if (fImage->isFinished()) {
108                         // fall through
109                     } else {
110                         return true;
111                     }
112                 case kResetKey:
113                     fImage->reset();
114                     fCurrentTime = fLastWallTime;
115                     fTimeToShowNextFrame = fCurrentTime + fImage->currentFrameDuration();
116                     return true;
117                 default:
118                     break;
119             }
120         }
121         return false;
122     }
123 };
124 
125 DEF_SAMPLE( return new SampleAnimatedImage(); )
126