1 /*
2 * Copyright 2010 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
8 #include "include/private/SkImageInfoPriv.h"
9 #include "src/core/SkReadBuffer.h"
10 #include "src/core/SkSafeMath.h"
11 #include "src/core/SkWriteBuffer.h"
12
SkColorTypeBytesPerPixel(SkColorType ct)13 int SkColorTypeBytesPerPixel(SkColorType ct) {
14 switch (ct) {
15 case kUnknown_SkColorType: return 0;
16 case kAlpha_8_SkColorType: return 1;
17 case kRGB_565_SkColorType: return 2;
18 case kARGB_4444_SkColorType: return 2;
19 case kRGBA_8888_SkColorType: return 4;
20 case kBGRA_8888_SkColorType: return 4;
21 case kRGB_888x_SkColorType: return 4;
22 case kRGBA_1010102_SkColorType: return 4;
23 case kRGB_101010x_SkColorType: return 4;
24 case kBGRA_1010102_SkColorType: return 4;
25 case kBGR_101010x_SkColorType: return 4;
26 case kGray_8_SkColorType: return 1;
27 case kRGBA_F16Norm_SkColorType: return 8;
28 case kRGBA_F16_SkColorType: return 8;
29 case kRGBA_F32_SkColorType: return 16;
30 case kR8G8_unorm_SkColorType: return 2;
31 case kA16_unorm_SkColorType: return 2;
32 case kR16G16_unorm_SkColorType: return 4;
33 case kA16_float_SkColorType: return 2;
34 case kR16G16_float_SkColorType: return 4;
35 case kR16G16B16A16_unorm_SkColorType: return 8;
36 case kSRGBA_8888_SkColorType: return 4;
37 case kR8_unorm_SkColorType: return 1;
38 }
39 SkUNREACHABLE;
40 }
41
SkColorTypeIsAlwaysOpaque(SkColorType ct)42 bool SkColorTypeIsAlwaysOpaque(SkColorType ct) {
43 return !(SkColorTypeChannelFlags(ct) & kAlpha_SkColorChannelFlag);
44 }
45
46 ///////////////////////////////////////////////////////////////////////////////////////////////////
47
bytesPerPixel() const48 int SkColorInfo::bytesPerPixel() const { return SkColorTypeBytesPerPixel(fColorType); }
49
shiftPerPixel() const50 int SkColorInfo::shiftPerPixel() const { return SkColorTypeShiftPerPixel(fColorType); }
51
52 ///////////////////////////////////////////////////////////////////////////////////////////////////
53
computeOffset(int x,int y,size_t rowBytes) const54 size_t SkImageInfo::computeOffset(int x, int y, size_t rowBytes) const {
55 SkASSERT((unsigned)x < (unsigned)this->width());
56 SkASSERT((unsigned)y < (unsigned)this->height());
57 return SkColorTypeComputeOffset(this->colorType(), x, y, rowBytes);
58 }
59
computeByteSize(size_t rowBytes) const60 size_t SkImageInfo::computeByteSize(size_t rowBytes) const {
61 if (0 == this->height()) {
62 return 0;
63 }
64 SkSafeMath safe;
65 size_t bytes = safe.add(safe.mul(safe.addInt(this->height(), -1), rowBytes),
66 safe.mul(this->width(), this->bytesPerPixel()));
67
68 // The CPU backend implements some memory operations on images using instructions that take a
69 // signed 32-bit offset from the base. If we ever make an image larger than that, overflow can
70 // cause us to read/write memory that starts 2GB *before* the buffer. (crbug.com/1264705)
71 constexpr size_t kMaxSigned32BitSize = SK_MaxS32;
72 return (safe.ok() && (bytes <= kMaxSigned32BitSize)) ? bytes : SIZE_MAX;
73 }
74
MakeS32(int width,int height,SkAlphaType at)75 SkImageInfo SkImageInfo::MakeS32(int width, int height, SkAlphaType at) {
76 return SkImageInfo({width, height}, {kN32_SkColorType, at, SkColorSpace::MakeSRGB()});
77 }
78
79 #ifdef SK_DEBUG
validate() const80 void SkImageInfo::validate() const {
81 SkASSERT(fDimensions.width() >= 0);
82 SkASSERT(fDimensions.height() >= 0);
83 SkASSERT(SkColorTypeIsValid(this->colorType()));
84 SkASSERT(SkAlphaTypeIsValid(this->alphaType()));
85 }
86 #endif
87
SkColorTypeValidateAlphaType(SkColorType colorType,SkAlphaType alphaType,SkAlphaType * canonical)88 bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType,
89 SkAlphaType* canonical) {
90 switch (colorType) {
91 case kUnknown_SkColorType:
92 alphaType = kUnknown_SkAlphaType;
93 break;
94 case kAlpha_8_SkColorType: // fall-through
95 case kA16_unorm_SkColorType: // fall-through
96 case kA16_float_SkColorType:
97 if (kUnpremul_SkAlphaType == alphaType) {
98 alphaType = kPremul_SkAlphaType;
99 }
100 [[fallthrough]];
101 case kARGB_4444_SkColorType:
102 case kRGBA_8888_SkColorType:
103 case kSRGBA_8888_SkColorType:
104 case kBGRA_8888_SkColorType:
105 case kRGBA_1010102_SkColorType:
106 case kBGRA_1010102_SkColorType:
107 case kRGBA_F16Norm_SkColorType:
108 case kRGBA_F16_SkColorType:
109 case kRGBA_F32_SkColorType:
110 case kR16G16B16A16_unorm_SkColorType:
111 if (kUnknown_SkAlphaType == alphaType) {
112 return false;
113 }
114 break;
115 case kGray_8_SkColorType:
116 case kR8G8_unorm_SkColorType:
117 case kR16G16_unorm_SkColorType:
118 case kR16G16_float_SkColorType:
119 case kRGB_565_SkColorType:
120 case kRGB_888x_SkColorType:
121 case kRGB_101010x_SkColorType:
122 case kBGR_101010x_SkColorType:
123 case kR8_unorm_SkColorType:
124 alphaType = kOpaque_SkAlphaType;
125 break;
126 }
127 if (canonical) {
128 *canonical = alphaType;
129 }
130 return true;
131 }
132
133 ///////////////////////////////////////////////////////////////////////////////////////////////////
134
135 #include "src/image/SkReadPixelsRec.h"
136
trim(int srcWidth,int srcHeight)137 bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) {
138 if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) {
139 return false;
140 }
141 if (0 >= fInfo.width() || 0 >= fInfo.height()) {
142 return false;
143 }
144
145 int x = fX;
146 int y = fY;
147 SkIRect srcR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height());
148 if (!srcR.intersect({0, 0, srcWidth, srcHeight})) {
149 return false;
150 }
151
152 // if x or y are negative, then we have to adjust pixels
153 if (x > 0) {
154 x = 0;
155 }
156 if (y > 0) {
157 y = 0;
158 }
159 // here x,y are either 0 or negative
160 // we negate and add them so UBSAN (pointer-overflow) doesn't get confused.
161 fPixels = ((char*)fPixels + -y*fRowBytes + -x*fInfo.bytesPerPixel());
162 // the intersect may have shrunk info's logical size
163 fInfo = fInfo.makeDimensions(srcR.size());
164 fX = srcR.x();
165 fY = srcR.y();
166
167 return true;
168 }
169
170 ///////////////////////////////////////////////////////////////////////////////////////////////////
171
172 #include "src/core/SkWritePixelsRec.h"
173
trim(int dstWidth,int dstHeight)174 bool SkWritePixelsRec::trim(int dstWidth, int dstHeight) {
175 if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) {
176 return false;
177 }
178 if (0 >= fInfo.width() || 0 >= fInfo.height()) {
179 return false;
180 }
181
182 int x = fX;
183 int y = fY;
184 SkIRect dstR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height());
185 if (!dstR.intersect({0, 0, dstWidth, dstHeight})) {
186 return false;
187 }
188
189 // if x or y are negative, then we have to adjust pixels
190 if (x > 0) {
191 x = 0;
192 }
193 if (y > 0) {
194 y = 0;
195 }
196 // here x,y are either 0 or negative
197 // we negate and add them so UBSAN (pointer-overflow) doesn't get confused.
198 fPixels = ((const char*)fPixels + -y*fRowBytes + -x*fInfo.bytesPerPixel());
199 // the intersect may have shrunk info's logical size
200 fInfo = fInfo.makeDimensions(dstR.size());
201 fX = dstR.x();
202 fY = dstR.y();
203
204 return true;
205 }
206