blob: 015e95f8a1392e86e7f16a783740ac60bf69ce20 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkColorSpace_Base_DEFINED
#define SkColorSpace_Base_DEFINED
#include "SkColorLookUpTable.h"
#include "SkColorSpace.h"
#include "SkData.h"
#include "SkOnce.h"
#include "SkTemplates.h"
enum SkGammaNamed : uint8_t {
kLinear_SkGammaNamed,
kSRGB_SkGammaNamed,
k2Dot2Curve_SkGammaNamed,
kNonStandard_SkGammaNamed,
};
struct SkGammas : SkRefCnt {
// There are four possible representations for gamma curves. kNone_Type is used
// as a placeholder until the struct is initialized. It is not a valid value.
enum class Type : uint8_t {
kNone_Type,
kNamed_Type,
kValue_Type,
kTable_Type,
kParam_Type,
};
// Contains information for a gamma table.
struct Table {
size_t fOffset;
int fSize;
const float* table(const SkGammas* base) const {
return SkTAddOffset<const float>(base, sizeof(SkGammas) + fOffset);
}
};
// Contains the actual gamma curve information. Should be interpreted
// based on the type of the gamma curve.
union Data {
Data()
: fTable{ 0, 0 }
{}
inline bool operator==(const Data& that) const {
return this->fTable.fOffset == that.fTable.fOffset &&
this->fTable.fSize == that.fTable.fSize;
}
inline bool operator!=(const Data& that) const {
return !(*this == that);
}
SkGammaNamed fNamed;
float fValue;
Table fTable;
size_t fParamOffset;
const SkColorSpaceTransferFn& params(const SkGammas* base) const {
return *SkTAddOffset<const SkColorSpaceTransferFn>(
base, sizeof(SkGammas) + fParamOffset);
}
};
bool isNamed(int i) const {
return Type::kNamed_Type == this->type(i);
}
bool isValue(int i) const {
return Type::kValue_Type == this->type(i);
}
bool isTable(int i) const {
return Type::kTable_Type == this->type(i);
}
bool isParametric(int i) const {
return Type::kParam_Type == this->type(i);
}
const Data& data(int i) const {
SkASSERT(i >= 0 && i < fChannels);
return fData[i];
}
const float* table(int i) const {
SkASSERT(isTable(i));
return this->data(i).fTable.table(this);
}
int tableSize(int i) const {
SkASSERT(isTable(i));
return this->data(i).fTable.fSize;
}
const SkColorSpaceTransferFn& params(int i) const {
SkASSERT(isParametric(i));
return this->data(i).params(this);
}
Type type(int i) const {
SkASSERT(i >= 0 && i < fChannels);
return fType[i];
}
uint8_t channels() const { return fChannels; }
SkGammas(uint8_t channels)
: fChannels(channels) {
SkASSERT(channels <= kMaxColorChannels);
for (uint8_t i = 0; i < kMaxColorChannels; ++i) {
fType[i] = Type::kNone_Type;
}
}
// These fields should only be modified when initializing the struct.
uint8_t fChannels;
Data fData[kMaxColorChannels];
Type fType[kMaxColorChannels];
// Objects of this type are sometimes created in a custom fashion using
// sk_malloc_throw and therefore must be sk_freed. We overload new to
// also call sk_malloc_throw so that memory can be unconditionally released
// using sk_free in an overloaded delete. Overloading regular new means we
// must also overload placement new.
void* operator new(size_t size) { return sk_malloc_throw(size); }
void* operator new(size_t, void* p) { return p; }
void operator delete(void* p) { sk_free(p); }
};
class SkColorSpace_Base : public SkColorSpace {
public:
/**
* Describes color space gamut as a transformation to XYZ D50.
* Returns nullptr if color gamut cannot be described in terms of XYZ D50.
*/
virtual const SkMatrix44* toXYZD50() const = 0;
/**
* Returns a hash of the gamut transofmration to XYZ D50. Allows for fast equality checking
* of gamuts, at the (very small) risk of collision.
* Returns 0 if color gamut cannot be described in terms of XYZ D50.
*/
virtual uint32_t toXYZD50Hash() const = 0;
/**
* Describes color space gamut as a transformation from XYZ D50
* Returns nullptr if color gamut cannot be described in terms of XYZ D50.
*/
virtual const SkMatrix44* fromXYZD50() const = 0;
virtual bool onGammaCloseToSRGB() const = 0;
virtual bool onGammaIsLinear() const = 0;
virtual bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const = 0;
virtual bool onIsCMYK() const { return false; }
/**
* Returns a color space with the same gamut as this one, but with a linear gamma.
* For color spaces whose gamut can not be described in terms of XYZ D50, returns
* linear sRGB.
*/
virtual sk_sp<SkColorSpace> makeLinearGamma() const = 0;
/**
* Returns a color space with the same gamut as this one, with with the sRGB transfer
* function. For color spaces whose gamut can not be described in terms of XYZ D50, returns
* sRGB.
*/
virtual sk_sp<SkColorSpace> makeSRGBGamma() const = 0;
enum class Type : uint8_t {
kXYZ,
kA2B
};
virtual Type type() const = 0;
typedef uint8_t ICCTypeFlag;
static constexpr ICCTypeFlag kRGB_ICCTypeFlag = 1 << 0;
static constexpr ICCTypeFlag kCMYK_ICCTypeFlag = 1 << 1;
static constexpr ICCTypeFlag kGray_ICCTypeFlag = 1 << 2;
static sk_sp<SkColorSpace> MakeICC(const void* input, size_t len, ICCTypeFlag type);
static sk_sp<SkColorSpace> MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50);
enum Named : uint8_t {
kSRGB_Named,
kAdobeRGB_Named,
kSRGBLinear_Named,
kSRGB_NonLinearBlending_Named,
};
static sk_sp<SkColorSpace> MakeNamed(Named);
protected:
SkColorSpace_Base(sk_sp<SkData> profileData);
private:
sk_sp<SkData> fProfileData;
friend class SkColorSpace;
friend class SkColorSpace_XYZ;
friend class ColorSpaceXformTest;
friend class ColorSpaceTest;
typedef SkColorSpace INHERITED;
};
static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) {
return static_cast<SkColorSpace_Base*>(colorSpace);
}
static inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) {
return static_cast<const SkColorSpace_Base*>(colorSpace);
}
static inline SkColorSpace_Base* as_CSB(const sk_sp<SkColorSpace>& colorSpace) {
return static_cast<SkColorSpace_Base*>(colorSpace.get());
}
#endif