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