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 "SkAndroidCodec.h"
9#include "SkAnimatedImage.h"
10#include "SkAnimTimer.h"
11#include "SkCanvas.h"
12#include "SkPaint.h"
13#include "SkPictureRecorder.h"
14#include "SkRect.h"
15#include "SkScalar.h"
16#include "SkString.h"
17
18#include "SampleCode.h"
19#include "Resources.h"
20
21static constexpr char kPauseKey = 'p';
22static constexpr char kResetKey = 'r';
23
24class SampleAnimatedImage : public SampleView {
25public:
26    SampleAnimatedImage()
27        : INHERITED()
28        , fYOffset(0)
29    {}
30
31protected:
32    void onDrawBackground(SkCanvas* canvas) override {
33        SkPaint paint;
34        paint.setAntiAlias(true);
35        constexpr SkScalar kTextSize = 20;
36        paint.setTextSize(kTextSize);
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        paint.measureText(text, strlen(text), &bounds);
43        fYOffset = bounds.height();
44
45        canvas->drawText(text, strlen(text), 5, fYOffset, paint);
46        fYOffset *= 2;
47    }
48
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
60    bool onAnimate(const SkAnimTimer& animTimer) override {
61        if (!fImage) {
62            return false;
63        }
64
65        const double lastWallTime = fLastWallTime;
66        fLastWallTime = animTimer.msec();
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
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
100    bool onQuery(SkEvent* evt) override {
101        if (SampleCode::TitleQ(*evt)) {
102            SampleCode::TitleR(evt, "AnimatedImage");
103            return true;
104        }
105
106        SkUnichar uni;
107        if (fImage && SampleCode::CharQ(*evt, &uni)) {
108            switch (uni) {
109                case kPauseKey:
110                    fRunning = !fRunning;
111                    if (fImage->isFinished()) {
112                        // fall through
113                    } else {
114                        return true;
115                    }
116                case kResetKey:
117                    fImage->reset();
118                    fCurrentTime = fLastWallTime;
119                    fTimeToShowNextFrame = fCurrentTime + fImage->currentFrameDuration();
120                    return true;
121                default:
122                    break;
123            }
124        }
125        return this->INHERITED::onQuery(evt);
126    }
127
128private:
129    sk_sp<SkAnimatedImage>  fImage;
130    sk_sp<SkDrawable>       fDrawable;
131    SkScalar                fYOffset;
132    bool                    fRunning = false;
133    double                  fCurrentTime = 0.0;
134    double                  fLastWallTime = 0.0;
135    double                  fTimeToShowNextFrame = 0.0;
136    typedef SampleView INHERITED;
137};
138
139///////////////////////////////////////////////////////////////////////////////
140
141static SkView* MyFactory() {
142    return new SampleAnimatedImage;
143}
144
145static SkViewRegister reg(MyFactory);
146