Home | History | Annotate | Download | only in core
      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     : fProfileData(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     : fProfileData(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::onFromXYZD50() 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->allChannelsSame()) {
     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() const {
     86     if (this->gammaIsLinear()) {
     87         return sk_ref_sp(const_cast<SkColorSpace_XYZ*>(this));
     88     }
     89     return SkColorSpace::MakeRGB(kLinear_SkGammaNamed, fToXYZD50);
     90 }
     91 
     92 sk_sp<SkColorSpace> SkColorSpace_XYZ::makeSRGBGamma() const {
     93     if (this->gammaCloseToSRGB()) {
     94         return sk_ref_sp(const_cast<SkColorSpace_XYZ*>(this));
     95     }
     96     return SkColorSpace::MakeRGB(kSRGB_SkGammaNamed, fToXYZD50);
     97 }
     98 
     99 sk_sp<SkColorSpace> SkColorSpace_XYZ::makeColorSpin() const {
    100     SkMatrix44 spin(SkMatrix44::kUninitialized_Constructor);
    101     spin.set3x3(0, 1, 0, 0, 0, 1, 1, 0, 0);
    102     spin.postConcat(fToXYZD50);
    103     return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(fGammaNamed, fGammas, spin, fProfileData));
    104 }
    105 
    106 void SkColorSpace_XYZ::toDstGammaTables(const uint8_t* tables[3], sk_sp<SkData>* storage,
    107                                          int numTables) const {
    108     fToDstGammaOnce([this, numTables] {
    109         const bool gammasAreMatching = numTables <= 1;
    110         fDstStorage =
    111                 SkData::MakeUninitialized(numTables * SkColorSpaceXform_Base::kDstGammaTableSize);
    112         SkColorSpaceXform_Base::BuildDstGammaTables(fToDstGammaTables,
    113                                                     (uint8_t*) fDstStorage->writable_data(), this,
    114                                                     gammasAreMatching);
    115     });
    116 
    117     *storage = fDstStorage;
    118     tables[0] = fToDstGammaTables[0];
    119     tables[1] = fToDstGammaTables[1];
    120     tables[2] = fToDstGammaTables[2];
    121 }
    122