xref: /aosp_15_r20/external/skia/src/image/SkImage_Raster.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2012 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 #include "src/image/SkImage_Raster.h"
8 
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkPixelRef.h"
15 #include "include/core/SkPixmap.h"
16 #include "include/core/SkPoint.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkSurface.h"
21 #include "include/core/SkTypes.h"
22 #include "src/base/SkRectMemcpy.h"
23 #include "src/core/SkImageInfoPriv.h"
24 #include "src/core/SkImagePriv.h"
25 #include "src/image/SkImage_Base.h"
26 
27 #include <cstddef>
28 #include <cstdint>
29 #include <utility>
30 
31 class GrDirectContext;
32 class SkSurfaceProps;
33 
34 // fixes https://bug.skia.org/5096
is_not_subset(const SkBitmap & bm)35 static bool is_not_subset(const SkBitmap& bm) {
36     SkASSERT(bm.pixelRef());
37     SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height());
38     SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
39     return dim == bm.dimensions();
40 }
41 
release_data(void * addr,void * context)42 static void release_data(void* addr, void* context) {
43     SkData* data = static_cast<SkData*>(context);
44     data->unref();
45 }
46 
SkImage_Raster(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes,uint32_t id)47 SkImage_Raster::SkImage_Raster(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes,
48                                uint32_t id)
49         : SkImage_Base(info, id) {
50     void* addr = const_cast<void*>(data->data());
51 
52     fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());
53     fBitmap.setImmutable();
54 }
55 
SkImage_Raster(const SkBitmap & bm,bool bitmapMayBeMutable)56 SkImage_Raster::SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable)
57         : SkImage_Base(bm.info(),
58                     is_not_subset(bm) ? bm.getGenerationID() : (uint32_t)kNeedNewImageUniqueID)
59         , fBitmap(bm) {
60     SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
61 }
62 
~SkImage_Raster()63 SkImage_Raster::~SkImage_Raster() {}
64 
onReadPixels(GrDirectContext *,const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const65 bool SkImage_Raster::onReadPixels(GrDirectContext*,
66                                   const SkImageInfo& dstInfo,
67                                   void* dstPixels,
68                                   size_t dstRowBytes,
69                                   int srcX,
70                                   int srcY,
71                                   CachingHint) const {
72     SkBitmap shallowCopy(fBitmap);
73     return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
74 }
75 
onPeekPixels(SkPixmap * pm) const76 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
77     return fBitmap.peekPixels(pm);
78 }
79 
getROPixels(GrDirectContext *,SkBitmap * dst,CachingHint) const80 bool SkImage_Raster::getROPixels(GrDirectContext*, SkBitmap* dst, CachingHint) const {
81     *dst = fBitmap;
82     return true;
83 }
84 
onMakeSurface(skgpu::graphite::Recorder *,const SkImageInfo & info) const85 sk_sp<SkSurface> SkImage_Raster::onMakeSurface(skgpu::graphite::Recorder*,
86                                                const SkImageInfo& info) const {
87     const SkSurfaceProps* props = nullptr;
88     const size_t rowBytes = 0;
89     return SkSurfaces::Raster(info, rowBytes, props);
90 }
91 
copy_bitmap_subset(const SkBitmap & orig,const SkIRect & subset)92 static SkBitmap copy_bitmap_subset(const SkBitmap& orig, const SkIRect& subset) {
93     SkImageInfo info = orig.info().makeDimensions(subset.size());
94     SkBitmap bitmap;
95     if (!bitmap.tryAllocPixels(info)) {
96         return {};
97     }
98 
99     void* dst = bitmap.getPixels();
100     void* src = orig.getAddr(subset.x(), subset.y());
101     if (!dst || !src) {
102         SkDEBUGFAIL("SkImage_Raster::onMakeSubset with nullptr src or dst");
103         return {};
104     }
105 
106     SkRectMemcpy(dst, bitmap.rowBytes(), src, orig.rowBytes(), bitmap.rowBytes(),
107                  subset.height());
108 
109     bitmap.setImmutable();
110     return bitmap;
111 }
112 
onMakeSubset(GrDirectContext *,const SkIRect & subset) const113 sk_sp<SkImage> SkImage_Raster::onMakeSubset(GrDirectContext*, const SkIRect& subset) const {
114     SkBitmap copy = copy_bitmap_subset(fBitmap, subset);
115     if (copy.isNull()) {
116         return nullptr;
117     } else {
118         return copy.asImage();
119     }
120 }
121 
copy_mipmaps(const SkBitmap & src,SkMipmap * srcMips)122 static sk_sp<SkMipmap> copy_mipmaps(const SkBitmap& src, SkMipmap* srcMips) {
123     if (!srcMips) {
124         return nullptr;
125     }
126 
127     sk_sp<SkMipmap> dst;
128     dst.reset(SkMipmap::Build(src.pixmap(),
129                               /* factoryProc= */ nullptr,
130                               /* computeContents= */ false));
131     if (!dst) {
132         return nullptr;
133     }
134     for (int i = 0; i < dst->countLevels(); ++i) {
135         SkMipmap::Level srcLevel, dstLevel;
136         srcMips->getLevel(i, &srcLevel);
137         dst->getLevel(i, &dstLevel);
138         srcLevel.fPixmap.readPixels(dstLevel.fPixmap);
139     }
140 
141     return dst;
142 }
143 
onMakeSubset(skgpu::graphite::Recorder *,const SkIRect & subset,RequiredProperties requiredProperties) const144 sk_sp<SkImage> SkImage_Raster::onMakeSubset(skgpu::graphite::Recorder*,
145                                             const SkIRect& subset,
146                                             RequiredProperties requiredProperties) const {
147     sk_sp<SkImage> img;
148 
149     if (requiredProperties.fMipmapped) {
150         bool fullCopy = subset == SkIRect::MakeSize(fBitmap.dimensions());
151 
152         sk_sp<SkMipmap> mips = fullCopy ? copy_mipmaps(fBitmap, fBitmap.fMips.get()) : nullptr;
153 
154         // SkImage::withMipmaps will always make a copy for us so we can temporarily share
155         // the pixel ref with fBitmap
156         SkBitmap tmpSubset;
157         if (!fBitmap.extractSubset(&tmpSubset, subset)) {
158             return nullptr;
159         }
160 
161         sk_sp<SkImage> tmp(new SkImage_Raster(tmpSubset, /* bitmapMayBeMutable= */ true));
162 
163         // withMipmaps will auto generate the mipmaps if a nullptr is passed in
164         SkASSERT(!mips || mips->validForRootLevel(tmp->imageInfo()));
165         img = tmp->withMipmaps(std::move(mips));
166     } else {
167         SkBitmap copy = copy_bitmap_subset(fBitmap, subset);
168         if (!copy.isNull()) {
169             img = copy.asImage();
170         }
171     }
172 
173     return img;
174 }
175 
176 ///////////////////////////////////////////////////////////////////////////////
177 
SkMakeImageFromRasterBitmapPriv(const SkBitmap & bm,SkCopyPixelsMode cpm,uint32_t idForCopy)178 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
179                                                uint32_t idForCopy) {
180     if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
181         SkPixmap pmap;
182         if (bm.peekPixels(&pmap)) {
183             return MakeRasterCopyPriv(pmap, idForCopy);
184         } else {
185             return sk_sp<SkImage>();
186         }
187     }
188     return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
189 }
190 
SkMakeImageFromRasterBitmap(const SkBitmap & bm,SkCopyPixelsMode cpm)191 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
192     if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
193         return nullptr;
194     }
195 
196     return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
197 }
198 
SkBitmapImageGetPixelRef(const SkImage * image)199 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
200     return ((const SkImage_Raster*)image)->getPixelRef();
201 }
202 
onAsLegacyBitmap(GrDirectContext *,SkBitmap * bitmap) const203 bool SkImage_Raster::onAsLegacyBitmap(GrDirectContext*, SkBitmap* bitmap) const {
204     // When we're a snapshot from a surface, our bitmap may not be marked immutable
205     // even though logically always we are, but in that case we can't physically share our
206     // pixelref since the caller might call setImmutable() themselves
207     // (thus changing our state).
208     if (fBitmap.isImmutable()) {
209         SkIPoint origin = fBitmap.pixelRefOrigin();
210         bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
211         bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), origin.x(), origin.y());
212         return true;
213     }
214     return this->SkImage_Base::onAsLegacyBitmap(nullptr, bitmap);
215 }
216 
217 ///////////////////////////////////////////////////////////////////////////////
218 
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,GrDirectContext *) const219 sk_sp<SkImage> SkImage_Raster::onMakeColorTypeAndColorSpace(SkColorType targetCT,
220                                                             sk_sp<SkColorSpace> targetCS,
221                                                             GrDirectContext*) const {
222     SkPixmap src;
223     SkAssertResult(fBitmap.peekPixels(&src));
224 
225     SkBitmap dst;
226     if (!dst.tryAllocPixels(fBitmap.info().makeColorType(targetCT).makeColorSpace(targetCS))) {
227         return nullptr;
228     }
229 
230     SkAssertResult(dst.writePixels(src));
231     dst.setImmutable();
232     return dst.asImage();
233 }
234 
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const235 sk_sp<SkImage> SkImage_Raster::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
236     // TODO: If our bitmap is immutable, then we could theoretically create another image sharing
237     // our pixelRef. That doesn't work (without more invasive logic), because the image gets its
238     // gen ID from the bitmap, which gets it from the pixelRef.
239     SkPixmap pixmap = fBitmap.pixmap();
240     pixmap.setColorSpace(std::move(newCS));
241     return SkImages::RasterFromPixmapCopy(pixmap);
242 }
243