99#include " SkColorSpace_XYZ.h"
1010#include " SkColorSpacePriv.h"
1111#include " SkPoint3.h"
12- #include " SkTemplates.h"
1312#include < new>
1413
1514bool SkColorSpacePrimaries::toXYZD50 (SkMatrix44* toXYZ_D50) const {
@@ -128,7 +127,7 @@ sk_sp<SkColorSpace> SkColorSpace::MakeRGB(SkGammaNamed gammaNamed, const SkMatri
128127 break ;
129128 }
130129
131- return sk_sp<SkColorSpace>(new SkColorSpace_XYZ (gammaNamed, nullptr , toXYZD50));
130+ return sk_sp<SkColorSpace>(new SkColorSpace_XYZ (gammaNamed, toXYZD50));
132131}
133132
134133sk_sp<SkColorSpace> SkColorSpace::MakeRGB (RenderTargetGamma gamma, const SkMatrix44& toXYZD50) {
@@ -160,7 +159,18 @@ sk_sp<SkColorSpace> SkColorSpace::MakeRGB(const SkColorSpaceTransferFn& coeffs,
160159 return SkColorSpace::MakeRGB (kLinear_SkGammaNamed , toXYZD50);
161160 }
162161
163- return sk_sp<SkColorSpace>(new SkColorSpace_XYZ (kNonStandard_SkGammaNamed , &coeffs, toXYZD50));
162+ void * memory = sk_malloc_throw (sizeof (SkGammas) + sizeof (SkColorSpaceTransferFn));
163+ sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas (3 ));
164+ SkColorSpaceTransferFn* fn = SkTAddOffset<SkColorSpaceTransferFn>(memory, sizeof (SkGammas));
165+ *fn = coeffs;
166+ SkGammas::Data data;
167+ data.fParamOffset = 0 ;
168+ for (int channel = 0 ; channel < 3 ; ++channel) {
169+ gammas->fType [channel] = SkGammas::Type::kParam_Type ;
170+ gammas->fData [channel] = data;
171+ }
172+ return sk_sp<SkColorSpace>(new SkColorSpace_XYZ (kNonStandard_SkGammaNamed ,
173+ std::move (gammas), toXYZD50, nullptr ));
164174}
165175
166176sk_sp<SkColorSpace> SkColorSpace::MakeRGB (RenderTargetGamma gamma, Gamut gamut) {
@@ -179,7 +189,7 @@ static SkColorSpace* singleton_colorspace(SkGammaNamed gamma, const float to_xyz
179189 SkMatrix44 m44 (SkMatrix44::kUninitialized_Constructor );
180190 m44.set3x3RowMajorf (to_xyz);
181191 (void )m44.getType (); // Force typemask to be computed to avoid races.
182- return new SkColorSpace_XYZ (gamma, nullptr , m44);
192+ return new SkColorSpace_XYZ (gamma, m44);
183193}
184194
185195SkColorSpace* sk_srgb_singleton () {
@@ -201,6 +211,14 @@ sk_sp<SkColorSpace> SkColorSpace::MakeSRGBLinear() {
201211
202212// /////////////////////////////////////////////////////////////////////////////////////////////////
203213
214+ SkColorSpace::Type SkColorSpace::type () const {
215+ const SkMatrix44* m = this ->toXYZD50 ();
216+ if (m) {
217+ return m->isScale () ? kGray_Type : kRGB_Type ;
218+ }
219+ return this ->onIsCMYK () ? kCMYK_Type : kRGB_Type ;
220+ }
221+
204222SkGammaNamed SkColorSpace::gammaNamed () const {
205223 return this ->onGammaNamed ();
206224}
@@ -271,7 +289,6 @@ struct ColorSpaceHeader {
271289 * If kICC_Flag is set, we will write an ICC profile after the header.
272290 * The ICC profile will be written as a uint32 size, followed immediately
273291 * by the data (padded to 4 bytes).
274- * DEPRECATED / UNUSED
275292 */
276293 static constexpr uint8_t kICC_Flag = 1 << 1 ;
277294
@@ -307,61 +324,87 @@ struct ColorSpaceHeader {
307324};
308325
309326size_t SkColorSpace::writeToMemory (void * memory) const {
310- // If we have a named profile, only write the enum.
311- const SkGammaNamed gammaNamed = this ->gammaNamed ();
312- if (this == sk_srgb_singleton ()) {
313- if (memory) {
314- *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack (
315- k0_Version, kSRGB_NamedColorSpace , gammaNamed, 0 );
316- }
317- return sizeof (ColorSpaceHeader);
318- } else if (this == sk_srgb_linear_singleton ()) {
319- if (memory) {
320- *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack (
321- k0_Version, kSRGBLinear_NamedColorSpace , gammaNamed, 0 );
322- }
323- return sizeof (ColorSpaceHeader);
324- }
325-
326- // If we have a named gamma, write the enum and the matrix.
327- switch (gammaNamed) {
328- case kSRGB_SkGammaNamed :
329- case k2Dot2Curve_SkGammaNamed:
330- case kLinear_SkGammaNamed : {
327+ // Start by trying the serialization fast path. If we haven't saved ICC profile data,
328+ // we must have a profile that we can serialize easily.
329+ if (!this ->onProfileData ()) {
330+ // Profile data is mandatory for A2B0 color spaces, so we must be XYZ.
331+ SkASSERT (this ->toXYZD50 ());
332+ // If we have a named profile, only write the enum.
333+ const SkGammaNamed gammaNamed = this ->gammaNamed ();
334+ if (this == sk_srgb_singleton ()) {
331335 if (memory) {
332- *((ColorSpaceHeader*) memory) =
333- ColorSpaceHeader::Pack (k0_Version, 0 , gammaNamed,
334- ColorSpaceHeader::kMatrix_Flag );
335- memory = SkTAddOffset<void >(memory, sizeof (ColorSpaceHeader));
336- this ->toXYZD50 ()->as3x4RowMajorf ((float *) memory);
336+ *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack (
337+ k0_Version, kSRGB_NamedColorSpace , gammaNamed, 0 );
337338 }
338- return sizeof (ColorSpaceHeader) + 12 * sizeof (float );
339- }
340- default : {
341- SkColorSpaceTransferFn transferFn;
342- SkAssertResult (this ->isNumericalTransferFn (&transferFn));
343-
339+ return sizeof (ColorSpaceHeader);
340+ } else if (this == sk_srgb_linear_singleton ()) {
344341 if (memory) {
345- *((ColorSpaceHeader*) memory) =
346- ColorSpaceHeader::Pack (k0_Version, 0 , gammaNamed,
347- ColorSpaceHeader::kTransferFn_Flag );
348- memory = SkTAddOffset<void >(memory, sizeof (ColorSpaceHeader));
349-
350- *(((float *) memory) + 0 ) = transferFn.fA ;
351- *(((float *) memory) + 1 ) = transferFn.fB ;
352- *(((float *) memory) + 2 ) = transferFn.fC ;
353- *(((float *) memory) + 3 ) = transferFn.fD ;
354- *(((float *) memory) + 4 ) = transferFn.fE ;
355- *(((float *) memory) + 5 ) = transferFn.fF ;
356- *(((float *) memory) + 6 ) = transferFn.fG ;
357- memory = SkTAddOffset<void >(memory, 7 * sizeof (float ));
358-
359- this ->toXYZD50 ()->as3x4RowMajorf ((float *) memory);
342+ *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack (
343+ k0_Version, kSRGBLinear_NamedColorSpace , gammaNamed, 0 );
360344 }
345+ return sizeof (ColorSpaceHeader);
346+ }
361347
362- return sizeof (ColorSpaceHeader) + 19 * sizeof (float );
348+ // If we have a named gamma, write the enum and the matrix.
349+ switch (gammaNamed) {
350+ case kSRGB_SkGammaNamed :
351+ case k2Dot2Curve_SkGammaNamed:
352+ case kLinear_SkGammaNamed : {
353+ if (memory) {
354+ *((ColorSpaceHeader*) memory) =
355+ ColorSpaceHeader::Pack (k0_Version, 0 , gammaNamed,
356+ ColorSpaceHeader::kMatrix_Flag );
357+ memory = SkTAddOffset<void >(memory, sizeof (ColorSpaceHeader));
358+ this ->toXYZD50 ()->as3x4RowMajorf ((float *) memory);
359+ }
360+ return sizeof (ColorSpaceHeader) + 12 * sizeof (float );
361+ }
362+ default : {
363+ SkColorSpaceTransferFn transferFn;
364+ SkAssertResult (this ->isNumericalTransferFn (&transferFn));
365+
366+ if (memory) {
367+ *((ColorSpaceHeader*) memory) =
368+ ColorSpaceHeader::Pack (k0_Version, 0 , gammaNamed,
369+ ColorSpaceHeader::kTransferFn_Flag );
370+ memory = SkTAddOffset<void >(memory, sizeof (ColorSpaceHeader));
371+
372+ *(((float *) memory) + 0 ) = transferFn.fA ;
373+ *(((float *) memory) + 1 ) = transferFn.fB ;
374+ *(((float *) memory) + 2 ) = transferFn.fC ;
375+ *(((float *) memory) + 3 ) = transferFn.fD ;
376+ *(((float *) memory) + 4 ) = transferFn.fE ;
377+ *(((float *) memory) + 5 ) = transferFn.fF ;
378+ *(((float *) memory) + 6 ) = transferFn.fG ;
379+ memory = SkTAddOffset<void >(memory, 7 * sizeof (float ));
380+
381+ this ->toXYZD50 ()->as3x4RowMajorf ((float *) memory);
382+ }
383+
384+ return sizeof (ColorSpaceHeader) + 19 * sizeof (float );
385+ }
363386 }
364387 }
388+
389+ // Otherwise, serialize the ICC data.
390+ size_t profileSize = this ->onProfileData ()->size ();
391+ if (SkAlign4 (profileSize) != (uint32_t ) SkAlign4 (profileSize)) {
392+ return 0 ;
393+ }
394+
395+ if (memory) {
396+ *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack (k0_Version, 0 ,
397+ kNonStandard_SkGammaNamed ,
398+ ColorSpaceHeader::kICC_Flag );
399+ memory = SkTAddOffset<void >(memory, sizeof (ColorSpaceHeader));
400+
401+ *((uint32_t *) memory) = (uint32_t ) SkAlign4 (profileSize);
402+ memory = SkTAddOffset<void >(memory, sizeof (uint32_t ));
403+
404+ memcpy (memory, this ->onProfileData ()->data (), profileSize);
405+ memset (SkTAddOffset<void >(memory, profileSize), 0 , SkAlign4 (profileSize) - profileSize);
406+ }
407+ return sizeof (ColorSpaceHeader) + sizeof (uint32_t ) + SkAlign4 (profileSize);
365408}
366409
367410sk_sp<SkData> SkColorSpace::serialize () const {
@@ -412,8 +455,18 @@ sk_sp<SkColorSpace> SkColorSpace::Deserialize(const void* data, size_t length) {
412455
413456 switch (header.fFlags ) {
414457 case ColorSpaceHeader::kICC_Flag : {
415- // Deprecated and unsupported code path
416- return nullptr ;
458+ if (length < sizeof (uint32_t )) {
459+ return nullptr ;
460+ }
461+
462+ uint32_t profileSize = *((uint32_t *) data);
463+ data = SkTAddOffset<const void >(data, sizeof (uint32_t ));
464+ length -= sizeof (uint32_t );
465+ if (length < profileSize) {
466+ return nullptr ;
467+ }
468+
469+ return MakeICC (data, profileSize);
417470 }
418471 case ColorSpaceHeader::kTransferFn_Flag : {
419472 if (length < 19 * sizeof (float )) {
@@ -448,6 +501,18 @@ bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) {
448501 return false ;
449502 }
450503
504+ const SkData* srcData = src->onProfileData ();
505+ const SkData* dstData = dst->onProfileData ();
506+ if (srcData || dstData) {
507+ if (srcData && dstData) {
508+ return srcData->size () == dstData->size () &&
509+ 0 == memcmp (srcData->data (), dstData->data (), srcData->size ());
510+ }
511+
512+ return false ;
513+ }
514+
515+ // Profiles are mandatory for A2B0 color spaces, so these must be XYZ
451516 if (src->gammaNamed () != dst->gammaNamed ()) {
452517 return false ;
453518 }
@@ -463,7 +528,6 @@ bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) {
463528 return false ;
464529 default :
465530 // It is unlikely that we will reach this case.
466- // TODO: Simplify this case now that color spaces have one representation.
467531 sk_sp<SkData> serializedSrcData = src->serialize ();
468532 sk_sp<SkData> serializedDstData = dst->serialize ();
469533 return serializedSrcData->size () == serializedDstData->size () &&
0 commit comments