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 #include "SkAndroidCodec.h"
9 #include "SkAnimatedImage.h"
10 #include "SkCanvas.h"
11 #include "SkCodec.h"
12 #include "SkCodecPriv.h"
13 #include "SkPicture.h"
14 #include "SkPictureRecorder.h"
15 
Make(std::unique_ptr<SkAndroidCodec> codec,SkISize scaledSize,SkIRect cropRect,sk_sp<SkPicture> postProcess)16 sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec,
17         SkISize scaledSize, SkIRect cropRect, sk_sp<SkPicture> postProcess) {
18     if (!codec) {
19         return nullptr;
20     }
21 
22     SkISize decodeSize = scaledSize;
23     auto decodeInfo = codec->getInfo();
24     if (codec->getEncodedFormat() == SkEncodedImageFormat::kWEBP
25             && scaledSize.width()  < decodeInfo.width()
26             && scaledSize.height() < decodeInfo.height()) {
27         // libwebp can decode to arbitrary smaller sizes.
28         decodeInfo = decodeInfo.makeWH(decodeSize.width(), decodeSize.height());
29     }
30 
31     auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
32                 decodeInfo, cropRect, std::move(postProcess)));
33     if (!image->fActiveFrame.fBitmap.getPixels()) {
34         // tryAllocPixels failed.
35         return nullptr;
36     }
37 
38     return image;
39 }
40 
Make(std::unique_ptr<SkAndroidCodec> codec)41 sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec) {
42     if (!codec) {
43         return nullptr;
44     }
45 
46     const auto decodeInfo = codec->getInfo();
47     const auto scaledSize = decodeInfo.dimensions();
48     const auto cropRect   = SkIRect::MakeSize(scaledSize);
49     auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
50                 decodeInfo, cropRect, nullptr));
51 
52     if (!image->fActiveFrame.fBitmap.getPixels()) {
53         // tryAllocPixels failed.
54         return nullptr;
55     }
56 
57     SkASSERT(image->fSimple);
58     return image;
59 }
60 
SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec,SkISize scaledSize,SkImageInfo decodeInfo,SkIRect cropRect,sk_sp<SkPicture> postProcess)61 SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize,
62         SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess)
63     : fCodec(std::move(codec))
64     , fScaledSize(scaledSize)
65     , fDecodeInfo(decodeInfo)
66     , fCropRect(cropRect)
67     , fPostProcess(std::move(postProcess))
68     , fFrameCount(fCodec->codec()->getFrameCount())
69     , fSimple(fScaledSize == fDecodeInfo.dimensions() && !fPostProcess
70               && fCropRect == fDecodeInfo.bounds())
71     , fFinished(false)
72     , fRepetitionCount(fCodec->codec()->getRepetitionCount())
73     , fRepetitionsCompleted(0)
74 {
75     if (!fActiveFrame.fBitmap.tryAllocPixels(fDecodeInfo)) {
76         return;
77     }
78 
79     if (!fSimple) {
80         fMatrix = SkMatrix::MakeTrans(-fCropRect.fLeft, -fCropRect.fTop);
81         float scaleX = (float) fScaledSize.width()  / fDecodeInfo.width();
82         float scaleY = (float) fScaledSize.height() / fDecodeInfo.height();
83         fMatrix.preConcat(SkMatrix::MakeScale(scaleX, scaleY));
84     }
85     this->decodeNextFrame();
86 }
87 
~SkAnimatedImage()88 SkAnimatedImage::~SkAnimatedImage() { }
89 
onGetBounds()90 SkRect SkAnimatedImage::onGetBounds() {
91     return SkRect::MakeIWH(fCropRect.width(), fCropRect.height());
92 }
93 
Frame()94 SkAnimatedImage::Frame::Frame()
95     : fIndex(SkCodec::kNone)
96 {}
97 
copyTo(Frame * dst) const98 bool SkAnimatedImage::Frame::copyTo(Frame* dst) const {
99     if (dst->fBitmap.getPixels()) {
100         dst->fBitmap.setAlphaType(fBitmap.alphaType());
101     } else if (!dst->fBitmap.tryAllocPixels(fBitmap.info())) {
102         return false;
103     }
104 
105     memcpy(dst->fBitmap.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
106     dst->fIndex = fIndex;
107     dst->fDisposalMethod = fDisposalMethod;
108     return true;
109 }
110 
reset()111 void SkAnimatedImage::reset() {
112     fFinished = false;
113     fRepetitionsCompleted = 0;
114     if (fActiveFrame.fIndex == 0) {
115         // Already showing the first frame.
116         return;
117     }
118 
119     if (fRestoreFrame.fIndex == 0) {
120         SkTSwap(fActiveFrame, fRestoreFrame);
121         // Now we're showing the first frame.
122         return;
123     }
124 
125     fActiveFrame.fIndex = SkCodec::kNone;
126     this->decodeNextFrame();
127 }
128 
is_restore_previous(SkCodecAnimation::DisposalMethod dispose)129 static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) {
130     return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose;
131 }
132 
computeNextFrame(int current,bool * animationEnded)133 int SkAnimatedImage::computeNextFrame(int current, bool* animationEnded) {
134     SkASSERT(animationEnded != nullptr);
135     *animationEnded = false;
136 
137     const int frameToDecode = current + 1;
138     if (frameToDecode == fFrameCount - 1) {
139         // Final frame. Check to determine whether to stop.
140         fRepetitionsCompleted++;
141         if (fRepetitionCount != SkCodec::kRepetitionCountInfinite
142                 && fRepetitionsCompleted > fRepetitionCount) {
143             *animationEnded = true;
144         }
145     } else if (frameToDecode == fFrameCount) {
146         return 0;
147     }
148     return frameToDecode;
149 }
150 
finish()151 double SkAnimatedImage::finish() {
152     fFinished = true;
153     fCurrentFrameDuration = kFinished;
154     return kFinished;
155 }
156 
decodeNextFrame()157 int SkAnimatedImage::decodeNextFrame() {
158     if (fFinished) {
159         return kFinished;
160     }
161 
162     bool animationEnded = false;
163     int frameToDecode = this->computeNextFrame(fActiveFrame.fIndex, &animationEnded);
164 
165     SkCodec::FrameInfo frameInfo;
166     if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
167         if (!frameInfo.fFullyReceived) {
168             SkCodecPrintf("Frame %i not fully received\n", frameToDecode);
169             return this->finish();
170         }
171 
172         fCurrentFrameDuration = frameInfo.fDuration;
173     } else {
174         animationEnded = true;
175         if (0 == frameToDecode) {
176             // Static image. This is okay.
177             frameInfo.fRequiredFrame = SkCodec::kNone;
178             frameInfo.fAlphaType = fCodec->getInfo().alphaType();
179             // These fields won't be read.
180             frameInfo.fDuration = INT_MAX;
181             frameInfo.fFullyReceived = true;
182             fCurrentFrameDuration = kFinished;
183         } else {
184             SkCodecPrintf("Error getting frameInfo for frame %i\n",
185                           frameToDecode);
186             return this->finish();
187         }
188     }
189 
190     if (frameToDecode == fActiveFrame.fIndex) {
191         if (animationEnded) {
192             return this->finish();
193         }
194         return fCurrentFrameDuration;
195     }
196 
197     if (frameToDecode == fRestoreFrame.fIndex) {
198         SkTSwap(fActiveFrame, fRestoreFrame);
199         if (animationEnded) {
200             return this->finish();
201         }
202         return fCurrentFrameDuration;
203     }
204 
205     // The following code makes an effort to avoid overwriting a frame that will
206     // be used again. If frame |i| is_restore_previous, frame |i+1| will not
207     // depend on frame |i|, so do not overwrite frame |i-1|, which may be needed
208     // for frame |i+1|.
209     // We could be even smarter about which frames to save by looking at the
210     // entire dependency chain.
211     SkCodec::Options options;
212     options.fFrameIndex = frameToDecode;
213     if (frameInfo.fRequiredFrame == SkCodec::kNone) {
214         if (is_restore_previous(frameInfo.fDisposalMethod)) {
215             // frameToDecode will be discarded immediately after drawing, so
216             // do not overwrite a frame which could possibly be used in the
217             // future.
218             if (fActiveFrame.fIndex != SkCodec::kNone &&
219                     !is_restore_previous(fActiveFrame.fDisposalMethod)) {
220                 SkTSwap(fActiveFrame, fRestoreFrame);
221             }
222         }
223     } else {
224         auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) {
225             if (SkCodec::kNone == frame.fIndex || is_restore_previous(frame.fDisposalMethod)) {
226                 return false;
227             }
228 
229             return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode;
230         };
231         if (validPriorFrame(fActiveFrame)) {
232             if (is_restore_previous(frameInfo.fDisposalMethod)) {
233                 // fActiveFrame is a good frame to use for this one, but we
234                 // don't want to overwrite it.
235                 fActiveFrame.copyTo(&fRestoreFrame);
236             }
237             options.fPriorFrame = fActiveFrame.fIndex;
238         } else if (validPriorFrame(fRestoreFrame)) {
239             if (!is_restore_previous(frameInfo.fDisposalMethod)) {
240                 SkTSwap(fActiveFrame, fRestoreFrame);
241             } else if (!fRestoreFrame.copyTo(&fActiveFrame)) {
242                 SkCodecPrintf("Failed to restore frame\n");
243                 return this->finish();
244             }
245             options.fPriorFrame = fActiveFrame.fIndex;
246         }
247     }
248 
249     auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ?
250                      kOpaque_SkAlphaType : kPremul_SkAlphaType;
251     SkBitmap* dst = &fActiveFrame.fBitmap;
252     if (dst->getPixels()) {
253         SkAssertResult(dst->setAlphaType(alphaType));
254     } else {
255         auto info = fDecodeInfo.makeAlphaType(alphaType);
256         if (!dst->tryAllocPixels(info)) {
257             return this->finish();
258         }
259     }
260 
261     auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(),
262                                              &options);
263     if (result != SkCodec::kSuccess) {
264         SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount);
265         return this->finish();
266     }
267 
268     fActiveFrame.fIndex = frameToDecode;
269     fActiveFrame.fDisposalMethod = frameInfo.fDisposalMethod;
270 
271     if (animationEnded) {
272         return this->finish();
273     }
274     return fCurrentFrameDuration;
275 }
276 
onDraw(SkCanvas * canvas)277 void SkAnimatedImage::onDraw(SkCanvas* canvas) {
278     if (fSimple) {
279         canvas->drawBitmap(fActiveFrame.fBitmap, 0, 0);
280         return;
281     }
282 
283     SkRect bounds = this->getBounds();
284     if (fPostProcess) {
285         canvas->saveLayer(&bounds, nullptr);
286     }
287     {
288         SkAutoCanvasRestore acr(canvas, fPostProcess);
289         canvas->concat(fMatrix);
290         SkPaint paint;
291         paint.setBlendMode(SkBlendMode::kSrc);
292         paint.setFilterQuality(kLow_SkFilterQuality);
293         canvas->drawBitmap(fActiveFrame.fBitmap, 0, 0, &paint);
294     }
295     if (fPostProcess) {
296         canvas->drawPicture(fPostProcess);
297         canvas->restore();
298     }
299 }
300 
setRepetitionCount(int newCount)301 void SkAnimatedImage::setRepetitionCount(int newCount) {
302     fRepetitionCount = newCount;
303 }
304