• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c
2index 36b7011..69b7141 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)
7 	       return false;
8
9-       if (profile->A2B0 || profile->B2A0)
10+       if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0))
11                return false;
12
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;
17
18+#if defined (_MSC_VER)
19+#pragma warning(push)
20+/* Disable double to float truncation warning 4305 */
21+#pragma warning(disable:4305)
22+#endif
23        // Build our target vector (see mozilla bug 460629)
24        target[0] = 0.96420;
25        target[1] = 1.00000;
26@@ -310,6 +315,10 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
27        tolerance[1] = 0.02;
28        tolerance[2] = 0.04;
29
30+#if defined (_MSC_VER)
31+/* Restore warnings */
32+#pragma warning(pop)
33+#endif
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
42
43 static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
44 {
45@@ -344,6 +354,47 @@ static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
46 	return tag;
47 }
48
49+#define DESC_TYPE 0x64657363 // 'desc'
50+#define MLUC_TYPE 0x6d6c7563 // 'mluc'
51+
52+static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
53+{
54+	struct tag *tag = find_tag(index, tag_id);
55+	if (tag) {
56+		const uint32_t limit = sizeof profile->description;
57+		uint32_t offset = tag->offset;
58+		uint32_t type = read_u32(src, offset);
59+		uint32_t length = read_u32(src, offset+8);
60+		uint32_t i, description;
61+		if (length && type == MLUC_TYPE) {
62+			length = read_u32(src, offset+20);
63+			if (!length || (length & 1) || (read_u32(src, offset+12) != 12))
64+				goto invalid_desc_tag;
65+			description = offset + read_u32(src, offset+24);
66+			if (!src->valid)
67+				goto invalid_desc_tag;
68+		} else if (length && type == DESC_TYPE) {
69+			description = offset + 12;
70+		} else {
71+			goto invalid_desc_tag;
72+		}
73+		if (length >= limit)
74+			length = limit - 1;
75+		for (i = 0; i < length; ++i)
76+			profile->description[i] = read_u8(src, description+i);
77+		profile->description[length] = 0;
78+	} else {
79+		goto invalid_desc_tag;
80+	}
81+
82+	if (src->valid)
83+		return true;
84+
85+invalid_desc_tag:
86+	invalid_source(src, "invalid description");
87+	return false;
88+}
89+
90 #define XYZ_TYPE		0x58595a20 // 'XYZ '
91 #define CURVE_TYPE		0x63757276 // 'curv'
92 #define PARAMETRIC_CURVE_TYPE	0x70617261 // 'para'
93@@ -402,7 +453,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_inde
94 // present that are not part of the tag_index.
95 static struct curveType *read_curveType(struct mem_source *src, uint32_t offset, uint32_t *len)
96 {
97-	static const size_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
98+	static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
99 	struct curveType *curve = NULL;
100 	uint32_t type = read_u32(src, offset);
101 	uint32_t count;
102@@ -484,19 +535,23 @@ static void read_nested_curveType(struct mem_source *src, struct curveType *(*cu
103 	uint32_t channel_offset = 0;
104 	int i;
105 	for (i = 0; i < num_channels; i++) {
106-		uint32_t tag_len;
107+		uint32_t tag_len = ~0;
108
109 		(*curveArray)[i] = read_curveType(src, curve_offset + channel_offset, &tag_len);
110 		if (!(*curveArray)[i]) {
111 			invalid_source(src, "invalid nested curveType curve");
112 		}
113
114+		if (tag_len == ~0) {
115+			invalid_source(src, "invalid nested curveType tag length");
116+			return;
117+		}
118+
119 		channel_offset += tag_len;
120 		// 4 byte aligned
121 		if ((tag_len % 4) != 0)
122 			channel_offset += 4 - (tag_len % 4);
123 	}
124-
125 }
126
127 static void mAB_release(struct lutmABType *lut)
128@@ -657,7 +712,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
129 	uint16_t num_input_table_entries;
130 	uint16_t num_output_table_entries;
131 	uint8_t in_chan, grid_points, out_chan;
132-	uint32_t clut_offset, output_offset;
133+	size_t clut_offset, output_offset;
134 	uint32_t clut_size;
135 	size_t entry_size;
136 	struct lutType *lut;
137@@ -979,6 +1034,9 @@ qcms_profile* qcms_profile_sRGB(void)
138 		return NO_MEM_PROFILE;
139
140 	profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024);
141+	if (profile)
142+		strcpy(profile->description, "sRGB IEC61966-2.1");
143+
144 	free(table);
145 	return profile;
146 }
147@@ -997,6 +1055,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
148 	source.size = size;
149 	source.valid = true;
150
151+	if (size < 4)
152+		return INVALID_PROFILE;
153+
154 	length = read_u32(src, 0);
155 	if (length <= size) {
156 		// shrink the area that we can read if appropriate
157@@ -1028,6 +1089,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
158 	if (!src->valid || !index.tags)
159 		goto invalid_tag_table;
160
161+	if (!read_tag_descType(profile, src, index, TAG_desc))
162+		goto invalid_tag_table;
163+
164 	if (find_tag(index, TAG_CHAD)) {
165 		profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD);
166 	} else {
167@@ -1098,6 +1162,11 @@ invalid_profile:
168 	return INVALID_PROFILE;
169 }
170
171+qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2)
172+{
173+    return memcmp(p1->description, p2->description, sizeof p1->description) == 0;
174+}
175+
176 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile)
177 {
178 	return profile->rendering_intent;
179diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h
180index 7d83623..e59528a 100644
181--- a/third_party/qcms/src/qcms.h
182+++ b/third_party/qcms/src/qcms.h
183@@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written
184 authorization from SunSoft Inc.
185 ******************************************************************/
186
187+/*
188+ * QCMS, in general, is not threadsafe. However, it should be safe to create
189+ * profile and transformation objects on different threads, so long as you
190+ * don't use the same objects on different threads at the same time.
191+ */
192+
193 /*
194  * Color Space Signatures
195  * Note that only icSigXYZData and icSigLabData are valid
196@@ -102,6 +108,12 @@ typedef enum {
197 	QCMS_DATA_GRAYA_8
198 } qcms_data_type;
199
200+/* Format of the output data for qcms_transform_data_type() */
201+typedef enum {
202+	QCMS_OUTPUT_RGBX,
203+	QCMS_OUTPUT_BGRX
204+} qcms_output_type;
205+
206 /* the names for the following two types are sort of ugly */
207 typedef struct
208 {
209@@ -136,6 +148,8 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile);
210 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile);
211 icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile);
212
213+qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2);
214+
215 void qcms_profile_precache_output_transform(qcms_profile *profile);
216
217 qcms_transform* qcms_transform_create(
218@@ -146,6 +160,7 @@ qcms_transform* qcms_transform_create(
219 void qcms_transform_release(qcms_transform *);
220
221 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length);
222+void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type);
223
224 void qcms_enable_iccv4();
225
226diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h
227index 53a3420..4116ed5 100644
228--- a/third_party/qcms/src/qcmsint.h
229+++ b/third_party/qcms/src/qcmsint.h
230@@ -45,6 +45,11 @@ struct precache_output
231 #define ALIGN __attribute__(( aligned (16) ))
232 #endif
233
234+typedef struct _qcms_format_type {
235+	int r;
236+	int b;
237+} qcms_format_type;
238+
239 struct _qcms_transform {
240 	float ALIGN matrix[3][4];
241 	float *input_gamma_table_r;
242@@ -88,7 +93,7 @@ struct _qcms_transform {
243 	struct precache_output *output_table_g;
244 	struct precache_output *output_table_b;
245
246-	void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length);
247+	void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, struct _qcms_format_type output_format);
248 };
249
250 struct matrix {
251@@ -225,6 +230,7 @@ struct tag_value {
252 #define LAB_SIGNATURE  0x4C616220
253
254 struct _qcms_profile {
255+	char description[64];
256 	uint32_t class;
257 	uint32_t color_space;
258 	uint32_t pcs;
259@@ -280,18 +286,40 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
260 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
261                                           unsigned char *src,
262                                           unsigned char *dest,
263-                                          size_t length);
264+                                          size_t length,
265+                                          qcms_format_type output_format);
266 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
267                                           unsigned char *src,
268                                           unsigned char *dest,
269-                                          size_t length);
270+                                          size_t length,
271+                                          qcms_format_type output_format);
272 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
273                                           unsigned char *src,
274                                           unsigned char *dest,
275-                                          size_t length);
276+                                          size_t length,
277+                                          qcms_format_type output_format);
278 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
279                                           unsigned char *src,
280                                           unsigned char *dest,
281-                                          size_t length);
282+                                          size_t length,
283+                                          qcms_format_type output_format);
284
285 extern qcms_bool qcms_supports_iccv4;
286+
287+
288+#ifdef _MSC_VER
289+
290+long __cdecl _InterlockedIncrement(long volatile *);
291+long __cdecl _InterlockedDecrement(long volatile *);
292+#pragma intrinsic(_InterlockedIncrement)
293+#pragma intrinsic(_InterlockedDecrement)
294+
295+#define qcms_atomic_increment(x) _InterlockedIncrement((long volatile *)&x)
296+#define qcms_atomic_decrement(x) _InterlockedDecrement((long volatile*)&x)
297+
298+#else
299+
300+#define qcms_atomic_increment(x) __sync_add_and_fetch(&x, 1)
301+#define qcms_atomic_decrement(x) __sync_sub_and_fetch(&x, 1)
302+
303+#endif
304diff --git a/third_party/qcms/src/qcmstypes.h b/third_party/qcms/src/qcmstypes.h
305index 56d8de3..d58f691 100644
306--- a/third_party/qcms/src/qcmstypes.h
307+++ b/third_party/qcms/src/qcmstypes.h
308@@ -22,37 +22,6 @@
309 #ifndef QCMS_TYPES_H
310 #define QCMS_TYPES_H
311
312-#ifdef MOZ_QCMS
313-
314-#include "prtypes.h"
315-
316-/* prtypes.h defines IS_LITTLE_ENDIAN and IS_BIG ENDIAN */
317-
318-#if defined (__SVR4) && defined (__sun)
319-/* int_types.h gets included somehow, so avoid redefining the types differently */
320-#include <sys/int_types.h>
321-#elif defined (_AIX)
322-#include <sys/types.h>
323-#elif !defined(ANDROID) && !defined(__OpenBSD__)
324-typedef PRInt8 int8_t;
325-typedef PRUint8 uint8_t;
326-typedef PRInt16 int16_t;
327-typedef PRUint16 uint16_t;
328-typedef PRInt32 int32_t;
329-typedef PRUint32 uint32_t;
330-typedef PRInt64 int64_t;
331-typedef PRUint64 uint64_t;
332-
333-#ifdef __OS2__
334-/* OS/2's stdlib typdefs uintptr_t. So we'll just include that so we don't collide */
335-#include <stdlib.h>
336-#elif !defined(__intptr_t_defined) && !defined(_UINTPTR_T_DEFINED)
337-typedef PRUptrdiff uintptr_t;
338-#endif
339-#endif
340-
341-#else // MOZ_QCMS
342-
343 #if BYTE_ORDER == LITTLE_ENDIAN
344 #define IS_LITTLE_ENDIAN
345 #elif BYTE_ORDER == BIG_ENDIAN
346@@ -75,7 +44,7 @@ typedef PRUptrdiff uintptr_t;
347
348 #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__)
349 #  include <inttypes.h>
350-#elif defined (_MSC_VER)
351+#elif defined (_MSC_VER) && _MSC_VER < 1600
352 typedef __int8 int8_t;
353 typedef unsigned __int8 uint8_t;
354 typedef __int16 int16_t;
355@@ -87,7 +56,12 @@ typedef unsigned __int64 uint64_t;
356 #ifdef _WIN64
357 typedef unsigned __int64 uintptr_t;
358 #else
359+#pragma warning(push)
360+/* Disable benign redefinition of type warning 4142 */
361+#pragma warning(disable:4142)
362 typedef unsigned long uintptr_t;
363+/* Restore warnings */
364+#pragma warning(pop)
365 #endif
366
367 #elif defined (_AIX)
368@@ -96,8 +70,6 @@ typedef unsigned long uintptr_t;
369 #  include <stdint.h>
370 #endif
371
372-#endif
373-
374 typedef qcms_bool bool;
375 #define true 1
376 #define false 0
377diff --git a/third_party/qcms/src/transform-sse1.c b/third_party/qcms/src/transform-sse1.c
378index 2f34db5..aaee1bf 100644
379--- a/third_party/qcms/src/transform-sse1.c
380+++ b/third_party/qcms/src/transform-sse1.c
381@@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
382 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
383                                           unsigned char *src,
384                                           unsigned char *dest,
385-                                          size_t length)
386+                                          size_t length,
387+                                          qcms_format_type output_format)
388 {
389     unsigned int i;
390     float (*mat)[4] = transform->matrix;
391@@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
392
393     /* working variables */
394     __m128 vec_r, vec_g, vec_b, result;
395+    const int r_out = output_format.r;
396+    const int b_out = output_format.b;
397
398     /* CYA */
399     if (!length)
400@@ -116,9 +119,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
401         src += 3;
402
403         /* use calc'd indices to output RGB values */
404-        dest[0] = otdata_r[output[0]];
405-        dest[1] = otdata_g[output[1]];
406-        dest[2] = otdata_b[output[2]];
407+        dest[r_out] = otdata_r[output[0]];
408+        dest[1]     = otdata_g[output[1]];
409+        dest[b_out] = otdata_b[output[2]];
410         dest += 3;
411     }
412
413@@ -141,9 +144,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
414     result = _mm_movehl_ps(result, result);
415     *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
416
417-    dest[0] = otdata_r[output[0]];
418-    dest[1] = otdata_g[output[1]];
419-    dest[2] = otdata_b[output[2]];
420+    dest[r_out] = otdata_r[output[0]];
421+    dest[1]     = otdata_g[output[1]];
422+    dest[b_out] = otdata_b[output[2]];
423
424     _mm_empty();
425 }
426@@ -151,7 +154,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
427 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
428                                            unsigned char *src,
429                                            unsigned char *dest,
430-                                           size_t length)
431+                                           size_t length,
432+                                           qcms_format_type output_format)
433 {
434     unsigned int i;
435     float (*mat)[4] = transform->matrix;
436@@ -187,6 +191,8 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
437
438     /* working variables */
439     __m128 vec_r, vec_g, vec_b, result;
440+    const int r_out = output_format.r;
441+    const int b_out = output_format.b;
442     unsigned char alpha;
443
444     /* CYA */
445@@ -239,9 +245,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
446         src += 4;
447
448         /* use calc'd indices to output RGB values */
449-        dest[0] = otdata_r[output[0]];
450-        dest[1] = otdata_g[output[1]];
451-        dest[2] = otdata_b[output[2]];
452+        dest[r_out] = otdata_r[output[0]];
453+        dest[1]     = otdata_g[output[1]];
454+        dest[b_out] = otdata_b[output[2]];
455         dest += 4;
456     }
457
458@@ -266,9 +272,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
459     result = _mm_movehl_ps(result, result);
460     *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
461
462-    dest[0] = otdata_r[output[0]];
463-    dest[1] = otdata_g[output[1]];
464-    dest[2] = otdata_b[output[2]];
465+    dest[r_out] = otdata_r[output[0]];
466+    dest[1]     = otdata_g[output[1]];
467+    dest[b_out] = otdata_b[output[2]];
468
469     _mm_empty();
470 }
471diff --git a/third_party/qcms/src/transform-sse2.c b/third_party/qcms/src/transform-sse2.c
472index 6a5faf9..fa7f2d1 100644
473--- a/third_party/qcms/src/transform-sse2.c
474+++ b/third_party/qcms/src/transform-sse2.c
475@@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
476 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
477                                           unsigned char *src,
478                                           unsigned char *dest,
479-                                          size_t length)
480+                                          size_t length,
481+                                          qcms_format_type output_format)
482 {
483     unsigned int i;
484     float (*mat)[4] = transform->matrix;
485@@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
486
487     /* working variables */
488     __m128 vec_r, vec_g, vec_b, result;
489+    const int r_out = output_format.r;
490+    const int b_out = output_format.b;
491
492     /* CYA */
493     if (!length)
494@@ -114,9 +117,9 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
495         src += 3;
496
497         /* use calc'd indices to output RGB values */
498-        dest[0] = otdata_r[output[0]];
499-        dest[1] = otdata_g[output[1]];
500-        dest[2] = otdata_b[output[2]];
501+        dest[r_out] = otdata_r[output[0]];
502+        dest[1]     = otdata_g[output[1]];
503+        dest[b_out] = otdata_b[output[2]];
504         dest += 3;
505     }
506
507@@ -137,15 +140,16 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
508
509     _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
510
511-    dest[0] = otdata_r[output[0]];
512-    dest[1] = otdata_g[output[1]];
513-    dest[2] = otdata_b[output[2]];
514+    dest[r_out] = otdata_r[output[0]];
515+    dest[1]     = otdata_g[output[1]];
516+    dest[b_out] = otdata_b[output[2]];
517 }
518
519 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
520                                            unsigned char *src,
521                                            unsigned char *dest,
522-                                           size_t length)
523+                                           size_t length,
524+                                           qcms_format_type output_format)
525 {
526     unsigned int i;
527     float (*mat)[4] = transform->matrix;
528@@ -181,6 +185,8 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
529
530     /* working variables */
531     __m128 vec_r, vec_g, vec_b, result;
532+    const int r_out = output_format.r;
533+    const int b_out = output_format.b;
534     unsigned char alpha;
535
536     /* CYA */
537@@ -231,9 +237,9 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
538         src += 4;
539
540         /* use calc'd indices to output RGB values */
541-        dest[0] = otdata_r[output[0]];
542-        dest[1] = otdata_g[output[1]];
543-        dest[2] = otdata_b[output[2]];
544+        dest[r_out] = otdata_r[output[0]];
545+        dest[1]     = otdata_g[output[1]];
546+        dest[b_out] = otdata_b[output[2]];
547         dest += 4;
548     }
549
550@@ -256,7 +262,7 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
551
552     _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
553
554-    dest[0] = otdata_r[output[0]];
555-    dest[1] = otdata_g[output[1]];
556-    dest[2] = otdata_b[output[2]];
557+    dest[r_out] = otdata_r[output[0]];
558+    dest[1]     = otdata_g[output[1]];
559+    dest[b_out] = otdata_b[output[2]];
560 }
561diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c
562index 9a6562b..08db142 100644
563--- a/third_party/qcms/src/transform.c
564+++ b/third_party/qcms/src/transform.c
565@@ -181,11 +181,20 @@ compute_chromatic_adaption(struct CIE_XYZ source_white_point,
566 static struct matrix
567 adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination)
568 {
569+#if defined (_MSC_VER)
570+#pragma warning(push)
571+/* Disable double to float truncation warning 4305 */
572+#pragma warning(disable:4305)
573+#endif
574 	struct matrix lam_rigg = {{ // Bradford matrix
575 	                         {  0.8951,  0.2664, -0.1614 },
576 	                         { -0.7502,  1.7135,  0.0367 },
577 	                         {  0.0389, -0.0685,  1.0296 }
578 	                         }};
579+#if defined (_MSC_VER)
580+/* Restore warnings */
581+#pragma warning(pop)
582+#endif
583 	return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg);
584 }
585
586@@ -230,8 +239,11 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
587 }
588
589 #if 0
590-static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
591+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)
592 {
593+	const int r_out = output_format.r;
594+	const int b_out = output_format.b;
595+
596 	int i;
597 	float (*mat)[4] = transform->matrix;
598 	for (i=0; i<length; i++) {
599@@ -251,15 +263,19 @@ static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned
600 		float out_device_g = pow(out_linear_g, transform->out_gamma_g);
601 		float out_device_b = pow(out_linear_b, transform->out_gamma_b);
602
603-		*dest++ = clamp_u8(255*out_device_r);
604-		*dest++ = clamp_u8(255*out_device_g);
605-		*dest++ = clamp_u8(255*out_device_b);
606+		dest[r_out] = clamp_u8(out_device_r*255);
607+		dest[1]     = clamp_u8(out_device_g*255);
608+		dest[b_out] = clamp_u8(out_device_b*255);
609+		dest += 3;
610 	}
611 }
612 #endif
613
614-static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
615+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)
616 {
617+	const int r_out = output_format.r;
618+	const int b_out = output_format.b;
619+
620 	unsigned int i;
621 	for (i = 0; i < length; i++) {
622 		float out_device_r, out_device_g, out_device_b;
623@@ -267,13 +283,14 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
624
625 		float linear = transform->input_gamma_table_gray[device];
626
627-                out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
628+		out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
629 		out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
630 		out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
631
632-		*dest++ = clamp_u8(out_device_r*255);
633-		*dest++ = clamp_u8(out_device_g*255);
634-		*dest++ = clamp_u8(out_device_b*255);
635+		dest[r_out] = clamp_u8(out_device_r*255);
636+		dest[1]     = clamp_u8(out_device_g*255);
637+		dest[b_out] = clamp_u8(out_device_b*255);
638+		dest += 3;
639 	}
640 }
641
642@@ -283,8 +300,11 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
643 	See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
644 */
645
646-static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
647+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)
648 {
649+	const int r_out = output_format.r;
650+	const int b_out = output_format.b;
651+
652 	unsigned int i;
653 	for (i = 0; i < length; i++) {
654 		float out_device_r, out_device_g, out_device_b;
655@@ -293,20 +313,24 @@ static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigne
656
657 		float linear = transform->input_gamma_table_gray[device];
658
659-                out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
660+		out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
661 		out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
662 		out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
663
664-		*dest++ = clamp_u8(out_device_r*255);
665-		*dest++ = clamp_u8(out_device_g*255);
666-		*dest++ = clamp_u8(out_device_b*255);
667-		*dest++ = alpha;
668+		dest[r_out] = clamp_u8(out_device_r*255);
669+		dest[1]     = clamp_u8(out_device_g*255);
670+		dest[b_out] = clamp_u8(out_device_b*255);
671+		dest[3]     = alpha;
672+		dest += 4;
673 	}
674 }
675
676
677-static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
678+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)
679 {
680+	const int r_out = output_format.r;
681+	const int b_out = output_format.b;
682+
683 	unsigned int i;
684 	for (i = 0; i < length; i++) {
685 		unsigned char device = *src++;
686@@ -317,14 +341,19 @@ static void qcms_transform_data_gray_out_precache(qcms_transform *transform, uns
687 		/* we could round here... */
688 		gray = linear * PRECACHE_OUTPUT_MAX;
689
690-		*dest++ = transform->output_table_r->data[gray];
691-		*dest++ = transform->output_table_g->data[gray];
692-		*dest++ = transform->output_table_b->data[gray];
693+		dest[r_out] = transform->output_table_r->data[gray];
694+		dest[1]     = transform->output_table_g->data[gray];
695+		dest[b_out] = transform->output_table_b->data[gray];
696+		dest += 3;
697 	}
698 }
699
700-static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
701+
702+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)
703 {
704+	const int r_out = output_format.r;
705+	const int b_out = output_format.b;
706+
707 	unsigned int i;
708 	for (i = 0; i < length; i++) {
709 		unsigned char device = *src++;
710@@ -336,15 +365,19 @@ static void qcms_transform_data_graya_out_precache(qcms_transform *transform, un
711 		/* we could round here... */
712 		gray = linear * PRECACHE_OUTPUT_MAX;
713
714-		*dest++ = transform->output_table_r->data[gray];
715-		*dest++ = transform->output_table_g->data[gray];
716-		*dest++ = transform->output_table_b->data[gray];
717-		*dest++ = alpha;
718+		dest[r_out] = transform->output_table_r->data[gray];
719+		dest[1]     = transform->output_table_g->data[gray];
720+		dest[b_out] = transform->output_table_b->data[gray];
721+		dest[3]     = alpha;
722+		dest += 4;
723 	}
724 }
725
726-static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
727+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)
728 {
729+	const int r_out = output_format.r;
730+	const int b_out = output_format.b;
731+
732 	unsigned int i;
733 	float (*mat)[4] = transform->matrix;
734 	for (i = 0; i < length; i++) {
735@@ -370,14 +403,18 @@ static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform,
736 		g = out_linear_g * PRECACHE_OUTPUT_MAX;
737 		b = out_linear_b * PRECACHE_OUTPUT_MAX;
738
739-		*dest++ = transform->output_table_r->data[r];
740-		*dest++ = transform->output_table_g->data[g];
741-		*dest++ = transform->output_table_b->data[b];
742+		dest[r_out] = transform->output_table_r->data[r];
743+		dest[1]     = transform->output_table_g->data[g];
744+		dest[b_out] = transform->output_table_b->data[b];
745+		dest += 3;
746 	}
747 }
748
749-static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
750+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)
751 {
752+	const int r_out = output_format.r;
753+	const int b_out = output_format.b;
754+
755 	unsigned int i;
756 	float (*mat)[4] = transform->matrix;
757 	for (i = 0; i < length; i++) {
758@@ -404,16 +441,21 @@ static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform,
759 		g = out_linear_g * PRECACHE_OUTPUT_MAX;
760 		b = out_linear_b * PRECACHE_OUTPUT_MAX;
761
762-		*dest++ = transform->output_table_r->data[r];
763-		*dest++ = transform->output_table_g->data[g];
764-		*dest++ = transform->output_table_b->data[b];
765-		*dest++ = alpha;
766+		dest[r_out] = transform->output_table_r->data[r];
767+		dest[1]     = transform->output_table_g->data[g];
768+		dest[b_out] = transform->output_table_b->data[b];
769+		dest[3]     = alpha;
770+		dest += 4;
771 	}
772 }
773
774 // Not used
775 /*
776-static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
777+static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
778+{
779+	const int r_out = output_format.r;
780+	const int b_out = output_format.b;
781+
782 	unsigned int i;
783 	int xy_len = 1;
784 	int x_len = transform->grid_size;
785@@ -462,15 +504,20 @@ static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *s
786 		float b_y2 = lerp(b_x3, b_x4, y_d);
787 		float clut_b = lerp(b_y1, b_y2, z_d);
788
789-		*dest++ = clamp_u8(clut_r*255.0f);
790-		*dest++ = clamp_u8(clut_g*255.0f);
791-		*dest++ = clamp_u8(clut_b*255.0f);
792-	}
793+		dest[r_out] = clamp_u8(clut_r*255.0f);
794+		dest[1]     = clamp_u8(clut_g*255.0f);
795+		dest[b_out] = clamp_u8(clut_b*255.0f);
796+		dest += 3;
797+	}
798 }
799 */
800
801 // Using lcms' tetra interpolation algorithm.
802-static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
803+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)
804+{
805+	const int r_out = output_format.r;
806+	const int b_out = output_format.b;
807+
808 	unsigned int i;
809 	int xy_len = 1;
810 	int x_len = transform->grid_size;
811@@ -577,15 +624,20 @@ static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsig
812 		clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
813 		clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
814
815-		*dest++ = clamp_u8(clut_r*255.0f);
816-		*dest++ = clamp_u8(clut_g*255.0f);
817-		*dest++ = clamp_u8(clut_b*255.0f);
818-		*dest++ = in_a;
819-	}
820+		dest[r_out] = clamp_u8(clut_r*255.0f);
821+		dest[1]     = clamp_u8(clut_g*255.0f);
822+		dest[b_out] = clamp_u8(clut_b*255.0f);
823+		dest[3]     = in_a;
824+		dest += 4;
825+	}
826 }
827
828 // Using lcms' tetra interpolation code.
829-static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
830+static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
831+{
832+	const int r_out = output_format.r;
833+	const int b_out = output_format.b;
834+
835 	unsigned int i;
836 	int xy_len = 1;
837 	int x_len = transform->grid_size;
838@@ -691,14 +743,18 @@ static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned c
839 		clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
840 		clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
841
842-		*dest++ = clamp_u8(clut_r*255.0f);
843-		*dest++ = clamp_u8(clut_g*255.0f);
844-		*dest++ = clamp_u8(clut_b*255.0f);
845-	}
846+		dest[r_out] = clamp_u8(clut_r*255.0f);
847+		dest[1]     = clamp_u8(clut_g*255.0f);
848+		dest[b_out] = clamp_u8(clut_b*255.0f);
849+		dest += 3;
850+	}
851 }
852
853-static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
854+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)
855 {
856+	const int r_out = output_format.r;
857+	const int b_out = output_format.b;
858+
859 	unsigned int i;
860 	float (*mat)[4] = transform->matrix;
861 	for (i = 0; i < length; i++) {
862@@ -726,14 +782,18 @@ static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned
863 		out_device_b = lut_interp_linear(out_linear_b,
864 				transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
865
866-		*dest++ = clamp_u8(out_device_r*255);
867-		*dest++ = clamp_u8(out_device_g*255);
868-		*dest++ = clamp_u8(out_device_b*255);
869+		dest[r_out] = clamp_u8(out_device_r*255);
870+		dest[1]     = clamp_u8(out_device_g*255);
871+		dest[b_out] = clamp_u8(out_device_b*255);
872+		dest += 3;
873 	}
874 }
875
876-static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
877+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)
878 {
879+	const int r_out = output_format.r;
880+	const int b_out = output_format.b;
881+
882 	unsigned int i;
883 	float (*mat)[4] = transform->matrix;
884 	for (i = 0; i < length; i++) {
885@@ -762,16 +822,20 @@ static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned
886 		out_device_b = lut_interp_linear(out_linear_b,
887 				transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
888
889-		*dest++ = clamp_u8(out_device_r*255);
890-		*dest++ = clamp_u8(out_device_g*255);
891-		*dest++ = clamp_u8(out_device_b*255);
892-		*dest++ = alpha;
893+		dest[r_out] = clamp_u8(out_device_r*255);
894+		dest[1]     = clamp_u8(out_device_g*255);
895+		dest[b_out] = clamp_u8(out_device_b*255);
896+		dest[3]     = alpha;
897+		dest += 4;
898 	}
899 }
900
901 #if 0
902-static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
903+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)
904 {
905+	const int r_out = output_format.r;
906+	const int b_out = output_format.b;
907+
908 	int i;
909 	float (*mat)[4] = transform->matrix;
910 	for (i = 0; i < length; i++) {
911@@ -787,16 +851,25 @@ static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsign
912 		float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
913 		float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
914
915-		*dest++ = clamp_u8(out_linear_r*255);
916-		*dest++ = clamp_u8(out_linear_g*255);
917-		*dest++ = clamp_u8(out_linear_b*255);
918+		dest[r_out] = clamp_u8(out_linear_r*255);
919+		dest[1]     = clamp_u8(out_linear_g*255);
920+		dest[b_out] = clamp_u8(out_linear_b*255);
921+		dest += 3;
922 	}
923 }
924 #endif
925
926+/*
927+ * If users create and destroy objects on different threads, even if the same
928+ * objects aren't used on different threads at the same time, we can still run
929+ * in to trouble with refcounts if they aren't atomic.
930+ *
931+ * This can lead to us prematurely deleting the precache if threads get unlucky
932+ * and write the wrong value to the ref count.
933+ */
934 static struct precache_output *precache_reference(struct precache_output *p)
935 {
936-	p->ref_count++;
937+	qcms_atomic_increment(p->ref_count);
938 	return p;
939 }
940
941@@ -810,12 +883,12 @@ static struct precache_output *precache_create()
942
943 void precache_release(struct precache_output *p)
944 {
945-	if (--p->ref_count == 0) {
946+	if (qcms_atomic_decrement(p->ref_count) == 0) {
947 		free(p);
948 	}
949 }
950
951-#ifdef HAS_POSIX_MEMALIGN
952+#ifdef HAVE_POSIX_MEMALIGN
953 static qcms_transform *transform_alloc(void)
954 {
955 	qcms_transform *t;
956@@ -994,13 +1067,15 @@ void qcms_profile_precache_output_transform(qcms_profile *profile)
957 	if (profile->color_space != RGB_SIGNATURE)
958 		return;
959
960-	/* don't precache since we will use the B2A LUT */
961-	if (profile->B2A0)
962-		return;
963+	if (qcms_supports_iccv4) {
964+		/* don't precache since we will use the B2A LUT */
965+		if (profile->B2A0)
966+			return;
967
968-	/* don't precache since we will use the mBA LUT */
969-	if (profile->mBA)
970-		return;
971+		/* don't precache since we will use the mBA LUT */
972+		if (profile->mBA)
973+			return;
974+	}
975
976 	/* don't precache if we do not have the TRC curves */
977 	if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC)
978@@ -1078,7 +1153,8 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
979 	//XXX: qcms_modular_transform_data may return either the src or dest buffer. If so it must not be free-ed
980 	if (src && lut != src) {
981 		free(src);
982-	} else if (dest && lut != src) {
983+	}
984+	if (dest && lut != dest) {
985 		free(dest);
986 	}
987
988@@ -1157,14 +1233,14 @@ qcms_transform* qcms_transform_create(
989                 	return NULL;
990             	}
991 		if (precache) {
992-#ifdef X86
993+#if defined(SSE2_ENABLE) && defined(X86)
994 		    if (sse_version_available() >= 2) {
995 			    if (in_type == QCMS_DATA_RGB_8)
996 				    transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2;
997 			    else
998 				    transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2;
999
1000-#if !(defined(_MSC_VER) && defined(_M_AMD64))
1001+#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64))
1002                     /* Microsoft Compiler for x64 doesn't support MMX.
1003                      * SSE code uses MMX so that we disable on x64 */
1004 		    } else
1005@@ -1256,13 +1332,34 @@ qcms_transform* qcms_transform_create(
1006 	return transform;
1007 }
1008
1009-#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
1010+/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on unused
1011+ * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the presence
1012+ * of the attribute but is currently only supported by clang */
1013+#if defined(__has_attribute)
1014+#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__)
1015+#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defined(__arm__) && !defined(__mips__)
1016+#define HAS_FORCE_ALIGN_ARG_POINTER 1
1017+#else
1018+#define HAS_FORCE_ALIGN_ARG_POINTER 0
1019+#endif
1020+
1021+#if HAS_FORCE_ALIGN_ARG_POINTER
1022 /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
1023 __attribute__((__force_align_arg_pointer__))
1024 #endif
1025 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length)
1026 {
1027-	transform->transform_fn(transform, src, dest, length);
1028+	static const struct _qcms_format_type output_rgbx = { 0, 2 };
1029+
1030+	transform->transform_fn(transform, src, dest, length, output_rgbx);
1031+}
1032+
1033+void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type)
1034+{
1035+	static const struct _qcms_format_type output_rgbx = { 0, 2 };
1036+	static const struct _qcms_format_type output_bgrx = { 2, 0 };
1037+
1038+	transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPUT_BGRX ? output_bgrx : output_rgbx);
1039 }
1040
1041 qcms_bool qcms_supports_iccv4;
1042diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c
1043index e8447e5..f4338b2 100644
1044--- a/third_party/qcms/src/transform_util.c
1045+++ b/third_party/qcms/src/transform_util.c
1046@@ -36,7 +36,7 @@
1047
1048 /* value must be a value between 0 and 1 */
1049 //XXX: is the above a good restriction to have?
1050-float lut_interp_linear(double value, uint16_t *table, int length)
1051+float lut_interp_linear(double value, uint16_t *table, size_t length)
1052 {
1053 	int upper, lower;
1054 	value = value * (length - 1); // scale to length of the array
1055@@ -49,11 +49,11 @@ float lut_interp_linear(double value, uint16_t *table, int length)
1056 }
1057
1058 /* same as above but takes and returns a uint16_t value representing a range from 0..1 */
1059-uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
1060+uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length)
1061 {
1062 	/* Start scaling input_value to the length of the array: 65535*(length-1).
1063 	 * We'll divide out the 65535 next */
1064-	uint32_t value = (input_value * (length - 1));
1065+	uintptr_t value = (input_value * (length - 1));
1066 	uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65535) */
1067 	uint32_t lower = value / 65535;           /* equivalent to floor(value/65535) */
1068 	/* interp is the distance from upper to value scaled to 0..65535 */
1069@@ -67,11 +67,11 @@ uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
1070 /* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX
1071  * and returns a uint8_t value representing a range from 0..1 */
1072 static
1073-uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, int length)
1074+uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, size_t length)
1075 {
1076 	/* Start scaling input_value to the length of the array: PRECACHE_OUTPUT_MAX*(length-1).
1077 	 * We'll divide out the PRECACHE_OUTPUT_MAX next */
1078-	uint32_t value = (input_value * (length - 1));
1079+	uintptr_t value = (input_value * (length - 1));
1080
1081 	/* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */
1082 	uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX;
1083@@ -91,7 +91,7 @@ uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table,
1084
1085 /* value must be a value between 0 and 1 */
1086 //XXX: is the above a good restriction to have?
1087-float lut_interp_linear_float(float value, float *table, int length)
1088+float lut_interp_linear_float(float value, float *table, size_t length)
1089 {
1090         int upper, lower;
1091         value = value * (length - 1);
1092@@ -235,6 +235,21 @@ float u8Fixed8Number_to_float(uint16_t x)
1093 	return x/256.;
1094 }
1095
1096+/* The SSE2 code uses min & max which let NaNs pass through.
1097+   We want to try to prevent that here by ensuring that
1098+   gamma table is within expected values. */
1099+void validate_gamma_table(float gamma_table[256])
1100+{
1101+	int i;
1102+	for (i = 0; i < 256; i++) {
1103+		// Note: we check that the gamma is not in range
1104+		// instead of out of range so that we catch NaNs
1105+		if (!(gamma_table[i] >= 0.f && gamma_table[i] <= 1.f)) {
1106+			gamma_table[i] = 0.f;
1107+		}
1108+	}
1109+}
1110+
1111 float *build_input_gamma_table(struct curveType *TRC)
1112 {
1113 	float *gamma_table;
1114@@ -254,7 +269,10 @@ float *build_input_gamma_table(struct curveType *TRC)
1115 			}
1116 		}
1117 	}
1118-        return gamma_table;
1119+
1120+	validate_gamma_table(gamma_table);
1121+
1122+	return gamma_table;
1123 }
1124
1125 struct matrix build_colorant_matrix(qcms_profile *p)
1126@@ -390,7 +408,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
1127  which has an maximum error of about 9855 (pixel difference of ~38.346)
1128
1129  For now, we punt the decision of output size to the caller. */
1130-static uint16_t *invert_lut(uint16_t *table, int length, int out_length)
1131+static uint16_t *invert_lut(uint16_t *table, int length, size_t out_length)
1132 {
1133         int i;
1134         /* for now we invert the lut by creating a lut of size out_length
1135diff --git a/third_party/qcms/src/transform_util.h b/third_party/qcms/src/transform_util.h
1136index 8f358a8..de465f4 100644
1137--- a/third_party/qcms/src/transform_util.h
1138+++ b/third_party/qcms/src/transform_util.h
1139@@ -31,9 +31,9 @@
1140 //XXX: could use a bettername
1141 typedef uint16_t uint16_fract_t;
1142
1143-float lut_interp_linear(double value, uint16_t *table, int length);
1144-float lut_interp_linear_float(float value, float *table, int length);
1145-uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length);
1146+float lut_interp_linear(double value, uint16_t *table, size_t length);
1147+float lut_interp_linear_float(float value, float *table, size_t length);
1148+uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length);
1149
1150
1151 static inline float lerp(float a, float b, float t)
1152