blob: 5c35db80d5e98ce577316443bcb09b9331bcfbb7 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#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"
Leon Scroggins7d1153f2020-11-06 17:05:36 -050017#include "src/core/SkPixmapPriv.h"
Leon Scroggins III7a10b332018-01-12 11:24:30 -050018
Ben Wagner0b9b1f12019-04-04 18:00:05 -040019#include <limits.h>
Ben Wagnerf08d1d02018-06-18 15:11:00 -040020#include <utility>
21
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050022sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec,
Leon Scroggins III85463352019-02-04 15:22:10 -050023 const SkImageInfo& requestedInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess) {
24 if (!codec) {
25 return nullptr;
26 }
27
Leon Scrogginsafdbd9d2020-11-06 11:07:37 -050028 if (!requestedInfo.bounds().contains(cropRect)) {
29 return nullptr;
30 }
31
Leon Scroggins III85463352019-02-04 15:22:10 -050032 auto scaledSize = requestedInfo.dimensions();
33 auto decodeInfo = requestedInfo;
34 if (codec->getEncodedFormat() != SkEncodedImageFormat::kWEBP
35 || scaledSize.width() >= decodeInfo.width()
36 || scaledSize.height() >= decodeInfo.height()) {
37 // Only libwebp can decode to arbitrary smaller sizes.
38 auto dims = codec->getInfo().dimensions();
Brian Salomon9241a6d2019-10-03 13:26:54 -040039 decodeInfo = decodeInfo.makeDimensions(dims);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050040 }
41
42 auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
43 decodeInfo, cropRect, std::move(postProcess)));
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040044 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050045 // tryAllocPixels failed.
46 return nullptr;
47 }
48
49 return image;
50}
51
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050052sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec) {
53 if (!codec) {
54 return nullptr;
55 }
56
57 const auto decodeInfo = codec->getInfo();
58 const auto scaledSize = decodeInfo.dimensions();
59 const auto cropRect = SkIRect::MakeSize(scaledSize);
60 auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize,
61 decodeInfo, cropRect, nullptr));
62
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040063 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050064 // tryAllocPixels failed.
65 return nullptr;
66 }
67
Leon Scroggins7d1153f2020-11-06 17:05:36 -050068 SkASSERT(image->simple());
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050069 return image;
70}
71
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050072SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize,
73 SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050074 : fCodec(std::move(codec))
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050075 , fDecodeInfo(decodeInfo)
76 , fCropRect(cropRect)
77 , fPostProcess(std::move(postProcess))
Leon Scroggins III4c119452018-01-20 10:33:24 -050078 , fFrameCount(fCodec->codec()->getFrameCount())
Leon Scroggins III7a10b332018-01-12 11:24:30 -050079 , fFinished(false)
Leon Scroggins III4c119452018-01-20 10:33:24 -050080 , fRepetitionCount(fCodec->codec()->getRepetitionCount())
81 , fRepetitionsCompleted(0)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050082{
Leon Scroggins7d1153f2020-11-06 17:05:36 -050083 // For simplicity in decoding and compositing frames, decode directly to a size and
84 // orientation that fCodec can do directly, and then use fMatrix to handle crop (along with a
85 // clip), orientation, and scaling outside of fCodec. The matrices are computed individually
86 // and applied in the following order:
87 // [crop] X [origin] X [scale]
88 const auto origin = fCodec->codec()->getOrigin();
89 if (fCodec->fOrientationBehavior == SkAndroidCodec::ExifOrientationBehavior::kRespect
90 && origin != SkEncodedOrigin::kDefault_SkEncodedOrigin) {
91 // The origin is applied after scaling, so use scaledSize, which is the final scaled size.
92 fMatrix = SkEncodedOriginToMatrix(origin, scaledSize.width(), scaledSize.height());
93
94 fCodec = SkAndroidCodec::MakeFromCodec(std::move(fCodec->fCodec),
95 SkAndroidCodec::ExifOrientationBehavior::kIgnore);
96 if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
97 // The client asked for sizes post-rotation. Swap back to the pre-rotation sizes to pass
98 // to fCodec and for the scale matrix computation.
99 fDecodeInfo = SkPixmapPriv::SwapWidthHeight(fDecodeInfo);
100 scaledSize = { scaledSize.height(), scaledSize.width() };
101 }
102 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400103 if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500104 return;
105 }
106
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500107 if (scaledSize != fDecodeInfo.dimensions()) {
108 float scaleX = (float) scaledSize.width() / fDecodeInfo.width();
109 float scaleY = (float) scaledSize.height() / fDecodeInfo.height();
Mike Reed1f607332020-05-21 12:11:27 -0400110 fMatrix.preConcat(SkMatrix::Scale(scaleX, scaleY));
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500111 }
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500112 fMatrix.postConcat(SkMatrix::Translate(-fCropRect.fLeft, -fCropRect.fTop));
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500113 this->decodeNextFrame();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500114}
115
116SkAnimatedImage::~SkAnimatedImage() { }
117
118SkRect SkAnimatedImage::onGetBounds() {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500119 return SkRect::MakeIWH(fCropRect.width(), fCropRect.height());
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500120}
121
122SkAnimatedImage::Frame::Frame()
Nigel Tao66bc5242018-08-22 10:56:03 +1000123 : fIndex(SkCodec::kNoFrame)
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500124{}
125
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400126bool SkAnimatedImage::Frame::init(const SkImageInfo& info, OnInit onInit) {
127 if (fBitmap.getPixels()) {
128 if (fBitmap.pixelRef()->unique()) {
129 SkAssertResult(fBitmap.setAlphaType(info.alphaType()));
130 return true;
131 }
132
133 // An SkCanvas provided to onDraw is still holding a reference.
134 // Copy before we decode to ensure that we don't overwrite the
135 // expected contents of the image.
136 if (OnInit::kRestoreIfNecessary == onInit) {
137 SkBitmap tmp;
138 if (!tmp.tryAllocPixels(info)) {
139 return false;
140 }
141
142 memcpy(tmp.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400143 using std::swap;
144 swap(tmp, fBitmap);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400145 return true;
146 }
147 }
148
149 return fBitmap.tryAllocPixels(info);
150}
151
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500152bool SkAnimatedImage::Frame::copyTo(Frame* dst) const {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400153 if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500154 return false;
155 }
156
157 memcpy(dst->fBitmap.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
158 dst->fIndex = fIndex;
159 dst->fDisposalMethod = fDisposalMethod;
160 return true;
161}
162
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500163void SkAnimatedImage::reset() {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500164 fFinished = false;
165 fRepetitionsCompleted = 0;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400166 if (fDisplayFrame.fIndex != 0) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000167 fDisplayFrame.fIndex = SkCodec::kNoFrame;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400168 this->decodeNextFrame();
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500169 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500170}
171
172static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) {
173 return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose;
174}
175
Leon Scroggins III4c119452018-01-20 10:33:24 -0500176int SkAnimatedImage::computeNextFrame(int current, bool* animationEnded) {
177 SkASSERT(animationEnded != nullptr);
178 *animationEnded = false;
179
180 const int frameToDecode = current + 1;
181 if (frameToDecode == fFrameCount - 1) {
182 // Final frame. Check to determine whether to stop.
183 fRepetitionsCompleted++;
184 if (fRepetitionCount != SkCodec::kRepetitionCountInfinite
185 && fRepetitionsCompleted > fRepetitionCount) {
186 *animationEnded = true;
187 }
188 } else if (frameToDecode == fFrameCount) {
189 return 0;
190 }
191 return frameToDecode;
192}
193
194double SkAnimatedImage::finish() {
195 fFinished = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500196 fCurrentFrameDuration = kFinished;
197 return kFinished;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500198}
199
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500200int SkAnimatedImage::decodeNextFrame() {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500201 if (fFinished) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500202 return kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500203 }
204
Leon Scroggins III4c119452018-01-20 10:33:24 -0500205 bool animationEnded = false;
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400206 const int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500207
208 SkCodec::FrameInfo frameInfo;
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500209 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500210 if (!frameInfo.fFullyReceived) {
211 SkCodecPrintf("Frame %i not fully received\n", frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500212 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500213 }
214
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500215 fCurrentFrameDuration = frameInfo.fDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500216 } else {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500217 animationEnded = true;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500218 if (0 == frameToDecode) {
219 // Static image. This is okay.
Nigel Tao66bc5242018-08-22 10:56:03 +1000220 frameInfo.fRequiredFrame = SkCodec::kNoFrame;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500221 frameInfo.fAlphaType = fCodec->getInfo().alphaType();
Kevin Lubick289d36f2018-02-13 10:25:00 -0500222 frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500223 // These fields won't be read.
224 frameInfo.fDuration = INT_MAX;
225 frameInfo.fFullyReceived = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500226 fCurrentFrameDuration = kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500227 } else {
228 SkCodecPrintf("Error getting frameInfo for frame %i\n",
229 frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500230 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500231 }
232 }
233
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400234 if (frameToDecode == fDisplayFrame.fIndex) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500235 if (animationEnded) {
236 return this->finish();
237 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500238 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500239 }
240
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400241 for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) {
242 if (frameToDecode == frame->fIndex) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400243 using std::swap;
244 swap(fDisplayFrame, *frame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400245 if (animationEnded) {
246 return this->finish();
247 }
248 return fCurrentFrameDuration;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500249 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500250 }
251
252 // The following code makes an effort to avoid overwriting a frame that will
253 // be used again. If frame |i| is_restore_previous, frame |i+1| will not
254 // depend on frame |i|, so do not overwrite frame |i-1|, which may be needed
255 // for frame |i+1|.
256 // We could be even smarter about which frames to save by looking at the
257 // entire dependency chain.
258 SkCodec::Options options;
259 options.fFrameIndex = frameToDecode;
Nigel Tao66bc5242018-08-22 10:56:03 +1000260 if (frameInfo.fRequiredFrame == SkCodec::kNoFrame) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500261 if (is_restore_previous(frameInfo.fDisposalMethod)) {
262 // frameToDecode will be discarded immediately after drawing, so
263 // do not overwrite a frame which could possibly be used in the
264 // future.
Nigel Tao66bc5242018-08-22 10:56:03 +1000265 if (fDecodingFrame.fIndex != SkCodec::kNoFrame &&
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400266 !is_restore_previous(fDecodingFrame.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400267 using std::swap;
268 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500269 }
270 }
271 } else {
272 auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000273 if (SkCodec::kNoFrame == frame.fIndex ||
274 is_restore_previous(frame.fDisposalMethod)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500275 return false;
276 }
277
278 return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode;
279 };
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400280 if (validPriorFrame(fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500281 if (is_restore_previous(frameInfo.fDisposalMethod)) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400282 // fDecodingFrame is a good frame to use for this one, but we
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500283 // don't want to overwrite it.
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400284 fDecodingFrame.copyTo(&fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500285 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400286 options.fPriorFrame = fDecodingFrame.fIndex;
287 } else if (validPriorFrame(fDisplayFrame)) {
288 if (!fDisplayFrame.copyTo(&fDecodingFrame)) {
289 SkCodecPrintf("Failed to allocate pixels for frame\n");
290 return this->finish();
291 }
292 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500293 } else if (validPriorFrame(fRestoreFrame)) {
294 if (!is_restore_previous(frameInfo.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400295 using std::swap;
296 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400297 } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500298 SkCodecPrintf("Failed to restore frame\n");
Leon Scroggins III4c119452018-01-20 10:33:24 -0500299 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500300 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400301 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500302 }
303 }
304
305 auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ?
306 kOpaque_SkAlphaType : kPremul_SkAlphaType;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400307 auto info = fDecodeInfo.makeAlphaType(alphaType);
308 SkBitmap* dst = &fDecodingFrame.fBitmap;
309 if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) {
310 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500311 }
312
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500313 auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(),
314 &options);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500315 if (result != SkCodec::kSuccess) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500316 SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount);
317 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500318 }
319
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400320 fDecodingFrame.fIndex = frameToDecode;
321 fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod;
322
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400323 using std::swap;
324 swap(fDecodingFrame, fDisplayFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400325 fDisplayFrame.fBitmap.notifyPixelsChanged();
Leon Scroggins III4c119452018-01-20 10:33:24 -0500326
327 if (animationEnded) {
328 return this->finish();
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400329 } else if (fCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF) {
330 // HEIF doesn't know the frame duration until after decoding. Update to
331 // the correct value. Note that earlier returns in this method either
332 // return kFinished, or fCurrentFrameDuration. If they return the
333 // latter, it is a frame that was previously decoded, so it has the
334 // updated value.
335 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
336 fCurrentFrameDuration = frameInfo.fDuration;
337 } else {
338 SkCodecPrintf("Failed to getFrameInfo on second attempt (HEIF)");
339 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500340 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500341 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500342}
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500343
344void SkAnimatedImage::onDraw(SkCanvas* canvas) {
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500345 auto image = this->getCurrentFrameSimple();
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400346
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500347 if (this->simple()) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400348 canvas->drawImage(image, 0, 0);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500349 return;
350 }
351
352 SkRect bounds = this->getBounds();
353 if (fPostProcess) {
354 canvas->saveLayer(&bounds, nullptr);
355 }
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500356 canvas->clipRect(bounds);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500357 {
Ben Wagner5d1adbf2018-05-28 13:35:39 -0400358 SkAutoCanvasRestore acr(canvas, fPostProcess != nullptr);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500359 canvas->concat(fMatrix);
360 SkPaint paint;
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500361 paint.setFilterQuality(kLow_SkFilterQuality);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400362 canvas->drawImage(image, 0, 0, &paint);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500363 }
364 if (fPostProcess) {
365 canvas->drawPicture(fPostProcess);
366 canvas->restore();
367 }
368}
Leon Scroggins III4c119452018-01-20 10:33:24 -0500369
370void SkAnimatedImage::setRepetitionCount(int newCount) {
371 fRepetitionCount = newCount;
372}
Kevin Lubickf5bc8fb2020-01-08 13:29:31 -0500373
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500374sk_sp<SkImage> SkAnimatedImage::getCurrentFrameSimple() {
Kevin Lubickf5bc8fb2020-01-08 13:29:31 -0500375 // This SkBitmap may be reused later to decode the following frame. But Frame::init
376 // lazily copies the pixel ref if it has any other references. So it is safe to not
377 // do a deep copy here.
378 return SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap,
379 kNever_SkCopyPixelsMode);
380}
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500381
382sk_sp<SkImage> SkAnimatedImage::getCurrentFrame() {
383 if (this->simple()) return this->getCurrentFrameSimple();
384
385 auto imageInfo = fDisplayFrame.fBitmap.info().makeDimensions(fCropRect.size());
386 if (fPostProcess) {
387 // Defensively use premul in case the post process adds alpha.
388 imageInfo = imageInfo.makeAlphaType(kPremul_SkAlphaType);
389 }
390
391 SkBitmap dst;
392 if (!dst.tryAllocPixels(imageInfo)) {
393 return nullptr;
394 }
395
396 SkCanvas canvas(dst);
397 this->draw(&canvas);
398 return SkMakeImageFromRasterBitmap(dst, kNever_SkCopyPixelsMode);
399}