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