xref: /aosp_15_r20/external/skia/src/image/SkImage_RasterFactories.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 "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColorType.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkPixmap.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/private/base/SkMath.h"
17 #include "src/core/SkCompressedDataUtils.h"
18 #include "src/core/SkImageFilterTypes.h"
19 #include "src/core/SkImageFilter_Base.h"
20 #include "src/core/SkImagePriv.h"
21 #include "src/image/SkImage_Base.h"
22 #include "src/image/SkImage_Raster.h"
23 
24 #include <cstddef>
25 #include <cstdint>
26 #include <utility>
27 
28 class SkImageFilter;
29 struct SkIPoint;
30 struct SkIRect;
31 enum class SkTextureCompressionType;
32 
valid_args(const SkImageInfo & info,size_t rowBytes,size_t * minSize)33 static bool valid_args(const SkImageInfo& info, size_t rowBytes, size_t* minSize) {
34     const int maxDimension = SK_MaxS32 >> 2;
35 
36     // TODO(mtklein): eliminate anything here that setInfo() has already checked.
37     SkBitmap b;
38     if (!b.setInfo(info, rowBytes)) {
39         return false;
40     }
41 
42     if (info.width() <= 0 || info.height() <= 0) {
43         return false;
44     }
45     if (info.width() > maxDimension || info.height() > maxDimension) {
46         return false;
47     }
48     if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
49         return false;
50     }
51     if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
52         return false;
53     }
54 
55     if (kUnknown_SkColorType == info.colorType()) {
56         return false;
57     }
58     if (!info.validRowBytes(rowBytes)) {
59         return false;
60     }
61 
62     size_t size = info.computeByteSize(rowBytes);
63     if (SkImageInfo::ByteSizeOverflowed(size)) {
64         return false;
65     }
66 
67     if (minSize) {
68         *minSize = size;
69     }
70     return true;
71 }
72 
73 namespace SkImages {
RasterFromBitmap(const SkBitmap & bm)74 sk_sp<SkImage> RasterFromBitmap(const SkBitmap& bm) {
75     if (!bm.pixelRef()) {
76         return nullptr;
77     }
78 
79     return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode);
80 }
81 
RasterFromPixmapCopy(const SkPixmap & pmap)82 sk_sp<SkImage> RasterFromPixmapCopy(const SkPixmap& pmap) {
83     return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
84 }
85 
RasterFromData(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes)86 sk_sp<SkImage> RasterFromData(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes) {
87     size_t size;
88     if (!valid_args(info, rowBytes, &size) || !data) {
89         return nullptr;
90     }
91 
92     // did they give us enough data?
93     if (data->size() < size) {
94         return nullptr;
95     }
96 
97     return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
98 }
99 
MakeWithFilter(sk_sp<SkImage> src,const SkImageFilter * filter,const SkIRect & subset,const SkIRect & clipBounds,SkIRect * outSubset,SkIPoint * offset)100 sk_sp<SkImage> MakeWithFilter(sk_sp<SkImage> src,
101                               const SkImageFilter* filter,
102                               const SkIRect& subset,
103                               const SkIRect& clipBounds,
104                               SkIRect* outSubset,
105                               SkIPoint* offset) {
106     if (!src || !filter) {
107         return nullptr;
108     }
109 
110     sk_sp<skif::Backend> backend = skif::MakeRasterBackend({}, src->colorType());
111     return as_IFB(filter)->makeImageWithFilter(std::move(backend),
112                                                std::move(src),
113                                                subset,
114                                                clipBounds,
115                                                outSubset,
116                                                offset);
117 }
118 
119 // TODO: this could be improved to decode and make use of the mipmap
120 // levels potentially present in the compressed data. For now, any
121 // mipmap levels are discarded.
RasterFromCompressedTextureData(sk_sp<SkData> data,int width,int height,SkTextureCompressionType type)122 sk_sp<SkImage> RasterFromCompressedTextureData(sk_sp<SkData> data,
123                                                int width,
124                                                int height,
125                                                SkTextureCompressionType type) {
126     size_t expectedSize = SkCompressedFormatDataSize(type, {width, height}, false);
127     if (!data || data->size() < expectedSize) {
128         return nullptr;
129     }
130 
131     SkAlphaType at =
132             SkTextureCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
133 
134     SkImageInfo ii = SkImageInfo::MakeN32(width, height, at);
135 
136     if (!valid_args(ii, ii.minRowBytes(), nullptr)) {
137         return nullptr;
138     }
139 
140     SkBitmap bitmap;
141     if (!bitmap.tryAllocPixels(ii)) {
142         return nullptr;
143     }
144 
145     if (!SkDecompress(std::move(data), {width, height}, type, &bitmap)) {
146         return nullptr;
147     }
148 
149     bitmap.setImmutable();
150     return RasterFromBitmap(bitmap);
151 }
152 
RasterFromPixmap(const SkPixmap & pmap,RasterReleaseProc proc,ReleaseContext ctx)153 sk_sp<SkImage> RasterFromPixmap(const SkPixmap& pmap, RasterReleaseProc proc, ReleaseContext ctx) {
154     size_t size;
155     if (!valid_args(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
156         return nullptr;
157     }
158 
159     sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
160     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
161 }
162 
163 }  // namespace SkImages
164 
MakeRasterCopyPriv(const SkPixmap & pmap,uint32_t id)165 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
166     size_t size;
167     if (!valid_args(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
168         return nullptr;
169     }
170 
171     // Here we actually make a copy of the caller's pixel data
172     sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
173     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
174 }
175