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
SkImage_Base(const SkImageInfo & info,uint32_t uniqueID)27 SkImage_Base::SkImage_Base(const SkImageInfo& info, uint32_t uniqueID)
28 : SkImage(info, uniqueID), fAddedToRasterCache(false) {}
29
~SkImage_Base()30 SkImage_Base::~SkImage_Base() {
31 if (fAddedToRasterCache.load()) {
32 SkNotifyBitmapGenIDIsStale(this->uniqueID());
33 }
34 }
35
onAsyncRescaleAndReadPixels(const SkImageInfo & info,SkIRect origSrcRect,RescaleGamma rescaleGamma,RescaleMode rescaleMode,ReadPixelsCallback callback,ReadPixelsContext context) const36 void SkImage_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
37 SkIRect origSrcRect,
38 RescaleGamma rescaleGamma,
39 RescaleMode rescaleMode,
40 ReadPixelsCallback callback,
41 ReadPixelsContext context) const {
42 SkBitmap src;
43 SkPixmap peek;
44 SkIRect srcRect;
45 if (this->peekPixels(&peek)) {
46 src.installPixels(peek);
47 srcRect = origSrcRect;
48 } else {
49 // Context TODO: Elevate GrDirectContext requirement to public API.
50 auto dContext = as_IB(this)->directContext();
51 src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
52 src.allocPixels();
53 if (!this->readPixels(dContext, src.pixmap(), origSrcRect.x(), origSrcRect.y())) {
54 callback(context, nullptr);
55 return;
56 }
57 srcRect = SkIRect::MakeSize(src.dimensions());
58 }
59 return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleMode, callback, context);
60 }
61
onAsLegacyBitmap(GrDirectContext * dContext,SkBitmap * bitmap) const62 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 SkImageInfo info = fInfo.makeColorType(kN32_SkColorType).makeColorSpace(nullptr);
66 if (!bitmap->tryAllocPixels(info)) {
67 return false;
68 }
69
70 if (!this->readPixels(
71 dContext, bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
72 bitmap->reset();
73 return false;
74 }
75
76 bitmap->setImmutable();
77 return true;
78 }
79
makeSubset(GrDirectContext * direct,const SkIRect & subset) const80 sk_sp<SkImage> SkImage_Base::makeSubset(GrDirectContext* direct, const SkIRect& subset) const {
81 if (subset.isEmpty()) {
82 return nullptr;
83 }
84
85 const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
86 if (!bounds.contains(subset)) {
87 return nullptr;
88 }
89
90 // optimization : return self if the subset == our bounds
91 if (bounds == subset) {
92 return sk_ref_sp(const_cast<SkImage_Base*>(this));
93 }
94
95 return this->onMakeSubset(direct, subset);
96 }
97
makeSubset(skgpu::graphite::Recorder * recorder,const SkIRect & subset,RequiredProperties requiredProps) const98 sk_sp<SkImage> SkImage_Base::makeSubset(skgpu::graphite::Recorder* recorder,
99 const SkIRect& subset,
100 RequiredProperties requiredProps) const {
101 if (subset.isEmpty()) {
102 return nullptr;
103 }
104
105 const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height());
106 if (!bounds.contains(subset)) {
107 return nullptr;
108 }
109
110 return this->onMakeSubset(recorder, subset, requiredProps);
111 }
112
onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,bool readAlpha,sk_sp<SkColorSpace> dstColorSpace,SkIRect srcRect,SkISize dstSize,RescaleGamma,RescaleMode,ReadPixelsCallback callback,ReadPixelsContext context) const113 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 ReadPixelsContext context) const {
122 // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
123 // call client's callback.
124 callback(context, nullptr);
125 }
126
makeColorSpace(GrDirectContext * direct,sk_sp<SkColorSpace> target) const127 sk_sp<SkImage> SkImage_Base::makeColorSpace(GrDirectContext* direct,
128 sk_sp<SkColorSpace> target) const {
129 return this->makeColorTypeAndColorSpace(direct, this->colorType(), std::move(target));
130 }
131
makeColorSpace(skgpu::graphite::Recorder * recorder,sk_sp<SkColorSpace> target,RequiredProperties props) const132 sk_sp<SkImage> SkImage_Base::makeColorSpace(skgpu::graphite::Recorder* recorder,
133 sk_sp<SkColorSpace> target,
134 RequiredProperties props) const {
135 return this->makeColorTypeAndColorSpace(recorder, this->colorType(), std::move(target), props);
136 }
137
makeColorTypeAndColorSpace(GrDirectContext * dContext,SkColorType targetColorType,sk_sp<SkColorSpace> targetCS) const138 sk_sp<SkImage> SkImage_Base::makeColorTypeAndColorSpace(GrDirectContext* dContext,
139 SkColorType targetColorType,
140 sk_sp<SkColorSpace> targetCS) const {
141 if (kUnknown_SkColorType == targetColorType || !targetCS) {
142 return nullptr;
143 }
144
145 SkColorType colorType = this->colorType();
146 SkColorSpace* colorSpace = this->colorSpace();
147 if (!colorSpace) {
148 colorSpace = sk_srgb_singleton();
149 }
150 if (colorType == targetColorType &&
151 (SkColorSpace::Equals(colorSpace, targetCS.get()) || this->isAlphaOnly())) {
152 return sk_ref_sp(const_cast<SkImage_Base*>(this));
153 }
154
155 return this->onMakeColorTypeAndColorSpace(targetColorType, std::move(targetCS), dContext);
156 }
157
makeColorTypeAndColorSpace(skgpu::graphite::Recorder *,SkColorType ct,sk_sp<SkColorSpace> cs,RequiredProperties) const158 sk_sp<SkImage> SkImage_Base::makeColorTypeAndColorSpace(skgpu::graphite::Recorder*,
159 SkColorType ct,
160 sk_sp<SkColorSpace> cs,
161 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 return this->makeColorTypeAndColorSpace(nullptr, ct, std::move(cs));
166 }
167