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 #ifndef SkColorSpace_Base_DEFINED 9 #define SkColorSpace_Base_DEFINED 10 11 #include "SkColorLookUpTable.h" 12 #include "SkColorSpace.h" 13 #include "SkData.h" 14 #include "SkOnce.h" 15 #include "SkTemplates.h" 16 17 enum SkGammaNamed : uint8_t { 18 kLinear_SkGammaNamed, 19 kSRGB_SkGammaNamed, 20 k2Dot2Curve_SkGammaNamed, 21 kNonStandard_SkGammaNamed, 22 }; 23 24 struct SkGammas : SkRefCnt { 25 26 // There are four possible representations for gamma curves. kNone_Type is used 27 // as a placeholder until the struct is initialized. It is not a valid value. 28 enum class Type : uint8_t { 29 kNone_Type, 30 kNamed_Type, 31 kValue_Type, 32 kTable_Type, 33 kParam_Type, 34 }; 35 36 // Contains information for a gamma table. 37 struct Table { 38 size_t fOffset; 39 int fSize; 40 41 const float* table(const SkGammas* base) const { 42 return SkTAddOffset<const float>(base, sizeof(SkGammas) + fOffset); 43 } 44 }; 45 46 // Contains the actual gamma curve information. Should be interpreted 47 // based on the type of the gamma curve. 48 union Data { 49 Data() 50 : fTable{ 0, 0 } 51 {} 52 53 inline bool operator==(const Data& that) const { 54 return this->fTable.fOffset == that.fTable.fOffset && 55 this->fTable.fSize == that.fTable.fSize; 56 } 57 58 inline bool operator!=(const Data& that) const { 59 return !(*this == that); 60 } 61 62 SkGammaNamed fNamed; 63 float fValue; 64 Table fTable; 65 size_t fParamOffset; 66 67 const SkColorSpaceTransferFn& params(const SkGammas* base) const { 68 return *SkTAddOffset<const SkColorSpaceTransferFn>( 69 base, sizeof(SkGammas) + fParamOffset); 70 } 71 }; 72 73 bool isNamed(int i) const { 74 return Type::kNamed_Type == this->type(i); 75 } 76 77 bool isValue(int i) const { 78 return Type::kValue_Type == this->type(i); 79 } 80 81 bool isTable(int i) const { 82 return Type::kTable_Type == this->type(i); 83 } 84 85 bool isParametric(int i) const { 86 return Type::kParam_Type == this->type(i); 87 } 88 89 const Data& data(int i) const { 90 SkASSERT(i >= 0 && i < fChannels); 91 return fData[i]; 92 } 93 94 const float* table(int i) const { 95 SkASSERT(isTable(i)); 96 return this->data(i).fTable.table(this); 97 } 98 99 int tableSize(int i) const { 100 SkASSERT(isTable(i)); 101 return this->data(i).fTable.fSize; 102 } 103 104 const SkColorSpaceTransferFn& params(int i) const { 105 SkASSERT(isParametric(i)); 106 return this->data(i).params(this); 107 } 108 109 Type type(int i) const { 110 SkASSERT(i >= 0 && i < fChannels); 111 return fType[i]; 112 } 113 114 uint8_t channels() const { return fChannels; } 115 116 SkGammas(uint8_t channels) 117 : fChannels(channels) { 118 SkASSERT(channels <= kMaxColorChannels); 119 for (uint8_t i = 0; i < kMaxColorChannels; ++i) { 120 fType[i] = Type::kNone_Type; 121 } 122 } 123 124 // These fields should only be modified when initializing the struct. 125 uint8_t fChannels; 126 Data fData[kMaxColorChannels]; 127 Type fType[kMaxColorChannels]; 128 129 // Objects of this type are sometimes created in a custom fashion using 130 // sk_malloc_throw and therefore must be sk_freed. We overload new to 131 // also call sk_malloc_throw so that memory can be unconditionally released 132 // using sk_free in an overloaded delete. Overloading regular new means we 133 // must also overload placement new. 134 void* operator new(size_t size) { return sk_malloc_throw(size); } 135 void* operator new(size_t, void* p) { return p; } 136 void operator delete(void* p) { sk_free(p); } 137 }; 138 139 class SkColorSpace_Base : public SkColorSpace { 140 public: 141 142 /** 143 * Describes color space gamut as a transformation to XYZ D50. 144 * Returns nullptr if color gamut cannot be described in terms of XYZ D50. 145 */ 146 virtual const SkMatrix44* toXYZD50() const = 0; 147 148 /** 149 * Returns a hash of the gamut transofmration to XYZ D50. Allows for fast equality checking 150 * of gamuts, at the (very small) risk of collision. 151 * Returns 0 if color gamut cannot be described in terms of XYZ D50. 152 */ 153 virtual uint32_t toXYZD50Hash() const = 0; 154 155 /** 156 * Describes color space gamut as a transformation from XYZ D50 157 * Returns nullptr if color gamut cannot be described in terms of XYZ D50. 158 */ 159 virtual const SkMatrix44* fromXYZD50() const = 0; 160 161 virtual bool onGammaCloseToSRGB() const = 0; 162 163 virtual bool onGammaIsLinear() const = 0; 164 165 virtual bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const = 0; 166 167 virtual bool onIsCMYK() const { return false; } 168 169 /** 170 * Returns a color space with the same gamut as this one, but with a linear gamma. 171 * For color spaces whose gamut can not be described in terms of XYZ D50, returns 172 * linear sRGB. 173 */ 174 virtual sk_sp<SkColorSpace> makeLinearGamma() = 0; 175 176 /** 177 * Returns a color space with the same gamut as this one, with with the sRGB transfer 178 * function. For color spaces whose gamut can not be described in terms of XYZ D50, returns 179 * sRGB. 180 */ 181 virtual sk_sp<SkColorSpace> makeSRGBGamma() = 0; 182 183 enum class Type : uint8_t { 184 kXYZ, 185 kA2B 186 }; 187 188 virtual Type type() const = 0; 189 190 typedef uint8_t ICCTypeFlag; 191 static constexpr ICCTypeFlag kRGB_ICCTypeFlag = 1 << 0; 192 static constexpr ICCTypeFlag kCMYK_ICCTypeFlag = 1 << 1; 193 static constexpr ICCTypeFlag kGray_ICCTypeFlag = 1 << 2; 194 195 static sk_sp<SkColorSpace> MakeICC(const void* input, size_t len, ICCTypeFlag type); 196 197 static sk_sp<SkColorSpace> MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50); 198 199 enum Named : uint8_t { 200 kSRGB_Named, 201 kAdobeRGB_Named, 202 kSRGBLinear_Named, 203 kSRGB_NonLinearBlending_Named, 204 }; 205 206 static sk_sp<SkColorSpace> MakeNamed(Named); 207 208 protected: 209 SkColorSpace_Base(sk_sp<SkData> profileData); 210 211 private: 212 sk_sp<SkData> fProfileData; 213 214 friend class SkColorSpace; 215 friend class SkColorSpace_XYZ; 216 friend class ColorSpaceXformTest; 217 friend class ColorSpaceTest; 218 typedef SkColorSpace INHERITED; 219 }; 220 221 static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) { 222 return static_cast<SkColorSpace_Base*>(colorSpace); 223 } 224 225 static inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) { 226 return static_cast<const SkColorSpace_Base*>(colorSpace); 227 } 228 229 static inline SkColorSpace_Base* as_CSB(const sk_sp<SkColorSpace>& colorSpace) { 230 return static_cast<SkColorSpace_Base*>(colorSpace.get()); 231 } 232 233 #endif 234