blob: 5bf0272f6eaafb7d0c4d114eeb8514a8a20df37d [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"
Matt Sarett909d3792016-12-22 10:52:25 -050013#include "SkColorSpaceXformPriv.h"
msarett9e43cab2015-04-29 07:38:43 -070014#include "SkColorTable.h"
Matt Sarett1a85ca52016-11-04 11:52:48 -040015#include "SkEncodedInfo.h"
msarett74114382015-03-16 11:55:18 -070016#include "SkImageInfo.h"
msarett74114382015-03-16 11:55:18 -070017#include "SkTypes.h"
18
scroggoc5560be2016-02-03 09:42:42 -080019#ifdef SK_PRINT_CODEC_MESSAGES
20 #define SkCodecPrintf SkDebugf
21#else
22 #define SkCodecPrintf(...)
23#endif
24
msarett3d9d7a72015-10-21 10:27:10 -070025// FIXME: Consider sharing with dm, nanbench, and tools.
msarettd1ec89b2016-08-03 12:59:27 -070026static inline float get_scale_from_sample_size(int sampleSize) {
msarett3d9d7a72015-10-21 10:27:10 -070027 return 1.0f / ((float) sampleSize);
28}
29
msarettd1ec89b2016-08-03 12:59:27 -070030static inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) {
msarett3d9d7a72015-10-21 10:27:10 -070031 return SkIRect::MakeSize(imageDims).contains(subset);
32}
33
msarett5406d6f2015-08-31 06:55:13 -070034/*
msarett10522ff2015-09-07 08:54:01 -070035 * returns a scaled dimension based on the original dimension and the sampleSize
36 * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder
msarett3d9d7a72015-10-21 10:27:10 -070037 * FIXME: I think we should call this get_sampled_dimension().
msarett10522ff2015-09-07 08:54:01 -070038 */
msarettd1ec89b2016-08-03 12:59:27 -070039static inline int get_scaled_dimension(int srcDimension, int sampleSize) {
msarett10522ff2015-09-07 08:54:01 -070040 if (sampleSize > srcDimension) {
41 return 1;
42 }
43 return srcDimension / sampleSize;
44}
45
46/*
msarett5406d6f2015-08-31 06:55:13 -070047 * Returns the first coordinate that we will keep during a scaled decode.
48 * The output can be interpreted as an x-coordinate or a y-coordinate.
49 *
50 * This does not need to be called and is not called when sampleFactor == 1.
51 */
msarettd1ec89b2016-08-03 12:59:27 -070052static inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; };
msarett5406d6f2015-08-31 06:55:13 -070053
54/*
55 * Given a coordinate in the original image, this returns the corresponding
56 * coordinate in the scaled image. This function is meaningless if
57 * IsCoordNecessary returns false.
58 * The output can be interpreted as an x-coordinate or a y-coordinate.
59 *
60 * This does not need to be called and is not called when sampleFactor == 1.
61 */
msarettd1ec89b2016-08-03 12:59:27 -070062static inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; };
msarett5406d6f2015-08-31 06:55:13 -070063
64/*
65 * When scaling, we will discard certain y-coordinates (rows) and
66 * x-coordinates (columns). This function returns true if we should keep the
67 * coordinate and false otherwise.
68 * The inputs may be x-coordinates or y-coordinates.
69 *
70 * This does not need to be called and is not called when sampleFactor == 1.
71 */
msarettd1ec89b2016-08-03 12:59:27 -070072static inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) {
msarett5406d6f2015-08-31 06:55:13 -070073 // Get the first coordinate that we want to keep
74 int startCoord = get_start_coord(sampleFactor);
75
76 // Return false on edge cases
77 if (srcCoord < startCoord || get_dst_coord(srcCoord, sampleFactor) >= scaledDim) {
78 return false;
79 }
80
81 // Every sampleFactor rows are necessary
82 return ((srcCoord - startCoord) % sampleFactor) == 0;
83}
84
msarettd1ec89b2016-08-03 12:59:27 -070085static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080086 if (kUnknown_SkAlphaType == dstAlpha) {
87 return false;
88 }
89
msarett4ab9d5f2015-08-06 15:34:42 -070090 if (srcAlpha != dstAlpha) {
91 if (kOpaque_SkAlphaType == srcAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080092 // If the source is opaque, we can support any.
93 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
94 "- it is being decoded as non-opaque, which will draw slower\n");
95 return true;
msarett4ab9d5f2015-08-06 15:34:42 -070096 }
97
98 // The source is not opaque
99 switch (dstAlpha) {
100 case kPremul_SkAlphaType:
101 case kUnpremul_SkAlphaType:
102 // The source is not opaque, so either of these is okay
103 break;
104 default:
105 // We cannot decode a non-opaque image to opaque (or unknown)
106 return false;
107 }
108 }
109 return true;
110}
111
msarett74114382015-03-16 11:55:18 -0700112/*
halcanary96fcdcc2015-08-27 07:41:13 -0700113 * If there is a color table, get a pointer to the colors, otherwise return nullptr
msarett99f567e2015-08-05 12:58:26 -0700114 */
msarettd1ec89b2016-08-03 12:59:27 -0700115static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700116 return nullptr != colorTable ? colorTable->readColors() : nullptr;
msarett99f567e2015-08-05 12:58:26 -0700117}
118
119/*
msarette6dd0042015-10-09 11:07:34 -0700120 * Given that the encoded image uses a color table, return the fill value
121 */
msarettcf7b8772016-09-22 12:37:04 -0700122static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAlphaType alphaType,
msarettf7eb6fc2016-09-13 09:04:11 -0700123 const SkPMColor* colorPtr, uint8_t fillIndex, SkColorSpaceXform* colorXform) {
msarette6dd0042015-10-09 11:07:34 -0700124 SkASSERT(nullptr != colorPtr);
msarettcf7b8772016-09-22 12:37:04 -0700125 switch (dstColorType) {
msarett34e0ec42016-04-22 16:27:24 -0700126 case kRGBA_8888_SkColorType:
127 case kBGRA_8888_SkColorType:
msarette6dd0042015-10-09 11:07:34 -0700128 return colorPtr[fillIndex];
129 case kRGB_565_SkColorType:
130 return SkPixel32ToPixel16(colorPtr[fillIndex]);
131 case kIndex_8_SkColorType:
132 return fillIndex;
msarettf7eb6fc2016-09-13 09:04:11 -0700133 case kRGBA_F16_SkColorType: {
134 SkASSERT(colorXform);
135 uint64_t dstColor;
136 uint32_t srcColor = colorPtr[fillIndex];
msarett31d097e82016-10-11 12:15:03 -0700137 SkAssertResult(colorXform->apply(select_xform_format(dstColorType), &dstColor,
138 SkColorSpaceXform::kRGBA_8888_ColorFormat, &srcColor, 1, alphaType));
msarettf7eb6fc2016-09-13 09:04:11 -0700139 return dstColor;
140 }
msarette6dd0042015-10-09 11:07:34 -0700141 default:
142 SkASSERT(false);
143 return 0;
144 }
145}
146
147/*
msarett74114382015-03-16 11:55:18 -0700148 *
msarett9e43cab2015-04-29 07:38:43 -0700149 * Copy the codec color table back to the client when kIndex8 color type is requested
msarett9e43cab2015-04-29 07:38:43 -0700150 */
msarettd1ec89b2016-08-03 12:59:27 -0700151static inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
msarett9e43cab2015-04-29 07:38:43 -0700152 SkPMColor* inputColorPtr, int* inputColorCount) {
153 if (kIndex_8_SkColorType == dstInfo.colorType()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700154 SkASSERT(nullptr != inputColorPtr);
155 SkASSERT(nullptr != inputColorCount);
156 SkASSERT(nullptr != colorTable);
msarett10522ff2015-09-07 08:54:01 -0700157 memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor));
msarett9e43cab2015-04-29 07:38:43 -0700158 }
159}
160
161/*
msarett74114382015-03-16 11:55:18 -0700162 * Compute row bytes for an image using pixels per byte
msarett74114382015-03-16 11:55:18 -0700163 */
msarettd1ec89b2016-08-03 12:59:27 -0700164static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
msarett74114382015-03-16 11:55:18 -0700165 return (width + pixelsPerByte - 1) / pixelsPerByte;
166}
167
168/*
msarett74114382015-03-16 11:55:18 -0700169 * Compute row bytes for an image using bytes per pixel
msarett74114382015-03-16 11:55:18 -0700170 */
msarettd1ec89b2016-08-03 12:59:27 -0700171static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
msarett74114382015-03-16 11:55:18 -0700172 return width * bytesPerPixel;
173}
174
175/*
msarett74114382015-03-16 11:55:18 -0700176 * Compute row bytes for an image
msarett74114382015-03-16 11:55:18 -0700177 */
msarettd1ec89b2016-08-03 12:59:27 -0700178static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
msarett74114382015-03-16 11:55:18 -0700179 if (bitsPerPixel < 16) {
180 SkASSERT(0 == 8 % bitsPerPixel);
181 const uint32_t pixelsPerByte = 8 / bitsPerPixel;
182 return compute_row_bytes_ppb(width, pixelsPerByte);
183 } else {
184 SkASSERT(0 == bitsPerPixel % 8);
185 const uint32_t bytesPerPixel = bitsPerPixel / 8;
186 return compute_row_bytes_bpp(width, bytesPerPixel);
187 }
188}
189
190/*
msarett74114382015-03-16 11:55:18 -0700191 * Get a byte from a buffer
192 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700193 */
msarettd1ec89b2016-08-03 12:59:27 -0700194static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700195 return buffer[i];
196}
197
198/*
msarett74114382015-03-16 11:55:18 -0700199 * Get a short from a buffer
200 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700201 */
msarettd1ec89b2016-08-03 12:59:27 -0700202static inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700203 uint16_t result;
204 memcpy(&result, &(buffer[i]), 2);
205#ifdef SK_CPU_BENDIAN
206 return SkEndianSwap16(result);
207#else
208 return result;
209#endif
210}
211
212/*
msarett74114382015-03-16 11:55:18 -0700213 * Get an int from a buffer
214 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700215 */
msarettd1ec89b2016-08-03 12:59:27 -0700216static inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700217 uint32_t result;
218 memcpy(&result, &(buffer[i]), 4);
219#ifdef SK_CPU_BENDIAN
220 return SkEndianSwap32(result);
221#else
222 return result;
223#endif
224}
225
msarett0e6274f2016-03-21 08:04:40 -0700226/*
227 * @param data Buffer to read bytes from
228 * @param isLittleEndian Output parameter
229 * Indicates if the data is little endian
230 * Is unaffected on false returns
231 */
msarettd1ec89b2016-08-03 12:59:27 -0700232static inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700233 // II indicates Intel (little endian) and MM indicates motorola (big endian).
234 if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) {
235 return false;
236 }
237
238 *isLittleEndian = ('I' == data[0]);
239 return true;
240}
241
msarettd1ec89b2016-08-03 12:59:27 -0700242static inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700243 if (littleEndian) {
244 return (data[1] << 8) | (data[0]);
245 }
246
247 return (data[0] << 8) | (data[1]);
248}
249
msarettd1ec89b2016-08-03 12:59:27 -0700250static inline SkPMColor premultiply_argb_as_rgba(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700251 if (a != 255) {
252 r = SkMulDiv255Round(r, a);
253 g = SkMulDiv255Round(g, a);
254 b = SkMulDiv255Round(b, a);
255 }
256
257 return SkPackARGB_as_RGBA(a, r, g, b);
258}
259
msarettd1ec89b2016-08-03 12:59:27 -0700260static inline SkPMColor premultiply_argb_as_bgra(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700261 if (a != 255) {
262 r = SkMulDiv255Round(r, a);
263 g = SkMulDiv255Round(g, a);
264 b = SkMulDiv255Round(b, a);
265 }
266
267 return SkPackARGB_as_BGRA(a, r, g, b);
268}
269
msarettd1ec89b2016-08-03 12:59:27 -0700270static inline bool is_rgba(SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700271#ifdef SK_PMCOLOR_IS_RGBA
272 return (kBGRA_8888_SkColorType != colorType);
273#else
274 return (kRGBA_8888_SkColorType == colorType);
275#endif
276}
277
278// Method for coverting to a 32 bit pixel.
279typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
280
msarettd1ec89b2016-08-03 12:59:27 -0700281static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700282 bool isRGBA = is_rgba(colorType);
283 if (isPremul) {
284 if (isRGBA) {
285 return &premultiply_argb_as_rgba;
286 } else {
287 return &premultiply_argb_as_bgra;
288 }
289 } else {
290 if (isRGBA) {
291 return &SkPackARGB_as_RGBA;
292 } else {
293 return &SkPackARGB_as_BGRA;
294 }
295 }
296}
297
Matt Sarett61eedeb2016-11-04 13:19:48 -0400298static inline bool needs_premul(const SkImageInfo& dstInfo, const SkEncodedInfo& encodedInfo) {
msarettdcd5e652016-08-22 08:48:40 -0700299 return kPremul_SkAlphaType == dstInfo.alphaType() &&
Matt Sarett61eedeb2016-11-04 13:19:48 -0400300 SkEncodedInfo::kUnpremul_Alpha == encodedInfo.alpha();
msarettdcd5e652016-08-22 08:48:40 -0700301}
302
Matt Sarett61eedeb2016-11-04 13:19:48 -0400303static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
Matt Sarettcf3f2342017-03-23 15:32:25 -0400304 bool needsColorCorrectPremul) {
Matt Sarette522f4c2017-02-22 13:02:31 -0500305 // We never perform a color xform in legacy mode.
306 if (!dstInfo.colorSpace()) {
307 return false;
308 }
309
msarettdcd5e652016-08-22 08:48:40 -0700310 // F16 is by definition a linear space, so we always must perform a color xform.
311 bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType();
312
313 // Need a color xform when dst space does not match the src.
Matt Sarette522f4c2017-02-22 13:02:31 -0500314 bool srcDstNotEqual =
315 !SkColorSpace_Base::EqualsIgnoreFlags(srcInfo.colorSpace(), dstInfo.colorSpace());
msarettdcd5e652016-08-22 08:48:40 -0700316
Matt Sarette522f4c2017-02-22 13:02:31 -0500317 return needsColorCorrectPremul || isF16 || srcDstNotEqual;
msarettd1ec89b2016-08-03 12:59:27 -0700318}
319
msarettc0444612016-09-16 11:45:58 -0700320static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) {
msarette99883f2016-09-08 06:05:35 -0700321 return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType;
322}
323
Matt Sarett1a85ca52016-11-04 11:52:48 -0400324static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) {
325 // We will apply the color xform when reading the color table, unless F16 is requested.
326 return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType;
327}
328
msarett2ecc35f2016-09-08 11:55:16 -0700329/*
330 * Alpha Type Conversions
331 * - kOpaque to kOpaque, kUnpremul, kPremul is valid
332 * - kUnpremul to kUnpremul, kPremul is valid
333 *
334 * Color Type Conversions
335 * - Always support kRGBA_8888, kBGRA_8888
336 * - Support kRGBA_F16 when there is a linear dst color space
337 * - Support kIndex8 if it matches the src
338 * - Support k565 if kOpaque and color correction is not required
339 * - Support k565 if it matches the src, kOpaque, and color correction is not required
340 */
341static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
342 // Ensure the alpha type is valid.
343 if (!valid_alpha(dst.alphaType(), src.alphaType())) {
344 return false;
345 }
346
347 // Check for supported color types.
348 switch (dst.colorType()) {
349 case kRGBA_8888_SkColorType:
350 case kBGRA_8888_SkColorType:
351 return true;
352 case kRGBA_F16_SkColorType:
353 return dst.colorSpace() && dst.colorSpace()->gammaIsLinear();
354 case kIndex_8_SkColorType:
355 return kIndex_8_SkColorType == src.colorType();
356 case kRGB_565_SkColorType:
Matt Sarett61eedeb2016-11-04 13:19:48 -0400357 return kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src, false);
msarett2ecc35f2016-09-08 11:55:16 -0700358 case kGray_8_SkColorType:
359 return kGray_8_SkColorType == src.colorType() &&
Matt Sarett61eedeb2016-11-04 13:19:48 -0400360 kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src, false);
msarett2ecc35f2016-09-08 11:55:16 -0700361 default:
362 return false;
363 }
364}
365
msarett74114382015-03-16 11:55:18 -0700366#endif // SkCodecPriv_DEFINED