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