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