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 | |
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 | } |
37 | SkUNREACHABLE; |
38 | } |
39 | |
40 | bool SkColorTypeIsAlwaysOpaque(SkColorType ct) { |
41 | return !(SkColorTypeChannelFlags(ct) & kAlpha_SkColorChannelFlag); |
42 | } |
43 | |
44 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
45 | |
46 | int SkColorInfo::bytesPerPixel() const { return SkColorTypeBytesPerPixel(fColorType); } |
47 | |
48 | int SkColorInfo::shiftPerPixel() const { return SkColorTypeShiftPerPixel(fColorType); } |
49 | |
50 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
51 | |
52 | size_t SkImageInfo::computeOffset(int x, int y, size_t rowBytes) const { |
53 | SkASSERT((unsigned)x < (unsigned)this->width()); |
54 | SkASSERT((unsigned)y < (unsigned)this->height()); |
55 | return SkColorTypeComputeOffset(this->colorType(), x, y, rowBytes); |
56 | } |
57 | |
58 | size_t SkImageInfo::computeByteSize(size_t rowBytes) const { |
59 | if (0 == this->height()) { |
60 | return 0; |
61 | } |
62 | SkSafeMath safe; |
63 | size_t bytes = safe.add(safe.mul(safe.addInt(this->height(), -1), rowBytes), |
64 | safe.mul(this->width(), this->bytesPerPixel())); |
65 | return safe.ok() ? bytes : SIZE_MAX; |
66 | } |
67 | |
68 | SkImageInfo SkImageInfo::MakeS32(int width, int height, SkAlphaType at) { |
69 | return SkImageInfo({width, height}, {kN32_SkColorType, at, SkColorSpace::MakeSRGB()}); |
70 | } |
71 | |
72 | #ifdef SK_DEBUG |
73 | void SkImageInfo::validate() const { |
74 | SkASSERT(fDimensions.width() >= 0); |
75 | SkASSERT(fDimensions.height() >= 0); |
76 | SkASSERT(SkColorTypeIsValid(this->colorType())); |
77 | SkASSERT(SkAlphaTypeIsValid(this->alphaType())); |
78 | } |
79 | #endif |
80 | |
81 | bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, |
82 | SkAlphaType* canonical) { |
83 | switch (colorType) { |
84 | case kUnknown_SkColorType: |
85 | alphaType = kUnknown_SkAlphaType; |
86 | break; |
87 | case kAlpha_8_SkColorType: // fall-through |
88 | case kA16_unorm_SkColorType: // fall-through |
89 | case kA16_float_SkColorType: |
90 | if (kUnpremul_SkAlphaType == alphaType) { |
91 | alphaType = kPremul_SkAlphaType; |
92 | } |
93 | // fall-through |
94 | case kARGB_4444_SkColorType: |
95 | case kRGBA_8888_SkColorType: |
96 | case kBGRA_8888_SkColorType: |
97 | case kRGBA_1010102_SkColorType: |
98 | case kBGRA_1010102_SkColorType: |
99 | case kRGBA_F16Norm_SkColorType: |
100 | case kRGBA_F16_SkColorType: |
101 | case kRGBA_F32_SkColorType: |
102 | case kR16G16B16A16_unorm_SkColorType: |
103 | if (kUnknown_SkAlphaType == alphaType) { |
104 | return false; |
105 | } |
106 | break; |
107 | case kGray_8_SkColorType: |
108 | case kR8G8_unorm_SkColorType: |
109 | case kR16G16_unorm_SkColorType: |
110 | case kR16G16_float_SkColorType: |
111 | case kRGB_565_SkColorType: |
112 | case kRGB_888x_SkColorType: |
113 | case kRGB_101010x_SkColorType: |
114 | case kBGR_101010x_SkColorType: |
115 | alphaType = kOpaque_SkAlphaType; |
116 | break; |
117 | } |
118 | if (canonical) { |
119 | *canonical = alphaType; |
120 | } |
121 | return true; |
122 | } |
123 | |
124 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
125 | |
126 | #include "src/image/SkReadPixelsRec.h" |
127 | |
128 | bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) { |
129 | if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) { |
130 | return false; |
131 | } |
132 | if (0 >= fInfo.width() || 0 >= fInfo.height()) { |
133 | return false; |
134 | } |
135 | |
136 | int x = fX; |
137 | int y = fY; |
138 | SkIRect srcR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height()); |
139 | if (!srcR.intersect({0, 0, srcWidth, srcHeight})) { |
140 | return false; |
141 | } |
142 | |
143 | // if x or y are negative, then we have to adjust pixels |
144 | if (x > 0) { |
145 | x = 0; |
146 | } |
147 | if (y > 0) { |
148 | y = 0; |
149 | } |
150 | // here x,y are either 0 or negative |
151 | // we negate and add them so UBSAN (pointer-overflow) doesn't get confused. |
152 | fPixels = ((char*)fPixels + -y*fRowBytes + -x*fInfo.bytesPerPixel()); |
153 | // the intersect may have shrunk info's logical size |
154 | fInfo = fInfo.makeDimensions(srcR.size()); |
155 | fX = srcR.x(); |
156 | fY = srcR.y(); |
157 | |
158 | return true; |
159 | } |
160 | |
161 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
162 | |
163 | #include "src/core/SkWritePixelsRec.h" |
164 | |
165 | bool SkWritePixelsRec::trim(int dstWidth, int dstHeight) { |
166 | if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) { |
167 | return false; |
168 | } |
169 | if (0 >= fInfo.width() || 0 >= fInfo.height()) { |
170 | return false; |
171 | } |
172 | |
173 | int x = fX; |
174 | int y = fY; |
175 | SkIRect dstR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height()); |
176 | if (!dstR.intersect({0, 0, dstWidth, dstHeight})) { |
177 | return false; |
178 | } |
179 | |
180 | // if x or y are negative, then we have to adjust pixels |
181 | if (x > 0) { |
182 | x = 0; |
183 | } |
184 | if (y > 0) { |
185 | y = 0; |
186 | } |
187 | // here x,y are either 0 or negative |
188 | // we negate and add them so UBSAN (pointer-overflow) doesn't get confused. |
189 | fPixels = ((const char*)fPixels + -y*fRowBytes + -x*fInfo.bytesPerPixel()); |
190 | // the intersect may have shrunk info's logical size |
191 | fInfo = fInfo.makeDimensions(dstR.size()); |
192 | fX = dstR.x(); |
193 | fY = dstR.y(); |
194 | |
195 | return true; |
196 | } |
197 | |