blob: b768b23a8aed63356981fd12dcea9f42d3d4b3d1 [file] [log] [blame]
msarett74114382015-03-16 11:55:18 -07001/*
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
msarette6dd0042015-10-09 11:07:34 -070011#include "SkColorPriv.h"
msarett9e43cab2015-04-29 07:38:43 -070012#include "SkColorTable.h"
msarett74114382015-03-16 11:55:18 -070013#include "SkImageInfo.h"
msarett74114382015-03-16 11:55:18 -070014#include "SkTypes.h"
15
scroggoc5560be2016-02-03 09:42:42 -080016#ifdef SK_PRINT_CODEC_MESSAGES
17 #define SkCodecPrintf SkDebugf
18#else
19 #define SkCodecPrintf(...)
20#endif
21
msarett3d9d7a72015-10-21 10:27:10 -070022// FIXME: Consider sharing with dm, nanbench, and tools.
msarettd1ec89b2016-08-03 12:59:27 -070023static inline float get_scale_from_sample_size(int sampleSize) {
msarett3d9d7a72015-10-21 10:27:10 -070024 return 1.0f / ((float) sampleSize);
25}
26
msarettd1ec89b2016-08-03 12:59:27 -070027static inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) {
msarett3d9d7a72015-10-21 10:27:10 -070028 return SkIRect::MakeSize(imageDims).contains(subset);
29}
30
msarett5406d6f2015-08-31 06:55:13 -070031/*
msarett10522ff2015-09-07 08:54:01 -070032 * returns a scaled dimension based on the original dimension and the sampleSize
33 * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder
msarett3d9d7a72015-10-21 10:27:10 -070034 * FIXME: I think we should call this get_sampled_dimension().
msarett10522ff2015-09-07 08:54:01 -070035 */
msarettd1ec89b2016-08-03 12:59:27 -070036static inline int get_scaled_dimension(int srcDimension, int sampleSize) {
msarett10522ff2015-09-07 08:54:01 -070037 if (sampleSize > srcDimension) {
38 return 1;
39 }
40 return srcDimension / sampleSize;
41}
42
43/*
msarett5406d6f2015-08-31 06:55:13 -070044 * Returns the first coordinate that we will keep during a scaled decode.
45 * The output can be interpreted as an x-coordinate or a y-coordinate.
46 *
47 * This does not need to be called and is not called when sampleFactor == 1.
48 */
msarettd1ec89b2016-08-03 12:59:27 -070049static inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; };
msarett5406d6f2015-08-31 06:55:13 -070050
51/*
52 * Given a coordinate in the original image, this returns the corresponding
53 * coordinate in the scaled image. This function is meaningless if
54 * IsCoordNecessary returns false.
55 * The output can be interpreted as an x-coordinate or a y-coordinate.
56 *
57 * This does not need to be called and is not called when sampleFactor == 1.
58 */
msarettd1ec89b2016-08-03 12:59:27 -070059static inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; };
msarett5406d6f2015-08-31 06:55:13 -070060
61/*
62 * When scaling, we will discard certain y-coordinates (rows) and
63 * x-coordinates (columns). This function returns true if we should keep the
64 * coordinate and false otherwise.
65 * The inputs may be x-coordinates or y-coordinates.
66 *
67 * This does not need to be called and is not called when sampleFactor == 1.
68 */
msarettd1ec89b2016-08-03 12:59:27 -070069static inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) {
msarett5406d6f2015-08-31 06:55:13 -070070 // Get the first coordinate that we want to keep
71 int startCoord = get_start_coord(sampleFactor);
72
73 // Return false on edge cases
74 if (srcCoord < startCoord || get_dst_coord(srcCoord, sampleFactor) >= scaledDim) {
75 return false;
76 }
77
78 // Every sampleFactor rows are necessary
79 return ((srcCoord - startCoord) % sampleFactor) == 0;
80}
81
msarettd1ec89b2016-08-03 12:59:27 -070082static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080083 if (kUnknown_SkAlphaType == dstAlpha) {
84 return false;
85 }
86
msarett4ab9d5f2015-08-06 15:34:42 -070087 if (srcAlpha != dstAlpha) {
88 if (kOpaque_SkAlphaType == srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080089 // If the source is opaque, we can support any.
90 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
91 "- it is being decoded as non-opaque, which will draw slower\n");
92 return true;
msarett4ab9d5f2015-08-06 15:34:42 -070093 }
94
95 // The source is not opaque
96 switch (dstAlpha) {
97 case kPremul_SkAlphaType:
98 case kUnpremul_SkAlphaType:
99 // The source is not opaque, so either of these is okay
100 break;
101 default:
102 // We cannot decode a non-opaque image to opaque (or unknown)
103 return false;
104 }
105 }
106 return true;
107}
108
msarett74114382015-03-16 11:55:18 -0700109/*
scroggocc2feb12015-08-14 08:32:46 -0700110 * Most of our codecs support the same conversions:
scroggoc5560be2016-02-03 09:42:42 -0800111 * - opaque to any alpha type
112 * - 565 only if opaque
scroggocc2feb12015-08-14 08:32:46 -0700113 * - premul to unpremul and vice versa
114 * - always support N32
115 * - otherwise match the src color type
116 */
msarettd1ec89b2016-08-03 12:59:27 -0700117static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
scroggocc2feb12015-08-14 08:32:46 -0700118 // Ensure the alpha type is valid
119 if (!valid_alpha(dst.alphaType(), src.alphaType())) {
120 return false;
121 }
122
123 // Check for supported color types
124 switch (dst.colorType()) {
msarett34e0ec42016-04-22 16:27:24 -0700125 case kRGBA_8888_SkColorType:
126 case kBGRA_8888_SkColorType:
scroggocc2feb12015-08-14 08:32:46 -0700127 return true;
128 case kRGB_565_SkColorType:
scroggoba584892016-05-20 13:56:13 -0700129 return kOpaque_SkAlphaType == src.alphaType();
scroggocc2feb12015-08-14 08:32:46 -0700130 default:
131 return dst.colorType() == src.colorType();
132 }
133}
134
135/*
halcanary96fcdcc2015-08-27 07:41:13 -0700136 * If there is a color table, get a pointer to the colors, otherwise return nullptr
msarett99f567e2015-08-05 12:58:26 -0700137 */
msarettd1ec89b2016-08-03 12:59:27 -0700138static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700139 return nullptr != colorTable ? colorTable->readColors() : nullptr;
msarett99f567e2015-08-05 12:58:26 -0700140}
141
142/*
msarette6dd0042015-10-09 11:07:34 -0700143 * Given that the encoded image uses a color table, return the fill value
144 */
msarettd1ec89b2016-08-03 12:59:27 -0700145static inline uint32_t get_color_table_fill_value(SkColorType colorType, const SkPMColor* colorPtr,
msarette6dd0042015-10-09 11:07:34 -0700146 uint8_t fillIndex) {
147 SkASSERT(nullptr != colorPtr);
148 switch (colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700149 case kRGBA_8888_SkColorType:
150 case kBGRA_8888_SkColorType:
msarette6dd0042015-10-09 11:07:34 -0700151 return colorPtr[fillIndex];
152 case kRGB_565_SkColorType:
153 return SkPixel32ToPixel16(colorPtr[fillIndex]);
154 case kIndex_8_SkColorType:
155 return fillIndex;
156 default:
157 SkASSERT(false);
158 return 0;
159 }
160}
161
162/*
msarett74114382015-03-16 11:55:18 -0700163 *
msarett9e43cab2015-04-29 07:38:43 -0700164 * Copy the codec color table back to the client when kIndex8 color type is requested
msarett9e43cab2015-04-29 07:38:43 -0700165 */
msarettd1ec89b2016-08-03 12:59:27 -0700166static inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
msarett9e43cab2015-04-29 07:38:43 -0700167 SkPMColor* inputColorPtr, int* inputColorCount) {
168 if (kIndex_8_SkColorType == dstInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700169 SkASSERT(nullptr != inputColorPtr);
170 SkASSERT(nullptr != inputColorCount);
171 SkASSERT(nullptr != colorTable);
msarett10522ff2015-09-07 08:54:01 -0700172 memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor));
msarett9e43cab2015-04-29 07:38:43 -0700173 }
174}
175
176/*
msarett74114382015-03-16 11:55:18 -0700177 * Compute row bytes for an image using pixels per byte
msarett74114382015-03-16 11:55:18 -0700178 */
msarettd1ec89b2016-08-03 12:59:27 -0700179static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
msarett74114382015-03-16 11:55:18 -0700180 return (width + pixelsPerByte - 1) / pixelsPerByte;
181}
182
183/*
msarett74114382015-03-16 11:55:18 -0700184 * Compute row bytes for an image using bytes per pixel
msarett74114382015-03-16 11:55:18 -0700185 */
msarettd1ec89b2016-08-03 12:59:27 -0700186static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
msarett74114382015-03-16 11:55:18 -0700187 return width * bytesPerPixel;
188}
189
190/*
msarett74114382015-03-16 11:55:18 -0700191 * Compute row bytes for an image
msarett74114382015-03-16 11:55:18 -0700192 */
msarettd1ec89b2016-08-03 12:59:27 -0700193static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
msarett74114382015-03-16 11:55:18 -0700194 if (bitsPerPixel < 16) {
195 SkASSERT(0 == 8 % bitsPerPixel);
196 const uint32_t pixelsPerByte = 8 / bitsPerPixel;
197 return compute_row_bytes_ppb(width, pixelsPerByte);
198 } else {
199 SkASSERT(0 == bitsPerPixel % 8);
200 const uint32_t bytesPerPixel = bitsPerPixel / 8;
201 return compute_row_bytes_bpp(width, bytesPerPixel);
202 }
203}
204
205/*
msarett74114382015-03-16 11:55:18 -0700206 * Get a byte from a buffer
207 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700208 */
msarettd1ec89b2016-08-03 12:59:27 -0700209static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700210 return buffer[i];
211}
212
213/*
msarett74114382015-03-16 11:55:18 -0700214 * Get a short from a buffer
215 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700216 */
msarettd1ec89b2016-08-03 12:59:27 -0700217static inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700218 uint16_t result;
219 memcpy(&result, &(buffer[i]), 2);
220#ifdef SK_CPU_BENDIAN
221 return SkEndianSwap16(result);
222#else
223 return result;
224#endif
225}
226
227/*
msarett74114382015-03-16 11:55:18 -0700228 * Get an int from a buffer
229 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700230 */
msarettd1ec89b2016-08-03 12:59:27 -0700231static inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700232 uint32_t result;
233 memcpy(&result, &(buffer[i]), 4);
234#ifdef SK_CPU_BENDIAN
235 return SkEndianSwap32(result);
236#else
237 return result;
238#endif
239}
240
msarett0e6274f2016-03-21 08:04:40 -0700241/*
242 * @param data Buffer to read bytes from
243 * @param isLittleEndian Output parameter
244 * Indicates if the data is little endian
245 * Is unaffected on false returns
246 */
msarettd1ec89b2016-08-03 12:59:27 -0700247static inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700248 // II indicates Intel (little endian) and MM indicates motorola (big endian).
249 if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) {
250 return false;
251 }
252
253 *isLittleEndian = ('I' == data[0]);
254 return true;
255}
256
msarettd1ec89b2016-08-03 12:59:27 -0700257static inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700258 if (littleEndian) {
259 return (data[1] << 8) | (data[0]);
260 }
261
262 return (data[0] << 8) | (data[1]);
263}
264
msarettd1ec89b2016-08-03 12:59:27 -0700265static inline SkPMColor premultiply_argb_as_rgba(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700266 if (a != 255) {
267 r = SkMulDiv255Round(r, a);
268 g = SkMulDiv255Round(g, a);
269 b = SkMulDiv255Round(b, a);
270 }
271
272 return SkPackARGB_as_RGBA(a, r, g, b);
273}
274
msarettd1ec89b2016-08-03 12:59:27 -0700275static inline SkPMColor premultiply_argb_as_bgra(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700276 if (a != 255) {
277 r = SkMulDiv255Round(r, a);
278 g = SkMulDiv255Round(g, a);
279 b = SkMulDiv255Round(b, a);
280 }
281
282 return SkPackARGB_as_BGRA(a, r, g, b);
283}
284
msarettd1ec89b2016-08-03 12:59:27 -0700285static inline bool is_rgba(SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700286#ifdef SK_PMCOLOR_IS_RGBA
287 return (kBGRA_8888_SkColorType != colorType);
288#else
289 return (kRGBA_8888_SkColorType == colorType);
290#endif
291}
292
293// Method for coverting to a 32 bit pixel.
294typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
295
msarettd1ec89b2016-08-03 12:59:27 -0700296static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700297 bool isRGBA = is_rgba(colorType);
298 if (isPremul) {
299 if (isRGBA) {
300 return &premultiply_argb_as_rgba;
301 } else {
302 return &premultiply_argb_as_bgra;
303 }
304 } else {
305 if (isRGBA) {
306 return &SkPackARGB_as_RGBA;
307 } else {
308 return &SkPackARGB_as_BGRA;
309 }
310 }
311}
312
msarettd1ec89b2016-08-03 12:59:27 -0700313static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
314 return (kRGBA_F16_SkColorType == dstInfo.colorType()) ||
315 (dstInfo.colorSpace() && !SkColorSpace::Equals(srcInfo.colorSpace(),
316 dstInfo.colorSpace()));
317}
318
msarett74114382015-03-16 11:55:18 -0700319#endif // SkCodecPriv_DEFINED