blob: 015e95f8a1392e86e7f16a783740ac60bf69ce20 [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
raftias25636012016-11-11 15:27:39 -080011#include "SkColorLookUpTable.h"
msarett8cc20912016-05-23 09:29:29 -070012#include "SkColorSpace.h"
msarettab926f02016-05-25 08:53:40 -070013#include "SkData.h"
brianosman971cd492016-09-08 10:10:11 -070014#include "SkOnce.h"
msarette077e062016-05-24 10:16:53 -070015#include "SkTemplates.h"
msarettbb9f7742016-05-17 09:31:20 -070016
msarett600c7372016-09-07 12:03:53 -070017enum SkGammaNamed : uint8_t {
18 kLinear_SkGammaNamed,
19 kSRGB_SkGammaNamed,
20 k2Dot2Curve_SkGammaNamed,
21 kNonStandard_SkGammaNamed,
22};
23
msarett1b93bd12016-07-21 07:11:26 -070024struct SkGammas : SkRefCnt {
msarett2aec3ff2016-07-20 12:58:52 -070025
msarett1b93bd12016-07-21 07:11:26 -070026 // 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 };
msarett2aec3ff2016-07-20 12:58:52 -070035
msarett1b93bd12016-07-21 07:11:26 -070036 // Contains information for a gamma table.
37 struct Table {
38 size_t fOffset;
39 int fSize;
msarett959ccc12016-07-20 15:10:02 -070040
msarett1b93bd12016-07-21 07:11:26 -070041 const float* table(const SkGammas* base) const {
42 return SkTAddOffset<const float>(base, sizeof(SkGammas) + fOffset);
43 }
44 };
msarett959ccc12016-07-20 15:10:02 -070045
msarett1b93bd12016-07-21 07:11:26 -070046 // 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 {}
msarett959ccc12016-07-20 15:10:02 -070052
msarett1b93bd12016-07-21 07:11:26 -070053 inline bool operator==(const Data& that) const {
54 return this->fTable.fOffset == that.fTable.fOffset &&
55 this->fTable.fSize == that.fTable.fSize;
msarett456bf302016-07-20 16:14:16 -070056 }
57
Ravi Mistry113d05f2016-12-17 01:31:03 +000058 inline bool operator!=(const Data& that) const {
59 return !(*this == that);
60 }
61
msarett600c7372016-09-07 12:03:53 -070062 SkGammaNamed fNamed;
msarett1b93bd12016-07-21 07:11:26 -070063 float fValue;
64 Table fTable;
65 size_t fParamOffset;
66
Matt Sarettdf44fc52016-10-11 16:57:50 -040067 const SkColorSpaceTransferFn& params(const SkGammas* base) const {
68 return *SkTAddOffset<const SkColorSpaceTransferFn>(
69 base, sizeof(SkGammas) + fParamOffset);
msarett456bf302016-07-20 16:14:16 -070070 }
msarett1b93bd12016-07-21 07:11:26 -070071 };
msarett456bf302016-07-20 16:14:16 -070072
msarett1b93bd12016-07-21 07:11:26 -070073 bool isNamed(int i) const {
msaretta714bc32016-07-29 08:58:33 -070074 return Type::kNamed_Type == this->type(i);
msarett456bf302016-07-20 16:14:16 -070075 }
76
msarett1b93bd12016-07-21 07:11:26 -070077 bool isValue(int i) const {
msaretta714bc32016-07-29 08:58:33 -070078 return Type::kValue_Type == this->type(i);
msarett1b93bd12016-07-21 07:11:26 -070079 }
msarett456bf302016-07-20 16:14:16 -070080
msarett1b93bd12016-07-21 07:11:26 -070081 bool isTable(int i) const {
msaretta714bc32016-07-29 08:58:33 -070082 return Type::kTable_Type == this->type(i);
msarett1b93bd12016-07-21 07:11:26 -070083 }
84
85 bool isParametric(int i) const {
msaretta714bc32016-07-29 08:58:33 -070086 return Type::kParam_Type == this->type(i);
msarett1b93bd12016-07-21 07:11:26 -070087 }
88
89 const Data& data(int i) const {
raftias54761282016-12-01 13:44:07 -050090 SkASSERT(i >= 0 && i < fChannels);
91 return fData[i];
msarett1b93bd12016-07-21 07:11:26 -070092 }
93
94 const float* table(int i) const {
95 SkASSERT(isTable(i));
msaretta714bc32016-07-29 08:58:33 -070096 return this->data(i).fTable.table(this);
msarett1b93bd12016-07-21 07:11:26 -070097 }
98
raftiasa97a60c2016-12-16 17:24:30 -050099 int tableSize(int i) const {
100 SkASSERT(isTable(i));
101 return this->data(i).fTable.fSize;
102 }
103
Matt Sarettdf44fc52016-10-11 16:57:50 -0400104 const SkColorSpaceTransferFn& params(int i) const {
msarett1b93bd12016-07-21 07:11:26 -0700105 SkASSERT(isParametric(i));
msaretta714bc32016-07-29 08:58:33 -0700106 return this->data(i).params(this);
107 }
108
109 Type type(int i) const {
raftias54761282016-12-01 13:44:07 -0500110 SkASSERT(i >= 0 && i < fChannels);
111 return fType[i];
112 }
Matt Sarett1fa986c2017-05-01 17:42:20 -0400113
raftias54761282016-12-01 13:44:07 -0500114 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;
msaretta714bc32016-07-29 08:58:33 -0700121 }
msarett1b93bd12016-07-21 07:11:26 -0700122 }
123
msarett1b93bd12016-07-21 07:11:26 -0700124 // These fields should only be modified when initializing the struct.
raftias54761282016-12-01 13:44:07 -0500125 uint8_t fChannels;
126 Data fData[kMaxColorChannels];
127 Type fType[kMaxColorChannels];
msarett456bf302016-07-20 16:14:16 -0700128
msarett1b93bd12016-07-21 07:11:26 -0700129 // 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); }
msarettbb9f7742016-05-17 09:31:20 -0700137};
138
msarett8cc20912016-05-23 09:29:29 -0700139class SkColorSpace_Base : public SkColorSpace {
140public:
Matt Sarettf4898862016-10-16 10:20:41 -0400141
raftias7c602de2016-10-13 10:45:44 -0700142 /**
raftias94888332016-10-18 10:02:51 -0700143 * Describes color space gamut as a transformation to XYZ D50.
144 * Returns nullptr if color gamut cannot be described in terms of XYZ D50.
raftias7c602de2016-10-13 10:45:44 -0700145 */
raftias94888332016-10-18 10:02:51 -0700146 virtual const SkMatrix44* toXYZD50() const = 0;
147
148 /**
Brian Osmanbbf251b2016-10-19 14:56:07 -0400149 * 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 /**
raftias94888332016-10-18 10:02:51 -0700156 * 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;
Ravi Mistry113d05f2016-12-17 01:31:03 +0000160
raftias94888332016-10-18 10:02:51 -0700161 virtual bool onGammaCloseToSRGB() const = 0;
Ravi Mistry113d05f2016-12-17 01:31:03 +0000162
raftias94888332016-10-18 10:02:51 -0700163 virtual bool onGammaIsLinear() const = 0;
Ravi Mistry113d05f2016-12-17 01:31:03 +0000164
165 virtual bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const = 0;
166
Matt Sarett7f15b682017-02-24 17:22:09 -0500167 virtual bool onIsCMYK() const { return false; }
168
Brian Osman12313f02016-11-07 09:42:37 -0500169 /**
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 */
Mike Kleinb1e6cfd2017-06-12 15:20:33 -0400174 virtual sk_sp<SkColorSpace> makeLinearGamma() const = 0;
Brian Osman12313f02016-11-07 09:42:37 -0500175
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 */
Mike Kleinb1e6cfd2017-06-12 15:20:33 -0400181 virtual sk_sp<SkColorSpace> makeSRGBGamma() const = 0;
Brian Osman12313f02016-11-07 09:42:37 -0500182
raftias94888332016-10-18 10:02:51 -0700183 enum class Type : uint8_t {
184 kXYZ,
185 kA2B
186 };
raftias54761282016-12-01 13:44:07 -0500187
raftias94888332016-10-18 10:02:51 -0700188 virtual Type type() const = 0;
raftias54761282016-12-01 13:44:07 -0500189
Matt Sarett523116d2017-01-12 18:36:38 -0500190 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;
raftias54761282016-12-01 13:44:07 -0500194
Matt Sarett523116d2017-01-12 18:36:38 -0500195 static sk_sp<SkColorSpace> MakeICC(const void* input, size_t len, ICCTypeFlag type);
raftias54761282016-12-01 13:44:07 -0500196
Matt Sarettf3880932017-03-24 10:06:03 -0400197 static sk_sp<SkColorSpace> MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50);
Matt Sarett595599f2016-12-15 13:05:53 -0500198
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500199 enum Named : uint8_t {
200 kSRGB_Named,
201 kAdobeRGB_Named,
202 kSRGBLinear_Named,
Brian Osman3f405982017-02-15 08:51:19 -0500203 kSRGB_NonLinearBlending_Named,
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500204 };
205
206 static sk_sp<SkColorSpace> MakeNamed(Named);
207
raftias94888332016-10-18 10:02:51 -0700208protected:
Matt Sarettf3880932017-03-24 10:06:03 -0400209 SkColorSpace_Base(sk_sp<SkData> profileData);
brianosman971cd492016-09-08 10:10:11 -0700210
msarettc213f0d2016-08-01 14:23:32 -0700211private:
raftias94888332016-10-18 10:02:51 -0700212 sk_sp<SkData> fProfileData;
brianosman971cd492016-09-08 10:10:11 -0700213
msarett8cc20912016-05-23 09:29:29 -0700214 friend class SkColorSpace;
raftias94888332016-10-18 10:02:51 -0700215 friend class SkColorSpace_XYZ;
msarettb3906762016-06-22 14:07:48 -0700216 friend class ColorSpaceXformTest;
msarettc213f0d2016-08-01 14:23:32 -0700217 friend class ColorSpaceTest;
msarett8cc20912016-05-23 09:29:29 -0700218 typedef SkColorSpace INHERITED;
219};
220
221static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) {
222 return static_cast<SkColorSpace_Base*>(colorSpace);
223}
224
msarettab926f02016-05-25 08:53:40 -0700225static inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) {
226 return static_cast<const SkColorSpace_Base*>(colorSpace);
227}
228
msarett888dc162016-05-23 10:21:17 -0700229static inline SkColorSpace_Base* as_CSB(const sk_sp<SkColorSpace>& colorSpace) {
230 return static_cast<SkColorSpace_Base*>(colorSpace.get());
231}
232
msarettbb9f7742016-05-17 09:31:20 -0700233#endif