blob: 07fa3832530d3357a45350043a5a3b2d41b41d52 [file] [log] [blame]
msarettbb9f7742016-05-17 09:31:20 -07001/*
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
msarett8cc20912016-05-23 09:29:29 -07008#ifndef SkColorSpace_Base_DEFINED
9#define SkColorSpace_Base_DEFINED
10
11#include "SkColorSpace.h"
msarettab926f02016-05-25 08:53:40 -070012#include "SkData.h"
brianosman971cd492016-09-08 10:10:11 -070013#include "SkOnce.h"
msarette077e062016-05-24 10:16:53 -070014#include "SkTemplates.h"
msarettbb9f7742016-05-17 09:31:20 -070015
msarett600c7372016-09-07 12:03:53 -070016enum SkGammaNamed : uint8_t {
17 kLinear_SkGammaNamed,
18 kSRGB_SkGammaNamed,
19 k2Dot2Curve_SkGammaNamed,
20 kNonStandard_SkGammaNamed,
21};
22
msarett1b93bd12016-07-21 07:11:26 -070023struct SkGammas : SkRefCnt {
msarett2aec3ff2016-07-20 12:58:52 -070024
msarett1b93bd12016-07-21 07:11:26 -070025 // There are four possible representations for gamma curves. kNone_Type is used
26 // as a placeholder until the struct is initialized. It is not a valid value.
27 enum class Type : uint8_t {
28 kNone_Type,
29 kNamed_Type,
30 kValue_Type,
31 kTable_Type,
32 kParam_Type,
33 };
msarett2aec3ff2016-07-20 12:58:52 -070034
msarett1b93bd12016-07-21 07:11:26 -070035 // Contains information for a gamma table.
36 struct Table {
37 size_t fOffset;
38 int fSize;
msarett959ccc12016-07-20 15:10:02 -070039
msarett1b93bd12016-07-21 07:11:26 -070040 const float* table(const SkGammas* base) const {
41 return SkTAddOffset<const float>(base, sizeof(SkGammas) + fOffset);
42 }
43 };
msarett959ccc12016-07-20 15:10:02 -070044
msarett1b93bd12016-07-21 07:11:26 -070045 // Contains the parameters for a parametric curve.
46 struct Params {
47 // Y = (aX + b)^g + c for X >= d
48 // Y = eX + f otherwise
49 float fG;
50 float fA;
51 float fB;
52 float fC;
53 float fD;
54 float fE;
55 float fF;
56 };
msarett959ccc12016-07-20 15:10:02 -070057
msarett1b93bd12016-07-21 07:11:26 -070058 // Contains the actual gamma curve information. Should be interpreted
59 // based on the type of the gamma curve.
60 union Data {
61 Data()
62 : fTable{ 0, 0 }
63 {}
msarett959ccc12016-07-20 15:10:02 -070064
msarett1b93bd12016-07-21 07:11:26 -070065 inline bool operator==(const Data& that) const {
66 return this->fTable.fOffset == that.fTable.fOffset &&
67 this->fTable.fSize == that.fTable.fSize;
msarett456bf302016-07-20 16:14:16 -070068 }
69
msarett600c7372016-09-07 12:03:53 -070070 SkGammaNamed fNamed;
msarett1b93bd12016-07-21 07:11:26 -070071 float fValue;
72 Table fTable;
73 size_t fParamOffset;
74
75 const Params& params(const SkGammas* base) const {
76 return *SkTAddOffset<const Params>(base, sizeof(SkGammas) + fParamOffset);
msarett456bf302016-07-20 16:14:16 -070077 }
msarett1b93bd12016-07-21 07:11:26 -070078 };
msarett456bf302016-07-20 16:14:16 -070079
msarett1b93bd12016-07-21 07:11:26 -070080 bool isNamed(int i) const {
msaretta714bc32016-07-29 08:58:33 -070081 return Type::kNamed_Type == this->type(i);
msarett456bf302016-07-20 16:14:16 -070082 }
83
msarett1b93bd12016-07-21 07:11:26 -070084 bool isValue(int i) const {
msaretta714bc32016-07-29 08:58:33 -070085 return Type::kValue_Type == this->type(i);
msarett1b93bd12016-07-21 07:11:26 -070086 }
msarett456bf302016-07-20 16:14:16 -070087
msarett1b93bd12016-07-21 07:11:26 -070088 bool isTable(int i) const {
msaretta714bc32016-07-29 08:58:33 -070089 return Type::kTable_Type == this->type(i);
msarett1b93bd12016-07-21 07:11:26 -070090 }
91
92 bool isParametric(int i) const {
msaretta714bc32016-07-29 08:58:33 -070093 return Type::kParam_Type == this->type(i);
msarett1b93bd12016-07-21 07:11:26 -070094 }
95
96 const Data& data(int i) const {
msaretta714bc32016-07-29 08:58:33 -070097 switch (i) {
98 case 0:
99 return fRedData;
100 case 1:
101 return fGreenData;
102 case 2:
103 return fBlueData;
104 default:
105 SkASSERT(false);
106 return fRedData;
107 }
msarett1b93bd12016-07-21 07:11:26 -0700108 }
109
110 const float* table(int i) const {
111 SkASSERT(isTable(i));
msaretta714bc32016-07-29 08:58:33 -0700112 return this->data(i).fTable.table(this);
msarett1b93bd12016-07-21 07:11:26 -0700113 }
114
115 const Params& params(int i) const {
116 SkASSERT(isParametric(i));
msaretta714bc32016-07-29 08:58:33 -0700117 return this->data(i).params(this);
118 }
119
120 Type type(int i) const {
121 switch (i) {
122 case 0:
123 return fRedType;
124 case 1:
125 return fGreenType;
126 case 2:
127 return fBlueType;
128 default:
129 SkASSERT(false);
130 return fRedType;
131 }
msarett1b93bd12016-07-21 07:11:26 -0700132 }
133
134 SkGammas()
135 : fRedType(Type::kNone_Type)
136 , fGreenType(Type::kNone_Type)
137 , fBlueType(Type::kNone_Type)
msarett456bf302016-07-20 16:14:16 -0700138 {}
139
msarett1b93bd12016-07-21 07:11:26 -0700140 // These fields should only be modified when initializing the struct.
141 Data fRedData;
142 Data fGreenData;
143 Data fBlueData;
144 Type fRedType;
145 Type fGreenType;
146 Type fBlueType;
msarett456bf302016-07-20 16:14:16 -0700147
msarett1b93bd12016-07-21 07:11:26 -0700148 // Objects of this type are sometimes created in a custom fashion using
149 // sk_malloc_throw and therefore must be sk_freed. We overload new to
150 // also call sk_malloc_throw so that memory can be unconditionally released
151 // using sk_free in an overloaded delete. Overloading regular new means we
152 // must also overload placement new.
153 void* operator new(size_t size) { return sk_malloc_throw(size); }
154 void* operator new(size_t, void* p) { return p; }
155 void operator delete(void* p) { sk_free(p); }
msarettbb9f7742016-05-17 09:31:20 -0700156};
157
msarett0f83e012016-06-23 15:12:52 -0700158struct SkColorLookUpTable : public SkRefCnt {
msarett959d45b2016-07-21 13:19:03 -0700159 static constexpr uint8_t kOutputChannels = 3;
msarettbb9f7742016-05-17 09:31:20 -0700160
msarett959d45b2016-07-21 13:19:03 -0700161 uint8_t fInputChannels;
162 uint8_t fGridPoints[3];
163
164 const float* table() const {
165 return SkTAddOffset<const float>(this, sizeof(SkColorLookUpTable));
msarettbb9f7742016-05-17 09:31:20 -0700166 }
msarett959d45b2016-07-21 13:19:03 -0700167
168 SkColorLookUpTable(uint8_t inputChannels, uint8_t gridPoints[3])
169 : fInputChannels(inputChannels)
170 {
171 SkASSERT(3 == inputChannels);
172 memcpy(fGridPoints, gridPoints, 3 * sizeof(uint8_t));
173 }
174
175 // Objects of this type are created in a custom fashion using sk_malloc_throw
176 // and therefore must be sk_freed.
177 void* operator new(size_t size) = delete;
178 void* operator new(size_t, void* p) { return p; }
179 void operator delete(void* p) { sk_free(p); }
msarettbb9f7742016-05-17 09:31:20 -0700180};
181
msarett8cc20912016-05-23 09:29:29 -0700182class SkColorSpace_Base : public SkColorSpace {
183public:
184
msarettd9015a42016-08-22 12:29:31 -0700185 static sk_sp<SkColorSpace> NewRGB(const float gammas[3], const SkMatrix44& toXYZD50);
msarettc4ce6b52016-06-16 07:37:41 -0700186
msarett600c7372016-09-07 12:03:53 -0700187 SkGammaNamed gammaNamed() const { return fGammaNamed; }
msarettb3906762016-06-22 14:07:48 -0700188 const SkGammas* gammas() const { return fGammas.get(); }
msarett8cc20912016-05-23 09:29:29 -0700189
msarettb3906762016-06-22 14:07:48 -0700190 const SkColorLookUpTable* colorLUT() const { return fColorLUT.get(); }
msarettdc27a642016-06-06 12:02:31 -0700191
msarett7802c3d2016-09-28 11:15:27 -0700192 const SkMatrix44& toXYZD50() const { return fToXYZD50; }
brianosman971cd492016-09-08 10:10:11 -0700193 const SkMatrix44& fromXYZD50() const;
194
msarettc213f0d2016-08-01 14:23:32 -0700195private:
196
msarettab926f02016-05-25 08:53:40 -0700197 /**
msarettc213f0d2016-08-01 14:23:32 -0700198 * FIXME (msarett):
199 * Hiding this function until we can determine if we need it. Known issues include:
200 * Only writes 3x3 matrices
201 * Only writes float gammas
202 * Rejected by some parsers because the "profile description" is empty
msarettab926f02016-05-25 08:53:40 -0700203 */
204 sk_sp<SkData> writeToICC() const;
205
msarett600c7372016-09-07 12:03:53 -0700206 static sk_sp<SkColorSpace> NewRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50);
msarettab926f02016-05-25 08:53:40 -0700207
msarett600c7372016-09-07 12:03:53 -0700208 SkColorSpace_Base(SkGammaNamed gammaNamed, const SkMatrix44& toXYZ);
msarett8cc20912016-05-23 09:29:29 -0700209
msarett600c7372016-09-07 12:03:53 -0700210 SkColorSpace_Base(sk_sp<SkColorLookUpTable> colorLUT, SkGammaNamed gammaNamed,
msarett1b93bd12016-07-21 07:11:26 -0700211 sk_sp<SkGammas> gammas, const SkMatrix44& toXYZ, sk_sp<SkData> profileData);
msarett8cc20912016-05-23 09:29:29 -0700212
msarett0f83e012016-06-23 15:12:52 -0700213 sk_sp<SkColorLookUpTable> fColorLUT;
msarett600c7372016-09-07 12:03:53 -0700214 const SkGammaNamed fGammaNamed;
msarett0f83e012016-06-23 15:12:52 -0700215 sk_sp<SkGammas> fGammas;
216 sk_sp<SkData> fProfileData;
msarett8cc20912016-05-23 09:29:29 -0700217
msarett7802c3d2016-09-28 11:15:27 -0700218 const SkMatrix44 fToXYZD50;
brianosman971cd492016-09-08 10:10:11 -0700219 mutable SkMatrix44 fFromXYZD50;
220 mutable SkOnce fFromXYZOnce;
221
msarett8cc20912016-05-23 09:29:29 -0700222 friend class SkColorSpace;
msarettb3906762016-06-22 14:07:48 -0700223 friend class ColorSpaceXformTest;
msarettc213f0d2016-08-01 14:23:32 -0700224 friend class ColorSpaceTest;
msarett8cc20912016-05-23 09:29:29 -0700225 typedef SkColorSpace INHERITED;
226};
227
228static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) {
229 return static_cast<SkColorSpace_Base*>(colorSpace);
230}
231
msarettab926f02016-05-25 08:53:40 -0700232static inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) {
233 return static_cast<const SkColorSpace_Base*>(colorSpace);
234}
235
msarett888dc162016-05-23 10:21:17 -0700236static inline SkColorSpace_Base* as_CSB(const sk_sp<SkColorSpace>& colorSpace) {
237 return static_cast<SkColorSpace_Base*>(colorSpace.get());
238}
239
msarettbb9f7742016-05-17 09:31:20 -0700240#endif