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