1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkAutoMalloc.h"
9 #include "SkColorSpace.h"
10 #include "SkColorSpacePriv.h"
11 #include "SkColorSpace_A2B.h"
12 #include "SkColorSpace_XYZ.h"
13 #include "SkEndian.h"
14 #include "SkFixed.h"
15 #include "SkICCPriv.h"
16 #include "SkTemplates.h"
17 
18 #define return_if_false(pred, msg)                                   \
19     do {                                                             \
20         if (!(pred)) {                                               \
21             SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \
22             return false;                                            \
23         }                                                            \
24     } while (0)
25 
26 #define return_null(msg)                                             \
27     do {                                                             \
28         SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg));     \
29         return nullptr;                                              \
30     } while (0)
31 
read_big_endian_u16(const uint8_t * ptr)32 static uint16_t read_big_endian_u16(const uint8_t* ptr) {
33     return ptr[0] << 8 | ptr[1];
34 }
35 
read_big_endian_u32(const uint8_t * ptr)36 static uint32_t read_big_endian_u32(const uint8_t* ptr) {
37     return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
38 }
39 
read_big_endian_i32(const uint8_t * ptr)40 static int32_t read_big_endian_i32(const uint8_t* ptr) {
41     return (int32_t) read_big_endian_u32(ptr);
42 }
43 
44 static constexpr float kWhitePointD50[] = { 0.96420f, 1.00000f, 0.82491f, };
45 
46 struct ICCProfileHeader {
47     uint32_t fSize;
48 
49     // No reason to care about the preferred color management module (ex: Adobe, Apple, etc.).
50     // We're always going to use this one.
51     uint32_t fCMMType_ignored;
52 
53     uint32_t fVersion;
54     uint32_t fProfileClass;
55     uint32_t fInputColorSpace;
56     uint32_t fPCS;
57     uint32_t fDateTime_ignored[3];
58     uint32_t fSignature;
59 
60     // Indicates the platform that this profile was created for (ex: Apple, Microsoft).  This
61     // doesn't really matter to us.
62     uint32_t fPlatformTarget_ignored;
63 
64     // Flags can indicate:
65     // (1) Whether this profile was embedded in a file.  This flag is consistently wrong.
66     //     Ex: The profile came from a file but indicates that it did not.
67     // (2) Whether we are allowed to use the profile independently of the color data.  If set,
68     //     this may allow us to use the embedded profile for testing separate from the original
69     //     image.
70     uint32_t fFlags_ignored;
71 
72     // We support many output devices.  It doesn't make sense to think about the attributes of
73     // the device in the context of the image profile.
74     uint32_t fDeviceManufacturer_ignored;
75     uint32_t fDeviceModel_ignored;
76     uint32_t fDeviceAttributes_ignored[2];
77 
78     uint32_t fRenderingIntent;
79     int32_t  fIlluminantXYZ[3];
80 
81     // We don't care who created the profile.
82     uint32_t fCreator_ignored;
83 
84     // This is an MD5 checksum.  Could be useful for checking if profiles are equal.
85     uint32_t fProfileId_ignored[4];
86 
87     // Reserved for future use.
88     uint32_t fReserved_ignored[7];
89 
90     uint32_t fTagCount;
91 
initICCProfileHeader92     void init(const uint8_t* src, size_t len) {
93         SkASSERT(kICCHeaderSize == sizeof(*this));
94 
95         uint32_t* dst = (uint32_t*) this;
96         for (uint32_t i = 0; i < kICCHeaderSize / 4; i++, src+=4) {
97             dst[i] = read_big_endian_u32(src);
98         }
99     }
100 
validICCProfileHeader101     bool valid() const {
102         return_if_false(fSize >= kICCHeaderSize, "Size is too small");
103 
104         uint8_t majorVersion = fVersion >> 24;
105         return_if_false(majorVersion <= 4, "Unsupported version");
106 
107         // These are the four basic classes of profiles that we might expect to see embedded
108         // in images.  Additional classes exist, but they generally are used as a convenient
109         // way for CMMs to store calculated transforms.
110         return_if_false(fProfileClass == kDisplay_Profile ||
111                         fProfileClass == kInput_Profile ||
112                         fProfileClass == kOutput_Profile ||
113                         fProfileClass == kColorSpace_Profile,
114                         "Unsupported profile");
115 
116         switch (fInputColorSpace) {
117             case kRGB_ColorSpace:
118                 SkColorSpacePrintf("RGB Input Color Space");
119                 break;
120             case kCMYK_ColorSpace:
121                 SkColorSpacePrintf("CMYK Input Color Space\n");
122                 break;
123             case kGray_ColorSpace:
124                 SkColorSpacePrintf("Gray Input Color Space\n");
125                 break;
126             default:
127                 SkColorSpacePrintf("Unsupported Input Color Space: %c%c%c%c\n",
128                                    (fInputColorSpace>>24)&0xFF, (fInputColorSpace>>16)&0xFF,
129                                    (fInputColorSpace>> 8)&0xFF, (fInputColorSpace>> 0)&0xFF);
130                 return false;
131         }
132 
133         switch (fPCS) {
134             case kXYZ_PCSSpace:
135                 SkColorSpacePrintf("XYZ PCS\n");
136                 break;
137             case kLAB_PCSSpace:
138                 SkColorSpacePrintf("Lab PCS\n");
139                 break;
140             default:
141                 // ICC currently (V4.3) only specifices XYZ and Lab PCS spaces
142                 SkColorSpacePrintf("Unsupported PCS space: %c%c%c%c\n",
143                                    (fPCS>>24)&0xFF, (fPCS>>16)&0xFF,
144                                    (fPCS>> 8)&0xFF, (fPCS>> 0)&0xFF);
145                 return false;
146         }
147 
148         return_if_false(fSignature == kACSP_Signature, "Bad signature");
149 
150         // TODO (msarett):
151         // Should we treat different rendering intents differently?
152         // Valid rendering intents include kPerceptual (0), kRelative (1),
153         // kSaturation (2), and kAbsolute (3).
154         if (fRenderingIntent > 3) {
155             // Warn rather than fail here.  Occasionally, we see perfectly
156             // normal profiles with wacky rendering intents.
157             SkColorSpacePrintf("Warning, bad rendering intent.\n");
158         }
159 
160         return_if_false(
161                 color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[0]), kWhitePointD50[0]) &&
162                 color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[1]), kWhitePointD50[1]) &&
163                 color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[2]), kWhitePointD50[2]),
164                 "Illuminant must be D50");
165 
166         return_if_false(fTagCount <= 100, "Too many tags");
167 
168         return true;
169     }
170 };
171 
172 template <class T>
safe_add(T arg1,T arg2,size_t * result)173 static bool safe_add(T arg1, T arg2, size_t* result) {
174     SkASSERT(arg1 >= 0);
175     SkASSERT(arg2 >= 0);
176     if (arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) {
177         T sum = arg1 + arg2;
178         if (sum <= std::numeric_limits<size_t>::max()) {
179             *result = static_cast<size_t>(sum);
180             return true;
181         }
182     }
183     return false;
184 }
185 
safe_mul(uint32_t arg1,uint32_t arg2,uint32_t * result)186 static bool safe_mul(uint32_t arg1, uint32_t arg2, uint32_t* result) {
187     uint64_t product64 = (uint64_t) arg1 * (uint64_t) arg2;
188     uint32_t product32 = (uint32_t) product64;
189     if (product32 != product64) {
190         return false;
191     }
192 
193     *result = product32;
194     return true;
195 }
196 
197 struct ICCTag {
198     uint32_t fSignature;
199     uint32_t fOffset;
200     uint32_t fLength;
201 
initICCTag202     const uint8_t* init(const uint8_t* src) {
203         fSignature = read_big_endian_u32(src);
204         fOffset = read_big_endian_u32(src + 4);
205         fLength = read_big_endian_u32(src + 8);
206         return src + 12;
207     }
208 
validICCTag209     bool valid(size_t len) {
210         size_t tagEnd;
211         return_if_false(safe_add(fOffset, fLength, &tagEnd),
212                         "Tag too large, overflows integer addition");
213         return_if_false(tagEnd <= len, "Tag too large for ICC profile");
214         return true;
215     }
216 
addrICCTag217     const uint8_t* addr(const uint8_t* src) const {
218         return src + fOffset;
219     }
220 
FindICCTag221     static const ICCTag* Find(const ICCTag tags[], int count, uint32_t signature) {
222         for (int i = 0; i < count; ++i) {
223             if (tags[i].fSignature == signature) {
224                 return &tags[i];
225             }
226         }
227         return nullptr;
228     }
229 };
230 
load_xyz(float dst[3],const uint8_t * src,size_t len)231 static bool load_xyz(float dst[3], const uint8_t* src, size_t len) {
232     if (len < 20) {
233         SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len);
234         return false;
235     }
236 
237     dst[0] = SkFixedToFloat(read_big_endian_i32(src + 8));
238     dst[1] = SkFixedToFloat(read_big_endian_i32(src + 12));
239     dst[2] = SkFixedToFloat(read_big_endian_i32(src + 16));
240     SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]);
241     return true;
242 }
243 
set_gamma_value(SkGammas::Data * data,float value)244 static SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) {
245     if (color_space_almost_equal(2.2f, value)) {
246         data->fNamed = k2Dot2Curve_SkGammaNamed;
247         return SkGammas::Type::kNamed_Type;
248     }
249 
250     if (color_space_almost_equal(1.0f, value)) {
251         data->fNamed = kLinear_SkGammaNamed;
252         return SkGammas::Type::kNamed_Type;
253     }
254 
255     if (color_space_almost_equal(0.0f, value)) {
256         return SkGammas::Type::kNone_Type;
257     }
258 
259     data->fValue = value;
260     return SkGammas::Type::kValue_Type;
261 }
262 
read_big_endian_16_dot_16(const uint8_t buf[4])263 static float read_big_endian_16_dot_16(const uint8_t buf[4]) {
264     // It just so happens that SkFixed is also 16.16!
265     return SkFixedToFloat(read_big_endian_i32(buf));
266 }
267 
268 /**
269  *  @param outData     Set to the appropriate value on success.  If we have table or
270  *                     parametric gamma, it is the responsibility of the caller to set
271  *                     fOffset.
272  *  @param outParams   If this is a parametric gamma, this is set to the appropriate
273  *                     parameters on success.
274  *  @param outTagBytes Will be set to the length of the tag on success.
275  *  @src               Pointer to tag data.
276  *  @len               Length of tag data in bytes.
277  *
278  *  @return            kNone_Type on failure, otherwise the type of the gamma tag.
279  */
parse_gamma(SkGammas::Data * outData,SkColorSpaceTransferFn * outParams,size_t * outTagBytes,const uint8_t * src,size_t len)280 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkColorSpaceTransferFn* outParams,
281                                   size_t* outTagBytes, const uint8_t* src, size_t len) {
282     if (len < 12) {
283         SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
284         return SkGammas::Type::kNone_Type;
285     }
286 
287     // In the case of consecutive gamma tags, we need to count the number of bytes in the
288     // tag, so that we can move on to the next tag.
289     size_t tagBytes;
290 
291     uint32_t type = read_big_endian_u32(src);
292     // Bytes 4-7 are reserved and should be set to zero.
293     switch (type) {
294         case kTAG_CurveType: {
295             uint32_t count = read_big_endian_u32(src + 8);
296 
297             // tagBytes = 12 + 2 * count
298             // We need to do safe addition here to avoid integer overflow.
299             if (!safe_add(count, count, &tagBytes) ||
300                 !safe_add((size_t) 12, tagBytes, &tagBytes))
301             {
302                 SkColorSpacePrintf("Invalid gamma count");
303                 return SkGammas::Type::kNone_Type;
304             }
305 
306             if (len < tagBytes) {
307                 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
308                 return SkGammas::Type::kNone_Type;
309             }
310             *outTagBytes = tagBytes;
311 
312             if (0 == count) {
313                 // Some tags require a gamma curve, but the author doesn't actually want
314                 // to transform the data.  In this case, it is common to see a curve with
315                 // a count of 0.
316                 outData->fNamed = kLinear_SkGammaNamed;
317                 return SkGammas::Type::kNamed_Type;
318             }
319 
320             const uint16_t* table = (const uint16_t*) (src + 12);
321             if (1 == count) {
322                 // The table entry is the gamma (with a bias of 256).
323                 float value = (read_big_endian_u16((const uint8_t*) table)) / 256.0f;
324                 SkColorSpacePrintf("gamma %g\n", value);
325 
326                 return set_gamma_value(outData, value);
327             }
328 
329             // This optimization is especially important for A2B profiles, where we do
330             // not resize tables or interpolate lookups.
331             if (2 == count) {
332                 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) &&
333                         65535 == read_big_endian_u16((const uint8_t*) &table[1])) {
334                     outData->fNamed = kLinear_SkGammaNamed;
335                     return SkGammas::Type::kNamed_Type;
336                 }
337             }
338 
339             // Check for frequently occurring sRGB curves.
340             // We do this by sampling a few values and see if they match our expectation.
341             // A more robust solution would be to compare each value in this curve against
342             // an sRGB curve to see if we remain below an error threshold.  At this time,
343             // we haven't seen any images in the wild that make this kind of
344             // calculation necessary.  We encounter identical gamma curves over and
345             // over again, but relatively few variations.
346             if (1024 == count) {
347                 // The magic values were chosen because they match both the very common
348                 // HP sRGB gamma table and the less common Canon sRGB gamma table (which use
349                 // different rounding rules).
350                 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) &&
351                         3366 == read_big_endian_u16((const uint8_t*) &table[257]) &&
352                         14116 == read_big_endian_u16((const uint8_t*) &table[513]) &&
353                         34318 == read_big_endian_u16((const uint8_t*) &table[768]) &&
354                         65535 == read_big_endian_u16((const uint8_t*) &table[1023])) {
355                     outData->fNamed = kSRGB_SkGammaNamed;
356                     return SkGammas::Type::kNamed_Type;
357                 }
358             }
359 
360             if (26 == count) {
361                 // The magic values match a clever "minimum size" approach to representing sRGB.
362                 // code.facebook.com/posts/411525055626587/under-the-hood-improving-facebook-photos
363                 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) &&
364                         3062 == read_big_endian_u16((const uint8_t*) &table[6]) &&
365                         12824 == read_big_endian_u16((const uint8_t*) &table[12]) &&
366                         31237 == read_big_endian_u16((const uint8_t*) &table[18]) &&
367                         65535 == read_big_endian_u16((const uint8_t*) &table[25])) {
368                     outData->fNamed = kSRGB_SkGammaNamed;
369                     return SkGammas::Type::kNamed_Type;
370                 }
371             }
372 
373             if (4096 == count) {
374                 // The magic values were chosen because they match Nikon, Epson, and
375                 // lcms2 sRGB gamma tables (all of which use different rounding rules).
376                 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) &&
377                         950 == read_big_endian_u16((const uint8_t*) &table[515]) &&
378                         3342 == read_big_endian_u16((const uint8_t*) &table[1025]) &&
379                         14079 == read_big_endian_u16((const uint8_t*) &table[2051]) &&
380                         65535 == read_big_endian_u16((const uint8_t*) &table[4095])) {
381                     outData->fNamed = kSRGB_SkGammaNamed;
382                     return SkGammas::Type::kNamed_Type;
383                 }
384             }
385 
386             // Otherwise, we will represent gamma with a table.
387             outData->fTable.fSize = count;
388             return SkGammas::Type::kTable_Type;
389         }
390         case kTAG_ParaCurveType: {
391             // Determine the format of the parametric curve tag.
392             uint16_t format = read_big_endian_u16(src + 8);
393             if (format > kGABCDEF_ParaCurveType) {
394                 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
395                 return SkGammas::Type::kNone_Type;
396             }
397 
398             if (kExponential_ParaCurveType == format) {
399                 tagBytes = 12 + 4;
400                 if (len < tagBytes) {
401                     SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
402                     return SkGammas::Type::kNone_Type;
403                 }
404 
405                 // Y = X^g
406                 float g = read_big_endian_16_dot_16(src + 12);
407 
408                 *outTagBytes = tagBytes;
409                 return set_gamma_value(outData, g);
410             }
411 
412             // Here's where the real parametric gammas start.  There are many
413             // permutations of the same equations.
414             //
415             // Y = (aX + b)^g + e  for X >= d
416             // Y = cX + f          otherwise
417             //
418             // We will fill in with zeros as necessary to always match the above form.
419             if (len < 24) {
420                 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
421                 return SkGammas::Type::kNone_Type;
422             }
423             float g = read_big_endian_16_dot_16(src + 12);
424             float a = read_big_endian_16_dot_16(src + 16);
425             float b = read_big_endian_16_dot_16(src + 20);
426             float c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f;
427             switch(format) {
428                 case kGAB_ParaCurveType:
429                     tagBytes = 12 + 12;
430 
431                     // Y = (aX + b)^g  for X >= -b/a
432                     // Y = 0           otherwise
433                     d = -b / a;
434                     break;
435                 case kGABC_ParaCurveType:
436                     tagBytes = 12 + 16;
437                     if (len < tagBytes) {
438                         SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
439                         return SkGammas::Type::kNone_Type;
440                     }
441 
442                     // Y = (aX + b)^g + e  for X >= -b/a
443                     // Y = e               otherwise
444                     e = read_big_endian_16_dot_16(src + 24);
445                     d = -b / a;
446                     f = e;
447                     break;
448                 case kGABDE_ParaCurveType:
449                     tagBytes = 12 + 20;
450                     if (len < tagBytes) {
451                         SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
452                         return SkGammas::Type::kNone_Type;
453                     }
454 
455                     // Y = (aX + b)^g  for X >= d
456                     // Y = cX          otherwise
457                     c = read_big_endian_16_dot_16(src + 24);
458                     d = read_big_endian_16_dot_16(src + 28);
459                     break;
460                 case kGABCDEF_ParaCurveType:
461                     tagBytes = 12 + 28;
462                     if (len < tagBytes) {
463                         SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
464                         return SkGammas::Type::kNone_Type;
465                     }
466 
467                     // Y = (aX + b)^g + e  for X >= d
468                     // Y = cX + f          otherwise
469                     c = read_big_endian_16_dot_16(src + 24);
470                     d = read_big_endian_16_dot_16(src + 28);
471                     e = read_big_endian_16_dot_16(src + 32);
472                     f = read_big_endian_16_dot_16(src + 36);
473                     break;
474                 default:
475                     SkASSERT(false);
476                     return SkGammas::Type::kNone_Type;
477             }
478 
479             outParams->fG = g;
480             outParams->fA = a;
481             outParams->fB = b;
482             outParams->fC = c;
483             outParams->fD = d;
484             outParams->fE = e;
485             outParams->fF = f;
486 
487             if (!is_valid_transfer_fn(*outParams)) {
488                 return SkGammas::Type::kNone_Type;
489             }
490 
491             if (is_almost_srgb(*outParams)) {
492                 outData->fNamed = kSRGB_SkGammaNamed;
493                 return SkGammas::Type::kNamed_Type;
494             }
495 
496             if (is_almost_2dot2(*outParams)) {
497                 outData->fNamed = k2Dot2Curve_SkGammaNamed;
498                 return SkGammas::Type::kNamed_Type;
499             }
500 
501             *outTagBytes = tagBytes;
502             return SkGammas::Type::kParam_Type;
503         }
504         default:
505             SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
506             return SkGammas::Type::kNone_Type;
507     }
508 }
509 
510 /**
511  *  Returns the additional size in bytes needed to store the gamma tag.
512  */
gamma_alloc_size(SkGammas::Type type,const SkGammas::Data & data)513 static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) {
514     switch (type) {
515         case SkGammas::Type::kNamed_Type:
516         case SkGammas::Type::kValue_Type:
517             return 0;
518         case SkGammas::Type::kTable_Type:
519             return sizeof(float) * data.fTable.fSize;
520         case SkGammas::Type::kParam_Type:
521             return sizeof(SkColorSpaceTransferFn);
522         default:
523             SkASSERT(false);
524             return 0;
525     }
526 }
527 
528 /**
529  *  Sets invalid gamma to the default value.
530  */
handle_invalid_gamma(SkGammas::Type * type,SkGammas::Data * data)531 static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) {
532     if (SkGammas::Type::kNone_Type == *type) {
533         *type = SkGammas::Type::kNamed_Type;
534 
535         // Guess sRGB in the case of a malformed transfer function.
536         data->fNamed = kSRGB_SkGammaNamed;
537     }
538 }
539 
540 /**
541  *  Finish loading the gammas, now that we have allocated memory for the SkGammas struct.
542  *
543  *  There's nothing to do for the simple cases, but for table gammas we need to actually
544  *  read the table into heap memory.  And for parametric gammas, we need to copy over the
545  *  parameter values.
546  *
547  *  @param memory Pointer to start of the SkGammas memory block
548  *  @param offset Bytes of memory (after the SkGammas struct) that are already in use.
549  *  @param data   In-out variable.  Will fill in the offset to the table or parameters
550  *                if necessary.
551  *  @param params Parameters for gamma curve.  Only initialized/used when we have a
552  *                parametric gamma.
553  *  @param src    Pointer to start of the gamma tag.
554  *
555  *  @return       Additional bytes of memory that are being used by this gamma curve.
556  */
load_gammas(void * memory,size_t offset,SkGammas::Type type,SkGammas::Data * data,const SkColorSpaceTransferFn & params,const uint8_t * src)557 static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
558                         SkGammas::Data* data, const SkColorSpaceTransferFn& params,
559                         const uint8_t* src) {
560     void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas));
561 
562     switch (type) {
563         case SkGammas::Type::kNamed_Type:
564         case SkGammas::Type::kValue_Type:
565             // Nothing to do here.
566             return 0;
567         case SkGammas::Type::kTable_Type: {
568             data->fTable.fOffset = offset;
569 
570             float* outTable = (float*) storage;
571             const uint16_t* inTable = (const uint16_t*) (src + 12);
572             for (int i = 0; i < data->fTable.fSize; i++) {
573                 outTable[i] = (read_big_endian_u16((const uint8_t*) &inTable[i])) / 65535.0f;
574             }
575 
576             return sizeof(float) * data->fTable.fSize;
577         }
578         case SkGammas::Type::kParam_Type:
579             data->fTable.fOffset = offset;
580             memcpy(storage, &params, sizeof(SkColorSpaceTransferFn));
581             return sizeof(SkColorSpaceTransferFn);
582         default:
583             SkASSERT(false);
584             return 0;
585     }
586 }
587 
588 static constexpr uint32_t kTAG_AtoBType  = SkSetFourByteTag('m', 'A', 'B', ' ');
589 static constexpr uint32_t kTAG_lut8Type  = SkSetFourByteTag('m', 'f', 't', '1');
590 static constexpr uint32_t kTAG_lut16Type = SkSetFourByteTag('m', 'f', 't', '2');
591 
load_color_lut(sk_sp<SkColorLookUpTable> * colorLUT,uint32_t inputChannels,size_t precision,const uint8_t gridPoints[3],const uint8_t * src,size_t len)592 static bool load_color_lut(sk_sp<SkColorLookUpTable>* colorLUT, uint32_t inputChannels,
593                            size_t precision, const uint8_t gridPoints[3], const uint8_t* src,
594                            size_t len) {
595     switch (precision) {
596         case 1: //  8-bit data
597         case 2: // 16-bit data
598             break;
599         default:
600             SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit. Found: %d-bit\n",
601                                8*precision);
602             return false;
603     }
604 
605     uint32_t numEntries = SkColorLookUpTable::kOutputChannels;
606     for (uint32_t i = 0; i < inputChannels; i++) {
607         if (1 >= gridPoints[i]) {
608             SkColorSpacePrintf("Each input channel must have at least two grid points.");
609             return false;
610         }
611 
612         if (!safe_mul(numEntries, gridPoints[i], &numEntries)) {
613             SkColorSpacePrintf("Too many entries in Color LUT.");
614             return false;
615         }
616     }
617 
618     uint32_t clutBytes;
619     if (!safe_mul(numEntries, precision, &clutBytes)) {
620         SkColorSpacePrintf("Too many entries in Color LUT.\n");
621         return false;
622     }
623 
624     if (len < clutBytes) {
625         SkColorSpacePrintf("Color LUT tag is too small (%d / %d bytes).\n", len, clutBytes);
626         return false;
627     }
628 
629     // Movable struct colorLUT has ownership of fTable.
630     void* memory = sk_malloc_throw(sizeof(SkColorLookUpTable) + sizeof(float) * numEntries);
631     *colorLUT = sk_sp<SkColorLookUpTable>(new (memory) SkColorLookUpTable(inputChannels,
632                                                                           gridPoints));
633 
634     float* table = SkTAddOffset<float>(memory, sizeof(SkColorLookUpTable));
635     const uint8_t* ptr = src;
636     for (uint32_t i = 0; i < numEntries; i++, ptr += precision) {
637         if (1 == precision) {
638             table[i] = ((float) *ptr) / 255.0f;
639         } else {
640             table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f;
641         }
642     }
643 
644     return true;
645 }
646 
647 /**
648  *  Reads a matrix out of an A2B tag of an ICC profile.
649  *  If |translate| is true, it will load a 3x4 matrix out that corresponds to a XYZ
650  *  transform as well as a translation, and if |translate| is false it only loads a
651  *  3x3 matrix with no translation
652  *
653  *  @param matrix    The matrix to store the result in
654  *  @param src       Data to load the matrix out of.
655  *  @param len       The length of |src|.
656  *                   Must have 48 bytes if |translate| is set and 36 bytes otherwise.
657  *  @param translate Whether to read the translation column or not
658  *  @param pcs       The profile connection space of the profile this matrix is for
659  *
660  *  @return          false on failure, true on success
661  */
load_matrix(SkMatrix44 * matrix,const uint8_t * src,size_t len,bool translate,SkColorSpace_A2B::PCS pcs)662 static bool load_matrix(SkMatrix44* matrix, const uint8_t* src, size_t len, bool translate,
663                         SkColorSpace_A2B::PCS pcs) {
664     const size_t minLen = translate ? 48 : 36;
665     if (len < minLen) {
666         SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len);
667         return false;
668     }
669 
670     float encodingFactor;
671     switch (pcs) {
672         case SkColorSpace_A2B::PCS::kLAB:
673             encodingFactor = 1.f;
674             break;
675         case SkColorSpace_A2B::PCS::kXYZ:
676             encodingFactor = 65535 / 32768.f;
677             break;
678         default:
679             encodingFactor = 1.f;
680             SkASSERT(false);
681             break;
682     }
683     float array[16];
684     array[ 0] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src));
685     array[ 1] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 4));
686     array[ 2] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 8));
687 
688     array[ 4] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 12));
689     array[ 5] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 16));
690     array[ 6] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 20));
691 
692     array[ 8] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 24));
693     array[ 9] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 28));
694     array[10] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 32));
695 
696     if (translate) {
697         array[ 3] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 36)); // translate R
698         array[ 7] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 40)); // translate G
699         array[11] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 44)); // translate B
700     } else {
701         array[ 3] = 0.0f;
702         array[ 7] = 0.0f;
703         array[11] = 0.0f;
704     }
705 
706     array[12] = 0.0f;
707     array[13] = 0.0f;
708     array[14] = 0.0f;
709     array[15] = 1.0f;
710     matrix->setRowMajorf(array);
711     SkColorSpacePrintf("A2B0 matrix loaded:\n");
712     for (int r = 0; r < 4; ++r) {
713         SkColorSpacePrintf("|");
714         for (int c = 0; c < 4; ++c) {
715             SkColorSpacePrintf(" %f ", matrix->get(r, c));
716         }
717         SkColorSpacePrintf("|\n");
718     }
719     return true;
720 }
721 
is_named(const sk_sp<SkGammas> & gammas)722 static inline SkGammaNamed is_named(const sk_sp<SkGammas>& gammas) {
723     for (uint8_t i = 0; i < gammas->channels(); ++i) {
724         if (!gammas->isNamed(i) || gammas->data(i).fNamed != gammas->data(0).fNamed) {
725             return kNonStandard_SkGammaNamed;
726         }
727     }
728     return gammas->data(0).fNamed;
729 }
730 
731 /**
732  *  Parse and load an entire stored curve. Handles invalid gammas as well.
733  *
734  *  There's nothing to do for the simple cases, but for table gammas we need to actually
735  *  read the table into heap memory.  And for parametric gammas, we need to copy over the
736  *  parameter values.
737  *
738  *  @param gammaNamed    Out-variable. The named gamma curve.
739  *  @param gammas        Out-variable. The stored gamma curve information. Can be null if
740  *                       gammaNamed is a named curve
741  *  @param inputChannels The number of gamma input channels
742  *  @param rTagPtr       Pointer to start of the gamma tag.
743  *  @param taglen        The size in bytes of the tag
744  *
745  *  @return              false on failure, true on success
746  */
parse_and_load_gamma(SkGammaNamed * gammaNamed,sk_sp<SkGammas> * gammas,uint8_t inputChannels,const uint8_t * tagSrc,size_t tagLen)747 static bool parse_and_load_gamma(SkGammaNamed* gammaNamed, sk_sp<SkGammas>* gammas,
748                                  uint8_t inputChannels, const uint8_t* tagSrc, size_t tagLen) {
749     SkGammas::Data data[kMaxColorChannels];
750     SkColorSpaceTransferFn params[kMaxColorChannels];
751     SkGammas::Type type[kMaxColorChannels];
752     const uint8_t* tagPtr[kMaxColorChannels];
753 
754     tagPtr[0] = tagSrc;
755 
756     *gammaNamed = kNonStandard_SkGammaNamed;
757 
758     // On an invalid first gamma, tagBytes remains set as zero.  This causes the two
759     // subsequent to be treated as identical (which is what we want).
760     size_t tagBytes = 0;
761     type[0] = parse_gamma(&data[0], &params[0], &tagBytes, tagPtr[0], tagLen);
762     handle_invalid_gamma(&type[0], &data[0]);
763     size_t alignedTagBytes = SkAlign4(tagBytes);
764 
765     bool allChannelsSame = false;
766     if (inputChannels * alignedTagBytes <= tagLen) {
767         allChannelsSame = true;
768         for (uint8_t i = 1; i < inputChannels; ++i) {
769             if (0 != memcmp(tagSrc, tagSrc + i * alignedTagBytes, tagBytes)) {
770                 allChannelsSame = false;
771                 break;
772             }
773         }
774     }
775     if (allChannelsSame) {
776         if (SkGammas::Type::kNamed_Type == type[0]) {
777             *gammaNamed = data[0].fNamed;
778         } else {
779             size_t allocSize = sizeof(SkGammas);
780             return_if_false(safe_add(allocSize, gamma_alloc_size(type[0], data[0]), &allocSize),
781                             "SkGammas struct is too large to allocate");
782             void* memory = sk_malloc_throw(allocSize);
783             *gammas = sk_sp<SkGammas>(new (memory) SkGammas(inputChannels));
784             load_gammas(memory, 0, type[0], &data[0], params[0], tagPtr[0]);
785 
786             for (uint8_t channel = 0; channel < inputChannels; ++channel) {
787                 (*gammas)->fType[channel] = type[0];
788                 (*gammas)->fData[channel] = data[0];
789             }
790         }
791     } else {
792         for (uint8_t channel = 1; channel < inputChannels; ++channel) {
793             tagPtr[channel] = tagPtr[channel - 1] + alignedTagBytes;
794             tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
795             tagBytes = 0;
796             type[channel] = parse_gamma(&data[channel], &params[channel], &tagBytes,
797                                         tagPtr[channel], tagLen);
798             handle_invalid_gamma(&type[channel], &data[channel]);
799             alignedTagBytes = SkAlign4(tagBytes);
800         }
801 
802         size_t allocSize = sizeof(SkGammas);
803         for (uint8_t channel = 0; channel < inputChannels; ++channel) {
804             return_if_false(safe_add(allocSize, gamma_alloc_size(type[channel], data[channel]),
805                                      &allocSize),
806                             "SkGammas struct is too large to allocate");
807         }
808         void* memory = sk_malloc_throw(allocSize);
809         *gammas = sk_sp<SkGammas>(new (memory) SkGammas(inputChannels));
810 
811         uint32_t offset = 0;
812         for (uint8_t channel = 0; channel < inputChannels; ++channel) {
813             (*gammas)->fType[channel] = type[channel];
814             offset += load_gammas(memory,offset, type[channel], &data[channel], params[channel],
815                                   tagPtr[channel]);
816             (*gammas)->fData[channel] = data[channel];
817 
818         }
819     }
820 
821     if (kNonStandard_SkGammaNamed == *gammaNamed) {
822         *gammaNamed = is_named(*gammas);
823         if (kNonStandard_SkGammaNamed != *gammaNamed) {
824             // No need to keep the gammas struct, the enum is enough.
825             *gammas = nullptr;
826         }
827     }
828     return true;
829 }
830 
is_lut_gamma_linear(const uint8_t * src,size_t count,size_t precision)831 static bool is_lut_gamma_linear(const uint8_t* src, size_t count, size_t precision) {
832     // check for linear gamma (this is very common in lut gammas, as they aren't optional)
833     const float normalizeX = 1.f / (count - 1);
834     for (uint32_t x = 0; x < count; ++x) {
835         const float y = precision == 1 ? (src[x] / 255.f)
836                                        : (read_big_endian_u16(src + 2*x) / 65535.f);
837         if (!color_space_almost_equal(x * normalizeX, y)) {
838             return false;
839         }
840     }
841     return true;
842 }
843 
load_lut_gammas(sk_sp<SkGammas> * gammas,SkGammaNamed * gammaNamed,size_t numTables,size_t entriesPerTable,size_t precision,const uint8_t * src,size_t len)844 static bool load_lut_gammas(sk_sp<SkGammas>* gammas, SkGammaNamed* gammaNamed, size_t numTables,
845                             size_t entriesPerTable, size_t precision, const uint8_t* src,
846                             size_t len) {
847     if (precision != 1 && precision != 2) {
848         SkColorSpacePrintf("Invalid gamma table precision %d\n", precision);
849         return false;
850     }
851     uint32_t totalEntries;
852     return_if_false(safe_mul(entriesPerTable, numTables, &totalEntries),
853                     "Too many entries in gamma table.");
854     uint32_t readBytes;
855     return_if_false(safe_mul(precision, totalEntries, &readBytes),
856                     "SkGammas struct is too large to read");
857     if (len < readBytes) {
858         SkColorSpacePrintf("Gamma table is too small. Provided: %d. Required: %d\n",
859                            len, readBytes);
860         return false;
861     }
862 
863     uint32_t writeBytesPerChannel;
864     return_if_false(safe_mul(sizeof(float), entriesPerTable, &writeBytesPerChannel),
865                     "SkGammas struct is too large to allocate");
866     const size_t readBytesPerChannel = precision * entriesPerTable;
867     size_t numTablesToUse = 1;
868     for (size_t tableIndex = 1; tableIndex < numTables; ++tableIndex) {
869         if (0 != memcmp(src, src + readBytesPerChannel * tableIndex, readBytesPerChannel)) {
870             numTablesToUse = numTables;
871             break;
872         }
873     }
874 
875     if (1 == numTablesToUse) {
876         if (is_lut_gamma_linear(src, entriesPerTable, precision)) {
877             *gammaNamed = kLinear_SkGammaNamed;
878             return true;
879         }
880     }
881     *gammaNamed = kNonStandard_SkGammaNamed;
882 
883     uint32_t writetableBytes;
884     return_if_false(safe_mul(numTablesToUse, writeBytesPerChannel, &writetableBytes),
885                     "SkGammas struct is too large to allocate");
886     size_t allocSize = sizeof(SkGammas);
887     return_if_false(safe_add(allocSize, (size_t)writetableBytes, &allocSize),
888                     "SkGammas struct is too large to allocate");
889 
890     void* memory = sk_malloc_throw(allocSize);
891     *gammas = sk_sp<SkGammas>(new (memory) SkGammas(numTables));
892 
893     for (size_t tableIndex = 0; tableIndex < numTablesToUse; ++tableIndex) {
894         const uint8_t* ptr = src + readBytesPerChannel * tableIndex;
895         const size_t offset = sizeof(SkGammas) + tableIndex * writeBytesPerChannel;
896         float* table = SkTAddOffset<float>(memory, offset);
897         if (1 == precision) {
898             for (uint32_t i = 0; i < entriesPerTable; ++i, ptr += 1) {
899                 table[i] = ((float) *ptr) / 255.0f;
900             }
901         } else if (2 == precision) {
902             for (uint32_t i = 0; i < entriesPerTable; ++i, ptr += 2) {
903                 table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f;
904             }
905         }
906     }
907 
908     SkASSERT(1 == numTablesToUse|| numTables == numTablesToUse);
909 
910     size_t tableOffset = 0;
911     for (size_t tableIndex = 0; tableIndex < numTables; ++tableIndex) {
912         (*gammas)->fType[tableIndex]                = SkGammas::Type::kTable_Type;
913         (*gammas)->fData[tableIndex].fTable.fOffset = tableOffset;
914         (*gammas)->fData[tableIndex].fTable.fSize   = entriesPerTable;
915         if (numTablesToUse > 1) {
916             tableOffset += writeBytesPerChannel;
917         }
918     }
919 
920     return true;
921 }
922 
load_a2b0_a_to_b_type(std::vector<SkColorSpace_A2B::Element> * elements,const uint8_t * src,size_t len,SkColorSpace_A2B::PCS pcs)923 bool load_a2b0_a_to_b_type(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src,
924                            size_t len, SkColorSpace_A2B::PCS pcs) {
925     SkASSERT(len >= 32);
926     // Read the number of channels.  The four bytes (4-7) that we skipped are reserved and
927     // must be zero.
928     const uint8_t inputChannels = src[8];
929     const uint8_t outputChannels = src[9];
930     if (SkColorLookUpTable::kOutputChannels != outputChannels) {
931         // We only handle RGB outputs. The number of output channels must be 3.
932         SkColorSpacePrintf("Output channels (%d) must equal 3 in A to B tag.\n", outputChannels);
933         return false;
934     }
935     if (inputChannels == 0 || inputChannels > 4) {
936         // And we only support 4 input channels.
937         // ICC says up to 16 but our decode can only handle 4.
938         // It could easily be extended to support up to 8, but we only allow CMYK/RGB
939         // input color spaces which are 3 and 4 so let's restrict it to 4 instead of 8.
940         // We can always change this check when we support bigger input spaces.
941         SkColorSpacePrintf("Input channels (%d) must be between 1 and 4 in A to B tag.\n",
942                            inputChannels);
943         return false;
944     }
945 
946 
947     // It is important that these are loaded in the order of application, as the
948     // order you construct an A2B color space's elements is the order it is applied
949 
950     // If the offset is non-zero it indicates that the element is present.
951     const uint32_t offsetToACurves = read_big_endian_i32(src + 28);
952     if (0 != offsetToACurves && offsetToACurves < len) {
953         const size_t tagLen = len - offsetToACurves;
954         SkGammaNamed gammaNamed;
955         sk_sp<SkGammas> gammas;
956         if (!parse_and_load_gamma(&gammaNamed, &gammas, inputChannels, src + offsetToACurves,
957                                   tagLen)) {
958             return false;
959         }
960         if (gammas) {
961             elements->push_back(SkColorSpace_A2B::Element(std::move(gammas)));
962         } else if (kLinear_SkGammaNamed != gammaNamed) {
963             elements->push_back(SkColorSpace_A2B::Element(gammaNamed, inputChannels));
964         }
965     }
966 
967     const uint32_t offsetToColorLUT = read_big_endian_i32(src + 24);
968     if (0 != offsetToColorLUT && offsetToColorLUT < len) {
969         sk_sp<SkColorLookUpTable> colorLUT;
970         const uint8_t* clutSrc = src + offsetToColorLUT;
971         const size_t clutLen = len - offsetToColorLUT;
972         // 16 bytes reserved for grid points, 1 for precision, 3 for padding.
973         // The color LUT data follows after this header.
974         static constexpr uint32_t kColorLUTHeaderSize = 20;
975         if (clutLen < kColorLUTHeaderSize) {
976             SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", clutLen);
977             return false;
978         }
979 
980         SkASSERT(inputChannels <= kMaxColorChannels);
981         uint8_t gridPoints[kMaxColorChannels];
982         for (uint32_t i = 0; i < inputChannels; ++i) {
983             gridPoints[i] = clutSrc[i];
984         }
985         // Space is provided for a maximum of 16 input channels.
986         // Now we determine the precision of the table values.
987         const uint8_t precision = clutSrc[16];
988         if (!load_color_lut(&colorLUT, inputChannels, precision, gridPoints,
989                             clutSrc + kColorLUTHeaderSize, clutLen - kColorLUTHeaderSize)) {
990             SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n");
991             return false;
992         }
993         elements->push_back(SkColorSpace_A2B::Element(std::move(colorLUT)));
994     }
995 
996     const uint32_t offsetToMCurves = read_big_endian_i32(src + 20);
997     if (0 != offsetToMCurves && offsetToMCurves < len) {
998         const size_t tagLen = len - offsetToMCurves;
999         SkGammaNamed gammaNamed;
1000         sk_sp<SkGammas> gammas;
1001         if (!parse_and_load_gamma(&gammaNamed, &gammas, outputChannels, src + offsetToMCurves,
1002                                   tagLen)) {
1003             return false;
1004         }
1005         if (gammas) {
1006             elements->push_back(SkColorSpace_A2B::Element(std::move(gammas)));
1007         } else if (kLinear_SkGammaNamed != gammaNamed) {
1008             elements->push_back(SkColorSpace_A2B::Element(gammaNamed, outputChannels));
1009         }
1010     }
1011 
1012     const uint32_t offsetToMatrix = read_big_endian_i32(src + 16);
1013     if (0 != offsetToMatrix && offsetToMatrix < len) {
1014         SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
1015         if (!load_matrix(&matrix, src + offsetToMatrix, len - offsetToMatrix, true, pcs)) {
1016             SkColorSpacePrintf("Failed to read matrix from A to B tag.\n");
1017         } else if (!matrix.isIdentity()) {
1018             elements->push_back(SkColorSpace_A2B::Element(matrix));
1019         }
1020     }
1021 
1022     const uint32_t offsetToBCurves = read_big_endian_i32(src + 12);
1023     if (0 != offsetToBCurves && offsetToBCurves < len) {
1024         const size_t tagLen = len - offsetToBCurves;
1025         SkGammaNamed gammaNamed;
1026         sk_sp<SkGammas> gammas;
1027         if (!parse_and_load_gamma(&gammaNamed, &gammas, outputChannels, src + offsetToBCurves,
1028                                   tagLen)) {
1029             return false;
1030         }
1031         if (gammas) {
1032             elements->push_back(SkColorSpace_A2B::Element(std::move(gammas)));
1033         } else if (kLinear_SkGammaNamed != gammaNamed) {
1034             elements->push_back(SkColorSpace_A2B::Element(gammaNamed, outputChannels));
1035         }
1036     }
1037 
1038     return true;
1039 }
1040 
load_a2b0_lutn_type(std::vector<SkColorSpace_A2B::Element> * elements,const uint8_t * src,size_t len,SkColorSpace_A2B::PCS pcs)1041 bool load_a2b0_lutn_type(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src,
1042                          size_t len, SkColorSpace_A2B::PCS pcs) {
1043     const uint32_t type = read_big_endian_u32(src);
1044     switch (type) {
1045         case kTAG_lut8Type:
1046             SkASSERT(len >= 48);
1047             break;
1048         case kTAG_lut16Type:
1049             SkASSERT(len >= 52);
1050             break;
1051         default:
1052             SkASSERT(false);
1053             return false;
1054     }
1055     // Read the number of channels.
1056     // The four bytes (4-7) that we skipped are reserved and must be zero.
1057     const uint8_t inputChannels = src[8];
1058     const uint8_t outputChannels = src[9];
1059     if (SkColorLookUpTable::kOutputChannels != outputChannels) {
1060         // We only handle RGB outputs. The number of output channels must be 3.
1061         SkColorSpacePrintf("Output channels (%d) must equal 3 in A to B tag.\n", outputChannels);
1062         return false;
1063     }
1064     if (inputChannels == 0 || inputChannels > 4) {
1065         // And we only support 4 input channels.
1066         // ICC says up to 16 but our decode can only handle 4.
1067         // It could easily be extended to support up to 8, but we only allow CMYK/RGB
1068         // input color spaces which are 3 and 4 so let's restrict it to 4 instead of 8.
1069         // We can always change this check when we support bigger input spaces.
1070         SkColorSpacePrintf("Input channels (%d) must be between 1 and 4 in A to B tag.\n",
1071                            inputChannels);
1072         return false;
1073     }
1074 
1075     const uint8_t clutGridPoints = src[10];
1076     // 11th byte reserved for padding (required to be zero)
1077 
1078     SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
1079     load_matrix(&matrix, &src[12], len - 12, false, pcs);
1080     if (!matrix.isIdentity()) {
1081         // ICC specs (10.8/10.9) say lut8/16Type profiles must have identity matrices
1082         // if the input color space is not PCSXYZ, and we do not support PCSXYZ input color spaces
1083         // so we should never encounter a non-identity matrix here.
1084         // However, 2 test images from the ICC website have RGB input spaces and non-identity
1085         // matrices so we're not going to fail here, despite being against the spec.
1086         SkColorSpacePrintf("Warning: non-Identity matrix found in non-XYZ input color space"
1087                            "lut profile");
1088         elements->push_back(SkColorSpace_A2B::Element(matrix));
1089     }
1090 
1091     size_t dataOffset      = 48;
1092     // # of input table entries
1093     size_t inTableEntries  = 256;
1094     // # of output table entries
1095     size_t outTableEntries = 256;
1096     size_t precision       = 1;
1097     if (kTAG_lut16Type == type) {
1098         dataOffset      = 52;
1099         inTableEntries  = read_big_endian_u16(src + 48);
1100         outTableEntries = read_big_endian_u16(src + 50);
1101         precision       = 2;
1102 
1103         constexpr size_t kMaxLut16GammaEntries = 4096;
1104         if (inTableEntries < 2) {
1105             SkColorSpacePrintf("Too few (%d) input gamma table entries. Must have at least 2.\n",
1106                                inTableEntries);
1107             return false;
1108         } else if (inTableEntries > kMaxLut16GammaEntries) {
1109             SkColorSpacePrintf("Too many (%d) input gamma table entries. Must have at most %d.\n",
1110                                inTableEntries, kMaxLut16GammaEntries);
1111             return false;
1112         }
1113 
1114         if (outTableEntries < 2) {
1115             SkColorSpacePrintf("Too few (%d) output gamma table entries. Must have at least 2.\n",
1116                                outTableEntries);
1117             return false;
1118         } else if (outTableEntries > kMaxLut16GammaEntries) {
1119             SkColorSpacePrintf("Too many (%d) output gamma table entries. Must have at most %d.\n",
1120                                outTableEntries, kMaxLut16GammaEntries);
1121             return false;
1122         }
1123     }
1124 
1125     const size_t inputOffset = dataOffset;
1126     return_if_false(len >= inputOffset, "A2B0 lutnType tag too small for input gamma table");
1127     sk_sp<SkGammas> inputGammas;
1128     SkGammaNamed inputGammaNamed;
1129     if (!load_lut_gammas(&inputGammas, &inputGammaNamed, inputChannels, inTableEntries, precision,
1130                          src + inputOffset, len - inputOffset)) {
1131         SkColorSpacePrintf("Failed to read input gammas from lutnType tag.\n");
1132         return false;
1133     }
1134     SkASSERT(inputGammas || inputGammaNamed != kNonStandard_SkGammaNamed);
1135     if (kLinear_SkGammaNamed != inputGammaNamed) {
1136         if (kNonStandard_SkGammaNamed != inputGammaNamed) {
1137             elements->push_back(SkColorSpace_A2B::Element(inputGammaNamed, inputChannels));
1138         } else {
1139             elements->push_back(SkColorSpace_A2B::Element(std::move(inputGammas)));
1140         }
1141     }
1142 
1143     const size_t clutOffset = inputOffset + precision*inTableEntries*inputChannels;
1144     return_if_false(len >= clutOffset, "A2B0 lutnType tag too small for CLUT");
1145     sk_sp<SkColorLookUpTable> colorLUT;
1146     const uint8_t gridPoints[kMaxColorChannels] = {
1147         clutGridPoints, clutGridPoints, clutGridPoints, clutGridPoints
1148     };
1149     if (!load_color_lut(&colorLUT, inputChannels, precision, gridPoints, src + clutOffset,
1150                         len - clutOffset)) {
1151         SkColorSpacePrintf("Failed to read color LUT from lutnType tag.\n");
1152         return false;
1153     }
1154     SkASSERT(colorLUT);
1155     elements->push_back(SkColorSpace_A2B::Element(std::move(colorLUT)));
1156 
1157     size_t clutSize = precision * outputChannels;
1158     for (int i = 0; i < inputChannels; ++i) {
1159         clutSize *= clutGridPoints;
1160     }
1161     const size_t outputOffset = clutOffset + clutSize;
1162     return_if_false(len >= outputOffset, "A2B0 lutnType tag too small for output gamma table");
1163     sk_sp<SkGammas> outputGammas;
1164     SkGammaNamed outputGammaNamed;
1165     if (!load_lut_gammas(&outputGammas, &outputGammaNamed, outputChannels, outTableEntries,
1166                          precision, src + outputOffset, len - outputOffset)) {
1167         SkColorSpacePrintf("Failed to read output gammas from lutnType tag.\n");
1168         return false;
1169     }
1170     SkASSERT(outputGammas || outputGammaNamed != kNonStandard_SkGammaNamed);
1171     if (kLinear_SkGammaNamed != outputGammaNamed) {
1172         if (kNonStandard_SkGammaNamed != outputGammaNamed) {
1173             elements->push_back(SkColorSpace_A2B::Element(outputGammaNamed, outputChannels));
1174         } else {
1175             elements->push_back(SkColorSpace_A2B::Element(std::move(outputGammas)));
1176         }
1177     }
1178 
1179     return true;
1180 }
1181 
icf_channels(SkColorSpace::Type iccType)1182 static inline int icf_channels(SkColorSpace::Type iccType) {
1183     switch (iccType) {
1184         case SkColorSpace::kRGB_Type:
1185             return 3;
1186         case SkColorSpace::kCMYK_Type:
1187             return 4;
1188         default:
1189             SkASSERT(false);
1190             return 0;
1191     }
1192 }
1193 
load_a2b0(std::vector<SkColorSpace_A2B::Element> * elements,const uint8_t * src,size_t len,SkColorSpace_A2B::PCS pcs,SkColorSpace::Type iccType)1194 static bool load_a2b0(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src,
1195                       size_t len, SkColorSpace_A2B::PCS pcs,
1196                       SkColorSpace::Type iccType) {
1197     if (len < 4) {
1198         return false;
1199     }
1200     const uint32_t type = read_big_endian_u32(src);
1201 
1202     switch (type) {
1203         case kTAG_AtoBType:
1204             if (len < 32) {
1205                 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len);
1206                 return false;
1207             }
1208             SkColorSpacePrintf("A2B0 tag is of type lutAtoBType\n");
1209             if (!load_a2b0_a_to_b_type(elements, src, len, pcs)) {
1210                 return false;
1211             }
1212             break;
1213         case kTAG_lut8Type:
1214             if (len < 48) {
1215                 SkColorSpacePrintf("lut8 tag is too small (%d bytes).", len);
1216                 return false;
1217             }
1218             SkColorSpacePrintf("A2B0 tag of type lut8Type\n");
1219             if (!load_a2b0_lutn_type(elements, src, len, pcs)) {
1220                 return false;
1221             }
1222             break;
1223         case kTAG_lut16Type:
1224             if (len < 52) {
1225                 SkColorSpacePrintf("lut16 tag is too small (%d bytes).", len);
1226                 return false;
1227             }
1228             SkColorSpacePrintf("A2B0 tag of type lut16Type\n");
1229             if (!load_a2b0_lutn_type(elements, src, len, pcs)) {
1230                 return false;
1231             }
1232             break;
1233         default:
1234             SkColorSpacePrintf("Unsupported A to B tag type: %c%c%c%c\n", (type>>24)&0xFF,
1235                                (type>>16)&0xFF, (type>>8)&0xFF, type&0xFF);
1236             return false;
1237     }
1238     SkASSERT(SkColorSpace_A2B::PCS::kLAB == pcs || SkColorSpace_A2B::PCS::kXYZ == pcs);
1239     static constexpr int kPCSChannels = 3; // must be PCSLAB or PCSXYZ
1240     if (elements->empty()) {
1241         return kPCSChannels == icf_channels(iccType);
1242     }
1243     // now let's verify that the input/output channels of each A2B element actually match up
1244     if (icf_channels(iccType) != elements->front().inputChannels()) {
1245         SkColorSpacePrintf("Input channel count does not match first A2B element's input count");
1246         return false;
1247     }
1248     for (size_t i = 1; i < elements->size(); ++i) {
1249         if ((*elements)[i - 1].outputChannels() != (*elements)[i].inputChannels()) {
1250             SkColorSpacePrintf("A2B elements don't agree in input/output channel counts");
1251             return false;
1252         }
1253     }
1254     if (kPCSChannels != elements->back().outputChannels()) {
1255         SkColorSpacePrintf("PCS channel count doesn't match last A2B element's output count");
1256         return false;
1257     }
1258     return true;
1259 }
1260 
tag_equals(const ICCTag * a,const ICCTag * b,const uint8_t * base)1261 static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) {
1262     if (!a || !b) {
1263         return a == b;
1264     }
1265 
1266     if (a->fLength != b->fLength) {
1267         return false;
1268     }
1269 
1270     if (a->fOffset == b->fOffset) {
1271         return true;
1272     }
1273 
1274     return !memcmp(a->addr(base), b->addr(base), a->fLength);
1275 }
1276 
is_close_to_d50(const SkMatrix44 & matrix)1277 static inline bool is_close_to_d50(const SkMatrix44& matrix) {
1278     // rX + gX + bX
1279     float X = matrix.getFloat(0, 0) + matrix.getFloat(0, 1) + matrix.getFloat(0, 2);
1280 
1281     // rY + gY + bY
1282     float Y = matrix.getFloat(1, 0) + matrix.getFloat(1, 1) + matrix.getFloat(1, 2);
1283 
1284     // rZ + gZ + bZ
1285     float Z = matrix.getFloat(2, 0) + matrix.getFloat(2, 1) + matrix.getFloat(2, 2);
1286 
1287     static const float kD50_WhitePoint[3] = { 0.96420f, 1.00000f, 0.82491f };
1288 
1289     // This is a bit more lenient than QCMS and Adobe.  Is there a reason to be stricter here?
1290     return (SkTAbs(X - kD50_WhitePoint[0]) <= 0.04f) &&
1291            (SkTAbs(Y - kD50_WhitePoint[1]) <= 0.04f) &&
1292            (SkTAbs(Z - kD50_WhitePoint[2]) <= 0.04f);
1293 }
1294 
make_xyz(const ICCProfileHeader & header,ICCTag * tags,int tagCount,const uint8_t * base,sk_sp<SkData> profileData)1295 static sk_sp<SkColorSpace> make_xyz(const ICCProfileHeader& header, ICCTag* tags, int tagCount,
1296                                     const uint8_t* base, sk_sp<SkData> profileData) {
1297     if (kLAB_PCSSpace == header.fPCS) {
1298         return nullptr;
1299     }
1300 
1301     // Recognize the rXYZ, gXYZ, and bXYZ tags.
1302     const ICCTag* r = ICCTag::Find(tags, tagCount, kTAG_rXYZ);
1303     const ICCTag* g = ICCTag::Find(tags, tagCount, kTAG_gXYZ);
1304     const ICCTag* b = ICCTag::Find(tags, tagCount, kTAG_bXYZ);
1305     if (!r || !g || !b) {
1306         return nullptr;
1307     }
1308 
1309     float toXYZ[9];
1310     if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) ||
1311         !load_xyz(&toXYZ[3], g->addr(base), g->fLength) ||
1312         !load_xyz(&toXYZ[6], b->addr(base), b->fLength))
1313     {
1314         return_null("Need valid rgb tags for XYZ space");
1315     }
1316     SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor);
1317     mat.set3x3(toXYZ[0], toXYZ[1], toXYZ[2],
1318                toXYZ[3], toXYZ[4], toXYZ[5],
1319                toXYZ[6], toXYZ[7], toXYZ[8]);
1320     if (!is_close_to_d50(mat)) {
1321         return_null("XYZ matrix is not D50");
1322     }
1323 
1324     // If some, but not all, of the gamma tags are missing, assume that all
1325     // gammas are meant to be the same.
1326     r = ICCTag::Find(tags, tagCount, kTAG_rTRC);
1327     g = ICCTag::Find(tags, tagCount, kTAG_gTRC);
1328     b = ICCTag::Find(tags, tagCount, kTAG_bTRC);
1329     if ((!r || !g || !b)) {
1330         if (!r) {
1331             r = g ? g : b;
1332         }
1333         if (!g) {
1334             g = r ? r : b;
1335         }
1336         if (!b) {
1337             b = r ? r : g;
1338         }
1339     }
1340 
1341     SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed;
1342     sk_sp<SkGammas> gammas = nullptr;
1343     size_t tagBytes;
1344     if (r && g && b) {
1345         if (tag_equals(r, g, base) && tag_equals(g, b, base)) {
1346             SkGammas::Data data;
1347             SkColorSpaceTransferFn params;
1348             SkGammas::Type type =
1349                     parse_gamma(&data, &params, &tagBytes, r->addr(base), r->fLength);
1350             handle_invalid_gamma(&type, &data);
1351 
1352             if (SkGammas::Type::kNamed_Type == type) {
1353                 gammaNamed = data.fNamed;
1354             } else {
1355                 size_t allocSize = sizeof(SkGammas);
1356                 if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) {
1357                     return_null("SkGammas struct is too large to allocate");
1358                 }
1359                 void* memory = sk_malloc_throw(allocSize);
1360                 gammas = sk_sp<SkGammas>(new (memory) SkGammas(3));
1361                 load_gammas(memory, 0, type, &data, params, r->addr(base));
1362 
1363                 for (int i = 0; i < 3; ++i) {
1364                     gammas->fType[i] = type;
1365                     gammas->fData[i] = data;
1366                 }
1367             }
1368         } else {
1369             SkGammas::Data rData;
1370             SkColorSpaceTransferFn rParams;
1371             SkGammas::Type rType =
1372                     parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength);
1373             handle_invalid_gamma(&rType, &rData);
1374 
1375             SkGammas::Data gData;
1376             SkColorSpaceTransferFn gParams;
1377             SkGammas::Type gType =
1378                     parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength);
1379             handle_invalid_gamma(&gType, &gData);
1380 
1381             SkGammas::Data bData;
1382             SkColorSpaceTransferFn bParams;
1383             SkGammas::Type bType =
1384                     parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength);
1385             handle_invalid_gamma(&bType, &bData);
1386 
1387             size_t allocSize = sizeof(SkGammas);
1388             if (!safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize) ||
1389                 !safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize) ||
1390                 !safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize)) {
1391                 return_null("SkGammas struct is too large to allocate");
1392             }
1393             void* memory = sk_malloc_throw(allocSize);
1394             gammas = sk_sp<SkGammas>(new (memory) SkGammas(3));
1395 
1396             uint32_t offset = 0;
1397             gammas->fType[0] = rType;
1398             offset += load_gammas(memory, offset, rType, &rData, rParams,
1399                                   r->addr(base));
1400 
1401             gammas->fType[1] = gType;
1402             offset += load_gammas(memory, offset, gType, &gData, gParams,
1403                                   g->addr(base));
1404 
1405             gammas->fType[2] = bType;
1406             load_gammas(memory, offset, bType, &bData, bParams, b->addr(base));
1407 
1408             gammas->fData[0] = rData;
1409             gammas->fData[1] = gData;
1410             gammas->fData[2] = bData;
1411         }
1412     } else {
1413         // Guess sRGB if the profile is missing transfer functions.
1414         gammaNamed = kSRGB_SkGammaNamed;
1415     }
1416 
1417     if (kNonStandard_SkGammaNamed == gammaNamed) {
1418         // It's possible that we'll initially detect non-matching gammas, only for
1419         // them to evaluate to the same named gamma curve.
1420         gammaNamed = is_named(gammas);
1421     }
1422 
1423     if (kNonStandard_SkGammaNamed == gammaNamed) {
1424         return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(gammaNamed,
1425                                                         std::move(gammas),
1426                                                         mat, std::move(profileData)));
1427     }
1428 
1429     return SkColorSpace::MakeRGB(gammaNamed, mat);
1430 }
1431 
make_gray(const ICCProfileHeader & header,ICCTag * tags,int tagCount,const uint8_t * base,sk_sp<SkData> profileData)1432 static sk_sp<SkColorSpace> make_gray(const ICCProfileHeader& header, ICCTag* tags, int tagCount,
1433                                      const uint8_t* base, sk_sp<SkData> profileData) {
1434     if (kLAB_PCSSpace == header.fPCS) {
1435         return nullptr;
1436     }
1437 
1438     const ICCTag* grayTRC = ICCTag::Find(tags, tagCount, kTAG_kTRC);
1439     if (!grayTRC) {
1440         return_null("grayTRC tag required for monochrome profiles.");
1441     }
1442     SkGammas::Data data;
1443     SkColorSpaceTransferFn params;
1444     size_t tagBytes;
1445     SkGammas::Type type =
1446             parse_gamma(&data, &params, &tagBytes, grayTRC->addr(base), grayTRC->fLength);
1447     handle_invalid_gamma(&type, &data);
1448 
1449     SkMatrix44 toXYZD50(SkMatrix44::kIdentity_Constructor);
1450     toXYZD50.setFloat(0, 0, kWhitePointD50[0]);
1451     toXYZD50.setFloat(1, 1, kWhitePointD50[1]);
1452     toXYZD50.setFloat(2, 2, kWhitePointD50[2]);
1453     if (SkGammas::Type::kNamed_Type == type) {
1454         return SkColorSpace::MakeRGB(data.fNamed, toXYZD50);
1455     }
1456 
1457     size_t allocSize = sizeof(SkGammas);
1458     if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) {
1459         return_null("SkGammas struct is too large to allocate");
1460     }
1461     void* memory = sk_malloc_throw(allocSize);
1462     sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(3));
1463     load_gammas(memory, 0, type, &data, params, grayTRC->addr(base));
1464     for (int i = 0; i < 3; ++i) {
1465         gammas->fType[i] = type;
1466         gammas->fData[i] = data;
1467     }
1468 
1469     return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(kNonStandard_SkGammaNamed,
1470                                                     std::move(gammas),
1471                                                     toXYZD50, std::move(profileData)));
1472 }
1473 
make_a2b(SkColorSpace::Type iccType,const ICCProfileHeader & header,ICCTag * tags,int tagCount,const uint8_t * base,sk_sp<SkData> profileData)1474 static sk_sp<SkColorSpace> make_a2b(SkColorSpace::Type iccType,
1475                                     const ICCProfileHeader& header, ICCTag* tags, int tagCount,
1476                                     const uint8_t* base, sk_sp<SkData> profileData) {
1477     const ICCTag* a2b0 = ICCTag::Find(tags, tagCount, kTAG_A2B0);
1478     if (a2b0) {
1479         const SkColorSpace_A2B::PCS pcs = kXYZ_PCSSpace == header.fPCS
1480                                         ? SkColorSpace_A2B::PCS::kXYZ
1481                                         : SkColorSpace_A2B::PCS::kLAB;
1482         std::vector<SkColorSpace_A2B::Element> elements;
1483         if (load_a2b0(&elements, a2b0->addr(base), a2b0->fLength, pcs, iccType)) {
1484             return sk_sp<SkColorSpace>(new SkColorSpace_A2B(iccType, std::move(elements),
1485                                                             pcs, std::move(profileData)));
1486         }
1487     }
1488 
1489     return nullptr;
1490 }
1491 
MakeICC(const void * input,size_t len)1492 sk_sp<SkColorSpace> SkColorSpace::MakeICC(const void* input, size_t len) {
1493     if (!input || len < kICCHeaderSize) {
1494         return_null("Data is null or not large enough to contain an ICC profile");
1495     }
1496 
1497     // Create our own copy of the input.
1498     void* memory = sk_malloc_throw(len);
1499     memcpy(memory, input, len);
1500     sk_sp<SkData> profileData = SkData::MakeFromMalloc(memory, len);
1501     const uint8_t* base = profileData->bytes();
1502     const uint8_t* ptr = base;
1503 
1504     // Read the ICC profile header and check to make sure that it is valid.
1505     ICCProfileHeader header;
1506     header.init(ptr, len);
1507     if (!header.valid()) {
1508         return nullptr;
1509     }
1510 
1511     // Adjust ptr and len before reading the tags.
1512     if (len < header.fSize) {
1513         SkColorSpacePrintf("ICC profile might be truncated.\n");
1514     } else if (len > header.fSize) {
1515         SkColorSpacePrintf("Caller provided extra data beyond the end of the ICC profile.\n");
1516         len = header.fSize;
1517     }
1518     ptr += kICCHeaderSize;
1519     len -= kICCHeaderSize;
1520 
1521     // Parse tag headers.
1522     uint32_t tagCount = header.fTagCount;
1523     SkColorSpacePrintf("ICC profile contains %d tags.\n", tagCount);
1524     if (len < kICCTagTableEntrySize * tagCount) {
1525         return_null("Not enough input data to read tag table entries");
1526     }
1527 
1528     SkAutoTArray<ICCTag> tags(tagCount);
1529     for (uint32_t i = 0; i < tagCount; i++) {
1530         ptr = tags[i].init(ptr);
1531         SkColorSpacePrintf("[%d] %c%c%c%c %d %d\n", i, (tags[i].fSignature >> 24) & 0xFF,
1532                 (tags[i].fSignature >> 16) & 0xFF, (tags[i].fSignature >>  8) & 0xFF,
1533                 (tags[i].fSignature >>  0) & 0xFF, tags[i].fOffset, tags[i].fLength);
1534 
1535         if (!tags[i].valid(kICCHeaderSize + len)) {
1536             return_null("Tag is too large to fit in ICC profile");
1537         }
1538     }
1539 
1540     Type a2b_type = kRGB_Type;
1541     switch (header.fInputColorSpace) {
1542         case kRGB_ColorSpace: {
1543             sk_sp<SkColorSpace> colorSpace =
1544                     make_xyz(header, tags.get(), tagCount, base, profileData);
1545             if (colorSpace) {
1546                 return colorSpace;
1547             }
1548             break;
1549         }
1550         case kGray_ColorSpace: {
1551             return make_gray(header, tags.get(), tagCount, base, profileData);
1552         }
1553         case kCMYK_ColorSpace:
1554             a2b_type = kCMYK_Type;
1555             break;
1556         default:
1557             return_null("ICC profile contains unsupported colorspace");
1558     }
1559 
1560     return make_a2b(a2b_type, header, tags.get(), tagCount, base, profileData);
1561 }
1562