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