SkColorSpaceXform.cpp revision 9488833428e83c93a7e6002f4d056084fb57112f
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"
99488833428e83c93a7e6002f4d056084fb57112fraftias#include "SkColorSpace_A2B.h"
109876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorSpace_Base.h"
119488833428e83c93a7e6002f4d056084fb57112fraftias#include "SkColorSpace_XYZ.h"
12200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkColorSpacePriv.h"
1331d097e865f266c8398f45114e4c75c0dfdef058msarett#include "SkColorSpaceXform_Base.h"
14200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkHalf.h"
15200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkOpts.h"
16ac41bac40f5a80d2bc5ccec584c23478a6900179mtklein#include "SkSRGB.h"
179876ac5b3016e5353c072378ac1545a0a2270757msarett
186006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic constexpr float sk_linear_from_2dot2[256] = {
19b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
20b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
21b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
22b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
23b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
24b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
25b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
26b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
27b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
28b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
29b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
30b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
31b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
32b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
33b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
34b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
35b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
36b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
37b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
38b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
39b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
40b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
41b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
42b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
43b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
44b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
45b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
46b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
47b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
48b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
49b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
50b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
51b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
52b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
53b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
54b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
55b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
56b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
57b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
58b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
59b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
60b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
61b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
62b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
63b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
64b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
65b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
66b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
67b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
68b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
69b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
70b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
71b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
72b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
73b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
74b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
75b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
76b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
77b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
78b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
79b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
80b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
81b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
82b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
83b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
84b39067696ad08a26bbe49b71a71f0546dc42a075msarett
856006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
866006f678e78af7b6f67a454cd4bc213048983f9dmsarett
8715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float exponent) {
8815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
8915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = powf(x, exponent);
9015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
9115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
9215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
9315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// Interpolating lookup in a variably sized table.
9415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic float interp_lut(float input, const float* table, int tableSize) {
9515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    float index = input * (tableSize - 1);
9615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    float diff = index - sk_float_floor2int(index);
9715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    return table[(int) sk_float_floor2int(index)] * (1.0f - diff) +
9815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            table[(int) sk_float_ceil2int(index)] * diff;
9915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
10015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
10115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// outTable is always 256 entries, inTable may be larger or smaller.
10215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, const float* inTable,
10315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          int inTableSize) {
10415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    if (256 == inTableSize) {
10515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        memcpy(outTable, inTable, sizeof(float) * 256);
10615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        return;
10715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
10815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
10915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
11015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = interp_lut(x, inTable, inTableSize);
11115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
11215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
11315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
11415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
11515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          float d, float e, float f) {
11615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = (aX + b)^g + c  for X >= d
11715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = eX + f          otherwise
11815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
11915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        if (x >= d) {
12015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            *outTable++ = powf(a * x + b, g) + c;
12115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        } else {
12215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            *outTable++ = e * x + f;
12315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        }
12415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
12515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
12615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
12715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
12815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
129a9e878c836994bce695274b4c28890290139dcdfmsarett// Expand range from 0-1 to 0-255, then convert.
130b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic uint8_t clamp_normalized_float_to_byte(float v) {
131dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // The ordering of the logic is a little strange here in order
132dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // to make sure we convert NaNs to 0.
1339876ac5b3016e5353c072378ac1545a0a2270757msarett    v = v * 255.0f;
134a9e878c836994bce695274b4c28890290139dcdfmsarett    if (v >= 254.5f) {
1359876ac5b3016e5353c072378ac1545a0a2270757msarett        return 255;
136dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else if (v >= 0.5f) {
1379876ac5b3016e5353c072378ac1545a0a2270757msarett        return (uint8_t) (v + 0.5f);
138dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else {
139dea0340cadb759932e53416a657f5ea75fee8b5fmsarett        return 0;
1409876ac5b3016e5353c072378ac1545a0a2270757msarett    }
1419876ac5b3016e5353c072378ac1545a0a2270757msarett}
1429876ac5b3016e5353c072378ac1545a0a2270757msarett
143f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettstatic const int kDstGammaTableSize = SkColorSpaceXform_Base::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,
2599488833428e83c93a7e6002f4d056084fb57112fraftias                               const SkColorSpace_XYZ* space, const GammaFns<T>& fns,
260f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                               bool gammasAreMatching)
2614be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett{
2629488833428e83c93a7e6002f4d056084fb57112fraftias    switch (space->gammaNamed()) {
263600c737b64eae2c7379442ae2c852853cce3a278msarett        case kSRGB_SkGammaNamed:
2641b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
2651b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
266600c737b64eae2c7379442ae2c852853cce3a278msarett        case k2Dot2Curve_SkGammaNamed:
2671b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
2681b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
269600c737b64eae2c7379442ae2c852853cce3a278msarett        case kLinear_SkGammaNamed:
2708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr;
2711b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
2721b93bd1e6eba3d14593490e4e24a34546638c8damsarett        default: {
2739488833428e83c93a7e6002f4d056084fb57112fraftias            const SkGammas* gammas = space->gammas();
2741b93bd1e6eba3d14593490e4e24a34546638c8damsarett            SkASSERT(gammas);
2751b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2767bbda991af353fbe6b34132132d211d23a3dba8cmsarett            auto build_table = [=](int i) {
2771b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (gammas->isNamed(i)) {
2781b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    switch (gammas->data(i).fNamed) {
279600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kSRGB_SkGammaNamed:
28055bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f,
28155bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                                                   (1.0f / 1.055f), (0.055f / 1.055f), 0.0f,
28255bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                                                   0.04045f, (1.0f / 12.92f), 0.0f);
28355bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2841b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
285600c737b64eae2c7379442ae2c852853cce3a278msarett                        case k2Dot2Curve_SkGammaNamed:
28655bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f);
28755bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2881b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
289600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kLinear_SkGammaNamed:
2901b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
2911b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2921b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2931b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        default:
2941b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            SkASSERT(false);
2951b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2961b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
2971b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isValue(i)) {
2981b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
2991b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fValue);
3001b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
3011b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isTable(i)) {
3021b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
3031b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fTable.fSize);
3041b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
3051b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else {
3061b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    SkASSERT(gammas->isParametric(i));
307df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett                    const SkColorSpaceTransferFn& params = gammas->params(i);
3081b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
3091b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fA, params.fB, params.fC, params.fD, params.fE,
3101b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fF);
3111b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
3121b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
3137bbda991af353fbe6b34132132d211d23a3dba8cmsarett            };
3147bbda991af353fbe6b34132132d211d23a3dba8cmsarett
3157bbda991af353fbe6b34132132d211d23a3dba8cmsarett            if (gammasAreMatching) {
3167bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
3177bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[1] = outGammaTables[0];
3187bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[2] = outGammaTables[0];
3197bbda991af353fbe6b34132132d211d23a3dba8cmsarett            } else {
3207bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
3217bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(1);
3227bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(2);
3231b93bd1e6eba3d14593490e4e24a34546638c8damsarett            }
3247bbda991af353fbe6b34132132d211d23a3dba8cmsarett
3257bbda991af353fbe6b34132132d211d23a3dba8cmsarett            break;
3261b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
3271b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
3281b93bd1e6eba3d14593490e4e24a34546638c8damsarett}
3291b93bd1e6eba3d14593490e4e24a34546638c8damsarett
330f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettvoid SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3],
3319488833428e83c93a7e6002f4d056084fb57112fraftias                                                 uint8_t* dstStorage,
3329488833428e83c93a7e6002f4d056084fb57112fraftias                                                 const SkColorSpace_XYZ* space,
333f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                                                 bool gammasAreMatching) {
334f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear,
335f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                       gammasAreMatching);
336f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett}
337f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
3381b93bd1e6eba3d14593490e4e24a34546638c8damsarett///////////////////////////////////////////////////////////////////////////////////////////////////
3391b93bd1e6eba3d14593490e4e24a34546638c8damsarett
340200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline bool is_almost_identity(const SkMatrix44& srcToDst) {
341200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    for (int i = 0; i < 4; i++) {
342200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        for (int j = 0; j < 4; j++) {
343200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            float expected = (i == j) ? 1.0f : 0.0f;
344200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) {
345200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                return false;
346200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
347200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
348200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
349200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return true;
350200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
351200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
35215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
35315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
3544be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace,
3554be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett                                                          SkColorSpace* dstSpace) {
3566006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!srcSpace || !dstSpace) {
3576006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // Invalid input
3586006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
3596006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3606006f678e78af7b6f67a454cd4bc213048983f9dmsarett
3619488833428e83c93a7e6002f4d056084fb57112fraftias    if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) {
3629488833428e83c93a7e6002f4d056084fb57112fraftias        SkColorSpacePrintf("A2B destinations not supported\n");
3639488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
3649488833428e83c93a7e6002f4d056084fb57112fraftias    }
3659488833428e83c93a7e6002f4d056084fb57112fraftias
3669488833428e83c93a7e6002f4d056084fb57112fraftias    if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) {
3679488833428e83c93a7e6002f4d056084fb57112fraftias        // TODO (raftias): return an A2B-supporting SkColorSpaceXform here once the xform.
3689488833428e83c93a7e6002f4d056084fb57112fraftias        // is implemented. SkColorSpaceXform_Base only supports XYZ+TRC based SkColorSpaces
3699488833428e83c93a7e6002f4d056084fb57112fraftias        //SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace);
3709488833428e83c93a7e6002f4d056084fb57112fraftias        //SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace);
3719488833428e83c93a7e6002f4d056084fb57112fraftias        //return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(src, dst));
3729488833428e83c93a7e6002f4d056084fb57112fraftias        SkColorSpacePrintf("A2B sources not supported (yet)\n");
3739488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
3749488833428e83c93a7e6002f4d056084fb57112fraftias    }
3759488833428e83c93a7e6002f4d056084fb57112fraftias    SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace);
3769488833428e83c93a7e6002f4d056084fb57112fraftias    SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace);
3779488833428e83c93a7e6002f4d056084fb57112fraftias
378200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    ColorSpaceMatch csm = kNone_ColorSpaceMatch;
3796006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
3804be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    if (SkColorSpace::Equals(srcSpace, dstSpace)) {
381200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        srcToDst.setIdentity();
382200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        csm = kFull_ColorSpaceMatch;
383971cd496b9e25f87f3a75a0015c203322907136abrianosman    } else {
3849488833428e83c93a7e6002f4d056084fb57112fraftias        srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50());
385971cd496b9e25f87f3a75a0015c203322907136abrianosman
386971cd496b9e25f87f3a75a0015c203322907136abrianosman        if (is_almost_identity(srcToDst)) {
387971cd496b9e25f87f3a75a0015c203322907136abrianosman            srcToDst.setIdentity();
388971cd496b9e25f87f3a75a0015c203322907136abrianosman            csm = kGamut_ColorSpaceMatch;
389971cd496b9e25f87f3a75a0015c203322907136abrianosman        }
3906006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3916006f678e78af7b6f67a454cd4bc213048983f9dmsarett
392200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    switch (csm) {
393200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kNone_ColorSpaceMatch:
3949488833428e83c93a7e6002f4d056084fb57112fraftias            switch (dstSpaceXYZ->gammaNamed()) {
395600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
3969488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
397f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3988bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch>
3999488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
401f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch>
4039488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
405600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
4069488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
407f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch>
4099488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4108bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
411f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch>
4139488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
4158bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
4169488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
417f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch>
4199488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4208bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
421f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4228bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch>
4239488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
425200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
4269488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
427f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
4299488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
431f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
4339488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
435200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
436200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kGamut_ColorSpaceMatch:
4379488833428e83c93a7e6002f4d056084fb57112fraftias            switch (dstSpaceXYZ->gammaNamed()) {
438600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
4399488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
440f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch>
4429488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
444f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch>
4469488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4478bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
448600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
4499488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
450f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4518bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch>
4529488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4538bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
454f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch>
4569488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
4588bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
4599488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
460f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch>
4629488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
464f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch>
4669488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4678bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
468200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
4699488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
470f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4718bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch>
4729488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
474f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch>
4769488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4778bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
478200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
479200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kFull_ColorSpaceMatch:
4809488833428e83c93a7e6002f4d056084fb57112fraftias            switch (dstSpaceXYZ->gammaNamed()) {
481600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
482f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, kSRGB_DstGamma, kFull_ColorSpaceMatch>
4849488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
485600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
486f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, k2Dot2_DstGamma, kFull_ColorSpaceMatch>
4889488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4898bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
490f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kLinear_SrcGamma, kLinear_DstGamma, kFull_ColorSpaceMatch>
4929488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
493200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
494f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, kTable_DstGamma, kFull_ColorSpaceMatch>
4969488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
497200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
4983418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        default:
499200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            SkASSERT(false);
500200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            return nullptr;
5016006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
5026006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
5036006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5046006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
5056006f678e78af7b6f67a454cd4bc213048983f9dmsarett
506200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_matrix(const float matrix[16],
507200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
508200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rXgXbX = Sk4f::Load(matrix +  0);
509200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rYgYbY = Sk4f::Load(matrix +  4);
510200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rZgZbZ = Sk4f::Load(matrix +  8);
511200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rTgTbT = Sk4f::Load(matrix + 12);
512200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
513200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
514cf7b877d62537672b67449bc96858cc1262be5f8msarettenum Order {
515cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_Order,
516cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_Order,
517cf7b877d62537672b67449bc96858cc1262be5f8msarett};
518cf7b877d62537672b67449bc96858cc1262be5f8msarett
519cf7b877d62537672b67449bc96858cc1262be5f8msarettstatic inline void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) {
520cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kRGBA_Order == kOrder) {
521cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 0;
522cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 16;
523cf7b877d62537672b67449bc96858cc1262be5f8msarett    } else {
524cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 16;
525cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 0;
526cf7b877d62537672b67449bc96858cc1262be5f8msarett    }
527cf7b877d62537672b67449bc96858cc1262be5f8msarett}
528cf7b877d62537672b67449bc96858cc1262be5f8msarett
529cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
530200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables(const uint32_t* src,
531200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
532200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        const float* const srcTables[3]) {
533cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
534cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
535cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
536cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
537cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
538cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
539cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
540cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
541cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
542cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
543cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
544cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
545cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
546cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
547200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
548200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
549200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
550cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
551200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables(const uint32_t* src,
552200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
553200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         const float* const srcTables[3]) {
554cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
555cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
556cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
557cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
558cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
559cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
5605414be06935ce0f990a2df5dccaf9ddec78ec553msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
561cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
562cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
563cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
564cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
565cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
566cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
567cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
568200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
569200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
570200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
571cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
5728bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgb_linear(const uint32_t* src,
573be362774f9b9e8964544a579281603ed995e6e5amsarett                                   Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
5748bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const float* const[3]) {
575cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
576cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
577cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
578cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
579cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
580be362774f9b9e8964544a579281603ed995e6e5amsarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
5818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
5828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
583cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
5848bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgba_linear(const uint32_t* src,
5858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
5868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    const float* const[3]) {
587cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
588cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
589cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
590cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
591cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
592cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 24));
5938bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
5948bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
595cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
596200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables_1(const uint32_t* src,
597200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&,
598200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          const float* const srcTables[3]) {
599cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
600cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
601cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
602cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
603cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
604200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
605200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
606cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
607200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables_1(const uint32_t* src,
608200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
609200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           const float* const srcTables[3]) {
610cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
611cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
612cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
613cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
614cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
615200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * Sk4f(*src >> 24);
616200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
617200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
618cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6198bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgb_linear_1(const uint32_t* src,
6208bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                     Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&,
6218bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                     const float* const srcTables[3]) {
622cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
623cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
624cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
625cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
626cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
6278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
629cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6308bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void load_rgba_linear_1(const uint32_t* src,
6318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
6328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      const float* const srcTables[3]) {
633cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
634cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
635cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
636cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
637cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
638cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = Sk4f((1.0f / 255.0f) * ((*src >> 24)));
6398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
641200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
642200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
643200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
644200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
645200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
646200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
647200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    da = a;
648200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
649200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
650200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
651200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
652200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     Sk4f& rgba) {
653200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
654200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
655200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
656200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
657200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = dr + rTgTbT[0];
658200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = dg + rTgTbT[1];
659200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = db + rTgTbT[2];
660200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
661200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
662200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
663200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rgba + rTgTbT;
664200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
665200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
666200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) {
667200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = da * dr;
668200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = da * dg;
669200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = da * db;
670200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
671200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
672200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply_1(const Sk4f& a, Sk4f& rgba) {
673200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = a * rgba;
674200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
675200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
676cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
677200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb(void* dst, const uint32_t* src,
678200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                              Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
6798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                              const uint8_t* const[3]) {
680cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
681cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
682200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_linear_to_srgb_needs_trunc(dr);
683200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_linear_to_srgb_needs_trunc(dg);
684200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_linear_to_srgb_needs_trunc(db);
685200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
686200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
687200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
688200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
689200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
690200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
691200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
692200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
693200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(dg) << kGShift)
694200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(db) << kBShift)
695200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                           );
696200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
697200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
698200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
699cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
700200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb_1(void* dst, const uint32_t* src,
701200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                Sk4f& rgba, const Sk4f&,
7028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                const uint8_t* const[3]) {
703200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
704200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
705200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
706200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
707200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
708cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
709200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
710200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
711200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
712200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
713200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
714200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
715200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline Sk4f linear_to_2dot2(const Sk4f& x) {
716200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
717200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    auto x2  = x.rsqrt(),                            // x^(-1/2)
718200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(),   // x^(-1/32)
719200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x64 = x32.rsqrt();                          // x^(+1/64)
720200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
721200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // 29 = 32 - 2 - 1
722200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return 255.0f * x2.invert() * x32 * x64.invert();
723200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
724200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
725cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
726200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2(void* dst, const uint32_t* src,
727200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
7288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
729cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
730cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
731200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = linear_to_2dot2(dr);
732200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = linear_to_2dot2(dg);
733200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = linear_to_2dot2(db);
734200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
735200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
736200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
737200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
738200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
739200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
740200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
741200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
742200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(dg) << kGShift)
743200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(db) << kBShift)
744200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                       );
745200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
746200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
747200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
748cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
749200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2_1(void* dst, const uint32_t* src,
750200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& rgba, const Sk4f&,
7518bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const uint8_t* const[3]) {
752200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
753200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
754200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
755200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
756200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
757cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
758200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
759200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
760200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
761200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
762200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
763200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
764cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7658bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void store_linear(void* dst, const uint32_t* src,
7668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
7678bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
768cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
769cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
770591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dr = sk_clamp_0_255(255.0f * dr);
771591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dg = sk_clamp_0_255(255.0f * dg);
772591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    db = sk_clamp_0_255(255.0f * db);
7738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7748bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
7758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
7778bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(dg) << kGShift)
7788bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(db) << kBShift)
7798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (da                       );
7808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    rgba.store(dst);
7818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
783cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7848bbcd5aab81dc0742c3367479c0c9d97363b1203msarettstatic inline void store_linear_1(void* dst, const uint32_t* src,
7858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  Sk4f& rgba, const Sk4f&,
7868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                  const uint8_t* const[3]) {
787591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    rgba = sk_clamp_0_255(255.0f * rgba);
7888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7898bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    uint32_t tmp;
7908bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
7918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
792cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
7938bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        tmp = SkSwizzle_RB(tmp);
7948bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
7958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    *(uint32_t*)dst = tmp;
7978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7988bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
799cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
800200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16(void* dst, const uint32_t* src,
801200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                             Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
8028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const uint8_t* const[3]) {
80333cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
80433cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
80533cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
80633cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(da));
807200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
808200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
809cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
810200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1(void* dst, const uint32_t* src,
811200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rgba, const Sk4f& a,
8128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                               const uint8_t* const[3]) {
813200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
8148ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst);
815200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
816200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
817cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
818c0444615ed76360f680619ad4d1f92cda6181a50msarettstatic inline void store_f32(void* dst, const uint32_t* src,
819c0444615ed76360f680619ad4d1f92cda6181a50msarett                             Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
820c0444615ed76360f680619ad4d1f92cda6181a50msarett                             const uint8_t* const[3]) {
82133cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4f::Store4(dst, dr, dg, db, da);
822c0444615ed76360f680619ad4d1f92cda6181a50msarett}
823c0444615ed76360f680619ad4d1f92cda6181a50msarett
824cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
825c0444615ed76360f680619ad4d1f92cda6181a50msarettstatic inline void store_f32_1(void* dst, const uint32_t* src,
826c0444615ed76360f680619ad4d1f92cda6181a50msarett                               Sk4f& rgba, const Sk4f& a,
827c0444615ed76360f680619ad4d1f92cda6181a50msarett                               const uint8_t* const[3]) {
828c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
829c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba.store((float*) dst);
830c0444615ed76360f680619ad4d1f92cda6181a50msarett}
831c0444615ed76360f680619ad4d1f92cda6181a50msarett
832cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
833200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_opaque(void* dst, const uint32_t* src,
834c0444615ed76360f680619ad4d1f92cda6181a50msarett                                    Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
8358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                    const uint8_t* const[3]) {
83633cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
83733cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
83833cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
83933cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SK_Half1);
840200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
841200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
842cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
843200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1_opaque(void* dst, const uint32_t* src,
844c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      Sk4f& rgba, const Sk4f&,
8458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                      const uint8_t* const[3]) {
846200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint64_t tmp;
8478ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store(&tmp);
848200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp |= static_cast<uint64_t>(SK_Half1) << 48;
849200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *((uint64_t*) dst) = tmp;
850200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
851200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
852cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
853200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic(void* dst, const uint32_t* src,
854200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
8558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const uint8_t* const dstTables[3]) {
856cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
857cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
858200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
859200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
860200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
861200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
862200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ir = Sk4f_round(dr);
863200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ig = Sk4f_round(dg);
864200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ib = Sk4f_round(db);
865200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
866200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
867200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
868200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t* dst32 = (uint32_t*) dst;
869200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[0] = dstTables[0][ir[0]] << kRShift
870200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[0]] << kGShift
871200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[0]] << kBShift
872200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[0];
873200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[1] = dstTables[0][ir[1]] << kRShift
874200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[1]] << kGShift
875200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[1]] << kBShift
876200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[1];
877200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[2] = dstTables[0][ir[2]] << kRShift
878200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[2]] << kGShift
879200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[2]] << kBShift
880200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[2];
881200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[3] = dstTables[0][ir[3]] << kRShift
882200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[3]] << kGShift
883200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[3]] << kBShift
884200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[3];
885200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
886200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
887cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
888200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic_1(void* dst, const uint32_t* src,
889200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& rgba, const Sk4f&,
8908bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const uint8_t* const dstTables[3]) {
891cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
892cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
893200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
894200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
895200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i indices = Sk4f_round(rgba);
896200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
8979dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
8989dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[1][indices[1]] << kGShift
8999dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[2][indices[2]] << kBShift
900200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | (*src & 0xFF000000);
901200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
902200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
903cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables<kRGBA_Order>  )* LoadFn;
904cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables_1<kRGBA_Order>)* Load1Fn;
905cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic<kRGBA_Order>         )* StoreFn;
906cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic_1<kRGBA_Order>       )* Store1Fn;
9078bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
9088bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum SrcFormat {
9098bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Linear_SrcFormat,
9108bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Table_SrcFormat,
911cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_SrcFormat,
912cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_SrcFormat,
9138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
9148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
9158bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum DstFormat {
916cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Linear_DstFormat,
917cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_SRGB_DstFormat,
918cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_2Dot2_DstFormat,
919cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Table_DstFormat,
920cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_DstFormat,
921cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_SRGB_DstFormat,
922cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_2Dot2_DstFormat,
923cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_DstFormat,
9248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kF16_Linear_DstFormat,
925c0444615ed76360f680619ad4d1f92cda6181a50msarett    kF32_Linear_DstFormat,
9268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
9278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
9288bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcFormat kSrc,
9298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          DstFormat kDst,
9308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          SkAlphaType kAlphaType,
931cf7b877d62537672b67449bc96858cc1262be5f8msarett          ColorSpaceMatch kCSM>
932d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarettstatic void color_xform_RGBA(void* dst, const void* vsrc, int len,
9338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const float* const srcTables[3], const float matrix[16],
9348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                             const uint8_t* const dstTables[3]) {
9358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    LoadFn load;
9368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Load1Fn load_1;
937c0444615ed76360f680619ad4d1f92cda6181a50msarett    static constexpr bool loadAlpha = (kPremul_SkAlphaType == kAlphaType) ||
938c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF16_Linear_DstFormat == kDst) ||
939c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF32_Linear_DstFormat == kDst);
9408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kSrc) {
9418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Linear_SrcFormat:
942c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
943cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kRGBA_Order>;
944cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kRGBA_Order>;
9458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
946cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kRGBA_Order>;
947cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kRGBA_Order>;
9488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
9498bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
9508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Table_SrcFormat:
951c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
952cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kRGBA_Order>;
953cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kRGBA_Order>;
9548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
955cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kRGBA_Order>;
956cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kRGBA_Order>;
957cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
958cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
959cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_SrcFormat:
960cf7b877d62537672b67449bc96858cc1262be5f8msarett            if (loadAlpha) {
961cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kBGRA_Order>;
962cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kBGRA_Order>;
963cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
964cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kBGRA_Order>;
965cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kBGRA_Order>;
966cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
967cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
968cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_SrcFormat:
969cf7b877d62537672b67449bc96858cc1262be5f8msarett            if (loadAlpha) {
970cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kBGRA_Order>;
971cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kBGRA_Order>;
972cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
973cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kBGRA_Order>;
974cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kBGRA_Order>;
9758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
9768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
9778bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
9788bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
9798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    StoreFn store;
9808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Store1Fn store_1;
9818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    size_t sizeOfDstPixel;
9828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kDst) {
983cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Linear_DstFormat:
984cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kRGBA_Order>;
985cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kRGBA_Order>;
986cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
987cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
988cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_SRGB_DstFormat:
989cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kRGBA_Order>;
990cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kRGBA_Order>;
991cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
992cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
993cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_2Dot2_DstFormat:
994cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kRGBA_Order>;
995cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kRGBA_Order>;
9968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
9978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
998cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Table_DstFormat:
999cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kRGBA_Order>;
1000cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kRGBA_Order>;
10018bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
10028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1003cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_DstFormat:
1004cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kBGRA_Order>;
1005cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kBGRA_Order>;
10068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
10078bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1008cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_SRGB_DstFormat:
1009cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kBGRA_Order>;
1010cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kBGRA_Order>;
1011cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
1012cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1013cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_2Dot2_DstFormat:
1014cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kBGRA_Order>;
1015cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kBGRA_Order>;
1016cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
1017cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
1018cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_DstFormat:
1019cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kBGRA_Order>;
1020cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kBGRA_Order>;
10218bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
10228bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
10238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kF16_Linear_DstFormat:
1024cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque<kRGBA_Order> :
1025cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16<kRGBA_Order>;
1026cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque<kRGBA_Order> :
1027cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16_1<kRGBA_Order>;
10288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 8;
10298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
1030c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kF32_Linear_DstFormat:
1031cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_f32<kRGBA_Order>;
1032cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_f32_1<kRGBA_Order>;
1033c0444615ed76360f680619ad4d1f92cda6181a50msarett            sizeOfDstPixel = 16;
1034c0444615ed76360f680619ad4d1f92cda6181a50msarett            break;
10358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
10368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
1037d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    const uint32_t* src = (const uint32_t*) vsrc;
1038d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
1039d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
1040d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1041d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    if (len >= 4) {
1042d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        // Naively this would be a loop of load-transform-store, but we found it faster to
1043d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        // move the N+1th load ahead of the Nth store.  We don't bother doing this for N<4.
1044d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f r, g, b, a;
1045d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        load(src, r, g, b, a, srcTables);
1046d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        src += 4;
1047d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        len -= 4;
1048d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1049d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f dr, dg, db, da;
1050d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        while (len >= 4) {
1051d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            if (kNone_ColorSpaceMatch == kCSM) {
1052d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1053d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                translate_gamut(rTgTbT, dr, dg, db);
1054d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            } else {
1055d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                dr = r;
1056d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                dg = g;
1057d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                db = b;
1058d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                da = a;
1059d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            }
1060d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1061d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            if (kPremul_SkAlphaType == kAlphaType) {
1062d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                premultiply(dr, dg, db, da);
1063d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            }
1064d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1065d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            load(src, r, g, b, a, srcTables);
1066d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1067d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            store(dst, src - 4, dr, dg, db, da, dstTables);
1068d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1069d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            src += 4;
1070d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            len -= 4;
1071d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1072d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1073d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kNone_ColorSpaceMatch == kCSM) {
1074d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1075d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            translate_gamut(rTgTbT, dr, dg, db);
1076d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        } else {
1077d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dr = r;
1078d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dg = g;
1079d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            db = b;
1080d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            da = a;
1081d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1082d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1083d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kPremul_SkAlphaType == kAlphaType) {
1084d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            premultiply(dr, dg, db, da);
1085d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1086d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1087d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        store(dst, src - 4, dr, dg, db, da, dstTables);
1088d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1089d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    }
1090d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1091d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    while (len > 0) {
1092d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f r, g, b, a;
1093d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        load_1(src, r, g, b, a, srcTables);
1094d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1095d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f rgba;
1096d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kNone_ColorSpaceMatch == kCSM) {
1097d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
1098d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            translate_gamut_1(rTgTbT, rgba);
1099d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        } else {
1100d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            rgba = Sk4f(r[0], g[0], b[0], a[0]);
1101d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1102d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1103d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kPremul_SkAlphaType == kAlphaType) {
1104d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            premultiply_1(a, rgba);
1105d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1106d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1107d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        store_1(dst, src, rgba, a, dstTables);
1108d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1109d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        src += 1;
1110d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        len -= 1;
1111d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
1112d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    }
11138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
11148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
11153418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett///////////////////////////////////////////////////////////////////////////////////////////////////
11160f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
11179488833428e83c93a7e6002f4d056084fb57112fraftiasstatic inline int num_tables(SkColorSpace_XYZ* space) {
11189488833428e83c93a7e6002f4d056084fb57112fraftias    switch (space->gammaNamed()) {
11197bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kSRGB_SkGammaNamed:
11207bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case k2Dot2Curve_SkGammaNamed:
11217bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kLinear_SkGammaNamed:
11227bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return 0;
11237bbda991af353fbe6b34132132d211d23a3dba8cmsarett        default: {
11249488833428e83c93a7e6002f4d056084fb57112fraftias            const SkGammas* gammas = space->gammas();
11257bbda991af353fbe6b34132132d211d23a3dba8cmsarett            SkASSERT(gammas);
11267bbda991af353fbe6b34132132d211d23a3dba8cmsarett
11277bbda991af353fbe6b34132132d211d23a3dba8cmsarett            bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
11287bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(1)) &&
11297bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->type(0) == gammas->type(2)) &&
11307bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(2));
11317bbda991af353fbe6b34132132d211d23a3dba8cmsarett
11327bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // It's likely that each component will have the same gamma.  In this case,
11337bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // we only need to build one table.
11347bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return gammasAreMatching ? 1 : 3;
11357bbda991af353fbe6b34132132d211d23a3dba8cmsarett        }
11367bbda991af353fbe6b34132132d211d23a3dba8cmsarett    }
11377bbda991af353fbe6b34132132d211d23a3dba8cmsarett}
11387bbda991af353fbe6b34132132d211d23a3dba8cmsarett
11398bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
1140f489886915034093278353d06c6f1973b2e8b7d2Matt SarettSkColorSpaceXform_XYZ<kSrc, kDst, kCSM>
11419488833428e83c93a7e6002f4d056084fb57112fraftias::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst,
11429488833428e83c93a7e6002f4d056084fb57112fraftias                        SkColorSpace_XYZ* dstSpace)
11433418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1144de68d6c4616d86621373d88100002ddfdb9c08e3brianosman    srcToDst.asColMajorf(fSrcToDst);
11457bbda991af353fbe6b34132132d211d23a3dba8cmsarett
11464be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    const int numSrcTables = num_tables(srcSpace);
1147f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    const size_t srcEntries = numSrcTables * 256;
11487bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const bool srcGammasAreMatching = (1 >= numSrcTables);
1149f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    fSrcStorage.reset(srcEntries);
1150f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear,
1151f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                       srcGammasAreMatching);
1152f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
1153f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    const int numDstTables = num_tables(dstSpace);
11549488833428e83c93a7e6002f4d056084fb57112fraftias    dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables);
11553418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
1156dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
11577bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
11587bbda991af353fbe6b34132132d211d23a3dba8cmsarett
1159cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
116031d097e865f266c8398f45114e4c75c0dfdef058msarettstatic inline bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaType alphaType,
11618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const float* const srcTables[3], const float matrix[16],
11628bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                   const uint8_t* const dstTables[3]) {
11638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (alphaType) {
11648bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kOpaque_SkAlphaType:
116531d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kOpaque_SkAlphaType, kCSM>
11668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
116731d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
11688bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kPremul_SkAlphaType:
116931d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kPremul_SkAlphaType, kCSM>
11708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
117131d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
11728bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kUnpremul_SkAlphaType:
117331d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kUnpremul_SkAlphaType, kCSM>
11748bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
117531d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
11768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        default:
117731d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
11788bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
11798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
11808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
1181cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <SrcGamma kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
118231d097e865f266c8398f45114e4c75c0dfdef058msarettstatic inline bool apply_set_src(void* dst, const void* src, int len, SkAlphaType alphaType,
11838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                 const float* const srcTables[3], const float matrix[16],
1184cf7b877d62537672b67449bc96858cc1262be5f8msarett                                 const uint8_t* const dstTables[3],
1185cf7b877d62537672b67449bc96858cc1262be5f8msarett                                 SkColorSpaceXform::ColorFormat srcColorFormat) {
1186cf7b877d62537672b67449bc96858cc1262be5f8msarett    switch (srcColorFormat) {
1187cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kRGBA_8888_ColorFormat:
1188cf7b877d62537672b67449bc96858cc1262be5f8msarett            switch (kSrc) {
1189cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1190cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Linear_SrcFormat, kDst, kCSM>
1191cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1192cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kTable_SrcGamma:
1193cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Table_SrcFormat, kDst, kCSM>
1194cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1195cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1196cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kBGRA_8888_ColorFormat:
1197cf7b877d62537672b67449bc96858cc1262be5f8msarett            switch (kSrc) {
1198cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1199cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Linear_SrcFormat, kDst, kCSM>
1200cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1201cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kTable_SrcGamma:
1202cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Table_SrcFormat, kDst, kCSM>
1203cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1204cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1205cf7b877d62537672b67449bc96858cc1262be5f8msarett        default:
120631d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
12078bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
12088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
12098bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
12108bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
1211f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettbool SkColorSpaceXform_XYZ<kSrc, kDst, kCSM>
121231d097e865f266c8398f45114e4c75c0dfdef058msarett::onApply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, const void* src,
121331d097e865f266c8398f45114e4c75c0dfdef058msarett          int len, SkAlphaType alphaType) const
12143418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1215200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kFull_ColorSpaceMatch == kCSM) {
12168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        switch (alphaType) {
1217200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            case kPremul_SkAlphaType:
1218200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // We can't skip the xform since we need to perform a premultiply in the
1219200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // linear space.
1220200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                break;
1221200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            default:
1222c0444615ed76360f680619ad4d1f92cda6181a50msarett                switch (dstColorFormat) {
1223c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_8888_ColorFormat:
122431d097e865f266c8398f45114e4c75c0dfdef058msarett                        memcpy(dst, src, len * sizeof(uint32_t));
122531d097e865f266c8398f45114e4c75c0dfdef058msarett                        return true;
1226c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kBGRA_8888_ColorFormat:
122731d097e865f266c8398f45114e4c75c0dfdef058msarett                        SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
122831d097e865f266c8398f45114e4c75c0dfdef058msarett                        return true;
1229c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F16_ColorFormat:
1230c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F32_ColorFormat:
1231c0444615ed76360f680619ad4d1f92cda6181a50msarett                        // There's still work to do to xform to linear floats.
1232200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        break;
1233200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    default:
123431d097e865f266c8398f45114e4c75c0dfdef058msarett                        return false;
1235200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                }
1236200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1237200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1238200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1239c0444615ed76360f680619ad4d1f92cda6181a50msarett    switch (dstColorFormat) {
1240c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_8888_ColorFormat:
12418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
12428bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1243cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_Linear_DstFormat, kCSM>
1244cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1245cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1247cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_SRGB_DstFormat, kCSM>
1248cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1249cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1251cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_2Dot2_DstFormat, kCSM>
1252cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1253cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1255cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_Table_DstFormat, kCSM>
1256cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1257cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1258d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1259c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kBGRA_8888_ColorFormat:
12608bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
12618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1262cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_Linear_DstFormat, kCSM>
1263cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1264cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1266cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_SRGB_DstFormat, kCSM>
1267cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1268cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1270cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_2Dot2_DstFormat, kCSM>
1271cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1272cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1274cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_Table_DstFormat, kCSM>
1275cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1276cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1277d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1278c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F16_ColorFormat:
12798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
12808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1281cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kF16_Linear_DstFormat, kCSM>
1282cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1283cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1284d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
128531d097e865f266c8398f45114e4c75c0dfdef058msarett                    return false;
1286d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1287c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F32_ColorFormat:
1288c0444615ed76360f680619ad4d1f92cda6181a50msarett            switch (kDst) {
1289c0444615ed76360f680619ad4d1f92cda6181a50msarett                case kLinear_DstGamma:
1290cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kF32_Linear_DstFormat, kCSM>
1291cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1292cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1293c0444615ed76360f680619ad4d1f92cda6181a50msarett                default:
129431d097e865f266c8398f45114e4c75c0dfdef058msarett                    return false;
1295c0444615ed76360f680619ad4d1f92cda6181a50msarett            }
1296d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        default:
129731d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
1298d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett    }
12999ce3a543c92a73e6daca420defc042886b3f2019msarett}
13009dc6cf6b8833d36c29a23d2519989b069745fcd5msarett
1301f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettbool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
1302f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                              const void* src, int len, SkAlphaType alphaType) const {
1303f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcColorFormat, src, len,
1304f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                                                     alphaType);
1305f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett}
1306f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
13077bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
13087bbda991af353fbe6b34132132d211d23a3dba8cmsarett
13099488833428e83c93a7e6002f4d056084fb57112fraftiasstd::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) {
1310f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
13118bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
13129dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                (space, SkMatrix::I(), space));
13139dc6cf6b8833d36c29a23d2519989b069745fcd5msarett}
1314