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 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 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 40 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 54 bool SkColorSpace_XYZ::onGammaCloseToSRGB() const { 55 return kSRGB_SkGammaNamed == fGammaNamed || k2Dot2Curve_SkGammaNamed == fGammaNamed; 56 } 57 58 bool SkColorSpace_XYZ::onGammaIsLinear() const { 59 return kLinear_SkGammaNamed == fGammaNamed; 60 } 61 62 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 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 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 99 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