| Index: third_party/qcms/google.patch
|
| diff --git a/third_party/qcms/google.patch b/third_party/qcms/google.patch
|
| index ce60f9f0a7a7712608dd1b19d4fb8f9f0ecbcaab..dea54fc41303d01fa328b0ecb5fb99720ba7e9a3 100644
|
| --- a/third_party/qcms/google.patch
|
| +++ b/third_party/qcms/google.patch
|
| @@ -1,5 +1,5 @@
|
| diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c
|
| -index 36b7011..aca19d3 100644
|
| +index 36b7011..6cec34a 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)
|
| @@ -42,12 +42,13 @@ index 36b7011..aca19d3 100644
|
|
|
| static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
|
| {
|
| -@@ -344,6 +354,47 @@ static struct tag *find_tag(struct tag_index index, uint32_t tag_id)
|
| +@@ -344,6 +354,152 @@ 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'
|
| +
|
| +static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id)
|
| +{
|
| @@ -57,23 +58,31 @@ index 36b7011..aca19d3 100644
|
| + uint32_t offset = tag->offset;
|
| + uint32_t type = read_u32(src, offset);
|
| + uint32_t length = read_u32(src, offset+8);
|
| -+ uint32_t i, description;
|
| ++ 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 + read_u32(src, offset+24);
|
| ++ 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 + 12;
|
| ++ description_offset = offset + 12;
|
| + } else {
|
| + goto invalid_desc_tag;
|
| + }
|
| + if (length >= limit)
|
| + length = limit - 1;
|
| -+ for (i = 0; i < length; ++i)
|
| -+ profile->description[i] = read_u8(src, description+i);
|
| ++ 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;
|
| @@ -87,10 +96,106 @@ index 36b7011..aca19d3 100644
|
| + 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 +453,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_inde
|
| +@@ -402,7 +558,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)
|
| {
|
| @@ -99,7 +204,7 @@ index 36b7011..aca19d3 100644
|
| struct curveType *curve = NULL;
|
| uint32_t type = read_u32(src, offset);
|
| uint32_t count;
|
| -@@ -484,19 +535,23 @@ static void read_nested_curveType(struct mem_source *src, struct curveType *(*cu
|
| +@@ -484,19 +640,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++) {
|
| @@ -125,7 +230,7 @@ index 36b7011..aca19d3 100644
|
| }
|
|
|
| static void mAB_release(struct lutmABType *lut)
|
| -@@ -657,7 +712,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
|
| +@@ -657,7 +817,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;
|
| @@ -134,7 +239,7 @@ index 36b7011..aca19d3 100644
|
| uint32_t clut_size;
|
| size_t entry_size;
|
| struct lutType *lut;
|
| -@@ -979,6 +1034,9 @@ qcms_profile* qcms_profile_sRGB(void)
|
| +@@ -979,6 +1139,9 @@ qcms_profile* qcms_profile_sRGB(void)
|
| return NO_MEM_PROFILE;
|
|
|
| profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024);
|
| @@ -144,7 +249,7 @@ index 36b7011..aca19d3 100644
|
| free(table);
|
| return profile;
|
| }
|
| -@@ -997,6 +1055,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
|
| +@@ -997,6 +1160,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
|
| source.size = size;
|
| source.valid = true;
|
|
|
| @@ -154,17 +259,23 @@ index 36b7011..aca19d3 100644
|
| length = read_u32(src, 0);
|
| if (length <= size) {
|
| // shrink the area that we can read if appropriate
|
| -@@ -1028,6 +1089,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
|
| +@@ -1028,6 +1194,15 @@ 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 {
|
| -@@ -1098,6 +1162,16 @@ invalid_profile:
|
| +@@ -1098,6 +1273,16 @@ invalid_profile:
|
| return INVALID_PROFILE;
|
| }
|
|
|
| @@ -182,7 +293,7 @@ index 36b7011..aca19d3 100644
|
| {
|
| return profile->rendering_intent;
|
| diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h
|
| -index 7d83623..c69a772 100644
|
| +index 7d83623..e9c0b09 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
|
| @@ -221,11 +332,19 @@ index 7d83623..c69a772 100644
|
| void qcms_profile_precache_output_transform(qcms_profile *profile);
|
|
|
| qcms_transform* qcms_transform_create(
|
| -@@ -146,6 +161,7 @@ qcms_transform* qcms_transform_create(
|
| - void qcms_transform_release(qcms_transform *);
|
| +@@ -143,9 +158,14 @@ qcms_transform* qcms_transform_create(
|
| + 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();
|
|
|
| @@ -565,7 +684,7 @@ index 6a5faf9..fa7f2d1 100644
|
| + 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..08db142 100644
|
| +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,
|
| @@ -981,8 +1100,53 @@ index 9a6562b..08db142 100644
|
|
|
| /* don't precache if we do not have the TRC curves */
|
| if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC)
|
| -@@ -1078,7 +1153,8 @@ 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
|
| +@@ -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) {
|
| @@ -991,7 +1155,79 @@ index 9a6562b..08db142 100644
|
| free(dest);
|
| }
|
|
|
| -@@ -1157,14 +1233,14 @@ qcms_transform* qcms_transform_create(
|
| +@@ -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) {
|
| @@ -1008,7 +1244,7 @@ index 9a6562b..08db142 100644
|
| /* Microsoft Compiler for x64 doesn't support MMX.
|
| * SSE code uses MMX so that we disable on x64 */
|
| } else
|
| -@@ -1256,13 +1332,34 @@ qcms_transform* qcms_transform_create(
|
| +@@ -1256,13 +1400,34 @@ qcms_transform* qcms_transform_create(
|
| return transform;
|
| }
|
|
|
|
|