1 /*
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
8 #include "SkColorSpace_XYZ.h"
9 #include "SkColorSpacePriv.h"
10 #include "SkColorSpaceXform_Base.h"
11 #include "SkOpts.h"
12
SkColorSpace_XYZ(SkGammaNamed gammaNamed,const SkMatrix44 & toXYZD50)13 SkColorSpace_XYZ::SkColorSpace_XYZ(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50)
14 : INHERITED(nullptr)
15 , fGammaNamed(gammaNamed)
16 , fGammas(nullptr)
17 , fToXYZD50(toXYZD50)
18 , fToXYZD50Hash(SkOpts::hash_fn(toXYZD50.values(), 16 * sizeof(SkMScalar), 0))
19 , fFromXYZD50(SkMatrix44::kUninitialized_Constructor)
20 {}
21
SkColorSpace_XYZ(SkGammaNamed gammaNamed,sk_sp<SkGammas> gammas,const SkMatrix44 & toXYZD50,sk_sp<SkData> profileData)22 SkColorSpace_XYZ::SkColorSpace_XYZ(SkGammaNamed gammaNamed, sk_sp<SkGammas> gammas,
23 const SkMatrix44& toXYZD50, sk_sp<SkData> profileData)
24 : INHERITED(std::move(profileData))
25 , fGammaNamed(gammaNamed)
26 , fGammas(std::move(gammas))
27 , fToXYZD50(toXYZD50)
28 , fToXYZD50Hash(SkOpts::hash_fn(toXYZD50.values(), 16 * sizeof(SkMScalar), 0))
29 , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) {
30 SkASSERT(!fGammas || 3 == fGammas->channels());
31 if (fGammas) {
32 for (int i = 0; i < fGammas->channels(); ++i) {
33 if (SkGammas::Type::kTable_Type == fGammas->type(i)) {
34 SkASSERT(fGammas->data(i).fTable.fSize >= 2);
35 }
36 }
37 }
38 }
39
fromXYZD50() const40 const SkMatrix44* SkColorSpace_XYZ::fromXYZD50() const {
41 fFromXYZOnce([this] {
42 if (!fToXYZD50.invert(&fFromXYZD50)) {
43 // If a client gives us a dst gamut with a transform that we can't invert, we will
44 // simply give them back a transform to sRGB gamut.
45 SkDEBUGFAIL("Non-invertible XYZ matrix, defaulting to sRGB");
46 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor);
47 srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50);
48 srgbToxyzD50.invert(&fFromXYZD50);
49 }
50 });
51 return &fFromXYZD50;
52 }
53
onGammaCloseToSRGB() const54 bool SkColorSpace_XYZ::onGammaCloseToSRGB() const {
55 return kSRGB_SkGammaNamed == fGammaNamed || k2Dot2Curve_SkGammaNamed == fGammaNamed;
56 }
57
onGammaIsLinear() const58 bool SkColorSpace_XYZ::onGammaIsLinear() const {
59 return kLinear_SkGammaNamed == fGammaNamed;
60 }
61
onIsNumericalTransferFn(SkColorSpaceTransferFn * coeffs) const62 bool SkColorSpace_XYZ::onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const {
63 if (named_to_parametric(coeffs, fGammaNamed)) {
64 return true;
65 }
66
67 SkASSERT(fGammas);
68 if (fGammas->data(0) != fGammas->data(1) || fGammas->data(0) != fGammas->data(2)) {
69 return false;
70 }
71
72 if (fGammas->isValue(0)) {
73 value_to_parametric(coeffs, fGammas->data(0).fValue);
74 return true;
75 }
76
77 if (fGammas->isParametric(0)) {
78 *coeffs = fGammas->params(0);
79 return true;
80 }
81
82 return false;
83 }
84
makeLinearGamma()85 sk_sp<SkColorSpace> SkColorSpace_XYZ::makeLinearGamma() {
86 if (this->gammaIsLinear()) {
87 return sk_ref_sp(this);
88 }
89 return SkColorSpace_Base::MakeRGB(kLinear_SkGammaNamed, fToXYZD50);
90 }
91
makeSRGBGamma()92 sk_sp<SkColorSpace> SkColorSpace_XYZ::makeSRGBGamma() {
93 if (this->gammaCloseToSRGB()) {
94 return sk_ref_sp(this);
95 }
96 return SkColorSpace_Base::MakeRGB(kSRGB_SkGammaNamed, fToXYZD50);
97 }
98
toDstGammaTables(const uint8_t * tables[3],sk_sp<SkData> * storage,int numTables) const99 void SkColorSpace_XYZ::toDstGammaTables(const uint8_t* tables[3], sk_sp<SkData>* storage,
100 int numTables) const {
101 fToDstGammaOnce([this, numTables] {
102 const bool gammasAreMatching = numTables <= 1;
103 fDstStorage =
104 SkData::MakeUninitialized(numTables * SkColorSpaceXform_Base::kDstGammaTableSize);
105 SkColorSpaceXform_Base::BuildDstGammaTables(fToDstGammaTables,
106 (uint8_t*) fDstStorage->writable_data(), this,
107 gammasAreMatching);
108 });
109
110 *storage = fDstStorage;
111 tables[0] = fToDstGammaTables[0];
112 tables[1] = fToDstGammaTables[1];
113 tables[2] = fToDstGammaTables[2];
114 }
115