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
tableSkGammas::Table41 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 {
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
params(const SkGammas * base)67 const SkColorSpaceTransferFn& params(const SkGammas* base) const {
68 return *SkTAddOffset<const SkColorSpaceTransferFn>(
69 base, sizeof(SkGammas) + fParamOffset);
70 }
71 };
72
isNamedSkGammas73 bool isNamed(int i) const {
74 return Type::kNamed_Type == this->type(i);
75 }
76
isValueSkGammas77 bool isValue(int i) const {
78 return Type::kValue_Type == this->type(i);
79 }
80
isTableSkGammas81 bool isTable(int i) const {
82 return Type::kTable_Type == this->type(i);
83 }
84
isParametricSkGammas85 bool isParametric(int i) const {
86 return Type::kParam_Type == this->type(i);
87 }
88
dataSkGammas89 const Data& data(int i) const {
90 SkASSERT(i >= 0 && i < fChannels);
91 return fData[i];
92 }
93
tableSkGammas94 const float* table(int i) const {
95 SkASSERT(isTable(i));
96 return this->data(i).fTable.table(this);
97 }
98
tableSizeSkGammas99 int tableSize(int i) const {
100 SkASSERT(isTable(i));
101 return this->data(i).fTable.fSize;
102 }
103
paramsSkGammas104 const SkColorSpaceTransferFn& params(int i) const {
105 SkASSERT(isParametric(i));
106 return this->data(i).params(this);
107 }
108
typeSkGammas109 Type type(int i) const {
110 SkASSERT(i >= 0 && i < fChannels);
111 return fType[i];
112 }
113
channelsSkGammas114 uint8_t channels() const { return fChannels; }
115
SkGammasSkGammas116 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.
newSkGammas134 void* operator new(size_t size) { return sk_malloc_throw(size); }
newSkGammas135 void* operator new(size_t, void* p) { return p; }
deleteSkGammas136 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
onIsCMYK()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() const = 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() const = 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
as_CSB(SkColorSpace * colorSpace)221 static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) {
222 return static_cast<SkColorSpace_Base*>(colorSpace);
223 }
224
as_CSB(const SkColorSpace * colorSpace)225 static inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) {
226 return static_cast<const SkColorSpace_Base*>(colorSpace);
227 }
228
as_CSB(const sk_sp<SkColorSpace> & colorSpace)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