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