summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authorrobert.bradford <robert.bradford@intel.com>2015-05-12 10:27:12 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-12 17:27:26 +0000
commite0469a68bcc7a037f52642dae821ad05d9cf67d2 (patch)
tree26516e2f14a21b75707dedb5eddb5d80553a9ff0 /third_party
parent7109355da4f837784b1db260385280c928b2dcbb (diff)
downloadchromium_src-e0469a68bcc7a037f52642dae821ad05d9cf67d2.zip
chromium_src-e0469a68bcc7a037f52642dae821ad05d9cf67d2.tar.gz
chromium_src-e0469a68bcc7a037f52642dae821ad05d9cf67d2.tar.bz2
qcms: Drop the google.patch file
Rather than having a file that must be kept current with all changes to third_party/qcms/src highlight in the README.Chromium how the changes since the import can be readily seen. R=noel@chromium.org BUG=None TEST=None Review URL: https://codereview.chromium.org/1136283002 Cr-Commit-Position: refs/heads/master@{#329431}
Diffstat (limited to 'third_party')
-rw-r--r--third_party/qcms/README.chromium8
-rw-r--r--third_party/qcms/google.patch1699
2 files changed, 4 insertions, 1703 deletions
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium
index 0e3ec7b..3548a0f 100644
--- a/third_party/qcms/README.chromium
+++ b/third_party/qcms/README.chromium
@@ -16,8 +16,7 @@ Local Modifications:
Some files only have license headers in the master branch.
- Added the same license headers to the versions brought down from the 'v4'
branch src URL qcms/tree/v4
-google.patch contains the following modifications. Apply with
- patch -p1 < google.patch.
+The following changes have been made since qcms was imported:
- Add bgra output support.
- Use HAVE_POSIX_MEMALIGN instead of HAS_POSIX_MEMALIG
(https://bugzilla.mozilla.org/show_bug.cgi?id=692922)
@@ -67,5 +66,6 @@ google.patch contains the following modifications. Apply with
- https://code.google.com/p/chromium/issues/detail?id=471749
- Limit vcgt table to a maximum of 1024 entries
- https://code.google.com/p/chromium/issues/detail?id=471749
-To regenerate google.patch:
- git diff b8456f38 src > google.patch
+
+For the Chromium changes, since the import, in a patch format run:
+ git diff b8456f38 src
diff --git a/third_party/qcms/google.patch b/third_party/qcms/google.patch
deleted file mode 100644
index 0b0b8b9..0000000
--- a/third_party/qcms/google.patch
+++ /dev/null
@@ -1,1699 +0,0 @@
-diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c
-index 36b7011..0deab10 100644
---- a/third_party/qcms/src/iccread.c
-+++ b/third_party/qcms/src/iccread.c
-@@ -266,7 +266,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
- if (profile->color_space != RGB_SIGNATURE)
- return false;
-
-- if (profile->A2B0 || profile->B2A0)
-+ if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0))
- return false;
-
- rX = s15Fixed16Number_to_float(profile->redColorant.X);
-@@ -297,6 +297,11 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
- sum[1] = rY + gY + bY;
- sum[2] = rZ + gZ + bZ;
-
-+#if defined (_MSC_VER)
-+#pragma warning(push)
-+/* Disable double to float truncation warning 4305 */
-+#pragma warning(disable:4305)
-+#endif
- // Build our target vector (see mozilla bug 460629)
- target[0] = 0.96420;
- target[1] = 1.00000;
-@@ -310,6 +315,10 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
- tolerance[1] = 0.02;
- tolerance[2] = 0.04;
-
-+#if defined (_MSC_VER)
-+/* Restore warnings */
-+#pragma warning(pop)
-+#endif
- // Compare with our tolerance
- for (i = 0; i < 3; ++i) {
- if (!(((sum[i] - tolerance[i]) <= target[i]) &&
-@@ -331,6 +340,8 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
- #define TAG_A2B0 0x41324230
- #define TAG_B2A0 0x42324130
- #define TAG_CHAD 0x63686164
-+#define TAG_desc 0x64657363
-+#define TAG_vcgt 0x76636774
-
- static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
- {
-@@ -344,6 +355,215 @@ static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
- return tag;
- }
-
-+#define DESC_TYPE 0x64657363 // 'desc'
-+#define MLUC_TYPE 0x6d6c7563 // 'mluc'
-+#define MMOD_TYPE 0x6D6D6F64 // 'mmod'
-+#define VCGT_TYPE 0x76636774 // 'vcgt'
-+
-+// Check unsigned short is uint16_t.
-+typedef char assert_short_not_16b[(sizeof(unsigned short) == sizeof(uint16_t)) ? 1 : -1];
-+
-+qcms_bool read_tag_vcgtType(qcms_profile *profile, struct mem_source *src, struct tag_index index) {
-+ size_t tag_offset = find_tag(index, TAG_vcgt)->offset;
-+ uint32_t tag_type = read_u32(src, tag_offset);
-+ uint32_t vcgt_type = read_u32(src, tag_offset + 8);
-+ uint16_t channels = read_u16(src, tag_offset + 12);
-+ uint16_t elements = read_u16(src, tag_offset + 14);
-+ uint16_t byte_depth = read_u16(src, tag_offset + 16);
-+ size_t table_offset = tag_offset + 18;
-+ uint32_t i;
-+ uint16_t *dest;
-+
-+ if (!src->valid || tag_type != VCGT_TYPE)
-+ goto invalid_vcgt_tag;
-+
-+ // Only support 3 channels.
-+ if (channels != 3)
-+ return true;
-+ // Only support single or double byte values.
-+ if (byte_depth != 1 && byte_depth != 2)
-+ return true;
-+ // Only support table data, not equation.
-+ if (vcgt_type != 0)
-+ return true;
-+ // Limit the table to a sensible size; 10-bit gamma is a reasonable
-+ // maximum for hardware correction.
-+ if (elements > 1024)
-+ return true;
-+
-+ // Empty table is invalid.
-+ if (!elements)
-+ goto invalid_vcgt_tag;
-+
-+ profile->vcgt.length = elements;
-+ profile->vcgt.data = malloc(3 * elements * sizeof(uint16_t));
-+ if (!profile->vcgt.data)
-+ return false;
-+
-+ dest = profile->vcgt.data;
-+
-+ for (i = 0; i < 3 * elements; ++i) {
-+ if (byte_depth == 1) {
-+ *dest++ = read_u8(src, table_offset) * 256;
-+ } else {
-+ *dest++ = read_u16(src, table_offset);
-+ }
-+
-+ table_offset += byte_depth;
-+
-+ if (!src->valid)
-+ goto invalid_vcgt_tag;
-+ }
-+
-+ return true;
-+
-+invalid_vcgt_tag:
-+ invalid_source(src, "invalid vcgt tag");
-+ return false;
-+}
-+
-+static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
-+{
-+ struct tag *tag = find_tag(index, tag_id);
-+ if (tag) {
-+ const uint32_t limit = sizeof profile->description;
-+ uint32_t offset = tag->offset;
-+ uint32_t type = read_u32(src, offset);
-+ uint32_t length = read_u32(src, offset+8);
-+ uint32_t i, description_offset;
-+ bool mluc = false;
-+ if (length && type == MLUC_TYPE) {
-+ length = read_u32(src, offset+20);
-+ if (!length || (length & 1) || (read_u32(src, offset+12) != 12))
-+ goto invalid_desc_tag;
-+ description_offset = offset + read_u32(src, offset+24);
-+ if (!src->valid)
-+ goto invalid_desc_tag;
-+ mluc = true;
-+ } else if (length && type == DESC_TYPE) {
-+ description_offset = offset + 12;
-+ } else {
-+ goto invalid_desc_tag;
-+ }
-+ if (length >= limit)
-+ length = limit - 1;
-+ for (i = 0; i < length; ++i) {
-+ uint8_t value = read_u8(src, description_offset + i);
-+ if (!src->valid)
-+ goto invalid_desc_tag;
-+ if (mluc && !value)
-+ value = '.';
-+ profile->description[i] = value;
-+ }
-+ profile->description[length] = 0;
-+ } else {
-+ goto invalid_desc_tag;
-+ }
-+
-+ if (src->valid)
-+ return true;
-+
-+invalid_desc_tag:
-+ invalid_source(src, "invalid description");
-+ return false;
-+}
-+
-+#if defined(__APPLE__)
-+
-+// Use the dscm tag to change profile description "Display" to its more specific en-localized monitor name, if any.
-+
-+#define TAG_dscm 0x6473636D // 'dscm'
-+
-+static bool read_tag_dscmType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
-+{
-+ if (strcmp(profile->description, "Display") != 0)
-+ return true;
-+
-+ struct tag *tag = find_tag(index, tag_id);
-+ if (tag) {
-+ uint32_t offset = tag->offset;
-+ uint32_t type = read_u32(src, offset);
-+ uint32_t records = read_u32(src, offset+8);
-+
-+ if (!src->valid || !records || type != MLUC_TYPE)
-+ goto invalid_dscm_tag;
-+ if (read_u32(src, offset+12) != 12) // MLUC record size: bytes
-+ goto invalid_dscm_tag;
-+
-+ for (uint32_t i = 0; i < records; ++i) {
-+ const uint32_t limit = sizeof profile->description;
-+ const uint16_t isoen = 0x656E; // ISO-3166-1 language 'en'
-+
-+ uint16_t language = read_u16(src, offset + 16 + (i * 12) + 0);
-+ uint32_t length = read_u32(src, offset + 16 + (i * 12) + 4);
-+ uint32_t description_offset = read_u32(src, offset + 16 + (i * 12) + 8);
-+
-+ if (!src->valid || !length || (length & 1))
-+ goto invalid_dscm_tag;
-+ if (language != isoen)
-+ continue;
-+
-+ // Use a prefix to identify the display description source
-+ strcpy(profile->description, "dscm:");
-+ length += 5;
-+
-+ if (length >= limit)
-+ length = limit - 1;
-+ for (uint32_t j = 5; j < length; ++j) {
-+ uint8_t value = read_u8(src, offset + description_offset + j - 5);
-+ if (!src->valid)
-+ goto invalid_dscm_tag;
-+ profile->description[j] = value ? value : '.';
-+ }
-+ profile->description[length] = 0;
-+ break;
-+ }
-+ }
-+
-+ if (src->valid)
-+ return true;
-+
-+invalid_dscm_tag:
-+ invalid_source(src, "invalid dscm tag");
-+ return false;
-+}
-+
-+// Use the mmod tag to change profile description "Display" to its specific mmod maker model data, if any.
-+
-+#define TAG_mmod 0x6D6D6F64 // 'mmod'
-+
-+static bool read_tag_mmodType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
-+{
-+ if (strcmp(profile->description, "Display") != 0)
-+ return true;
-+
-+ struct tag *tag = find_tag(index, tag_id);
-+ if (tag) {
-+ const uint8_t length = 4 * 4; // Four 4-byte fields: 'mmod', 0, maker, model.
-+
-+ uint32_t offset = tag->offset;
-+ if (tag->size < 40 || read_u32(src, offset) != MMOD_TYPE)
-+ goto invalid_mmod_tag;
-+
-+ for (uint8_t i = 0; i < length; ++i) {
-+ uint8_t value = read_u8(src, offset + i);
-+ if (!src->valid)
-+ goto invalid_mmod_tag;
-+ profile->description[i] = value ? value : '.';
-+ }
-+ profile->description[length] = 0;
-+ }
-+
-+ if (src->valid)
-+ return true;
-+
-+invalid_mmod_tag:
-+ invalid_source(src, "invalid mmod tag");
-+ return false;
-+}
-+
-+#endif // __APPLE__
-+
- #define XYZ_TYPE 0x58595a20 // 'XYZ '
- #define CURVE_TYPE 0x63757276 // 'curv'
- #define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para'
-@@ -402,7 +622,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_inde
- // present that are not part of the tag_index.
- static struct curveType *read_curveType(struct mem_source *src, uint32_t offset, uint32_t *len)
- {
-- static const size_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
-+ static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7};
- struct curveType *curve = NULL;
- uint32_t type = read_u32(src, offset);
- uint32_t count;
-@@ -484,19 +704,23 @@ static void read_nested_curveType(struct mem_source *src, struct curveType *(*cu
- uint32_t channel_offset = 0;
- int i;
- for (i = 0; i < num_channels; i++) {
-- uint32_t tag_len;
-+ uint32_t tag_len = ~0;
-
- (*curveArray)[i] = read_curveType(src, curve_offset + channel_offset, &tag_len);
- if (!(*curveArray)[i]) {
- invalid_source(src, "invalid nested curveType curve");
- }
-
-+ if (tag_len == ~0) {
-+ invalid_source(src, "invalid nested curveType tag length");
-+ return;
-+ }
-+
- channel_offset += tag_len;
- // 4 byte aligned
- if ((tag_len % 4) != 0)
- channel_offset += 4 - (tag_len % 4);
- }
--
- }
-
- static void mAB_release(struct lutmABType *lut)
-@@ -540,7 +764,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag
- // We require 3in/out channels since we only support RGB->XYZ (or RGB->LAB)
- // XXX: If we remove this restriction make sure that the number of channels
- // is less or equal to the maximum number of mAB curves in qcmsint.h
-- // also check for clut_size overflow.
-+ // also check for clut_size overflow. Also make sure it's != 0
- if (num_in_channels != 3 || num_out_channels != 3)
- return NULL;
-
-@@ -570,6 +794,9 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag
- // clut_size can not overflow since lg(256^num_in_channels) = 24 bits.
- for (i = 0; i < num_in_channels; i++) {
- clut_size *= read_u8(src, clut_offset + i);
-+ if (clut_size == 0) {
-+ invalid_source(src, "bad clut_size");
-+ }
- }
- } else {
- clut_size = 0;
-@@ -590,6 +817,9 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag
-
- for (i = 0; i < num_in_channels; i++) {
- lut->num_grid_points[i] = read_u8(src, clut_offset + i);
-+ if (lut->num_grid_points[i] == 0) {
-+ invalid_source(src, "bad grid_points");
-+ }
- }
-
- // Reverse the processing of transformation elements for mBA type.
-@@ -657,7 +887,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
- uint16_t num_input_table_entries;
- uint16_t num_output_table_entries;
- uint8_t in_chan, grid_points, out_chan;
-- uint32_t clut_offset, output_offset;
-+ size_t clut_offset, output_offset;
- uint32_t clut_size;
- size_t entry_size;
- struct lutType *lut;
-@@ -672,6 +902,10 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
- } else if (type == LUT16_TYPE) {
- num_input_table_entries = read_u16(src, offset + 48);
- num_output_table_entries = read_u16(src, offset + 50);
-+ if (num_input_table_entries == 0 || num_output_table_entries == 0) {
-+ invalid_source(src, "Bad channel count");
-+ return NULL;
-+ }
- entry_size = 2;
- } else {
- assert(0); // the caller checks that this doesn't happen
-@@ -685,15 +919,18 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
-
- clut_size = pow(grid_points, in_chan);
- if (clut_size > MAX_CLUT_SIZE) {
-+ invalid_source(src, "CLUT too large");
- return NULL;
- }
-
- if (in_chan != 3 || out_chan != 3) {
-+ invalid_source(src, "CLUT only supports RGB");
- return NULL;
- }
-
- lut = malloc(sizeof(struct lutType) + (num_input_table_entries * in_chan + clut_size*out_chan + num_output_table_entries * out_chan)*sizeof(float));
- if (!lut) {
-+ invalid_source(src, "CLUT too large");
- return NULL;
- }
-
-@@ -704,9 +941,9 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
-
- lut->num_input_table_entries = num_input_table_entries;
- lut->num_output_table_entries = num_output_table_entries;
-- lut->num_input_channels = read_u8(src, offset + 8);
-- lut->num_output_channels = read_u8(src, offset + 9);
-- lut->num_clut_grid_points = read_u8(src, offset + 10);
-+ lut->num_input_channels = in_chan;
-+ lut->num_output_channels = out_chan;
-+ lut->num_clut_grid_points = grid_points;
- lut->e00 = read_s15Fixed16Number(src, offset+12);
- lut->e01 = read_s15Fixed16Number(src, offset+16);
- lut->e02 = read_s15Fixed16Number(src, offset+20);
-@@ -979,11 +1216,13 @@ qcms_profile* qcms_profile_sRGB(void)
- return NO_MEM_PROFILE;
-
- profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024);
-+ if (profile)
-+ strcpy(profile->description, "sRGB IEC61966-2.1");
-+
- free(table);
- return profile;
- }
-
--
- /* qcms_profile_from_memory does not hold a reference to the memory passed in */
- qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
- {
-@@ -997,6 +1236,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
- source.size = size;
- source.valid = true;
-
-+ if (size < 4)
-+ return INVALID_PROFILE;
-+
- length = read_u32(src, 0);
- if (length <= size) {
- // shrink the area that we can read if appropriate
-@@ -1028,12 +1270,26 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
- if (!src->valid || !index.tags)
- goto invalid_tag_table;
-
-+ if (!read_tag_descType(profile, src, index, TAG_desc))
-+ goto invalid_tag_table;
-+#if defined(__APPLE__)
-+ if (!read_tag_dscmType(profile, src, index, TAG_dscm))
-+ goto invalid_tag_table;
-+ if (!read_tag_mmodType(profile, src, index, TAG_mmod))
-+ goto invalid_tag_table;
-+#endif // __APPLE__
-+
- if (find_tag(index, TAG_CHAD)) {
- profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD);
- } else {
- profile->chromaticAdaption.invalid = true; //Signal the data is not present
- }
-
-+ if (find_tag(index, TAG_vcgt)) {
-+ if (!read_tag_vcgtType(profile, src, index))
-+ goto invalid_tag_table;
-+ }
-+
- if (profile->class == DISPLAY_DEVICE_PROFILE || profile->class == INPUT_DEVICE_PROFILE ||
- profile->class == OUTPUT_DEVICE_PROFILE || profile->class == COLOR_SPACE_PROFILE) {
- if (profile->color_space == RGB_SIGNATURE) {
-@@ -1098,6 +1354,16 @@ invalid_profile:
- return INVALID_PROFILE;
- }
-
-+qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2)
-+{
-+ return memcmp(p1->description, p2->description, sizeof p1->description) == 0;
-+}
-+
-+const char* qcms_profile_get_description(qcms_profile *profile)
-+{
-+ return profile->description;
-+}
-+
- qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile)
- {
- return profile->rendering_intent;
-@@ -1114,6 +1380,18 @@ static void lut_release(struct lutType *lut)
- free(lut);
- }
-
-+size_t qcms_profile_get_vcgt_channel_length(qcms_profile *profile) {
-+ return profile->vcgt.length;
-+}
-+
-+qcms_bool qcms_profile_get_vcgt_rgb_channels(qcms_profile *profile, unsigned short *data) {
-+ size_t vcgt_channel_bytes = qcms_profile_get_vcgt_channel_length(profile) * sizeof(uint16_t);
-+ if (!vcgt_channel_bytes || !data)
-+ return false;
-+ memcpy(data, profile->vcgt.data, 3 * vcgt_channel_bytes);
-+ return true;
-+}
-+
- void qcms_profile_release(qcms_profile *profile)
- {
- if (profile->output_table_r)
-@@ -1133,6 +1411,9 @@ void qcms_profile_release(qcms_profile *profile)
- if (profile->mBA)
- mAB_release(profile->mBA);
-
-+ if (profile->vcgt.data)
-+ free(profile->vcgt.data);
-+
- free(profile->redTRC);
- free(profile->blueTRC);
- free(profile->greenTRC);
-diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h
-index 7d83623..be74717 100644
---- a/third_party/qcms/src/qcms.h
-+++ b/third_party/qcms/src/qcms.h
-@@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written
- authorization from SunSoft Inc.
- ******************************************************************/
-
-+/*
-+ * QCMS, in general, is not threadsafe. However, it should be safe to create
-+ * profile and transformation objects on different threads, so long as you
-+ * don't use the same objects on different threads at the same time.
-+ */
-+
- /*
- * Color Space Signatures
- * Note that only icSigXYZData and icSigLabData are valid
-@@ -102,6 +108,12 @@ typedef enum {
- QCMS_DATA_GRAYA_8
- } qcms_data_type;
-
-+/* Format of the output data for qcms_transform_data_type() */
-+typedef enum {
-+ QCMS_OUTPUT_RGBX,
-+ QCMS_OUTPUT_BGRX
-+} qcms_output_type;
-+
- /* the names for the following two types are sort of ugly */
- typedef struct
- {
-@@ -136,16 +148,27 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile);
- qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile);
- icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile);
-
-+qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2);
-+const char* qcms_profile_get_description(qcms_profile *profile);
-+
- void qcms_profile_precache_output_transform(qcms_profile *profile);
-
-+size_t qcms_profile_get_vcgt_channel_length(qcms_profile *profile);
-+qcms_bool qcms_profile_get_vcgt_rgb_channels(qcms_profile *profile, unsigned short *data);
-+
- qcms_transform* qcms_transform_create(
- qcms_profile *in, qcms_data_type in_type,
- qcms_profile* out, qcms_data_type out_type,
- qcms_intent intent);
-
--void qcms_transform_release(qcms_transform *);
-+qcms_bool qcms_transform_create_LUT_zyx_bgra(
-+ qcms_profile *in, qcms_profile* out, qcms_intent intent,
-+ int samples, unsigned char* lut);
-
- void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length);
-+void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type);
-+
-+void qcms_transform_release(qcms_transform *);
-
- void qcms_enable_iccv4();
-
-diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h
-index 53a3420..6b22c5a 100644
---- a/third_party/qcms/src/qcmsint.h
-+++ b/third_party/qcms/src/qcmsint.h
-@@ -45,6 +45,11 @@ struct precache_output
- #define ALIGN __attribute__(( aligned (16) ))
- #endif
-
-+typedef struct _qcms_format_type {
-+ int r;
-+ int b;
-+} qcms_format_type;
-+
- struct _qcms_transform {
- float ALIGN matrix[3][4];
- float *input_gamma_table_r;
-@@ -88,7 +93,7 @@ struct _qcms_transform {
- struct precache_output *output_table_g;
- struct precache_output *output_table_b;
-
-- void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length);
-+ void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, struct _qcms_format_type output_format);
- };
-
- struct matrix {
-@@ -200,6 +205,14 @@ struct lutType { // used by lut8Type/lut16Type (mft2) only
-
- float table_data[];
- };
-+
-+struct vcgtType {
-+ /* data contains three gamma channels: R[length], then G[length], then
-+ * B[length]. */
-+ uint16_t *data;
-+ size_t length;
-+};
-+
- #if 0
- /* this is from an intial idea of having the struct correspond to the data in
- * the file. I decided that it wasn't a good idea.
-@@ -225,6 +238,7 @@ struct tag_value {
- #define LAB_SIGNATURE 0x4C616220
-
- struct _qcms_profile {
-+ char description[64];
- uint32_t class;
- uint32_t color_space;
- uint32_t pcs;
-@@ -241,6 +255,7 @@ struct _qcms_profile {
- struct lutmABType *mAB;
- struct lutmABType *mBA;
- struct matrix chromaticAdaption;
-+ struct vcgtType vcgt;
-
- struct precache_output *output_table_r;
- struct precache_output *output_table_g;
-@@ -280,18 +295,40 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
- void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length);
-+ size_t length,
-+ qcms_format_type output_format);
- void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length);
-+ size_t length,
-+ qcms_format_type output_format);
- void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length);
-+ size_t length,
-+ qcms_format_type output_format);
- void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length);
-+ size_t length,
-+ qcms_format_type output_format);
-
- extern qcms_bool qcms_supports_iccv4;
-+
-+
-+#ifdef _MSC_VER
-+
-+long __cdecl _InterlockedIncrement(long volatile *);
-+long __cdecl _InterlockedDecrement(long volatile *);
-+#pragma intrinsic(_InterlockedIncrement)
-+#pragma intrinsic(_InterlockedDecrement)
-+
-+#define qcms_atomic_increment(x) _InterlockedIncrement((long volatile *)&x)
-+#define qcms_atomic_decrement(x) _InterlockedDecrement((long volatile*)&x)
-+
-+#else
-+
-+#define qcms_atomic_increment(x) __sync_add_and_fetch(&x, 1)
-+#define qcms_atomic_decrement(x) __sync_sub_and_fetch(&x, 1)
-+
-+#endif
-diff --git a/third_party/qcms/src/qcmstypes.h b/third_party/qcms/src/qcmstypes.h
-index 56d8de3..d58f691 100644
---- a/third_party/qcms/src/qcmstypes.h
-+++ b/third_party/qcms/src/qcmstypes.h
-@@ -22,37 +22,6 @@
- #ifndef QCMS_TYPES_H
- #define QCMS_TYPES_H
-
--#ifdef MOZ_QCMS
--
--#include "prtypes.h"
--
--/* prtypes.h defines IS_LITTLE_ENDIAN and IS_BIG ENDIAN */
--
--#if defined (__SVR4) && defined (__sun)
--/* int_types.h gets included somehow, so avoid redefining the types differently */
--#include <sys/int_types.h>
--#elif defined (_AIX)
--#include <sys/types.h>
--#elif !defined(ANDROID) && !defined(__OpenBSD__)
--typedef PRInt8 int8_t;
--typedef PRUint8 uint8_t;
--typedef PRInt16 int16_t;
--typedef PRUint16 uint16_t;
--typedef PRInt32 int32_t;
--typedef PRUint32 uint32_t;
--typedef PRInt64 int64_t;
--typedef PRUint64 uint64_t;
--
--#ifdef __OS2__
--/* OS/2's stdlib typdefs uintptr_t. So we'll just include that so we don't collide */
--#include <stdlib.h>
--#elif !defined(__intptr_t_defined) && !defined(_UINTPTR_T_DEFINED)
--typedef PRUptrdiff uintptr_t;
--#endif
--#endif
--
--#else // MOZ_QCMS
--
- #if BYTE_ORDER == LITTLE_ENDIAN
- #define IS_LITTLE_ENDIAN
- #elif BYTE_ORDER == BIG_ENDIAN
-@@ -75,7 +44,7 @@ typedef PRUptrdiff uintptr_t;
-
- #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__)
- # include <inttypes.h>
--#elif defined (_MSC_VER)
-+#elif defined (_MSC_VER) && _MSC_VER < 1600
- typedef __int8 int8_t;
- typedef unsigned __int8 uint8_t;
- typedef __int16 int16_t;
-@@ -87,7 +56,12 @@ typedef unsigned __int64 uint64_t;
- #ifdef _WIN64
- typedef unsigned __int64 uintptr_t;
- #else
-+#pragma warning(push)
-+/* Disable benign redefinition of type warning 4142 */
-+#pragma warning(disable:4142)
- typedef unsigned long uintptr_t;
-+/* Restore warnings */
-+#pragma warning(pop)
- #endif
-
- #elif defined (_AIX)
-@@ -96,8 +70,6 @@ typedef unsigned long uintptr_t;
- # include <stdint.h>
- #endif
-
--#endif
--
- typedef qcms_bool bool;
- #define true 1
- #define false 0
-diff --git a/third_party/qcms/src/transform-sse1.c b/third_party/qcms/src/transform-sse1.c
-index 2f34db5..aaee1bf 100644
---- a/third_party/qcms/src/transform-sse1.c
-+++ b/third_party/qcms/src/transform-sse1.c
-@@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
- void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length)
-+ size_t length,
-+ qcms_format_type output_format)
- {
- unsigned int i;
- float (*mat)[4] = transform->matrix;
-@@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
-
- /* working variables */
- __m128 vec_r, vec_g, vec_b, result;
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-
- /* CYA */
- if (!length)
-@@ -116,9 +119,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
- src += 3;
-
- /* use calc'd indices to output RGB values */
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
- dest += 3;
- }
-
-@@ -141,9 +144,9 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
- result = _mm_movehl_ps(result, result);
- *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
-
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
-
- _mm_empty();
- }
-@@ -151,7 +154,8 @@ void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform,
- void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length)
-+ size_t length,
-+ qcms_format_type output_format)
- {
- unsigned int i;
- float (*mat)[4] = transform->matrix;
-@@ -187,6 +191,8 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
-
- /* working variables */
- __m128 vec_r, vec_g, vec_b, result;
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
- unsigned char alpha;
-
- /* CYA */
-@@ -239,9 +245,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
- src += 4;
-
- /* use calc'd indices to output RGB values */
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
- dest += 4;
- }
-
-@@ -266,9 +272,9 @@ void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform,
- result = _mm_movehl_ps(result, result);
- *((__m64 *)&output[2]) = _mm_cvtps_pi32(result);
-
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
-
- _mm_empty();
- }
-diff --git a/third_party/qcms/src/transform-sse2.c b/third_party/qcms/src/transform-sse2.c
-index 6a5faf9..fa7f2d1 100644
---- a/third_party/qcms/src/transform-sse2.c
-+++ b/third_party/qcms/src/transform-sse2.c
-@@ -34,7 +34,8 @@ static const ALIGN float clampMaxValueX4[4] =
- void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length)
-+ size_t length,
-+ qcms_format_type output_format)
- {
- unsigned int i;
- float (*mat)[4] = transform->matrix;
-@@ -70,6 +71,8 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
-
- /* working variables */
- __m128 vec_r, vec_g, vec_b, result;
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-
- /* CYA */
- if (!length)
-@@ -114,9 +117,9 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
- src += 3;
-
- /* use calc'd indices to output RGB values */
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
- dest += 3;
- }
-
-@@ -137,15 +140,16 @@ void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform,
-
- _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
-
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
- }
-
- void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
- unsigned char *src,
- unsigned char *dest,
-- size_t length)
-+ size_t length,
-+ qcms_format_type output_format)
- {
- unsigned int i;
- float (*mat)[4] = transform->matrix;
-@@ -181,6 +185,8 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
-
- /* working variables */
- __m128 vec_r, vec_g, vec_b, result;
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
- unsigned char alpha;
-
- /* CYA */
-@@ -231,9 +237,9 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
- src += 4;
-
- /* use calc'd indices to output RGB values */
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
- dest += 4;
- }
-
-@@ -256,7 +262,7 @@ void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform,
-
- _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result));
-
-- dest[0] = otdata_r[output[0]];
-- dest[1] = otdata_g[output[1]];
-- dest[2] = otdata_b[output[2]];
-+ dest[r_out] = otdata_r[output[0]];
-+ dest[1] = otdata_g[output[1]];
-+ dest[b_out] = otdata_b[output[2]];
- }
-diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c
-index 9a6562b..f669a6b 100644
---- a/third_party/qcms/src/transform.c
-+++ b/third_party/qcms/src/transform.c
-@@ -181,11 +181,20 @@ compute_chromatic_adaption(struct CIE_XYZ source_white_point,
- static struct matrix
- adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination)
- {
-+#if defined (_MSC_VER)
-+#pragma warning(push)
-+/* Disable double to float truncation warning 4305 */
-+#pragma warning(disable:4305)
-+#endif
- struct matrix lam_rigg = {{ // Bradford matrix
- { 0.8951, 0.2664, -0.1614 },
- { -0.7502, 1.7135, 0.0367 },
- { 0.0389, -0.0685, 1.0296 }
- }};
-+#if defined (_MSC_VER)
-+/* Restore warnings */
-+#pragma warning(pop)
-+#endif
- return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg);
- }
-
-@@ -230,8 +239,11 @@ qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm
- }
-
- #if 0
--static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- int i;
- float (*mat)[4] = transform->matrix;
- for (i=0; i<length; i++) {
-@@ -251,15 +263,19 @@ static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned
- float out_device_g = pow(out_linear_g, transform->out_gamma_g);
- float out_device_b = pow(out_linear_b, transform->out_gamma_b);
-
-- *dest++ = clamp_u8(255*out_device_r);
-- *dest++ = clamp_u8(255*out_device_g);
-- *dest++ = clamp_u8(255*out_device_b);
-+ dest[r_out] = clamp_u8(out_device_r*255);
-+ dest[1] = clamp_u8(out_device_g*255);
-+ dest[b_out] = clamp_u8(out_device_b*255);
-+ dest += 3;
- }
- }
- #endif
-
--static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- for (i = 0; i < length; i++) {
- float out_device_r, out_device_g, out_device_b;
-@@ -267,13 +283,14 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
-
- float linear = transform->input_gamma_table_gray[device];
-
-- out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
-+ out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
- out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
- out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
-
-- *dest++ = clamp_u8(out_device_r*255);
-- *dest++ = clamp_u8(out_device_g*255);
-- *dest++ = clamp_u8(out_device_b*255);
-+ dest[r_out] = clamp_u8(out_device_r*255);
-+ dest[1] = clamp_u8(out_device_g*255);
-+ dest[b_out] = clamp_u8(out_device_b*255);
-+ dest += 3;
- }
- }
-
-@@ -283,8 +300,11 @@ static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned
- See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
- */
-
--static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- for (i = 0; i < length; i++) {
- float out_device_r, out_device_g, out_device_b;
-@@ -293,20 +313,24 @@ static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigne
-
- float linear = transform->input_gamma_table_gray[device];
-
-- out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
-+ out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
- out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
- out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
-
-- *dest++ = clamp_u8(out_device_r*255);
-- *dest++ = clamp_u8(out_device_g*255);
-- *dest++ = clamp_u8(out_device_b*255);
-- *dest++ = alpha;
-+ dest[r_out] = clamp_u8(out_device_r*255);
-+ dest[1] = clamp_u8(out_device_g*255);
-+ dest[b_out] = clamp_u8(out_device_b*255);
-+ dest[3] = alpha;
-+ dest += 4;
- }
- }
-
-
--static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- for (i = 0; i < length; i++) {
- unsigned char device = *src++;
-@@ -317,14 +341,19 @@ static void qcms_transform_data_gray_out_precache(qcms_transform *transform, uns
- /* we could round here... */
- gray = linear * PRECACHE_OUTPUT_MAX;
-
-- *dest++ = transform->output_table_r->data[gray];
-- *dest++ = transform->output_table_g->data[gray];
-- *dest++ = transform->output_table_b->data[gray];
-+ dest[r_out] = transform->output_table_r->data[gray];
-+ dest[1] = transform->output_table_g->data[gray];
-+ dest[b_out] = transform->output_table_b->data[gray];
-+ dest += 3;
- }
- }
-
--static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- for (i = 0; i < length; i++) {
- unsigned char device = *src++;
-@@ -336,15 +365,19 @@ static void qcms_transform_data_graya_out_precache(qcms_transform *transform, un
- /* we could round here... */
- gray = linear * PRECACHE_OUTPUT_MAX;
-
-- *dest++ = transform->output_table_r->data[gray];
-- *dest++ = transform->output_table_g->data[gray];
-- *dest++ = transform->output_table_b->data[gray];
-- *dest++ = alpha;
-+ dest[r_out] = transform->output_table_r->data[gray];
-+ dest[1] = transform->output_table_g->data[gray];
-+ dest[b_out] = transform->output_table_b->data[gray];
-+ dest[3] = alpha;
-+ dest += 4;
- }
- }
-
--static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- float (*mat)[4] = transform->matrix;
- for (i = 0; i < length; i++) {
-@@ -370,14 +403,18 @@ static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform,
- g = out_linear_g * PRECACHE_OUTPUT_MAX;
- b = out_linear_b * PRECACHE_OUTPUT_MAX;
-
-- *dest++ = transform->output_table_r->data[r];
-- *dest++ = transform->output_table_g->data[g];
-- *dest++ = transform->output_table_b->data[b];
-+ dest[r_out] = transform->output_table_r->data[r];
-+ dest[1] = transform->output_table_g->data[g];
-+ dest[b_out] = transform->output_table_b->data[b];
-+ dest += 3;
- }
- }
-
--static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- float (*mat)[4] = transform->matrix;
- for (i = 0; i < length; i++) {
-@@ -404,16 +441,21 @@ static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform,
- g = out_linear_g * PRECACHE_OUTPUT_MAX;
- b = out_linear_b * PRECACHE_OUTPUT_MAX;
-
-- *dest++ = transform->output_table_r->data[r];
-- *dest++ = transform->output_table_g->data[g];
-- *dest++ = transform->output_table_b->data[b];
-- *dest++ = alpha;
-+ dest[r_out] = transform->output_table_r->data[r];
-+ dest[1] = transform->output_table_g->data[g];
-+ dest[b_out] = transform->output_table_b->data[b];
-+ dest[3] = alpha;
-+ dest += 4;
- }
- }
-
- // Not used
- /*
--static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
-+static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
-+{
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- int xy_len = 1;
- int x_len = transform->grid_size;
-@@ -462,15 +504,20 @@ static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *s
- float b_y2 = lerp(b_x3, b_x4, y_d);
- float clut_b = lerp(b_y1, b_y2, z_d);
-
-- *dest++ = clamp_u8(clut_r*255.0f);
-- *dest++ = clamp_u8(clut_g*255.0f);
-- *dest++ = clamp_u8(clut_b*255.0f);
-- }
-+ dest[r_out] = clamp_u8(clut_r*255.0f);
-+ dest[1] = clamp_u8(clut_g*255.0f);
-+ dest[b_out] = clamp_u8(clut_b*255.0f);
-+ dest += 3;
-+ }
- }
- */
-
- // Using lcms' tetra interpolation algorithm.
--static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
-+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)
-+{
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- int xy_len = 1;
- int x_len = transform->grid_size;
-@@ -577,15 +624,20 @@ static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsig
- clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
- clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
-
-- *dest++ = clamp_u8(clut_r*255.0f);
-- *dest++ = clamp_u8(clut_g*255.0f);
-- *dest++ = clamp_u8(clut_b*255.0f);
-- *dest++ = in_a;
-- }
-+ dest[r_out] = clamp_u8(clut_r*255.0f);
-+ dest[1] = clamp_u8(clut_g*255.0f);
-+ dest[b_out] = clamp_u8(clut_b*255.0f);
-+ dest[3] = in_a;
-+ dest += 4;
-+ }
- }
-
- // Using lcms' tetra interpolation code.
--static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
-+static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
-+{
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- int xy_len = 1;
- int x_len = transform->grid_size;
-@@ -691,14 +743,18 @@ static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned c
- clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
- clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
-
-- *dest++ = clamp_u8(clut_r*255.0f);
-- *dest++ = clamp_u8(clut_g*255.0f);
-- *dest++ = clamp_u8(clut_b*255.0f);
-- }
-+ dest[r_out] = clamp_u8(clut_r*255.0f);
-+ dest[1] = clamp_u8(clut_g*255.0f);
-+ dest[b_out] = clamp_u8(clut_b*255.0f);
-+ dest += 3;
-+ }
- }
-
--static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- float (*mat)[4] = transform->matrix;
- for (i = 0; i < length; i++) {
-@@ -726,14 +782,18 @@ static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned
- out_device_b = lut_interp_linear(out_linear_b,
- transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
-
-- *dest++ = clamp_u8(out_device_r*255);
-- *dest++ = clamp_u8(out_device_g*255);
-- *dest++ = clamp_u8(out_device_b*255);
-+ dest[r_out] = clamp_u8(out_device_r*255);
-+ dest[1] = clamp_u8(out_device_g*255);
-+ dest[b_out] = clamp_u8(out_device_b*255);
-+ dest += 3;
- }
- }
-
--static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- unsigned int i;
- float (*mat)[4] = transform->matrix;
- for (i = 0; i < length; i++) {
-@@ -762,16 +822,20 @@ static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned
- out_device_b = lut_interp_linear(out_linear_b,
- transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
-
-- *dest++ = clamp_u8(out_device_r*255);
-- *dest++ = clamp_u8(out_device_g*255);
-- *dest++ = clamp_u8(out_device_b*255);
-- *dest++ = alpha;
-+ dest[r_out] = clamp_u8(out_device_r*255);
-+ dest[1] = clamp_u8(out_device_g*255);
-+ dest[b_out] = clamp_u8(out_device_b*255);
-+ dest[3] = alpha;
-+ dest += 4;
- }
- }
-
- #if 0
--static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
-+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)
- {
-+ const int r_out = output_format.r;
-+ const int b_out = output_format.b;
-+
- int i;
- float (*mat)[4] = transform->matrix;
- for (i = 0; i < length; i++) {
-@@ -787,16 +851,25 @@ static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsign
- float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
- float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
-
-- *dest++ = clamp_u8(out_linear_r*255);
-- *dest++ = clamp_u8(out_linear_g*255);
-- *dest++ = clamp_u8(out_linear_b*255);
-+ dest[r_out] = clamp_u8(out_linear_r*255);
-+ dest[1] = clamp_u8(out_linear_g*255);
-+ dest[b_out] = clamp_u8(out_linear_b*255);
-+ dest += 3;
- }
- }
- #endif
-
-+/*
-+ * If users create and destroy objects on different threads, even if the same
-+ * objects aren't used on different threads at the same time, we can still run
-+ * in to trouble with refcounts if they aren't atomic.
-+ *
-+ * This can lead to us prematurely deleting the precache if threads get unlucky
-+ * and write the wrong value to the ref count.
-+ */
- static struct precache_output *precache_reference(struct precache_output *p)
- {
-- p->ref_count++;
-+ qcms_atomic_increment(p->ref_count);
- return p;
- }
-
-@@ -810,12 +883,12 @@ static struct precache_output *precache_create()
-
- void precache_release(struct precache_output *p)
- {
-- if (--p->ref_count == 0) {
-+ if (qcms_atomic_decrement(p->ref_count) == 0) {
- free(p);
- }
- }
-
--#ifdef HAS_POSIX_MEMALIGN
-+#ifdef HAVE_POSIX_MEMALIGN
- static qcms_transform *transform_alloc(void)
- {
- qcms_transform *t;
-@@ -994,13 +1067,15 @@ void qcms_profile_precache_output_transform(qcms_profile *profile)
- if (profile->color_space != RGB_SIGNATURE)
- return;
-
-- /* don't precache since we will use the B2A LUT */
-- if (profile->B2A0)
-- return;
-+ if (qcms_supports_iccv4) {
-+ /* don't precache since we will use the B2A LUT */
-+ if (profile->B2A0)
-+ return;
-
-- /* don't precache since we will use the mBA LUT */
-- if (profile->mBA)
-- return;
-+ /* don't precache since we will use the mBA LUT */
-+ if (profile->mBA)
-+ return;
-+ }
-
- /* don't precache if we do not have the TRC curves */
- if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC)
-@@ -1043,28 +1118,31 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
- float* src = NULL;
- float* dest = NULL;
- float* lut = NULL;
-+ float inverse;
-
- src = malloc(lutSize*sizeof(float));
- dest = malloc(lutSize*sizeof(float));
-
- if (src && dest) {
-- /* Prepare a list of points we want to sample */
-+ /* Prepare a list of points we want to sample: x, y, z order */
- l = 0;
-+ inverse = 1 / (float)(samples-1);
- for (x = 0; x < samples; x++) {
- for (y = 0; y < samples; y++) {
- for (z = 0; z < samples; z++) {
-- src[l++] = x / (float)(samples-1);
-- src[l++] = y / (float)(samples-1);
-- src[l++] = z / (float)(samples-1);
-+ src[l++] = x * inverse; // r
-+ src[l++] = y * inverse; // g
-+ src[l++] = z * inverse; // b
- }
- }
- }
-
- lut = qcms_chain_transform(in, out, src, dest, lutSize);
-+
- if (lut) {
-- transform->r_clut = &lut[0];
-- transform->g_clut = &lut[1];
-- transform->b_clut = &lut[2];
-+ transform->r_clut = &lut[0]; // r
-+ transform->g_clut = &lut[1]; // g
-+ transform->b_clut = &lut[2]; // b
- transform->grid_size = samples;
- if (in_type == QCMS_DATA_RGBA_8) {
- transform->transform_fn = qcms_transform_data_tetra_clut_rgba;
-@@ -1074,11 +1152,12 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
- }
- }
-
--
-- //XXX: qcms_modular_transform_data may return either the src or dest buffer. If so it must not be free-ed
-+ // XXX: qcms_modular_transform_data may return the lut in either the src or the
-+ // dest buffer. If so, it must not be free-ed.
- if (src && lut != src) {
- free(src);
-- } else if (dest && lut != src) {
-+ }
-+ if (dest && lut != dest) {
- free(dest);
- }
-
-@@ -1088,6 +1167,71 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms
- return transform;
- }
-
-+/* Create a transform LUT using the given number of sample points. The transform LUT data is stored
-+ in the output (cube) in bgra format in zyx sample order. */
-+qcms_bool qcms_transform_create_LUT_zyx_bgra(qcms_profile *in, qcms_profile *out, qcms_intent intent,
-+ int samples, unsigned char* cube)
-+{
-+ uint16_t z,y,x;
-+ uint32_t l,index;
-+ uint32_t lutSize = 3 * samples * samples * samples;
-+
-+ float* src = NULL;
-+ float* dest = NULL;
-+ float* lut = NULL;
-+ float inverse;
-+
-+ src = malloc(lutSize*sizeof(float));
-+ dest = malloc(lutSize*sizeof(float));
-+
-+ if (src && dest) {
-+ /* Prepare a list of points we want to sample: z, y, x order */
-+ l = 0;
-+ inverse = 1 / (float)(samples-1);
-+ for (z = 0; z < samples; z++) {
-+ for (y = 0; y < samples; y++) {
-+ for (x = 0; x < samples; x++) {
-+ src[l++] = x * inverse; // r
-+ src[l++] = y * inverse; // g
-+ src[l++] = z * inverse; // b
-+ }
-+ }
-+ }
-+
-+ lut = qcms_chain_transform(in, out, src, dest, lutSize);
-+
-+ if (lut) {
-+ index = l = 0;
-+ for (z = 0; z < samples; z++) {
-+ for (y = 0; y < samples; y++) {
-+ for (x = 0; x < samples; x++) {
-+ cube[index++] = (int)floorf(lut[l + 2] * 255.0f + 0.5f); // b
-+ cube[index++] = (int)floorf(lut[l + 1] * 255.0f + 0.5f); // g
-+ cube[index++] = (int)floorf(lut[l + 0] * 255.0f + 0.5f); // r
-+ cube[index++] = 255; // a
-+ l += 3;
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+ // XXX: qcms_modular_transform_data may return the lut data in either the src or
-+ // dest buffer so free src, dest, and lut with care.
-+
-+ if (src && lut != src)
-+ free(src);
-+ if (dest && lut != dest)
-+ free(dest);
-+
-+ if (lut) {
-+ free(lut);
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
- #define NO_MEM_TRANSFORM NULL
-
- qcms_transform* qcms_transform_create(
-@@ -1157,14 +1301,14 @@ qcms_transform* qcms_transform_create(
- return NULL;
- }
- if (precache) {
--#ifdef X86
-+#if defined(SSE2_ENABLE) && defined(X86)
- if (sse_version_available() >= 2) {
- if (in_type == QCMS_DATA_RGB_8)
- transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2;
- else
- transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2;
-
--#if !(defined(_MSC_VER) && defined(_M_AMD64))
-+#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64))
- /* Microsoft Compiler for x64 doesn't support MMX.
- * SSE code uses MMX so that we disable on x64 */
- } else
-@@ -1256,13 +1400,34 @@ qcms_transform* qcms_transform_create(
- return transform;
- }
-
--#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
-+/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on unused
-+ * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the presence
-+ * of the attribute but is currently only supported by clang */
-+#if defined(__has_attribute)
-+#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__)
-+#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defined(__arm__) && !defined(__mips__)
-+#define HAS_FORCE_ALIGN_ARG_POINTER 1
-+#else
-+#define HAS_FORCE_ALIGN_ARG_POINTER 0
-+#endif
-+
-+#if HAS_FORCE_ALIGN_ARG_POINTER
- /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
- __attribute__((__force_align_arg_pointer__))
- #endif
- void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length)
- {
-- transform->transform_fn(transform, src, dest, length);
-+ static const struct _qcms_format_type output_rgbx = { 0, 2 };
-+
-+ transform->transform_fn(transform, src, dest, length, output_rgbx);
-+}
-+
-+void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type)
-+{
-+ static const struct _qcms_format_type output_rgbx = { 0, 2 };
-+ static const struct _qcms_format_type output_bgrx = { 2, 0 };
-+
-+ transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPUT_BGRX ? output_bgrx : output_rgbx);
- }
-
- qcms_bool qcms_supports_iccv4;
-diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c
-index e8447e5..5eeafa2 100644
---- a/third_party/qcms/src/transform_util.c
-+++ b/third_party/qcms/src/transform_util.c
-@@ -36,7 +36,7 @@
-
- /* value must be a value between 0 and 1 */
- //XXX: is the above a good restriction to have?
--float lut_interp_linear(double value, uint16_t *table, int length)
-+float lut_interp_linear(double value, uint16_t *table, size_t length)
- {
- int upper, lower;
- value = value * (length - 1); // scale to length of the array
-@@ -49,11 +49,11 @@ float lut_interp_linear(double value, uint16_t *table, int length)
- }
-
- /* same as above but takes and returns a uint16_t value representing a range from 0..1 */
--uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
-+uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length)
- {
- /* Start scaling input_value to the length of the array: 65535*(length-1).
- * We'll divide out the 65535 next */
-- uint32_t value = (input_value * (length - 1));
-+ uintptr_t value = (input_value * (length - 1));
- uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65535) */
- uint32_t lower = value / 65535; /* equivalent to floor(value/65535) */
- /* interp is the distance from upper to value scaled to 0..65535 */
-@@ -67,11 +67,11 @@ uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
- /* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX
- * and returns a uint8_t value representing a range from 0..1 */
- static
--uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, int length)
-+uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, size_t length)
- {
- /* Start scaling input_value to the length of the array: PRECACHE_OUTPUT_MAX*(length-1).
- * We'll divide out the PRECACHE_OUTPUT_MAX next */
-- uint32_t value = (input_value * (length - 1));
-+ uintptr_t value = (input_value * (length - 1));
-
- /* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */
- uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX;
-@@ -91,7 +91,7 @@ uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table,
-
- /* value must be a value between 0 and 1 */
- //XXX: is the above a good restriction to have?
--float lut_interp_linear_float(float value, float *table, int length)
-+float lut_interp_linear_float(float value, float *table, size_t length)
- {
- int upper, lower;
- value = value * (length - 1);
-@@ -235,6 +235,21 @@ float u8Fixed8Number_to_float(uint16_t x)
- return x/256.;
- }
-
-+/* The SSE2 code uses min & max which let NaNs pass through.
-+ We want to try to prevent that here by ensuring that
-+ gamma table is within expected values. */
-+void validate_gamma_table(float gamma_table[256])
-+{
-+ int i;
-+ for (i = 0; i < 256; i++) {
-+ // Note: we check that the gamma is not in range
-+ // instead of out of range so that we catch NaNs
-+ if (!(gamma_table[i] >= 0.f && gamma_table[i] <= 1.f)) {
-+ gamma_table[i] = 0.f;
-+ }
-+ }
-+}
-+
- float *build_input_gamma_table(struct curveType *TRC)
- {
- float *gamma_table;
-@@ -254,7 +269,10 @@ float *build_input_gamma_table(struct curveType *TRC)
- }
- }
- }
-- return gamma_table;
-+
-+ validate_gamma_table(gamma_table);
-+
-+ return gamma_table;
- }
-
- struct matrix build_colorant_matrix(qcms_profile *p)
-@@ -295,7 +313,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
-
- NumZeroes = 0;
- while (LutTable[NumZeroes] == 0 && NumZeroes < length-1)
-- NumZeroes++;
-+ NumZeroes++;
-
- // There are no zeros at the beginning and we are trying to find a zero, so
- // return anything. It seems zero would be the less destructive choice
-@@ -305,26 +323,37 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
-
- NumPoles = 0;
- while (LutTable[length-1- NumPoles] == 0xFFFF && NumPoles < length-1)
-- NumPoles++;
-+ NumPoles++;
-
- // Does the curve belong to this case?
- if (NumZeroes > 1 || NumPoles > 1)
-- {
-- int a, b;
-+ {
-+ int a, b, sample;
-
-- // Identify if value fall downto 0 or FFFF zone
-+ // Identify if value fall downto 0 or FFFF zone
- if (Value == 0) return 0;
-- // if (Value == 0xFFFF) return 0xFFFF;
-+ // if (Value == 0xFFFF) return 0xFFFF;
-+ sample = (length-1) * ((double) Value * (1./65535.));
-+ if (LutTable[sample] == 0)
-+ return 0;
-+ if (LutTable[sample] == 0xffff)
-+ return 0xffff;
-
- // else restrict to valid zone
-
-- a = ((NumZeroes-1) * 0xFFFF) / (length-1);
-+ a = ((NumZeroes-1) * 0xFFFF) / (length-1);
- b = ((length-1 - NumPoles) * 0xFFFF) / (length-1);
--
-+
- l = a - 1;
- r = b + 1;
-- }
-
-+ // Ensure a valid binary search range
-+
-+ if (l < 1)
-+ l = 1;
-+ if (r > 0x10000)
-+ r = 0x10000;
-+ }
-
- // Seems not a degenerated case... apply binary search
-
-@@ -332,12 +361,12 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
-
- x = (l + r) / 2;
-
-- res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length);
-+ res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length);
-
- if (res == Value) {
-
-- // Found exact match.
--
-+ // Found exact match.
-+
- return (uint16_fract_t) (x - 1);
- }
-
-@@ -347,14 +376,14 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
-
- // Not found, should we interpolate?
-
--
-+
- // Get surrounding nodes
--
-+
- val2 = (length-1) * ((double) (x - 1) / 65535.0);
-
- cell0 = (int) floor(val2);
- cell1 = (int) ceil(val2);
--
-+
- if (cell0 == cell1) return (uint16_fract_t) x;
-
- y0 = LutTable[cell0] ;
-@@ -373,8 +402,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
- if (f < 0.0) return (uint16_fract_t) 0;
- if (f >= 65535.0) return (uint16_fract_t) 0xFFFF;
-
-- return (uint16_fract_t) floor(f + 0.5);
--
-+ return (uint16_fract_t) floor(f + 0.5);
- }
-
- /*
-@@ -390,7 +418,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
- which has an maximum error of about 9855 (pixel difference of ~38.346)
-
- For now, we punt the decision of output size to the caller. */
--static uint16_t *invert_lut(uint16_t *table, int length, int out_length)
-+static uint16_t *invert_lut(uint16_t *table, int length, size_t out_length)
- {
- int i;
- /* for now we invert the lut by creating a lut of size out_length
-diff --git a/third_party/qcms/src/transform_util.h b/third_party/qcms/src/transform_util.h
-index 8f358a8..de465f4 100644
---- a/third_party/qcms/src/transform_util.h
-+++ b/third_party/qcms/src/transform_util.h
-@@ -31,9 +31,9 @@
- //XXX: could use a bettername
- typedef uint16_t uint16_fract_t;
-
--float lut_interp_linear(double value, uint16_t *table, int length);
--float lut_interp_linear_float(float value, float *table, int length);
--uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length);
-+float lut_interp_linear(double value, uint16_t *table, size_t length);
-+float lut_interp_linear_float(float value, float *table, size_t length);
-+uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length);
-
-
- static inline float lerp(float a, float b, float t)