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