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 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 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 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 90 SkAnimatedImage::~SkAnimatedImage() { } 91 92 SkRect SkAnimatedImage::onGetBounds() { 93 return SkRect::MakeIWH(fCropRect.width(), fCropRect.height()); 94 } 95 96 SkAnimatedImage::Frame::Frame() 97 : fIndex(SkCodec::kNone) 98 {} 99 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 125 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 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 145 static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) { 146 return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose; 147 } 148 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 167 double SkAnimatedImage::finish() { 168 fFinished = true; 169 fCurrentFrameDuration = kFinished; 170 return kFinished; 171 } 172 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 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 327 void SkAnimatedImage::setRepetitionCount(int newCount) { 328 fRepetitionCount = newCount; 329 } 330