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