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