SkColorSpaceXform.cpp revision df44fc5f2bb282557df291e20dbd26c070533aa6
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"
1131d097e865f266c8398f45114e4c75c0dfdef058msarett#include "SkColorSpaceXform_Base.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,
2594be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett                               SkColorSpace* space, const GammaFns<T>& fns, bool gammasAreMatching)
2604be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett{
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));
306df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett                    const SkColorSpaceTransferFn& 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
3454be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace,
3464be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett                                                          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);
3544be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    if (SkColorSpace::Equals(srcSpace, dstSpace)) {
355200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        srcToDst.setIdentity();
356200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        csm = kFull_ColorSpaceMatch;
357971cd496b9e25f87f3a75a0015c203322907136abrianosman    } else {
3587802c3db24effa6f3186bff7490a2a8dd85d2a70msarett        srcToDst.setConcat(as_CSB(dstSpace)->fromXYZD50(), as_CSB(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
58731d097e865f266c8398f45114e4c75c0dfdef058msarettstatic void handle_color_lut(uint32_t* dst, const void* vsrc, int len,
5883418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett                             SkColorLookUpTable* colorLUT) {
58931d097e865f266c8398f45114e4c75c0dfdef058msarett    const uint32_t* src = (const uint32_t*) vsrc;
590b39067696ad08a26bbe49b71a71f0546dc42a075msarett    while (len-- > 0) {
5910f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        uint8_t r = (*src >>  0) & 0xFF,
5920f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                g = (*src >>  8) & 0xFF,
5930f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                b = (*src >> 16) & 0xFF;
5940f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5953418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float in[3];
5963418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float out[3];
5973418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[0] = byte_to_float(r);
5983418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[1] = byte_to_float(g);
5993418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[2] = byte_to_float(b);
6003418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        interp_3d_clut(out, in, colorLUT);
6010f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6023418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        r = sk_float_round2int(255.0f * clamp_normalized_float(out[0]));
6033418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        g = sk_float_round2int(255.0f * clamp_normalized_float(out[1]));
6043418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        b = sk_float_round2int(255.0f * clamp_normalized_float(out[2]));
6053418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        *dst = SkPackARGB_as_RGBA(0xFF, r, g, b);
6060f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6073418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        src++;
6083418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        dst++;
6093418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    }
6103418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
6110f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
612200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_matrix(const float matrix[16],
613200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
614200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rXgXbX = Sk4f::Load(matrix +  0);
615200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rYgYbY = Sk4f::Load(matrix +  4);
616200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rZgZbZ = Sk4f::Load(matrix +  8);
617200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rTgTbT = Sk4f::Load(matrix + 12);
618200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
619200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
620cf7b877d62537672b67449bc96858cc1262be5f8msarettenum Order {
621cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_Order,
622cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_Order,
623cf7b877d62537672b67449bc96858cc1262be5f8msarett};
624cf7b877d62537672b67449bc96858cc1262be5f8msarett
625cf7b877d62537672b67449bc96858cc1262be5f8msarettstatic inline void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) {
626cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kRGBA_Order == kOrder) {
627cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 0;
628cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 16;
629cf7b877d62537672b67449bc96858cc1262be5f8msarett    } else {
630cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 16;
631cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 0;
632cf7b877d62537672b67449bc96858cc1262be5f8msarett    }
633cf7b877d62537672b67449bc96858cc1262be5f8msarett}
634cf7b877d62537672b67449bc96858cc1262be5f8msarett
635cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
636200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables(const uint32_t* src,
637200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
638200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        const float* const srcTables[3]) {
639cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
640cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
641cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
642cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
643cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
644cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
645cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
646cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
647cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
648cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
649cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
650cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
651cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
652cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
653200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
654200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
655200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
656cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
657200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables(const uint32_t* src,
658200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
659200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         const float* const srcTables[3]) {
660cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
661cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
662cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
663cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
664cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
665cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
6665414be06935ce0f990a2df5dccaf9ddec78ec553msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
667cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
668cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
669cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
670cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
671cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
672cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
673cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
674200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
675200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
676200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
677cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6788bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgb_linear(const uint32_t* src,
679be362774f9b9e8964544a579281603ed995e6e5amsarett                                   Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
6808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const float* const[3]) {
681cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
682cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
683cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
684cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
685cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
686be362774f9b9e8964544a579281603ed995e6e5amsarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
6878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
689cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6908bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgba_linear(const uint32_t* src,
6918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
6928bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    const float* const[3]) {
693cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
694cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
695cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
696cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
697cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
698cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 24));
6998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
701cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
702200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables_1(const uint32_t* src,
703200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&,
704200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          const float* const srcTables[3]) {
705cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
706cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
707cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
708cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
709cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
710200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
711200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
712cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
713200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables_1(const uint32_t* src,
714200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
715200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           const float* const srcTables[3]) {
716cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
717cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
718cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
719cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
720cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
721200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * Sk4f(*src >> 24);
722200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
723200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
724cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7258bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgb_linear_1(const uint32_t* src,
7268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                     Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&,
7278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                     const float* const srcTables[3]) {
728cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
729cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
730cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
731cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
732cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
7338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
735cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7368bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgba_linear_1(const uint32_t* src,
7378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
7388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      const float* const srcTables[3]) {
739cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
740cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
741cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
742cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
743cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
744cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = Sk4f((1.0f / 255.0f) * ((*src >> 24)));
7458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
747200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
748200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
749200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
750200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
751200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
752200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
753200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    da = a;
754200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
755200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
756200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
757200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
758200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     Sk4f& rgba) {
759200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
760200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
761200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
762200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
763200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = dr + rTgTbT[0];
764200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = dg + rTgTbT[1];
765200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = db + rTgTbT[2];
766200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
767200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
768200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
769200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rgba + rTgTbT;
770200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
771200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
772200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) {
773200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = da * dr;
774200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = da * dg;
775200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = da * db;
776200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
777200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
778200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply_1(const Sk4f& a, Sk4f& rgba) {
779200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = a * rgba;
780200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
781200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
782cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
783200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb(void* dst, const uint32_t* src,
784200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                              Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
7858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                              const uint8_t* const[3]) {
786cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
787cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
788200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_linear_to_srgb_needs_trunc(dr);
789200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_linear_to_srgb_needs_trunc(dg);
790200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_linear_to_srgb_needs_trunc(db);
791200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
792200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
793200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
794200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
795200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
796200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
797200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
798200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
799200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(dg) << kGShift)
800200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(db) << kBShift)
801200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                           );
802200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
803200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
804200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
805cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
806200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb_1(void* dst, const uint32_t* src,
807200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                Sk4f& rgba, const Sk4f&,
8088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                const uint8_t* const[3]) {
809200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
810200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
811200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
812200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
813200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
814cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
815200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
816200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
817200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
818200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
819200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
820200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
821200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline Sk4f linear_to_2dot2(const Sk4f& x) {
822200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
823200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    auto x2  = x.rsqrt(),                            // x^(-1/2)
824200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(),   // x^(-1/32)
825200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x64 = x32.rsqrt();                          // x^(+1/64)
826200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
827200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // 29 = 32 - 2 - 1
828200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return 255.0f * x2.invert() * x32 * x64.invert();
829200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
830200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
831cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
832200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2(void* dst, const uint32_t* src,
833200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
8348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
835cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
836cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
837200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = linear_to_2dot2(dr);
838200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = linear_to_2dot2(dg);
839200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = linear_to_2dot2(db);
840200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
841200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
842200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
843200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
844200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
845200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
846200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
847200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
848200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(dg) << kGShift)
849200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(db) << kBShift)
850200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                       );
851200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
852200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
853200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
854cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
855200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2_1(void* dst, const uint32_t* src,
856200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& rgba, const Sk4f&,
8578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const uint8_t* const[3]) {
858200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
859200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
860200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
861200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
862200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
863cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
864200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
865200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
866200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
867200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
868200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
869200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
870cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
8718bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void store_linear(void* dst, const uint32_t* src,
8728bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
8738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
874cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
875cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
876591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dr = sk_clamp_0_255(255.0f * dr);
877591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dg = sk_clamp_0_255(255.0f * dg);
878591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    db = sk_clamp_0_255(255.0f * db);
8798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
8818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
8838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(dg) << kGShift)
8848bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(db) << kBShift)
8858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (da                       );
8868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    rgba.store(dst);
8878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
8888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
889cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
8908bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void store_linear_1(void* dst, const uint32_t* src,
8918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  Sk4f& rgba, const Sk4f&,
8928bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  const uint8_t* const[3]) {
893591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    rgba = sk_clamp_0_255(255.0f * rgba);
8948bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    uint32_t tmp;
8968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
8978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
898cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
8998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        tmp = SkSwizzle_RB(tmp);
9008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
9018bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
9028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    *(uint32_t*)dst = tmp;
9038bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
9048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
905cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
906200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16(void* dst, const uint32_t* src,
907200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                             Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
9088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const uint8_t* const[3]) {
90933cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
91033cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
91133cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
91233cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(da));
913200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
914200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
915cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
916200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1(void* dst, const uint32_t* src,
917200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rgba, const Sk4f& a,
9188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
919200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
9208ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst);
921200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
922200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
923cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
924c0444615ed76360f680619ad4d1f92cda6181a50msarettstatic inline void store_f32(void* dst, const uint32_t* src,
925c0444615ed76360f680619ad4d1f92cda6181a50msarett                             Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
926c0444615ed76360f680619ad4d1f92cda6181a50msarett                             const uint8_t* const[3]) {
92733cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4f::Store4(dst, dr, dg, db, da);
928c0444615ed76360f680619ad4d1f92cda6181a50msarett}
929c0444615ed76360f680619ad4d1f92cda6181a50msarett
930cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
931c0444615ed76360f680619ad4d1f92cda6181a50msarettstatic inline void store_f32_1(void* dst, const uint32_t* src,
932c0444615ed76360f680619ad4d1f92cda6181a50msarett                               Sk4f& rgba, const Sk4f& a,
933c0444615ed76360f680619ad4d1f92cda6181a50msarett                               const uint8_t* const[3]) {
934c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
935c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba.store((float*) dst);
936c0444615ed76360f680619ad4d1f92cda6181a50msarett}
937c0444615ed76360f680619ad4d1f92cda6181a50msarett
938cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
939200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_opaque(void* dst, const uint32_t* src,
940c0444615ed76360f680619ad4d1f92cda6181a50msarett                                    Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
9418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    const uint8_t* const[3]) {
94233cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
94333cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
94433cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
94533cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SK_Half1);
946200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
947200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
948cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
949200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1_opaque(void* dst, const uint32_t* src,
950c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      Sk4f& rgba, const Sk4f&,
9518bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      const uint8_t* const[3]) {
952200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint64_t tmp;
9538ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store(&tmp);
954200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp |= static_cast<uint64_t>(SK_Half1) << 48;
955200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *((uint64_t*) dst) = tmp;
956200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
957200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
958cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
959200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic(void* dst, const uint32_t* src,
960200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
9618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const uint8_t* const dstTables[3]) {
962cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
963cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
964200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
965200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
966200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
967200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
968200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ir = Sk4f_round(dr);
969200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ig = Sk4f_round(dg);
970200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ib = Sk4f_round(db);
971200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
972200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
973200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
974200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t* dst32 = (uint32_t*) dst;
975200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[0] = dstTables[0][ir[0]] << kRShift
976200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[0]] << kGShift
977200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[0]] << kBShift
978200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[0];
979200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[1] = dstTables[0][ir[1]] << kRShift
980200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[1]] << kGShift
981200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[1]] << kBShift
982200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[1];
983200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[2] = dstTables[0][ir[2]] << kRShift
984200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[2]] << kGShift
985200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[2]] << kBShift
986200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[2];
987200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[3] = dstTables[0][ir[3]] << kRShift
988200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[3]] << kGShift
989200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[3]] << kBShift
990200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[3];
991200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
992200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
993cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
994200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic_1(void* dst, const uint32_t* src,
995200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& rgba, const Sk4f&,
9968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const uint8_t* const dstTables[3]) {
997cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
998cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
999200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
1000200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1001200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i indices = Sk4f_round(rgba);
1002200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10039dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
10049dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[1][indices[1]] << kGShift
10059dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[2][indices[2]] << kBShift
1006200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | (*src & 0xFF000000);
1007200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
1008200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1009cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables<kRGBA_Order>  )* LoadFn;
1010cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables_1<kRGBA_Order>)* Load1Fn;
1011cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic<kRGBA_Order>         )* StoreFn;
1012cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic_1<kRGBA_Order>       )* Store1Fn;
10138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
10148bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SkAlphaType kAlphaType,
10158bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          ColorSpaceMatch kCSM>
101631d097e865f266c8398f45114e4c75c0dfdef058msarettstatic inline void do_color_xform(void* dst, const void* vsrc, int len,
10178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  const float* const srcTables[3], const float matrix[16],
10188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  const uint8_t* const dstTables[3], LoadFn load, Load1Fn load_1,
10198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  StoreFn store, Store1Fn store_1, size_t sizeOfDstPixel) {
102031d097e865f266c8398f45114e4c75c0dfdef058msarett    const uint32_t* src = (const uint32_t*) vsrc;
1021200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
1022200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
1023200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1024200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (len >= 4) {
1025200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        // Naively this would be a loop of load-transform-store, but we found it faster to
1026200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        // move the N+1th load ahead of the Nth store.  We don't bother doing this for N<4.
1027200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f r, g, b, a;
1028200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        load(src, r, g, b, a, srcTables);
1029200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        src += 4;
1030200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        len -= 4;
1031200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1032200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f dr, dg, db, da;
1033200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        while (len >= 4) {
1034200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (kNone_ColorSpaceMatch == kCSM) {
1035200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1036200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                translate_gamut(rTgTbT, dr, dg, db);
1037200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            } else {
1038200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                dr = r;
1039200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                dg = g;
1040200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                db = b;
1041200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                da = a;
1042200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
1043200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1044200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (kPremul_SkAlphaType == kAlphaType) {
1045200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                premultiply(dr, dg, db, da);
1046200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
1047200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1048200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load(src, r, g, b, a, srcTables);
1049200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            store(dst, src - 4, dr, dg, db, da, dstTables);
1051200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1052200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            src += 4;
1053200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            len -= 4;
1054200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1055200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1056200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kNone_ColorSpaceMatch == kCSM) {
1057200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1058200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            translate_gamut(rTgTbT, dr, dg, db);
1059200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        } else {
1060200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dr = r;
1061200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dg = g;
1062200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            db = b;
1063200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            da = a;
1064200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1065200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1066200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kPremul_SkAlphaType == kAlphaType) {
1067200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            premultiply(dr, dg, db, da);
1068200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1069200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        store(dst, src - 4, dr, dg, db, da, dstTables);
1071200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1072200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1073200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1074200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    while (len > 0) {
1075200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f r, g, b, a;
1076200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        load_1(src, r, g, b, a, srcTables);
1077200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1078200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f rgba;
1079200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kNone_ColorSpaceMatch == kCSM) {
1080200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
1081200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            translate_gamut_1(rTgTbT, rgba);
1082200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        } else {
1083200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            rgba = Sk4f(r[0], g[0], b[0], a[0]);
1084200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1085200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1086200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kPremul_SkAlphaType == kAlphaType) {
1087200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            premultiply_1(a, rgba);
1088200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1089200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10908bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        store_1(dst, src, rgba, a, dstTables);
1091200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1092200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        src += 1;
1093200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        len -= 1;
1094200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
1095200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1096200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
1097200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10988bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum SrcFormat {
10998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Linear_SrcFormat,
11008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Table_SrcFormat,
1101cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_SrcFormat,
1102cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_SrcFormat,
11038bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
11048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11058bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum DstFormat {
1106cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Linear_DstFormat,
1107cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_SRGB_DstFormat,
1108cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_2Dot2_DstFormat,
1109cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Table_DstFormat,
1110cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_DstFormat,
1111cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_SRGB_DstFormat,
1112cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_2Dot2_DstFormat,
1113cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_DstFormat,
11148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kF16_Linear_DstFormat,
1115c0444615ed76360f680619ad4d1f92cda6181a50msarett    kF32_Linear_DstFormat,
11168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
11178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11188bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcFormat kSrc,
11198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          DstFormat kDst,
11208bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          SkAlphaType kAlphaType,
1121cf7b877d62537672b67449bc96858cc1262be5f8msarett          ColorSpaceMatch kCSM>
112231d097e865f266c8398f45114e4c75c0dfdef058msarettstatic void color_xform_RGBA(void* dst, const void* src, int len,
11238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const float* const srcTables[3], const float matrix[16],
11248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const uint8_t* const dstTables[3]) {
11258bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    LoadFn load;
11268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Load1Fn load_1;
1127c0444615ed76360f680619ad4d1f92cda6181a50msarett    static constexpr bool loadAlpha = (kPremul_SkAlphaType == kAlphaType) ||
1128c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF16_Linear_DstFormat == kDst) ||
1129c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF32_Linear_DstFormat == kDst);
11308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kSrc) {
11318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Linear_SrcFormat:
1132c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
1133cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kRGBA_Order>;
1134cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kRGBA_Order>;
11358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
1136cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kRGBA_Order>;
1137cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kRGBA_Order>;
11388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
11398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Table_SrcFormat:
1141c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
1142cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kRGBA_Order>;
1143cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kRGBA_Order>;
11448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
1145cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kRGBA_Order>;
1146cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kRGBA_Order>;
1147cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1148cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1149cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_SrcFormat:
1150cf7b877d62537672b67449bc96858cc1262be5f8msarett            if (loadAlpha) {
1151cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kBGRA_Order>;
1152cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kBGRA_Order>;
1153cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
1154cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kBGRA_Order>;
1155cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kBGRA_Order>;
1156cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1157cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1158cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_SrcFormat:
1159cf7b877d62537672b67449bc96858cc1262be5f8msarett            if (loadAlpha) {
1160cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kBGRA_Order>;
1161cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kBGRA_Order>;
1162cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
1163cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kBGRA_Order>;
1164cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kBGRA_Order>;
11658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
11668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
11678bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
11688bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    StoreFn store;
11708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Store1Fn store_1;
11718bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    size_t sizeOfDstPixel;
11728bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kDst) {
1173cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Linear_DstFormat:
1174cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kRGBA_Order>;
1175cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kRGBA_Order>;
1176cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
1177cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1178cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_SRGB_DstFormat:
1179cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kRGBA_Order>;
1180cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kRGBA_Order>;
1181cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
1182cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1183cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_2Dot2_DstFormat:
1184cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kRGBA_Order>;
1185cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kRGBA_Order>;
11868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
11878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1188cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Table_DstFormat:
1189cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kRGBA_Order>;
1190cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kRGBA_Order>;
11918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
11928bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1193cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_DstFormat:
1194cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kBGRA_Order>;
1195cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kBGRA_Order>;
11968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
11978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1198cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_SRGB_DstFormat:
1199cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kBGRA_Order>;
1200cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kBGRA_Order>;
1201cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
1202cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1203cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_2Dot2_DstFormat:
1204cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kBGRA_Order>;
1205cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kBGRA_Order>;
1206cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
1207cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1208cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_DstFormat:
1209cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kBGRA_Order>;
1210cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kBGRA_Order>;
12118bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
12128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
12138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kF16_Linear_DstFormat:
1214cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque<kRGBA_Order> :
1215cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16<kRGBA_Order>;
1216cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque<kRGBA_Order> :
1217cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16_1<kRGBA_Order>;
12188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 8;
12198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1220c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kF32_Linear_DstFormat:
1221cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_f32<kRGBA_Order>;
1222cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_f32_1<kRGBA_Order>;
1223c0444615ed76360f680619ad4d1f92cda6181a50msarett            sizeOfDstPixel = 16;
1224c0444615ed76360f680619ad4d1f92cda6181a50msarett            break;
12258bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
12268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
12278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    do_color_xform<kAlphaType, kCSM>
12288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            (dst, src, len, srcTables, matrix, dstTables, load, load_1, store, store_1,
12298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett             sizeOfDstPixel);
12308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
12318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
12323418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett///////////////////////////////////////////////////////////////////////////////////////////////////
12330f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
12347bbda991af353fbe6b34132132d211d23a3dba8cmsarettstatic inline int num_tables(SkColorSpace* space) {
12357bbda991af353fbe6b34132132d211d23a3dba8cmsarett    switch (as_CSB(space)->gammaNamed()) {
12367bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kSRGB_SkGammaNamed:
12377bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case k2Dot2Curve_SkGammaNamed:
12387bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kLinear_SkGammaNamed:
12397bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return 0;
12407bbda991af353fbe6b34132132d211d23a3dba8cmsarett        default: {
12417bbda991af353fbe6b34132132d211d23a3dba8cmsarett            const SkGammas* gammas = as_CSB(space)->gammas();
12427bbda991af353fbe6b34132132d211d23a3dba8cmsarett            SkASSERT(gammas);
12437bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12447bbda991af353fbe6b34132132d211d23a3dba8cmsarett            bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
12457bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(1)) &&
12467bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->type(0) == gammas->type(2)) &&
12477bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(2));
12487bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12497bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // It's likely that each component will have the same gamma.  In this case,
12507bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // we only need to build one table.
12517bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return gammasAreMatching ? 1 : 3;
12527bbda991af353fbe6b34132132d211d23a3dba8cmsarett        }
12537bbda991af353fbe6b34132132d211d23a3dba8cmsarett    }
12547bbda991af353fbe6b34132132d211d23a3dba8cmsarett}
12557bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12568bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
12578bbcd5aab81dc0742c3367479c0c9d97363b1203msarettSkColorSpaceXform_Base<kSrc, kDst, kCSM>
12584be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett::SkColorSpaceXform_Base(SkColorSpace* srcSpace, const SkMatrix44& srcToDst, SkColorSpace* dstSpace)
12593418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT()))
12603418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1261de68d6c4616d86621373d88100002ddfdb9c08e3brianosman    srcToDst.asColMajorf(fSrcToDst);
12627bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12634be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    const int numSrcTables = num_tables(srcSpace);
12644be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    const int numDstTables = num_tables(dstSpace);
12657bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const size_t srcTableBytes = numSrcTables * 256 * sizeof(float);
12667bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const size_t dstTableBytes = numDstTables * kDstGammaTableSize * sizeof(uint8_t);
12677bbda991af353fbe6b34132132d211d23a3dba8cmsarett    fStorage.reset(srcTableBytes + dstTableBytes);
12687bbda991af353fbe6b34132132d211d23a3dba8cmsarett    float* srcStorage = (float*) fStorage.get();
12697bbda991af353fbe6b34132132d211d23a3dba8cmsarett    uint8_t* dstStorage = SkTAddOffset<uint8_t>(fStorage.get(), srcTableBytes);
12707bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12717bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const bool srcGammasAreMatching = (1 >= numSrcTables);
12727bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const bool dstGammasAreMatching = (1 >= numDstTables);
12737bbda991af353fbe6b34132132d211d23a3dba8cmsarett    build_gamma_tables(fSrcGammaTables, srcStorage, 256, srcSpace, kToLinear, srcGammasAreMatching);
12747bbda991af353fbe6b34132132d211d23a3dba8cmsarett    build_gamma_tables(fDstGammaTables, dstStorage, kDstGammaTableSize, dstSpace, kFromLinear,
12757bbda991af353fbe6b34132132d211d23a3dba8cmsarett                       dstGammasAreMatching);
12763418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
1277dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
12787bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
12797bbda991af353fbe6b34132132d211d23a3dba8cmsarett
1280cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
128131d097e865f266c8398f45114e4c75c0dfdef058msarettstatic inline bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaType alphaType,
12828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const float* const srcTables[3], const float matrix[16],
12838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const uint8_t* const dstTables[3]) {
12848bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (alphaType) {
12858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kOpaque_SkAlphaType:
128631d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kOpaque_SkAlphaType, kCSM>
12878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
128831d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
12898bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kPremul_SkAlphaType:
129031d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kPremul_SkAlphaType, kCSM>
12918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
129231d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
12938bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kUnpremul_SkAlphaType:
129431d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kUnpremul_SkAlphaType, kCSM>
12958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
129631d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
12978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        default:
129831d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
12998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
13008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
13018bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
1302cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <SrcGamma kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
130331d097e865f266c8398f45114e4c75c0dfdef058msarettstatic inline bool apply_set_src(void* dst, const void* src, int len, SkAlphaType alphaType,
13048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const float* const srcTables[3], const float matrix[16],
1305cf7b877d62537672b67449bc96858cc1262be5f8msarett                                 const uint8_t* const dstTables[3],
1306cf7b877d62537672b67449bc96858cc1262be5f8msarett                                 SkColorSpaceXform::ColorFormat srcColorFormat) {
1307cf7b877d62537672b67449bc96858cc1262be5f8msarett    switch (srcColorFormat) {
1308cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kRGBA_8888_ColorFormat:
1309cf7b877d62537672b67449bc96858cc1262be5f8msarett            switch (kSrc) {
1310cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1311cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Linear_SrcFormat, kDst, kCSM>
1312cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1313cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kTable_SrcGamma:
1314cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Table_SrcFormat, kDst, kCSM>
1315cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1316cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1317cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kBGRA_8888_ColorFormat:
1318cf7b877d62537672b67449bc96858cc1262be5f8msarett            switch (kSrc) {
1319cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1320cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Linear_SrcFormat, kDst, kCSM>
1321cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1322cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kTable_SrcGamma:
1323cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Table_SrcFormat, kDst, kCSM>
1324cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1325cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1326cf7b877d62537672b67449bc96858cc1262be5f8msarett        default:
132731d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
13288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
13298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
13308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
13318bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
133231d097e865f266c8398f45114e4c75c0dfdef058msarettbool SkColorSpaceXform_Base<kSrc, kDst, kCSM>
133331d097e865f266c8398f45114e4c75c0dfdef058msarett::onApply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, const void* src,
133431d097e865f266c8398f45114e4c75c0dfdef058msarett          int len, SkAlphaType alphaType) const
13353418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1336200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kFull_ColorSpaceMatch == kCSM) {
13378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        switch (alphaType) {
1338200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            case kPremul_SkAlphaType:
1339200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // We can't skip the xform since we need to perform a premultiply in the
1340200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // linear space.
1341200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                break;
1342200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            default:
1343c0444615ed76360f680619ad4d1f92cda6181a50msarett                switch (dstColorFormat) {
1344c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_8888_ColorFormat:
134531d097e865f266c8398f45114e4c75c0dfdef058msarett                        memcpy(dst, src, len * sizeof(uint32_t));
134631d097e865f266c8398f45114e4c75c0dfdef058msarett                        return true;
1347c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kBGRA_8888_ColorFormat:
134831d097e865f266c8398f45114e4c75c0dfdef058msarett                        SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
134931d097e865f266c8398f45114e4c75c0dfdef058msarett                        return true;
1350c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F16_ColorFormat:
1351c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F32_ColorFormat:
1352c0444615ed76360f680619ad4d1f92cda6181a50msarett                        // There's still work to do to xform to linear floats.
1353200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        break;
1354200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    default:
135531d097e865f266c8398f45114e4c75c0dfdef058msarett                        return false;
1356200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                }
1357200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1358200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1359200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
13603418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#if defined(GOOGLE3)
1361c6cc28c35be30f9ea144f433f3f04273674e29edraftias    // Stack frame size is limited in GOOGLE3.
1362c6cc28c35be30f9ea144f433f3f04273674e29edraftias    SkAutoSMalloc<256 * sizeof(uint32_t)> storage;
13633418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#else
1364c6cc28c35be30f9ea144f433f3f04273674e29edraftias    SkAutoSMalloc<1024 * sizeof(uint32_t)> storage;
13653418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#endif
1366c6cc28c35be30f9ea144f433f3f04273674e29edraftias    if (fColorLUT) {
1367c6cc28c35be30f9ea144f433f3f04273674e29edraftias        size_t storageBytes = len * sizeof(uint32_t);
1368c6cc28c35be30f9ea144f433f3f04273674e29edraftias        storage.reset(storageBytes);
1369d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get());
1370d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        src = (const uint32_t*) storage.get();
13713418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    }
13723418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1373c0444615ed76360f680619ad4d1f92cda6181a50msarett    switch (dstColorFormat) {
1374c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_8888_ColorFormat:
13758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
13768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1377cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_Linear_DstFormat, kCSM>
1378cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1379cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
13808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1381cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_SRGB_DstFormat, kCSM>
1382cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1383cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
13848bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1385cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_2Dot2_DstFormat, kCSM>
1386cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1387cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
13888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1389cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_Table_DstFormat, kCSM>
1390cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1391cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1392d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1393c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kBGRA_8888_ColorFormat:
13948bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
13958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1396cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_Linear_DstFormat, kCSM>
1397cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1398cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
13998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1400cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_SRGB_DstFormat, kCSM>
1401cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1402cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
14038bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1404cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_2Dot2_DstFormat, kCSM>
1405cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1406cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
14078bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1408cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_Table_DstFormat, kCSM>
1409cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1410cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1411d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1412c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F16_ColorFormat:
14138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
14148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1415cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kF16_Linear_DstFormat, kCSM>
1416cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1417cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1418d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
141931d097e865f266c8398f45114e4c75c0dfdef058msarett                    return false;
1420d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1421c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F32_ColorFormat:
1422c0444615ed76360f680619ad4d1f92cda6181a50msarett            switch (kDst) {
1423c0444615ed76360f680619ad4d1f92cda6181a50msarett                case kLinear_DstGamma:
1424cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kF32_Linear_DstFormat, kCSM>
1425cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1426cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1427c0444615ed76360f680619ad4d1f92cda6181a50msarett                default:
142831d097e865f266c8398f45114e4c75c0dfdef058msarett                    return false;
1429c0444615ed76360f680619ad4d1f92cda6181a50msarett            }
1430d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        default:
143131d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
1432d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett    }
14339ce3a543c92a73e6daca420defc042886b3f2019msarett}
14349dc6cf6b8833d36c29a23d2519989b069745fcd5msarett
14357bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
14367bbda991af353fbe6b34132132d211d23a3dba8cmsarett
14374be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarettstd::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace* space) {
14389dc6cf6b8833d36c29a23d2519989b069745fcd5msarett        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
14398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
14409dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                (space, SkMatrix::I(), space));
14419dc6cf6b8833d36c29a23d2519989b069745fcd5msarett}
1442