Coverage Report

Created: 2021-08-22 09:07

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