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