1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/android/SkAnimatedImage.h" 9cb93a386Sopenharmony_ci#include "include/codec/SkAndroidCodec.h" 10cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h" 11cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPicture.h" 13cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h" 14cb93a386Sopenharmony_ci#include "include/core/SkPixelRef.h" 15cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h" 16cb93a386Sopenharmony_ci#include "src/core/SkImagePriv.h" 17cb93a386Sopenharmony_ci#include "src/core/SkPixmapPriv.h" 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci#include <limits.h> 20cb93a386Sopenharmony_ci#include <utility> 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_cisk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec, 23cb93a386Sopenharmony_ci const SkImageInfo& requestedInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess) { 24cb93a386Sopenharmony_ci if (!codec) { 25cb93a386Sopenharmony_ci return nullptr; 26cb93a386Sopenharmony_ci } 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci if (!requestedInfo.bounds().contains(cropRect)) { 29cb93a386Sopenharmony_ci return nullptr; 30cb93a386Sopenharmony_ci } 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), requestedInfo, 33cb93a386Sopenharmony_ci cropRect, std::move(postProcess))); 34cb93a386Sopenharmony_ci if (!image->fDisplayFrame.fBitmap.getPixels()) { 35cb93a386Sopenharmony_ci // tryAllocPixels failed. 36cb93a386Sopenharmony_ci return nullptr; 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci return image; 40cb93a386Sopenharmony_ci} 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_cisk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec) { 43cb93a386Sopenharmony_ci if (!codec) { 44cb93a386Sopenharmony_ci return nullptr; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci auto decodeInfo = codec->getInfo(); 48cb93a386Sopenharmony_ci const auto origin = codec->codec()->getOrigin(); 49cb93a386Sopenharmony_ci if (SkEncodedOriginSwapsWidthHeight(origin)) { 50cb93a386Sopenharmony_ci decodeInfo = decodeInfo.makeWH(decodeInfo.height(), decodeInfo.width()); 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci const auto cropRect = SkIRect::MakeSize(decodeInfo.dimensions()); 53cb93a386Sopenharmony_ci return Make(std::move(codec), decodeInfo, cropRect, nullptr); 54cb93a386Sopenharmony_ci} 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciSkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, 57cb93a386Sopenharmony_ci const SkImageInfo& requestedInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess) 58cb93a386Sopenharmony_ci : fCodec(std::move(codec)) 59cb93a386Sopenharmony_ci , fDecodeInfo(requestedInfo) 60cb93a386Sopenharmony_ci , fCropRect(cropRect) 61cb93a386Sopenharmony_ci , fPostProcess(std::move(postProcess)) 62cb93a386Sopenharmony_ci , fFrameCount(fCodec->codec()->getFrameCount()) 63cb93a386Sopenharmony_ci , fSampleSize(1) 64cb93a386Sopenharmony_ci , fFinished(false) 65cb93a386Sopenharmony_ci , fRepetitionCount(fCodec->codec()->getRepetitionCount()) 66cb93a386Sopenharmony_ci , fRepetitionsCompleted(0) 67cb93a386Sopenharmony_ci{ 68cb93a386Sopenharmony_ci auto scaledSize = requestedInfo.dimensions(); 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci // For simplicity in decoding and compositing frames, decode directly to a size and 71cb93a386Sopenharmony_ci // orientation that fCodec can do directly, and then use fMatrix to handle crop (along with a 72cb93a386Sopenharmony_ci // clip), orientation, and scaling outside of fCodec. The matrices are computed individually 73cb93a386Sopenharmony_ci // and applied in the following order: 74cb93a386Sopenharmony_ci // [crop] X [origin] X [scale] 75cb93a386Sopenharmony_ci const auto origin = fCodec->codec()->getOrigin(); 76cb93a386Sopenharmony_ci if (origin != SkEncodedOrigin::kDefault_SkEncodedOrigin) { 77cb93a386Sopenharmony_ci // The origin is applied after scaling, so use scaledSize, which is the final scaled size. 78cb93a386Sopenharmony_ci fMatrix = SkEncodedOriginToMatrix(origin, scaledSize.width(), scaledSize.height()); 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci if (SkEncodedOriginSwapsWidthHeight(origin)) { 81cb93a386Sopenharmony_ci // The client asked for sizes post-rotation. Swap back to the pre-rotation sizes to pass 82cb93a386Sopenharmony_ci // to fCodec and for the scale matrix computation. 83cb93a386Sopenharmony_ci fDecodeInfo = SkPixmapPriv::SwapWidthHeight(fDecodeInfo); 84cb93a386Sopenharmony_ci scaledSize = { scaledSize.height(), scaledSize.width() }; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci auto decodeSize = scaledSize; 89cb93a386Sopenharmony_ci fSampleSize = fCodec->computeSampleSize(&decodeSize); 90cb93a386Sopenharmony_ci fDecodeInfo = fDecodeInfo.makeDimensions(decodeSize); 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) { 93cb93a386Sopenharmony_ci return; 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci if (scaledSize != fDecodeInfo.dimensions()) { 97cb93a386Sopenharmony_ci float scaleX = (float) scaledSize.width() / fDecodeInfo.width(); 98cb93a386Sopenharmony_ci float scaleY = (float) scaledSize.height() / fDecodeInfo.height(); 99cb93a386Sopenharmony_ci fMatrix.preConcat(SkMatrix::Scale(scaleX, scaleY)); 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci fMatrix.postConcat(SkMatrix::Translate(-fCropRect.fLeft, -fCropRect.fTop)); 102cb93a386Sopenharmony_ci this->decodeNextFrame(); 103cb93a386Sopenharmony_ci} 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ciSkAnimatedImage::~SkAnimatedImage() { } 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ciSkRect SkAnimatedImage::onGetBounds() { 108cb93a386Sopenharmony_ci return SkRect::MakeIWH(fCropRect.width(), fCropRect.height()); 109cb93a386Sopenharmony_ci} 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ciSkAnimatedImage::Frame::Frame() 112cb93a386Sopenharmony_ci : fIndex(SkCodec::kNoFrame) 113cb93a386Sopenharmony_ci{} 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_cibool SkAnimatedImage::Frame::init(const SkImageInfo& info, OnInit onInit) { 116cb93a386Sopenharmony_ci if (fBitmap.getPixels()) { 117cb93a386Sopenharmony_ci if (fBitmap.pixelRef()->unique()) { 118cb93a386Sopenharmony_ci SkAssertResult(fBitmap.setAlphaType(info.alphaType())); 119cb93a386Sopenharmony_ci return true; 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci // An SkCanvas provided to onDraw is still holding a reference. 123cb93a386Sopenharmony_ci // Copy before we decode to ensure that we don't overwrite the 124cb93a386Sopenharmony_ci // expected contents of the image. 125cb93a386Sopenharmony_ci if (OnInit::kRestoreIfNecessary == onInit) { 126cb93a386Sopenharmony_ci SkBitmap tmp; 127cb93a386Sopenharmony_ci if (!tmp.tryAllocPixels(info)) { 128cb93a386Sopenharmony_ci return false; 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci memcpy(tmp.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize()); 132cb93a386Sopenharmony_ci using std::swap; 133cb93a386Sopenharmony_ci swap(tmp, fBitmap); 134cb93a386Sopenharmony_ci return true; 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci return fBitmap.tryAllocPixels(info); 139cb93a386Sopenharmony_ci} 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_cibool SkAnimatedImage::Frame::copyTo(Frame* dst) const { 142cb93a386Sopenharmony_ci if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) { 143cb93a386Sopenharmony_ci return false; 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci memcpy(dst->fBitmap.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize()); 147cb93a386Sopenharmony_ci dst->fIndex = fIndex; 148cb93a386Sopenharmony_ci dst->fDisposalMethod = fDisposalMethod; 149cb93a386Sopenharmony_ci return true; 150cb93a386Sopenharmony_ci} 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_civoid SkAnimatedImage::reset() { 153cb93a386Sopenharmony_ci fFinished = false; 154cb93a386Sopenharmony_ci fRepetitionsCompleted = 0; 155cb93a386Sopenharmony_ci if (fDisplayFrame.fIndex != 0) { 156cb93a386Sopenharmony_ci fDisplayFrame.fIndex = SkCodec::kNoFrame; 157cb93a386Sopenharmony_ci this->decodeNextFrame(); 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci} 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_cistatic bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) { 162cb93a386Sopenharmony_ci return SkCodecAnimation::DisposalMethod::kRestorePrevious == dispose; 163cb93a386Sopenharmony_ci} 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ciint SkAnimatedImage::computeNextFrame(int current, bool* animationEnded) { 166cb93a386Sopenharmony_ci SkASSERT(animationEnded != nullptr); 167cb93a386Sopenharmony_ci *animationEnded = false; 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci const int frameToDecode = current + 1; 170cb93a386Sopenharmony_ci if (frameToDecode == fFrameCount - 1) { 171cb93a386Sopenharmony_ci // Final frame. Check to determine whether to stop. 172cb93a386Sopenharmony_ci fRepetitionsCompleted++; 173cb93a386Sopenharmony_ci if (fRepetitionCount != SkCodec::kRepetitionCountInfinite 174cb93a386Sopenharmony_ci && fRepetitionsCompleted > fRepetitionCount) { 175cb93a386Sopenharmony_ci *animationEnded = true; 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci } else if (frameToDecode == fFrameCount) { 178cb93a386Sopenharmony_ci return 0; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci return frameToDecode; 181cb93a386Sopenharmony_ci} 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_cidouble SkAnimatedImage::finish() { 184cb93a386Sopenharmony_ci fFinished = true; 185cb93a386Sopenharmony_ci fCurrentFrameDuration = kFinished; 186cb93a386Sopenharmony_ci return kFinished; 187cb93a386Sopenharmony_ci} 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ciint SkAnimatedImage::decodeNextFrame() { 190cb93a386Sopenharmony_ci if (fFinished) { 191cb93a386Sopenharmony_ci return kFinished; 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ci bool animationEnded = false; 195cb93a386Sopenharmony_ci const int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded); 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci SkCodec::FrameInfo frameInfo; 198cb93a386Sopenharmony_ci if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) { 199cb93a386Sopenharmony_ci if (!frameInfo.fFullyReceived) { 200cb93a386Sopenharmony_ci SkCodecPrintf("Frame %i not fully received\n", frameToDecode); 201cb93a386Sopenharmony_ci return this->finish(); 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci fCurrentFrameDuration = frameInfo.fDuration; 205cb93a386Sopenharmony_ci } else { 206cb93a386Sopenharmony_ci animationEnded = true; 207cb93a386Sopenharmony_ci if (0 == frameToDecode) { 208cb93a386Sopenharmony_ci // Static image. This is okay. 209cb93a386Sopenharmony_ci frameInfo.fRequiredFrame = SkCodec::kNoFrame; 210cb93a386Sopenharmony_ci frameInfo.fAlphaType = fCodec->getInfo().alphaType(); 211cb93a386Sopenharmony_ci frameInfo.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep; 212cb93a386Sopenharmony_ci // These fields won't be read. 213cb93a386Sopenharmony_ci frameInfo.fDuration = INT_MAX; 214cb93a386Sopenharmony_ci frameInfo.fFullyReceived = true; 215cb93a386Sopenharmony_ci fCurrentFrameDuration = kFinished; 216cb93a386Sopenharmony_ci } else { 217cb93a386Sopenharmony_ci SkCodecPrintf("Error getting frameInfo for frame %i\n", 218cb93a386Sopenharmony_ci frameToDecode); 219cb93a386Sopenharmony_ci return this->finish(); 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci if (frameToDecode == fDisplayFrame.fIndex) { 224cb93a386Sopenharmony_ci if (animationEnded) { 225cb93a386Sopenharmony_ci return this->finish(); 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci return fCurrentFrameDuration; 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) { 231cb93a386Sopenharmony_ci if (frameToDecode == frame->fIndex) { 232cb93a386Sopenharmony_ci using std::swap; 233cb93a386Sopenharmony_ci swap(fDisplayFrame, *frame); 234cb93a386Sopenharmony_ci if (animationEnded) { 235cb93a386Sopenharmony_ci return this->finish(); 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci return fCurrentFrameDuration; 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ci // The following code makes an effort to avoid overwriting a frame that will 242cb93a386Sopenharmony_ci // be used again. If frame |i| is_restore_previous, frame |i+1| will not 243cb93a386Sopenharmony_ci // depend on frame |i|, so do not overwrite frame |i-1|, which may be needed 244cb93a386Sopenharmony_ci // for frame |i+1|. 245cb93a386Sopenharmony_ci // We could be even smarter about which frames to save by looking at the 246cb93a386Sopenharmony_ci // entire dependency chain. 247cb93a386Sopenharmony_ci SkAndroidCodec::AndroidOptions options; 248cb93a386Sopenharmony_ci options.fSampleSize = fSampleSize; 249cb93a386Sopenharmony_ci options.fFrameIndex = frameToDecode; 250cb93a386Sopenharmony_ci if (frameInfo.fRequiredFrame == SkCodec::kNoFrame) { 251cb93a386Sopenharmony_ci if (is_restore_previous(frameInfo.fDisposalMethod)) { 252cb93a386Sopenharmony_ci // frameToDecode will be discarded immediately after drawing, so 253cb93a386Sopenharmony_ci // do not overwrite a frame which could possibly be used in the 254cb93a386Sopenharmony_ci // future. 255cb93a386Sopenharmony_ci if (fDecodingFrame.fIndex != SkCodec::kNoFrame && 256cb93a386Sopenharmony_ci !is_restore_previous(fDecodingFrame.fDisposalMethod)) { 257cb93a386Sopenharmony_ci using std::swap; 258cb93a386Sopenharmony_ci swap(fDecodingFrame, fRestoreFrame); 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci } else { 262cb93a386Sopenharmony_ci auto validPriorFrame = [&frameInfo, &frameToDecode](const Frame& frame) { 263cb93a386Sopenharmony_ci if (SkCodec::kNoFrame == frame.fIndex || 264cb93a386Sopenharmony_ci is_restore_previous(frame.fDisposalMethod)) { 265cb93a386Sopenharmony_ci return false; 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode; 269cb93a386Sopenharmony_ci }; 270cb93a386Sopenharmony_ci if (validPriorFrame(fDecodingFrame)) { 271cb93a386Sopenharmony_ci if (is_restore_previous(frameInfo.fDisposalMethod)) { 272cb93a386Sopenharmony_ci // fDecodingFrame is a good frame to use for this one, but we 273cb93a386Sopenharmony_ci // don't want to overwrite it. 274cb93a386Sopenharmony_ci fDecodingFrame.copyTo(&fRestoreFrame); 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci options.fPriorFrame = fDecodingFrame.fIndex; 277cb93a386Sopenharmony_ci } else if (validPriorFrame(fDisplayFrame)) { 278cb93a386Sopenharmony_ci if (!fDisplayFrame.copyTo(&fDecodingFrame)) { 279cb93a386Sopenharmony_ci SkCodecPrintf("Failed to allocate pixels for frame\n"); 280cb93a386Sopenharmony_ci return this->finish(); 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci options.fPriorFrame = fDecodingFrame.fIndex; 283cb93a386Sopenharmony_ci } else if (validPriorFrame(fRestoreFrame)) { 284cb93a386Sopenharmony_ci if (!is_restore_previous(frameInfo.fDisposalMethod)) { 285cb93a386Sopenharmony_ci using std::swap; 286cb93a386Sopenharmony_ci swap(fDecodingFrame, fRestoreFrame); 287cb93a386Sopenharmony_ci } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) { 288cb93a386Sopenharmony_ci SkCodecPrintf("Failed to restore frame\n"); 289cb93a386Sopenharmony_ci return this->finish(); 290cb93a386Sopenharmony_ci } 291cb93a386Sopenharmony_ci options.fPriorFrame = fDecodingFrame.fIndex; 292cb93a386Sopenharmony_ci } 293cb93a386Sopenharmony_ci } 294cb93a386Sopenharmony_ci 295cb93a386Sopenharmony_ci auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ? 296cb93a386Sopenharmony_ci kOpaque_SkAlphaType : kPremul_SkAlphaType; 297cb93a386Sopenharmony_ci auto info = fDecodeInfo.makeAlphaType(alphaType); 298cb93a386Sopenharmony_ci SkBitmap* dst = &fDecodingFrame.fBitmap; 299cb93a386Sopenharmony_ci if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) { 300cb93a386Sopenharmony_ci return this->finish(); 301cb93a386Sopenharmony_ci } 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci auto result = fCodec->getAndroidPixels(dst->info(), dst->getPixels(), dst->rowBytes(), 304cb93a386Sopenharmony_ci &options); 305cb93a386Sopenharmony_ci if (result != SkCodec::kSuccess) { 306cb93a386Sopenharmony_ci SkCodecPrintf("error %i, frame %i of %i\n", result, frameToDecode, fFrameCount); 307cb93a386Sopenharmony_ci return this->finish(); 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_ci fDecodingFrame.fIndex = frameToDecode; 311cb93a386Sopenharmony_ci fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod; 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci using std::swap; 314cb93a386Sopenharmony_ci swap(fDecodingFrame, fDisplayFrame); 315cb93a386Sopenharmony_ci fDisplayFrame.fBitmap.notifyPixelsChanged(); 316cb93a386Sopenharmony_ci 317cb93a386Sopenharmony_ci if (animationEnded) { 318cb93a386Sopenharmony_ci return this->finish(); 319cb93a386Sopenharmony_ci } else if (fCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF) { 320cb93a386Sopenharmony_ci // HEIF doesn't know the frame duration until after decoding. Update to 321cb93a386Sopenharmony_ci // the correct value. Note that earlier returns in this method either 322cb93a386Sopenharmony_ci // return kFinished, or fCurrentFrameDuration. If they return the 323cb93a386Sopenharmony_ci // latter, it is a frame that was previously decoded, so it has the 324cb93a386Sopenharmony_ci // updated value. 325cb93a386Sopenharmony_ci if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) { 326cb93a386Sopenharmony_ci fCurrentFrameDuration = frameInfo.fDuration; 327cb93a386Sopenharmony_ci } else { 328cb93a386Sopenharmony_ci SkCodecPrintf("Failed to getFrameInfo on second attempt (HEIF)"); 329cb93a386Sopenharmony_ci } 330cb93a386Sopenharmony_ci } 331cb93a386Sopenharmony_ci return fCurrentFrameDuration; 332cb93a386Sopenharmony_ci} 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_civoid SkAnimatedImage::onDraw(SkCanvas* canvas) { 335cb93a386Sopenharmony_ci auto image = this->getCurrentFrameSimple(); 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci if (this->simple()) { 338cb93a386Sopenharmony_ci canvas->drawImage(image, 0, 0); 339cb93a386Sopenharmony_ci return; 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci SkRect bounds = this->getBounds(); 343cb93a386Sopenharmony_ci if (fPostProcess) { 344cb93a386Sopenharmony_ci canvas->saveLayer(&bounds, nullptr); 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci canvas->clipRect(bounds); 347cb93a386Sopenharmony_ci { 348cb93a386Sopenharmony_ci SkAutoCanvasRestore acr(canvas, fPostProcess != nullptr); 349cb93a386Sopenharmony_ci canvas->concat(fMatrix); 350cb93a386Sopenharmony_ci canvas->drawImage(image, 0, 0, SkSamplingOptions(SkFilterMode::kLinear), nullptr); 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci if (fPostProcess) { 353cb93a386Sopenharmony_ci canvas->drawPicture(fPostProcess); 354cb93a386Sopenharmony_ci canvas->restore(); 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci} 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_civoid SkAnimatedImage::setRepetitionCount(int newCount) { 359cb93a386Sopenharmony_ci fRepetitionCount = newCount; 360cb93a386Sopenharmony_ci} 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_cisk_sp<SkImage> SkAnimatedImage::getCurrentFrameSimple() { 363cb93a386Sopenharmony_ci // This SkBitmap may be reused later to decode the following frame. But Frame::init 364cb93a386Sopenharmony_ci // lazily copies the pixel ref if it has any other references. So it is safe to not 365cb93a386Sopenharmony_ci // do a deep copy here. 366cb93a386Sopenharmony_ci return SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap, 367cb93a386Sopenharmony_ci kNever_SkCopyPixelsMode); 368cb93a386Sopenharmony_ci} 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_cisk_sp<SkImage> SkAnimatedImage::getCurrentFrame() { 371cb93a386Sopenharmony_ci if (this->simple()) return this->getCurrentFrameSimple(); 372cb93a386Sopenharmony_ci 373cb93a386Sopenharmony_ci auto imageInfo = fDisplayFrame.fBitmap.info().makeDimensions(fCropRect.size()); 374cb93a386Sopenharmony_ci if (fPostProcess) { 375cb93a386Sopenharmony_ci // Defensively use premul in case the post process adds alpha. 376cb93a386Sopenharmony_ci imageInfo = imageInfo.makeAlphaType(kPremul_SkAlphaType); 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci SkBitmap dst; 380cb93a386Sopenharmony_ci if (!dst.tryAllocPixels(imageInfo)) { 381cb93a386Sopenharmony_ci return nullptr; 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ci SkCanvas canvas(dst); 385cb93a386Sopenharmony_ci this->draw(&canvas); 386cb93a386Sopenharmony_ci return SkMakeImageFromRasterBitmap(dst, kNever_SkCopyPixelsMode); 387cb93a386Sopenharmony_ci} 388