Add SkColorSpaceTransferFn to SkColorSpace

BUG=skia:

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3178

Change-Id: I354342d4469cee0e25a7b0d189e925e431da623c
Reviewed-on: https://skia-review.googlesource.com/3178
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
This commit is contained in:
Matt Sarett 2016-10-11 16:57:50 -04:00 committed by Skia Commit-Bot
parent 3eb71216d2
commit df44fc5f2b
8 changed files with 267 additions and 106 deletions

View File

@ -29,6 +29,27 @@ struct SK_API SkColorSpacePrimaries {
bool toXYZD50(SkMatrix44* toXYZD50) const;
};
/**
* Contains the coefficients for a common transfer function equation, specified as
* a transformation from a curved space to linear.
*
* LinearVal = E*InputVal + F , for 0.0f <= InputVal < D
* LinearVal = (A*InputVal + B)^G + C, for D <= InputVal <= 1.0f
*
* Function is undefined if InputVal is not in [ 0.0f, 1.0f ].
* Resulting LinearVals must be in [ 0.0f, 1.0f ].
* Function must be positive and increasing.
*/
struct SK_API SkColorSpaceTransferFn {
float fG;
float fA;
float fB;
float fC;
float fD;
float fE;
float fF;
};
class SK_API SkColorSpace : public SkRefCnt {
public:
@ -68,10 +89,12 @@ public:
/**
* Create an SkColorSpace from a transfer function and a color gamut.
*
* Transfer function is specified as linear or sRGB.
* Transfer function can be specified as a render target or as the coefficients to an equation.
* Gamut is specified using the matrix transformation to XYZ D50.
*/
static sk_sp<SkColorSpace> NewRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50);
static sk_sp<SkColorSpace> NewRGB(const SkColorSpaceTransferFn& coeffs,
const SkMatrix44& toXYZD50);
/**
* Create a common, named SkColorSpace.

View File

@ -11,10 +11,6 @@
#include "SkOnce.h"
#include "SkPoint3.h"
static inline bool is_zero_to_one(float v) {
return (0.0f <= v) && (v <= 1.0f);
}
bool SkColorSpacePrimaries::toXYZD50(SkMatrix44* toXYZ_D50) const {
if (!is_zero_to_one(fRX) || !is_zero_to_one(fRY) ||
!is_zero_to_one(fGX) || !is_zero_to_one(fGY) ||
@ -211,6 +207,37 @@ sk_sp<SkColorSpace> SkColorSpace::NewRGB(RenderTargetGamma gamma, const SkMatrix
}
}
sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkColorSpaceTransferFn& coeffs,
const SkMatrix44& toXYZD50) {
if (!is_valid_transfer_fn(coeffs)) {
return nullptr;
}
if (is_almost_srgb(coeffs)) {
return SkColorSpace::NewRGB(kSRGB_RenderTargetGamma, toXYZD50);
}
if (is_almost_2dot2(coeffs)) {
return SkColorSpace_Base::NewRGB(k2Dot2Curve_SkGammaNamed, toXYZD50);
}
void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn));
sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
SkColorSpaceTransferFn* fn = SkTAddOffset<SkColorSpaceTransferFn>(memory, sizeof(SkGammas));
*fn = coeffs;
gammas->fRedType = SkGammas::Type::kParam_Type;
gammas->fGreenType = SkGammas::Type::kParam_Type;
gammas->fBlueType = SkGammas::Type::kParam_Type;
SkGammas::Data data;
data.fParamOffset = 0;
gammas->fRedData = data;
gammas->fGreenData = data;
gammas->fBlueData = data;
return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, kNonStandard_SkGammaNamed,
std::move(gammas), toXYZD50, nullptr));
}
static SkColorSpace* gAdobeRGB;
static SkColorSpace* gSRGB;
static SkColorSpace* gSRGBLinear;
@ -299,9 +326,13 @@ enum Version {
};
struct ColorSpaceHeader {
/**
* It is only valid to set zero or one flags.
* Setting multiple flags is invalid.
*/
/**
* If kMatrix_Flag is set, we will write 12 floats after the header.
* Should not be set at the same time as the kICC_Flag or kFloatGamma_Flag.
*/
static constexpr uint8_t kMatrix_Flag = 1 << 0;
@ -309,7 +340,6 @@ struct ColorSpaceHeader {
* If kICC_Flag is set, we will write an ICC profile after the header.
* The ICC profile will be written as a uint32 size, followed immediately
* by the data (padded to 4 bytes).
* Should not be set at the same time as the kMatrix_Flag or kFloatGamma_Flag.
*/
static constexpr uint8_t kICC_Flag = 1 << 1;
@ -317,10 +347,16 @@ struct ColorSpaceHeader {
* If kFloatGamma_Flag is set, we will write 15 floats after the header.
* The first three are the gamma values, and the next twelve are the
* matrix.
* Should not be set at the same time as the kICC_Flag or kMatrix_Flag.
*/
static constexpr uint8_t kFloatGamma_Flag = 1 << 2;
/**
* If kTransferFn_Flag is set, we will write 19 floats after the header.
* The first seven represent the transfer fn, and the next twelve are the
* matrix.
*/
static constexpr uint8_t kTransferFn_Flag = 1 << 3;
static ColorSpaceHeader Pack(Version version, uint8_t named, uint8_t gammaNamed, uint8_t flags)
{
ColorSpaceHeader header;
@ -334,7 +370,7 @@ struct ColorSpaceHeader {
SkASSERT(gammaNamed <= kNonStandard_SkGammaNamed);
header.fGammaNamed = (uint8_t) gammaNamed;
SkASSERT(flags <= kFloatGamma_Flag);
SkASSERT(flags <= kTransferFn_Flag);
header.fFlags = flags;
return header;
}
@ -388,26 +424,51 @@ size_t SkColorSpace::writeToMemory(void* memory) const {
return sizeof(ColorSpaceHeader) + 12 * sizeof(float);
}
default:
// Otherwise, write the gamma values and the matrix.
if (memory) {
*((ColorSpaceHeader*) memory) =
ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed,
ColorSpaceHeader::kFloatGamma_Flag);
memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader));
const SkGammas* gammas = as_CSB(this)->gammas();
SkASSERT(gammas);
if (gammas->isValue(0) && gammas->isValue(1) && gammas->isValue(2)) {
if (memory) {
*((ColorSpaceHeader*) memory) =
ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed,
ColorSpaceHeader::kFloatGamma_Flag);
memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader));
const SkGammas* gammas = as_CSB(this)->gammas();
SkASSERT(gammas);
SkASSERT(SkGammas::Type::kValue_Type == gammas->fRedType &&
SkGammas::Type::kValue_Type == gammas->fGreenType &&
SkGammas::Type::kValue_Type == gammas->fBlueType);
*(((float*) memory) + 0) = gammas->fRedData.fValue;
*(((float*) memory) + 1) = gammas->fGreenData.fValue;
*(((float*) memory) + 2) = gammas->fBlueData.fValue;
memory = SkTAddOffset<void>(memory, 3 * sizeof(float));
*(((float*) memory) + 0) = gammas->fRedData.fValue;
*(((float*) memory) + 1) = gammas->fGreenData.fValue;
*(((float*) memory) + 2) = gammas->fBlueData.fValue;
memory = SkTAddOffset<void>(memory, 3 * sizeof(float));
as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory);
as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory);
}
return sizeof(ColorSpaceHeader) + 15 * sizeof(float);
} else {
SkASSERT(gammas->isParametric(0));
SkASSERT(gammas->isParametric(1));
SkASSERT(gammas->isParametric(2));
SkASSERT(gammas->data(0) == gammas->data(1));
SkASSERT(gammas->data(0) == gammas->data(2));
if (memory) {
*((ColorSpaceHeader*) memory) =
ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed,
ColorSpaceHeader::kTransferFn_Flag);
memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader));
*(((float*) memory) + 0) = gammas->params(0).fA;
*(((float*) memory) + 1) = gammas->params(0).fB;
*(((float*) memory) + 2) = gammas->params(0).fC;
*(((float*) memory) + 3) = gammas->params(0).fD;
*(((float*) memory) + 4) = gammas->params(0).fE;
*(((float*) memory) + 5) = gammas->params(0).fF;
*(((float*) memory) + 6) = gammas->params(0).fG;
memory = SkTAddOffset<void>(memory, 7 * sizeof(float));
as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory);
}
return sizeof(ColorSpaceHeader) + 19 * sizeof(float);
}
return sizeof(ColorSpaceHeader) + 15 * sizeof(float);
}
}
@ -501,6 +562,25 @@ sk_sp<SkColorSpace> SkColorSpace::Deserialize(const void* data, size_t length) {
toXYZ.set3x4RowMajorf((const float*) data);
return SkColorSpace_Base::NewRGB(gammas, toXYZ);
}
case ColorSpaceHeader::kTransferFn_Flag: {
if (length < 19 * sizeof(float)) {
return nullptr;
}
SkColorSpaceTransferFn transferFn;
transferFn.fA = *(((const float*) data) + 0);
transferFn.fB = *(((const float*) data) + 1);
transferFn.fC = *(((const float*) data) + 2);
transferFn.fD = *(((const float*) data) + 3);
transferFn.fE = *(((const float*) data) + 4);
transferFn.fF = *(((const float*) data) + 5);
transferFn.fG = *(((const float*) data) + 6);
data = SkTAddOffset<const void>(data, 7 * sizeof(float));
SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor);
toXYZ.set3x4RowMajorf((const float*) data);
return SkColorSpace::NewRGB(transferFn, toXYZ);
}
default:
return nullptr;
}

View File

@ -7,6 +7,80 @@
#define SkColorSpacePrintf(...)
inline bool color_space_almost_equal(float a, float b) {
static inline bool color_space_almost_equal(float a, float b) {
return SkTAbs(a - b) < 0.01f;
}
static inline bool is_zero_to_one(float v) {
return (0.0f <= v) && (v <= 1.0f);
}
static inline bool is_valid_transfer_fn(const SkColorSpaceTransferFn& coeffs) {
if (SkScalarIsNaN(coeffs.fA) || SkScalarIsNaN(coeffs.fB) ||
SkScalarIsNaN(coeffs.fC) || SkScalarIsNaN(coeffs.fD) ||
SkScalarIsNaN(coeffs.fE) || SkScalarIsNaN(coeffs.fF) ||
SkScalarIsNaN(coeffs.fG))
{
return false;
}
if (!is_zero_to_one(coeffs.fD)) {
return false;
}
if (coeffs.fD == 0.0f) {
// Y = (aX + b)^g + c for always
if (0.0f == coeffs.fA || 0.0f == coeffs.fG) {
SkColorSpacePrintf("A or G is zero, constant transfer function "
"is nonsense");
return false;
}
}
if (coeffs.fD == 1.0f) {
// Y = eX + f for always
if (0.0f == coeffs.fE) {
SkColorSpacePrintf("E is zero, constant transfer function is "
"nonsense");
return false;
}
}
if ((0.0f == coeffs.fA || 0.0f == coeffs.fG) && 0.0f == coeffs.fE) {
SkColorSpacePrintf("A or G, and E are zero, constant transfer function "
"is nonsense");
return false;
}
if (coeffs.fE < 0.0f) {
SkColorSpacePrintf("Transfer function must be increasing");
return false;
}
if (coeffs.fA < 0.0f || coeffs.fG < 0.0f) {
SkColorSpacePrintf("Transfer function must be positive or increasing");
return false;
}
return true;
}
static inline bool is_almost_srgb(const SkColorSpaceTransferFn& coeffs) {
return color_space_almost_equal(0.9479f, coeffs.fA) &&
color_space_almost_equal(0.0521f, coeffs.fB) &&
color_space_almost_equal(0.0000f, coeffs.fC) &&
color_space_almost_equal(0.0405f, coeffs.fD) &&
color_space_almost_equal(0.0774f, coeffs.fE) &&
color_space_almost_equal(0.0000f, coeffs.fF) &&
color_space_almost_equal(2.4000f, coeffs.fG);
}
static inline bool is_almost_2dot2(const SkColorSpaceTransferFn& coeffs) {
return color_space_almost_equal(1.0f, coeffs.fA) &&
color_space_almost_equal(0.0f, coeffs.fB) &&
color_space_almost_equal(0.0f, coeffs.fC) &&
color_space_almost_equal(0.0f, coeffs.fD) &&
color_space_almost_equal(0.0f, coeffs.fE) &&
color_space_almost_equal(0.0f, coeffs.fF) &&
color_space_almost_equal(2.2f, coeffs.fG);
}

View File

@ -303,7 +303,7 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage,
outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
} else {
SkASSERT(gammas->isParametric(i));
const SkGammas::Params& params = gammas->params(i);
const SkColorSpaceTransferFn& params = gammas->params(i);
(*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
params.fA, params.fB, params.fC, params.fD, params.fE,
params.fF);

View File

@ -42,19 +42,6 @@ struct SkGammas : SkRefCnt {
}
};
// Contains the parameters for a parametric curve.
struct Params {
// Y = (aX + b)^g + c for X >= d
// Y = eX + f otherwise
float fG;
float fA;
float fB;
float fC;
float fD;
float fE;
float fF;
};
// Contains the actual gamma curve information. Should be interpreted
// based on the type of the gamma curve.
union Data {
@ -72,8 +59,9 @@ struct SkGammas : SkRefCnt {
Table fTable;
size_t fParamOffset;
const Params& params(const SkGammas* base) const {
return *SkTAddOffset<const Params>(base, sizeof(SkGammas) + fParamOffset);
const SkColorSpaceTransferFn& params(const SkGammas* base) const {
return *SkTAddOffset<const SkColorSpaceTransferFn>(
base, sizeof(SkGammas) + fParamOffset);
}
};
@ -112,7 +100,7 @@ struct SkGammas : SkRefCnt {
return this->data(i).fTable.table(this);
}
const Params& params(int i) const {
const SkColorSpaceTransferFn& params(int i) const {
SkASSERT(isParametric(i));
return this->data(i).params(this);
}

View File

@ -274,8 +274,8 @@ static float read_big_endian_16_dot_16(const uint8_t buf[4]) {
*
* @return kNone_Type on failure, otherwise the type of the gamma tag.
*/
static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* outParams,
size_t* outTagBytes, const uint8_t* src, size_t len) {
static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkColorSpaceTransferFn* outParams,
size_t* outTagBytes, const uint8_t* src, size_t len) {
if (len < 12) {
SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
return SkGammas::Type::kNone_Type;
@ -478,49 +478,6 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out
return SkGammas::Type::kNone_Type;
}
// Recognize and simplify a very common parametric representation of sRGB gamma.
if (color_space_almost_equal(0.9479f, a) &&
color_space_almost_equal(0.0521f, b) &&
color_space_almost_equal(0.0000f, c) &&
color_space_almost_equal(0.0405f, d) &&
color_space_almost_equal(0.0774f, e) &&
color_space_almost_equal(0.0000f, f) &&
color_space_almost_equal(2.4000f, g)) {
outData->fNamed = kSRGB_SkGammaNamed;
return SkGammas::Type::kNamed_Type;
}
// Fail on invalid gammas.
if (SkScalarIsNaN(d)) {
return SkGammas::Type::kNone_Type;
}
if (d <= 0.0f) {
// Y = (aX + b)^g + c for always
if (0.0f == a || 0.0f == g) {
SkColorSpacePrintf("A or G is zero, constant gamma function "
"is nonsense");
return SkGammas::Type::kNone_Type;
}
}
if (d >= 1.0f) {
// Y = eX + f for always
if (0.0f == e) {
SkColorSpacePrintf("E is zero, constant gamma function is "
"nonsense");
return SkGammas::Type::kNone_Type;
}
}
if ((0.0f == a || 0.0f == g) && 0.0f == e) {
SkColorSpacePrintf("A or G, and E are zero, constant gamma function "
"is nonsense");
return SkGammas::Type::kNone_Type;
}
*outTagBytes = tagBytes;
outParams->fG = g;
outParams->fA = a;
outParams->fB = b;
@ -528,6 +485,22 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out
outParams->fD = d;
outParams->fE = e;
outParams->fF = f;
if (!is_valid_transfer_fn(*outParams)) {
return SkGammas::Type::kNone_Type;
}
if (is_almost_srgb(*outParams)) {
outData->fNamed = kSRGB_SkGammaNamed;
return SkGammas::Type::kNamed_Type;
}
if (is_almost_2dot2(*outParams)) {
outData->fNamed = k2Dot2Curve_SkGammaNamed;
return SkGammas::Type::kNamed_Type;
}
*outTagBytes = tagBytes;
return SkGammas::Type::kParam_Type;
}
default:
@ -547,7 +520,7 @@ static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data)
case SkGammas::Type::kTable_Type:
return sizeof(float) * data.fTable.fSize;
case SkGammas::Type::kParam_Type:
return sizeof(SkGammas::Params);
return sizeof(SkColorSpaceTransferFn);
default:
SkASSERT(false);
return 0;
@ -584,7 +557,7 @@ static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) {
* @return Additional bytes of memory that are being used by this gamma curve.
*/
static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
SkGammas::Data* data, const SkGammas::Params& params,
SkGammas::Data* data, const SkColorSpaceTransferFn& params,
const uint8_t* src) {
void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas));
@ -606,8 +579,8 @@ static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
}
case SkGammas::Type::kParam_Type:
data->fTable.fOffset = offset;
memcpy(storage, &params, sizeof(SkGammas::Params));
return sizeof(SkGammas::Params);
memcpy(storage, &params, sizeof(SkColorSpaceTransferFn));
return sizeof(SkColorSpaceTransferFn);
default:
SkASSERT(false);
return 0;
@ -785,7 +758,7 @@ static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, SkGammaNamed* gammaNa
size_t tagLen = len - offsetToMCurves;
SkGammas::Data rData;
SkGammas::Params rParams;
SkColorSpaceTransferFn rParams;
// On an invalid first gamma, tagBytes remains set as zero. This causes the two
// subsequent to be treated as identical (which is what we want).
@ -820,17 +793,17 @@ static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, SkGammaNamed* gammaNa
const uint8_t* gTagPtr = rTagPtr + alignedTagBytes;
tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
SkGammas::Data gData;
SkGammas::Params gParams;
SkColorSpaceTransferFn gParams;
tagBytes = 0;
SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTagPtr,
tagLen);
tagLen);
handle_invalid_gamma(&gType, &gData);
alignedTagBytes = SkAlign4(tagBytes);
const uint8_t* bTagPtr = gTagPtr + alignedTagBytes;
tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
SkGammas::Data bData;
SkGammas::Params bParams;
SkColorSpaceTransferFn bParams;
SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTagPtr,
tagLen);
handle_invalid_gamma(&bType, &bData);
@ -993,7 +966,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) {
if (r && g && b) {
if (tag_equals(r, g, base) && tag_equals(g, b, base)) {
SkGammas::Data data;
SkGammas::Params params;
SkColorSpaceTransferFn params;
SkGammas::Type type =
parse_gamma(&data, &params, &tagBytes, r->addr(base), r->fLength);
handle_invalid_gamma(&type, &data);
@ -1019,19 +992,19 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) {
}
} else {
SkGammas::Data rData;
SkGammas::Params rParams;
SkColorSpaceTransferFn rParams;
SkGammas::Type rType =
parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength);
handle_invalid_gamma(&rType, &rData);
SkGammas::Data gData;
SkGammas::Params gParams;
SkColorSpaceTransferFn gParams;
SkGammas::Type gType =
parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength);
handle_invalid_gamma(&gType, &gData);
SkGammas::Data bData;
SkGammas::Params bParams;
SkColorSpaceTransferFn bParams;
SkGammas::Type bType =
parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength);
handle_invalid_gamma(&bType, &bData);

View File

@ -229,6 +229,16 @@ DEF_TEST(ColorSpace_Serialize, r) {
const float gammas[] = { 1.1f, 1.2f, 1.7f, };
SkMatrix44 toXYZ(SkMatrix44::kIdentity_Constructor);
test_serialize(r, SkColorSpace_Base::NewRGB(gammas, toXYZ).get(), false);
SkColorSpaceTransferFn fn;
fn.fA = 1.0f;
fn.fB = 0.0f;
fn.fC = 0.0f;
fn.fD = 0.5f;
fn.fE = 1.0f;
fn.fF = 0.0f;
fn.fG = 1.0f;
test_serialize(r, SkColorSpace::NewRGB(fn, toXYZ).get(), false);
}
DEF_TEST(ColorSpace_Equals, r) {
@ -250,6 +260,16 @@ DEF_TEST(ColorSpace_Equals, r) {
sk_sp<SkColorSpace> rgb2 = SkColorSpace_Base::NewRGB(gammas2, toXYZ);
sk_sp<SkColorSpace> rgb3 = SkColorSpace_Base::NewRGB(gammas1, toXYZ);
SkColorSpaceTransferFn fn;
fn.fA = 1.0f;
fn.fB = 0.0f;
fn.fC = 0.0f;
fn.fD = 0.5f;
fn.fE = 1.0f;
fn.fF = 0.0f;
fn.fG = 1.0f;
sk_sp<SkColorSpace> rgb4 = SkColorSpace::NewRGB(fn, toXYZ);
REPORTER_ASSERT(r, SkColorSpace::Equals(nullptr, nullptr));
REPORTER_ASSERT(r, SkColorSpace::Equals(srgb.get(), srgb.get()));
REPORTER_ASSERT(r, SkColorSpace::Equals(adobe.get(), adobe.get()));
@ -259,6 +279,7 @@ DEF_TEST(ColorSpace_Equals, r) {
REPORTER_ASSERT(r, SkColorSpace::Equals(upperRight.get(), upperRight.get()));
REPORTER_ASSERT(r, SkColorSpace::Equals(rgb1.get(), rgb1.get()));
REPORTER_ASSERT(r, SkColorSpace::Equals(rgb1.get(), rgb3.get()));
REPORTER_ASSERT(r, SkColorSpace::Equals(rgb4.get(), rgb4.get()));
REPORTER_ASSERT(r, !SkColorSpace::Equals(nullptr, srgb.get()));
REPORTER_ASSERT(r, !SkColorSpace::Equals(srgb.get(), nullptr));
@ -270,6 +291,7 @@ DEF_TEST(ColorSpace_Equals, r) {
REPORTER_ASSERT(r, !SkColorSpace::Equals(z30.get(), upperRight.get()));
REPORTER_ASSERT(r, !SkColorSpace::Equals(upperRight.get(), adobe.get()));
REPORTER_ASSERT(r, !SkColorSpace::Equals(rgb1.get(), rgb2.get()));
REPORTER_ASSERT(r, !SkColorSpace::Equals(rgb1.get(), rgb4.get()));
}
DEF_TEST(ColorSpace_Primaries, r) {

View File

@ -86,12 +86,13 @@ DEF_TEST(ColorSpaceXform_TableGamma, r) {
DEF_TEST(ColorSpaceXform_ParametricGamma, r) {
// Parametric gamma curves
void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkGammas::Params));
void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn));
sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type::kParam_Type;
gammas->fRedData.fParamOffset = gammas->fGreenData.fParamOffset =
gammas->fBlueData.fParamOffset = 0;
SkGammas::Params* params = SkTAddOffset<SkGammas::Params>(memory, sizeof(SkGammas));
SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn>
(memory, sizeof(SkGammas));
// Interval, switch xforms at 0.0031308f
params->fD = 0.04045f;
@ -129,7 +130,7 @@ DEF_TEST(ColorSpaceXform_NamedGamma, r) {
DEF_TEST(ColorSpaceXform_NonMatchingGamma, r) {
constexpr size_t tableSize = 10;
void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize +
sizeof(SkGammas::Params));
sizeof(SkColorSpaceTransferFn));
sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
float* table = SkTAddOffset<float>(memory, sizeof(SkGammas));
@ -144,8 +145,8 @@ DEF_TEST(ColorSpaceXform_NonMatchingGamma, r) {
table[8] = 0.85f;
table[9] = 1.00f;
SkGammas::Params* params = SkTAddOffset<SkGammas::Params>(memory, sizeof(SkGammas) +
sizeof(float) * tableSize);
SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn>(memory,
sizeof(SkGammas) + sizeof(float) * tableSize);
params->fA = 1.0f / 1.055f;
params->fB = 0.055f / 1.055f;
params->fC = 0.0f;