1 | /* |
2 | * Copyright 2015 The Android Open Source Project |
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 | #ifndef SkCodecPriv_DEFINED |
9 | #define SkCodecPriv_DEFINED |
10 | |
11 | #include "include/codec/SkEncodedOrigin.h" |
12 | #include "include/core/SkImageInfo.h" |
13 | #include "include/core/SkTypes.h" |
14 | #include "include/private/SkColorData.h" |
15 | #include "include/private/SkEncodedInfo.h" |
16 | #include "src/codec/SkColorTable.h" |
17 | |
18 | #ifdef SK_PRINT_CODEC_MESSAGES |
19 | #define SkCodecPrintf SkDebugf |
20 | #else |
21 | #define SkCodecPrintf(...) |
22 | #endif |
23 | |
24 | // Defined in SkCodec.cpp |
25 | bool sk_select_xform_format(SkColorType colorType, bool forColorTable, |
26 | skcms_PixelFormat* outFormat); |
27 | |
28 | // FIXME: Consider sharing with dm, nanbench, and tools. |
29 | static inline float get_scale_from_sample_size(int sampleSize) { |
30 | return 1.0f / ((float) sampleSize); |
31 | } |
32 | |
33 | static inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) { |
34 | return SkIRect::MakeSize(imageDims).contains(subset); |
35 | } |
36 | |
37 | /* |
38 | * returns a scaled dimension based on the original dimension and the sampleSize |
39 | * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder |
40 | * FIXME: I think we should call this get_sampled_dimension(). |
41 | */ |
42 | static inline int get_scaled_dimension(int srcDimension, int sampleSize) { |
43 | if (sampleSize > srcDimension) { |
44 | return 1; |
45 | } |
46 | return srcDimension / sampleSize; |
47 | } |
48 | |
49 | /* |
50 | * Returns the first coordinate that we will keep during a scaled decode. |
51 | * The output can be interpreted as an x-coordinate or a y-coordinate. |
52 | * |
53 | * This does not need to be called and is not called when sampleFactor == 1. |
54 | */ |
55 | static inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; }; |
56 | |
57 | /* |
58 | * Given a coordinate in the original image, this returns the corresponding |
59 | * coordinate in the scaled image. This function is meaningless if |
60 | * IsCoordNecessary returns false. |
61 | * The output can be interpreted as an x-coordinate or a y-coordinate. |
62 | * |
63 | * This does not need to be called and is not called when sampleFactor == 1. |
64 | */ |
65 | static inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; }; |
66 | |
67 | /* |
68 | * When scaling, we will discard certain y-coordinates (rows) and |
69 | * x-coordinates (columns). This function returns true if we should keep the |
70 | * coordinate and false otherwise. |
71 | * The inputs may be x-coordinates or y-coordinates. |
72 | * |
73 | * This does not need to be called and is not called when sampleFactor == 1. |
74 | */ |
75 | static inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) { |
76 | // Get the first coordinate that we want to keep |
77 | int startCoord = get_start_coord(sampleFactor); |
78 | |
79 | // Return false on edge cases |
80 | if (srcCoord < startCoord || get_dst_coord(srcCoord, sampleFactor) >= scaledDim) { |
81 | return false; |
82 | } |
83 | |
84 | // Every sampleFactor rows are necessary |
85 | return ((srcCoord - startCoord) % sampleFactor) == 0; |
86 | } |
87 | |
88 | static inline bool valid_alpha(SkAlphaType dstAlpha, bool srcIsOpaque) { |
89 | if (kUnknown_SkAlphaType == dstAlpha) { |
90 | return false; |
91 | } |
92 | |
93 | if (srcIsOpaque) { |
94 | if (kOpaque_SkAlphaType != dstAlpha) { |
95 | SkCodecPrintf("Warning: an opaque image should be decoded as opaque " |
96 | "- it is being decoded as non-opaque, which will draw slower\n" ); |
97 | } |
98 | return true; |
99 | } |
100 | |
101 | return dstAlpha != kOpaque_SkAlphaType; |
102 | } |
103 | |
104 | /* |
105 | * If there is a color table, get a pointer to the colors, otherwise return nullptr |
106 | */ |
107 | static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) { |
108 | return nullptr != colorTable ? colorTable->readColors() : nullptr; |
109 | } |
110 | |
111 | /* |
112 | * Compute row bytes for an image using pixels per byte |
113 | */ |
114 | static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) { |
115 | return (width + pixelsPerByte - 1) / pixelsPerByte; |
116 | } |
117 | |
118 | /* |
119 | * Compute row bytes for an image using bytes per pixel |
120 | */ |
121 | static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) { |
122 | return width * bytesPerPixel; |
123 | } |
124 | |
125 | /* |
126 | * Compute row bytes for an image |
127 | */ |
128 | static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) { |
129 | if (bitsPerPixel < 16) { |
130 | SkASSERT(0 == 8 % bitsPerPixel); |
131 | const uint32_t pixelsPerByte = 8 / bitsPerPixel; |
132 | return compute_row_bytes_ppb(width, pixelsPerByte); |
133 | } else { |
134 | SkASSERT(0 == bitsPerPixel % 8); |
135 | const uint32_t bytesPerPixel = bitsPerPixel / 8; |
136 | return compute_row_bytes_bpp(width, bytesPerPixel); |
137 | } |
138 | } |
139 | |
140 | /* |
141 | * Get a byte from a buffer |
142 | * This method is unsafe, the caller is responsible for performing a check |
143 | */ |
144 | static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) { |
145 | return buffer[i]; |
146 | } |
147 | |
148 | /* |
149 | * Get a short from a buffer |
150 | * This method is unsafe, the caller is responsible for performing a check |
151 | */ |
152 | static inline uint16_t get_short(uint8_t* buffer, uint32_t i) { |
153 | uint16_t result; |
154 | memcpy(&result, &(buffer[i]), 2); |
155 | #ifdef SK_CPU_BENDIAN |
156 | return SkEndianSwap16(result); |
157 | #else |
158 | return result; |
159 | #endif |
160 | } |
161 | |
162 | /* |
163 | * Get an int from a buffer |
164 | * This method is unsafe, the caller is responsible for performing a check |
165 | */ |
166 | static inline uint32_t get_int(uint8_t* buffer, uint32_t i) { |
167 | uint32_t result; |
168 | memcpy(&result, &(buffer[i]), 4); |
169 | #ifdef SK_CPU_BENDIAN |
170 | return SkEndianSwap32(result); |
171 | #else |
172 | return result; |
173 | #endif |
174 | } |
175 | |
176 | /* |
177 | * @param data Buffer to read bytes from |
178 | * @param isLittleEndian Output parameter |
179 | * Indicates if the data is little endian |
180 | * Is unaffected on false returns |
181 | */ |
182 | static inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) { |
183 | // II indicates Intel (little endian) and MM indicates motorola (big endian). |
184 | if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) { |
185 | return false; |
186 | } |
187 | |
188 | *isLittleEndian = ('I' == data[0]); |
189 | return true; |
190 | } |
191 | |
192 | static inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) { |
193 | if (littleEndian) { |
194 | return (data[1] << 8) | (data[0]); |
195 | } |
196 | |
197 | return (data[0] << 8) | (data[1]); |
198 | } |
199 | |
200 | static inline SkPMColor premultiply_argb_as_rgba(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { |
201 | if (a != 255) { |
202 | r = SkMulDiv255Round(r, a); |
203 | g = SkMulDiv255Round(g, a); |
204 | b = SkMulDiv255Round(b, a); |
205 | } |
206 | |
207 | return SkPackARGB_as_RGBA(a, r, g, b); |
208 | } |
209 | |
210 | static inline SkPMColor premultiply_argb_as_bgra(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { |
211 | if (a != 255) { |
212 | r = SkMulDiv255Round(r, a); |
213 | g = SkMulDiv255Round(g, a); |
214 | b = SkMulDiv255Round(b, a); |
215 | } |
216 | |
217 | return SkPackARGB_as_BGRA(a, r, g, b); |
218 | } |
219 | |
220 | static inline bool is_rgba(SkColorType colorType) { |
221 | #ifdef SK_PMCOLOR_IS_RGBA |
222 | return (kBGRA_8888_SkColorType != colorType); |
223 | #else |
224 | return (kRGBA_8888_SkColorType == colorType); |
225 | #endif |
226 | } |
227 | |
228 | // Method for coverting to a 32 bit pixel. |
229 | typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
230 | |
231 | static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType) { |
232 | bool isRGBA = is_rgba(colorType); |
233 | if (isPremul) { |
234 | if (isRGBA) { |
235 | return &premultiply_argb_as_rgba; |
236 | } else { |
237 | return &premultiply_argb_as_bgra; |
238 | } |
239 | } else { |
240 | if (isRGBA) { |
241 | return &SkPackARGB_as_RGBA; |
242 | } else { |
243 | return &SkPackARGB_as_BGRA; |
244 | } |
245 | } |
246 | } |
247 | |
248 | bool is_orientation_marker(const uint8_t* data, size_t data_length, SkEncodedOrigin* orientation); |
249 | |
250 | #endif // SkCodecPriv_DEFINED |
251 | |