blob: 60015ea1bfdf7f53c404f346323a726c979b98f4 [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 Scrogginsda3d8c22020-11-09 16:00:53 -050032 auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), requestedInfo,
33 cropRect, std::move(postProcess)));
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040034 if (!image->fDisplayFrame.fBitmap.getPixels()) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050035 // tryAllocPixels failed.
36 return nullptr;
37 }
38
39 return image;
40}
41
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050042sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec) {
43 if (!codec) {
44 return nullptr;
45 }
46
Leon Scrogginsda3d8c22020-11-09 16:00:53 -050047 const auto& decodeInfo = codec->getInfo();
48 const auto cropRect = SkIRect::MakeSize(decodeInfo.dimensions());
49 auto image = Make(std::move(codec), decodeInfo, cropRect, nullptr);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050050
Leon Scrogginsda3d8c22020-11-09 16:00:53 -050051 SkASSERT(!image || image->simple());
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050052 return image;
53}
54
Leon Scrogginsda3d8c22020-11-09 16:00:53 -050055SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec,
56 const SkImageInfo& requestedInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050057 : fCodec(std::move(codec))
Leon Scrogginsda3d8c22020-11-09 16:00:53 -050058 , fDecodeInfo(requestedInfo)
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -050059 , fCropRect(cropRect)
60 , fPostProcess(std::move(postProcess))
Leon Scroggins III4c119452018-01-20 10:33:24 -050061 , fFrameCount(fCodec->codec()->getFrameCount())
Leon Scrogginsda3d8c22020-11-09 16:00:53 -050062 , fSampleSize(1)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050063 , fFinished(false)
Leon Scroggins III4c119452018-01-20 10:33:24 -050064 , fRepetitionCount(fCodec->codec()->getRepetitionCount())
65 , fRepetitionsCompleted(0)
Leon Scroggins III7a10b332018-01-12 11:24:30 -050066{
Leon Scrogginsda3d8c22020-11-09 16:00:53 -050067 auto scaledSize = requestedInfo.dimensions();
68
Leon Scroggins7d1153f2020-11-06 17:05:36 -050069 // For simplicity in decoding and compositing frames, decode directly to a size and
70 // orientation that fCodec can do directly, and then use fMatrix to handle crop (along with a
71 // clip), orientation, and scaling outside of fCodec. The matrices are computed individually
72 // and applied in the following order:
73 // [crop] X [origin] X [scale]
74 const auto origin = fCodec->codec()->getOrigin();
75 if (fCodec->fOrientationBehavior == SkAndroidCodec::ExifOrientationBehavior::kRespect
76 && origin != SkEncodedOrigin::kDefault_SkEncodedOrigin) {
77 // The origin is applied after scaling, so use scaledSize, which is the final scaled size.
78 fMatrix = SkEncodedOriginToMatrix(origin, scaledSize.width(), scaledSize.height());
79
80 fCodec = SkAndroidCodec::MakeFromCodec(std::move(fCodec->fCodec),
81 SkAndroidCodec::ExifOrientationBehavior::kIgnore);
82 if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
83 // The client asked for sizes post-rotation. Swap back to the pre-rotation sizes to pass
84 // to fCodec and for the scale matrix computation.
85 fDecodeInfo = SkPixmapPriv::SwapWidthHeight(fDecodeInfo);
86 scaledSize = { scaledSize.height(), scaledSize.width() };
87 }
88 }
Leon Scrogginsda3d8c22020-11-09 16:00:53 -050089
90 auto decodeSize = scaledSize;
91 fSampleSize = fCodec->computeSampleSize(&decodeSize);
92 fDecodeInfo = fDecodeInfo.makeDimensions(decodeSize);
93
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -040094 if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -050095 return;
96 }
97
Leon Scroggins7d1153f2020-11-06 17:05:36 -050098 if (scaledSize != fDecodeInfo.dimensions()) {
99 float scaleX = (float) scaledSize.width() / fDecodeInfo.width();
100 float scaleY = (float) scaledSize.height() / fDecodeInfo.height();
Mike Reed1f607332020-05-21 12:11:27 -0400101 fMatrix.preConcat(SkMatrix::Scale(scaleX, scaleY));
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500102 }
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500103 fMatrix.postConcat(SkMatrix::Translate(-fCropRect.fLeft, -fCropRect.fTop));
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500104 this->decodeNextFrame();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500105}
106
107SkAnimatedImage::~SkAnimatedImage() { }
108
109SkRect SkAnimatedImage::onGetBounds() {
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500110 return SkRect::MakeIWH(fCropRect.width(), fCropRect.height());
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500111}
112
113SkAnimatedImage::Frame::Frame()
Nigel Tao66bc5242018-08-22 10:56:03 +1000114 : fIndex(SkCodec::kNoFrame)
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500115{}
116
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400117bool SkAnimatedImage::Frame::init(const SkImageInfo& info, OnInit onInit) {
118 if (fBitmap.getPixels()) {
119 if (fBitmap.pixelRef()->unique()) {
120 SkAssertResult(fBitmap.setAlphaType(info.alphaType()));
121 return true;
122 }
123
124 // An SkCanvas provided to onDraw is still holding a reference.
125 // Copy before we decode to ensure that we don't overwrite the
126 // expected contents of the image.
127 if (OnInit::kRestoreIfNecessary == onInit) {
128 SkBitmap tmp;
129 if (!tmp.tryAllocPixels(info)) {
130 return false;
131 }
132
133 memcpy(tmp.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400134 using std::swap;
135 swap(tmp, fBitmap);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400136 return true;
137 }
138 }
139
140 return fBitmap.tryAllocPixels(info);
141}
142
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500143bool SkAnimatedImage::Frame::copyTo(Frame* dst) const {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400144 if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500145 return false;
146 }
147
148 memcpy(dst->fBitmap.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize());
149 dst->fIndex = fIndex;
150 dst->fDisposalMethod = fDisposalMethod;
151 return true;
152}
153
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500154void SkAnimatedImage::reset() {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500155 fFinished = false;
156 fRepetitionsCompleted = 0;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400157 if (fDisplayFrame.fIndex != 0) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000158 fDisplayFrame.fIndex = SkCodec::kNoFrame;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400159 this->decodeNextFrame();
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500160 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500161}
162
163static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) {
164 return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose;
165}
166
Leon Scroggins III4c119452018-01-20 10:33:24 -0500167int SkAnimatedImage::computeNextFrame(int current, bool* animationEnded) {
168 SkASSERT(animationEnded != nullptr);
169 *animationEnded = false;
170
171 const int frameToDecode = current + 1;
172 if (frameToDecode == fFrameCount - 1) {
173 // Final frame. Check to determine whether to stop.
174 fRepetitionsCompleted++;
175 if (fRepetitionCount != SkCodec::kRepetitionCountInfinite
176 && fRepetitionsCompleted > fRepetitionCount) {
177 *animationEnded = true;
178 }
179 } else if (frameToDecode == fFrameCount) {
180 return 0;
181 }
182 return frameToDecode;
183}
184
185double SkAnimatedImage::finish() {
186 fFinished = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500187 fCurrentFrameDuration = kFinished;
188 return kFinished;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500189}
190
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500191int SkAnimatedImage::decodeNextFrame() {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500192 if (fFinished) {
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500193 return kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500194 }
195
Leon Scroggins III4c119452018-01-20 10:33:24 -0500196 bool animationEnded = false;
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400197 const int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500198
199 SkCodec::FrameInfo frameInfo;
Leon Scroggins III42ee2842018-01-14 14:46:51 -0500200 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500201 if (!frameInfo.fFullyReceived) {
202 SkCodecPrintf("Frame %i not fully received\n", frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500203 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500204 }
205
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500206 fCurrentFrameDuration = frameInfo.fDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500207 } else {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500208 animationEnded = true;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500209 if (0 == frameToDecode) {
210 // Static image. This is okay.
Nigel Tao66bc5242018-08-22 10:56:03 +1000211 frameInfo.fRequiredFrame = SkCodec::kNoFrame;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500212 frameInfo.fAlphaType = fCodec->getInfo().alphaType();
Kevin Lubick289d36f2018-02-13 10:25:00 -0500213 frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500214 // These fields won't be read.
215 frameInfo.fDuration = INT_MAX;
216 frameInfo.fFullyReceived = true;
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500217 fCurrentFrameDuration = kFinished;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500218 } else {
219 SkCodecPrintf("Error getting frameInfo for frame %i\n",
220 frameToDecode);
Leon Scroggins III4c119452018-01-20 10:33:24 -0500221 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500222 }
223 }
224
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400225 if (frameToDecode == fDisplayFrame.fIndex) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500226 if (animationEnded) {
227 return this->finish();
228 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500229 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500230 }
231
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400232 for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) {
233 if (frameToDecode == frame->fIndex) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400234 using std::swap;
235 swap(fDisplayFrame, *frame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400236 if (animationEnded) {
237 return this->finish();
238 }
239 return fCurrentFrameDuration;
Leon Scroggins III4c119452018-01-20 10:33:24 -0500240 }
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500241 }
242
243 // The following code makes an effort to avoid overwriting a frame that will
244 // be used again. If frame |i| is_restore_previous, frame |i+1| will not
245 // depend on frame |i|, so do not overwrite frame |i-1|, which may be needed
246 // for frame |i+1|.
247 // We could be even smarter about which frames to save by looking at the
248 // entire dependency chain.
Leon Scrogginsda3d8c22020-11-09 16:00:53 -0500249 SkAndroidCodec::AndroidOptions options;
250 options.fSampleSize = fSampleSize;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500251 options.fFrameIndex = frameToDecode;
Nigel Tao66bc5242018-08-22 10:56:03 +1000252 if (frameInfo.fRequiredFrame == SkCodec::kNoFrame) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500253 if (is_restore_previous(frameInfo.fDisposalMethod)) {
254 // frameToDecode will be discarded immediately after drawing, so
255 // do not overwrite a frame which could possibly be used in the
256 // future.
Nigel Tao66bc5242018-08-22 10:56:03 +1000257 if (fDecodingFrame.fIndex != SkCodec::kNoFrame &&
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400258 !is_restore_previous(fDecodingFrame.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400259 using std::swap;
260 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500261 }
262 }
263 } else {
264 auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) {
Nigel Tao66bc5242018-08-22 10:56:03 +1000265 if (SkCodec::kNoFrame == frame.fIndex ||
266 is_restore_previous(frame.fDisposalMethod)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500267 return false;
268 }
269
270 return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode;
271 };
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400272 if (validPriorFrame(fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500273 if (is_restore_previous(frameInfo.fDisposalMethod)) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400274 // fDecodingFrame is a good frame to use for this one, but we
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500275 // don't want to overwrite it.
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400276 fDecodingFrame.copyTo(&fRestoreFrame);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500277 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400278 options.fPriorFrame = fDecodingFrame.fIndex;
279 } else if (validPriorFrame(fDisplayFrame)) {
280 if (!fDisplayFrame.copyTo(&fDecodingFrame)) {
281 SkCodecPrintf("Failed to allocate pixels for frame\n");
282 return this->finish();
283 }
284 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500285 } else if (validPriorFrame(fRestoreFrame)) {
286 if (!is_restore_previous(frameInfo.fDisposalMethod)) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400287 using std::swap;
288 swap(fDecodingFrame, fRestoreFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400289 } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) {
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500290 SkCodecPrintf("Failed to restore frame\n");
Leon Scroggins III4c119452018-01-20 10:33:24 -0500291 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500292 }
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400293 options.fPriorFrame = fDecodingFrame.fIndex;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500294 }
295 }
296
297 auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ?
298 kOpaque_SkAlphaType : kPremul_SkAlphaType;
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400299 auto info = fDecodeInfo.makeAlphaType(alphaType);
300 SkBitmap* dst = &fDecodingFrame.fBitmap;
301 if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) {
302 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500303 }
304
Leon Scrogginsda3d8c22020-11-09 16:00:53 -0500305 auto result = fCodec->getAndroidPixels(dst->info(), dst->getPixels(), dst->rowBytes(),
306 &options);
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500307 if (result != SkCodec::kSuccess) {
Leon Scroggins III4c119452018-01-20 10:33:24 -0500308 SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount);
309 return this->finish();
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500310 }
311
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400312 fDecodingFrame.fIndex = frameToDecode;
313 fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod;
314
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400315 using std::swap;
316 swap(fDecodingFrame, fDisplayFrame);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400317 fDisplayFrame.fBitmap.notifyPixelsChanged();
Leon Scroggins III4c119452018-01-20 10:33:24 -0500318
319 if (animationEnded) {
320 return this->finish();
Leon Scroggins III0e68f442019-08-28 11:41:02 -0400321 } else if (fCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF) {
322 // HEIF doesn't know the frame duration until after decoding. Update to
323 // the correct value. Note that earlier returns in this method either
324 // return kFinished, or fCurrentFrameDuration. If they return the
325 // latter, it is a frame that was previously decoded, so it has the
326 // updated value.
327 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) {
328 fCurrentFrameDuration = frameInfo.fDuration;
329 } else {
330 SkCodecPrintf("Failed to getFrameInfo on second attempt (HEIF)");
331 }
Leon Scroggins III4c119452018-01-20 10:33:24 -0500332 }
Leon Scroggins III495e0f02018-01-29 19:35:55 -0500333 return fCurrentFrameDuration;
Leon Scroggins III7a10b332018-01-12 11:24:30 -0500334}
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500335
336void SkAnimatedImage::onDraw(SkCanvas* canvas) {
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500337 auto image = this->getCurrentFrameSimple();
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400338
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500339 if (this->simple()) {
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400340 canvas->drawImage(image, 0, 0);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500341 return;
342 }
343
344 SkRect bounds = this->getBounds();
345 if (fPostProcess) {
346 canvas->saveLayer(&bounds, nullptr);
347 }
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500348 canvas->clipRect(bounds);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500349 {
Ben Wagner5d1adbf2018-05-28 13:35:39 -0400350 SkAutoCanvasRestore acr(canvas, fPostProcess != nullptr);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500351 canvas->concat(fMatrix);
352 SkPaint paint;
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500353 paint.setFilterQuality(kLow_SkFilterQuality);
Leon Scroggins III4aafb3a2018-05-23 16:15:09 -0400354 canvas->drawImage(image, 0, 0, &paint);
Leon Scroggins IIIb1b7f7012018-01-16 15:26:35 -0500355 }
356 if (fPostProcess) {
357 canvas->drawPicture(fPostProcess);
358 canvas->restore();
359 }
360}
Leon Scroggins III4c119452018-01-20 10:33:24 -0500361
362void SkAnimatedImage::setRepetitionCount(int newCount) {
363 fRepetitionCount = newCount;
364}
Kevin Lubickf5bc8fb2020-01-08 13:29:31 -0500365
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500366sk_sp<SkImage> SkAnimatedImage::getCurrentFrameSimple() {
Kevin Lubickf5bc8fb2020-01-08 13:29:31 -0500367 // This SkBitmap may be reused later to decode the following frame. But Frame::init
368 // lazily copies the pixel ref if it has any other references. So it is safe to not
369 // do a deep copy here.
370 return SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap,
371 kNever_SkCopyPixelsMode);
372}
Leon Scroggins7d1153f2020-11-06 17:05:36 -0500373
374sk_sp<SkImage> SkAnimatedImage::getCurrentFrame() {
375 if (this->simple()) return this->getCurrentFrameSimple();
376
377 auto imageInfo = fDisplayFrame.fBitmap.info().makeDimensions(fCropRect.size());
378 if (fPostProcess) {
379 // Defensively use premul in case the post process adds alpha.
380 imageInfo = imageInfo.makeAlphaType(kPremul_SkAlphaType);
381 }
382
383 SkBitmap dst;
384 if (!dst.tryAllocPixels(imageInfo)) {
385 return nullptr;
386 }
387
388 SkCanvas canvas(dst);
389 this->draw(&canvas);
390 return SkMakeImageFromRasterBitmap(dst, kNever_SkCopyPixelsMode);
391}