/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkColorSpace_XYZ.h" #include "SkColorSpacePriv.h" #include "SkColorSpaceXformPriv.h" #include "SkOpts.h" SkColorSpace_XYZ::SkColorSpace_XYZ(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) : fProfileData(nullptr) , fGammaNamed(gammaNamed) , fGammas(nullptr) , fToXYZD50(toXYZD50) , fToXYZD50Hash(SkOpts::hash_fn(toXYZD50.values(), 16 * sizeof(SkMScalar), 0)) , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) {} SkColorSpace_XYZ::SkColorSpace_XYZ(SkGammaNamed gammaNamed, sk_sp gammas, const SkMatrix44& toXYZD50, sk_sp profileData) : fProfileData(std::move(profileData)) , fGammaNamed(gammaNamed) , fGammas(std::move(gammas)) , fToXYZD50(toXYZD50) , fToXYZD50Hash(SkOpts::hash_fn(toXYZD50.values(), 16 * sizeof(SkMScalar), 0)) , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) { SkASSERT(!fGammas || 3 == fGammas->channels()); if (fGammas) { for (int i = 0; i < fGammas->channels(); ++i) { if (SkGammas::Type::kTable_Type == fGammas->type(i)) { SkASSERT(fGammas->data(i).fTable.fSize >= 2); } } } } const SkMatrix44* SkColorSpace_XYZ::onFromXYZD50() const { fFromXYZOnce([this] { if (!fToXYZD50.invert(&fFromXYZD50)) { // If a client gives us a dst gamut with a transform that we can't invert, we will // simply give them back a transform to sRGB gamut. SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50); srgbToxyzD50.invert(&fFromXYZD50); } }); return &fFromXYZD50; } bool SkColorSpace_XYZ::onGammaCloseToSRGB() const { return kSRGB_SkGammaNamed == fGammaNamed || k2Dot2Curve_SkGammaNamed == fGammaNamed; } bool SkColorSpace_XYZ::onGammaIsLinear() const { return kLinear_SkGammaNamed == fGammaNamed; } bool SkColorSpace_XYZ::onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const { if (named_to_parametric(coeffs, fGammaNamed)) { return true; } SkASSERT(fGammas); if (!fGammas->allChannelsSame()) { return false; } if (fGammas->isValue(0)) { value_to_parametric(coeffs, fGammas->data(0).fValue); return true; } if (fGammas->isParametric(0)) { *coeffs = fGammas->params(0); return true; } return false; } sk_sp SkColorSpace_XYZ::makeLinearGamma() const { if (this->gammaIsLinear()) { return sk_ref_sp(const_cast(this)); } return SkColorSpace::MakeRGB(kLinear_SkGammaNamed, fToXYZD50); } sk_sp SkColorSpace_XYZ::makeSRGBGamma() const { if (this->gammaCloseToSRGB()) { return sk_ref_sp(const_cast(this)); } return SkColorSpace::MakeRGB(kSRGB_SkGammaNamed, fToXYZD50); } sk_sp SkColorSpace_XYZ::makeColorSpin() const { SkMatrix44 spin(SkMatrix44::kUninitialized_Constructor); spin.set3x3(0, 1, 0, 0, 0, 1, 1, 0, 0); spin.postConcat(fToXYZD50); (void)spin.getType(); // Pre-cache spin matrix type to avoid races in future getType() calls. return sk_sp(new SkColorSpace_XYZ(fGammaNamed, fGammas, spin, fProfileData)); }