1 /* 2 * Copyright 2017 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_New.h" 9 #include "SkOpts.h" 10 #include "SkRasterPipeline.h" 11 12 // ~~~~~~~~~~~~~~~~~~~~~~~ SkColorSpace_New::TransferFn ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 13 14 namespace { 15 16 struct LinearTransferFn : public SkColorSpace_New::TransferFn { 17 SkColorSpaceTransferFn parameterize() const override { 18 return { 1,1, 0,0,0,0,0 }; 19 } 20 21 void linearizeDst(SkRasterPipeline*) const override {} 22 void linearizeSrc(SkRasterPipeline*) const override {} 23 void encodeSrc(SkRasterPipeline*) const override {} 24 }; 25 26 struct SRGBTransferFn : public SkColorSpace_New::TransferFn { 27 SkColorSpaceTransferFn parameterize() const override { 28 return { 2.4f, 1/1.055f, 0.055f/1.055f, 1/12.92f, 0.04045f, 0, 0 }; 29 } 30 31 void linearizeDst(SkRasterPipeline* p) const override { 32 p->append(SkRasterPipeline::from_srgb_dst); 33 } 34 void linearizeSrc(SkRasterPipeline* p) const override { 35 p->append(SkRasterPipeline::from_srgb); 36 } 37 void encodeSrc(SkRasterPipeline* p) const override { 38 p->append(SkRasterPipeline::to_srgb); 39 } 40 }; 41 42 struct GammaTransferFn : public SkColorSpace_New::TransferFn { 43 float fGamma; 44 float fInv; 45 46 explicit GammaTransferFn(float gamma) : fGamma(gamma), fInv(1.0f/gamma) {} 47 48 SkColorSpaceTransferFn parameterize() const override { 49 return { fGamma, 1, 0,0,0,0,0 }; 50 } 51 52 void linearizeDst(SkRasterPipeline* p) const override { 53 p->append(SkRasterPipeline::gamma_dst, &fGamma); 54 } 55 void linearizeSrc(SkRasterPipeline* p) const override { 56 p->append(SkRasterPipeline::gamma, &fGamma); 57 } 58 void encodeSrc(SkRasterPipeline* p) const override { 59 p->append(SkRasterPipeline::gamma, &fInv); 60 } 61 }; 62 63 } 64 65 sk_sp<SkColorSpace_New::TransferFn> SkColorSpace_New::TransferFn::MakeLinear() { 66 return sk_make_sp<LinearTransferFn>(); 67 } 68 sk_sp<SkColorSpace_New::TransferFn> SkColorSpace_New::TransferFn::MakeSRGB() { 69 return sk_make_sp<SRGBTransferFn>(); 70 } 71 sk_sp<SkColorSpace_New::TransferFn> SkColorSpace_New::TransferFn::MakeGamma(float gamma) { 72 if (gamma == 1) { 73 return MakeLinear(); 74 } 75 return sk_make_sp<GammaTransferFn>(gamma); 76 } 77 78 bool SkColorSpace_New::TransferFn::equals(const SkColorSpace_New::TransferFn& other) const { 79 SkColorSpaceTransferFn a = this->parameterize(), 80 b = other.parameterize(); 81 return 0 == memcmp(&a,&b, sizeof(SkColorSpaceTransferFn)); 82 } 83 84 void SkColorSpace_New::TransferFn::updateICCProfile(ICCProfile*) const { 85 // TODO 86 } 87 88 // ~~~~~~~~~~~~~~~~~~~~~~~ SkColorSpace_New ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 89 90 SkColorSpace_New::SkColorSpace_New(sk_sp<TransferFn> transferFn, 91 SkMatrix44 toXYZD50, 92 Blending blending) 93 : fTransferFn(std::move(transferFn)) 94 , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) 95 , fToXYZD50(toXYZD50) 96 , fToXYZD50Hash(SkOpts::hash_fn(&toXYZD50, 16*sizeof(SkMScalar), 0)) 97 , fBlending(blending) 98 { 99 // It's pretty subtle what do to if the to-XYZ matrix is not invertible. 100 // That means the same point in XYZ is mapped to from more than one point in RGB, 101 // or put another way, we threw information away when mapping RGB -> XYZ. 102 // 103 // We'd probably like to set fToXYZD50 as one of the family of matrices that 104 // will correctly roundtrip XYZ -> RGB -> XYZ. Choosing which is an open problem. 105 SkAssertResult(fToXYZD50.invert(&fFromXYZD50)); 106 } 107 108 sk_sp<SkColorSpace> SkColorSpace_New::makeLinearGamma() const { 109 return sk_make_sp<SkColorSpace_New>(TransferFn::MakeLinear(), fToXYZD50, fBlending); 110 } 111 sk_sp<SkColorSpace> SkColorSpace_New::makeSRGBGamma() const { 112 return sk_make_sp<SkColorSpace_New>(TransferFn::MakeSRGB(), fToXYZD50, fBlending); 113 } 114 115 SkGammaNamed SkColorSpace_New::onGammaNamed() const { 116 return kNonStandard_SkGammaNamed; // TODO 117 } 118 119 bool SkColorSpace_New::onGammaCloseToSRGB() const { 120 return fTransferFn->equals(*TransferFn::MakeSRGB()); // TODO: more efficient? 121 } 122 123 bool SkColorSpace_New::onGammaIsLinear() const { 124 return fTransferFn->equals(*TransferFn::MakeLinear()); // TODO: more efficient? 125 } 126 127 bool SkColorSpace_New::onIsNumericalTransferFn(SkColorSpaceTransferFn* fn) const { 128 *fn = fTransferFn->parameterize(); 129 return true; 130 } 131