Coverage Report

Created: 2024-05-20 07:14

/src/skia/modules/skresources/src/SkAnimCodecPlayer.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 "modules/skresources/src/SkAnimCodecPlayer.h"
9
10
#include "include/codec/SkCodec.h"
11
#include "include/codec/SkEncodedOrigin.h"
12
#include "include/core/SkAlphaType.h"
13
#include "include/core/SkBlendMode.h"
14
#include "include/core/SkCanvas.h"
15
#include "include/core/SkData.h"
16
#include "include/core/SkImage.h"
17
#include "include/core/SkImageInfo.h"
18
#include "include/core/SkMatrix.h"
19
#include "include/core/SkPaint.h"
20
#include "include/core/SkRefCnt.h"
21
#include "include/core/SkSamplingOptions.h"
22
#include "include/core/SkSize.h"
23
#include "include/core/SkTypes.h"
24
#include "src/codec/SkCodecImageGenerator.h"
25
26
#include <algorithm>
27
#include <cstddef>
28
#include <memory>
29
#include <utility>
30
#include <vector>
31
32
0
SkAnimCodecPlayer::SkAnimCodecPlayer(std::unique_ptr<SkCodec> codec) : fCodec(std::move(codec)) {
33
0
    fImageInfo = fCodec->getInfo();
34
0
    fFrameInfos = fCodec->getFrameInfo();
35
0
    fImages.resize(fFrameInfos.size());
36
37
    // change the interpretation of fDuration to a end-time for that frame
38
0
    size_t dur = 0;
39
0
    for (auto& f : fFrameInfos) {
40
0
        dur += f.fDuration;
41
0
        f.fDuration = dur;
42
0
    }
43
0
    fTotalDuration = dur;
44
45
0
    if (!fTotalDuration) {
46
        // Static image -- may or may not have returned a single frame info.
47
0
        fFrameInfos.clear();
48
0
        fImages.clear();
49
0
        fImages.push_back(SkImages::DeferredFromGenerator(
50
0
                SkCodecImageGenerator::MakeFromCodec(std::move(fCodec))));
51
0
    }
52
0
}
53
54
0
SkAnimCodecPlayer::~SkAnimCodecPlayer() {}
55
56
0
SkISize SkAnimCodecPlayer::dimensions() const {
57
0
    if (!fCodec) {
58
0
        auto image = fImages.front();
59
0
        return image ? image->dimensions() : SkISize::MakeEmpty();
60
0
    }
61
0
    if (SkEncodedOriginSwapsWidthHeight(fCodec->getOrigin())) {
62
0
        return { fImageInfo.height(), fImageInfo.width() };
63
0
    }
64
0
    return { fImageInfo.width(), fImageInfo.height() };
65
0
}
66
67
0
sk_sp<SkImage> SkAnimCodecPlayer::getFrameAt(int index) {
68
0
    SkASSERT((unsigned)index < fFrameInfos.size());
69
70
0
    if (fImages[index]) {
71
0
        return fImages[index];
72
0
    }
73
74
0
    size_t rb = fImageInfo.minRowBytes();
75
0
    size_t size = fImageInfo.computeByteSize(rb);
76
0
    auto data = SkData::MakeUninitialized(size);
77
78
0
    SkCodec::Options opts;
79
0
    opts.fFrameIndex = index;
80
81
0
    const auto origin = fCodec->getOrigin();
82
0
    const auto orientedDims = this->dimensions();
83
0
    const auto originMatrix = SkEncodedOriginToMatrix(origin, orientedDims.width(),
84
0
                                                              orientedDims.height());
85
86
0
    SkPaint paint;
87
0
    paint.setBlendMode(SkBlendMode::kSrc);
88
89
0
    auto imageInfo = fImageInfo;
90
0
    if (fFrameInfos[index].fAlphaType != kOpaque_SkAlphaType && imageInfo.isOpaque()) {
91
0
        imageInfo = imageInfo.makeAlphaType(kPremul_SkAlphaType);
92
0
    }
93
0
    const int requiredFrame = fFrameInfos[index].fRequiredFrame;
94
0
    if (requiredFrame != SkCodec::kNoFrame && fImages[requiredFrame]) {
95
0
        auto requiredImage = fImages[requiredFrame];
96
0
        auto canvas = SkCanvas::MakeRasterDirect(imageInfo, data->writable_data(), rb);
97
0
        if (origin != kDefault_SkEncodedOrigin) {
98
            // The required frame is stored after applying the origin. Undo that,
99
            // because the codec decodes prior to applying the origin.
100
            // FIXME: Another approach would be to decode the frame's delta on top
101
            // of transparent black, and then draw that through the origin matrix
102
            // onto the required frame. To do that, SkCodec needs to expose the
103
            // rectangle of the delta and the blend mode, so we can handle
104
            // kRestoreBGColor frames and Blend::kSrc.
105
0
            SkMatrix inverse;
106
0
            SkAssertResult(originMatrix.invert(&inverse));
107
0
            canvas->concat(inverse);
108
0
        }
109
0
        canvas->drawImage(requiredImage, 0, 0, SkSamplingOptions(), &paint);
110
0
        opts.fPriorFrame = requiredFrame;
111
0
    }
112
113
0
    if (SkCodec::kSuccess != fCodec->getPixels(imageInfo, data->writable_data(), rb, &opts)) {
114
0
        return nullptr;
115
0
    }
116
117
0
    auto image = SkImages::RasterFromData(imageInfo, std::move(data), rb);
118
0
    if (origin != kDefault_SkEncodedOrigin) {
119
0
        imageInfo = imageInfo.makeDimensions(orientedDims);
120
0
        rb = imageInfo.minRowBytes();
121
0
        size = imageInfo.computeByteSize(rb);
122
0
        data = SkData::MakeUninitialized(size);
123
0
        auto canvas = SkCanvas::MakeRasterDirect(imageInfo, data->writable_data(), rb);
124
0
        canvas->concat(originMatrix);
125
0
        canvas->drawImage(image, 0, 0, SkSamplingOptions(), &paint);
126
0
        image = SkImages::RasterFromData(imageInfo, std::move(data), rb);
127
0
    }
128
0
    return fImages[index] = image;
129
0
}
130
131
0
sk_sp<SkImage> SkAnimCodecPlayer::getFrame() {
132
0
    SkASSERT(fTotalDuration > 0 || fImages.size() == 1);
133
134
0
    return fTotalDuration > 0
135
0
        ? this->getFrameAt(fCurrIndex)
136
0
        : fImages.front();
137
0
}
138
139
0
bool SkAnimCodecPlayer::seek(uint32_t msec) {
140
0
    if (!fTotalDuration) {
141
0
        return false;
142
0
    }
143
144
0
    msec %= fTotalDuration;
145
146
0
    auto lower = std::lower_bound(fFrameInfos.begin(), fFrameInfos.end(), msec,
147
0
                                  [](const SkCodec::FrameInfo& info, uint32_t msec) {
148
0
                                      return (uint32_t)info.fDuration <= msec;
149
0
                                  });
150
0
    int prevIndex = fCurrIndex;
151
0
    fCurrIndex = lower - fFrameInfos.begin();
152
0
    return fCurrIndex != prevIndex;
153
0
}
154
155