blob: d03040c52a04b9bcc2d5d398b108ef20ed439a79 [file] [log] [blame]
Leon Scroggins III7a10b332018-01-12 11:24:30 -05001/*
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
Leon Scroggins III42ee2842018-01-14 14:46:51 -05008#include "SkAndroidCodec.h"
Leon Scroggins III7a10b332018-01-12 11:24:30 -05009#include "SkAnimatedImage.h"
10#include "SkCanvas.h"
11#include "SkCodec.h"
12#include "SkCodecPriv.h"
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040013#include "SkImagePriv.h"
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050014#include "SkPicture.h"
15#include "SkPictureRecorder.h"
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040016#include "SkPixelRef.h"
Leon Scroggins III7a10b332018-01-12 11:24:30 -050017
Ben Wagnerf08d1d02018-06-18 15:11:00 -040018#include <utility>
19
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050020sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec,
21 SkISize scaledSize, SkIRect cropRect, sk_sp<SkPicture> postProcess) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050022 if (!codec) {
23 return nullptr;
24 }
25
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050026 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)));
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040037 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050038 // tryAllocPixels failed.
39 return nullptr;
40 }
41
42 return image;
43}
44
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050045sk_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
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040056 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050057 // tryAllocPixels failed.
58 return nullptr;
59 }
60
61 SkASSERT(image->fSimple);
62 return image;
63}
64
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050065SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize,
66 SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050067 : fCodec(std::move(codec))
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050068 , fScaledSize(scaledSize)
69 , fDecodeInfo(decodeInfo)
70 , fCropRect(cropRect)
71 , fPostProcess(std::move(postProcess))
Leon Scroggins III4c119452018-01-20 10:33:24 -050072 , fFrameCount(fCodec->codec()->getFrameCount())
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050073 , fSimple(fScaledSize == fDecodeInfo.dimensions() && !fPostProcess
74 && fCropRect == fDecodeInfo.bounds())
Leon Scroggins III7a10b332018-01-12 11:24:30 -050075 , fFinished(false)
Leon Scroggins III4c119452018-01-20 10:33:24 -050076 , fRepetitionCount(fCodec->codec()->getRepetitionCount())
77 , fRepetitionsCompleted(0)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050078{
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040079 if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050080 return;
81 }
82
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050083 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 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -050089 this->decodeNextFrame();
Leon Scroggins III7a10b332018-01-12 11:24:30 -050090}
91
92SkAnimatedImage::~SkAnimatedImage() { }
93
94SkRect SkAnimatedImage::onGetBounds() {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050095 return SkRect::MakeIWH(fCropRect.width(), fCropRect.height());
Leon Scroggins III7a10b332018-01-12 11:24:30 -050096}
97
98SkAnimatedImage::Frame::Frame()
Nigel Tao66bc5242018-08-22 10:56:03 +100099 : fIndex(SkCodec::kNoFrame)
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500100{}
101
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400102bool 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());
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400119 using std::swap;
120 swap(tmp, fBitmap);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400121 return true;
122 }
123 }
124
125 return fBitmap.tryAllocPixels(info);
126}
127
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500128bool SkAnimatedImage::Frame::copyTo(Frame* dst) const {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400129 if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500130 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
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500139void SkAnimatedImage::reset() {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500140 fFinished = false;
141 fRepetitionsCompleted = 0;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400142 if (fDisplayFrame.fIndex != 0) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000143 fDisplayFrame.fIndex = SkCodec::kNoFrame;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400144 this->decodeNextFrame();
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500145 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500146}
147
148static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) {
149 return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose;
150}
151
Leon Scroggins III4c119452018-01-20 10:33:24 -0500152int 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
170double SkAnimatedImage::finish() {
171 fFinished = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500172 fCurrentFrameDuration = kFinished;
173 return kFinished;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500174}
175
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500176int SkAnimatedImage::decodeNextFrame() {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500177 if (fFinished) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500178 return kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500179 }
180
Leon Scroggins III4c119452018-01-20 10:33:24 -0500181 bool animationEnded = false;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400182 int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500183
184 SkCodec::FrameInfo frameInfo;
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500185 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500186 if (!frameInfo.fFullyReceived) {
187 SkCodecPrintf("Frame %i not fully received\n", frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500188 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500189 }
190
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500191 fCurrentFrameDuration = frameInfo.fDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500192 } else {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500193 animationEnded = true;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500194 if (0 == frameToDecode) {
195 // Static image. This is okay.
Nigel Tao66bc5242018-08-22 10:56:03 +1000196 frameInfo.fRequiredFrame = SkCodec::kNoFrame;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500197 frameInfo.fAlphaType = fCodec->getInfo().alphaType();
Kevin Lubick289d36f2018-02-13 10:25:00 -0500198 frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500199 // These fields won't be read.
200 frameInfo.fDuration = INT_MAX;
201 frameInfo.fFullyReceived = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500202 fCurrentFrameDuration = kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500203 } else {
204 SkCodecPrintf("Error getting frameInfo for frame %i\n",
205 frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500206 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500207 }
208 }
209
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400210 if (frameToDecode == fDisplayFrame.fIndex) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500211 if (animationEnded) {
212 return this->finish();
213 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500214 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500215 }
216
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400217 for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) {
218 if (frameToDecode == frame->fIndex) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400219 using std::swap;
220 swap(fDisplayFrame, *frame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400221 if (animationEnded) {
222 return this->finish();
223 }
224 return fCurrentFrameDuration;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500225 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500226 }
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;
Nigel Tao66bc5242018-08-22 10:56:03 +1000236 if (frameInfo.fRequiredFrame == SkCodec::kNoFrame) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500237 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.
Nigel Tao66bc5242018-08-22 10:56:03 +1000241 if (fDecodingFrame.fIndex != SkCodec::kNoFrame &&
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400242 !is_restore_previous(fDecodingFrame.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400243 using std::swap;
244 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500245 }
246 }
247 } else {
248 auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000249 if (SkCodec::kNoFrame == frame.fIndex ||
250 is_restore_previous(frame.fDisposalMethod)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500251 return false;
252 }
253
254 return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode;
255 };
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400256 if (validPriorFrame(fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500257 if (is_restore_previous(frameInfo.fDisposalMethod)) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400258 // fDecodingFrame is a good frame to use for this one, but we
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500259 // don't want to overwrite it.
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400260 fDecodingFrame.copyTo(&fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500261 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400262 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;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500269 } else if (validPriorFrame(fRestoreFrame)) {
270 if (!is_restore_previous(frameInfo.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400271 using std::swap;
272 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400273 } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500274 SkCodecPrintf("Failed to restore frame\n");
Leon Scroggins III4c119452018-01-20 10:33:24 -0500275 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500276 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400277 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500278 }
279 }
280
281 auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ?
282 kOpaque_SkAlphaType : kPremul_SkAlphaType;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400283 auto info = fDecodeInfo.makeAlphaType(alphaType);
284 SkBitmap* dst = &fDecodingFrame.fBitmap;
285 if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) {
286 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500287 }
288
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500289 auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(),
290 &options);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500291 if (result != SkCodec::kSuccess) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500292 SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount);
293 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500294 }
295
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400296 fDecodingFrame.fIndex = frameToDecode;
297 fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod;
298
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400299 using std::swap;
300 swap(fDecodingFrame, fDisplayFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400301 fDisplayFrame.fBitmap.notifyPixelsChanged();
Leon Scroggins III4c119452018-01-20 10:33:24 -0500302
303 if (animationEnded) {
304 return this->finish();
305 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500306 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500307}
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500308
309void SkAnimatedImage::onDraw(SkCanvas* canvas) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400310 auto image = SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap,
311 kNever_SkCopyPixelsMode);
312
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500313 if (fSimple) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400314 canvas->drawImage(image, 0, 0);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500315 return;
316 }
317
318 SkRect bounds = this->getBounds();
319 if (fPostProcess) {
320 canvas->saveLayer(&bounds, nullptr);
321 }
322 {
Ben Wagner5d1adbf2018-05-28 13:35:39 -0400323 SkAutoCanvasRestore acr(canvas, fPostProcess != nullptr);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500324 canvas->concat(fMatrix);
325 SkPaint paint;
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500326 paint.setFilterQuality(kLow_SkFilterQuality);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400327 canvas->drawImage(image, 0, 0, &paint);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500328 }
329 if (fPostProcess) {
330 canvas->drawPicture(fPostProcess);
331 canvas->restore();
332 }
333}
Leon Scroggins III4c119452018-01-20 10:33:24 -0500334
335void SkAnimatedImage::setRepetitionCount(int newCount) {
336 fRepetitionCount = newCount;
337}