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 18 #include <utility> 19 20 sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec, 21 SkISize scaledSize, SkIRect cropRect, sk_sp<SkPicture> postProcess) { 22 if (!codec) { 23 return nullptr; 24 } 25 26 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))); 37 if (!image->fDisplayFrame.fBitmap.getPixels()) { 38 // tryAllocPixels failed. 39 return nullptr; 40 } 41 42 return image; 43 } 44 45 sk_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 56 if (!image->fDisplayFrame.fBitmap.getPixels()) { 57 // tryAllocPixels failed. 58 return nullptr; 59 } 60 61 SkASSERT(image->fSimple); 62 return image; 63 } 64 65 SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize, 66 SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess) 67 : fCodec(std::move(codec)) 68 , fScaledSize(scaledSize) 69 , fDecodeInfo(decodeInfo) 70 , fCropRect(cropRect) 71 , fPostProcess(std::move(postProcess)) 72 , fFrameCount(fCodec->codec()->getFrameCount()) 73 , fSimple(fScaledSize == fDecodeInfo.dimensions() && !fPostProcess 74 && fCropRect == fDecodeInfo.bounds()) 75 , fFinished(false) 76 , fRepetitionCount(fCodec->codec()->getRepetitionCount()) 77 , fRepetitionsCompleted(0) 78 { 79 if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) { 80 return; 81 } 82 83 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 } 89 this->decodeNextFrame(); 90 } 91 92 SkAnimatedImage::~SkAnimatedImage() { } 93 94 SkRect SkAnimatedImage::onGetBounds() { 95 return SkRect::MakeIWH(fCropRect.width(), fCropRect.height()); 96 } 97 98 SkAnimatedImage::Frame::Frame() 99 : fIndex(SkCodec::kNoFrame) 100 {} 101 102 bool 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()); 119 using std::swap; 120 swap(tmp, fBitmap); 121 return true; 122 } 123 } 124 125 return fBitmap.tryAllocPixels(info); 126 } 127 128 bool SkAnimatedImage::Frame::copyTo(Frame* dst) const { 129 if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) { 130 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 139 void SkAnimatedImage::reset() { 140 fFinished = false; 141 fRepetitionsCompleted = 0; 142 if (fDisplayFrame.fIndex != 0) { 143 fDisplayFrame.fIndex = SkCodec::kNoFrame; 144 this->decodeNextFrame(); 145 } 146 } 147 148 static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) { 149 return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose; 150 } 151 152 int 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 170 double SkAnimatedImage::finish() { 171 fFinished = true; 172 fCurrentFrameDuration = kFinished; 173 return kFinished; 174 } 175 176 int SkAnimatedImage::decodeNextFrame() { 177 if (fFinished) { 178 return kFinished; 179 } 180 181 bool animationEnded = false; 182 int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded); 183 184 SkCodec::FrameInfo frameInfo; 185 if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) { 186 if (!frameInfo.fFullyReceived) { 187 SkCodecPrintf("Frame %i not fully received\n", frameToDecode); 188 return this->finish(); 189 } 190 191 fCurrentFrameDuration = frameInfo.fDuration; 192 } else { 193 animationEnded = true; 194 if (0 == frameToDecode) { 195 // Static image. This is okay. 196 frameInfo.fRequiredFrame = SkCodec::kNoFrame; 197 frameInfo.fAlphaType = fCodec->getInfo().alphaType(); 198 frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep; 199 // These fields won't be read. 200 frameInfo.fDuration = INT_MAX; 201 frameInfo.fFullyReceived = true; 202 fCurrentFrameDuration = kFinished; 203 } else { 204 SkCodecPrintf("Error getting frameInfo for frame %i\n", 205 frameToDecode); 206 return this->finish(); 207 } 208 } 209 210 if (frameToDecode == fDisplayFrame.fIndex) { 211 if (animationEnded) { 212 return this->finish(); 213 } 214 return fCurrentFrameDuration; 215 } 216 217 for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) { 218 if (frameToDecode == frame->fIndex) { 219 using std::swap; 220 swap(fDisplayFrame, *frame); 221 if (animationEnded) { 222 return this->finish(); 223 } 224 return fCurrentFrameDuration; 225 } 226 } 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; 236 if (frameInfo.fRequiredFrame == SkCodec::kNoFrame) { 237 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. 241 if (fDecodingFrame.fIndex != SkCodec::kNoFrame && 242 !is_restore_previous(fDecodingFrame.fDisposalMethod)) { 243 using std::swap; 244 swap(fDecodingFrame, fRestoreFrame); 245 } 246 } 247 } else { 248 auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) { 249 if (SkCodec::kNoFrame == frame.fIndex || 250 is_restore_previous(frame.fDisposalMethod)) { 251 return false; 252 } 253 254 return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode; 255 }; 256 if (validPriorFrame(fDecodingFrame)) { 257 if (is_restore_previous(frameInfo.fDisposalMethod)) { 258 // fDecodingFrame is a good frame to use for this one, but we 259 // don't want to overwrite it. 260 fDecodingFrame.copyTo(&fRestoreFrame); 261 } 262 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; 269 } else if (validPriorFrame(fRestoreFrame)) { 270 if (!is_restore_previous(frameInfo.fDisposalMethod)) { 271 using std::swap; 272 swap(fDecodingFrame, fRestoreFrame); 273 } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) { 274 SkCodecPrintf("Failed to restore frame\n"); 275 return this->finish(); 276 } 277 options.fPriorFrame = fDecodingFrame.fIndex; 278 } 279 } 280 281 auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ? 282 kOpaque_SkAlphaType : kPremul_SkAlphaType; 283 auto info = fDecodeInfo.makeAlphaType(alphaType); 284 SkBitmap* dst = &fDecodingFrame.fBitmap; 285 if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) { 286 return this->finish(); 287 } 288 289 auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(), 290 &options); 291 if (result != SkCodec::kSuccess) { 292 SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount); 293 return this->finish(); 294 } 295 296 fDecodingFrame.fIndex = frameToDecode; 297 fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod; 298 299 using std::swap; 300 swap(fDecodingFrame, fDisplayFrame); 301 fDisplayFrame.fBitmap.notifyPixelsChanged(); 302 303 if (animationEnded) { 304 return this->finish(); 305 } 306 return fCurrentFrameDuration; 307 } 308 309 void SkAnimatedImage::onDraw(SkCanvas* canvas) { 310 auto image = SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap, 311 kNever_SkCopyPixelsMode); 312 313 if (fSimple) { 314 canvas->drawImage(image, 0, 0); 315 return; 316 } 317 318 SkRect bounds = this->getBounds(); 319 if (fPostProcess) { 320 canvas->saveLayer(&bounds, nullptr); 321 } 322 { 323 SkAutoCanvasRestore acr(canvas, fPostProcess != nullptr); 324 canvas->concat(fMatrix); 325 SkPaint paint; 326 paint.setFilterQuality(kLow_SkFilterQuality); 327 canvas->drawImage(image, 0, 0, &paint); 328 } 329 if (fPostProcess) { 330 canvas->drawPicture(fPostProcess); 331 canvas->restore(); 332 } 333 } 334 335 void SkAnimatedImage::setRepetitionCount(int newCount) { 336 fRepetitionCount = newCount; 337 } 338