xref: /aosp_15_r20/external/skia/src/image/SkImage_Base.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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