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