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