SkColorSpaceXform.cpp revision 1b93bd1e6eba3d14593490e4e24a34546638c8da
19876ac5b3016e5353c072378ac1545a0a2270757msarett/*
29876ac5b3016e5353c072378ac1545a0a2270757msarett * Copyright 2016 Google Inc.
39876ac5b3016e5353c072378ac1545a0a2270757msarett *
49876ac5b3016e5353c072378ac1545a0a2270757msarett * Use of this source code is governed by a BSD-style license that can be
59876ac5b3016e5353c072378ac1545a0a2270757msarett * found in the LICENSE file.
69876ac5b3016e5353c072378ac1545a0a2270757msarett */
79876ac5b3016e5353c072378ac1545a0a2270757msarett
89876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorPriv.h"
99876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorSpace_Base.h"
109876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorSpaceXform.h"
11a9e878c836994bce695274b4c28890290139dcdfmsarett#include "SkOpts.h"
12ac41bac40f5a80d2bc5ccec584c23478a6900179mtklein#include "SkSRGB.h"
139876ac5b3016e5353c072378ac1545a0a2270757msarett
146006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic constexpr float sk_linear_from_2dot2[256] = {
15b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
16b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
17b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
18b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
19b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
20b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
21b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
22b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
23b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
24b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
25b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
26b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
27b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
28b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
29b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
30b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
31b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
32b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
33b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
34b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
35b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
36b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
37b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
38b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
39b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
40b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
41b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
42b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
43b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
44b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
45b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
46b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
47b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
48b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
49b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
50b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
51b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
52b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
53b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
54b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
55b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
56b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
57b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
58b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
59b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
60b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
61b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
62b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
63b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
64b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
65b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
66b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
67b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
68b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
69b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
70b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
71b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
72b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
73b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
74b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
75b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
76b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
77b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
78b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
79b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
80b39067696ad08a26bbe49b71a71f0546dc42a075msarett
81b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic void build_table_linear_from_gamma(float* outTable, float exponent) {
82b39067696ad08a26bbe49b71a71f0546dc42a075msarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
83b39067696ad08a26bbe49b71a71f0546dc42a075msarett        *outTable++ = powf(x, exponent);
84b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
859876ac5b3016e5353c072378ac1545a0a2270757msarett}
869876ac5b3016e5353c072378ac1545a0a2270757msarett
87b39067696ad08a26bbe49b71a71f0546dc42a075msarett// Interpolating lookup in a variably sized table.
88b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float interp_lut(float input, const float* table, int tableSize) {
89b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float index = input * (tableSize - 1);
90b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float diff = index - sk_float_floor2int(index);
91b39067696ad08a26bbe49b71a71f0546dc42a075msarett    return table[(int) sk_float_floor2int(index)] * (1.0f - diff) +
92b39067696ad08a26bbe49b71a71f0546dc42a075msarett            table[(int) sk_float_ceil2int(index)] * diff;
93b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
94b39067696ad08a26bbe49b71a71f0546dc42a075msarett
95b39067696ad08a26bbe49b71a71f0546dc42a075msarett// outTable is always 256 entries, inTable may be larger or smaller.
96b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic void build_table_linear_from_gamma(float* outTable, const float* inTable,
97b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                          int inTableSize) {
98b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (256 == inTableSize) {
99b39067696ad08a26bbe49b71a71f0546dc42a075msarett        memcpy(outTable, inTable, sizeof(float) * 256);
100b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return;
101b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
102b39067696ad08a26bbe49b71a71f0546dc42a075msarett
103b39067696ad08a26bbe49b71a71f0546dc42a075msarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
104b39067696ad08a26bbe49b71a71f0546dc42a075msarett        *outTable++ = interp_lut(x, inTable, inTableSize);
105b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
106b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
107b39067696ad08a26bbe49b71a71f0546dc42a075msarett
108b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
109b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                          float d, float e, float f) {
110b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = (aX + b)^g + c  for X >= d
111b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = eX + f          otherwise
112b39067696ad08a26bbe49b71a71f0546dc42a075msarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
113b39067696ad08a26bbe49b71a71f0546dc42a075msarett        if (x >= d) {
114b39067696ad08a26bbe49b71a71f0546dc42a075msarett            *outTable++ = powf(a * x + b, g) + c;
115b39067696ad08a26bbe49b71a71f0546dc42a075msarett        } else {
116b39067696ad08a26bbe49b71a71f0546dc42a075msarett            *outTable++ = e * x + f;
117b39067696ad08a26bbe49b71a71f0546dc42a075msarett        }
118b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
119b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
120b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1216006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& srcToXYZ,
1226006f678e78af7b6f67a454cd4bc213048983f9dmsarett                                       const SkMatrix44& dstToXYZ) {
1236006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!dstToXYZ.invert(srcToDst)) {
1246006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return false;
1256006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
1266006f678e78af7b6f67a454cd4bc213048983f9dmsarett
1276006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDst->postConcat(srcToXYZ);
1286006f678e78af7b6f67a454cd4bc213048983f9dmsarett    return true;
1296006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
1306006f678e78af7b6f67a454cd4bc213048983f9dmsarett
1316006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
1326006f678e78af7b6f67a454cd4bc213048983f9dmsarett
133b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic constexpr uint8_t linear_to_srgb[1024] = {
134b39067696ad08a26bbe49b71a71f0546dc42a075msarett          0,   3,   6,  10,  13,  15,  18,  20,  22,  23,  25,  27,  28,  30,  31,  32,  34,  35,
135b39067696ad08a26bbe49b71a71f0546dc42a075msarett         36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  49,  50,  51,  52,
136b39067696ad08a26bbe49b71a71f0546dc42a075msarett         53,  53,  54,  55,  56,  56,  57,  58,  58,  59,  60,  61,  61,  62,  62,  63,  64,  64,
137b39067696ad08a26bbe49b71a71f0546dc42a075msarett         65,  66,  66,  67,  67,  68,  68,  69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,
138b39067696ad08a26bbe49b71a71f0546dc42a075msarett         75,  76,  76,  77,  77,  78,  78,  79,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,
139b39067696ad08a26bbe49b71a71f0546dc42a075msarett         84,  84,  85,  85,  85,  86,  86,  87,  87,  88,  88,  88,  89,  89,  90,  90,  91,  91,
140b39067696ad08a26bbe49b71a71f0546dc42a075msarett         91,  92,  92,  93,  93,  93,  94,  94,  95,  95,  95,  96,  96,  97,  97,  97,  98,  98,
141b39067696ad08a26bbe49b71a71f0546dc42a075msarett         98,  99,  99,  99, 100, 100, 101, 101, 101, 102, 102, 102, 103, 103, 103, 104, 104, 104,
142b39067696ad08a26bbe49b71a71f0546dc42a075msarett        105, 105, 106, 106, 106, 107, 107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110,
143b39067696ad08a26bbe49b71a71f0546dc42a075msarett        111, 111, 111, 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
144b39067696ad08a26bbe49b71a71f0546dc42a075msarett        116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120, 120, 120, 121, 121, 121, 121,
145b39067696ad08a26bbe49b71a71f0546dc42a075msarett        122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126,
146b39067696ad08a26bbe49b71a71f0546dc42a075msarett        127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131,
147b39067696ad08a26bbe49b71a71f0546dc42a075msarett        131, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135, 136, 136,
148b39067696ad08a26bbe49b71a71f0546dc42a075msarett        136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 140,
149b39067696ad08a26bbe49b71a71f0546dc42a075msarett        140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143, 143, 144, 144, 144, 144,
150b39067696ad08a26bbe49b71a71f0546dc42a075msarett        145, 145, 145, 145, 146, 146, 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, 148, 148,
151b39067696ad08a26bbe49b71a71f0546dc42a075msarett        149, 149, 149, 149, 150, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 152,
152b39067696ad08a26bbe49b71a71f0546dc42a075msarett        153, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155, 155, 156, 156, 156, 156,
153b39067696ad08a26bbe49b71a71f0546dc42a075msarett        156, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 159, 159, 159, 159, 159, 160, 160,
154b39067696ad08a26bbe49b71a71f0546dc42a075msarett        160, 160, 160, 161, 161, 161, 161, 161, 162, 162, 162, 162, 162, 163, 163, 163, 163, 163,
155b39067696ad08a26bbe49b71a71f0546dc42a075msarett        164, 164, 164, 164, 164, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 167, 167, 167,
156b39067696ad08a26bbe49b71a71f0546dc42a075msarett        167, 167, 168, 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170,
157b39067696ad08a26bbe49b71a71f0546dc42a075msarett        171, 171, 171, 171, 171, 171, 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, 173, 174,
158b39067696ad08a26bbe49b71a71f0546dc42a075msarett        174, 174, 174, 174, 175, 175, 175, 175, 175, 175, 176, 176, 176, 176, 176, 177, 177, 177,
159b39067696ad08a26bbe49b71a71f0546dc42a075msarett        177, 177, 177, 178, 178, 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, 180, 180, 180,
160b39067696ad08a26bbe49b71a71f0546dc42a075msarett        180, 180, 181, 181, 181, 181, 181, 181, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183,
161b39067696ad08a26bbe49b71a71f0546dc42a075msarett        183, 183, 184, 184, 184, 184, 184, 184, 185, 185, 185, 185, 185, 185, 186, 186, 186, 186,
162b39067696ad08a26bbe49b71a71f0546dc42a075msarett        186, 186, 187, 187, 187, 187, 187, 187, 188, 188, 188, 188, 188, 188, 189, 189, 189, 189,
163b39067696ad08a26bbe49b71a71f0546dc42a075msarett        189, 189, 190, 190, 190, 190, 190, 190, 191, 191, 191, 191, 191, 191, 191, 192, 192, 192,
164b39067696ad08a26bbe49b71a71f0546dc42a075msarett        192, 192, 192, 193, 193, 193, 193, 193, 193, 194, 194, 194, 194, 194, 194, 194, 195, 195,
165b39067696ad08a26bbe49b71a71f0546dc42a075msarett        195, 195, 195, 195, 196, 196, 196, 196, 196, 196, 197, 197, 197, 197, 197, 197, 197, 198,
166b39067696ad08a26bbe49b71a71f0546dc42a075msarett        198, 198, 198, 198, 198, 199, 199, 199, 199, 199, 199, 199, 200, 200, 200, 200, 200, 200,
167b39067696ad08a26bbe49b71a71f0546dc42a075msarett        200, 201, 201, 201, 201, 201, 201, 202, 202, 202, 202, 202, 202, 202, 203, 203, 203, 203,
168b39067696ad08a26bbe49b71a71f0546dc42a075msarett        203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 205, 205, 205, 205, 205, 205, 206, 206,
169b39067696ad08a26bbe49b71a71f0546dc42a075msarett        206, 206, 206, 206, 206, 207, 207, 207, 207, 207, 207, 207, 208, 208, 208, 208, 208, 208,
170b39067696ad08a26bbe49b71a71f0546dc42a075msarett        208, 209, 209, 209, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210, 210, 211, 211, 211,
171b39067696ad08a26bbe49b71a71f0546dc42a075msarett        211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213,
172b39067696ad08a26bbe49b71a71f0546dc42a075msarett        213, 214, 214, 214, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 216, 216, 216,
173b39067696ad08a26bbe49b71a71f0546dc42a075msarett        216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 218, 218, 218, 218, 218, 218,
174b39067696ad08a26bbe49b71a71f0546dc42a075msarett        218, 219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 221, 221,
175b39067696ad08a26bbe49b71a71f0546dc42a075msarett        221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222, 222, 222, 222, 223, 223, 223, 223,
176b39067696ad08a26bbe49b71a71f0546dc42a075msarett        223, 223, 223, 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 225,
177b39067696ad08a26bbe49b71a71f0546dc42a075msarett        225, 226, 226, 226, 226, 226, 226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228,
178b39067696ad08a26bbe49b71a71f0546dc42a075msarett        228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, 230,
179b39067696ad08a26bbe49b71a71f0546dc42a075msarett        230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232, 232, 232, 232,
180b39067696ad08a26bbe49b71a71f0546dc42a075msarett        232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234,
181b39067696ad08a26bbe49b71a71f0546dc42a075msarett        235, 235, 235, 235, 235, 235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 237,
182b39067696ad08a26bbe49b71a71f0546dc42a075msarett        237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 238, 238, 239, 239, 239,
183b39067696ad08a26bbe49b71a71f0546dc42a075msarett        239, 239, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, 241,
184b39067696ad08a26bbe49b71a71f0546dc42a075msarett        241, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243,
185b39067696ad08a26bbe49b71a71f0546dc42a075msarett        243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245,
186b39067696ad08a26bbe49b71a71f0546dc42a075msarett        245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247,
187b39067696ad08a26bbe49b71a71f0546dc42a075msarett        247, 247, 248, 248, 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249, 249, 249,
188b39067696ad08a26bbe49b71a71f0546dc42a075msarett        249, 249, 250, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251,
189b39067696ad08a26bbe49b71a71f0546dc42a075msarett        251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253,
190b39067696ad08a26bbe49b71a71f0546dc42a075msarett        253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255
191b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
192b39067696ad08a26bbe49b71a71f0546dc42a075msarett
193b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic constexpr uint8_t linear_to_2dot2[1024] = {
194b39067696ad08a26bbe49b71a71f0546dc42a075msarett          0,  11,  15,  18,  21,  23,  25,  26,  28,  30,  31,  32,  34,  35,  36,  37,  39,  40,
195b39067696ad08a26bbe49b71a71f0546dc42a075msarett         41,  42,  43,  44,  45,  45,  46,  47,  48,  49,  50,  50,  51,  52,  53,  54,  54,  55,
196b39067696ad08a26bbe49b71a71f0546dc42a075msarett         56,  56,  57,  58,  58,  59,  60,  60,  61,  62,  62,  63,  63,  64,  65,  65,  66,  66,
197b39067696ad08a26bbe49b71a71f0546dc42a075msarett         67,  68,  68,  69,  69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,  75,  75,  76,
198b39067696ad08a26bbe49b71a71f0546dc42a075msarett         76,  77,  77,  78,  78,  79,  79,  80,  80,  81,  81,  81,  82,  82,  83,  83,  84,  84,
199b39067696ad08a26bbe49b71a71f0546dc42a075msarett         84,  85,  85,  86,  86,  87,  87,  87,  88,  88,  89,  89,  89,  90,  90,  91,  91,  91,
200b39067696ad08a26bbe49b71a71f0546dc42a075msarett         92,  92,  93,  93,  93,  94,  94,  94,  95,  95,  96,  96,  96,  97,  97,  97,  98,  98,
201b39067696ad08a26bbe49b71a71f0546dc42a075msarett         98,  99,  99,  99, 100, 100, 101, 101, 101, 102, 102, 102, 103, 103, 103, 104, 104, 104,
202b39067696ad08a26bbe49b71a71f0546dc42a075msarett        105, 105, 105, 106, 106, 106, 107, 107, 107, 108, 108, 108, 108, 109, 109, 109, 110, 110,
203b39067696ad08a26bbe49b71a71f0546dc42a075msarett        110, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115,
204b39067696ad08a26bbe49b71a71f0546dc42a075msarett        116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 121,
205b39067696ad08a26bbe49b71a71f0546dc42a075msarett        121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125,
206b39067696ad08a26bbe49b71a71f0546dc42a075msarett        126, 126, 126, 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130,
207b39067696ad08a26bbe49b71a71f0546dc42a075msarett        130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135,
208b39067696ad08a26bbe49b71a71f0546dc42a075msarett        135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 138, 139, 139,
209b39067696ad08a26bbe49b71a71f0546dc42a075msarett        139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 142, 143, 143, 143,
210b39067696ad08a26bbe49b71a71f0546dc42a075msarett        143, 144, 144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 146, 147, 147, 147,
211b39067696ad08a26bbe49b71a71f0546dc42a075msarett        147, 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151,
212b39067696ad08a26bbe49b71a71f0546dc42a075msarett        151, 151, 152, 152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 154, 155, 155,
213b39067696ad08a26bbe49b71a71f0546dc42a075msarett        155, 155, 155, 156, 156, 156, 156, 156, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158,
214b39067696ad08a26bbe49b71a71f0546dc42a075msarett        159, 159, 159, 159, 159, 160, 160, 160, 160, 160, 161, 161, 161, 161, 161, 162, 162, 162,
215b39067696ad08a26bbe49b71a71f0546dc42a075msarett        162, 162, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 165, 165, 165, 165, 165, 165,
216b39067696ad08a26bbe49b71a71f0546dc42a075msarett        166, 166, 166, 166, 166, 167, 167, 167, 167, 167, 168, 168, 168, 168, 168, 168, 169, 169,
217b39067696ad08a26bbe49b71a71f0546dc42a075msarett        169, 169, 169, 170, 170, 170, 170, 170, 171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
218b39067696ad08a26bbe49b71a71f0546dc42a075msarett        172, 173, 173, 173, 173, 173, 173, 174, 174, 174, 174, 174, 174, 175, 175, 175, 175, 175,
219b39067696ad08a26bbe49b71a71f0546dc42a075msarett        176, 176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 178, 178, 178, 178, 178, 179,
220b39067696ad08a26bbe49b71a71f0546dc42a075msarett        179, 179, 179, 179, 179, 180, 180, 180, 180, 180, 180, 181, 181, 181, 181, 181, 181, 182,
221b39067696ad08a26bbe49b71a71f0546dc42a075msarett        182, 182, 182, 182, 182, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 184, 185, 185,
222b39067696ad08a26bbe49b71a71f0546dc42a075msarett        185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187, 187, 187, 187, 188,
223b39067696ad08a26bbe49b71a71f0546dc42a075msarett        188, 188, 188, 188, 188, 189, 189, 189, 189, 189, 189, 190, 190, 190, 190, 190, 190, 191,
224b39067696ad08a26bbe49b71a71f0546dc42a075msarett        191, 191, 191, 191, 191, 192, 192, 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, 193,
225b39067696ad08a26bbe49b71a71f0546dc42a075msarett        194, 194, 194, 194, 194, 194, 195, 195, 195, 195, 195, 195, 195, 196, 196, 196, 196, 196,
226b39067696ad08a26bbe49b71a71f0546dc42a075msarett        196, 197, 197, 197, 197, 197, 197, 197, 198, 198, 198, 198, 198, 198, 199, 199, 199, 199,
227b39067696ad08a26bbe49b71a71f0546dc42a075msarett        199, 199, 199, 200, 200, 200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 202, 202,
228b39067696ad08a26bbe49b71a71f0546dc42a075msarett        202, 202, 202, 202, 202, 203, 203, 203, 203, 203, 203, 204, 204, 204, 204, 204, 204, 204,
229b39067696ad08a26bbe49b71a71f0546dc42a075msarett        205, 205, 205, 205, 205, 205, 205, 206, 206, 206, 206, 206, 206, 206, 207, 207, 207, 207,
230b39067696ad08a26bbe49b71a71f0546dc42a075msarett        207, 207, 207, 208, 208, 208, 208, 208, 208, 209, 209, 209, 209, 209, 209, 209, 210, 210,
231b39067696ad08a26bbe49b71a71f0546dc42a075msarett        210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 212, 212,
232b39067696ad08a26bbe49b71a71f0546dc42a075msarett        212, 213, 213, 213, 213, 213, 213, 213, 213, 214, 214, 214, 214, 214, 214, 214, 215, 215,
233b39067696ad08a26bbe49b71a71f0546dc42a075msarett        215, 215, 215, 215, 215, 216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217,
234b39067696ad08a26bbe49b71a71f0546dc42a075msarett        217, 218, 218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 220, 220,
235b39067696ad08a26bbe49b71a71f0546dc42a075msarett        220, 220, 220, 220, 220, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222,
236b39067696ad08a26bbe49b71a71f0546dc42a075msarett        222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 224, 224, 224, 225,
237b39067696ad08a26bbe49b71a71f0546dc42a075msarett        225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 226, 226, 227, 227, 227,
238b39067696ad08a26bbe49b71a71f0546dc42a075msarett        227, 227, 227, 227, 228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229,
239b39067696ad08a26bbe49b71a71f0546dc42a075msarett        229, 229, 230, 230, 230, 230, 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 232,
240b39067696ad08a26bbe49b71a71f0546dc42a075msarett        232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 234, 234, 234,
241b39067696ad08a26bbe49b71a71f0546dc42a075msarett        234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235, 236, 236, 236, 236, 236,
242b39067696ad08a26bbe49b71a71f0546dc42a075msarett        236, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 238,
243b39067696ad08a26bbe49b71a71f0546dc42a075msarett        238, 238, 239, 239, 239, 239, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, 240,
244b39067696ad08a26bbe49b71a71f0546dc42a075msarett        241, 241, 241, 241, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243,
245b39067696ad08a26bbe49b71a71f0546dc42a075msarett        243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245,
246b39067696ad08a26bbe49b71a71f0546dc42a075msarett        245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247,
247b39067696ad08a26bbe49b71a71f0546dc42a075msarett        247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249,
248b39067696ad08a26bbe49b71a71f0546dc42a075msarett        249, 249, 249, 249, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251,
249b39067696ad08a26bbe49b71a71f0546dc42a075msarett        251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253,
250b39067696ad08a26bbe49b71a71f0546dc42a075msarett        253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255,
251b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
252b39067696ad08a26bbe49b71a71f0546dc42a075msarett
253a9e878c836994bce695274b4c28890290139dcdfmsarett// Expand range from 0-1 to 0-255, then convert.
254b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic uint8_t clamp_normalized_float_to_byte(float v) {
255dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // The ordering of the logic is a little strange here in order
256dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // to make sure we convert NaNs to 0.
2579876ac5b3016e5353c072378ac1545a0a2270757msarett    v = v * 255.0f;
258a9e878c836994bce695274b4c28890290139dcdfmsarett    if (v >= 254.5f) {
2599876ac5b3016e5353c072378ac1545a0a2270757msarett        return 255;
260dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else if (v >= 0.5f) {
2619876ac5b3016e5353c072378ac1545a0a2270757msarett        return (uint8_t) (v + 0.5f);
262dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else {
263dea0340cadb759932e53416a657f5ea75fee8b5fmsarett        return 0;
2649876ac5b3016e5353c072378ac1545a0a2270757msarett    }
2659876ac5b3016e5353c072378ac1545a0a2270757msarett}
2669876ac5b3016e5353c072378ac1545a0a2270757msarett
2671b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
268b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float toGammaExp = 1.0f / exponent;
269b39067696ad08a26bbe49b71a71f0546dc42a075msarett
2701b93bd1e6eba3d14593490e4e24a34546638c8damsarett    for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) {
2711b93bd1e6eba3d14593490e4e24a34546638c8damsarett        float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTableSize - 1)));
272b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
273b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
274dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
275dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
276dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// Inverse table lookup.  Ex: what index corresponds to the input value?  This will
277dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// have strange results when the table is non-increasing.  But any sane gamma
278dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// function will be increasing.
2791b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic float inverse_interp_lut(float input, const float* table, int tableSize) {
280dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    if (input <= table[0]) {
281dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        return table[0];
282dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    } else if (input >= table[tableSize - 1]) {
283dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        return 1.0f;
284dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
285dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
286b39067696ad08a26bbe49b71a71f0546dc42a075msarett    for (int i = 1; i < tableSize; i++) {
287dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        if (table[i] >= input) {
288dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            // We are guaranteed that input is greater than table[i - 1].
289dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float diff = input - table[i - 1];
290dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float distance = table[i] - table[i - 1];
291dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float index = (i - 1) + diff / distance;
292dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            return index / (tableSize - 1);
293dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        }
294dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
295dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
296dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    // Should be unreachable, since we'll return before the loop if input is
297dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    // larger than the last entry.
298dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    SkASSERT(false);
299dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    return 0.0f;
300dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
301dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
3021b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
303b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        int inTableSize) {
3041b93bd1e6eba3d14593490e4e24a34546638c8damsarett    for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) {
3051b93bd1e6eba3d14593490e4e24a34546638c8damsarett        float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTableSize - 1)));
306b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_interp_lut(x, inTable, inTableSize);
307b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
308b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
309b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
310dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
311b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
312b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                float f) {
313b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // We need to take the inverse of the following piecewise function.
314b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = (aX + b)^g + c  for X >= d
315b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = eX + f          otherwise
316b39067696ad08a26bbe49b71a71f0546dc42a075msarett
317b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Assume that the gamma function is continuous, or this won't make much sense anyway.
318b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Plug in |d| to the first equation to calculate the new piecewise interval.
319b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Then simply use the inverse of the original functions.
320b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float interval = e * d + f;
321b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (x < interval) {
322b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // X = (Y - F) / E
323b39067696ad08a26bbe49b71a71f0546dc42a075msarett        if (0.0f == e) {
324b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // The gamma curve for this segment is constant, so the inverse is undefined.
325b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // Since this is the lower segment, guess zero.
326b39067696ad08a26bbe49b71a71f0546dc42a075msarett            return 0.0f;
327b39067696ad08a26bbe49b71a71f0546dc42a075msarett        }
328b39067696ad08a26bbe49b71a71f0546dc42a075msarett
329b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return (x - f) / e;
330b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
331b39067696ad08a26bbe49b71a71f0546dc42a075msarett
332b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // X = ((Y - C)^(1 / G) - B) / A
333b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (0.0f == a || 0.0f == g) {
334b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // The gamma curve for this segment is constant, so the inverse is undefined.
335b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // Since this is the upper segment, guess one.
336b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
337b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
338b39067696ad08a26bbe49b71a71f0546dc42a075msarett
339b39067696ad08a26bbe49b71a71f0546dc42a075msarett    return (powf(x - c, 1.0f / g) - b) / a;
340b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
341b39067696ad08a26bbe49b71a71f0546dc42a075msarett
3421b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
343b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        float b, float c, float d, float e, float f) {
3441b93bd1e6eba3d14593490e4e24a34546638c8damsarett    for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) {
3451b93bd1e6eba3d14593490e4e24a34546638c8damsarett        float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTableSize - 1)));
346b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_parametric(x, g, a, b, c, d, e, f);
347b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
348b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
349b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
350b39067696ad08a26bbe49b71a71f0546dc42a075msarett
3516006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
3526006f678e78af7b6f67a454cd4bc213048983f9dmsarett
3531b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
3541b93bd1e6eba3d14593490e4e24a34546638c8damsarettstruct GammaFns {
3551b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* fSRGBTable;
3561b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* f2Dot2Table;
3571b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3581b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromValue)(T*, float);
3591b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromTable)(T*, const float*, int);
3601b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
3611b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
3621b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3631b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<float> kToLinear {
3641b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_srgb,
3651b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_2dot2,
3661b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
3671b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
3681b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
3691b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
3701b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3711b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<uint8_t> kFromLinear {
3721b93bd1e6eba3d14593490e4e24a34546638c8damsarett    linear_to_srgb,
3731b93bd1e6eba3d14593490e4e24a34546638c8damsarett    linear_to_2dot2,
3741b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
3751b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
3761b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
3771b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
3781b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3791b93bd1e6eba3d14593490e4e24a34546638c8damsarett// Build tables to transform src gamma to linear.
3801b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
3811b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
3821b93bd1e6eba3d14593490e4e24a34546638c8damsarett                               const sk_sp<SkColorSpace>& space, const GammaFns<T>& fns) {
3831b93bd1e6eba3d14593490e4e24a34546638c8damsarett    switch (space->gammaNamed()) {
3841b93bd1e6eba3d14593490e4e24a34546638c8damsarett        case SkColorSpace::kSRGB_GammaNamed:
3851b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
3861b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
3871b93bd1e6eba3d14593490e4e24a34546638c8damsarett        case SkColorSpace::k2Dot2Curve_GammaNamed:
3881b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
3891b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
3901b93bd1e6eba3d14593490e4e24a34546638c8damsarett        case SkColorSpace::kLinear_GammaNamed:
3911b93bd1e6eba3d14593490e4e24a34546638c8damsarett            (*fns.fBuildFromValue)(gammaTableStorage, 1.0f);
3921b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = gammaTableStorage;
3931b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
3941b93bd1e6eba3d14593490e4e24a34546638c8damsarett        default: {
3951b93bd1e6eba3d14593490e4e24a34546638c8damsarett            const SkGammas* gammas = as_CSB(space)->gammas();
3961b93bd1e6eba3d14593490e4e24a34546638c8damsarett            SkASSERT(gammas);
3971b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3981b93bd1e6eba3d14593490e4e24a34546638c8damsarett            for (int i = 0; i < 3; i++) {
3991b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (i > 0) {
4001b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // Check if this curve matches the first curve.  In this case, we can
4011b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // share the same table pointer.  This should almost always be true.
4021b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // I've never seen a profile where all three gamma curves didn't match.
4031b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // But it is possible that they won't.
4041b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    if (gammas->data(0) == gammas->data(i)) {
4051b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        outGammaTables[i] = outGammaTables[0];
4061b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        continue;
4071b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
4081b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
4091b93bd1e6eba3d14593490e4e24a34546638c8damsarett
4101b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (gammas->isNamed(i)) {
4111b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    switch (gammas->data(i).fNamed) {
4121b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        case SkColorSpace::kSRGB_GammaNamed:
4131b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = fns.fSRGBTable;
4141b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4151b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        case SkColorSpace::k2Dot2Curve_GammaNamed:
4161b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = fns.f2Dot2Table;
4171b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4181b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        case SkColorSpace::kLinear_GammaNamed:
4191b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
4201b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4211b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4221b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        default:
4231b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            SkASSERT(false);
4241b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4251b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
4261b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isValue(i)) {
4271b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
4281b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fValue);
4291b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4301b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isTable(i)) {
4311b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
4321b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fTable.fSize);
4331b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4341b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else {
4351b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    SkASSERT(gammas->isParametric(i));
4361b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    const SkGammas::Params& params = gammas->params(i);
4371b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
4381b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fA, params.fB, params.fC, params.fD, params.fE,
4391b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fF);
4401b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4411b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
4421b93bd1e6eba3d14593490e4e24a34546638c8damsarett            }
4431b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
4441b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
4451b93bd1e6eba3d14593490e4e24a34546638c8damsarett}
4461b93bd1e6eba3d14593490e4e24a34546638c8damsarett
4471b93bd1e6eba3d14593490e4e24a34546638c8damsarett///////////////////////////////////////////////////////////////////////////////////////////////////
4481b93bd1e6eba3d14593490e4e24a34546638c8damsarett
4496006f678e78af7b6f67a454cd4bc213048983f9dmsarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpace>& srcSpace,
4506006f678e78af7b6f67a454cd4bc213048983f9dmsarett                                                          const sk_sp<SkColorSpace>& dstSpace) {
4516006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!srcSpace || !dstSpace) {
4526006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // Invalid input
4536006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
4546006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4556006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4566006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (as_CSB(dstSpace)->colorLUT()) {
4576006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // It would be really weird for a dst profile to have a color LUT.  I don't think
4586006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // we need to support this.
4596006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
4606006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4616006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4626006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
4636006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())) {
4646006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
4656006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4666006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4676006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (0.0f == srcToDst.getFloat(3, 0) &&
4686006f678e78af7b6f67a454cd4bc213048983f9dmsarett        0.0f == srcToDst.getFloat(3, 1) &&
4696006f678e78af7b6f67a454cd4bc213048983f9dmsarett        0.0f == srcToDst.getFloat(3, 2) &&
4706006f678e78af7b6f67a454cd4bc213048983f9dmsarett        !as_CSB(srcSpace)->colorLUT())
4716006f678e78af7b6f67a454cd4bc213048983f9dmsarett    {
4726006f678e78af7b6f67a454cd4bc213048983f9dmsarett        switch (dstSpace->gammaNamed()) {
4736006f678e78af7b6f67a454cd4bc213048983f9dmsarett            case SkColorSpace::kSRGB_GammaNamed:
4746006f678e78af7b6f67a454cd4bc213048983f9dmsarett                return std::unique_ptr<SkColorSpaceXform>(
4756006f678e78af7b6f67a454cd4bc213048983f9dmsarett                        new SkFastXform<SkColorSpace::kSRGB_GammaNamed>(srcSpace, srcToDst,
4766006f678e78af7b6f67a454cd4bc213048983f9dmsarett                                                                        dstSpace));
4776006f678e78af7b6f67a454cd4bc213048983f9dmsarett            case SkColorSpace::k2Dot2Curve_GammaNamed:
4786006f678e78af7b6f67a454cd4bc213048983f9dmsarett                return std::unique_ptr<SkColorSpaceXform>(
4796006f678e78af7b6f67a454cd4bc213048983f9dmsarett                        new SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed>(srcSpace, srcToDst,
4806006f678e78af7b6f67a454cd4bc213048983f9dmsarett                                                                              dstSpace));
4816006f678e78af7b6f67a454cd4bc213048983f9dmsarett            default:
4826006f678e78af7b6f67a454cd4bc213048983f9dmsarett                return std::unique_ptr<SkColorSpaceXform>(
4836006f678e78af7b6f67a454cd4bc213048983f9dmsarett                        new SkFastXform<SkColorSpace::kNonStandard_GammaNamed>(srcSpace, srcToDst,
4846006f678e78af7b6f67a454cd4bc213048983f9dmsarett                                                                               dstSpace));
4856006f678e78af7b6f67a454cd4bc213048983f9dmsarett        }
4866006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4876006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4886006f678e78af7b6f67a454cd4bc213048983f9dmsarett    return std::unique_ptr<SkColorSpaceXform>(new SkDefaultXform(srcSpace, srcToDst, dstSpace));
4896006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
4906006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4916006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
4926006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4939ce3a543c92a73e6daca420defc042886b3f2019msarett// TODO (msarett):
4949ce3a543c92a73e6daca420defc042886b3f2019msarett// Once SkFastXform supports translation, delete this function and use asRowMajorf().
4956006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic void build_src_to_dst(float srcToDstArray[12], const SkMatrix44& srcToDstMatrix) {
4966006f678e78af7b6f67a454cd4bc213048983f9dmsarett    // Build the following row major matrix:
4976006f678e78af7b6f67a454cd4bc213048983f9dmsarett    //   rX gX bX 0
4986006f678e78af7b6f67a454cd4bc213048983f9dmsarett    //   rY gY bY 0
4996006f678e78af7b6f67a454cd4bc213048983f9dmsarett    //   rZ gZ bZ 0
5006006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[0] = srcToDstMatrix.getFloat(0, 0);
5016006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[1] = srcToDstMatrix.getFloat(0, 1);
5026006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[2] = srcToDstMatrix.getFloat(0, 2);
5036006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[3] = 0.0f;
5046006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[4] = srcToDstMatrix.getFloat(1, 0);
5056006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[5] = srcToDstMatrix.getFloat(1, 1);
5066006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[6] = srcToDstMatrix.getFloat(1, 2);
5076006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[7] = 0.0f;
5086006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[8] = srcToDstMatrix.getFloat(2, 0);
5096006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1);
5106006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2);
5116006f678e78af7b6f67a454cd4bc213048983f9dmsarett    srcToDstArray[11] = 0.0f;
5126006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
5136006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5146006f678e78af7b6f67a454cd4bc213048983f9dmsaretttemplate <SkColorSpace::GammaNamed Dst>
5156006f678e78af7b6f67a454cd4bc213048983f9dmsarettSkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst,
5166006f678e78af7b6f67a454cd4bc213048983f9dmsarett                              const sk_sp<SkColorSpace>& dstSpace)
5176006f678e78af7b6f67a454cd4bc213048983f9dmsarett{
5186006f678e78af7b6f67a454cd4bc213048983f9dmsarett    build_src_to_dst(fSrcToDst, srcToDst);
5191b93bd1e6eba3d14593490e4e24a34546638c8damsarett    build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kToLinear);
5201b93bd1e6eba3d14593490e4e24a34546638c8damsarett    build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::kDstGammaTableSize,
5211b93bd1e6eba3d14593490e4e24a34546638c8damsarett                       dstSpace, kFromLinear);
5226006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
5236006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5246006f678e78af7b6f67a454cd4bc213048983f9dmsaretttemplate <>
5256006f678e78af7b6f67a454cd4bc213048983f9dmsarettvoid SkFastXform<SkColorSpace::kSRGB_GammaNamed>
5269ce3a543c92a73e6daca420defc042886b3f2019msarett::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
5276006f678e78af7b6f67a454cd4bc213048983f9dmsarett{
5286006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst);
5296006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
5306006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5316006f678e78af7b6f67a454cd4bc213048983f9dmsaretttemplate <>
5326006f678e78af7b6f67a454cd4bc213048983f9dmsarettvoid SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed>
5339ce3a543c92a73e6daca420defc042886b3f2019msarett::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
5346006f678e78af7b6f67a454cd4bc213048983f9dmsarett{
5356006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkOpts::color_xform_RGB1_to_2dot2(dst, src, len, fSrcGammaTables, fSrcToDst);
5366006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
5376006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5386006f678e78af7b6f67a454cd4bc213048983f9dmsaretttemplate <>
5396006f678e78af7b6f67a454cd4bc213048983f9dmsarettvoid SkFastXform<SkColorSpace::kNonStandard_GammaNamed>
5409ce3a543c92a73e6daca420defc042886b3f2019msarett::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
5416006f678e78af7b6f67a454cd4bc213048983f9dmsarett{
5426006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkOpts::color_xform_RGB1_to_table(dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
5436006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
5446006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5459ce3a543c92a73e6daca420defc042886b3f2019msaretttemplate <SkColorSpace::GammaNamed T>
5469ce3a543c92a73e6daca420defc042886b3f2019msarettvoid SkFastXform<T>
5479ce3a543c92a73e6daca420defc042886b3f2019msarett::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
5489ce3a543c92a73e6daca420defc042886b3f2019msarett{
5499ce3a543c92a73e6daca420defc042886b3f2019msarett    SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst);
5509ce3a543c92a73e6daca420defc042886b3f2019msarett}
5519ce3a543c92a73e6daca420defc042886b3f2019msarett
5526006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
5536006f678e78af7b6f67a454cd4bc213048983f9dmsarett
554b39067696ad08a26bbe49b71a71f0546dc42a075msarettSkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst,
555b39067696ad08a26bbe49b71a71f0546dc42a075msarett                               const sk_sp<SkColorSpace>& dstSpace)
5560f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT()))
5570f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    , fSrcToDst(srcToDst)
558b39067696ad08a26bbe49b71a71f0546dc42a075msarett{
5591b93bd1e6eba3d14593490e4e24a34546638c8damsarett    build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kToLinear);
5601b93bd1e6eba3d14593490e4e24a34546638c8damsarett    build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::kDstGammaTableSize,
5611b93bd1e6eba3d14593490e4e24a34546638c8damsarett                       dstSpace, kFromLinear);
562b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
563b39067696ad08a26bbe49b71a71f0546dc42a075msarett
5640f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarettstatic float byte_to_float(uint8_t byte) {
5650f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    return ((float) byte) * (1.0f / 255.0f);
5660f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett}
5670f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
568b39067696ad08a26bbe49b71a71f0546dc42a075msarett// Clamp to the 0-1 range.
569b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float clamp_normalized_float(float v) {
570b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (v > 1.0f) {
571b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
572b39067696ad08a26bbe49b71a71f0546dc42a075msarett    } else if ((v < 0.0f) || (v != v)) {
573b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 0.0f;
574b39067696ad08a26bbe49b71a71f0546dc42a075msarett    } else {
575b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return v;
576b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
577b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
578b39067696ad08a26bbe49b71a71f0546dc42a075msarett
5790f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarettstatic void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable* colorLUT) {
5800f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Call the src components x, y, and z.
5810f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxX = colorLUT->fGridPoints[0] - 1;
5820f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxY = colorLUT->fGridPoints[1] - 1;
5830f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxZ = colorLUT->fGridPoints[2] - 1;
5840f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5850f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // An approximate index into each of the three dimensions of the table.
5860f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float x = src[0] * maxX;
5870f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float y = src[1] * maxY;
5880f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float z = src[2] * maxZ;
5890f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5900f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // This gives us the low index for our interpolation.
5910f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int ix = sk_float_floor2int(x);
5920f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int iy = sk_float_floor2int(y);
5930f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int iz = sk_float_floor2int(z);
5940f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5950f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Make sure the low index is not also the max index.
5960f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    ix = (maxX == ix) ? ix - 1 : ix;
5970f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    iy = (maxY == iy) ? iy - 1 : iy;
5980f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    iz = (maxZ == iz) ? iz - 1 : iz;
5990f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6000f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Weighting factors for the interpolation.
6010f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffX = x - ix;
6020f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffY = y - iy;
6030f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffZ = z - iz;
6040f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6050f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Constants to help us navigate the 3D table.
6060f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Ex: Assume x = a, y = b, z = c.
6070f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    //     table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c].
6080f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n000 = 0;
6090f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2];
6100f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n010 = 3 * colorLUT->fGridPoints[2];
6110f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n011 = n001 + n010;
6120f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n100 = 3;
6130f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n101 = n100 + n001;
6140f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n110 = n100 + n010;
6150f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n111 = n110 + n001;
6160f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6170f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Base ptr into the table.
6180f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float* ptr = &colorLUT->fTable[ix*n001 + iy*n010 + iz*n100];
6190f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6200f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // The code below performs a tetrahedral interpolation for each of the three
6210f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // dst components.  Once the tetrahedron containing the interpolation point is
6220f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // identified, the interpolation is a weighted sum of grid values at the
6230f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // vertices of the tetrahedron.  The claim is that tetrahedral interpolation
6240f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // provides a more accurate color conversion.
6250f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/
6260f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    //
6270f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // I have one test image, and visually I can't tell the difference between
6280f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral and trilinear interpolation.  In terms of computation, the
6290f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral code requires more branches but less computation.  The
6300f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // SampleICC library provides an option for the client to choose either
6310f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral or trilinear.
6320f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    for (int i = 0; i < 3; i++) {
6330f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        if (diffZ < diffY) {
6340f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            if (diffZ < diffX) {
6350f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) +
6360f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n010] - ptr[n000]) +
6370f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n111] - ptr[n110]));
6380f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else if (diffY < diffX) {
6390f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
6400f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n011] - ptr[n001]) +
6410f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n001] - ptr[n000]));
6420f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else {
6430f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
6440f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n010] - ptr[n000]) +
6450f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n011] - ptr[n010]));
6460f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            }
6470f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        } else {
6480f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            if (diffZ < diffX) {
6490f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) +
6500f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n111] - ptr[n101]) +
6510f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n001] - ptr[n000]));
6520f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else if (diffY < diffX) {
6530f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
6540f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n111] - ptr[n101]) +
6550f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n101] - ptr[n100]));
6560f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else {
6570f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
6580f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n110] - ptr[n100]) +
6590f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n111] - ptr[n110]));
6600f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            }
6610f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        }
6620f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6630f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // Increment the table ptr in order to handle the next component.
6640f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // Note that this is the how table is designed: all of nXXX
6650f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // variables are multiples of 3 because there are 3 output
6660f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // components.
6670f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        ptr++;
6680f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    }
6690f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett}
6700f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6719ce3a543c92a73e6daca420defc042886b3f2019msarettvoid SkDefaultXform::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const {
672b39067696ad08a26bbe49b71a71f0546dc42a075msarett    while (len-- > 0) {
6730f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        uint8_t r = (*src >>  0) & 0xFF,
6740f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                g = (*src >>  8) & 0xFF,
6750f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                b = (*src >> 16) & 0xFF;
6760f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6770f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        if (fColorLUT) {
6780f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            float in[3];
6790f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            float out[3];
6800f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6810f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            in[0] = byte_to_float(r);
6820f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            in[1] = byte_to_float(g);
6830f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            in[2] = byte_to_float(b);
6840f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6850f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            interp_3d_clut(out, in, fColorLUT.get());
6860f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6870f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            r = sk_float_round2int(255.0f * clamp_normalized_float(out[0]));
6880f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            g = sk_float_round2int(255.0f * clamp_normalized_float(out[1]));
6890f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            b = sk_float_round2int(255.0f * clamp_normalized_float(out[2]));
6900f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        }
6910f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
692b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // Convert to linear.
693b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float srcFloats[3];
6940f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        srcFloats[0] = fSrcGammaTables[0][r];
6950f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        srcFloats[1] = fSrcGammaTables[1][g];
6960f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        srcFloats[2] = fSrcGammaTables[2][b];
697dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
698dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        // Convert to dst gamut.
699dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        float dstFloats[3];
700dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        dstFloats[0] = srcFloats[0] * fSrcToDst.getFloat(0, 0) +
701dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett                       srcFloats[1] * fSrcToDst.getFloat(1, 0) +
702dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett                       srcFloats[2] * fSrcToDst.getFloat(2, 0) + fSrcToDst.getFloat(3, 0);
703dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        dstFloats[1] = srcFloats[0] * fSrcToDst.getFloat(0, 1) +
704dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett                       srcFloats[1] * fSrcToDst.getFloat(1, 1) +
705dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett                       srcFloats[2] * fSrcToDst.getFloat(2, 1) + fSrcToDst.getFloat(3, 1);
706dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        dstFloats[2] = srcFloats[0] * fSrcToDst.getFloat(0, 2) +
707dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett                       srcFloats[1] * fSrcToDst.getFloat(1, 2) +
708dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett                       srcFloats[2] * fSrcToDst.getFloat(2, 2) + fSrcToDst.getFloat(3, 2);
709dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
710b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // Clamp to 0-1.
711b39067696ad08a26bbe49b71a71f0546dc42a075msarett        dstFloats[0] = clamp_normalized_float(dstFloats[0]);
712b39067696ad08a26bbe49b71a71f0546dc42a075msarett        dstFloats[1] = clamp_normalized_float(dstFloats[1]);
713b39067696ad08a26bbe49b71a71f0546dc42a075msarett        dstFloats[2] = clamp_normalized_float(dstFloats[2]);
714b39067696ad08a26bbe49b71a71f0546dc42a075msarett
715dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        // Convert to dst gamma.
7160f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        r = fDstGammaTables[0][sk_float_round2int((kDstGammaTableSize - 1) * dstFloats[0])];
7170f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        g = fDstGammaTables[1][sk_float_round2int((kDstGammaTableSize - 1) * dstFloats[1])];
7180f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        b = fDstGammaTables[2][sk_float_round2int((kDstGammaTableSize - 1) * dstFloats[2])];
719dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
720b39067696ad08a26bbe49b71a71f0546dc42a075msarett        *dst = SkPackARGB32NoCheck(0xFF, r, g, b);
721dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
722dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        dst++;
723dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        src++;
724dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
725dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
7269ce3a543c92a73e6daca420defc042886b3f2019msarett
7279ce3a543c92a73e6daca420defc042886b3f2019msarettvoid SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const {
7289ce3a543c92a73e6daca420defc042886b3f2019msarett    // FIXME (msarett):
7299ce3a543c92a73e6daca420defc042886b3f2019msarett    // Planning to delete SkDefaultXform.  Not going to bother to implement this.
7309ce3a543c92a73e6daca420defc042886b3f2019msarett    memset(dst, 0, len * sizeof(RGBAF16));
7319ce3a543c92a73e6daca420defc042886b3f2019msarett}
732