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#ifndef SkAnimatedImage_DEFINED
9#define SkAnimatedImage_DEFINED
10
11#include "include/codec/SkCodecAnimation.h"
12#include "include/core/SkBitmap.h"
13#include "include/core/SkDrawable.h"
14#include "include/core/SkMatrix.h"
15#include "include/core/SkRect.h"
16
17class SkAndroidCodec;
18class SkImage;
19class SkPicture;
20
21/**
22 *  Thread unsafe drawable for drawing animated images (e.g. GIF).
23 */
24class SK_API SkAnimatedImage : public SkDrawable {
25public:
26    /**
27     *  Create an SkAnimatedImage from the SkAndroidCodec.
28     *
29     *  Returns null on failure to allocate pixels. On success, this will
30     *  decode the first frame.
31     *
32     *  @param info Width and height may require scaling.
33     *  @param cropRect Rectangle to crop to after scaling.
34     *  @param postProcess Picture to apply after scaling and cropping.
35     */
36    static sk_sp<SkAnimatedImage> Make(std::unique_ptr<SkAndroidCodec>,
37            const SkImageInfo& info, SkIRect cropRect, sk_sp<SkPicture> postProcess);
38
39    /**
40     *  Simpler version that uses the default size, no cropping, and no postProcess.
41     */
42    static sk_sp<SkAnimatedImage> Make(std::unique_ptr<SkAndroidCodec>);
43
44    ~SkAnimatedImage() override;
45
46    /**
47     *  Reset the animation to the beginning.
48     */
49    void reset();
50
51    /**
52     *  Whether the animation completed.
53     *
54     *  Returns true after all repetitions are complete, or an error stops the
55     *  animation. Gets reset to false if the animation is restarted.
56     */
57    bool isFinished() const { return fFinished; }
58
59    /**
60     * Returned by decodeNextFrame and currentFrameDuration if the animation
61     * is not running.
62     */
63    static constexpr int kFinished = -1;
64
65    /**
66     *  Decode the next frame.
67     *
68     *  If the animation is on the last frame or has hit an error, returns
69     *  kFinished.
70     */
71    int decodeNextFrame();
72
73    /**
74     *  Returns the current frame as an SkImage. The SkImage will not change
75     *  after it has been returned.
76     *  If there is no current frame, nullptr will be returned.
77     */
78    sk_sp<SkImage> getCurrentFrame();
79
80    /**
81     *  How long to display the current frame.
82     *
83     *  Useful for the first frame, for which decodeNextFrame is called
84     *  internally.
85     */
86    int currentFrameDuration() {
87        return fCurrentFrameDuration;
88    }
89
90    /**
91     *  Change the repetition count.
92     *
93     *  By default, the image will repeat the number of times indicated in the
94     *  encoded data.
95     *
96     *  Use SkCodec::kRepetitionCountInfinite for infinite, and 0 to show all
97     *  frames once and then stop.
98     */
99    void setRepetitionCount(int count);
100
101    /**
102     *  Return the currently set repetition count.
103     */
104    int getRepetitionCount() const {
105        return fRepetitionCount;
106    }
107
108    /**
109     *  Return the total number of frames in the animation.
110     */
111    int getFrameCount() const { return fFrameCount; }
112
113protected:
114    SkRect onGetBounds() override;
115    void onDraw(SkCanvas*) override;
116
117private:
118    struct Frame {
119        SkBitmap fBitmap;
120        int      fIndex;
121        SkCodecAnimation::DisposalMethod fDisposalMethod;
122
123        // init() may have to create a new SkPixelRef, if the
124        // current one is already in use by another owner (e.g.
125        // an SkPicture). This determines whether to copy the
126        // existing one to the new one.
127        enum class OnInit {
128            // Restore the image from the old SkPixelRef to the
129            // new one.
130            kRestoreIfNecessary,
131            // No need to restore.
132            kNoRestore,
133        };
134
135        Frame();
136        bool init(const SkImageInfo& info, OnInit);
137        bool copyTo(Frame*) const;
138    };
139
140    std::unique_ptr<SkAndroidCodec> fCodec;
141          SkImageInfo               fDecodeInfo;
142    const SkIRect                   fCropRect;
143    const sk_sp<SkPicture>          fPostProcess;
144    const int                       fFrameCount;
145    SkMatrix                        fMatrix;
146    int                             fSampleSize;
147
148    bool                            fFinished;
149    int                             fCurrentFrameDuration;
150    Frame                           fDisplayFrame;
151    Frame                           fDecodingFrame;
152    Frame                           fRestoreFrame;
153    int                             fRepetitionCount;
154    int                             fRepetitionsCompleted;
155
156    SkAnimatedImage(std::unique_ptr<SkAndroidCodec>, const SkImageInfo& requestedInfo,
157            SkIRect cropRect, sk_sp<SkPicture> postProcess);
158
159    int computeNextFrame(int current, bool* animationEnded);
160    double finish();
161
162    /**
163     *  True if there is no crop, orientation, or post decoding scaling.
164     */
165    bool simple() const { return fMatrix.isIdentity() && !fPostProcess
166                                 && fCropRect == fDecodeInfo.bounds(); }
167
168    /**
169     *  Returns the current frame as an SkImage.
170     *
171     *  Like getCurrentFrame, but only returns the raw data from the internal SkBitmap. (i.e. no
172     *  scaling, orientation-correction or cropping.) If simple(), this is the final output.
173     */
174    sk_sp<SkImage> getCurrentFrameSimple();
175
176    using INHERITED = SkDrawable;
177};
178
179#endif // SkAnimatedImage_DEFINED
180