Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/image/SkImage_Base.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2023 Google LLC
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 "src/image/SkImage_Base.h"
9
10
#include "include/core/SkBitmap.h"
11
#include "include/core/SkColorSpace.h"
12
#include "include/core/SkColorType.h"
13
#include "include/core/SkImage.h"
14
#include "include/core/SkImageInfo.h"
15
#include "include/core/SkPixmap.h"
16
#include "include/core/SkRect.h"
17
#include "include/core/SkSize.h"
18
#include "include/core/SkTypes.h"
19
#include "include/private/base/SkDebug.h"
20
#include "src/core/SkBitmapCache.h"
21
#include "src/core/SkColorSpacePriv.h"
22
#include "src/image/SkRescaleAndReadPixels.h"
23
24
#include <atomic>
25
#include <utility>
26
27
SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
28
447k
        : SkImage(info, uniqueID), fAddedToRasterCache(false) {}
29
30
447k
SkImage_Base::~SkImage_Base() {
31
447k
    if (fAddedToRasterCache.load()) {
32
5.27k
        SkNotifyBitmapGenIDIsStale(this->uniqueID());
33
5.27k
    }
34
447k
}
35
36
void SkImage_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
37
                                               SkIRect origSrcRect,
38
                                               RescaleGamma rescaleGamma,
39
                                               RescaleMode rescaleMode,
40
                                               ReadPixelsCallback callback,
41
0
                                               ReadPixelsContext context) const {
42
0
    SkBitmap src;
43
0
    SkPixmap peek;
44
0
    SkIRect srcRect;
45
0
    if (this->peekPixels(&peek)) {
46
0
        src.installPixels(peek);
47
0
        srcRect = origSrcRect;
48
0
    } else {
49
        // Context TODO: Elevate GrDirectContext requirement to public API.
50
0
        auto dContext = as_IB(this)->directContext();
51
0
        src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
52
0
        src.allocPixels();
53
0
        if (!this->readPixels(dContext, src.pixmap(), origSrcRect.x(), origSrcRect.y())) {
54
0
            callback(context, nullptr);
55
0
            return;
56
0
        }
57
0
        srcRect = SkIRect::MakeSize(src.dimensions());
58
0
    }
59
0
    return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleMode, callback, context);
60
0
}
61
62
0
bool SkImage_Base::onAsLegacyBitmap(GrDirectContext* dContext, SkBitmap* bitmap) const {
63
    // As the base-class, all we can do is make a copy (regardless of mode).
64
    // Subclasses that want to be more optimal should override.
65
0
    SkImageInfo info = fInfo.makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
66
0
    if (!bitmap->tryAllocPixels(info)) {
67
0
        return false;
68
0
    }
69
70
0
    if (!this->readPixels(
71
0
                dContext, bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
72
0
        bitmap->reset();
73
0
        return false;
74
0
    }
75
76
0
    bitmap->setImmutable();
77
0
    return true;
78
0
}
79
80
25.2k
sk_sp<SkImage> SkImage_Base::makeSubset(GrDirectContext* direct, const SkIRect& subset) const {
81
25.2k
    if (subset.isEmpty()) {
82
2.98k
        return nullptr;
83
2.98k
    }
84
85
22.2k
    const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
86
22.2k
    if (!bounds.contains(subset)) {
87
1.69k
        return nullptr;
88
1.69k
    }
89
90
    // optimization : return self if the subset == our bounds
91
20.5k
    if (bounds == subset) {
92
71
        return sk_ref_sp(const_cast<SkImage_Base*>(this));
93
71
    }
94
95
20.4k
    return this->onMakeSubset(direct, subset);
96
20.5k
}
97
98
sk_sp<SkImage> SkImage_Base::makeSubset(skgpu::graphite::Recorder* recorder,
99
                                        const SkIRect& subset,
100
0
                                        RequiredProperties requiredProps) const {
101
0
    if (subset.isEmpty()) {
102
0
        return nullptr;
103
0
    }
104
105
0
    const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
106
0
    if (!bounds.contains(subset)) {
107
0
        return nullptr;
108
0
    }
109
110
0
    return this->onMakeSubset(recorder, subset, requiredProps);
111
0
}
112
113
void SkImage_Base::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,
114
                                                     bool readAlpha,
115
                                                     sk_sp<SkColorSpace> dstColorSpace,
116
                                                     SkIRect srcRect,
117
                                                     SkISize dstSize,
118
                                                     RescaleGamma,
119
                                                     RescaleMode,
120
                                                     ReadPixelsCallback callback,
121
0
                                                     ReadPixelsContext context) const {
122
    // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
123
    // call client's callback.
124
0
    callback(context, nullptr);
125
0
}
126
127
sk_sp<SkImage> SkImage_Base::makeColorSpace(GrDirectContext* direct,
128
0
                                            sk_sp<SkColorSpace> target) const {
129
0
    return this->makeColorTypeAndColorSpace(direct, this->colorType(), std::move(target));
130
0
}
131
132
sk_sp<SkImage> SkImage_Base::makeColorSpace(skgpu::graphite::Recorder* recorder,
133
                                            sk_sp<SkColorSpace> target,
134
0
                                            RequiredProperties props) const {
135
0
    return this->makeColorTypeAndColorSpace(recorder, this->colorType(), std::move(target), props);
136
0
}
137
138
sk_sp<SkImage> SkImage_Base::makeColorTypeAndColorSpace(GrDirectContext* dContext,
139
                                                        SkColorType targetColorType,
140
0
                                                        sk_sp<SkColorSpace> targetCS) const {
141
0
    if (kUnknown_SkColorType == targetColorType || !targetCS) {
142
0
        return nullptr;
143
0
    }
144
145
0
    SkColorType colorType = this->colorType();
146
0
    SkColorSpace* colorSpace = this->colorSpace();
147
0
    if (!colorSpace) {
148
0
        colorSpace = sk_srgb_singleton();
149
0
    }
150
0
    if (colorType == targetColorType &&
151
0
        (SkColorSpace::Equals(colorSpace, targetCS.get()) || this->isAlphaOnly())) {
152
0
        return sk_ref_sp(const_cast<SkImage_Base*>(this));
153
0
    }
154
155
0
    return this->onMakeColorTypeAndColorSpace(targetColorType, std::move(targetCS), dContext);
156
0
}
157
158
sk_sp<SkImage> SkImage_Base::makeColorTypeAndColorSpace(skgpu::graphite::Recorder*,
159
                                                        SkColorType ct,
160
                                                        sk_sp<SkColorSpace> cs,
161
0
                                                        RequiredProperties) const {
162
    // Default to the ganesh version which should be backend agnostic if this
163
    // image is, for example, a raster backed image. The graphite subclass overrides
164
    // this method and things work correctly.
165
0
    return this->makeColorTypeAndColorSpace(nullptr, ct, std::move(cs));
166
0
}