1bb9f77437dad6a127840e6898edb3f811e3e9e94msarett/*
2bb9f77437dad6a127840e6898edb3f811e3e9e94msarett * Copyright 2016 Google Inc.
3bb9f77437dad6a127840e6898edb3f811e3e9e94msarett *
4bb9f77437dad6a127840e6898edb3f811e3e9e94msarett * Use of this source code is governed by a BSD-style license that can be
5bb9f77437dad6a127840e6898edb3f811e3e9e94msarett * found in the LICENSE file.
6bb9f77437dad6a127840e6898edb3f811e3e9e94msarett */
7bb9f77437dad6a127840e6898edb3f811e3e9e94msarett
88cc209111876b7c78b5ec577c9221d8ed5e21024msarett#ifndef SkColorSpace_Base_DEFINED
98cc209111876b7c78b5ec577c9221d8ed5e21024msarett#define SkColorSpace_Base_DEFINED
108cc209111876b7c78b5ec577c9221d8ed5e21024msarett
112563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorLookUpTable.h"
128cc209111876b7c78b5ec577c9221d8ed5e21024msarett#include "SkColorSpace.h"
13ab926f0a1bca1c6e17520803d964a0344b4f79b4msarett#include "SkData.h"
14971cd496b9e25f87f3a75a0015c203322907136abrianosman#include "SkOnce.h"
15e077e0683a6fe79f71f3e3762edb259941431adamsarett#include "SkTemplates.h"
16bb9f77437dad6a127840e6898edb3f811e3e9e94msarett
17600c737b64eae2c7379442ae2c852853cce3a278msarettenum SkGammaNamed : uint8_t {
18600c737b64eae2c7379442ae2c852853cce3a278msarett    kLinear_SkGammaNamed,
19600c737b64eae2c7379442ae2c852853cce3a278msarett    kSRGB_SkGammaNamed,
20600c737b64eae2c7379442ae2c852853cce3a278msarett    k2Dot2Curve_SkGammaNamed,
21600c737b64eae2c7379442ae2c852853cce3a278msarett    kNonStandard_SkGammaNamed,
22600c737b64eae2c7379442ae2c852853cce3a278msarett};
23600c737b64eae2c7379442ae2c852853cce3a278msarett
241b93bd1e6eba3d14593490e4e24a34546638c8damsarettstruct SkGammas : SkRefCnt {
251b93bd1e6eba3d14593490e4e24a34546638c8damsarett
261b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // There are four possible representations for gamma curves.  kNone_Type is used
271b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // as a placeholder until the struct is initialized.  It is not a valid value.
281b93bd1e6eba3d14593490e4e24a34546638c8damsarett    enum class Type : uint8_t {
291b93bd1e6eba3d14593490e4e24a34546638c8damsarett        kNone_Type,
301b93bd1e6eba3d14593490e4e24a34546638c8damsarett        kNamed_Type,
311b93bd1e6eba3d14593490e4e24a34546638c8damsarett        kValue_Type,
321b93bd1e6eba3d14593490e4e24a34546638c8damsarett        kTable_Type,
331b93bd1e6eba3d14593490e4e24a34546638c8damsarett        kParam_Type,
341b93bd1e6eba3d14593490e4e24a34546638c8damsarett    };
351b93bd1e6eba3d14593490e4e24a34546638c8damsarett
361b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // Contains information for a gamma table.
371b93bd1e6eba3d14593490e4e24a34546638c8damsarett    struct Table {
381b93bd1e6eba3d14593490e4e24a34546638c8damsarett        size_t fOffset;
391b93bd1e6eba3d14593490e4e24a34546638c8damsarett        int    fSize;
401b93bd1e6eba3d14593490e4e24a34546638c8damsarett
411b93bd1e6eba3d14593490e4e24a34546638c8damsarett        const float* table(const SkGammas* base) const {
421b93bd1e6eba3d14593490e4e24a34546638c8damsarett            return SkTAddOffset<const float>(base, sizeof(SkGammas) + fOffset);
431b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
441b93bd1e6eba3d14593490e4e24a34546638c8damsarett    };
451b93bd1e6eba3d14593490e4e24a34546638c8damsarett
461b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // Contains the actual gamma curve information.  Should be interpreted
471b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // based on the type of the gamma curve.
481b93bd1e6eba3d14593490e4e24a34546638c8damsarett    union Data {
491b93bd1e6eba3d14593490e4e24a34546638c8damsarett        Data()
501b93bd1e6eba3d14593490e4e24a34546638c8damsarett            : fTable{ 0, 0 }
511b93bd1e6eba3d14593490e4e24a34546638c8damsarett        {}
521b93bd1e6eba3d14593490e4e24a34546638c8damsarett
531b93bd1e6eba3d14593490e4e24a34546638c8damsarett        inline bool operator==(const Data& that) const {
541b93bd1e6eba3d14593490e4e24a34546638c8damsarett            return this->fTable.fOffset == that.fTable.fOffset &&
551b93bd1e6eba3d14593490e4e24a34546638c8damsarett                   this->fTable.fSize == that.fTable.fSize;
561b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
57c4ce6b592487305de251bbebaf8eeee38371b877msarett
58113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry        inline bool operator!=(const Data& that) const {
59113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return !(*this == that);
60113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry        }
61113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
62600c737b64eae2c7379442ae2c852853cce3a278msarett        SkGammaNamed             fNamed;
631b93bd1e6eba3d14593490e4e24a34546638c8damsarett        float                    fValue;
641b93bd1e6eba3d14593490e4e24a34546638c8damsarett        Table                    fTable;
651b93bd1e6eba3d14593490e4e24a34546638c8damsarett        size_t                   fParamOffset;
662aec3ffe32558505d7314f064b88ecb7f13b1c16msarett
67df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett        const SkColorSpaceTransferFn& params(const SkGammas* base) const {
68df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett            return *SkTAddOffset<const SkColorSpaceTransferFn>(
69df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett                    base, sizeof(SkGammas) + fParamOffset);
701b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
711b93bd1e6eba3d14593490e4e24a34546638c8damsarett    };
722aec3ffe32558505d7314f064b88ecb7f13b1c16msarett
731b93bd1e6eba3d14593490e4e24a34546638c8damsarett    bool isNamed(int i) const {
74a714bc39294f19500269c8ec536139f75c4b1f25msarett        return Type::kNamed_Type == this->type(i);
75dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
76dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
771b93bd1e6eba3d14593490e4e24a34546638c8damsarett    bool isValue(int i) const {
78a714bc39294f19500269c8ec536139f75c4b1f25msarett        return Type::kValue_Type == this->type(i);
792ea944c2b710caf29d4795ac953bad14224796f7msarett    }
80456bf30d321292da7f15d1af35fd94fbb6a4bb59msarett
811b93bd1e6eba3d14593490e4e24a34546638c8damsarett    bool isTable(int i) const {
82a714bc39294f19500269c8ec536139f75c4b1f25msarett        return Type::kTable_Type == this->type(i);
831b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
84456bf30d321292da7f15d1af35fd94fbb6a4bb59msarett
851b93bd1e6eba3d14593490e4e24a34546638c8damsarett    bool isParametric(int i) const {
86a714bc39294f19500269c8ec536139f75c4b1f25msarett        return Type::kParam_Type == this->type(i);
87959ccc1f3f49e1ddeb51c32c30ac4a2d94653856msarett    }
882aec3ffe32558505d7314f064b88ecb7f13b1c16msarett
891b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const Data& data(int i) const {
905476128f0a88217414f05e6a7ee518cdb411d026raftias        SkASSERT(i >= 0 && i < fChannels);
915476128f0a88217414f05e6a7ee518cdb411d026raftias        return fData[i];
92959ccc1f3f49e1ddeb51c32c30ac4a2d94653856msarett    }
93264f88aff5c2303339c1dbcad02e12f70c62ae72msarett
941b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const float* table(int i) const {
951b93bd1e6eba3d14593490e4e24a34546638c8damsarett        SkASSERT(isTable(i));
96a714bc39294f19500269c8ec536139f75c4b1f25msarett        return this->data(i).fTable.table(this);
971b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
98456bf30d321292da7f15d1af35fd94fbb6a4bb59msarett
99a97a60c8ecaa5c59334e404750d6299f7b08015draftias    int tableSize(int i) const {
100a97a60c8ecaa5c59334e404750d6299f7b08015draftias        SkASSERT(isTable(i));
101a97a60c8ecaa5c59334e404750d6299f7b08015draftias        return this->data(i).fTable.fSize;
102a97a60c8ecaa5c59334e404750d6299f7b08015draftias    }
103a97a60c8ecaa5c59334e404750d6299f7b08015draftias
104df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett    const SkColorSpaceTransferFn& params(int i) const {
1051b93bd1e6eba3d14593490e4e24a34546638c8damsarett        SkASSERT(isParametric(i));
106a714bc39294f19500269c8ec536139f75c4b1f25msarett        return this->data(i).params(this);
107a714bc39294f19500269c8ec536139f75c4b1f25msarett    }
108a714bc39294f19500269c8ec536139f75c4b1f25msarett
109a714bc39294f19500269c8ec536139f75c4b1f25msarett    Type type(int i) const {
1105476128f0a88217414f05e6a7ee518cdb411d026raftias        SkASSERT(i >= 0 && i < fChannels);
1115476128f0a88217414f05e6a7ee518cdb411d026raftias        return fType[i];
11251c3fcd376c5c9972d9476b5532f6164375a38d1raftias    }
1135476128f0a88217414f05e6a7ee518cdb411d026raftias
1145476128f0a88217414f05e6a7ee518cdb411d026raftias    uint8_t channels() const { return fChannels; }
115456bf30d321292da7f15d1af35fd94fbb6a4bb59msarett
1165476128f0a88217414f05e6a7ee518cdb411d026raftias    SkGammas(uint8_t channels)
1175476128f0a88217414f05e6a7ee518cdb411d026raftias        : fChannels(channels) {
1185476128f0a88217414f05e6a7ee518cdb411d026raftias        SkASSERT(channels <= kMaxColorChannels);
1195476128f0a88217414f05e6a7ee518cdb411d026raftias        for (uint8_t i = 0; i < kMaxColorChannels; ++i) {
1205476128f0a88217414f05e6a7ee518cdb411d026raftias            fType[i] = Type::kNone_Type;
1215476128f0a88217414f05e6a7ee518cdb411d026raftias        }
1225476128f0a88217414f05e6a7ee518cdb411d026raftias    }
12362458a6778bc39eea5360301a67d192b3a263df1Mike Klein
1241b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // These fields should only be modified when initializing the struct.
1255476128f0a88217414f05e6a7ee518cdb411d026raftias    uint8_t fChannels;
1265476128f0a88217414f05e6a7ee518cdb411d026raftias    Data    fData[kMaxColorChannels];
1275476128f0a88217414f05e6a7ee518cdb411d026raftias    Type    fType[kMaxColorChannels];
1281b93bd1e6eba3d14593490e4e24a34546638c8damsarett
1291b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // Objects of this type are sometimes created in a custom fashion using
1301b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // sk_malloc_throw and therefore must be sk_freed.  We overload new to
1311b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // also call sk_malloc_throw so that memory can be unconditionally released
1321b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // using sk_free in an overloaded delete. Overloading regular new means we
1331b93bd1e6eba3d14593490e4e24a34546638c8damsarett    // must also overload placement new.
1341b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void* operator new(size_t size) { return sk_malloc_throw(size); }
1351b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void* operator new(size_t, void* p) { return p; }
1361b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void operator delete(void* p) { sk_free(p); }
137bb9f77437dad6a127840e6898edb3f811e3e9e94msarett};
138bb9f77437dad6a127840e6898edb3f811e3e9e94msarett
1398cc209111876b7c78b5ec577c9221d8ed5e21024msarettclass SkColorSpace_Base : public SkColorSpace {
1408cc209111876b7c78b5ec577c9221d8ed5e21024msarettpublic:
1418cc209111876b7c78b5ec577c9221d8ed5e21024msarett
1429488833428e83c93a7e6002f4d056084fb57112fraftias    /**
1439488833428e83c93a7e6002f4d056084fb57112fraftias     *  Describes color space gamut as a transformation to XYZ D50.
1449488833428e83c93a7e6002f4d056084fb57112fraftias     *  Returns nullptr if color gamut cannot be described in terms of XYZ D50.
1459488833428e83c93a7e6002f4d056084fb57112fraftias     */
1469488833428e83c93a7e6002f4d056084fb57112fraftias    virtual const SkMatrix44* toXYZD50() const = 0;
147f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
1487c602de058c6332dfd92b70a3d05d4a3c401a3aeraftias    /**
149bbf251bf225489a0939fff6df938035a290f4d16Brian Osman     *  Returns a hash of the gamut transofmration to XYZ D50. Allows for fast equality checking
150bbf251bf225489a0939fff6df938035a290f4d16Brian Osman     *  of gamuts, at the (very small) risk of collision.
151bbf251bf225489a0939fff6df938035a290f4d16Brian Osman     *  Returns 0 if color gamut cannot be described in terms of XYZ D50.
152bbf251bf225489a0939fff6df938035a290f4d16Brian Osman     */
153bbf251bf225489a0939fff6df938035a290f4d16Brian Osman    virtual uint32_t toXYZD50Hash() const = 0;
154bbf251bf225489a0939fff6df938035a290f4d16Brian Osman
155bbf251bf225489a0939fff6df938035a290f4d16Brian Osman    /**
1569488833428e83c93a7e6002f4d056084fb57112fraftias     *  Describes color space gamut as a transformation from XYZ D50
1579488833428e83c93a7e6002f4d056084fb57112fraftias     *  Returns nullptr if color gamut cannot be described in terms of XYZ D50.
1587c602de058c6332dfd92b70a3d05d4a3c401a3aeraftias     */
1599488833428e83c93a7e6002f4d056084fb57112fraftias    virtual const SkMatrix44* fromXYZD50() const = 0;
160113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
1619488833428e83c93a7e6002f4d056084fb57112fraftias    virtual bool onGammaCloseToSRGB() const = 0;
162113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
1639488833428e83c93a7e6002f4d056084fb57112fraftias    virtual bool onGammaIsLinear() const = 0;
164113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
165113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    virtual bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const = 0;
166113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
1677f15b682f4e3e0f61a56d3bbdb8163d3a54b997cMatt Sarett    virtual bool onIsCMYK() const { return false; }
1687f15b682f4e3e0f61a56d3bbdb8163d3a54b997cMatt Sarett
16912313f072b3563d652a789e28140f70b48e57e03Brian Osman    /**
17012313f072b3563d652a789e28140f70b48e57e03Brian Osman     *  Returns a color space with the same gamut as this one, but with a linear gamma.
17112313f072b3563d652a789e28140f70b48e57e03Brian Osman     *  For color spaces whose gamut can not be described in terms of XYZ D50, returns
17212313f072b3563d652a789e28140f70b48e57e03Brian Osman     *  linear sRGB.
17312313f072b3563d652a789e28140f70b48e57e03Brian Osman     */
17412313f072b3563d652a789e28140f70b48e57e03Brian Osman    virtual sk_sp<SkColorSpace> makeLinearGamma() = 0;
17512313f072b3563d652a789e28140f70b48e57e03Brian Osman
17612313f072b3563d652a789e28140f70b48e57e03Brian Osman    /**
17712313f072b3563d652a789e28140f70b48e57e03Brian Osman     *  Returns a color space with the same gamut as this one, with with the sRGB transfer
17812313f072b3563d652a789e28140f70b48e57e03Brian Osman     *  function. For color spaces whose gamut can not be described in terms of XYZ D50, returns
17912313f072b3563d652a789e28140f70b48e57e03Brian Osman     *  sRGB.
18012313f072b3563d652a789e28140f70b48e57e03Brian Osman     */
18112313f072b3563d652a789e28140f70b48e57e03Brian Osman    virtual sk_sp<SkColorSpace> makeSRGBGamma() = 0;
18212313f072b3563d652a789e28140f70b48e57e03Brian Osman
1839488833428e83c93a7e6002f4d056084fb57112fraftias    enum class Type : uint8_t {
1849488833428e83c93a7e6002f4d056084fb57112fraftias        kXYZ,
1859488833428e83c93a7e6002f4d056084fb57112fraftias        kA2B
1869488833428e83c93a7e6002f4d056084fb57112fraftias    };
1875476128f0a88217414f05e6a7ee518cdb411d026raftias
1889488833428e83c93a7e6002f4d056084fb57112fraftias    virtual Type type() const = 0;
1895476128f0a88217414f05e6a7ee518cdb411d026raftias
190523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    typedef uint8_t ICCTypeFlag;
191523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    static constexpr ICCTypeFlag kRGB_ICCTypeFlag  = 1 << 0;
192523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    static constexpr ICCTypeFlag kCMYK_ICCTypeFlag = 1 << 1;
193523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    static constexpr ICCTypeFlag kGray_ICCTypeFlag = 1 << 2;
1945476128f0a88217414f05e6a7ee518cdb411d026raftias
195523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    static sk_sp<SkColorSpace> MakeICC(const void* input, size_t len, ICCTypeFlag type);
1965476128f0a88217414f05e6a7ee518cdb411d026raftias
197f3880933092c3226cd7ffd1690fe72c9c0cc376cMatt Sarett    static sk_sp<SkColorSpace> MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50);
198595599f46261225dfc67ab4d91d326e099558239Matt Sarett
19977a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett    enum Named : uint8_t {
20077a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett        kSRGB_Named,
20177a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett        kAdobeRGB_Named,
20277a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett        kSRGBLinear_Named,
2033f405985be5c84a8b4b3e38f24091656aa699b5cBrian Osman        kSRGB_NonLinearBlending_Named,
20477a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett    };
20577a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett
20677a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett    static sk_sp<SkColorSpace> MakeNamed(Named);
20777a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett
2089488833428e83c93a7e6002f4d056084fb57112fraftiasprotected:
209f3880933092c3226cd7ffd1690fe72c9c0cc376cMatt Sarett    SkColorSpace_Base(sk_sp<SkData> profileData);
210971cd496b9e25f87f3a75a0015c203322907136abrianosman
211c213f0df22430dce53a49416c748a08715b62d9cmsarettprivate:
2129488833428e83c93a7e6002f4d056084fb57112fraftias    sk_sp<SkData> fProfileData;
213971cd496b9e25f87f3a75a0015c203322907136abrianosman
2148cc209111876b7c78b5ec577c9221d8ed5e21024msarett    friend class SkColorSpace;
2159488833428e83c93a7e6002f4d056084fb57112fraftias    friend class SkColorSpace_XYZ;
216b39067696ad08a26bbe49b71a71f0546dc42a075msarett    friend class ColorSpaceXformTest;
217c213f0df22430dce53a49416c748a08715b62d9cmsarett    friend class ColorSpaceTest;
2188cc209111876b7c78b5ec577c9221d8ed5e21024msarett    typedef SkColorSpace INHERITED;
2198cc209111876b7c78b5ec577c9221d8ed5e21024msarett};
2208cc209111876b7c78b5ec577c9221d8ed5e21024msarett
2218cc209111876b7c78b5ec577c9221d8ed5e21024msarettstatic inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) {
2228cc209111876b7c78b5ec577c9221d8ed5e21024msarett    return static_cast<SkColorSpace_Base*>(colorSpace);
2238cc209111876b7c78b5ec577c9221d8ed5e21024msarett}
2248cc209111876b7c78b5ec577c9221d8ed5e21024msarett
225ab926f0a1bca1c6e17520803d964a0344b4f79b4msarettstatic inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) {
226ab926f0a1bca1c6e17520803d964a0344b4f79b4msarett    return static_cast<const SkColorSpace_Base*>(colorSpace);
227ab926f0a1bca1c6e17520803d964a0344b4f79b4msarett}
228ab926f0a1bca1c6e17520803d964a0344b4f79b4msarett
229888dc16684da2158702639be2023f998b7c27f66msarettstatic inline SkColorSpace_Base* as_CSB(const sk_sp<SkColorSpace>& colorSpace) {
230888dc16684da2158702639be2023f998b7c27f66msarett    return static_cast<SkColorSpace_Base*>(colorSpace.get());
231888dc16684da2158702639be2023f998b7c27f66msarett}
232888dc16684da2158702639be2023f998b7c27f66msarett
233bb9f77437dad6a127840e6898edb3f811e3e9e94msarett#endif
234