blob: a13cdbba92c56a00083c3a98435dcaac61108bb3 [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"
msarettf7eb6fc2016-09-13 09:04:11 -070012#include "SkColorSpaceXform.h"
msarett9e43cab2015-04-29 07:38:43 -070013#include "SkColorTable.h"
Matt Sarett1a85ca52016-11-04 11:52:48 -040014#include "SkEncodedInfo.h"
msarett74114382015-03-16 11:55:18 -070015#include "SkImageInfo.h"
msarett74114382015-03-16 11:55:18 -070016#include "SkTypes.h"
17
scroggoc5560be2016-02-03 09:42:42 -080018#ifdef SK_PRINT_CODEC_MESSAGES
19 #define SkCodecPrintf SkDebugf
20#else
21 #define SkCodecPrintf(...)
22#endif
23
msarett3d9d7a72015-10-21 10:27:10 -070024// FIXME: Consider sharing with dm, nanbench, and tools.
msarettd1ec89b2016-08-03 12:59:27 -070025static inline float get_scale_from_sample_size(int sampleSize) {
msarett3d9d7a72015-10-21 10:27:10 -070026 return 1.0f / ((float) sampleSize);
27}
28
msarettd1ec89b2016-08-03 12:59:27 -070029static inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) {
msarett3d9d7a72015-10-21 10:27:10 -070030 return SkIRect::MakeSize(imageDims).contains(subset);
31}
32
msarett5406d6f2015-08-31 06:55:13 -070033/*
msarett10522ff2015-09-07 08:54:01 -070034 * returns a scaled dimension based on the original dimension and the sampleSize
35 * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder
msarett3d9d7a72015-10-21 10:27:10 -070036 * FIXME: I think we should call this get_sampled_dimension().
msarett10522ff2015-09-07 08:54:01 -070037 */
msarettd1ec89b2016-08-03 12:59:27 -070038static inline int get_scaled_dimension(int srcDimension, int sampleSize) {
msarett10522ff2015-09-07 08:54:01 -070039 if (sampleSize > srcDimension) {
40 return 1;
41 }
42 return srcDimension / sampleSize;
43}
44
45/*
msarett5406d6f2015-08-31 06:55:13 -070046 * Returns the first coordinate that we will keep during a scaled decode.
47 * The output can be interpreted as an x-coordinate or a y-coordinate.
48 *
49 * This does not need to be called and is not called when sampleFactor == 1.
50 */
msarettd1ec89b2016-08-03 12:59:27 -070051static inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; };
msarett5406d6f2015-08-31 06:55:13 -070052
53/*
54 * Given a coordinate in the original image, this returns the corresponding
55 * coordinate in the scaled image. This function is meaningless if
56 * IsCoordNecessary returns false.
57 * The output can be interpreted as an x-coordinate or a y-coordinate.
58 *
59 * This does not need to be called and is not called when sampleFactor == 1.
60 */
msarettd1ec89b2016-08-03 12:59:27 -070061static inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; };
msarett5406d6f2015-08-31 06:55:13 -070062
63/*
64 * When scaling, we will discard certain y-coordinates (rows) and
65 * x-coordinates (columns). This function returns true if we should keep the
66 * coordinate and false otherwise.
67 * The inputs may be x-coordinates or y-coordinates.
68 *
69 * This does not need to be called and is not called when sampleFactor == 1.
70 */
msarettd1ec89b2016-08-03 12:59:27 -070071static inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) {
msarett5406d6f2015-08-31 06:55:13 -070072 // Get the first coordinate that we want to keep
73 int startCoord = get_start_coord(sampleFactor);
74
75 // Return false on edge cases
76 if (srcCoord < startCoord || get_dst_coord(srcCoord, sampleFactor) >= scaledDim) {
77 return false;
78 }
79
80 // Every sampleFactor rows are necessary
81 return ((srcCoord - startCoord) % sampleFactor) == 0;
82}
83
msarettd1ec89b2016-08-03 12:59:27 -070084static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080085 if (kUnknown_SkAlphaType == dstAlpha) {
86 return false;
87 }
88
msarett4ab9d5f2015-08-06 15:34:42 -070089 if (srcAlpha != dstAlpha) {
90 if (kOpaque_SkAlphaType == srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080091 // If the source is opaque, we can support any.
92 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
93 "- it is being decoded as non-opaque, which will draw slower\n");
94 return true;
msarett4ab9d5f2015-08-06 15:34:42 -070095 }
96
97 // The source is not opaque
98 switch (dstAlpha) {
99 case kPremul_SkAlphaType:
100 case kUnpremul_SkAlphaType:
101 // The source is not opaque, so either of these is okay
102 break;
103 default:
104 // We cannot decode a non-opaque image to opaque (or unknown)
105 return false;
106 }
107 }
108 return true;
109}
110
msarett74114382015-03-16 11:55:18 -0700111/*
msarett2ecc35f2016-09-08 11:55:16 -0700112 * Original version of conversion_possible that does not account for color spaces.
113 * Used by codecs that have not been updated to support color spaces.
114 *
scroggocc2feb12015-08-14 08:32:46 -0700115 * Most of our codecs support the same conversions:
scroggoc5560be2016-02-03 09:42:42 -0800116 * - opaque to any alpha type
117 * - 565 only if opaque
scroggocc2feb12015-08-14 08:32:46 -0700118 * - premul to unpremul and vice versa
msarett2ecc35f2016-09-08 11:55:16 -0700119 * - always support RGBA, BGRA
scroggocc2feb12015-08-14 08:32:46 -0700120 * - otherwise match the src color type
121 */
msarett2ecc35f2016-09-08 11:55:16 -0700122static inline bool conversion_possible_ignore_color_space(const SkImageInfo& dst,
123 const SkImageInfo& src) {
scroggocc2feb12015-08-14 08:32:46 -0700124 // Ensure the alpha type is valid
125 if (!valid_alpha(dst.alphaType(), src.alphaType())) {
126 return false;
127 }
128
129 // Check for supported color types
130 switch (dst.colorType()) {
msarett34e0ec42016-04-22 16:27:24 -0700131 case kRGBA_8888_SkColorType:
132 case kBGRA_8888_SkColorType:
scroggocc2feb12015-08-14 08:32:46 -0700133 return true;
134 case kRGB_565_SkColorType:
scroggoba584892016-05-20 13:56:13 -0700135 return kOpaque_SkAlphaType == src.alphaType();
scroggocc2feb12015-08-14 08:32:46 -0700136 default:
137 return dst.colorType() == src.colorType();
138 }
139}
140
141/*
halcanary96fcdcc2015-08-27 07:41:13 -0700142 * If there is a color table, get a pointer to the colors, otherwise return nullptr
msarett99f567e2015-08-05 12:58:26 -0700143 */
msarettd1ec89b2016-08-03 12:59:27 -0700144static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700145 return nullptr != colorTable ? colorTable->readColors() : nullptr;
msarett99f567e2015-08-05 12:58:26 -0700146}
147
msarettc0444612016-09-16 11:45:58 -0700148static inline SkColorSpaceXform::ColorFormat select_xform_format(SkColorType colorType) {
149 switch (colorType) {
150 case kRGBA_8888_SkColorType:
151 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
152 case kBGRA_8888_SkColorType:
153 return SkColorSpaceXform::kBGRA_8888_ColorFormat;
154 case kRGBA_F16_SkColorType:
155 return SkColorSpaceXform::kRGBA_F16_ColorFormat;
Matt Sarett1a85ca52016-11-04 11:52:48 -0400156 case kIndex_8_SkColorType:
157#ifdef SK_PMCOLOR_IS_RGBA
158 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
159#else
160 return SkColorSpaceXform::kBGRA_8888_ColorFormat;
161#endif
msarettc0444612016-09-16 11:45:58 -0700162 default:
163 SkASSERT(false);
164 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
165 }
166}
167
msarett99f567e2015-08-05 12:58:26 -0700168/*
msarette6dd0042015-10-09 11:07:34 -0700169 * Given that the encoded image uses a color table, return the fill value
170 */
msarettcf7b8772016-09-22 12:37:04 -0700171static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAlphaType alphaType,
msarettf7eb6fc2016-09-13 09:04:11 -0700172 const SkPMColor* colorPtr, uint8_t fillIndex, SkColorSpaceXform* colorXform) {
msarette6dd0042015-10-09 11:07:34 -0700173 SkASSERT(nullptr != colorPtr);
msarettcf7b8772016-09-22 12:37:04 -0700174 switch (dstColorType) {
msarett34e0ec42016-04-22 16:27:24 -0700175 case kRGBA_8888_SkColorType:
176 case kBGRA_8888_SkColorType:
msarette6dd0042015-10-09 11:07:34 -0700177 return colorPtr[fillIndex];
178 case kRGB_565_SkColorType:
179 return SkPixel32ToPixel16(colorPtr[fillIndex]);
180 case kIndex_8_SkColorType:
181 return fillIndex;
msarettf7eb6fc2016-09-13 09:04:11 -0700182 case kRGBA_F16_SkColorType: {
183 SkASSERT(colorXform);
184 uint64_t dstColor;
185 uint32_t srcColor = colorPtr[fillIndex];
msarett31d097e82016-10-11 12:15:03 -0700186 SkAssertResult(colorXform->apply(select_xform_format(dstColorType), &dstColor,
187 SkColorSpaceXform::kRGBA_8888_ColorFormat, &srcColor, 1, alphaType));
msarettf7eb6fc2016-09-13 09:04:11 -0700188 return dstColor;
189 }
msarette6dd0042015-10-09 11:07:34 -0700190 default:
191 SkASSERT(false);
192 return 0;
193 }
194}
195
196/*
msarett74114382015-03-16 11:55:18 -0700197 *
msarett9e43cab2015-04-29 07:38:43 -0700198 * Copy the codec color table back to the client when kIndex8 color type is requested
msarett9e43cab2015-04-29 07:38:43 -0700199 */
msarettd1ec89b2016-08-03 12:59:27 -0700200static inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
msarett9e43cab2015-04-29 07:38:43 -0700201 SkPMColor* inputColorPtr, int* inputColorCount) {
202 if (kIndex_8_SkColorType == dstInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700203 SkASSERT(nullptr != inputColorPtr);
204 SkASSERT(nullptr != inputColorCount);
205 SkASSERT(nullptr != colorTable);
msarett10522ff2015-09-07 08:54:01 -0700206 memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor));
msarett9e43cab2015-04-29 07:38:43 -0700207 }
208}
209
210/*
msarett74114382015-03-16 11:55:18 -0700211 * Compute row bytes for an image using pixels per byte
msarett74114382015-03-16 11:55:18 -0700212 */
msarettd1ec89b2016-08-03 12:59:27 -0700213static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
msarett74114382015-03-16 11:55:18 -0700214 return (width + pixelsPerByte - 1) / pixelsPerByte;
215}
216
217/*
msarett74114382015-03-16 11:55:18 -0700218 * Compute row bytes for an image using bytes per pixel
msarett74114382015-03-16 11:55:18 -0700219 */
msarettd1ec89b2016-08-03 12:59:27 -0700220static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
msarett74114382015-03-16 11:55:18 -0700221 return width * bytesPerPixel;
222}
223
224/*
msarett74114382015-03-16 11:55:18 -0700225 * Compute row bytes for an image
msarett74114382015-03-16 11:55:18 -0700226 */
msarettd1ec89b2016-08-03 12:59:27 -0700227static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
msarett74114382015-03-16 11:55:18 -0700228 if (bitsPerPixel < 16) {
229 SkASSERT(0 == 8 % bitsPerPixel);
230 const uint32_t pixelsPerByte = 8 / bitsPerPixel;
231 return compute_row_bytes_ppb(width, pixelsPerByte);
232 } else {
233 SkASSERT(0 == bitsPerPixel % 8);
234 const uint32_t bytesPerPixel = bitsPerPixel / 8;
235 return compute_row_bytes_bpp(width, bytesPerPixel);
236 }
237}
238
239/*
msarett74114382015-03-16 11:55:18 -0700240 * Get a byte from a buffer
241 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700242 */
msarettd1ec89b2016-08-03 12:59:27 -0700243static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700244 return buffer[i];
245}
246
247/*
msarett74114382015-03-16 11:55:18 -0700248 * Get a short from a buffer
249 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700250 */
msarettd1ec89b2016-08-03 12:59:27 -0700251static inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700252 uint16_t result;
253 memcpy(&result, &(buffer[i]), 2);
254#ifdef SK_CPU_BENDIAN
255 return SkEndianSwap16(result);
256#else
257 return result;
258#endif
259}
260
261/*
msarett74114382015-03-16 11:55:18 -0700262 * Get an int from a buffer
263 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700264 */
msarettd1ec89b2016-08-03 12:59:27 -0700265static inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700266 uint32_t result;
267 memcpy(&result, &(buffer[i]), 4);
268#ifdef SK_CPU_BENDIAN
269 return SkEndianSwap32(result);
270#else
271 return result;
272#endif
273}
274
msarett0e6274f2016-03-21 08:04:40 -0700275/*
276 * @param data Buffer to read bytes from
277 * @param isLittleEndian Output parameter
278 * Indicates if the data is little endian
279 * Is unaffected on false returns
280 */
msarettd1ec89b2016-08-03 12:59:27 -0700281static inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700282 // II indicates Intel (little endian) and MM indicates motorola (big endian).
283 if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) {
284 return false;
285 }
286
287 *isLittleEndian = ('I' == data[0]);
288 return true;
289}
290
msarettd1ec89b2016-08-03 12:59:27 -0700291static inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700292 if (littleEndian) {
293 return (data[1] << 8) | (data[0]);
294 }
295
296 return (data[0] << 8) | (data[1]);
297}
298
msarettd1ec89b2016-08-03 12:59:27 -0700299static inline SkPMColor premultiply_argb_as_rgba(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700300 if (a != 255) {
301 r = SkMulDiv255Round(r, a);
302 g = SkMulDiv255Round(g, a);
303 b = SkMulDiv255Round(b, a);
304 }
305
306 return SkPackARGB_as_RGBA(a, r, g, b);
307}
308
msarettd1ec89b2016-08-03 12:59:27 -0700309static inline SkPMColor premultiply_argb_as_bgra(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700310 if (a != 255) {
311 r = SkMulDiv255Round(r, a);
312 g = SkMulDiv255Round(g, a);
313 b = SkMulDiv255Round(b, a);
314 }
315
316 return SkPackARGB_as_BGRA(a, r, g, b);
317}
318
msarettd1ec89b2016-08-03 12:59:27 -0700319static inline bool is_rgba(SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700320#ifdef SK_PMCOLOR_IS_RGBA
321 return (kBGRA_8888_SkColorType != colorType);
322#else
323 return (kRGBA_8888_SkColorType == colorType);
324#endif
325}
326
327// Method for coverting to a 32 bit pixel.
328typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
329
msarettd1ec89b2016-08-03 12:59:27 -0700330static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700331 bool isRGBA = is_rgba(colorType);
332 if (isPremul) {
333 if (isRGBA) {
334 return &premultiply_argb_as_rgba;
335 } else {
336 return &premultiply_argb_as_bgra;
337 }
338 } else {
339 if (isRGBA) {
340 return &SkPackARGB_as_RGBA;
341 } else {
342 return &SkPackARGB_as_BGRA;
343 }
344 }
345}
346
msarettdcd5e652016-08-22 08:48:40 -0700347static inline bool needs_premul(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
348 return kPremul_SkAlphaType == dstInfo.alphaType() &&
349 kUnpremul_SkAlphaType == srcInfo.alphaType();
350}
351
msarettd1ec89b2016-08-03 12:59:27 -0700352static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
msarettdcd5e652016-08-22 08:48:40 -0700353 // Color xform is necessary in order to correctly perform premultiply in linear space.
354 bool needsPremul = needs_premul(dstInfo, srcInfo);
355
356 // F16 is by definition a linear space, so we always must perform a color xform.
357 bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType();
358
359 // Need a color xform when dst space does not match the src.
360 bool srcDstNotEqual = !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace());
361
362 // We never perform a color xform in legacy mode.
363 bool isLegacy = nullptr == dstInfo.colorSpace();
364
365 return !isLegacy && (needsPremul || isF16 || srcDstNotEqual);
msarettd1ec89b2016-08-03 12:59:27 -0700366}
367
msarettc0444612016-09-16 11:45:58 -0700368static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) {
msarette99883f2016-09-08 06:05:35 -0700369 return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType;
370}
371
Matt Sarett1a85ca52016-11-04 11:52:48 -0400372static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) {
373 // We will apply the color xform when reading the color table, unless F16 is requested.
374 return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
375}
376
msarett2ecc35f2016-09-08 11:55:16 -0700377/*
378 * Alpha Type Conversions
379 * - kOpaque to kOpaque, kUnpremul, kPremul is valid
380 * - kUnpremul to kUnpremul, kPremul is valid
381 *
382 * Color Type Conversions
383 * - Always support kRGBA_8888, kBGRA_8888
384 * - Support kRGBA_F16 when there is a linear dst color space
385 * - Support kIndex8 if it matches the src
386 * - Support k565 if kOpaque and color correction is not required
387 * - Support k565 if it matches the src, kOpaque, and color correction is not required
388 */
389static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
390 // Ensure the alpha type is valid.
391 if (!valid_alpha(dst.alphaType(), src.alphaType())) {
392 return false;
393 }
394
395 // Check for supported color types.
396 switch (dst.colorType()) {
397 case kRGBA_8888_SkColorType:
398 case kBGRA_8888_SkColorType:
399 return true;
400 case kRGBA_F16_SkColorType:
401 return dst.colorSpace() && dst.colorSpace()->gammaIsLinear();
402 case kIndex_8_SkColorType:
403 return kIndex_8_SkColorType == src.colorType();
404 case kRGB_565_SkColorType:
405 return kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src);
406 case kGray_8_SkColorType:
407 return kGray_8_SkColorType == src.colorType() &&
408 kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src);
409 default:
410 return false;
411 }
412}
413
msarett74114382015-03-16 11:55:18 -0700414#endif // SkCodecPriv_DEFINED