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