SkColorSpaceXform.cpp revision c0444615ed76360f680619ad4d1f92cda6181a50
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"
10200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkColorSpacePriv.h"
119876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorSpaceXform.h"
12200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkHalf.h"
13200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkOpts.h"
14ac41bac40f5a80d2bc5ccec584c23478a6900179mtklein#include "SkSRGB.h"
159876ac5b3016e5353c072378ac1545a0a2270757msarett
166006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic constexpr float sk_linear_from_2dot2[256] = {
17b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
18b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
19b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
20b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
21b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
22b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
23b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
24b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
25b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
26b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
27b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
28b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
29b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
30b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
31b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
32b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
33b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
34b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
35b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
36b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
37b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
38b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
39b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
40b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
41b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
42b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
43b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
44b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
45b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
46b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
47b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
48b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
49b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
50b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
51b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
52b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
53b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
54b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
55b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
56b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
57b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
58b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
59b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
60b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
61b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
62b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
63b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
64b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
65b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
66b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
67b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
68b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
69b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
70b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
71b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
72b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
73b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
74b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
75b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
76b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
77b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
78b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
79b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
80b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
81b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
82b39067696ad08a26bbe49b71a71f0546dc42a075msarett
836006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
846006f678e78af7b6f67a454cd4bc213048983f9dmsarett
8515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float exponent) {
8615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
8715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = powf(x, exponent);
8815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
8915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
9015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
9115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// Interpolating lookup in a variably sized table.
9215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic float interp_lut(float input, const float* table, int tableSize) {
9315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    float index = input * (tableSize - 1);
9415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    float diff = index - sk_float_floor2int(index);
9515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    return table[(int) sk_float_floor2int(index)] * (1.0f - diff) +
9615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            table[(int) sk_float_ceil2int(index)] * diff;
9715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
9815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
9915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// outTable is always 256 entries, inTable may be larger or smaller.
10015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, const float* inTable,
10115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          int inTableSize) {
10215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    if (256 == inTableSize) {
10315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        memcpy(outTable, inTable, sizeof(float) * 256);
10415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        return;
10515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
10615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
10715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
10815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = interp_lut(x, inTable, inTableSize);
10915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
11015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
11115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
11215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
11315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          float d, float e, float f) {
11415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = (aX + b)^g + c  for X >= d
11515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = eX + f          otherwise
11615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
11715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        if (x >= d) {
11815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            *outTable++ = powf(a * x + b, g) + c;
11915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        } else {
12015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            *outTable++ = e * x + f;
12115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        }
12215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
12315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
12415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
12515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
12615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
127a9e878c836994bce695274b4c28890290139dcdfmsarett// Expand range from 0-1 to 0-255, then convert.
128b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic uint8_t clamp_normalized_float_to_byte(float v) {
129dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // The ordering of the logic is a little strange here in order
130dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // to make sure we convert NaNs to 0.
1319876ac5b3016e5353c072378ac1545a0a2270757msarett    v = v * 255.0f;
132a9e878c836994bce695274b4c28890290139dcdfmsarett    if (v >= 254.5f) {
1339876ac5b3016e5353c072378ac1545a0a2270757msarett        return 255;
134dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else if (v >= 0.5f) {
1359876ac5b3016e5353c072378ac1545a0a2270757msarett        return (uint8_t) (v + 0.5f);
136dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else {
137dea0340cadb759932e53416a657f5ea75fee8b5fmsarett        return 0;
1389876ac5b3016e5353c072378ac1545a0a2270757msarett    }
1399876ac5b3016e5353c072378ac1545a0a2270757msarett}
1409876ac5b3016e5353c072378ac1545a0a2270757msarett
1413418c0e797e2ee841d1c031ca9d7a5ba73205f51msarettstatic const int kDstGammaTableSize =
1428bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        SkColorSpaceXform_Base<kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
143200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        ::kDstGammaTableSize;
1443418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1451b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
146b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float toGammaExp = 1.0f / exponent;
147b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1483418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
1493418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
150b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
151b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
152dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
153dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
154dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// Inverse table lookup.  Ex: what index corresponds to the input value?  This will
155dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// have strange results when the table is non-increasing.  But any sane gamma
156dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// function will be increasing.
1571b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic float inverse_interp_lut(float input, const float* table, int tableSize) {
158dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    if (input <= table[0]) {
159dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        return table[0];
160dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    } else if (input >= table[tableSize - 1]) {
161dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        return 1.0f;
162dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
163dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
164b39067696ad08a26bbe49b71a71f0546dc42a075msarett    for (int i = 1; i < tableSize; i++) {
165dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        if (table[i] >= input) {
166dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            // We are guaranteed that input is greater than table[i - 1].
167dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float diff = input - table[i - 1];
168dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float distance = table[i] - table[i - 1];
169dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float index = (i - 1) + diff / distance;
170dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            return index / (tableSize - 1);
171dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        }
172dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
173dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
174dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    // Should be unreachable, since we'll return before the loop if input is
175dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    // larger than the last entry.
176dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    SkASSERT(false);
177dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    return 0.0f;
178dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
179dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
1801b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
181b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        int inTableSize) {
1823418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
1833418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
184b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_interp_lut(x, inTable, inTableSize);
185b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
186b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
187b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
188dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
189b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
190b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                float f) {
191b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // We need to take the inverse of the following piecewise function.
192b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = (aX + b)^g + c  for X >= d
193b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = eX + f          otherwise
194b39067696ad08a26bbe49b71a71f0546dc42a075msarett
195b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Assume that the gamma function is continuous, or this won't make much sense anyway.
196b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Plug in |d| to the first equation to calculate the new piecewise interval.
197b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Then simply use the inverse of the original functions.
198b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float interval = e * d + f;
199b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (x < interval) {
200b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // X = (Y - F) / E
201b39067696ad08a26bbe49b71a71f0546dc42a075msarett        if (0.0f == e) {
202b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // The gamma curve for this segment is constant, so the inverse is undefined.
203b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // Since this is the lower segment, guess zero.
204b39067696ad08a26bbe49b71a71f0546dc42a075msarett            return 0.0f;
205b39067696ad08a26bbe49b71a71f0546dc42a075msarett        }
206b39067696ad08a26bbe49b71a71f0546dc42a075msarett
207b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return (x - f) / e;
208b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
209b39067696ad08a26bbe49b71a71f0546dc42a075msarett
210b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // X = ((Y - C)^(1 / G) - B) / A
211b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (0.0f == a || 0.0f == g) {
212b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // The gamma curve for this segment is constant, so the inverse is undefined.
213b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // Since this is the upper segment, guess one.
214b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
215b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
216b39067696ad08a26bbe49b71a71f0546dc42a075msarett
217b39067696ad08a26bbe49b71a71f0546dc42a075msarett    return (powf(x - c, 1.0f / g) - b) / a;
218b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
219b39067696ad08a26bbe49b71a71f0546dc42a075msarett
2201b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
221b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        float b, float c, float d, float e, float f) {
2223418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
2233418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
224b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_parametric(x, g, a, b, c, d, e, f);
225b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
226b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
227b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
228b39067696ad08a26bbe49b71a71f0546dc42a075msarett
2296006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
2306006f678e78af7b6f67a454cd4bc213048983f9dmsarett
2311b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
2321b93bd1e6eba3d14593490e4e24a34546638c8damsarettstruct GammaFns {
2331b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* fSRGBTable;
2341b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* f2Dot2Table;
2351b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromValue)(T*, float);
2361b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromTable)(T*, const float*, int);
2371b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
2381b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2391b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2401b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<float> kToLinear {
2411b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_srgb,
2421b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_2dot2,
2431b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
2441b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
2451b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
2461b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2471b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2481b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<uint8_t> kFromLinear {
24955bcc8e0af3415601b3d62252a0d579fbe87c85amsarett    nullptr,
25055bcc8e0af3415601b3d62252a0d579fbe87c85amsarett    nullptr,
2511b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2521b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2531b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2541b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2551b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2561b93bd1e6eba3d14593490e4e24a34546638c8damsarett// Build tables to transform src gamma to linear.
2571b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
2581b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
2597bbda991af353fbe6b34132132d211d23a3dba8cmsarett                               const sk_sp<SkColorSpace>& space, const GammaFns<T>& fns,
2607bbda991af353fbe6b34132132d211d23a3dba8cmsarett                               bool gammasAreMatching) {
261600c737b64eae2c7379442ae2c852853cce3a278msarett    switch (as_CSB(space)->gammaNamed()) {
262600c737b64eae2c7379442ae2c852853cce3a278msarett        case kSRGB_SkGammaNamed:
2631b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
2641b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
265600c737b64eae2c7379442ae2c852853cce3a278msarett        case k2Dot2Curve_SkGammaNamed:
2661b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
2671b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
268600c737b64eae2c7379442ae2c852853cce3a278msarett        case kLinear_SkGammaNamed:
2698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr;
2701b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
2711b93bd1e6eba3d14593490e4e24a34546638c8damsarett        default: {
2721b93bd1e6eba3d14593490e4e24a34546638c8damsarett            const SkGammas* gammas = as_CSB(space)->gammas();
2731b93bd1e6eba3d14593490e4e24a34546638c8damsarett            SkASSERT(gammas);
2741b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2757bbda991af353fbe6b34132132d211d23a3dba8cmsarett            auto build_table = [=](int i) {
2761b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (gammas->isNamed(i)) {
2771b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    switch (gammas->data(i).fNamed) {
278600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kSRGB_SkGammaNamed:
27955bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f,
28055bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                                                   (1.0f / 1.055f), (0.055f / 1.055f), 0.0f,
28155bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                                                   0.04045f, (1.0f / 12.92f), 0.0f);
28255bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2831b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
284600c737b64eae2c7379442ae2c852853cce3a278msarett                        case k2Dot2Curve_SkGammaNamed:
28555bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f);
28655bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2871b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
288600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kLinear_SkGammaNamed:
2891b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
2901b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2911b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2921b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        default:
2931b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            SkASSERT(false);
2941b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2951b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
2961b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isValue(i)) {
2971b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
2981b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fValue);
2991b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
3001b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isTable(i)) {
3011b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
3021b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fTable.fSize);
3031b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
3041b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else {
3051b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    SkASSERT(gammas->isParametric(i));
3061b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    const SkGammas::Params& params = gammas->params(i);
3071b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
3081b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fA, params.fB, params.fC, params.fD, params.fE,
3091b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fF);
3101b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
3111b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
3127bbda991af353fbe6b34132132d211d23a3dba8cmsarett            };
3137bbda991af353fbe6b34132132d211d23a3dba8cmsarett
3147bbda991af353fbe6b34132132d211d23a3dba8cmsarett            if (gammasAreMatching) {
3157bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
3167bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[1] = outGammaTables[0];
3177bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[2] = outGammaTables[0];
3187bbda991af353fbe6b34132132d211d23a3dba8cmsarett            } else {
3197bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
3207bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(1);
3217bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(2);
3221b93bd1e6eba3d14593490e4e24a34546638c8damsarett            }
3237bbda991af353fbe6b34132132d211d23a3dba8cmsarett
3247bbda991af353fbe6b34132132d211d23a3dba8cmsarett            break;
3251b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
3261b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
3271b93bd1e6eba3d14593490e4e24a34546638c8damsarett}
3281b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3291b93bd1e6eba3d14593490e4e24a34546638c8damsarett///////////////////////////////////////////////////////////////////////////////////////////////////
3301b93bd1e6eba3d14593490e4e24a34546638c8damsarett
331200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline bool is_almost_identity(const SkMatrix44& srcToDst) {
332200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    for (int i = 0; i < 4; i++) {
333200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        for (int j = 0; j < 4; j++) {
334200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            float expected = (i == j) ? 1.0f : 0.0f;
335200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) {
336200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                return false;
337200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
338200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
339200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
340200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return true;
341200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
342200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
34315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
34415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
3456006f678e78af7b6f67a454cd4bc213048983f9dmsarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpace>& srcSpace,
3466006f678e78af7b6f67a454cd4bc213048983f9dmsarett                                                          const sk_sp<SkColorSpace>& dstSpace) {
3476006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!srcSpace || !dstSpace) {
3486006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // Invalid input
3496006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
3506006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3516006f678e78af7b6f67a454cd4bc213048983f9dmsarett
352200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    ColorSpaceMatch csm = kNone_ColorSpaceMatch;
3536006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
354200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (SkColorSpace::Equals(srcSpace.get(), dstSpace.get())) {
355200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        srcToDst.setIdentity();
356200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        csm = kFull_ColorSpaceMatch;
357971cd496b9e25f87f3a75a0015c203322907136abrianosman    } else {
358de68d6c4616d86621373d88100002ddfdb9c08e3brianosman        srcToDst.setConcat(as_CSB(dstSpace)->fromXYZD50(), srcSpace->toXYZD50());
359971cd496b9e25f87f3a75a0015c203322907136abrianosman
360971cd496b9e25f87f3a75a0015c203322907136abrianosman        if (is_almost_identity(srcToDst)) {
361971cd496b9e25f87f3a75a0015c203322907136abrianosman            srcToDst.setIdentity();
362971cd496b9e25f87f3a75a0015c203322907136abrianosman            csm = kGamut_ColorSpaceMatch;
363971cd496b9e25f87f3a75a0015c203322907136abrianosman        }
3646006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3656006f678e78af7b6f67a454cd4bc213048983f9dmsarett
366200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    switch (csm) {
367200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kNone_ColorSpaceMatch:
368600c737b64eae2c7379442ae2c852853cce3a278msarett            switch (as_CSB(dstSpace)->gammaNamed()) {
369600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
3708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
3718bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
3728bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch>
3738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
3748bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
3758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
3768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch>
3778bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
3788bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
379600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
3808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
3818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
3828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch>
3838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
3848bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
3858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
3868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch>
3878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
3888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
3898bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
3908bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
3918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
3928bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch>
3938bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
3948bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
3958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
3968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch>
3978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
3988bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
399200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
4008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
4018bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
4038bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
4058bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
4078bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
409200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
410200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kGamut_ColorSpaceMatch:
411600c737b64eae2c7379442ae2c852853cce3a278msarett            switch (as_CSB(dstSpace)->gammaNamed()) {
412600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
4138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
4148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4158bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch>
4168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
4188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch>
4208bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4218bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
422600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
4238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
4248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4258bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch>
4268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
4288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch>
4308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
4328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
4338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
4348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch>
4368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
4388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch>
4408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
442200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
4438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    if (srcSpace->gammaIsLinear()) {
4448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch>
4468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4478bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
4488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4498bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch>
4508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                (srcSpace, srcToDst, dstSpace));
4518bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
452200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
453200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kFull_ColorSpaceMatch:
454600c737b64eae2c7379442ae2c852853cce3a278msarett            switch (as_CSB(dstSpace)->gammaNamed()) {
455600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
456200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, kSRGB_DstGamma, kFull_ColorSpaceMatch>
458200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
459600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
460200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, k2Dot2_DstGamma, kFull_ColorSpaceMatch>
4628bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (srcSpace, srcToDst, dstSpace));
4638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
4648bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kLinear_SrcGamma, kLinear_DstGamma, kFull_ColorSpaceMatch>
466200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
467200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
468200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
4698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, kTable_DstGamma, kFull_ColorSpaceMatch>
470200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
471200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
4723418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        default:
473200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            SkASSERT(false);
474200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            return nullptr;
4756006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4766006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
4776006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4786006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
4796006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4800f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarettstatic float byte_to_float(uint8_t byte) {
4810f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    return ((float) byte) * (1.0f / 255.0f);
4820f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett}
4830f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
484b39067696ad08a26bbe49b71a71f0546dc42a075msarett// Clamp to the 0-1 range.
485b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float clamp_normalized_float(float v) {
486b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (v > 1.0f) {
487b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
488b39067696ad08a26bbe49b71a71f0546dc42a075msarett    } else if ((v < 0.0f) || (v != v)) {
489b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 0.0f;
490b39067696ad08a26bbe49b71a71f0546dc42a075msarett    } else {
491b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return v;
492b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
493b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
494b39067696ad08a26bbe49b71a71f0546dc42a075msarett
4950f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarettstatic void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable* colorLUT) {
4960f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Call the src components x, y, and z.
4970f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxX = colorLUT->fGridPoints[0] - 1;
4980f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxY = colorLUT->fGridPoints[1] - 1;
4990f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxZ = colorLUT->fGridPoints[2] - 1;
5000f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5010f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // An approximate index into each of the three dimensions of the table.
5020f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float x = src[0] * maxX;
5030f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float y = src[1] * maxY;
5040f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float z = src[2] * maxZ;
5050f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5060f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // This gives us the low index for our interpolation.
5070f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int ix = sk_float_floor2int(x);
5080f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int iy = sk_float_floor2int(y);
5090f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int iz = sk_float_floor2int(z);
5100f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5110f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Make sure the low index is not also the max index.
5120f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    ix = (maxX == ix) ? ix - 1 : ix;
5130f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    iy = (maxY == iy) ? iy - 1 : iy;
5140f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    iz = (maxZ == iz) ? iz - 1 : iz;
5150f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5160f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Weighting factors for the interpolation.
5170f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffX = x - ix;
5180f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffY = y - iy;
5190f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffZ = z - iz;
5200f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5210f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Constants to help us navigate the 3D table.
5220f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Ex: Assume x = a, y = b, z = c.
5230f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    //     table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c].
5240f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n000 = 0;
5250f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2];
5260f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n010 = 3 * colorLUT->fGridPoints[2];
5270f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n011 = n001 + n010;
5280f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n100 = 3;
5290f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n101 = n100 + n001;
5300f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n110 = n100 + n010;
5310f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n111 = n110 + n001;
5320f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5330f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Base ptr into the table.
534959d45b43357a40854938586c303177c6aa53220msarett    const float* ptr = &(colorLUT->table()[ix*n001 + iy*n010 + iz*n100]);
5350f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5360f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // The code below performs a tetrahedral interpolation for each of the three
5370f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // dst components.  Once the tetrahedron containing the interpolation point is
5380f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // identified, the interpolation is a weighted sum of grid values at the
5390f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // vertices of the tetrahedron.  The claim is that tetrahedral interpolation
5400f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // provides a more accurate color conversion.
5410f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/
5420f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    //
5430f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // I have one test image, and visually I can't tell the difference between
5440f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral and trilinear interpolation.  In terms of computation, the
5450f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral code requires more branches but less computation.  The
5460f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // SampleICC library provides an option for the client to choose either
5470f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral or trilinear.
5480f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    for (int i = 0; i < 3; i++) {
5490f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        if (diffZ < diffY) {
5500f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            if (diffZ < diffX) {
5510f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) +
5520f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n010] - ptr[n000]) +
5530f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n111] - ptr[n110]));
5540f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else if (diffY < diffX) {
5550f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
5560f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n011] - ptr[n001]) +
5570f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n001] - ptr[n000]));
5580f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else {
5590f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
5600f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n010] - ptr[n000]) +
5610f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n011] - ptr[n010]));
5620f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            }
5630f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        } else {
5640f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            if (diffZ < diffX) {
5650f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) +
5660f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n111] - ptr[n101]) +
5670f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n001] - ptr[n000]));
5680f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else if (diffY < diffX) {
5690f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
5700f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n111] - ptr[n101]) +
5710f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n101] - ptr[n100]));
5720f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else {
5730f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
5740f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n110] - ptr[n100]) +
5750f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n111] - ptr[n110]));
5760f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            }
5770f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        }
5780f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5790f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // Increment the table ptr in order to handle the next component.
5800f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // Note that this is the how table is designed: all of nXXX
5810f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // variables are multiples of 3 because there are 3 output
5820f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // components.
5830f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        ptr++;
5840f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    }
5850f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett}
5860f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5873418c0e797e2ee841d1c031ca9d7a5ba73205f51msarettstatic void handle_color_lut(uint32_t* dst, const uint32_t* src, int len,
5883418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett                             SkColorLookUpTable* colorLUT) {
589b39067696ad08a26bbe49b71a71f0546dc42a075msarett    while (len-- > 0) {
5900f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        uint8_t r = (*src >>  0) & 0xFF,
5910f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                g = (*src >>  8) & 0xFF,
5920f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                b = (*src >> 16) & 0xFF;
5930f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5943418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float in[3];
5953418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float out[3];
5963418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[0] = byte_to_float(r);
5973418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[1] = byte_to_float(g);
5983418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[2] = byte_to_float(b);
5993418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        interp_3d_clut(out, in, colorLUT);
6000f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6013418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        r = sk_float_round2int(255.0f * clamp_normalized_float(out[0]));
6023418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        g = sk_float_round2int(255.0f * clamp_normalized_float(out[1]));
6033418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        b = sk_float_round2int(255.0f * clamp_normalized_float(out[2]));
6043418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        *dst = SkPackARGB_as_RGBA(0xFF, r, g, b);
6050f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6063418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        src++;
6073418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        dst++;
6083418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    }
6093418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
6100f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
611200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_matrix(const float matrix[16],
612200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
613200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rXgXbX = Sk4f::Load(matrix +  0);
614200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rYgYbY = Sk4f::Load(matrix +  4);
615200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rZgZbZ = Sk4f::Load(matrix +  8);
616200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rTgTbT = Sk4f::Load(matrix + 12);
617200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
618200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
619200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables(const uint32_t* src,
620200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
621200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        const float* const srcTables[3]) {
622200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = { srcTables[0][(src[0] >>  0) & 0xFF],
623200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[1] >>  0) & 0xFF],
624200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[2] >>  0) & 0xFF],
625200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[3] >>  0) & 0xFF], };
626200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = { srcTables[1][(src[0] >>  8) & 0xFF],
627200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[1] >>  8) & 0xFF],
628200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[2] >>  8) & 0xFF],
629200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[3] >>  8) & 0xFF], };
630200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = { srcTables[2][(src[0] >> 16) & 0xFF],
631200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[1] >> 16) & 0xFF],
632200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[2] >> 16) & 0xFF],
633200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[3] >> 16) & 0xFF], };
634200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
635200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
636200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
637200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables(const uint32_t* src,
638200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
639200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         const float* const srcTables[3]) {
640200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = { srcTables[0][(src[0] >>  0) & 0xFF],
641200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[1] >>  0) & 0xFF],
642200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[2] >>  0) & 0xFF],
643200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[3] >>  0) & 0xFF], };
644200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = { srcTables[1][(src[0] >>  8) & 0xFF],
645200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[1] >>  8) & 0xFF],
646200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[2] >>  8) & 0xFF],
647200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[3] >>  8) & 0xFF], };
648200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = { srcTables[2][(src[0] >> 16) & 0xFF],
649200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[1] >> 16) & 0xFF],
650200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[2] >> 16) & 0xFF],
651200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[3] >> 16) & 0xFF], };
652200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
653200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
654200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
6558bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgb_linear(const uint32_t* src,
656be362774f9b9e8964544a579281603ed995e6e5amsarett                                   Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
6578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const float* const[3]) {
6588bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src)      ) & 0xFF);
6598bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >>  8) & 0xFF);
6608bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 16) & 0xFF);
661be362774f9b9e8964544a579281603ed995e6e5amsarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
6628bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
6648bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgba_linear(const uint32_t* src,
6658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
6668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    const float* const[3]) {
6678bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src)      ) & 0xFF);
6688bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >>  8) & 0xFF);
6698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 16) & 0xFF);
6708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    a = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 24)       );
6718bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6728bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
673200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables_1(const uint32_t* src,
674200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&,
675200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          const float* const srcTables[3]) {
676200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // Splat r,g,b across a register each.
677200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = Sk4f(srcTables[0][(*src >>  0) & 0xFF]);
678200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = Sk4f(srcTables[1][(*src >>  8) & 0xFF]);
679200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = Sk4f(srcTables[2][(*src >> 16) & 0xFF]);
680200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
681200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
682200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables_1(const uint32_t* src,
683200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
684200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           const float* const srcTables[3]) {
685200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // Splat r,g,b across a register each.
686200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = Sk4f(srcTables[0][(*src >>  0) & 0xFF]);
687200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = Sk4f(srcTables[1][(*src >>  8) & 0xFF]);
688200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = Sk4f(srcTables[2][(*src >> 16) & 0xFF]);
689200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * Sk4f(*src >> 24);
690200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
691200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
6928bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgb_linear_1(const uint32_t* src,
6938bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                     Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&,
6948bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                     const float* const srcTables[3]) {
6958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    // Splat r,g,b across a register each.
6968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    r = Sk4f((1.0f / 255.0f) * ((*src      ) & 0xFF));
6978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    g = Sk4f((1.0f / 255.0f) * ((*src >>  8) & 0xFF));
6988bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> 16) & 0xFF));
6998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7018bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgba_linear_1(const uint32_t* src,
7028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
7038bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      const float* const srcTables[3]) {
7048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    // Splat r,g,b,a across a register each.
7058bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    r = Sk4f((1.0f / 255.0f) * ((*src      ) & 0xFF));
7068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    g = Sk4f((1.0f / 255.0f) * ((*src >>  8) & 0xFF));
7078bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> 16) & 0xFF));
7088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    a = Sk4f((1.0f / 255.0f) * ((*src >> 24)       ));
7098bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7108bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
711200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
712200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
713200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
714200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
715200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
716200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
717200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    da = a;
718200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
719200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
720200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
721200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
722200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     Sk4f& rgba) {
723200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
724200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
725200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
726200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
727200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = dr + rTgTbT[0];
728200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = dg + rTgTbT[1];
729200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = db + rTgTbT[2];
730200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
731200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
732200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
733200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rgba + rTgTbT;
734200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
735200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
736200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) {
737200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = da * dr;
738200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = da * dg;
739200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = da * db;
740200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
741200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
742200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply_1(const Sk4f& a, Sk4f& rgba) {
743200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = a * rgba;
744200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
745200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
7468bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum SwapRB {
7478bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kNo_SwapRB,
7488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kYes_SwapRB,
7498bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
7508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7518bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
752200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb(void* dst, const uint32_t* src,
753200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                              Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
7548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                              const uint8_t* const[3]) {
755200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kRShift = 0;
756200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kGShift = 8;
757200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kBShift = 16;
758200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
759200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kBShift = 0;
760200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kRShift = 16;
761200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
762200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
763200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_linear_to_srgb_needs_trunc(dr);
764200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_linear_to_srgb_needs_trunc(dg);
765200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_linear_to_srgb_needs_trunc(db);
766200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
767200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
768200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
769200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
770200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
771200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
772200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
773200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
774200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(dg) << kGShift)
775200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(db) << kBShift)
776200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                           );
777200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
778200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
779200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
7808bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
781200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb_1(void* dst, const uint32_t* src,
782200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                Sk4f& rgba, const Sk4f&,
7838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                const uint8_t* const[3]) {
784200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
785200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
786200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
787200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
788200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
789200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
790200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
791200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
792200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
793200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
794200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
795200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
796200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline Sk4f linear_to_2dot2(const Sk4f& x) {
797200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
798200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    auto x2  = x.rsqrt(),                            // x^(-1/2)
799200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(),   // x^(-1/32)
800200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x64 = x32.rsqrt();                          // x^(+1/64)
801200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
802200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // 29 = 32 - 2 - 1
803200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return 255.0f * x2.invert() * x32 * x64.invert();
804200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
805200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
8068bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
807200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2(void* dst, const uint32_t* src,
808200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
8098bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
810200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kRShift = 0;
811200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kGShift = 8;
812200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kBShift = 16;
813200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
814200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kBShift = 0;
815200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kRShift = 16;
816200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
817200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
818200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = linear_to_2dot2(dr);
819200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = linear_to_2dot2(dg);
820200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = linear_to_2dot2(db);
821200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
822200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
823200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
824200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
825200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
826200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
827200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
828200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
829200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(dg) << kGShift)
830200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(db) << kBShift)
831200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                       );
832200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
833200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
834200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
8358bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
836200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2_1(void* dst, const uint32_t* src,
837200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& rgba, const Sk4f&,
8388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const uint8_t* const[3]) {
839200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
840200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
841200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
842200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
843200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
844200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
845200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
846200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
847200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
848200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
849200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
850200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
8518bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
8528bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void store_linear(void* dst, const uint32_t* src,
8538bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
8548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
8558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    int kRShift = 0;
8568bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    int kGShift = 8;
8578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    int kBShift = 16;
8588bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    if (kYes_SwapRB == kSwapRB) {
8598bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        kBShift = 0;
8608bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        kRShift = 16;
8618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
8628bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
863591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dr = sk_clamp_0_255(255.0f * dr);
864591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dg = sk_clamp_0_255(255.0f * dg);
865591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    db = sk_clamp_0_255(255.0f * db);
8668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8678bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
8688bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
8708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(dg) << kGShift)
8718bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(db) << kBShift)
8728bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (da                       );
8738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    rgba.store(dst);
8748bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
8758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8768bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
8778bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void store_linear_1(void* dst, const uint32_t* src,
8788bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  Sk4f& rgba, const Sk4f&,
8798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  const uint8_t* const[3]) {
880591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    rgba = sk_clamp_0_255(255.0f * rgba);
8818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    uint32_t tmp;
8838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
8848bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
8858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    if (kYes_SwapRB == kSwapRB) {
8868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        tmp = SkSwizzle_RB(tmp);
8878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
8888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8898bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    *(uint32_t*)dst = tmp;
8908bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
8918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8928bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
893200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16(void* dst, const uint32_t* src,
894200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                             Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
8958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const uint8_t* const[3]) {
8968ae991e433d2c0814ea5579613f00173805ff057mtklein    Sk4h_store4(dst, SkFloatToHalf_finite_ftz(dr),
8978ae991e433d2c0814ea5579613f00173805ff057mtklein                     SkFloatToHalf_finite_ftz(dg),
8988ae991e433d2c0814ea5579613f00173805ff057mtklein                     SkFloatToHalf_finite_ftz(db),
8998ae991e433d2c0814ea5579613f00173805ff057mtklein                     SkFloatToHalf_finite_ftz(da));
900200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
901200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
9028bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
903200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1(void* dst, const uint32_t* src,
904200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rgba, const Sk4f& a,
9058bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
906200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
9078ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst);
908200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
909200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
9108bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
911c0444615ed76360f680619ad4d1f92cda6181a50msarettstatic inline void store_f32(void* dst, const uint32_t* src,
912c0444615ed76360f680619ad4d1f92cda6181a50msarett                             Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
913c0444615ed76360f680619ad4d1f92cda6181a50msarett                             const uint8_t* const[3]) {
914c0444615ed76360f680619ad4d1f92cda6181a50msarett    Sk4f_store4(dst, dr, dg, db, da);
915c0444615ed76360f680619ad4d1f92cda6181a50msarett}
916c0444615ed76360f680619ad4d1f92cda6181a50msarett
917c0444615ed76360f680619ad4d1f92cda6181a50msaretttemplate <SwapRB kSwapRB>
918c0444615ed76360f680619ad4d1f92cda6181a50msarettstatic inline void store_f32_1(void* dst, const uint32_t* src,
919c0444615ed76360f680619ad4d1f92cda6181a50msarett                               Sk4f& rgba, const Sk4f& a,
920c0444615ed76360f680619ad4d1f92cda6181a50msarett                               const uint8_t* const[3]) {
921c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
922c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba.store((float*) dst);
923c0444615ed76360f680619ad4d1f92cda6181a50msarett}
924c0444615ed76360f680619ad4d1f92cda6181a50msarett
925c0444615ed76360f680619ad4d1f92cda6181a50msaretttemplate <SwapRB kSwapRB>
926200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_opaque(void* dst, const uint32_t* src,
927c0444615ed76360f680619ad4d1f92cda6181a50msarett                                    Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
9288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    const uint8_t* const[3]) {
9298ae991e433d2c0814ea5579613f00173805ff057mtklein    Sk4h_store4(dst, SkFloatToHalf_finite_ftz(dr),
9308ae991e433d2c0814ea5579613f00173805ff057mtklein                     SkFloatToHalf_finite_ftz(dg),
9318ae991e433d2c0814ea5579613f00173805ff057mtklein                     SkFloatToHalf_finite_ftz(db),
932200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                     SK_Half1);
933200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
934200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
9358bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
936200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1_opaque(void* dst, const uint32_t* src,
937c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      Sk4f& rgba, const Sk4f&,
9388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      const uint8_t* const[3]) {
939200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint64_t tmp;
9408ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store(&tmp);
941200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp |= static_cast<uint64_t>(SK_Half1) << 48;
942200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *((uint64_t*) dst) = tmp;
943200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
944200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
9458bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
946200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic(void* dst, const uint32_t* src,
947200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
9488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const uint8_t* const dstTables[3]) {
949200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kRShift = 0;
950200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kGShift = 8;
951200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kBShift = 16;
952200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
953200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kBShift = 0;
954200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kRShift = 16;
955200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
956200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
957200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
958200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
959200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
960200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
961200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ir = Sk4f_round(dr);
962200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ig = Sk4f_round(dg);
963200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ib = Sk4f_round(db);
964200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
965200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
966200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
967200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t* dst32 = (uint32_t*) dst;
968200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[0] = dstTables[0][ir[0]] << kRShift
969200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[0]] << kGShift
970200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[0]] << kBShift
971200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[0];
972200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[1] = dstTables[0][ir[1]] << kRShift
973200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[1]] << kGShift
974200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[1]] << kBShift
975200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[1];
976200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[2] = dstTables[0][ir[2]] << kRShift
977200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[2]] << kGShift
978200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[2]] << kBShift
979200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[2];
980200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[3] = dstTables[0][ir[3]] << kRShift
981200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[3]] << kGShift
982200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[3]] << kBShift
983200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[3];
984200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
985200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
9868bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SwapRB kSwapRB>
987200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic_1(void* dst, const uint32_t* src,
988200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& rgba, const Sk4f&,
9898bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const uint8_t* const dstTables[3]) {
9909dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    int kRShift = 0;
9919dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    int kGShift = 8;
9929dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    int kBShift = 16;
9939dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    if (kYes_SwapRB == kSwapRB) {
9949dc6cf6b8833d36c29a23d2519989b069745fcd5msarett        kBShift = 0;
9959dc6cf6b8833d36c29a23d2519989b069745fcd5msarett        kRShift = 16;
9969dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    }
9979dc6cf6b8833d36c29a23d2519989b069745fcd5msarett
998200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
999200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1000200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i indices = Sk4f_round(rgba);
1001200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10029dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
10039dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[1][indices[1]] << kGShift
10049dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[2][indices[2]] << kBShift
1005200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | (*src & 0xFF000000);
1006200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
1007200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10088bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttypedef decltype(load_rgb_from_tables       )* LoadFn;
10098bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttypedef decltype(load_rgb_from_tables_1     )* Load1Fn;
10108bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttypedef decltype(store_generic<kNo_SwapRB>  )* StoreFn;
10118bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttypedef decltype(store_generic_1<kNo_SwapRB>)* Store1Fn;
10128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
10138bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SkAlphaType kAlphaType,
10148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          ColorSpaceMatch kCSM>
10158bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void do_color_xform(void* dst, const uint32_t* src, int len,
10168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  const float* const srcTables[3], const float matrix[16],
10178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  const uint8_t* const dstTables[3], LoadFn load, Load1Fn load_1,
10188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  StoreFn store, Store1Fn store_1, size_t sizeOfDstPixel) {
1019200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
1020200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
1021200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1022200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (len >= 4) {
1023200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        // Naively this would be a loop of load-transform-store, but we found it faster to
1024200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        // move the N+1th load ahead of the Nth store.  We don't bother doing this for N<4.
1025200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f r, g, b, a;
1026200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        load(src, r, g, b, a, srcTables);
1027200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        src += 4;
1028200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        len -= 4;
1029200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1030200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f dr, dg, db, da;
1031200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        while (len >= 4) {
1032200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (kNone_ColorSpaceMatch == kCSM) {
1033200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1034200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                translate_gamut(rTgTbT, dr, dg, db);
1035200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            } else {
1036200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                dr = r;
1037200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                dg = g;
1038200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                db = b;
1039200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                da = a;
1040200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
1041200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1042200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (kPremul_SkAlphaType == kAlphaType) {
1043200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                premultiply(dr, dg, db, da);
1044200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
1045200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1046200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load(src, r, g, b, a, srcTables);
1047200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store(dst, src - 4, dr, dg, db, da, dstTables);
1049200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1050200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            src += 4;
1051200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            len -= 4;
1052200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1053200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1054200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kNone_ColorSpaceMatch == kCSM) {
1055200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1056200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            translate_gamut(rTgTbT, dr, dg, db);
1057200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        } else {
1058200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dr = r;
1059200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dg = g;
1060200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            db = b;
1061200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            da = a;
1062200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1063200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1064200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kPremul_SkAlphaType == kAlphaType) {
1065200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            premultiply(dr, dg, db, da);
1066200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1067200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10688bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        store(dst, src - 4, dr, dg, db, da, dstTables);
1069200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1070200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1071200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1072200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    while (len > 0) {
1073200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f r, g, b, a;
1074200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        load_1(src, r, g, b, a, srcTables);
1075200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1076200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f rgba;
1077200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kNone_ColorSpaceMatch == kCSM) {
1078200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
1079200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            translate_gamut_1(rTgTbT, rgba);
1080200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        } else {
1081200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            rgba = Sk4f(r[0], g[0], b[0], a[0]);
1082200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1083200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1084200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kPremul_SkAlphaType == kAlphaType) {
1085200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            premultiply_1(a, rgba);
1086200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1087200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        store_1(dst, src, rgba, a, dstTables);
1089200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1090200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        src += 1;
1091200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        len -= 1;
1092200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
1093200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1094200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
1095200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10968bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum SrcFormat {
10978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Linear_SrcFormat,
10988bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Table_SrcFormat,
10998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
11008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11018bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum DstFormat {
11028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    k8888_Linear_DstFormat,
11038bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    k8888_SRGB_DstFormat,
11048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    k8888_2Dot2_DstFormat,
11058bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    k8888_Table_DstFormat,
11068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kF16_Linear_DstFormat,
1107c0444615ed76360f680619ad4d1f92cda6181a50msarett    kF32_Linear_DstFormat,
11088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
11098bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11108bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcFormat kSrc,
11118bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          DstFormat kDst,
11128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          SkAlphaType kAlphaType,
11138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          ColorSpaceMatch kCSM,
11148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          SwapRB kSwapRB>
11158bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic void color_xform_RGBA(void* dst, const uint32_t* src, int len,
11168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const float* const srcTables[3], const float matrix[16],
11178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const uint8_t* const dstTables[3]) {
11188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    LoadFn load;
11198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Load1Fn load_1;
1120c0444615ed76360f680619ad4d1f92cda6181a50msarett    static constexpr bool loadAlpha = (kPremul_SkAlphaType == kAlphaType) ||
1121c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF16_Linear_DstFormat == kDst) ||
1122c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF32_Linear_DstFormat == kDst);
11238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kSrc) {
11248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Linear_SrcFormat:
1125c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
11268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load = load_rgba_linear;
11278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load_1 = load_rgba_linear_1;
11288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
11298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load = load_rgb_linear;
11308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load_1 = load_rgb_linear_1;
11318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
11328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Table_SrcFormat:
1134c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
11358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load = load_rgba_from_tables;
11368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load_1 = load_rgba_from_tables_1;
11378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
11388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load = load_rgb_from_tables;
11398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                load_1 = load_rgb_from_tables_1;
11408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
11418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11428bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
11438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    StoreFn store;
11458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Store1Fn store_1;
11468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    size_t sizeOfDstPixel;
11478bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kDst) {
11488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case k8888_Linear_DstFormat:
11498bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store   = store_linear<kSwapRB>;
11508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store_1 = store_linear_1<kSwapRB>;
11518bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
11528bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11538bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case k8888_SRGB_DstFormat:
11548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store   = store_srgb<kSwapRB>;
11558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store_1 = store_srgb_1<kSwapRB>;
11568bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
11578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11588bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case k8888_2Dot2_DstFormat:
11598bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store   = store_2dot2<kSwapRB>;
11608bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store_1 = store_2dot2_1<kSwapRB>;
11618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
11628bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case k8888_Table_DstFormat:
11648bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store   = store_generic<kSwapRB>;
11658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store_1 = store_generic_1<kSwapRB>;
11668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
11678bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11688bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kF16_Linear_DstFormat:
11698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store   = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque<kSwapRB> :
11708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                                            store_f16<kSwapRB>;
11718bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque<kSwapRB> :
11728bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                                            store_f16_1<kSwapRB>;
11738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 8;
11748bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1175c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kF32_Linear_DstFormat:
1176c0444615ed76360f680619ad4d1f92cda6181a50msarett            store   = store_f32<kSwapRB>;
1177c0444615ed76360f680619ad4d1f92cda6181a50msarett            store_1 = store_f32_1<kSwapRB>;
1178c0444615ed76360f680619ad4d1f92cda6181a50msarett            sizeOfDstPixel = 16;
1179c0444615ed76360f680619ad4d1f92cda6181a50msarett            break;
11808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
11818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    do_color_xform<kAlphaType, kCSM>
11838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            (dst, src, len, srcTables, matrix, dstTables, load, load_1, store, store_1,
11848bbcd5aab81dc0742c3367479c0c9d97363b1203msarett             sizeOfDstPixel);
11858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
11868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11873418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett///////////////////////////////////////////////////////////////////////////////////////////////////
11880f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
11897bbda991af353fbe6b34132132d211d23a3dba8cmsarettstatic inline int num_tables(SkColorSpace* space) {
11907bbda991af353fbe6b34132132d211d23a3dba8cmsarett    switch (as_CSB(space)->gammaNamed()) {
11917bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kSRGB_SkGammaNamed:
11927bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case k2Dot2Curve_SkGammaNamed:
11937bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kLinear_SkGammaNamed:
11947bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return 0;
11957bbda991af353fbe6b34132132d211d23a3dba8cmsarett        default: {
11967bbda991af353fbe6b34132132d211d23a3dba8cmsarett            const SkGammas* gammas = as_CSB(space)->gammas();
11977bbda991af353fbe6b34132132d211d23a3dba8cmsarett            SkASSERT(gammas);
11987bbda991af353fbe6b34132132d211d23a3dba8cmsarett
11997bbda991af353fbe6b34132132d211d23a3dba8cmsarett            bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
12007bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(1)) &&
12017bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->type(0) == gammas->type(2)) &&
12027bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(2));
12037bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12047bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // It's likely that each component will have the same gamma.  In this case,
12057bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // we only need to build one table.
12067bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return gammasAreMatching ? 1 : 3;
12077bbda991af353fbe6b34132132d211d23a3dba8cmsarett        }
12087bbda991af353fbe6b34132132d211d23a3dba8cmsarett    }
12097bbda991af353fbe6b34132132d211d23a3dba8cmsarett}
12107bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12118bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
12128bbcd5aab81dc0742c3367479c0c9d97363b1203msarettSkColorSpaceXform_Base<kSrc, kDst, kCSM>
12138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett::SkColorSpaceXform_Base(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst,
12148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                         const sk_sp<SkColorSpace>& dstSpace)
12153418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT()))
12163418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1217de68d6c4616d86621373d88100002ddfdb9c08e3brianosman    srcToDst.asColMajorf(fSrcToDst);
12187bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12197bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const int numSrcTables = num_tables(srcSpace.get());
12207bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const int numDstTables = num_tables(dstSpace.get());
12217bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const size_t srcTableBytes = numSrcTables * 256 * sizeof(float);
12227bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const size_t dstTableBytes = numDstTables * kDstGammaTableSize * sizeof(uint8_t);
12237bbda991af353fbe6b34132132d211d23a3dba8cmsarett    fStorage.reset(srcTableBytes + dstTableBytes);
12247bbda991af353fbe6b34132132d211d23a3dba8cmsarett    float* srcStorage = (float*) fStorage.get();
12257bbda991af353fbe6b34132132d211d23a3dba8cmsarett    uint8_t* dstStorage = SkTAddOffset<uint8_t>(fStorage.get(), srcTableBytes);
12267bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12277bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const bool srcGammasAreMatching = (1 >= numSrcTables);
12287bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const bool dstGammasAreMatching = (1 >= numDstTables);
12297bbda991af353fbe6b34132132d211d23a3dba8cmsarett    build_gamma_tables(fSrcGammaTables, srcStorage, 256, srcSpace, kToLinear, srcGammasAreMatching);
12307bbda991af353fbe6b34132132d211d23a3dba8cmsarett    build_gamma_tables(fDstGammaTables, dstStorage, kDstGammaTableSize, dstSpace, kFromLinear,
12317bbda991af353fbe6b34132132d211d23a3dba8cmsarett                       dstGammasAreMatching);
12323418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
1233dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
12347bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
12357bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12368bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM, SwapRB kSwap>
12378bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void apply_set_alpha(void* dst, const uint32_t* src, int len, SkAlphaType alphaType,
12388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const float* const srcTables[3], const float matrix[16],
12398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const uint8_t* const dstTables[3]) {
12408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (alphaType) {
12418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kOpaque_SkAlphaType:
12428bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            return color_xform_RGBA<kSrc, kDst, kOpaque_SkAlphaType, kCSM, kSwap>
12438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
12448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kPremul_SkAlphaType:
12458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            return color_xform_RGBA<kSrc, kDst, kPremul_SkAlphaType, kCSM, kSwap>
12468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
12478bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kUnpremul_SkAlphaType:
12488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            return color_xform_RGBA<kSrc, kDst, kUnpremul_SkAlphaType, kCSM, kSwap>
12498bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
12508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        default:
12518bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            SkASSERT(false);
12528bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            return;
12538bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
12548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
12558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
12568bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstFormat kDst, ColorSpaceMatch kCSM, SwapRB kSwap>
12578bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void apply_set_src(void* dst, const uint32_t* src, int len, SkAlphaType alphaType,
12588bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const float* const srcTables[3], const float matrix[16],
12598bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const uint8_t* const dstTables[3]) {
12608bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kSrc) {
12618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kLinear_SrcGamma:
12628bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            return apply_set_alpha<kRGBA_8888_Linear_SrcFormat, kDst, kCSM, kSwap>
12638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, alphaType, nullptr, matrix, dstTables);
12648bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kTable_SrcGamma:
12658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            return apply_set_alpha<kRGBA_8888_Table_SrcFormat, kDst, kCSM, kSwap>
12668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, alphaType, srcTables, matrix, dstTables);
12678bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
12688bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
12698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
12708bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
12718bbcd5aab81dc0742c3367479c0c9d97363b1203msarettvoid SkColorSpaceXform_Base<kSrc, kDst, kCSM>
1272c0444615ed76360f680619ad4d1f92cda6181a50msarett::apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, SkAlphaType alphaType)
1273d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarettconst
12743418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1275200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kFull_ColorSpaceMatch == kCSM) {
12768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        switch (alphaType) {
1277200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            case kPremul_SkAlphaType:
1278200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // We can't skip the xform since we need to perform a premultiply in the
1279200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // linear space.
1280200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                break;
1281200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            default:
1282c0444615ed76360f680619ad4d1f92cda6181a50msarett                switch (dstColorFormat) {
1283c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_8888_ColorFormat:
1284200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        return (void) memcpy(dst, src, len * sizeof(uint32_t));
1285c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kBGRA_8888_ColorFormat:
1286200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        return SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
1287c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F16_ColorFormat:
1288c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F32_ColorFormat:
1289c0444615ed76360f680619ad4d1f92cda6181a50msarett                        // There's still work to do to xform to linear floats.
1290200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        break;
1291200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    default:
1292200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        SkASSERT(false);
1293200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        return;
1294200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                }
1295200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1296200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1297200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
12983418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    if (fColorLUT) {
1299d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        size_t storageBytes = len * sizeof(uint32_t);
13003418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#if defined(GOOGLE3)
13013418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        // Stack frame size is limited in GOOGLE3.
1302d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        SkAutoSMalloc<256 * sizeof(uint32_t)> storage(storageBytes);
13033418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#else
1304d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        SkAutoSMalloc<1024 * sizeof(uint32_t)> storage(storageBytes);
13053418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#endif
13063418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1307d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get());
1308d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        src = (const uint32_t*) storage.get();
13093418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    }
13103418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1311c0444615ed76360f680619ad4d1f92cda6181a50msarett    switch (dstColorFormat) {
1312c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_8888_ColorFormat:
13138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
13148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
13158bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_Linear_DstFormat, kCSM, kNo_SwapRB>
13168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
13178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
13188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_SRGB_DstFormat, kCSM, kNo_SwapRB>
13198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
13208bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
13218bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_2Dot2_DstFormat, kCSM, kNo_SwapRB>
13228bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
13238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
13248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_Table_DstFormat, kCSM, kNo_SwapRB>
13258bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1326d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1327c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kBGRA_8888_ColorFormat:
13288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
13298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
13308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_Linear_DstFormat, kCSM, kYes_SwapRB>
13318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
13328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
13338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_SRGB_DstFormat, kCSM, kYes_SwapRB>
13348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
13358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
13368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_2Dot2_DstFormat, kCSM, kYes_SwapRB>
13378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
13388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
13398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, k8888_Table_DstFormat, kCSM, kYes_SwapRB>
13408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1341d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1342c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F16_ColorFormat:
13438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
13448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
13458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    return apply_set_src<kSrc, kF16_Linear_DstFormat, kCSM, kNo_SwapRB>
13468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
1347d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
1348d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    SkASSERT(false);
1349d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    return;
1350d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1351c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F32_ColorFormat:
1352c0444615ed76360f680619ad4d1f92cda6181a50msarett            switch (kDst) {
1353c0444615ed76360f680619ad4d1f92cda6181a50msarett                case kLinear_DstGamma:
1354c0444615ed76360f680619ad4d1f92cda6181a50msarett                    return apply_set_src<kSrc, kF32_Linear_DstFormat, kCSM, kNo_SwapRB>
1355c0444615ed76360f680619ad4d1f92cda6181a50msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr);
1356c0444615ed76360f680619ad4d1f92cda6181a50msarett                default:
1357c0444615ed76360f680619ad4d1f92cda6181a50msarett                    SkASSERT(false);
1358c0444615ed76360f680619ad4d1f92cda6181a50msarett                    return;
1359c0444615ed76360f680619ad4d1f92cda6181a50msarett            }
1360d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        default:
1361d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            SkASSERT(false);
1362d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            return;
1363d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett    }
13649ce3a543c92a73e6daca420defc042886b3f2019msarett}
13659dc6cf6b8833d36c29a23d2519989b069745fcd5msarett
13667bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
13677bbda991af353fbe6b34132132d211d23a3dba8cmsarett
13689dc6cf6b8833d36c29a23d2519989b069745fcd5msarettstd::unique_ptr<SkColorSpaceXform> SlowIdentityXform(const sk_sp<SkColorSpace>& space) {
13699dc6cf6b8833d36c29a23d2519989b069745fcd5msarett        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
13708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
13719dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                (space, SkMatrix::I(), space));
13729dc6cf6b8833d36c29a23d2519989b069745fcd5msarett}
1373