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