1 diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c
2 index 36b7011..6cec34a 100644
3 --- a/third_party/qcms/src/iccread.c
4 +++ b/third_party/qcms/src/iccread.c
5 @@ -266,7 +266,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
6 if (profile->color_space != RGB_SIGNATURE)
9 - if (profile->A2B0 || profile->B2A0)
10 + if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0))
13 rX = s15Fixed16Number_to_float(profile->redColorant.X);
14 @@ -297,6 +297,11 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
15 sum[1] = rY + gY + bY;
16 sum[2] = rZ + gZ + bZ;
18 +#if defined (_MSC_VER)
19 +#pragma warning(push)
20 +/* Disable double to float truncation warning 4305 */
21 +#pragma warning(disable:4305)
23 // Build our target vector (see mozilla bug 460629)
26 @@ -310,6 +315,10 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
30 +#if defined (_MSC_VER)
31 +/* Restore warnings */
34 // Compare with our tolerance
35 for (i = 0; i < 3; ++i) {
36 if (!(((sum[i] - tolerance[i]) <= target[i]) &&
37 @@ -331,6 +340,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
38 #define TAG_A2B0 0x41324230
39 #define TAG_B2A0 0x42324130
40 #define TAG_CHAD 0x63686164
41 +#define TAG_desc 0x64657363
43 static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
45 @@ -344,6 +354,152 @@ static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
49 +#define DESC_TYPE 0x64657363 // 'desc'
50 +#define MLUC_TYPE 0x6d6c7563 // 'mluc'
51 +#define MMOD_TYPE 0x6D6D6F64 // 'mmod'
53 +static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
55 + struct tag *tag = find_tag(index, tag_id);
57 + const uint32_t limit = sizeof profile->description;
58 + uint32_t offset = tag->offset;
59 + uint32_t type = read_u32(src, offset);
60 + uint32_t length = read_u32(src, offset+8);
61 + uint32_t i, description_offset;
63 + if (length && type == MLUC_TYPE) {
64 + length = read_u32(src, offset+20);
65 + if (!length || (length & 1) || (read_u32(src, offset+12) != 12))
66 + goto invalid_desc_tag;
67 + description_offset = offset + read_u32(src, offset+24);
69 + goto invalid_desc_tag;
71 + } else if (length && type == DESC_TYPE) {
72 + description_offset = offset + 12;
74 + goto invalid_desc_tag;
76 + if (length >= limit)
78 + for (i = 0; i < length; ++i) {
79 + uint8_t value = read_u8(src, description_offset + i);
81 + goto invalid_desc_tag;
84 + profile->description[i] = value;
86 + profile->description[length] = 0;
88 + goto invalid_desc_tag;
95 + invalid_source(src, "invalid description");
99 +#if defined(__APPLE__)
101 +// Use the dscm tag to change profile description "Display" to its more specific en-localized monitor name, if any.
103 +#define TAG_dscm 0x6473636D // 'dscm'
105 +static bool read_tag_dscmType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
107 + if (strcmp(profile->description, "Display") != 0)
110 + struct tag *tag = find_tag(index, tag_id);
112 + uint32_t offset = tag->offset;
113 + uint32_t type = read_u32(src, offset);
114 + uint32_t records = read_u32(src, offset+8);
116 + if (!src->valid || !records || type != MLUC_TYPE)
117 + goto invalid_dscm_tag;
118 + if (read_u32(src, offset+12) != 12) // MLUC record size: bytes
119 + goto invalid_dscm_tag;
121 + for (uint32_t i = 0; i < records; ++i) {
122 + const uint32_t limit = sizeof profile->description;
123 + const uint16_t isoen = 0x656E; // ISO-3166-1 language 'en'
125 + uint16_t language = read_u16(src, offset + 16 + (i * 12) + 0);
126 + uint32_t length = read_u32(src, offset + 16 + (i * 12) + 4);
127 + uint32_t description_offset = read_u32(src, offset + 16 + (i * 12) + 8);
129 + if (!src->valid || !length || (length & 1))
130 + goto invalid_dscm_tag;
131 + if (language != isoen)
134 + // Use a prefix to identify the display description source
135 + strcpy(profile->description, "dscm:");
138 + if (length >= limit)
139 + length = limit - 1;
140 + for (uint32_t j = 5; j < length; ++j) {
141 + uint8_t value = read_u8(src, offset + description_offset + j - 5);
143 + goto invalid_dscm_tag;
144 + profile->description[j] = value ? value : '.';
146 + profile->description[length] = 0;
155 + invalid_source(src, "invalid dscm tag");
159 +// Use the mmod tag to change profile description "Display" to its specific mmod maker model data, if any.
161 +#define TAG_mmod 0x6D6D6F64 // 'mmod'
163 +static bool read_tag_mmodType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
165 + if (strcmp(profile->description, "Display") != 0)
168 + struct tag *tag = find_tag(index, tag_id);
170 + const uint8_t length = 4 * 4; // Four 4-byte fields: 'mmod', 0, maker, model.
172 + uint32_t offset = tag->offset;
173 + if (tag->size < 40 || read_u32(src, offset) != MMOD_TYPE)
174 + goto invalid_mmod_tag;
176 + for (uint8_t i = 0; i < length; ++i) {
177 + uint8_t value = read_u8(src, offset + i);
179 + goto invalid_mmod_tag;
180 + profile->description[i] = value ? value : '.';
182 + profile->description[length] = 0;
189 + invalid_source(src, "invalid mmod tag");
195 #define XYZ_TYPE 0x58595a20 // 'XYZ '
196 #define CURVE_TYPE 0x63757276 // 'curv'
197 #define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para'
198 @@ -402,7 +558,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_inde
199 // present that are not part of the tag_index.
200 static struct curveType *read_curveType(struct mem_source *src, uint32_t offset, uint32_t *len)
202 - static const size_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
203 + static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
204 struct curveType *curve = NULL;
205 uint32_t type = read_u32(src, offset);
207 @@ -484,19 +640,23 @@ static void read_nested_curveType(struct mem_source *src, struct curveType *(*cu
208 uint32_t channel_offset = 0;
210 for (i = 0; i < num_channels; i++) {
212 + uint32_t tag_len = ~0;
214 (*curveArray)[i] = read_curveType(src, curve_offset + channel_offset, &tag_len);
215 if (!(*curveArray)[i]) {
216 invalid_source(src, "invalid nested curveType curve");
219 + if (tag_len == ~0) {
220 + invalid_source(src, "invalid nested curveType tag length");
224 channel_offset += tag_len;
226 if ((tag_len % 4) != 0)
227 channel_offset += 4 - (tag_len % 4);
232 static void mAB_release(struct lutmABType *lut)
233 @@ -657,7 +817,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
234 uint16_t num_input_table_entries;
235 uint16_t num_output_table_entries;
236 uint8_t in_chan, grid_points, out_chan;
237 - uint32_t clut_offset, output_offset;
238 + size_t clut_offset, output_offset;
242 @@ -979,6 +1139,9 @@ qcms_profile* qcms_profile_sRGB(void)
243 return NO_MEM_PROFILE;
245 profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024);
247 + strcpy(profile->description, "sRGB IEC61966-2.1");
252 @@ -997,6 +1160,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
257 + return INVALID_PROFILE;
259 length = read_u32(src, 0);
260 if (length <= size) {
261 // shrink the area that we can read if appropriate
262 @@ -1028,6 +1194,15 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
263 if (!src->valid || !index.tags)
264 goto invalid_tag_table;
266 + if (!read_tag_descType(profile, src, index, TAG_desc))
267 + goto invalid_tag_table;
268 +#if defined(__APPLE__)
269 + if (!read_tag_dscmType(profile, src, index, TAG_dscm))
270 + goto invalid_tag_table;
271 + if (!read_tag_mmodType(profile, src, index, TAG_mmod))
272 + goto invalid_tag_table;
275 if (find_tag(index, TAG_CHAD)) {
276 profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD);
278 @@ -1098,6 +1273,16 @@ invalid_profile:
279 return INVALID_PROFILE;
282 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2)
284 + return memcmp(p1->description, p2->description, sizeof p1->description) == 0;
287 +const char* qcms_profile_get_description(qcms_profile *profile)
289 + return profile->description;
292 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile)
294 return profile->rendering_intent;
295 diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h
296 index 7d83623..e9c0b09 100644
297 --- a/third_party/qcms/src/qcms.h
298 +++ b/third_party/qcms/src/qcms.h
299 @@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written
300 authorization from SunSoft Inc.
301 ******************************************************************/
304 + * QCMS, in general, is not threadsafe. However, it should be safe to create
305 + * profile and transformation objects on different threads, so long as you
306 + * don't use the same objects on different threads at the same time.
310 * Color Space Signatures
311 * Note that only icSigXYZData and icSigLabData are valid
312 @@ -102,6 +108,12 @@ typedef enum {
316 +/* Format of the output data for qcms_transform_data_type() */
322 /* the names for the following two types are sort of ugly */
325 @@ -136,6 +148,9 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile);
326 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile);
327 icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile);
329 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2);
330 +const char* qcms_profile_get_description(qcms_profile *profile);
332 void qcms_profile_precache_output_transform(qcms_profile *profile);
334 qcms_transform* qcms_transform_create(
335 @@ -143,9 +158,14 @@ qcms_transform* qcms_transform_create(
336 qcms_profile* out, qcms_data_type out_type,
339 -void qcms_transform_release(qcms_transform *);
340 +qcms_bool qcms_transform_create_LUT_zyx_bgra(
341 + qcms_profile *in, qcms_profile* out, qcms_intent intent,
342 + int samples, unsigned char* lut);
344 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length);
345 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type);
347 +void qcms_transform_release(qcms_transform *);
349 void qcms_enable_iccv4();
351 diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h
352 index 53a3420..4116ed5 100644
353 --- a/third_party/qcms/src/qcmsint.h
354 +++ b/third_party/qcms/src/qcmsint.h
355 @@ -45,6 +45,11 @@ struct precache_output
356 #define ALIGN __attribute__(( aligned (16) ))
359 +typedef struct _qcms_format_type {
364 struct _qcms_transform {
365 float ALIGN matrix[3][4];
366 float *input_gamma_table_r;
367 @@ -88,7 +93,7 @@ struct _qcms_transform {
368 struct precache_output *output_table_g;
369 struct precache_output *output_table_b;
371 - void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length);
372 + void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, struct _qcms_format_type output_format);
376 @@ -225,6 +230,7 @@ struct tag_value {
377 #define LAB_SIGNATURE 0x4C616220
379 struct _qcms_profile {
380 + char description[64];
382 uint32_t color_space;
384 @@ -280,18 +286,40 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
385 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
390 + qcms_format_type output_format);
391 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
396 + qcms_format_type output_format);
397 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
402 + qcms_format_type output_format);
403 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
408 + qcms_format_type output_format);
410 extern qcms_bool qcms_supports_iccv4;
415 +long __cdecl _InterlockedIncrement(long volatile *);
416 +long __cdecl _InterlockedDecrement(long volatile *);
417 +#pragma intrinsic(_InterlockedIncrement)
418 +#pragma intrinsic(_InterlockedDecrement)
420 +#define qcms_atomic_increment(x) _InterlockedIncrement((long volatile *)&x)
421 +#define qcms_atomic_decrement(x) _InterlockedDecrement((long volatile*)&x)
425 +#define qcms_atomic_increment(x) __sync_add_and_fetch(&x, 1)
426 +#define qcms_atomic_decrement(x) __sync_sub_and_fetch(&x, 1)
429 diff --git a/third_party/qcms/src/qcmstypes.h b/third_party/qcms/src/qcmstypes.h
430 index 56d8de3..d58f691 100644
431 --- a/third_party/qcms/src/qcmstypes.h
432 +++ b/third_party/qcms/src/qcmstypes.h
439 -#include "prtypes.h"
441 -/* prtypes.h defines IS_LITTLE_ENDIAN and IS_BIG ENDIAN */
443 -#if defined (__SVR4) && defined (__sun)
444 -/* int_types.h gets included somehow, so avoid redefining the types differently */
445 -#include <sys/int_types.h>
446 -#elif defined (_AIX)
447 -#include <sys/types.h>
448 -#elif !defined(ANDROID) && !defined(__OpenBSD__)
449 -typedef PRInt8 int8_t;
450 -typedef PRUint8 uint8_t;
451 -typedef PRInt16 int16_t;
452 -typedef PRUint16 uint16_t;
453 -typedef PRInt32 int32_t;
454 -typedef PRUint32 uint32_t;
455 -typedef PRInt64 int64_t;
456 -typedef PRUint64 uint64_t;
459 -/* OS/2's stdlib typdefs uintptr_t. So we'll just include that so we don't collide */
461 -#elif !defined(__intptr_t_defined) && !defined(_UINTPTR_T_DEFINED)
462 -typedef PRUptrdiff uintptr_t;
468 #if BYTE_ORDER == LITTLE_ENDIAN
469 #define IS_LITTLE_ENDIAN
470 #elif BYTE_ORDER == BIG_ENDIAN
471 @@ -75,7 +44,7 @@ typedef PRUptrdiff uintptr_t;
473 #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__)
474 # include <inttypes.h>
475 -#elif defined (_MSC_VER)
476 +#elif defined (_MSC_VER) && _MSC_VER < 1600
477 typedef __int8 int8_t;
478 typedef unsigned __int8 uint8_t;
479 typedef __int16 int16_t;
480 @@ -87,7 +56,12 @@ typedef unsigned __int64 uint64_t;
482 typedef unsigned __int64 uintptr_t;
484 +#pragma warning(push)
485 +/* Disable benign redefinition of type warning 4142 */
486 +#pragma warning(disable:4142)
487 typedef unsigned long uintptr_t;
488 +/* Restore warnings */
489 +#pragma warning(pop)
493 @@ -96,8 +70,6 @@ typedef unsigned long uintptr_t;
499 typedef qcms_bool bool;
502 diff --git a/third_party/qcms/src/transform-sse1.c b/third_party/qcms/src/transform-sse1.c
503 index 2f34db5..aaee1bf 100644
504 --- a/third_party/qcms/src/transform-sse1.c
505 +++ b/third_party/qcms/src/transform-sse1.c
506 @@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
507 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
512 + qcms_format_type output_format)
515 float (*mat)[4] = transform->matrix;
516 @@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
518 /* working variables */
519 __m128 vec_r, vec_g, vec_b, result;
520 + const int r_out = output_format.r;
521 + const int b_out = output_format.b;
525 @@ -116,9 +119,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
528 /* use calc'd indices to output RGB values */
529 - dest[0] = otdata_r[output[0]];
530 - dest[1] = otdata_g[output[1]];
531 - dest[2] = otdata_b[output[2]];
532 + dest[r_out] = otdata_r[output[0]];
533 + dest[1] = otdata_g[output[1]];
534 + dest[b_out] = otdata_b[output[2]];
538 @@ -141,9 +144,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
539 result = _mm_movehl_ps(result, result);
540 *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
542 - dest[0] = otdata_r[output[0]];
543 - dest[1] = otdata_g[output[1]];
544 - dest[2] = otdata_b[output[2]];
545 + dest[r_out] = otdata_r[output[0]];
546 + dest[1] = otdata_g[output[1]];
547 + dest[b_out] = otdata_b[output[2]];
551 @@ -151,7 +154,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
552 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
557 + qcms_format_type output_format)
560 float (*mat)[4] = transform->matrix;
561 @@ -187,6 +191,8 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
563 /* working variables */
564 __m128 vec_r, vec_g, vec_b, result;
565 + const int r_out = output_format.r;
566 + const int b_out = output_format.b;
570 @@ -239,9 +245,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
573 /* use calc'd indices to output RGB values */
574 - dest[0] = otdata_r[output[0]];
575 - dest[1] = otdata_g[output[1]];
576 - dest[2] = otdata_b[output[2]];
577 + dest[r_out] = otdata_r[output[0]];
578 + dest[1] = otdata_g[output[1]];
579 + dest[b_out] = otdata_b[output[2]];
583 @@ -266,9 +272,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
584 result = _mm_movehl_ps(result, result);
585 *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
587 - dest[0] = otdata_r[output[0]];
588 - dest[1] = otdata_g[output[1]];
589 - dest[2] = otdata_b[output[2]];
590 + dest[r_out] = otdata_r[output[0]];
591 + dest[1] = otdata_g[output[1]];
592 + dest[b_out] = otdata_b[output[2]];
596 diff --git a/third_party/qcms/src/transform-sse2.c b/third_party/qcms/src/transform-sse2.c
597 index 6a5faf9..fa7f2d1 100644
598 --- a/third_party/qcms/src/transform-sse2.c
599 +++ b/third_party/qcms/src/transform-sse2.c
600 @@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
601 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
606 + qcms_format_type output_format)
609 float (*mat)[4] = transform->matrix;
610 @@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
612 /* working variables */
613 __m128 vec_r, vec_g, vec_b, result;
614 + const int r_out = output_format.r;
615 + const int b_out = output_format.b;
619 @@ -114,9 +117,9 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
622 /* use calc'd indices to output RGB values */
623 - dest[0] = otdata_r[output[0]];
624 - dest[1] = otdata_g[output[1]];
625 - dest[2] = otdata_b[output[2]];
626 + dest[r_out] = otdata_r[output[0]];
627 + dest[1] = otdata_g[output[1]];
628 + dest[b_out] = otdata_b[output[2]];
632 @@ -137,15 +140,16 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
634 _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
636 - dest[0] = otdata_r[output[0]];
637 - dest[1] = otdata_g[output[1]];
638 - dest[2] = otdata_b[output[2]];
639 + dest[r_out] = otdata_r[output[0]];
640 + dest[1] = otdata_g[output[1]];
641 + dest[b_out] = otdata_b[output[2]];
644 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
649 + qcms_format_type output_format)
652 float (*mat)[4] = transform->matrix;
653 @@ -181,6 +185,8 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
655 /* working variables */
656 __m128 vec_r, vec_g, vec_b, result;
657 + const int r_out = output_format.r;
658 + const int b_out = output_format.b;
662 @@ -231,9 +237,9 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
665 /* use calc'd indices to output RGB values */
666 - dest[0] = otdata_r[output[0]];
667 - dest[1] = otdata_g[output[1]];
668 - dest[2] = otdata_b[output[2]];
669 + dest[r_out] = otdata_r[output[0]];
670 + dest[1] = otdata_g[output[1]];
671 + dest[b_out] = otdata_b[output[2]];
675 @@ -256,7 +262,7 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
677 _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
679 - dest[0] = otdata_r[output[0]];
680 - dest[1] = otdata_g[output[1]];
681 - dest[2] = otdata_b[output[2]];
682 + dest[r_out] = otdata_r[output[0]];
683 + dest[1] = otdata_g[output[1]];
684 + dest[b_out] = otdata_b[output[2]];
686 diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c
687 index 9a6562b..f669a6b 100644
688 --- a/third_party/qcms/src/transform.c
689 +++ b/third_party/qcms/src/transform.c
690 @@ -181,11 +181,20 @@ compute_chromatic_adaption(struct CIE_XYZ source_white_point,
692 adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination)
694 +#if defined (_MSC_VER)
695 +#pragma warning(push)
696 +/* Disable double to float truncation warning 4305 */
697 +#pragma warning(disable:4305)
699 struct matrix lam_rigg = {{ // Bradford matrix
700 { 0.8951, 0.2664, -0.1614 },
701 { -0.7502, 1.7135, 0.0367 },
702 { 0.0389, -0.0685, 1.0296 }
704 +#if defined (_MSC_VER)
705 +/* Restore warnings */
706 +#pragma warning(pop)
708 return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg);
711 @@ -230,8 +239,11 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
715 -static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
716 +static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
718 + const int r_out = output_format.r;
719 + const int b_out = output_format.b;
722 float (*mat)[4] = transform->matrix;
723 for (i=0; i<length; i++) {
724 @@ -251,15 +263,19 @@ static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned
725 float out_device_g = pow(out_linear_g, transform->out_gamma_g);
726 float out_device_b = pow(out_linear_b, transform->out_gamma_b);
728 - *dest++ = clamp_u8(255*out_device_r);
729 - *dest++ = clamp_u8(255*out_device_g);
730 - *dest++ = clamp_u8(255*out_device_b);
731 + dest[r_out] = clamp_u8(out_device_r*255);
732 + dest[1] = clamp_u8(out_device_g*255);
733 + dest[b_out] = clamp_u8(out_device_b*255);
739 -static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
740 +static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
742 + const int r_out = output_format.r;
743 + const int b_out = output_format.b;
746 for (i = 0; i < length; i++) {
747 float out_device_r, out_device_g, out_device_b;
748 @@ -267,13 +283,14 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
750 float linear = transform->input_gamma_table_gray[device];
752 - out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
753 + out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
754 out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
755 out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
757 - *dest++ = clamp_u8(out_device_r*255);
758 - *dest++ = clamp_u8(out_device_g*255);
759 - *dest++ = clamp_u8(out_device_b*255);
760 + dest[r_out] = clamp_u8(out_device_r*255);
761 + dest[1] = clamp_u8(out_device_g*255);
762 + dest[b_out] = clamp_u8(out_device_b*255);
767 @@ -283,8 +300,11 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
768 See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
771 -static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
772 +static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
774 + const int r_out = output_format.r;
775 + const int b_out = output_format.b;
778 for (i = 0; i < length; i++) {
779 float out_device_r, out_device_g, out_device_b;
780 @@ -293,20 +313,24 @@ static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigne
782 float linear = transform->input_gamma_table_gray[device];
784 - out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
785 + out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
786 out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
787 out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
789 - *dest++ = clamp_u8(out_device_r*255);
790 - *dest++ = clamp_u8(out_device_g*255);
791 - *dest++ = clamp_u8(out_device_b*255);
793 + dest[r_out] = clamp_u8(out_device_r*255);
794 + dest[1] = clamp_u8(out_device_g*255);
795 + dest[b_out] = clamp_u8(out_device_b*255);
802 -static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
803 +static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
805 + const int r_out = output_format.r;
806 + const int b_out = output_format.b;
809 for (i = 0; i < length; i++) {
810 unsigned char device = *src++;
811 @@ -317,14 +341,19 @@ static void qcms_transform_data_gray_out_precache(qcms_transform *transform, uns
812 /* we could round here... */
813 gray = linear * PRECACHE_OUTPUT_MAX;
815 - *dest++ = transform->output_table_r->data[gray];
816 - *dest++ = transform->output_table_g->data[gray];
817 - *dest++ = transform->output_table_b->data[gray];
818 + dest[r_out] = transform->output_table_r->data[gray];
819 + dest[1] = transform->output_table_g->data[gray];
820 + dest[b_out] = transform->output_table_b->data[gray];
825 -static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
827 +static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
829 + const int r_out = output_format.r;
830 + const int b_out = output_format.b;
833 for (i = 0; i < length; i++) {
834 unsigned char device = *src++;
835 @@ -336,15 +365,19 @@ static void qcms_transform_data_graya_out_precache(qcms_transform *transform, un
836 /* we could round here... */
837 gray = linear * PRECACHE_OUTPUT_MAX;
839 - *dest++ = transform->output_table_r->data[gray];
840 - *dest++ = transform->output_table_g->data[gray];
841 - *dest++ = transform->output_table_b->data[gray];
843 + dest[r_out] = transform->output_table_r->data[gray];
844 + dest[1] = transform->output_table_g->data[gray];
845 + dest[b_out] = transform->output_table_b->data[gray];
851 -static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
852 +static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
854 + const int r_out = output_format.r;
855 + const int b_out = output_format.b;
858 float (*mat)[4] = transform->matrix;
859 for (i = 0; i < length; i++) {
860 @@ -370,14 +403,18 @@ static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform,
861 g = out_linear_g * PRECACHE_OUTPUT_MAX;
862 b = out_linear_b * PRECACHE_OUTPUT_MAX;
864 - *dest++ = transform->output_table_r->data[r];
865 - *dest++ = transform->output_table_g->data[g];
866 - *dest++ = transform->output_table_b->data[b];
867 + dest[r_out] = transform->output_table_r->data[r];
868 + dest[1] = transform->output_table_g->data[g];
869 + dest[b_out] = transform->output_table_b->data[b];
874 -static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
875 +static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
877 + const int r_out = output_format.r;
878 + const int b_out = output_format.b;
881 float (*mat)[4] = transform->matrix;
882 for (i = 0; i < length; i++) {
883 @@ -404,16 +441,21 @@ static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform,
884 g = out_linear_g * PRECACHE_OUTPUT_MAX;
885 b = out_linear_b * PRECACHE_OUTPUT_MAX;
887 - *dest++ = transform->output_table_r->data[r];
888 - *dest++ = transform->output_table_g->data[g];
889 - *dest++ = transform->output_table_b->data[b];
891 + dest[r_out] = transform->output_table_r->data[r];
892 + dest[1] = transform->output_table_g->data[g];
893 + dest[b_out] = transform->output_table_b->data[b];
901 -static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
902 +static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
904 + const int r_out = output_format.r;
905 + const int b_out = output_format.b;
909 int x_len = transform->grid_size;
910 @@ -462,15 +504,20 @@ static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *s
911 float b_y2 = lerp(b_x3, b_x4, y_d);
912 float clut_b = lerp(b_y1, b_y2, z_d);
914 - *dest++ = clamp_u8(clut_r*255.0f);
915 - *dest++ = clamp_u8(clut_g*255.0f);
916 - *dest++ = clamp_u8(clut_b*255.0f);
918 + dest[r_out] = clamp_u8(clut_r*255.0f);
919 + dest[1] = clamp_u8(clut_g*255.0f);
920 + dest[b_out] = clamp_u8(clut_b*255.0f);
926 // Using lcms' tetra interpolation algorithm.
927 -static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
928 +static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
930 + const int r_out = output_format.r;
931 + const int b_out = output_format.b;
935 int x_len = transform->grid_size;
936 @@ -577,15 +624,20 @@ static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsig
937 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
938 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
940 - *dest++ = clamp_u8(clut_r*255.0f);
941 - *dest++ = clamp_u8(clut_g*255.0f);
942 - *dest++ = clamp_u8(clut_b*255.0f);
945 + dest[r_out] = clamp_u8(clut_r*255.0f);
946 + dest[1] = clamp_u8(clut_g*255.0f);
947 + dest[b_out] = clamp_u8(clut_b*255.0f);
953 // Using lcms' tetra interpolation code.
954 -static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
955 +static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
957 + const int r_out = output_format.r;
958 + const int b_out = output_format.b;
962 int x_len = transform->grid_size;
963 @@ -691,14 +743,18 @@ static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned c
964 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
965 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
967 - *dest++ = clamp_u8(clut_r*255.0f);
968 - *dest++ = clamp_u8(clut_g*255.0f);
969 - *dest++ = clamp_u8(clut_b*255.0f);
971 + dest[r_out] = clamp_u8(clut_r*255.0f);
972 + dest[1] = clamp_u8(clut_g*255.0f);
973 + dest[b_out] = clamp_u8(clut_b*255.0f);
978 -static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
979 +static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
981 + const int r_out = output_format.r;
982 + const int b_out = output_format.b;
985 float (*mat)[4] = transform->matrix;
986 for (i = 0; i < length; i++) {
987 @@ -726,14 +782,18 @@ static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned
988 out_device_b = lut_interp_linear(out_linear_b,
989 transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
991 - *dest++ = clamp_u8(out_device_r*255);
992 - *dest++ = clamp_u8(out_device_g*255);
993 - *dest++ = clamp_u8(out_device_b*255);
994 + dest[r_out] = clamp_u8(out_device_r*255);
995 + dest[1] = clamp_u8(out_device_g*255);
996 + dest[b_out] = clamp_u8(out_device_b*255);
1001 -static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
1002 +static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
1004 + const int r_out = output_format.r;
1005 + const int b_out = output_format.b;
1008 float (*mat)[4] = transform->matrix;
1009 for (i = 0; i < length; i++) {
1010 @@ -762,16 +822,20 @@ static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned
1011 out_device_b = lut_interp_linear(out_linear_b,
1012 transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
1014 - *dest++ = clamp_u8(out_device_r*255);
1015 - *dest++ = clamp_u8(out_device_g*255);
1016 - *dest++ = clamp_u8(out_device_b*255);
1018 + dest[r_out] = clamp_u8(out_device_r*255);
1019 + dest[1] = clamp_u8(out_device_g*255);
1020 + dest[b_out] = clamp_u8(out_device_b*255);
1027 -static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
1028 +static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
1030 + const int r_out = output_format.r;
1031 + const int b_out = output_format.b;
1034 float (*mat)[4] = transform->matrix;
1035 for (i = 0; i < length; i++) {
1036 @@ -787,16 +851,25 @@ static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsign
1037 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
1038 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
1040 - *dest++ = clamp_u8(out_linear_r*255);
1041 - *dest++ = clamp_u8(out_linear_g*255);
1042 - *dest++ = clamp_u8(out_linear_b*255);
1043 + dest[r_out] = clamp_u8(out_linear_r*255);
1044 + dest[1] = clamp_u8(out_linear_g*255);
1045 + dest[b_out] = clamp_u8(out_linear_b*255);
1052 + * If users create and destroy objects on different threads, even if the same
1053 + * objects aren't used on different threads at the same time, we can still run
1054 + * in to trouble with refcounts if they aren't atomic.
1056 + * This can lead to us prematurely deleting the precache if threads get unlucky
1057 + * and write the wrong value to the ref count.
1059 static struct precache_output *precache_reference(struct precache_output *p)
1062 + qcms_atomic_increment(p->ref_count);
1066 @@ -810,12 +883,12 @@ static struct precache_output *precache_create()
1068 void precache_release(struct precache_output *p)
1070 - if (--p->ref_count == 0) {
1071 + if (qcms_atomic_decrement(p->ref_count) == 0) {
1076 -#ifdef HAS_POSIX_MEMALIGN
1077 +#ifdef HAVE_POSIX_MEMALIGN
1078 static qcms_transform *transform_alloc(void)
1081 @@ -994,13 +1067,15 @@ void qcms_profile_precache_output_transform(qcms_profile *profile)
1082 if (profile->color_space != RGB_SIGNATURE)
1085 - /* don't precache since we will use the B2A LUT */
1086 - if (profile->B2A0)
1088 + if (qcms_supports_iccv4) {
1089 + /* don't precache since we will use the B2A LUT */
1090 + if (profile->B2A0)
1093 - /* don't precache since we will use the mBA LUT */
1096 + /* don't precache since we will use the mBA LUT */
1101 /* don't precache if we do not have the TRC curves */
1102 if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC)
1103 @@ -1043,28 +1118,31 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
1109 src = malloc(lutSize*sizeof(float));
1110 dest = malloc(lutSize*sizeof(float));
1113 - /* Prepare a list of points we want to sample */
1114 + /* Prepare a list of points we want to sample: x, y, z order */
1116 + inverse = 1 / (float)(samples-1);
1117 for (x = 0; x < samples; x++) {
1118 for (y = 0; y < samples; y++) {
1119 for (z = 0; z < samples; z++) {
1120 - src[l++] = x / (float)(samples-1);
1121 - src[l++] = y / (float)(samples-1);
1122 - src[l++] = z / (float)(samples-1);
1123 + src[l++] = x * inverse; // r
1124 + src[l++] = y * inverse; // g
1125 + src[l++] = z * inverse; // b
1130 lut = qcms_chain_transform(in, out, src, dest, lutSize);
1133 - transform->r_clut = &lut[0];
1134 - transform->g_clut = &lut[1];
1135 - transform->b_clut = &lut[2];
1136 + transform->r_clut = &lut[0]; // r
1137 + transform->g_clut = &lut[1]; // g
1138 + transform->b_clut = &lut[2]; // b
1139 transform->grid_size = samples;
1140 if (in_type == QCMS_DATA_RGBA_8) {
1141 transform->transform_fn = qcms_transform_data_tetra_clut_rgba;
1142 @@ -1074,11 +1152,12 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
1147 - //XXX: qcms_modular_transform_data may return either the src or dest buffer. If so it must not be free-ed
1148 + // XXX: qcms_modular_transform_data may return the lut in either the src or the
1149 + // dest buffer. If so, it must not be free-ed.
1150 if (src && lut != src) {
1152 - } else if (dest && lut != src) {
1154 + if (dest && lut != dest) {
1158 @@ -1088,6 +1167,71 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
1162 +/* Create a transform LUT using the given number of sample points. The transform LUT data is stored
1163 + in the output (cube) in bgra format in zyx sample order. */
1164 +qcms_bool qcms_transform_create_LUT_zyx_bgra(qcms_profile *in, qcms_profile *out, qcms_intent intent,
1165 + int samples, unsigned char* cube)
1169 + uint32_t lutSize = 3 * samples * samples * samples;
1171 + float* src = NULL;
1172 + float* dest = NULL;
1173 + float* lut = NULL;
1176 + src = malloc(lutSize*sizeof(float));
1177 + dest = malloc(lutSize*sizeof(float));
1179 + if (src && dest) {
1180 + /* Prepare a list of points we want to sample: z, y, x order */
1182 + inverse = 1 / (float)(samples-1);
1183 + for (z = 0; z < samples; z++) {
1184 + for (y = 0; y < samples; y++) {
1185 + for (x = 0; x < samples; x++) {
1186 + src[l++] = x * inverse; // r
1187 + src[l++] = y * inverse; // g
1188 + src[l++] = z * inverse; // b
1193 + lut = qcms_chain_transform(in, out, src, dest, lutSize);
1197 + for (z = 0; z < samples; z++) {
1198 + for (y = 0; y < samples; y++) {
1199 + for (x = 0; x < samples; x++) {
1200 + cube[index++] = (int)floorf(lut[l + 2] * 255.0f + 0.5f); // b
1201 + cube[index++] = (int)floorf(lut[l + 1] * 255.0f + 0.5f); // g
1202 + cube[index++] = (int)floorf(lut[l + 0] * 255.0f + 0.5f); // r
1203 + cube[index++] = 255; // a
1211 + // XXX: qcms_modular_transform_data may return the lut data in either the src or
1212 + // dest buffer so free src, dest, and lut with care.
1214 + if (src && lut != src)
1216 + if (dest && lut != dest)
1227 #define NO_MEM_TRANSFORM NULL
1229 qcms_transform* qcms_transform_create(
1230 @@ -1157,14 +1301,14 @@ qcms_transform* qcms_transform_create(
1235 +#if defined(SSE2_ENABLE) && defined(X86)
1236 if (sse_version_available() >= 2) {
1237 if (in_type == QCMS_DATA_RGB_8)
1238 transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2;
1240 transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2;
1242 -#if !(defined(_MSC_VER) && defined(_M_AMD64))
1243 +#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64))
1244 /* Microsoft Compiler for x64 doesn't support MMX.
1245 * SSE code uses MMX so that we disable on x64 */
1247 @@ -1256,13 +1400,34 @@ qcms_transform* qcms_transform_create(
1251 -#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
1252 +/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on unused
1253 + * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the presence
1254 + * of the attribute but is currently only supported by clang */
1255 +#if defined(__has_attribute)
1256 +#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__)
1257 +#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defined(__arm__) && !defined(__mips__)
1258 +#define HAS_FORCE_ALIGN_ARG_POINTER 1
1260 +#define HAS_FORCE_ALIGN_ARG_POINTER 0
1263 +#if HAS_FORCE_ALIGN_ARG_POINTER
1264 /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
1265 __attribute__((__force_align_arg_pointer__))
1267 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length)
1269 - transform->transform_fn(transform, src, dest, length);
1270 + static const struct _qcms_format_type output_rgbx = { 0, 2 };
1272 + transform->transform_fn(transform, src, dest, length, output_rgbx);
1275 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type)
1277 + static const struct _qcms_format_type output_rgbx = { 0, 2 };
1278 + static const struct _qcms_format_type output_bgrx = { 2, 0 };
1280 + transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPUT_BGRX ? output_bgrx : output_rgbx);
1283 qcms_bool qcms_supports_iccv4;
1284 diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c
1285 index e8447e5..f4338b2 100644
1286 --- a/third_party/qcms/src/transform_util.c
1287 +++ b/third_party/qcms/src/transform_util.c
1290 /* value must be a value between 0 and 1 */
1291 //XXX: is the above a good restriction to have?
1292 -float lut_interp_linear(double value, uint16_t *table, int length)
1293 +float lut_interp_linear(double value, uint16_t *table, size_t length)
1296 value = value * (length - 1); // scale to length of the array
1297 @@ -49,11 +49,11 @@ float lut_interp_linear(double value, uint16_t *table, int length)
1300 /* same as above but takes and returns a uint16_t value representing a range from 0..1 */
1301 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
1302 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length)
1304 /* Start scaling input_value to the length of the array: 65535*(length-1).
1305 * We'll divide out the 65535 next */
1306 - uint32_t value = (input_value * (length - 1));
1307 + uintptr_t value = (input_value * (length - 1));
1308 uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65535) */
1309 uint32_t lower = value / 65535; /* equivalent to floor(value/65535) */
1310 /* interp is the distance from upper to value scaled to 0..65535 */
1311 @@ -67,11 +67,11 @@ uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
1312 /* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX
1313 * and returns a uint8_t value representing a range from 0..1 */
1315 -uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, int length)
1316 +uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, size_t length)
1318 /* Start scaling input_value to the length of the array: PRECACHE_OUTPUT_MAX*(length-1).
1319 * We'll divide out the PRECACHE_OUTPUT_MAX next */
1320 - uint32_t value = (input_value * (length - 1));
1321 + uintptr_t value = (input_value * (length - 1));
1323 /* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */
1324 uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX;
1325 @@ -91,7 +91,7 @@ uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table,
1327 /* value must be a value between 0 and 1 */
1328 //XXX: is the above a good restriction to have?
1329 -float lut_interp_linear_float(float value, float *table, int length)
1330 +float lut_interp_linear_float(float value, float *table, size_t length)
1333 value = value * (length - 1);
1334 @@ -235,6 +235,21 @@ float u8Fixed8Number_to_float(uint16_t x)
1338 +/* The SSE2 code uses min & max which let NaNs pass through.
1339 + We want to try to prevent that here by ensuring that
1340 + gamma table is within expected values. */
1341 +void validate_gamma_table(float gamma_table[256])
1344 + for (i = 0; i < 256; i++) {
1345 + // Note: we check that the gamma is not in range
1346 + // instead of out of range so that we catch NaNs
1347 + if (!(gamma_table[i] >= 0.f && gamma_table[i] <= 1.f)) {
1348 + gamma_table[i] = 0.f;
1353 float *build_input_gamma_table(struct curveType *TRC)
1356 @@ -254,7 +269,10 @@ float *build_input_gamma_table(struct curveType *TRC)
1360 - return gamma_table;
1362 + validate_gamma_table(gamma_table);
1364 + return gamma_table;
1367 struct matrix build_colorant_matrix(qcms_profile *p)
1368 @@ -390,7 +408,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
1369 which has an maximum error of about 9855 (pixel difference of ~38.346)
1371 For now, we punt the decision of output size to the caller. */
1372 -static uint16_t *invert_lut(uint16_t *table, int length, int out_length)
1373 +static uint16_t *invert_lut(uint16_t *table, int length, size_t out_length)
1376 /* for now we invert the lut by creating a lut of size out_length
1377 diff --git a/third_party/qcms/src/transform_util.h b/third_party/qcms/src/transform_util.h
1378 index 8f358a8..de465f4 100644
1379 --- a/third_party/qcms/src/transform_util.h
1380 +++ b/third_party/qcms/src/transform_util.h
1382 //XXX: could use a bettername
1383 typedef uint16_t uint16_fract_t;
1385 -float lut_interp_linear(double value, uint16_t *table, int length);
1386 -float lut_interp_linear_float(float value, float *table, int length);
1387 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length);
1388 +float lut_interp_linear(double value, uint16_t *table, size_t length);
1389 +float lut_interp_linear_float(float value, float *table, size_t length);
1390 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length);
1393 static inline float lerp(float a, float b, float t)