blob: 84215b9fb3e20beab3bc9a08ff823fa0715fd55e [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
Cary Clarka4083c92017-09-15 11:59:23 -040011#include "SkColorData.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
Leon Scroggins III07418182017-08-15 12:24:02 -040085static inline bool valid_alpha(SkAlphaType dstAlpha, bool srcIsOpaque) {
scroggoc5560be2016-02-03 09:42:42 -080086 if (kUnknown_SkAlphaType == dstAlpha) {
87 return false;
88 }
89
Leon Scroggins III07418182017-08-15 12:24:02 -040090 if (srcIsOpaque) {
91 if (kOpaque_SkAlphaType != dstAlpha) {
scroggoc5560be2016-02-03 09:42:42 -080092 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
93 "- it is being decoded as non-opaque, which will draw slower\n");
msarett4ab9d5f2015-08-06 15:34:42 -070094 }
Leon Scroggins III07418182017-08-15 12:24:02 -040095 return true;
msarett4ab9d5f2015-08-06 15:34:42 -070096 }
Leon Scroggins III07418182017-08-15 12:24:02 -040097
98 return dstAlpha != kOpaque_SkAlphaType;
msarett4ab9d5f2015-08-06 15:34:42 -070099}
100
msarett74114382015-03-16 11:55:18 -0700101/*
halcanary96fcdcc2015-08-27 07:41:13 -0700102 * If there is a color table, get a pointer to the colors, otherwise return nullptr
msarett99f567e2015-08-05 12:58:26 -0700103 */
msarettd1ec89b2016-08-03 12:59:27 -0700104static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
halcanary96fcdcc2015-08-27 07:41:13 -0700105 return nullptr != colorTable ? colorTable->readColors() : nullptr;
msarett99f567e2015-08-05 12:58:26 -0700106}
107
108/*
msarette6dd0042015-10-09 11:07:34 -0700109 * Given that the encoded image uses a color table, return the fill value
110 */
msarettcf7b8772016-09-22 12:37:04 -0700111static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAlphaType alphaType,
Matt Sarett19aff5d2017-04-03 16:01:10 -0400112 const SkPMColor* colorPtr, uint8_t fillIndex, SkColorSpaceXform* colorXform, bool isRGBA) {
msarette6dd0042015-10-09 11:07:34 -0700113 SkASSERT(nullptr != colorPtr);
msarettcf7b8772016-09-22 12:37:04 -0700114 switch (dstColorType) {
msarett34e0ec42016-04-22 16:27:24 -0700115 case kRGBA_8888_SkColorType:
116 case kBGRA_8888_SkColorType:
msarette6dd0042015-10-09 11:07:34 -0700117 return colorPtr[fillIndex];
118 case kRGB_565_SkColorType:
119 return SkPixel32ToPixel16(colorPtr[fillIndex]);
msarettf7eb6fc2016-09-13 09:04:11 -0700120 case kRGBA_F16_SkColorType: {
121 SkASSERT(colorXform);
122 uint64_t dstColor;
123 uint32_t srcColor = colorPtr[fillIndex];
Matt Sarett19aff5d2017-04-03 16:01:10 -0400124 SkColorSpaceXform::ColorFormat srcFormat =
125 isRGBA ? SkColorSpaceXform::kRGBA_8888_ColorFormat
126 : SkColorSpaceXform::kBGRA_8888_ColorFormat;
msarett31d097e82016-10-11 12:15:03 -0700127 SkAssertResult(colorXform->apply(select_xform_format(dstColorType), &dstColor,
Matt Sarett19aff5d2017-04-03 16:01:10 -0400128 srcFormat, &srcColor, 1, alphaType));
msarettf7eb6fc2016-09-13 09:04:11 -0700129 return dstColor;
130 }
msarette6dd0042015-10-09 11:07:34 -0700131 default:
132 SkASSERT(false);
133 return 0;
134 }
135}
136
137/*
msarett74114382015-03-16 11:55:18 -0700138 * Compute row bytes for an image using pixels per byte
msarett74114382015-03-16 11:55:18 -0700139 */
msarettd1ec89b2016-08-03 12:59:27 -0700140static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
msarett74114382015-03-16 11:55:18 -0700141 return (width + pixelsPerByte - 1) / pixelsPerByte;
142}
143
144/*
msarett74114382015-03-16 11:55:18 -0700145 * Compute row bytes for an image using bytes per pixel
msarett74114382015-03-16 11:55:18 -0700146 */
msarettd1ec89b2016-08-03 12:59:27 -0700147static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
msarett74114382015-03-16 11:55:18 -0700148 return width * bytesPerPixel;
149}
150
151/*
msarett74114382015-03-16 11:55:18 -0700152 * Compute row bytes for an image
msarett74114382015-03-16 11:55:18 -0700153 */
msarettd1ec89b2016-08-03 12:59:27 -0700154static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
msarett74114382015-03-16 11:55:18 -0700155 if (bitsPerPixel < 16) {
156 SkASSERT(0 == 8 % bitsPerPixel);
157 const uint32_t pixelsPerByte = 8 / bitsPerPixel;
158 return compute_row_bytes_ppb(width, pixelsPerByte);
159 } else {
160 SkASSERT(0 == bitsPerPixel % 8);
161 const uint32_t bytesPerPixel = bitsPerPixel / 8;
162 return compute_row_bytes_bpp(width, bytesPerPixel);
163 }
164}
165
166/*
msarett74114382015-03-16 11:55:18 -0700167 * Get a byte from a buffer
168 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700169 */
msarettd1ec89b2016-08-03 12:59:27 -0700170static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700171 return buffer[i];
172}
173
174/*
msarett74114382015-03-16 11:55:18 -0700175 * Get a short from a buffer
176 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700177 */
msarettd1ec89b2016-08-03 12:59:27 -0700178static inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700179 uint16_t result;
180 memcpy(&result, &(buffer[i]), 2);
181#ifdef SK_CPU_BENDIAN
182 return SkEndianSwap16(result);
183#else
184 return result;
185#endif
186}
187
188/*
msarett74114382015-03-16 11:55:18 -0700189 * Get an int from a buffer
190 * This method is unsafe, the caller is responsible for performing a check
msarett74114382015-03-16 11:55:18 -0700191 */
msarettd1ec89b2016-08-03 12:59:27 -0700192static inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
msarett74114382015-03-16 11:55:18 -0700193 uint32_t result;
194 memcpy(&result, &(buffer[i]), 4);
195#ifdef SK_CPU_BENDIAN
196 return SkEndianSwap32(result);
197#else
198 return result;
199#endif
200}
201
msarett0e6274f2016-03-21 08:04:40 -0700202/*
203 * @param data Buffer to read bytes from
204 * @param isLittleEndian Output parameter
205 * Indicates if the data is little endian
206 * Is unaffected on false returns
207 */
msarettd1ec89b2016-08-03 12:59:27 -0700208static inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700209 // II indicates Intel (little endian) and MM indicates motorola (big endian).
210 if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) {
211 return false;
212 }
213
214 *isLittleEndian = ('I' == data[0]);
215 return true;
216}
217
msarettd1ec89b2016-08-03 12:59:27 -0700218static inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) {
msarett0e6274f2016-03-21 08:04:40 -0700219 if (littleEndian) {
220 return (data[1] << 8) | (data[0]);
221 }
222
223 return (data[0] << 8) | (data[1]);
224}
225
msarettd1ec89b2016-08-03 12:59:27 -0700226static inline SkPMColor premultiply_argb_as_rgba(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700227 if (a != 255) {
228 r = SkMulDiv255Round(r, a);
229 g = SkMulDiv255Round(g, a);
230 b = SkMulDiv255Round(b, a);
231 }
232
233 return SkPackARGB_as_RGBA(a, r, g, b);
234}
235
msarettd1ec89b2016-08-03 12:59:27 -0700236static inline SkPMColor premultiply_argb_as_bgra(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
msarett34e0ec42016-04-22 16:27:24 -0700237 if (a != 255) {
238 r = SkMulDiv255Round(r, a);
239 g = SkMulDiv255Round(g, a);
240 b = SkMulDiv255Round(b, a);
241 }
242
243 return SkPackARGB_as_BGRA(a, r, g, b);
244}
245
msarettd1ec89b2016-08-03 12:59:27 -0700246static inline bool is_rgba(SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700247#ifdef SK_PMCOLOR_IS_RGBA
248 return (kBGRA_8888_SkColorType != colorType);
249#else
250 return (kRGBA_8888_SkColorType == colorType);
251#endif
252}
253
254// Method for coverting to a 32 bit pixel.
255typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
256
msarettd1ec89b2016-08-03 12:59:27 -0700257static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType) {
msarett34e0ec42016-04-22 16:27:24 -0700258 bool isRGBA = is_rgba(colorType);
259 if (isPremul) {
260 if (isRGBA) {
261 return &premultiply_argb_as_rgba;
262 } else {
263 return &premultiply_argb_as_bgra;
264 }
265 } else {
266 if (isRGBA) {
267 return &SkPackARGB_as_RGBA;
268 } else {
269 return &SkPackARGB_as_BGRA;
270 }
271 }
272}
273
Leon Scroggins IIIae79f322017-08-18 10:53:24 -0400274static inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) {
275 return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha;
msarettdcd5e652016-08-22 08:48:40 -0700276}
277
Leon Scroggins III07418182017-08-15 12:24:02 -0400278static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkColorSpace* srcCS,
Matt Sarettcf3f2342017-03-23 15:32:25 -0400279 bool needsColorCorrectPremul) {
Matt Sarette522f4c2017-02-22 13:02:31 -0500280 // We never perform a color xform in legacy mode.
281 if (!dstInfo.colorSpace()) {
282 return false;
283 }
284
msarettdcd5e652016-08-22 08:48:40 -0700285 // F16 is by definition a linear space, so we always must perform a color xform.
286 bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType();
287
288 // Need a color xform when dst space does not match the src.
Leon Scroggins III07418182017-08-15 12:24:02 -0400289 bool srcDstNotEqual = !SkColorSpace::Equals(srcCS, dstInfo.colorSpace());
msarettdcd5e652016-08-22 08:48:40 -0700290
Matt Sarette522f4c2017-02-22 13:02:31 -0500291 return needsColorCorrectPremul || isF16 || srcDstNotEqual;
msarettd1ec89b2016-08-03 12:59:27 -0700292}
293
msarettc0444612016-09-16 11:45:58 -0700294static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) {
msarette99883f2016-09-08 06:05:35 -0700295 return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType;
296}
297
msarett74114382015-03-16 11:55:18 -0700298#endif // SkCodecPriv_DEFINED