| OLD | NEW | 
|     1 diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c |     1 diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c | 
|     2 index 36b7011..aca19d3 100644 |     2 index 36b7011..6cec34a 100644 | 
|     3 --- a/third_party/qcms/src/iccread.c |     3 --- a/third_party/qcms/src/iccread.c | 
|     4 +++ b/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) |     5 @@ -266,7 +266,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) | 
|     6         if (profile->color_space != RGB_SIGNATURE) |     6         if (profile->color_space != RGB_SIGNATURE) | 
|     7                return false; |     7                return false; | 
|     8   |     8   | 
|     9 -       if (profile->A2B0 || profile->B2A0) |     9 -       if (profile->A2B0 || profile->B2A0) | 
|    10 +       if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0)) |    10 +       if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0)) | 
|    11                 return false; |    11                 return false; | 
|    12   |    12   | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
|    35         for (i = 0; i < 3; ++i) { |    35         for (i = 0; i < 3; ++i) { | 
|    36             if (!(((sum[i] - tolerance[i]) <= target[i]) && |    36             if (!(((sum[i] - tolerance[i]) <= target[i]) && | 
|    37 @@ -331,6 +340,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) |    37 @@ -331,6 +340,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) | 
|    38  #define TAG_A2B0 0x41324230 |    38  #define TAG_A2B0 0x41324230 | 
|    39  #define TAG_B2A0 0x42324130 |    39  #define TAG_B2A0 0x42324130 | 
|    40  #define TAG_CHAD 0x63686164 |    40  #define TAG_CHAD 0x63686164 | 
|    41 +#define TAG_desc 0x64657363 |    41 +#define TAG_desc 0x64657363 | 
|    42   |    42   | 
|    43  static struct tag *find_tag(struct tag_index index, uint32_t tag_id) |    43  static struct tag *find_tag(struct tag_index index, uint32_t tag_id) | 
|    44  { |    44  { | 
|    45 @@ -344,6 +354,47 @@ static struct tag *find_tag(struct tag_index index, uint32_
      t tag_id) |    45 @@ -344,6 +354,152 @@ static struct tag *find_tag(struct tag_index index, uint32
      _t tag_id) | 
|    46         return tag; |    46         return tag; | 
|    47  } |    47  } | 
|    48   |    48   | 
|    49 +#define DESC_TYPE 0x64657363 // 'desc' |    49 +#define DESC_TYPE 0x64657363 // 'desc' | 
|    50 +#define MLUC_TYPE 0x6d6c7563 // 'mluc' |    50 +#define MLUC_TYPE 0x6d6c7563 // 'mluc' | 
 |    51 +#define MMOD_TYPE 0x6D6D6F64 // 'mmod' | 
|    51 + |    52 + | 
|    52 +static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, st
      ruct tag_index index, uint32_t tag_id) |    53 +static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, st
      ruct tag_index index, uint32_t tag_id) | 
|    53 +{ |    54 +{ | 
|    54 +       struct tag *tag = find_tag(index, tag_id); |    55 +       struct tag *tag = find_tag(index, tag_id); | 
|    55 +       if (tag) { |    56 +       if (tag) { | 
|    56 +               const uint32_t limit = sizeof profile->description; |    57 +               const uint32_t limit = sizeof profile->description; | 
|    57 +               uint32_t offset = tag->offset; |    58 +               uint32_t offset = tag->offset; | 
|    58 +               uint32_t type = read_u32(src, offset); |    59 +               uint32_t type = read_u32(src, offset); | 
|    59 +               uint32_t length = read_u32(src, offset+8); |    60 +               uint32_t length = read_u32(src, offset+8); | 
|    60 +»      »       uint32_t i, description; |    61 +»      »       uint32_t i, description_offset; | 
 |    62 +»      »       bool mluc = false; | 
|    61 +               if (length && type == MLUC_TYPE) { |    63 +               if (length && type == MLUC_TYPE) { | 
|    62 +                       length = read_u32(src, offset+20); |    64 +                       length = read_u32(src, offset+20); | 
|    63 +                       if (!length || (length & 1) || (read_u32(src, offset+12)
       != 12)) |    65 +                       if (!length || (length & 1) || (read_u32(src, offset+12)
       != 12)) | 
|    64 +                               goto invalid_desc_tag; |    66 +                               goto invalid_desc_tag; | 
|    65 +»      »       »       description = offset + read_u32(src, offset+24); |    67 +»      »       »       description_offset = offset + read_u32(src, offset+24); | 
|    66 +                       if (!src->valid) |    68 +                       if (!src->valid) | 
|    67 +                               goto invalid_desc_tag; |    69 +                               goto invalid_desc_tag; | 
 |    70 +                       mluc = true; | 
|    68 +               } else if (length && type == DESC_TYPE) { |    71 +               } else if (length && type == DESC_TYPE) { | 
|    69 +»      »       »       description = offset + 12; |    72 +»      »       »       description_offset = offset + 12; | 
|    70 +               } else { |    73 +               } else { | 
|    71 +                       goto invalid_desc_tag; |    74 +                       goto invalid_desc_tag; | 
|    72 +               } |    75 +               } | 
|    73 +               if (length >= limit) |    76 +               if (length >= limit) | 
|    74 +                       length = limit - 1; |    77 +                       length = limit - 1; | 
|    75 +»      »       for (i = 0; i < length; ++i) |    78 +»      »       for (i = 0; i < length; ++i) { | 
|    76 +»      »       »       profile->description[i] = read_u8(src, description+i); |    79 +»      »       »       uint8_t value = read_u8(src, description_offset + i); | 
 |    80 +»      »       »       if (!src->valid) | 
 |    81 +»      »       »       »       goto invalid_desc_tag; | 
 |    82 +»      »       »       if (mluc && !value) | 
 |    83 +»      »       »       »       value = '.'; | 
 |    84 +»      »       »       profile->description[i] = value; | 
 |    85 +»      »       } | 
|    77 +               profile->description[length] = 0; |    86 +               profile->description[length] = 0; | 
|    78 +       } else { |    87 +       } else { | 
|    79 +               goto invalid_desc_tag; |    88 +               goto invalid_desc_tag; | 
|    80 +       } |    89 +       } | 
|    81 + |    90 + | 
|    82 +       if (src->valid) |    91 +       if (src->valid) | 
|    83 +               return true; |    92 +               return true; | 
|    84 + |    93 + | 
|    85 +invalid_desc_tag: |    94 +invalid_desc_tag: | 
|    86 +       invalid_source(src, "invalid description"); |    95 +       invalid_source(src, "invalid description"); | 
|    87 +       return false; |    96 +       return false; | 
|    88 +} |    97 +} | 
|    89 + |    98 + | 
 |    99 +#if defined(__APPLE__) | 
 |   100 + | 
 |   101 +// Use the dscm tag to change profile description "Display" to its more specifi
      c en-localized monitor name, if any. | 
 |   102 + | 
 |   103 +#define TAG_dscm  0x6473636D // 'dscm' | 
 |   104 + | 
 |   105 +static bool read_tag_dscmType(qcms_profile *profile, struct mem_source *src, st
      ruct tag_index index, uint32_t tag_id) | 
 |   106 +{ | 
 |   107 +       if (strcmp(profile->description, "Display") != 0) | 
 |   108 +               return true; | 
 |   109 + | 
 |   110 +       struct tag *tag = find_tag(index, tag_id); | 
 |   111 +       if (tag) { | 
 |   112 +               uint32_t offset = tag->offset; | 
 |   113 +               uint32_t type = read_u32(src, offset); | 
 |   114 +               uint32_t records = read_u32(src, offset+8); | 
 |   115 + | 
 |   116 +               if (!src->valid || !records || type != MLUC_TYPE) | 
 |   117 +                       goto invalid_dscm_tag; | 
 |   118 +               if (read_u32(src, offset+12) != 12) // MLUC record size: bytes | 
 |   119 +                       goto invalid_dscm_tag; | 
 |   120 + | 
 |   121 +               for (uint32_t i = 0; i < records; ++i) { | 
 |   122 +                       const uint32_t limit = sizeof profile->description; | 
 |   123 +                       const uint16_t isoen = 0x656E; // ISO-3166-1 language 'e
      n' | 
 |   124 + | 
 |   125 +                       uint16_t language = read_u16(src, offset + 16 + (i * 12)
       + 0); | 
 |   126 +                       uint32_t length = read_u32(src, offset + 16 + (i * 12) +
       4); | 
 |   127 +                       uint32_t description_offset = read_u32(src, offset + 16 
      + (i * 12) + 8); | 
 |   128 + | 
 |   129 +                       if (!src->valid || !length || (length & 1)) | 
 |   130 +                               goto invalid_dscm_tag; | 
 |   131 +                       if (language != isoen) | 
 |   132 +                               continue; | 
 |   133 + | 
 |   134 +                       // Use a prefix to identify the display description sour
      ce | 
 |   135 +                       strcpy(profile->description, "dscm:"); | 
 |   136 +                       length += 5; | 
 |   137 + | 
 |   138 +                       if (length >= limit) | 
 |   139 +                               length = limit - 1; | 
 |   140 +                       for (uint32_t j = 5; j < length; ++j) { | 
 |   141 +                               uint8_t value = read_u8(src, offset + descriptio
      n_offset + j - 5); | 
 |   142 +                               if (!src->valid) | 
 |   143 +                                       goto invalid_dscm_tag; | 
 |   144 +                               profile->description[j] = value ? value : '.'; | 
 |   145 +                       } | 
 |   146 +                       profile->description[length] = 0; | 
 |   147 +                       break; | 
 |   148 +               } | 
 |   149 +       } | 
 |   150 + | 
 |   151 +       if (src->valid) | 
 |   152 +               return true; | 
 |   153 + | 
 |   154 +invalid_dscm_tag: | 
 |   155 +       invalid_source(src, "invalid dscm tag"); | 
 |   156 +       return false; | 
 |   157 +} | 
 |   158 + | 
 |   159 +// Use the mmod tag to change profile description "Display" to its specific mmo
      d maker model data, if any. | 
 |   160 + | 
 |   161 +#define TAG_mmod  0x6D6D6F64 // 'mmod' | 
 |   162 + | 
 |   163 +static bool read_tag_mmodType(qcms_profile *profile, struct mem_source *src, st
      ruct tag_index index, uint32_t tag_id) | 
 |   164 +{ | 
 |   165 +       if (strcmp(profile->description, "Display") != 0) | 
 |   166 +               return true; | 
 |   167 + | 
 |   168 +       struct tag *tag = find_tag(index, tag_id); | 
 |   169 +       if (tag) { | 
 |   170 +               const uint8_t length = 4 * 4; // Four 4-byte fields: 'mmod', 0, 
      maker, model. | 
 |   171 + | 
 |   172 +               uint32_t offset = tag->offset; | 
 |   173 +               if (tag->size < 40 || read_u32(src, offset) != MMOD_TYPE) | 
 |   174 +                       goto invalid_mmod_tag; | 
 |   175 + | 
 |   176 +               for (uint8_t i = 0; i < length; ++i) { | 
 |   177 +                       uint8_t value = read_u8(src, offset + i); | 
 |   178 +                       if (!src->valid) | 
 |   179 +                               goto invalid_mmod_tag; | 
 |   180 +                       profile->description[i] = value ? value : '.'; | 
 |   181 +               } | 
 |   182 +               profile->description[length] = 0; | 
 |   183 +       } | 
 |   184 + | 
 |   185 +       if (src->valid) | 
 |   186 +               return true; | 
 |   187 + | 
 |   188 +invalid_mmod_tag: | 
 |   189 +       invalid_source(src, "invalid mmod tag"); | 
 |   190 +       return false; | 
 |   191 +} | 
 |   192 + | 
 |   193 +#endif // __APPLE__ | 
 |   194 + | 
|    90  #define XYZ_TYPE               0x58595a20 // 'XYZ ' |   195  #define XYZ_TYPE               0x58595a20 // 'XYZ ' | 
|    91  #define CURVE_TYPE             0x63757276 // 'curv' |   196  #define CURVE_TYPE             0x63757276 // 'curv' | 
|    92  #define PARAMETRIC_CURVE_TYPE  0x70617261 // 'para' |   197  #define PARAMETRIC_CURVE_TYPE  0x70617261 // 'para' | 
|    93 @@ -402,7 +453,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *
      src, struct tag_inde |   198 @@ -402,7 +558,7 @@ static struct XYZNumber read_tag_XYZType(struct mem_source *
      src, struct tag_inde | 
|    94  // present that are not part of the tag_index. |   199  // present that are not part of the tag_index. | 
|    95  static struct curveType *read_curveType(struct mem_source *src, uint32_t offset
      , uint32_t *len) |   200  static struct curveType *read_curveType(struct mem_source *src, uint32_t offset
      , uint32_t *len) | 
|    96  { |   201  { | 
|    97 -       static const size_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; |   202 -       static const size_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; | 
|    98 +       static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; |   203 +       static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; | 
|    99         struct curveType *curve = NULL; |   204         struct curveType *curve = NULL; | 
|   100         uint32_t type = read_u32(src, offset); |   205         uint32_t type = read_u32(src, offset); | 
|   101         uint32_t count; |   206         uint32_t count; | 
|   102 @@ -484,19 +535,23 @@ static void read_nested_curveType(struct mem_source *src, 
      struct curveType *(*cu |   207 @@ -484,19 +640,23 @@ static void read_nested_curveType(struct mem_source *src, 
      struct curveType *(*cu | 
|   103         uint32_t channel_offset = 0; |   208         uint32_t channel_offset = 0; | 
|   104         int i; |   209         int i; | 
|   105         for (i = 0; i < num_channels; i++) { |   210         for (i = 0; i < num_channels; i++) { | 
|   106 -               uint32_t tag_len; |   211 -               uint32_t tag_len; | 
|   107 +               uint32_t tag_len = ~0; |   212 +               uint32_t tag_len = ~0; | 
|   108   |   213   | 
|   109                 (*curveArray)[i] = read_curveType(src, curve_offset + channel_of
      fset, &tag_len); |   214                 (*curveArray)[i] = read_curveType(src, curve_offset + channel_of
      fset, &tag_len); | 
|   110                 if (!(*curveArray)[i]) { |   215                 if (!(*curveArray)[i]) { | 
|   111                         invalid_source(src, "invalid nested curveType curve"); |   216                         invalid_source(src, "invalid nested curveType curve"); | 
|   112                 } |   217                 } | 
|   113   |   218   | 
|   114 +               if (tag_len == ~0) { |   219 +               if (tag_len == ~0) { | 
|   115 +                       invalid_source(src, "invalid nested curveType tag length
      "); |   220 +                       invalid_source(src, "invalid nested curveType tag length
      "); | 
|   116 +                       return; |   221 +                       return; | 
|   117 +               } |   222 +               } | 
|   118 + |   223 + | 
|   119                 channel_offset += tag_len; |   224                 channel_offset += tag_len; | 
|   120                 // 4 byte aligned |   225                 // 4 byte aligned | 
|   121                 if ((tag_len % 4) != 0) |   226                 if ((tag_len % 4) != 0) | 
|   122                         channel_offset += 4 - (tag_len % 4); |   227                         channel_offset += 4 - (tag_len % 4); | 
|   123         } |   228         } | 
|   124 - |   229 - | 
|   125  } |   230  } | 
|   126   |   231   | 
|   127  static void mAB_release(struct lutmABType *lut) |   232  static void mAB_release(struct lutmABType *lut) | 
|   128 @@ -657,7 +712,7 @@ static struct lutType *read_tag_lutType(struct mem_source *s
      rc, struct tag_index |   233 @@ -657,7 +817,7 @@ static struct lutType *read_tag_lutType(struct mem_source *s
      rc, struct tag_index | 
|   129         uint16_t num_input_table_entries; |   234         uint16_t num_input_table_entries; | 
|   130         uint16_t num_output_table_entries; |   235         uint16_t num_output_table_entries; | 
|   131         uint8_t in_chan, grid_points, out_chan; |   236         uint8_t in_chan, grid_points, out_chan; | 
|   132 -       uint32_t clut_offset, output_offset; |   237 -       uint32_t clut_offset, output_offset; | 
|   133 +       size_t clut_offset, output_offset; |   238 +       size_t clut_offset, output_offset; | 
|   134         uint32_t clut_size; |   239         uint32_t clut_size; | 
|   135         size_t entry_size; |   240         size_t entry_size; | 
|   136         struct lutType *lut; |   241         struct lutType *lut; | 
|   137 @@ -979,6 +1034,9 @@ qcms_profile* qcms_profile_sRGB(void) |   242 @@ -979,6 +1139,9 @@ qcms_profile* qcms_profile_sRGB(void) | 
|   138                 return NO_MEM_PROFILE; |   243                 return NO_MEM_PROFILE; | 
|   139   |   244   | 
|   140         profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table
      , 1024); |   245         profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table
      , 1024); | 
|   141 +       if (profile) |   246 +       if (profile) | 
|   142 +               strcpy(profile->description, "sRGB IEC61966-2.1"); |   247 +               strcpy(profile->description, "sRGB IEC61966-2.1"); | 
|   143 + |   248 + | 
|   144         free(table); |   249         free(table); | 
|   145         return profile; |   250         return profile; | 
|   146  } |   251  } | 
|   147 @@ -997,6 +1055,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, siz
      e_t size) |   252 @@ -997,6 +1160,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, siz
      e_t size) | 
|   148         source.size = size; |   253         source.size = size; | 
|   149         source.valid = true; |   254         source.valid = true; | 
|   150   |   255   | 
|   151 +       if (size < 4) |   256 +       if (size < 4) | 
|   152 +               return INVALID_PROFILE; |   257 +               return INVALID_PROFILE; | 
|   153 + |   258 + | 
|   154         length = read_u32(src, 0); |   259         length = read_u32(src, 0); | 
|   155         if (length <= size) { |   260         if (length <= size) { | 
|   156                 // shrink the area that we can read if appropriate |   261                 // shrink the area that we can read if appropriate | 
|   157 @@ -1028,6 +1089,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, si
      ze_t size) |   262 @@ -1028,6 +1194,15 @@ qcms_profile* qcms_profile_from_memory(const void *mem, s
      ize_t size) | 
|   158         if (!src->valid || !index.tags) |   263         if (!src->valid || !index.tags) | 
|   159                 goto invalid_tag_table; |   264                 goto invalid_tag_table; | 
|   160   |   265   | 
|   161 +       if (!read_tag_descType(profile, src, index, TAG_desc)) |   266 +       if (!read_tag_descType(profile, src, index, TAG_desc)) | 
|   162 +               goto invalid_tag_table; |   267 +               goto invalid_tag_table; | 
 |   268 +#if defined(__APPLE__) | 
 |   269 +       if (!read_tag_dscmType(profile, src, index, TAG_dscm)) | 
 |   270 +               goto invalid_tag_table; | 
 |   271 +       if (!read_tag_mmodType(profile, src, index, TAG_mmod)) | 
 |   272 +               goto invalid_tag_table; | 
 |   273 +#endif // __APPLE__ | 
|   163 + |   274 + | 
|   164         if (find_tag(index, TAG_CHAD)) { |   275         if (find_tag(index, TAG_CHAD)) { | 
|   165                 profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, i
      ndex, TAG_CHAD); |   276                 profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, i
      ndex, TAG_CHAD); | 
|   166         } else { |   277         } else { | 
|   167 @@ -1098,6 +1162,16 @@ invalid_profile: |   278 @@ -1098,6 +1273,16 @@ invalid_profile: | 
|   168         return INVALID_PROFILE; |   279         return INVALID_PROFILE; | 
|   169  } |   280  } | 
|   170   |   281   | 
|   171 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2) |   282 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2) | 
|   172 +{ |   283 +{ | 
|   173 +    return memcmp(p1->description, p2->description, sizeof p1->description) == 
      0; |   284 +    return memcmp(p1->description, p2->description, sizeof p1->description) == 
      0; | 
|   174 +} |   285 +} | 
|   175 + |   286 + | 
|   176 +const char* qcms_profile_get_description(qcms_profile *profile) |   287 +const char* qcms_profile_get_description(qcms_profile *profile) | 
|   177 +{ |   288 +{ | 
|   178 +    return profile->description; |   289 +    return profile->description; | 
|   179 +} |   290 +} | 
|   180 + |   291 + | 
|   181  qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) |   292  qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) | 
|   182  { |   293  { | 
|   183         return profile->rendering_intent; |   294         return profile->rendering_intent; | 
|   184 diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h |   295 diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h | 
|   185 index 7d83623..c69a772 100644 |   296 index 7d83623..e9c0b09 100644 | 
|   186 --- a/third_party/qcms/src/qcms.h |   297 --- a/third_party/qcms/src/qcms.h | 
|   187 +++ b/third_party/qcms/src/qcms.h |   298 +++ b/third_party/qcms/src/qcms.h | 
|   188 @@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written |   299 @@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written | 
|   189  authorization from SunSoft Inc.  |   300  authorization from SunSoft Inc.  | 
|   190  ******************************************************************/ |   301  ******************************************************************/ | 
|   191   |   302   | 
|   192 +/* |   303 +/* | 
|   193 + * QCMS, in general, is not threadsafe. However, it should be safe to create |   304 + * QCMS, in general, is not threadsafe. However, it should be safe to create | 
|   194 + * profile and transformation objects on different threads, so long as you |   305 + * profile and transformation objects on different threads, so long as you | 
|   195 + * don't use the same objects on different threads at the same time. |   306 + * don't use the same objects on different threads at the same time. | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
|   214 @@ -136,6 +148,9 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile); |   325 @@ -136,6 +148,9 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile); | 
|   215  qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile); |   326  qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile); | 
|   216  icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile); |   327  icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile); | 
|   217   |   328   | 
|   218 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2); |   329 +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2); | 
|   219 +const char* qcms_profile_get_description(qcms_profile *profile); |   330 +const char* qcms_profile_get_description(qcms_profile *profile); | 
|   220 + |   331 + | 
|   221  void qcms_profile_precache_output_transform(qcms_profile *profile); |   332  void qcms_profile_precache_output_transform(qcms_profile *profile); | 
|   222   |   333   | 
|   223  qcms_transform* qcms_transform_create( |   334  qcms_transform* qcms_transform_create( | 
|   224 @@ -146,6 +161,7 @@ qcms_transform* qcms_transform_create( |   335 @@ -143,9 +158,14 @@ qcms_transform* qcms_transform_create( | 
|   225  void qcms_transform_release(qcms_transform *); |   336  »      »       qcms_profile* out, qcms_data_type out_type, | 
 |   337  »      »       qcms_intent intent); | 
 |   338   | 
 |   339 -void qcms_transform_release(qcms_transform *); | 
 |   340 +qcms_bool qcms_transform_create_LUT_zyx_bgra( | 
 |   341 +»      »       qcms_profile *in, qcms_profile* out, qcms_intent intent, | 
 |   342 +»      »       int samples, unsigned char* lut); | 
|   226   |   343   | 
|   227  void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size
      _t length); |   344  void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size
      _t length); | 
|   228 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest,
       size_t length, qcms_output_type type); |   345 +void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest,
       size_t length, qcms_output_type type); | 
 |   346 + | 
 |   347 +void qcms_transform_release(qcms_transform *); | 
|   229   |   348   | 
|   230  void qcms_enable_iccv4(); |   349  void qcms_enable_iccv4(); | 
|   231   |   350   | 
|   232 diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h |   351 diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h | 
|   233 index 53a3420..4116ed5 100644 |   352 index 53a3420..4116ed5 100644 | 
|   234 --- a/third_party/qcms/src/qcmsint.h |   353 --- a/third_party/qcms/src/qcmsint.h | 
|   235 +++ b/third_party/qcms/src/qcmsint.h |   354 +++ b/third_party/qcms/src/qcmsint.h | 
|   236 @@ -45,6 +45,11 @@ struct precache_output |   355 @@ -45,6 +45,11 @@ struct precache_output | 
|   237  #define ALIGN __attribute__(( aligned (16) )) |   356  #define ALIGN __attribute__(( aligned (16) )) | 
|   238  #endif |   357  #endif | 
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   558      _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); |   677      _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); | 
|   559   |   678   | 
|   560 -    dest[0] = otdata_r[output[0]]; |   679 -    dest[0] = otdata_r[output[0]]; | 
|   561 -    dest[1] = otdata_g[output[1]]; |   680 -    dest[1] = otdata_g[output[1]]; | 
|   562 -    dest[2] = otdata_b[output[2]]; |   681 -    dest[2] = otdata_b[output[2]]; | 
|   563 +    dest[r_out] = otdata_r[output[0]]; |   682 +    dest[r_out] = otdata_r[output[0]]; | 
|   564 +    dest[1]     = otdata_g[output[1]]; |   683 +    dest[1]     = otdata_g[output[1]]; | 
|   565 +    dest[b_out] = otdata_b[output[2]]; |   684 +    dest[b_out] = otdata_b[output[2]]; | 
|   566  } |   685  } | 
|   567 diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c |   686 diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c | 
|   568 index 9a6562b..08db142 100644 |   687 index 9a6562b..f669a6b 100644 | 
|   569 --- a/third_party/qcms/src/transform.c |   688 --- a/third_party/qcms/src/transform.c | 
|   570 +++ b/third_party/qcms/src/transform.c |   689 +++ b/third_party/qcms/src/transform.c | 
|   571 @@ -181,11 +181,20 @@ compute_chromatic_adaption(struct CIE_XYZ source_white_poi
      nt, |   690 @@ -181,11 +181,20 @@ compute_chromatic_adaption(struct CIE_XYZ source_white_poi
      nt, | 
|   572  static struct matrix |   691  static struct matrix | 
|   573  adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illum
      ination) |   692  adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illum
      ination) | 
|   574  { |   693  { | 
|   575 +#if defined (_MSC_VER) |   694 +#if defined (_MSC_VER) | 
|   576 +#pragma warning(push) |   695 +#pragma warning(push) | 
|   577 +/* Disable double to float truncation warning 4305 */ |   696 +/* Disable double to float truncation warning 4305 */ | 
|   578 +#pragma warning(disable:4305) |   697 +#pragma warning(disable:4305) | 
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   974 -       /* don't precache since we will use the mBA LUT */ |  1093 -       /* don't precache since we will use the mBA LUT */ | 
|   975 -       if (profile->mBA) |  1094 -       if (profile->mBA) | 
|   976 -               return; |  1095 -               return; | 
|   977 +               /* don't precache since we will use the mBA LUT */ |  1096 +               /* don't precache since we will use the mBA LUT */ | 
|   978 +               if (profile->mBA) |  1097 +               if (profile->mBA) | 
|   979 +                       return; |  1098 +                       return; | 
|   980 +       } |  1099 +       } | 
|   981   |  1100   | 
|   982         /* don't precache if we do not have the TRC curves */ |  1101         /* don't precache if we do not have the TRC curves */ | 
|   983         if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC) |  1102         if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC) | 
|   984 @@ -1078,7 +1153,8 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_tran
      sform *transform, qcms |  1103 @@ -1043,28 +1118,31 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_tr
      ansform *transform, qcms | 
|   985  »      //XXX: qcms_modular_transform_data may return either the src or dest buf
      fer. If so it must not be free-ed |  1104  »      float* src = NULL; | 
 |  1105  »      float* dest = NULL; | 
 |  1106  »      float* lut = NULL; | 
 |  1107 +»      float inverse; | 
 |  1108   | 
 |  1109  »      src = malloc(lutSize*sizeof(float)); | 
 |  1110  »      dest = malloc(lutSize*sizeof(float)); | 
 |  1111   | 
 |  1112  »      if (src && dest) { | 
 |  1113 -»      »       /* Prepare a list of points we want to sample */ | 
 |  1114 +»      »       /* Prepare a list of points we want to sample: x, y, z order */ | 
 |  1115  »      »       l = 0; | 
 |  1116 +»      »       inverse = 1 / (float)(samples-1); | 
 |  1117  »      »       for (x = 0; x < samples; x++) { | 
 |  1118  »      »       »       for (y = 0; y < samples; y++) { | 
 |  1119  »      »       »       »       for (z = 0; z < samples; z++) { | 
 |  1120 -»      »       »       »       »       src[l++] = x / (float)(samples-1); | 
 |  1121 -»      »       »       »       »       src[l++] = y / (float)(samples-1); | 
 |  1122 -»      »       »       »       »       src[l++] = z / (float)(samples-1); | 
 |  1123 +»      »       »       »       »       src[l++] = x * inverse; // r | 
 |  1124 +»      »       »       »       »       src[l++] = y * inverse; // g | 
 |  1125 +»      »       »       »       »       src[l++] = z * inverse; // b | 
 |  1126  »      »       »       »       } | 
 |  1127  »      »       »       } | 
 |  1128  »      »       } | 
 |  1129   | 
 |  1130  »      »       lut = qcms_chain_transform(in, out, src, dest, lutSize); | 
 |  1131 + | 
 |  1132  »      »       if (lut) { | 
 |  1133 -»      »       »       transform->r_clut = &lut[0]; | 
 |  1134 -»      »       »       transform->g_clut = &lut[1]; | 
 |  1135 -»      »       »       transform->b_clut = &lut[2]; | 
 |  1136 +»      »       »       transform->r_clut = &lut[0]; // r | 
 |  1137 +»      »       »       transform->g_clut = &lut[1]; // g | 
 |  1138 +»      »       »       transform->b_clut = &lut[2]; // b | 
 |  1139  »      »       »       transform->grid_size = samples; | 
 |  1140  »      »       »       if (in_type == QCMS_DATA_RGBA_8) { | 
 |  1141  »      »       »       »       transform->transform_fn = qcms_transform_data_te
      tra_clut_rgba; | 
 |  1142 @@ -1074,11 +1152,12 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_tr
      ansform *transform, qcms | 
 |  1143  »      »       } | 
 |  1144  »      } | 
 |  1145   | 
 |  1146 - | 
 |  1147 -»      //XXX: qcms_modular_transform_data may return either the src or dest buf
      fer. If so it must not be free-ed | 
 |  1148 +»      // XXX: qcms_modular_transform_data may return the lut in either the src
       or the | 
 |  1149 +»      // dest buffer. If so, it must not be free-ed. | 
|   986         if (src && lut != src) { |  1150         if (src && lut != src) { | 
|   987                 free(src); |  1151                 free(src); | 
|   988 -       } else if (dest && lut != src) { |  1152 -       } else if (dest && lut != src) { | 
|   989 +       } |  1153 +       } | 
|   990 +       if (dest && lut != dest) { |  1154 +       if (dest && lut != dest) { | 
|   991                 free(dest); |  1155                 free(dest); | 
|   992         } |  1156         } | 
|   993   |  1157   | 
|   994 @@ -1157,14 +1233,14 @@ qcms_transform* qcms_transform_create( |  1158 @@ -1088,6 +1167,71 @@ qcms_transform* qcms_transform_precacheLUT_float(qcms_tra
      nsform *transform, qcms | 
 |  1159  »      return transform; | 
 |  1160  } | 
 |  1161   | 
 |  1162 +/* Create a transform LUT using the given number of sample points. The transfor
      m LUT data is stored | 
 |  1163 +   in the output (cube) in bgra format in zyx sample order. */ | 
 |  1164 +qcms_bool qcms_transform_create_LUT_zyx_bgra(qcms_profile *in, qcms_profile *ou
      t, qcms_intent intent, | 
 |  1165 +                                             int samples, unsigned char* cube) | 
 |  1166 +{ | 
 |  1167 +»      uint16_t z,y,x; | 
 |  1168 +»      uint32_t l,index; | 
 |  1169 +»      uint32_t lutSize = 3 * samples * samples * samples; | 
 |  1170 + | 
 |  1171 +»      float* src = NULL; | 
 |  1172 +»      float* dest = NULL; | 
 |  1173 +»      float* lut = NULL; | 
 |  1174 +»      float inverse; | 
 |  1175 + | 
 |  1176 +»      src = malloc(lutSize*sizeof(float)); | 
 |  1177 +»      dest = malloc(lutSize*sizeof(float)); | 
 |  1178 + | 
 |  1179 +»      if (src && dest) { | 
 |  1180 +»      »       /* Prepare a list of points we want to sample: z, y, x order */ | 
 |  1181 +»      »       l = 0; | 
 |  1182 +»      »       inverse = 1 / (float)(samples-1); | 
 |  1183 +»      »       for (z = 0; z < samples; z++) { | 
 |  1184 +»      »       »       for (y = 0; y < samples; y++) { | 
 |  1185 +»      »       »       »       for (x = 0; x < samples; x++) { | 
 |  1186 +»      »       »       »       »       src[l++] = x * inverse; // r | 
 |  1187 +»      »       »       »       »       src[l++] = y * inverse; // g | 
 |  1188 +»      »       »       »       »       src[l++] = z * inverse; // b | 
 |  1189 +»      »       »       »       } | 
 |  1190 +»      »       »       } | 
 |  1191 +»      »       } | 
 |  1192 + | 
 |  1193 +»      »       lut = qcms_chain_transform(in, out, src, dest, lutSize); | 
 |  1194 + | 
 |  1195 +»      »       if (lut) { | 
 |  1196 +»      »       »       index = l = 0; | 
 |  1197 +»      »       »       for (z = 0; z < samples; z++) { | 
 |  1198 +»      »       »       »       for (y = 0; y < samples; y++) { | 
 |  1199 +»      »       »       »       »       for (x = 0; x < samples; x++) { | 
 |  1200 +»      »       »       »       »       »       cube[index++] = (int)floorf(lut[
      l + 2] * 255.0f + 0.5f); // b | 
 |  1201 +»      »       »       »       »       »       cube[index++] = (int)floorf(lut[
      l + 1] * 255.0f + 0.5f); // g | 
 |  1202 +»      »       »       »       »       »       cube[index++] = (int)floorf(lut[
      l + 0] * 255.0f + 0.5f); // r | 
 |  1203 +»      »       »       »       »       »       cube[index++] = 255;            
                               // a | 
 |  1204 +»      »       »       »       »       »       l += 3; | 
 |  1205 +»      »       »       »       »       } | 
 |  1206 +»      »       »       »       } | 
 |  1207 +»      »       »       } | 
 |  1208 +»      »       } | 
 |  1209 +»      } | 
 |  1210 + | 
 |  1211 +»      // XXX: qcms_modular_transform_data may return the lut data in either th
      e src or | 
 |  1212 +»      // dest buffer so free src, dest, and lut with care. | 
 |  1213 + | 
 |  1214 +»      if (src && lut != src) | 
 |  1215 +»      »       free(src); | 
 |  1216 +»      if (dest && lut != dest) | 
 |  1217 +»      »       free(dest); | 
 |  1218 + | 
 |  1219 +»      if (lut) { | 
 |  1220 +»      »       free(lut); | 
 |  1221 +»      »       return true; | 
 |  1222 +»      } | 
 |  1223 + | 
 |  1224 +»      return false; | 
 |  1225 +} | 
 |  1226 + | 
 |  1227  #define NO_MEM_TRANSFORM NULL | 
 |  1228   | 
 |  1229  qcms_transform* qcms_transform_create( | 
 |  1230 @@ -1157,14 +1301,14 @@ qcms_transform* qcms_transform_create( | 
|   995                         return NULL; |  1231                         return NULL; | 
|   996                 } |  1232                 } | 
|   997                 if (precache) { |  1233                 if (precache) { | 
|   998 -#ifdef X86 |  1234 -#ifdef X86 | 
|   999 +#if defined(SSE2_ENABLE) && defined(X86) |  1235 +#if defined(SSE2_ENABLE) && defined(X86) | 
|  1000                     if (sse_version_available() >= 2) { |  1236                     if (sse_version_available() >= 2) { | 
|  1001                             if (in_type == QCMS_DATA_RGB_8) |  1237                             if (in_type == QCMS_DATA_RGB_8) | 
|  1002                                     transform->transform_fn = qcms_transform_dat
      a_rgb_out_lut_sse2; |  1238                                     transform->transform_fn = qcms_transform_dat
      a_rgb_out_lut_sse2; | 
|  1003                             else |  1239                             else | 
|  1004                                     transform->transform_fn = qcms_transform_dat
      a_rgba_out_lut_sse2; |  1240                                     transform->transform_fn = qcms_transform_dat
      a_rgba_out_lut_sse2; | 
|  1005   |  1241   | 
|  1006 -#if !(defined(_MSC_VER) && defined(_M_AMD64)) |  1242 -#if !(defined(_MSC_VER) && defined(_M_AMD64)) | 
|  1007 +#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64)) |  1243 +#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64)) | 
|  1008                      /* Microsoft Compiler for x64 doesn't support MMX. |  1244                      /* Microsoft Compiler for x64 doesn't support MMX. | 
|  1009                       * SSE code uses MMX so that we disable on x64 */ |  1245                       * SSE code uses MMX so that we disable on x64 */ | 
|  1010                     } else |  1246                     } else | 
|  1011 @@ -1256,13 +1332,34 @@ qcms_transform* qcms_transform_create( |  1247 @@ -1256,13 +1400,34 @@ qcms_transform* qcms_transform_create( | 
|  1012         return transform; |  1248         return transform; | 
|  1013  } |  1249  } | 
|  1014   |  1250   | 
|  1015 -#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) |  1251 -#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) | 
|  1016 +/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on
       unused |  1252 +/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on
       unused | 
|  1017 + * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the p
      resence |  1253 + * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the p
      resence | 
|  1018 + * of the attribute but is currently only supported by clang */ |  1254 + * of the attribute but is currently only supported by clang */ | 
|  1019 +#if defined(__has_attribute) |  1255 +#if defined(__has_attribute) | 
|  1020 +#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__
      ) |  1256 +#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__
      ) | 
|  1021 +#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defi
      ned(__arm__) && !defined(__mips__) |  1257 +#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defi
      ned(__arm__) && !defined(__mips__) | 
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1148   |  1384   | 
|  1149 -float lut_interp_linear(double value, uint16_t *table, int length); |  1385 -float lut_interp_linear(double value, uint16_t *table, int length); | 
|  1150 -float lut_interp_linear_float(float value, float *table, int length); |  1386 -float lut_interp_linear_float(float value, float *table, int length); | 
|  1151 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
      ; |  1387 -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
      ; | 
|  1152 +float lut_interp_linear(double value, uint16_t *table, size_t length); |  1388 +float lut_interp_linear(double value, uint16_t *table, size_t length); | 
|  1153 +float lut_interp_linear_float(float value, float *table, size_t length); |  1389 +float lut_interp_linear_float(float value, float *table, size_t length); | 
|  1154 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t leng
      th); |  1390 +uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t leng
      th); | 
|  1155   |  1391   | 
|  1156   |  1392   | 
|  1157  static inline float lerp(float a, float b, float t) |  1393  static inline float lerp(float a, float b, float t) | 
| OLD | NEW |