xref: /aosp_15_r20/external/skia/include/android/SkAnimatedImage.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
17 class SkAndroidCodec;
18 class SkImage;
19 class SkPicture;
20 
21 /**
22  *  Thread unsafe drawable for drawing animated images (e.g. GIF).
23  */
24 class SK_API SkAnimatedImage : public SkDrawable {
25 public:
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      */
isFinished()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      */
currentFrameDuration()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      */
getRepetitionCount()104     int getRepetitionCount() const {
105         return fRepetitionCount;
106     }
107 
108     /**
109      *  Return the total number of frames in the animation.
110      */
getFrameCount()111     int getFrameCount() const { return fFrameCount; }
112 
113     /**
114      *  Change the filter mode.
115      *
116      *  By default, the image will apply bilinear filtering when drawing in the
117      *  OnDraw method.
118      */
119     void setFilterMode(SkFilterMode filterMode);
120 
121     /**
122      *  Return the filter mode used for sampling when drawing.
123      */
getFilterMode()124     SkFilterMode getFilterMode() const { return fFilterMode; }
125 
126 protected:
127     SkRect onGetBounds() override;
128     void onDraw(SkCanvas*) override;
129 
130 private:
131     struct Frame {
132         SkBitmap fBitmap;
133         int      fIndex;
134         SkCodecAnimation::DisposalMethod fDisposalMethod;
135 
136         // init() may have to create a new SkPixelRef, if the
137         // current one is already in use by another owner (e.g.
138         // an SkPicture). This determines whether to copy the
139         // existing one to the new one.
140         enum class OnInit {
141             // Restore the image from the old SkPixelRef to the
142             // new one.
143             kRestoreIfNecessary,
144             // No need to restore.
145             kNoRestore,
146         };
147 
148         Frame();
149         bool init(const SkImageInfo& info, OnInit);
150         bool copyTo(Frame*) const;
151     };
152 
153     std::unique_ptr<SkAndroidCodec> fCodec;
154           SkImageInfo               fDecodeInfo;
155     const SkIRect                   fCropRect;
156     const sk_sp<SkPicture>          fPostProcess;
157     const int                       fFrameCount;
158     SkMatrix                        fMatrix;
159     int                             fSampleSize;
160 
161     bool                            fFinished;
162     int                             fCurrentFrameDuration;
163     Frame                           fDisplayFrame;
164     Frame                           fDecodingFrame;
165     Frame                           fRestoreFrame;
166     int                             fRepetitionCount;
167     int                             fRepetitionsCompleted;
168     SkFilterMode                    fFilterMode = SkFilterMode::kLinear;
169 
170     SkAnimatedImage(std::unique_ptr<SkAndroidCodec>, const SkImageInfo& requestedInfo,
171             SkIRect cropRect, sk_sp<SkPicture> postProcess);
172 
173     int computeNextFrame(int current, bool* animationEnded);
174     double finish();
175 
176     /**
177      *  True if there is no crop, orientation, or post decoding scaling.
178      */
simple()179     bool simple() const { return fMatrix.isIdentity() && !fPostProcess
180                                  && fCropRect == fDecodeInfo.bounds(); }
181 
182     /**
183      *  Returns the current frame as an SkImage.
184      *
185      *  Like getCurrentFrame, but only returns the raw data from the internal SkBitmap. (i.e. no
186      *  scaling, orientation-correction or cropping.) If simple(), this is the final output.
187      */
188     sk_sp<SkImage> getCurrentFrameSimple();
189 
190     using INHERITED = SkDrawable;
191 };
192 
193 #endif // SkAnimatedImage_DEFINED
194