1 diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c
2 index 36b7011..9ee6b94 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 @@ -402,7 +411,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_inde
38 // present that are not part of the tag_index.
39 static struct curveType *read_curveType(struct mem_source *src, uint32_t offset, uint32_t *len)
41 - static const size_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
42 + static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
43 struct curveType *curve = NULL;
44 uint32_t type = read_u32(src, offset);
46 @@ -657,7 +666,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
47 uint16_t num_input_table_entries;
48 uint16_t num_output_table_entries;
49 uint8_t in_chan, grid_points, out_chan;
50 - uint32_t clut_offset, output_offset;
51 + size_t clut_offset, output_offset;
55 @@ -997,6 +1006,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
60 + return INVALID_PROFILE;
62 length = read_u32(src, 0);
64 // shrink the area that we can read if appropriate
65 diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h
66 index 7d83623..11fe222 100644
67 --- a/third_party/qcms/src/qcms.h
68 +++ b/third_party/qcms/src/qcms.h
69 @@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written
70 authorization from SunSoft Inc.
71 ******************************************************************/
74 + * QCMS, in general, is not threadsafe. However, it should be safe to create
75 + * profile and transformation objects on different threads, so long as you
76 + * don't use the same objects on different threads at the same time.
80 * Color Space Signatures
81 * Note that only icSigXYZData and icSigLabData are valid
82 @@ -102,6 +108,12 @@ typedef enum {
86 +/* Format of the output data for qcms_transform_data_type() */
92 /* the names for the following two types are sort of ugly */
95 @@ -146,6 +158,7 @@ qcms_transform* qcms_transform_create(
96 void qcms_transform_release(qcms_transform *);
98 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length);
99 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type);
101 void qcms_enable_iccv4();
103 diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h
104 index 53a3420..fb53e96 100644
105 --- a/third_party/qcms/src/qcmsint.h
106 +++ b/third_party/qcms/src/qcmsint.h
107 @@ -45,6 +45,11 @@ struct precache_output
108 #define ALIGN __attribute__(( aligned (16) ))
111 +typedef struct _qcms_format_type {
116 struct _qcms_transform {
117 float ALIGN matrix[3][4];
118 float *input_gamma_table_r;
119 @@ -88,7 +93,7 @@ struct _qcms_transform {
120 struct precache_output *output_table_g;
121 struct precache_output *output_table_b;
123 - void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length);
124 + void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, struct _qcms_format_type output_format);
128 @@ -280,18 +285,40 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
129 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
134 + qcms_format_type output_format);
135 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
140 + qcms_format_type output_format);
141 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
146 + qcms_format_type output_format);
147 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
152 + qcms_format_type output_format);
154 extern qcms_bool qcms_supports_iccv4;
159 +long __cdecl _InterlockedIncrement(long volatile *);
160 +long __cdecl _InterlockedDecrement(long volatile *);
161 +#pragma intrinsic(_InterlockedIncrement)
162 +#pragma intrinsic(_InterlockedDecrement)
164 +#define qcms_atomic_increment(x) _InterlockedIncrement((long volatile *)&x)
165 +#define qcms_atomic_decrement(x) _InterlockedDecrement((long volatile*)&x)
169 +#define qcms_atomic_increment(x) __sync_add_and_fetch(&x, 1)
170 +#define qcms_atomic_decrement(x) __sync_sub_and_fetch(&x, 1)
173 diff --git a/third_party/qcms/src/qcmstypes.h b/third_party/qcms/src/qcmstypes.h
174 index 56d8de3..d58f691 100644
175 --- a/third_party/qcms/src/qcmstypes.h
176 +++ b/third_party/qcms/src/qcmstypes.h
183 -#include "prtypes.h"
185 -/* prtypes.h defines IS_LITTLE_ENDIAN and IS_BIG ENDIAN */
187 -#if defined (__SVR4) && defined (__sun)
188 -/* int_types.h gets included somehow, so avoid redefining the types differently */
189 -#include <sys/int_types.h>
190 -#elif defined (_AIX)
191 -#include <sys/types.h>
192 -#elif !defined(ANDROID) && !defined(__OpenBSD__)
193 -typedef PRInt8 int8_t;
194 -typedef PRUint8 uint8_t;
195 -typedef PRInt16 int16_t;
196 -typedef PRUint16 uint16_t;
197 -typedef PRInt32 int32_t;
198 -typedef PRUint32 uint32_t;
199 -typedef PRInt64 int64_t;
200 -typedef PRUint64 uint64_t;
203 -/* OS/2's stdlib typdefs uintptr_t. So we'll just include that so we don't collide */
205 -#elif !defined(__intptr_t_defined) && !defined(_UINTPTR_T_DEFINED)
206 -typedef PRUptrdiff uintptr_t;
212 #if BYTE_ORDER == LITTLE_ENDIAN
213 #define IS_LITTLE_ENDIAN
214 #elif BYTE_ORDER == BIG_ENDIAN
215 @@ -75,7 +44,7 @@ typedef PRUptrdiff uintptr_t;
217 #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__)
218 # include <inttypes.h>
219 -#elif defined (_MSC_VER)
220 +#elif defined (_MSC_VER) && _MSC_VER < 1600
221 typedef __int8 int8_t;
222 typedef unsigned __int8 uint8_t;
223 typedef __int16 int16_t;
224 @@ -87,7 +56,12 @@ typedef unsigned __int64 uint64_t;
226 typedef unsigned __int64 uintptr_t;
228 +#pragma warning(push)
229 +/* Disable benign redefinition of type warning 4142 */
230 +#pragma warning(disable:4142)
231 typedef unsigned long uintptr_t;
232 +/* Restore warnings */
233 +#pragma warning(pop)
237 @@ -96,8 +70,6 @@ typedef unsigned long uintptr_t;
243 typedef qcms_bool bool;
246 diff --git a/third_party/qcms/src/transform-sse1.c b/third_party/qcms/src/transform-sse1.c
247 index 2f34db5..aaee1bf 100644
248 --- a/third_party/qcms/src/transform-sse1.c
249 +++ b/third_party/qcms/src/transform-sse1.c
250 @@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
251 void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
256 + qcms_format_type output_format)
259 float (*mat)[4] = transform->matrix;
260 @@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
262 /* working variables */
263 __m128 vec_r, vec_g, vec_b, result;
264 + const int r_out = output_format.r;
265 + const int b_out = output_format.b;
269 @@ -116,9 +119,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
272 /* use calc'd indices to output RGB values */
273 - dest[0] = otdata_r[output[0]];
274 - dest[1] = otdata_g[output[1]];
275 - dest[2] = otdata_b[output[2]];
276 + dest[r_out] = otdata_r[output[0]];
277 + dest[1] = otdata_g[output[1]];
278 + dest[b_out] = otdata_b[output[2]];
282 @@ -141,9 +144,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
283 result = _mm_movehl_ps(result, result);
284 *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
286 - dest[0] = otdata_r[output[0]];
287 - dest[1] = otdata_g[output[1]];
288 - dest[2] = otdata_b[output[2]];
289 + dest[r_out] = otdata_r[output[0]];
290 + dest[1] = otdata_g[output[1]];
291 + dest[b_out] = otdata_b[output[2]];
295 @@ -151,7 +154,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
296 void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
301 + qcms_format_type output_format)
304 float (*mat)[4] = transform->matrix;
305 @@ -187,6 +191,8 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
307 /* working variables */
308 __m128 vec_r, vec_g, vec_b, result;
309 + const int r_out = output_format.r;
310 + const int b_out = output_format.b;
314 @@ -239,9 +245,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
317 /* use calc'd indices to output RGB values */
318 - dest[0] = otdata_r[output[0]];
319 - dest[1] = otdata_g[output[1]];
320 - dest[2] = otdata_b[output[2]];
321 + dest[r_out] = otdata_r[output[0]];
322 + dest[1] = otdata_g[output[1]];
323 + dest[b_out] = otdata_b[output[2]];
327 @@ -266,9 +272,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
328 result = _mm_movehl_ps(result, result);
329 *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
331 - dest[0] = otdata_r[output[0]];
332 - dest[1] = otdata_g[output[1]];
333 - dest[2] = otdata_b[output[2]];
334 + dest[r_out] = otdata_r[output[0]];
335 + dest[1] = otdata_g[output[1]];
336 + dest[b_out] = otdata_b[output[2]];
340 diff --git a/third_party/qcms/src/transform-sse2.c b/third_party/qcms/src/transform-sse2.c
341 index 6a5faf9..fa7f2d1 100644
342 --- a/third_party/qcms/src/transform-sse2.c
343 +++ b/third_party/qcms/src/transform-sse2.c
344 @@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
345 void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
350 + qcms_format_type output_format)
353 float (*mat)[4] = transform->matrix;
354 @@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
356 /* working variables */
357 __m128 vec_r, vec_g, vec_b, result;
358 + const int r_out = output_format.r;
359 + const int b_out = output_format.b;
363 @@ -114,9 +117,9 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
366 /* use calc'd indices to output RGB values */
367 - dest[0] = otdata_r[output[0]];
368 - dest[1] = otdata_g[output[1]];
369 - dest[2] = otdata_b[output[2]];
370 + dest[r_out] = otdata_r[output[0]];
371 + dest[1] = otdata_g[output[1]];
372 + dest[b_out] = otdata_b[output[2]];
376 @@ -137,15 +140,16 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
378 _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
380 - dest[0] = otdata_r[output[0]];
381 - dest[1] = otdata_g[output[1]];
382 - dest[2] = otdata_b[output[2]];
383 + dest[r_out] = otdata_r[output[0]];
384 + dest[1] = otdata_g[output[1]];
385 + dest[b_out] = otdata_b[output[2]];
388 void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
393 + qcms_format_type output_format)
396 float (*mat)[4] = transform->matrix;
397 @@ -181,6 +185,8 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
399 /* working variables */
400 __m128 vec_r, vec_g, vec_b, result;
401 + const int r_out = output_format.r;
402 + const int b_out = output_format.b;
406 @@ -231,9 +237,9 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
409 /* use calc'd indices to output RGB values */
410 - dest[0] = otdata_r[output[0]];
411 - dest[1] = otdata_g[output[1]];
412 - dest[2] = otdata_b[output[2]];
413 + dest[r_out] = otdata_r[output[0]];
414 + dest[1] = otdata_g[output[1]];
415 + dest[b_out] = otdata_b[output[2]];
419 @@ -256,7 +262,7 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
421 _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
423 - dest[0] = otdata_r[output[0]];
424 - dest[1] = otdata_g[output[1]];
425 - dest[2] = otdata_b[output[2]];
426 + dest[r_out] = otdata_r[output[0]];
427 + dest[1] = otdata_g[output[1]];
428 + dest[b_out] = otdata_b[output[2]];
430 diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c
431 index 9a6562b..7e0ba2c 100644
432 --- a/third_party/qcms/src/transform.c
433 +++ b/third_party/qcms/src/transform.c
434 @@ -181,11 +181,20 @@ compute_chromatic_adaption(struct CIE_XYZ source_white_point,
436 adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination)
438 +#if defined (_MSC_VER)
439 +#pragma warning(push)
440 +/* Disable double to float truncation warning 4305 */
441 +#pragma warning(disable:4305)
443 struct matrix lam_rigg = {{ // Bradford matrix
444 { 0.8951, 0.2664, -0.1614 },
445 { -0.7502, 1.7135, 0.0367 },
446 { 0.0389, -0.0685, 1.0296 }
448 +#if defined (_MSC_VER)
449 +/* Restore warnings */
450 +#pragma warning(pop)
452 return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg);
455 @@ -230,8 +239,11 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
459 -static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
460 +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)
462 + const int r_out = output_format.r;
463 + const int b_out = output_format.b;
466 float (*mat)[4] = transform->matrix;
467 for (i=0; i<length; i++) {
468 @@ -251,15 +263,19 @@ static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned
469 float out_device_g = pow(out_linear_g, transform->out_gamma_g);
470 float out_device_b = pow(out_linear_b, transform->out_gamma_b);
472 - *dest++ = clamp_u8(255*out_device_r);
473 - *dest++ = clamp_u8(255*out_device_g);
474 - *dest++ = clamp_u8(255*out_device_b);
475 + dest[r_out] = clamp_u8(out_device_r*255);
476 + dest[1] = clamp_u8(out_device_g*255);
477 + dest[b_out] = clamp_u8(out_device_b*255);
483 -static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
484 +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)
486 + const int r_out = output_format.r;
487 + const int b_out = output_format.b;
490 for (i = 0; i < length; i++) {
491 float out_device_r, out_device_g, out_device_b;
492 @@ -267,13 +283,14 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
494 float linear = transform->input_gamma_table_gray[device];
496 - out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
497 + out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
498 out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
499 out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
501 - *dest++ = clamp_u8(out_device_r*255);
502 - *dest++ = clamp_u8(out_device_g*255);
503 - *dest++ = clamp_u8(out_device_b*255);
504 + dest[r_out] = clamp_u8(out_device_r*255);
505 + dest[1] = clamp_u8(out_device_g*255);
506 + dest[b_out] = clamp_u8(out_device_b*255);
511 @@ -283,8 +300,11 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
512 See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
515 -static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
516 +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)
518 + const int r_out = output_format.r;
519 + const int b_out = output_format.b;
522 for (i = 0; i < length; i++) {
523 float out_device_r, out_device_g, out_device_b;
524 @@ -293,20 +313,24 @@ static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigne
526 float linear = transform->input_gamma_table_gray[device];
528 - out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
529 + out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
530 out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
531 out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
533 - *dest++ = clamp_u8(out_device_r*255);
534 - *dest++ = clamp_u8(out_device_g*255);
535 - *dest++ = clamp_u8(out_device_b*255);
537 + dest[r_out] = clamp_u8(out_device_r*255);
538 + dest[1] = clamp_u8(out_device_g*255);
539 + dest[b_out] = clamp_u8(out_device_b*255);
546 -static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
547 +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)
549 + const int r_out = output_format.r;
550 + const int b_out = output_format.b;
553 for (i = 0; i < length; i++) {
554 unsigned char device = *src++;
555 @@ -317,14 +341,19 @@ static void qcms_transform_data_gray_out_precache(qcms_transform *transform, uns
556 /* we could round here... */
557 gray = linear * PRECACHE_OUTPUT_MAX;
559 - *dest++ = transform->output_table_r->data[gray];
560 - *dest++ = transform->output_table_g->data[gray];
561 - *dest++ = transform->output_table_b->data[gray];
562 + dest[r_out] = transform->output_table_r->data[gray];
563 + dest[1] = transform->output_table_g->data[gray];
564 + dest[b_out] = transform->output_table_b->data[gray];
569 -static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
571 +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)
573 + const int r_out = output_format.r;
574 + const int b_out = output_format.b;
577 for (i = 0; i < length; i++) {
578 unsigned char device = *src++;
579 @@ -336,15 +365,19 @@ static void qcms_transform_data_graya_out_precache(qcms_transform *transform, un
580 /* we could round here... */
581 gray = linear * PRECACHE_OUTPUT_MAX;
583 - *dest++ = transform->output_table_r->data[gray];
584 - *dest++ = transform->output_table_g->data[gray];
585 - *dest++ = transform->output_table_b->data[gray];
587 + dest[r_out] = transform->output_table_r->data[gray];
588 + dest[1] = transform->output_table_g->data[gray];
589 + dest[b_out] = transform->output_table_b->data[gray];
595 -static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
596 +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)
598 + const int r_out = output_format.r;
599 + const int b_out = output_format.b;
602 float (*mat)[4] = transform->matrix;
603 for (i = 0; i < length; i++) {
604 @@ -370,14 +403,18 @@ static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform,
605 g = out_linear_g * PRECACHE_OUTPUT_MAX;
606 b = out_linear_b * PRECACHE_OUTPUT_MAX;
608 - *dest++ = transform->output_table_r->data[r];
609 - *dest++ = transform->output_table_g->data[g];
610 - *dest++ = transform->output_table_b->data[b];
611 + dest[r_out] = transform->output_table_r->data[r];
612 + dest[1] = transform->output_table_g->data[g];
613 + dest[b_out] = transform->output_table_b->data[b];
618 -static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
619 +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)
621 + const int r_out = output_format.r;
622 + const int b_out = output_format.b;
625 float (*mat)[4] = transform->matrix;
626 for (i = 0; i < length; i++) {
627 @@ -404,16 +441,21 @@ static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform,
628 g = out_linear_g * PRECACHE_OUTPUT_MAX;
629 b = out_linear_b * PRECACHE_OUTPUT_MAX;
631 - *dest++ = transform->output_table_r->data[r];
632 - *dest++ = transform->output_table_g->data[g];
633 - *dest++ = transform->output_table_b->data[b];
635 + dest[r_out] = transform->output_table_r->data[r];
636 + dest[1] = transform->output_table_g->data[g];
637 + dest[b_out] = transform->output_table_b->data[b];
645 -static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
646 +static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
648 + const int r_out = output_format.r;
649 + const int b_out = output_format.b;
653 int x_len = transform->grid_size;
654 @@ -462,15 +504,20 @@ static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *s
655 float b_y2 = lerp(b_x3, b_x4, y_d);
656 float clut_b = lerp(b_y1, b_y2, z_d);
658 - *dest++ = clamp_u8(clut_r*255.0f);
659 - *dest++ = clamp_u8(clut_g*255.0f);
660 - *dest++ = clamp_u8(clut_b*255.0f);
662 + dest[r_out] = clamp_u8(clut_r*255.0f);
663 + dest[1] = clamp_u8(clut_g*255.0f);
664 + dest[b_out] = clamp_u8(clut_b*255.0f);
670 // Using lcms' tetra interpolation algorithm.
671 -static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
672 +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)
674 + const int r_out = output_format.r;
675 + const int b_out = output_format.b;
679 int x_len = transform->grid_size;
680 @@ -577,15 +624,20 @@ static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsig
681 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
682 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
684 - *dest++ = clamp_u8(clut_r*255.0f);
685 - *dest++ = clamp_u8(clut_g*255.0f);
686 - *dest++ = clamp_u8(clut_b*255.0f);
689 + dest[r_out] = clamp_u8(clut_r*255.0f);
690 + dest[1] = clamp_u8(clut_g*255.0f);
691 + dest[b_out] = clamp_u8(clut_b*255.0f);
697 // Using lcms' tetra interpolation code.
698 -static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
699 +static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
701 + const int r_out = output_format.r;
702 + const int b_out = output_format.b;
706 int x_len = transform->grid_size;
707 @@ -691,14 +743,18 @@ static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned c
708 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
709 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
711 - *dest++ = clamp_u8(clut_r*255.0f);
712 - *dest++ = clamp_u8(clut_g*255.0f);
713 - *dest++ = clamp_u8(clut_b*255.0f);
715 + dest[r_out] = clamp_u8(clut_r*255.0f);
716 + dest[1] = clamp_u8(clut_g*255.0f);
717 + dest[b_out] = clamp_u8(clut_b*255.0f);
722 -static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
723 +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)
725 + const int r_out = output_format.r;
726 + const int b_out = output_format.b;
729 float (*mat)[4] = transform->matrix;
730 for (i = 0; i < length; i++) {
731 @@ -726,14 +782,18 @@ static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned
732 out_device_b = lut_interp_linear(out_linear_b,
733 transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
735 - *dest++ = clamp_u8(out_device_r*255);
736 - *dest++ = clamp_u8(out_device_g*255);
737 - *dest++ = clamp_u8(out_device_b*255);
738 + dest[r_out] = clamp_u8(out_device_r*255);
739 + dest[1] = clamp_u8(out_device_g*255);
740 + dest[b_out] = clamp_u8(out_device_b*255);
745 -static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
746 +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)
748 + const int r_out = output_format.r;
749 + const int b_out = output_format.b;
752 float (*mat)[4] = transform->matrix;
753 for (i = 0; i < length; i++) {
754 @@ -762,16 +822,20 @@ static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned
755 out_device_b = lut_interp_linear(out_linear_b,
756 transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
758 - *dest++ = clamp_u8(out_device_r*255);
759 - *dest++ = clamp_u8(out_device_g*255);
760 - *dest++ = clamp_u8(out_device_b*255);
762 + dest[r_out] = clamp_u8(out_device_r*255);
763 + dest[1] = clamp_u8(out_device_g*255);
764 + dest[b_out] = clamp_u8(out_device_b*255);
771 -static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
772 +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)
774 + const int r_out = output_format.r;
775 + const int b_out = output_format.b;
778 float (*mat)[4] = transform->matrix;
779 for (i = 0; i < length; i++) {
780 @@ -787,16 +851,25 @@ static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsign
781 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
782 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
784 - *dest++ = clamp_u8(out_linear_r*255);
785 - *dest++ = clamp_u8(out_linear_g*255);
786 - *dest++ = clamp_u8(out_linear_b*255);
787 + dest[r_out] = clamp_u8(out_linear_r*255);
788 + dest[1] = clamp_u8(out_linear_g*255);
789 + dest[b_out] = clamp_u8(out_linear_b*255);
796 + * If users create and destroy objects on different threads, even if the same
797 + * objects aren't used on different threads at the same time, we can still run
798 + * in to trouble with refcounts if they aren't atomic.
800 + * This can lead to us prematurely deleting the precache if threads get unlucky
801 + * and write the wrong value to the ref count.
803 static struct precache_output *precache_reference(struct precache_output *p)
806 + qcms_atomic_increment(p->ref_count);
810 @@ -810,12 +883,12 @@ static struct precache_output *precache_create()
812 void precache_release(struct precache_output *p)
814 - if (--p->ref_count == 0) {
815 + if (qcms_atomic_decrement(p->ref_count) == 0) {
820 -#ifdef HAS_POSIX_MEMALIGN
821 +#ifdef HAVE_POSIX_MEMALIGN
822 static qcms_transform *transform_alloc(void)
825 @@ -994,13 +1067,15 @@ void qcms_profile_precache_output_transform(qcms_profile *profile)
826 if (profile->color_space != RGB_SIGNATURE)
829 - /* don't precache since we will use the B2A LUT */
832 + if (qcms_supports_iccv4) {
833 + /* don't precache since we will use the B2A LUT */
837 - /* don't precache since we will use the mBA LUT */
840 + /* don't precache since we will use the mBA LUT */
845 /* don't precache if we do not have the TRC curves */
846 if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC)
847 @@ -1157,14 +1232,14 @@ qcms_transform* qcms_transform_create(
852 +#if defined(SSE2_ENABLE) && defined(X86)
853 if (sse_version_available() >= 2) {
854 if (in_type == QCMS_DATA_RGB_8)
855 transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2;
857 transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2;
859 -#if !(defined(_MSC_VER) && defined(_M_AMD64))
860 +#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64))
861 /* Microsoft Compiler for x64 doesn't support MMX.
862 * SSE code uses MMX so that we disable on x64 */
864 @@ -1256,13 +1331,34 @@ qcms_transform* qcms_transform_create(
868 -#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
869 +/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on unused
870 + * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the presence
871 + * of the attribute but is currently only supported by clang */
872 +#if defined(__has_attribute)
873 +#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__)
874 +#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defined(__arm__) && !defined(__mips__)
875 +#define HAS_FORCE_ALIGN_ARG_POINTER 1
877 +#define HAS_FORCE_ALIGN_ARG_POINTER 0
880 +#if HAS_FORCE_ALIGN_ARG_POINTER
881 /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
882 __attribute__((__force_align_arg_pointer__))
884 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length)
886 - transform->transform_fn(transform, src, dest, length);
887 + static const struct _qcms_format_type output_rgbx = { 0, 2 };
889 + transform->transform_fn(transform, src, dest, length, output_rgbx);
892 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type)
894 + static const struct _qcms_format_type output_rgbx = { 0, 2 };
895 + static const struct _qcms_format_type output_bgrx = { 2, 0 };
897 + transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPUT_BGRX ? output_bgrx : output_rgbx);
900 qcms_bool qcms_supports_iccv4;
901 diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c
902 index e8447e5..f4338b2 100644
903 --- a/third_party/qcms/src/transform_util.c
904 +++ b/third_party/qcms/src/transform_util.c
907 /* value must be a value between 0 and 1 */
908 //XXX: is the above a good restriction to have?
909 -float lut_interp_linear(double value, uint16_t *table, int length)
910 +float lut_interp_linear(double value, uint16_t *table, size_t length)
913 value = value * (length - 1); // scale to length of the array
914 @@ -49,11 +49,11 @@ float lut_interp_linear(double value, uint16_t *table, int length)
917 /* same as above but takes and returns a uint16_t value representing a range from 0..1 */
918 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
919 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length)
921 /* Start scaling input_value to the length of the array: 65535*(length-1).
922 * We'll divide out the 65535 next */
923 - uint32_t value = (input_value * (length - 1));
924 + uintptr_t value = (input_value * (length - 1));
925 uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65535) */
926 uint32_t lower = value / 65535; /* equivalent to floor(value/65535) */
927 /* interp is the distance from upper to value scaled to 0..65535 */
928 @@ -67,11 +67,11 @@ uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
929 /* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX
930 * and returns a uint8_t value representing a range from 0..1 */
932 -uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, int length)
933 +uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, size_t length)
935 /* Start scaling input_value to the length of the array: PRECACHE_OUTPUT_MAX*(length-1).
936 * We'll divide out the PRECACHE_OUTPUT_MAX next */
937 - uint32_t value = (input_value * (length - 1));
938 + uintptr_t value = (input_value * (length - 1));
940 /* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */
941 uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX;
942 @@ -91,7 +91,7 @@ uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table,
944 /* value must be a value between 0 and 1 */
945 //XXX: is the above a good restriction to have?
946 -float lut_interp_linear_float(float value, float *table, int length)
947 +float lut_interp_linear_float(float value, float *table, size_t length)
950 value = value * (length - 1);
951 @@ -235,6 +235,21 @@ float u8Fixed8Number_to_float(uint16_t x)
955 +/* The SSE2 code uses min & max which let NaNs pass through.
956 + We want to try to prevent that here by ensuring that
957 + gamma table is within expected values. */
958 +void validate_gamma_table(float gamma_table[256])
961 + for (i = 0; i < 256; i++) {
962 + // Note: we check that the gamma is not in range
963 + // instead of out of range so that we catch NaNs
964 + if (!(gamma_table[i] >= 0.f && gamma_table[i] <= 1.f)) {
965 + gamma_table[i] = 0.f;
970 float *build_input_gamma_table(struct curveType *TRC)
973 @@ -254,7 +269,10 @@ float *build_input_gamma_table(struct curveType *TRC)
977 - return gamma_table;
979 + validate_gamma_table(gamma_table);
981 + return gamma_table;
984 struct matrix build_colorant_matrix(qcms_profile *p)
985 @@ -390,7 +408,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
986 which has an maximum error of about 9855 (pixel difference of ~38.346)
988 For now, we punt the decision of output size to the caller. */
989 -static uint16_t *invert_lut(uint16_t *table, int length, int out_length)
990 +static uint16_t *invert_lut(uint16_t *table, int length, size_t out_length)
993 /* for now we invert the lut by creating a lut of size out_length
994 diff --git a/third_party/qcms/src/transform_util.h b/third_party/qcms/src/transform_util.h
995 index 8f358a8..de465f4 100644
996 --- a/third_party/qcms/src/transform_util.h
997 +++ b/third_party/qcms/src/transform_util.h
999 //XXX: could use a bettername
1000 typedef uint16_t uint16_fract_t;
1002 -float lut_interp_linear(double value, uint16_t *table, int length);
1003 -float lut_interp_linear_float(float value, float *table, int length);
1004 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length);
1005 +float lut_interp_linear(double value, uint16_t *table, size_t length);
1006 +float lut_interp_linear_float(float value, float *table, size_t length);
1007 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length);
1010 static inline float lerp(float a, float b, float t)