SkColorSpaceXform.cpp revision 2563601fc2b0505619f905f86bd249ae630197cc
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"
132563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXform_A2B.h"
1431d097e865f266c8398f45114e4c75c0dfdef058msarett#include "SkColorSpaceXform_Base.h"
152563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXformPriv.h"
16200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkHalf.h"
17200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkOpts.h"
18ac41bac40f5a80d2bc5ccec584c23478a6900179mtklein#include "SkSRGB.h"
199876ac5b3016e5353c072378ac1545a0a2270757msarett
206006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic constexpr float sk_linear_from_2dot2[256] = {
21b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
22b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
23b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
24b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
25b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
26b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
27b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
28b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
29b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
30b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
31b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
32b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
33b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
34b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
35b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
36b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
37b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
38b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
39b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
40b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
41b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
42b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
43b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
44b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
45b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
46b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
47b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
48b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
49b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
50b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
51b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
52b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
53b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
54b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
55b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
56b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
57b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
58b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
59b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
60b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
61b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
62b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
63b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
64b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
65b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
66b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
67b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
68b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
69b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
70b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
71b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
72b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
73b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
74b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
75b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
76b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
77b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
78b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
79b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
80b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
81b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
82b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
83b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
84b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
85b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
86b39067696ad08a26bbe49b71a71f0546dc42a075msarett
876006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
886006f678e78af7b6f67a454cd4bc213048983f9dmsarett
8915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float exponent) {
9015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
9115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = powf(x, exponent);
9215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
9315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
9415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
9515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// outTable is always 256 entries, inTable may be larger or smaller.
9615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, const float* inTable,
9715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          int inTableSize) {
9815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    if (256 == inTableSize) {
9915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        memcpy(outTable, inTable, sizeof(float) * 256);
10015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        return;
10115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
10215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
10315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
10415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = interp_lut(x, inTable, inTableSize);
10515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
10615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
10715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
108aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarettstatic inline float clamp_0_1(float v) {
109aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett    if (v >= 1.0f) {
110aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett        return 1.0f;
111aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett    } else if (v >= 0.0f) {
112aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett        return v;
113aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett    } else {
114aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett        return 0.0f;
115aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett    }
116aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett}
117aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett
11815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
11915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          float d, float e, float f) {
12015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = (aX + b)^g + c  for X >= d
12115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = eX + f          otherwise
12215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
12315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        if (x >= d) {
124aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett            *outTable++ = clamp_0_1(powf(a * x + b, g) + c);
12515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        } else {
126aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett            *outTable++ = clamp_0_1(e * x + f);
12715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        }
12815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
12915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
13015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
13115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
13215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
133a9e878c836994bce695274b4c28890290139dcdfmsarett// Expand range from 0-1 to 0-255, then convert.
134b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic uint8_t clamp_normalized_float_to_byte(float v) {
135dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // The ordering of the logic is a little strange here in order
136dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // to make sure we convert NaNs to 0.
1379876ac5b3016e5353c072378ac1545a0a2270757msarett    v = v * 255.0f;
138a9e878c836994bce695274b4c28890290139dcdfmsarett    if (v >= 254.5f) {
1399876ac5b3016e5353c072378ac1545a0a2270757msarett        return 255;
140dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else if (v >= 0.5f) {
1419876ac5b3016e5353c072378ac1545a0a2270757msarett        return (uint8_t) (v + 0.5f);
142dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else {
143dea0340cadb759932e53416a657f5ea75fee8b5fmsarett        return 0;
1449876ac5b3016e5353c072378ac1545a0a2270757msarett    }
1459876ac5b3016e5353c072378ac1545a0a2270757msarett}
1469876ac5b3016e5353c072378ac1545a0a2270757msarett
147f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettstatic const int kDstGammaTableSize = SkColorSpaceXform_Base::kDstGammaTableSize;
1483418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1491b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
150b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float toGammaExp = 1.0f / exponent;
151b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1523418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
1533418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
154b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
155b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
156dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
157dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
1581b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
159b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        int inTableSize) {
1603418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
1613418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
162b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_interp_lut(x, inTable, inTableSize);
163b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
164b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
165b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
166dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
167b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
168b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                float f) {
169b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // We need to take the inverse of the following piecewise function.
170b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = (aX + b)^g + c  for X >= d
171b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = eX + f          otherwise
172b39067696ad08a26bbe49b71a71f0546dc42a075msarett
173b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Assume that the gamma function is continuous, or this won't make much sense anyway.
174b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Plug in |d| to the first equation to calculate the new piecewise interval.
175b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Then simply use the inverse of the original functions.
176b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float interval = e * d + f;
177b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (x < interval) {
178b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // X = (Y - F) / E
179b39067696ad08a26bbe49b71a71f0546dc42a075msarett        if (0.0f == e) {
180b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // The gamma curve for this segment is constant, so the inverse is undefined.
181b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // Since this is the lower segment, guess zero.
182b39067696ad08a26bbe49b71a71f0546dc42a075msarett            return 0.0f;
183b39067696ad08a26bbe49b71a71f0546dc42a075msarett        }
184b39067696ad08a26bbe49b71a71f0546dc42a075msarett
185b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return (x - f) / e;
186b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
187b39067696ad08a26bbe49b71a71f0546dc42a075msarett
188b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // X = ((Y - C)^(1 / G) - B) / A
189b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (0.0f == a || 0.0f == g) {
190b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // The gamma curve for this segment is constant, so the inverse is undefined.
191b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // Since this is the upper segment, guess one.
192b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
193b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
194b39067696ad08a26bbe49b71a71f0546dc42a075msarett
195b39067696ad08a26bbe49b71a71f0546dc42a075msarett    return (powf(x - c, 1.0f / g) - b) / a;
196b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
197b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1981b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
199b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        float b, float c, float d, float e, float f) {
2003418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
2013418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
202b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_parametric(x, g, a, b, c, d, e, f);
203b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
204b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
205b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
206b39067696ad08a26bbe49b71a71f0546dc42a075msarett
2076006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
2086006f678e78af7b6f67a454cd4bc213048983f9dmsarett
2091b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
2101b93bd1e6eba3d14593490e4e24a34546638c8damsarettstruct GammaFns {
2111b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* fSRGBTable;
2121b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* f2Dot2Table;
2131b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromValue)(T*, float);
2141b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromTable)(T*, const float*, int);
2151b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
2161b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2171b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2181b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<float> kToLinear {
2191b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_srgb,
2201b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_2dot2,
2211b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
2221b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
2231b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
2241b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2251b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2261b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<uint8_t> kFromLinear {
22755bcc8e0af3415601b3d62252a0d579fbe87c85amsarett    nullptr,
22855bcc8e0af3415601b3d62252a0d579fbe87c85amsarett    nullptr,
2291b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2301b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2311b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2321b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2331b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2341b93bd1e6eba3d14593490e4e24a34546638c8damsarett// Build tables to transform src gamma to linear.
2351b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
2361b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
2379488833428e83c93a7e6002f4d056084fb57112fraftias                               const SkColorSpace_XYZ* space, const GammaFns<T>& fns,
238f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                               bool gammasAreMatching)
2394be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett{
2409488833428e83c93a7e6002f4d056084fb57112fraftias    switch (space->gammaNamed()) {
241600c737b64eae2c7379442ae2c852853cce3a278msarett        case kSRGB_SkGammaNamed:
2421b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
2431b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
244600c737b64eae2c7379442ae2c852853cce3a278msarett        case k2Dot2Curve_SkGammaNamed:
2451b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
2461b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
247600c737b64eae2c7379442ae2c852853cce3a278msarett        case kLinear_SkGammaNamed:
2488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr;
2491b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
2501b93bd1e6eba3d14593490e4e24a34546638c8damsarett        default: {
2519488833428e83c93a7e6002f4d056084fb57112fraftias            const SkGammas* gammas = space->gammas();
2521b93bd1e6eba3d14593490e4e24a34546638c8damsarett            SkASSERT(gammas);
2531b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2547bbda991af353fbe6b34132132d211d23a3dba8cmsarett            auto build_table = [=](int i) {
2551b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (gammas->isNamed(i)) {
2561b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    switch (gammas->data(i).fNamed) {
257600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kSRGB_SkGammaNamed:
25855bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f,
25955bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                                                   (1.0f / 1.055f), (0.055f / 1.055f), 0.0f,
26055bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                                                   0.04045f, (1.0f / 12.92f), 0.0f);
26155bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2621b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
263600c737b64eae2c7379442ae2c852853cce3a278msarett                        case k2Dot2Curve_SkGammaNamed:
26455bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f);
26555bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2661b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
267600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kLinear_SkGammaNamed:
2681b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
2691b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2701b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2711b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        default:
2721b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            SkASSERT(false);
2731b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2741b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
2751b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isValue(i)) {
2761b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
2771b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fValue);
2781b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2791b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isTable(i)) {
2801b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
2811b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fTable.fSize);
2821b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2831b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else {
2841b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    SkASSERT(gammas->isParametric(i));
285df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett                    const SkColorSpaceTransferFn& params = gammas->params(i);
2861b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
2871b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fA, params.fB, params.fC, params.fD, params.fE,
2881b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fF);
2891b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2901b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
2917bbda991af353fbe6b34132132d211d23a3dba8cmsarett            };
2927bbda991af353fbe6b34132132d211d23a3dba8cmsarett
2937bbda991af353fbe6b34132132d211d23a3dba8cmsarett            if (gammasAreMatching) {
2947bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
2957bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[1] = outGammaTables[0];
2967bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[2] = outGammaTables[0];
2977bbda991af353fbe6b34132132d211d23a3dba8cmsarett            } else {
2987bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
2997bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(1);
3007bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(2);
3011b93bd1e6eba3d14593490e4e24a34546638c8damsarett            }
3027bbda991af353fbe6b34132132d211d23a3dba8cmsarett
3037bbda991af353fbe6b34132132d211d23a3dba8cmsarett            break;
3041b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
3051b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
3061b93bd1e6eba3d14593490e4e24a34546638c8damsarett}
3071b93bd1e6eba3d14593490e4e24a34546638c8damsarett
308f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettvoid SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3],
3099488833428e83c93a7e6002f4d056084fb57112fraftias                                                 uint8_t* dstStorage,
3109488833428e83c93a7e6002f4d056084fb57112fraftias                                                 const SkColorSpace_XYZ* space,
311f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                                                 bool gammasAreMatching) {
312f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear,
313f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                       gammasAreMatching);
314f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett}
315f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
3161b93bd1e6eba3d14593490e4e24a34546638c8damsarett///////////////////////////////////////////////////////////////////////////////////////////////////
3171b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3184be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace,
3194be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett                                                          SkColorSpace* dstSpace) {
3206006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!srcSpace || !dstSpace) {
3216006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // Invalid input
3226006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
3236006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3246006f678e78af7b6f67a454cd4bc213048983f9dmsarett
3259488833428e83c93a7e6002f4d056084fb57112fraftias    if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) {
3262563601fc2b0505619f905f86bd249ae630197ccraftias        SkCSXformPrintf("A2B destinations not supported\n");
3279488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
3289488833428e83c93a7e6002f4d056084fb57112fraftias    }
3299488833428e83c93a7e6002f4d056084fb57112fraftias
3309488833428e83c93a7e6002f4d056084fb57112fraftias    if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) {
3312563601fc2b0505619f905f86bd249ae630197ccraftias        SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace);
3322563601fc2b0505619f905f86bd249ae630197ccraftias        SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace);
3332563601fc2b0505619f905f86bd249ae630197ccraftias        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(src, dst));
3349488833428e83c93a7e6002f4d056084fb57112fraftias    }
3359488833428e83c93a7e6002f4d056084fb57112fraftias    SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace);
3369488833428e83c93a7e6002f4d056084fb57112fraftias    SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace);
3379488833428e83c93a7e6002f4d056084fb57112fraftias
338200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    ColorSpaceMatch csm = kNone_ColorSpaceMatch;
3396006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
3404be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    if (SkColorSpace::Equals(srcSpace, dstSpace)) {
341200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        srcToDst.setIdentity();
342200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        csm = kFull_ColorSpaceMatch;
343971cd496b9e25f87f3a75a0015c203322907136abrianosman    } else {
344bbf251bf225489a0939fff6df938035a290f4d16Brian Osman        if (srcSpaceXYZ->toXYZD50Hash() == dstSpaceXYZ->toXYZD50Hash()) {
345bbf251bf225489a0939fff6df938035a290f4d16Brian Osman            SkASSERT(*srcSpaceXYZ->toXYZD50() == *dstSpaceXYZ->toXYZD50() && "Hash collision");
346971cd496b9e25f87f3a75a0015c203322907136abrianosman            srcToDst.setIdentity();
347971cd496b9e25f87f3a75a0015c203322907136abrianosman            csm = kGamut_ColorSpaceMatch;
348bbf251bf225489a0939fff6df938035a290f4d16Brian Osman        } else {
349bbf251bf225489a0939fff6df938035a290f4d16Brian Osman            srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50());
350971cd496b9e25f87f3a75a0015c203322907136abrianosman        }
3516006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3526006f678e78af7b6f67a454cd4bc213048983f9dmsarett
353200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    switch (csm) {
354200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kNone_ColorSpaceMatch:
3559488833428e83c93a7e6002f4d056084fb57112fraftias            switch (dstSpaceXYZ->gammaNamed()) {
356600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
3579488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
358f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3598bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch>
3609488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3618bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
362f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch>
3649488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
366600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
3679488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
368f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch>
3709488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3718bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
372f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3738bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch>
3749488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
3768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
3779488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
378f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch>
3809488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3818bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
382f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch>
3849488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
386200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
3879488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
388f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3898bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
3909488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
392f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
3938bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
3949488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
3958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
396200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
397200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kGamut_ColorSpaceMatch:
3989488833428e83c93a7e6002f4d056084fb57112fraftias            switch (dstSpaceXYZ->gammaNamed()) {
399600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
4009488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
401f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch>
4039488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
405f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch>
4079488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
409600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
4109488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
411f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch>
4139488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
415f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch>
4179488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
4198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
4209488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
421f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4228bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch>
4239488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
425f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch>
4279488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
429200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
4309488833428e83c93a7e6002f4d056084fb57112fraftias                    if (srcSpaceXYZ->gammaIsLinear()) {
431f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kLinear_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch>
4339488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    } else {
435f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                                <kTable_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch>
4379488833428e83c93a7e6002f4d056084fb57112fraftias                                (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    }
439200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
440200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kFull_ColorSpaceMatch:
4419488833428e83c93a7e6002f4d056084fb57112fraftias            switch (dstSpaceXYZ->gammaNamed()) {
442600c737b64eae2c7379442ae2c852853cce3a278msarett                case kSRGB_SkGammaNamed:
443f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, kSRGB_DstGamma, kFull_ColorSpaceMatch>
4459488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
446600c737b64eae2c7379442ae2c852853cce3a278msarett                case k2Dot2Curve_SkGammaNamed:
447f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, k2Dot2_DstGamma, kFull_ColorSpaceMatch>
4499488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
4508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_SkGammaNamed:
451f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4528bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kLinear_SrcGamma, kLinear_DstGamma, kFull_ColorSpaceMatch>
4539488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
454200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
455f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
4568bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                            <kTable_SrcGamma, kTable_DstGamma, kFull_ColorSpaceMatch>
4579488833428e83c93a7e6002f4d056084fb57112fraftias                            (srcSpaceXYZ, srcToDst, dstSpaceXYZ));
458200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
4593418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        default:
460200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            SkASSERT(false);
461200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            return nullptr;
4626006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4636006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
4646006f678e78af7b6f67a454cd4bc213048983f9dmsarett
4656006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
4666006f678e78af7b6f67a454cd4bc213048983f9dmsarett
467df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett#define AI SK_ALWAYS_INLINE
468df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett
469df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_matrix(const float matrix[16],
470df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
471200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rXgXbX = Sk4f::Load(matrix +  0);
472200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rYgYbY = Sk4f::Load(matrix +  4);
473200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rZgZbZ = Sk4f::Load(matrix +  8);
474200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rTgTbT = Sk4f::Load(matrix + 12);
475200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
476200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
477cf7b877d62537672b67449bc96858cc1262be5f8msarettenum Order {
478cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_Order,
479cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_Order,
480cf7b877d62537672b67449bc96858cc1262be5f8msarett};
481cf7b877d62537672b67449bc96858cc1262be5f8msarett
482df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) {
483cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kRGBA_Order == kOrder) {
484cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 0;
485cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 16;
486cf7b877d62537672b67449bc96858cc1262be5f8msarett    } else {
487cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 16;
488cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 0;
489cf7b877d62537672b67449bc96858cc1262be5f8msarett    }
490cf7b877d62537672b67449bc96858cc1262be5f8msarett}
491cf7b877d62537672b67449bc96858cc1262be5f8msarett
492cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
493df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgb_from_tables(const uint32_t* src,
494df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                    Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
495df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                    const float* const srcTables[3]) {
496cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
497cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
498cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
499cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
500cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
501cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
502cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
503cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
504cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
505cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
506cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
507cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
508cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
509cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
510200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
511200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
512200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
513cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
514df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgba_from_tables(const uint32_t* src,
515df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                     Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
516df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                     const float* const srcTables[3]) {
517cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
518cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
519cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
520cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
521cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
522cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
5235414be06935ce0f990a2df5dccaf9ddec78ec553msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
524cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
525cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
526cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
527cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
528cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
529cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
530cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
531200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
532200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
533200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
534cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
5352563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void load_rgb_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
536df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const float* const[3]) {
537cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
538cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
539cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
540cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
541cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
542be362774f9b9e8964544a579281603ed995e6e5amsarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
5438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
5448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
545cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
5462563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void load_rgba_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
547df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                const float* const[3]) {
548cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
549cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
550cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
551cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
552cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
553cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 24));
5548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
5558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
556cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
557df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgb_from_tables_1(const uint32_t* src,
558df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                      Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
559df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                      const float* const srcTables[3]) {
560cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
561cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
562cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
563cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
564cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
565a9f64dec63b6f4169ba16f8b6c63fff5a6494029Matt Sarett    a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
566200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
567200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
568cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
569df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgba_from_tables_1(const uint32_t* src,
570df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                       Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
571df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                       const float* const srcTables[3]) {
572cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
573cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
574cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
575cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
576cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
577200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * Sk4f(*src >> 24);
578200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
579200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
580cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
581df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgb_linear_1(const uint32_t* src,
582df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
583df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 const float* const srcTables[3]) {
584cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
585cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
586cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
587cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
588cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
589a9f64dec63b6f4169ba16f8b6c63fff5a6494029Matt Sarett    a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
5908bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
5918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
592cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
593df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgba_linear_1(const uint32_t* src,
594df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
595df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  const float* const srcTables[3]) {
596cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
597cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
598cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
599cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
600cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
601cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = Sk4f((1.0f / 255.0f) * ((*src >> 24)));
6028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6038bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
604df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
605df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
606df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
607200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
608200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
609200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
610200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    da = a;
611200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
612200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
613df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
614df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
615df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 Sk4f& rgba) {
616200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
617200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
618200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
619df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
620200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = dr + rTgTbT[0];
621200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = dg + rTgTbT[1];
622200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = db + rTgTbT[2];
623200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
624200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
625df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
626200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rgba + rTgTbT;
627200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
628200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
629df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) {
630200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = da * dr;
631200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = da * dg;
632200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = da * db;
633200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
634200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
635df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void premultiply_1(const Sk4f& a, Sk4f& rgba) {
636200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = a * rgba;
637200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
638200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
639cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6402563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_srgb(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
641df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                          const uint8_t* const[3]) {
642cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
643cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
644200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_linear_to_srgb_needs_trunc(dr);
645200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_linear_to_srgb_needs_trunc(dg);
646200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_linear_to_srgb_needs_trunc(db);
647200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
648200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
649200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
650200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
651200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
652200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
653200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
654200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
655200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(dg) << kGShift)
656200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(db) << kBShift)
657200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                           );
658200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
659200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
660200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
661cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
662df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_srgb_1(void* dst, const uint32_t* src,
663df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                            Sk4f& rgba, const Sk4f&,
664df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                            const uint8_t* const[3]) {
665200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
666200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
667200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
668200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
669200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
670cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
671200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
672200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
673200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
674200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
675200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
676200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
677df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI Sk4f linear_to_2dot2(const Sk4f& x) {
678200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
679200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    auto x2  = x.rsqrt(),                            // x^(-1/2)
680200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(),   // x^(-1/32)
681200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x64 = x32.rsqrt();                          // x^(+1/64)
682200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
683200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // 29 = 32 - 2 - 1
684200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return 255.0f * x2.invert() * x32 * x64.invert();
685200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
686200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
687cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6882563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_2dot2(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
689df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           const uint8_t* const[3]) {
690cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
691cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
692200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = linear_to_2dot2(dr);
693200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = linear_to_2dot2(dg);
694200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = linear_to_2dot2(db);
695200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
696200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
697200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
698200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
699200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
700200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
701200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
702200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
703200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(dg) << kGShift)
704200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(db) << kBShift)
705200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                       );
706200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
707200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
708200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
709cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
710df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_2dot2_1(void* dst, const uint32_t* src,
711df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             Sk4f& rgba, const Sk4f&,
712df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             const uint8_t* const[3]) {
713200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
714200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
715200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
716200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
717200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
718cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
719200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
720200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
721200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
722200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
723200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
724200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
725cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7262563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_linear(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
727df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                            const uint8_t* const[3]) {
728cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
729cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
730591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dr = sk_clamp_0_255(255.0f * dr);
731591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    dg = sk_clamp_0_255(255.0f * dg);
732591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    db = sk_clamp_0_255(255.0f * db);
7338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
7358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
7378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(dg) << kGShift)
7388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(db) << kBShift)
7398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (da                       );
7408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    rgba.store(dst);
7418bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7428bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
743cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
744df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_linear_1(void* dst, const uint32_t* src,
745df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                              Sk4f& rgba, const Sk4f&,
746df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                              const uint8_t* const[3]) {
747591971d02a8e22dac0955c0f07b7cf500a89d5ccmsarett    rgba = sk_clamp_0_255(255.0f * rgba);
7488bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7498bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    uint32_t tmp;
7508bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
7518bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
752cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
7538bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        tmp = SkSwizzle_RB(tmp);
7548bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
7558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7568bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    *(uint32_t*)dst = tmp;
7578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
7588bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
759cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7602563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_f16(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
7612563601fc2b0505619f905f86bd249ae630197ccraftias                         const uint8_t* const[3]) {
76233cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
76333cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
76433cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
76533cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(da));
766200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
767200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
768cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
769df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_f16_1(void* dst, const uint32_t* src,
770df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           Sk4f& rgba, const Sk4f& a,
771df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           const uint8_t* const[3]) {
772200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
7738ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst);
774200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
775200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
776cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7772563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_f32(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
778df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                         const uint8_t* const[3]) {
77933cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4f::Store4(dst, dr, dg, db, da);
780c0444615ed76360f680619ad4d1f92cda6181a50msarett}
781c0444615ed76360f680619ad4d1f92cda6181a50msarett
782cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
783df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_f32_1(void* dst, const uint32_t* src,
784df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           Sk4f& rgba, const Sk4f& a,
785df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           const uint8_t* const[3]) {
786c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
787c0444615ed76360f680619ad4d1f92cda6181a50msarett    rgba.store((float*) dst);
788c0444615ed76360f680619ad4d1f92cda6181a50msarett}
789c0444615ed76360f680619ad4d1f92cda6181a50msarett
790cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
7912563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_f16_opaque(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db,
7922563601fc2b0505619f905f86bd249ae630197ccraftias                                Sk4f&, const uint8_t* const[3]) {
79333cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
79433cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
79533cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
79633cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SK_Half1);
797200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
798200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
799cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
800df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_f16_1_opaque(void* dst, const uint32_t* src,
801df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  Sk4f& rgba, const Sk4f&,
802df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  const uint8_t* const[3]) {
803200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint64_t tmp;
8048ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store(&tmp);
805200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp |= static_cast<uint64_t>(SK_Half1) << 48;
806200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *((uint64_t*) dst) = tmp;
807200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
808200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
809cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
8102563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_generic(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
8112563601fc2b0505619f905f86bd249ae630197ccraftias                             const uint8_t* const dstTables[3]) {
812cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
813cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
814200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
815200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
816200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
817200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
818200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ir = Sk4f_round(dr);
819200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ig = Sk4f_round(dg);
820200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ib = Sk4f_round(db);
821200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
822200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
823200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
824200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t* dst32 = (uint32_t*) dst;
825200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[0] = dstTables[0][ir[0]] << kRShift
826200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[0]] << kGShift
827200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[0]] << kBShift
828200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[0];
829200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[1] = dstTables[0][ir[1]] << kRShift
830200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[1]] << kGShift
831200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[1]] << kBShift
832200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[1];
833200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[2] = dstTables[0][ir[2]] << kRShift
834200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[2]] << kGShift
835200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[2]] << kBShift
836200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[2];
837200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[3] = dstTables[0][ir[3]] << kRShift
838200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[3]] << kGShift
839200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[3]] << kBShift
840200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[3];
841200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
842200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
843cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
844df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_generic_1(void* dst, const uint32_t* src,
845df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               Sk4f& rgba, const Sk4f&,
846df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const uint8_t* const dstTables[3]) {
847cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
848cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
849200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
850200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
851200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i indices = Sk4f_round(rgba);
852200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
8539dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
8549dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[1][indices[1]] << kGShift
8559dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[2][indices[2]] << kBShift
856200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | (*src & 0xFF000000);
857200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
858200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
859cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables<kRGBA_Order>  )* LoadFn;
860cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables_1<kRGBA_Order>)* Load1Fn;
861cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic<kRGBA_Order>         )* StoreFn;
862cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic_1<kRGBA_Order>       )* Store1Fn;
8638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8648bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum SrcFormat {
8658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Linear_SrcFormat,
8668bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Table_SrcFormat,
867cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_SrcFormat,
868cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_SrcFormat,
8698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
8708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8718bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum DstFormat {
872cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Linear_DstFormat,
873cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_SRGB_DstFormat,
874cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_2Dot2_DstFormat,
875cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Table_DstFormat,
876cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_DstFormat,
877cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_SRGB_DstFormat,
878cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_2Dot2_DstFormat,
879cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_DstFormat,
8808bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kF16_Linear_DstFormat,
881c0444615ed76360f680619ad4d1f92cda6181a50msarett    kF32_Linear_DstFormat,
8828bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
8838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
8848bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcFormat kSrc,
8858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          DstFormat kDst,
8868bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          SkAlphaType kAlphaType,
887cf7b877d62537672b67449bc96858cc1262be5f8msarett          ColorSpaceMatch kCSM>
8885934646b4937a05d5e8297448ea6613a89f8903aMatt Sarettstatic void color_xform_RGBA(void* dst, const void* vsrc, int len,
8895934646b4937a05d5e8297448ea6613a89f8903aMatt Sarett                             const float* const srcTables[3], const float matrix[16],
8905934646b4937a05d5e8297448ea6613a89f8903aMatt Sarett                             const uint8_t* const dstTables[3]) {
8918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    LoadFn load;
8928bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Load1Fn load_1;
893c0444615ed76360f680619ad4d1f92cda6181a50msarett    static constexpr bool loadAlpha = (kPremul_SkAlphaType == kAlphaType) ||
894c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF16_Linear_DstFormat == kDst) ||
895c0444615ed76360f680619ad4d1f92cda6181a50msarett                                      (kF32_Linear_DstFormat == kDst);
8968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kSrc) {
8978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Linear_SrcFormat:
898c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
899cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kRGBA_Order>;
900cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kRGBA_Order>;
9018bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
902cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kRGBA_Order>;
903cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kRGBA_Order>;
9048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
9058bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
9068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Table_SrcFormat:
907c0444615ed76360f680619ad4d1f92cda6181a50msarett            if (loadAlpha) {
908cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kRGBA_Order>;
909cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kRGBA_Order>;
9108bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
911cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kRGBA_Order>;
912cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kRGBA_Order>;
913cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
914cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
915cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_SrcFormat:
916cf7b877d62537672b67449bc96858cc1262be5f8msarett            if (loadAlpha) {
917cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kBGRA_Order>;
918cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kBGRA_Order>;
919cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
920cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kBGRA_Order>;
921cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kBGRA_Order>;
922cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
923cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
924cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_SrcFormat:
925cf7b877d62537672b67449bc96858cc1262be5f8msarett            if (loadAlpha) {
926cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kBGRA_Order>;
927cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kBGRA_Order>;
928cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
929cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kBGRA_Order>;
930cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kBGRA_Order>;
9318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
9328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
9338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
9348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
9358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    StoreFn store;
9368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Store1Fn store_1;
9378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    size_t sizeOfDstPixel;
9388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kDst) {
939cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Linear_DstFormat:
940cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kRGBA_Order>;
941cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kRGBA_Order>;
942cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
943cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
944cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_SRGB_DstFormat:
945cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kRGBA_Order>;
946cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kRGBA_Order>;
947cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
948cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
949cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_2Dot2_DstFormat:
950cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kRGBA_Order>;
951cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kRGBA_Order>;
9528bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
9538bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
954cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Table_DstFormat:
955cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kRGBA_Order>;
956cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kRGBA_Order>;
9578bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
9588bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
959cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_DstFormat:
960cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kBGRA_Order>;
961cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kBGRA_Order>;
9628bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
9638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
964cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_SRGB_DstFormat:
965cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kBGRA_Order>;
966cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kBGRA_Order>;
967cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
968cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
969cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_2Dot2_DstFormat:
970cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kBGRA_Order>;
971cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kBGRA_Order>;
972cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
973cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
974cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_DstFormat:
975cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kBGRA_Order>;
976cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kBGRA_Order>;
9778bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
9788bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
9798bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kF16_Linear_DstFormat:
980cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque<kRGBA_Order> :
981cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16<kRGBA_Order>;
982cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque<kRGBA_Order> :
983cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16_1<kRGBA_Order>;
9848bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 8;
9858bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
986c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kF32_Linear_DstFormat:
987cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_f32<kRGBA_Order>;
988cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_f32_1<kRGBA_Order>;
989c0444615ed76360f680619ad4d1f92cda6181a50msarett            sizeOfDstPixel = 16;
990c0444615ed76360f680619ad4d1f92cda6181a50msarett            break;
9918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
9928bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
993d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    const uint32_t* src = (const uint32_t*) vsrc;
994d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
995d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
996d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
997d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    if (len >= 4) {
998d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        // Naively this would be a loop of load-transform-store, but we found it faster to
999d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        // move the N+1th load ahead of the Nth store.  We don't bother doing this for N<4.
1000d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f r, g, b, a;
1001d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        load(src, r, g, b, a, srcTables);
1002d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        src += 4;
1003d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        len -= 4;
1004d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1005d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f dr, dg, db, da;
1006d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        while (len >= 4) {
1007d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            if (kNone_ColorSpaceMatch == kCSM) {
1008d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1009d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                translate_gamut(rTgTbT, dr, dg, db);
1010d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            } else {
1011d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                dr = r;
1012d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                dg = g;
1013d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                db = b;
1014d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                da = a;
1015d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            }
1016d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1017d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            if (kPremul_SkAlphaType == kAlphaType) {
1018d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                premultiply(dr, dg, db, da);
1019d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            }
1020d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1021d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            load(src, r, g, b, a, srcTables);
1022d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1023d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            store(dst, src - 4, dr, dg, db, da, dstTables);
1024d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1025d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            src += 4;
1026d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            len -= 4;
1027d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1028d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1029d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kNone_ColorSpaceMatch == kCSM) {
1030d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1031d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            translate_gamut(rTgTbT, dr, dg, db);
1032d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        } else {
1033d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dr = r;
1034d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dg = g;
1035d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            db = b;
1036d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            da = a;
1037d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1038d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1039d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kPremul_SkAlphaType == kAlphaType) {
1040d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            premultiply(dr, dg, db, da);
1041d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1042d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1043d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        store(dst, src - 4, dr, dg, db, da, dstTables);
1044d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1045d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    }
1046d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1047d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    while (len > 0) {
1048d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f r, g, b, a;
1049d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        load_1(src, r, g, b, a, srcTables);
1050d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1051d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f rgba;
1052d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kNone_ColorSpaceMatch == kCSM) {
1053d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
1054d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            translate_gamut_1(rTgTbT, rgba);
1055d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        } else {
1056d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            rgba = Sk4f(r[0], g[0], b[0], a[0]);
1057d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1058d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1059d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kPremul_SkAlphaType == kAlphaType) {
1060d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            premultiply_1(a, rgba);
1061d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
1062d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1063d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        store_1(dst, src, rgba, a, dstTables);
1064d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
1065d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        src += 1;
1066d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        len -= 1;
1067d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
1068d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    }
10698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
10708bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
10713418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett///////////////////////////////////////////////////////////////////////////////////////////////////
10720f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
10732563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI int num_tables(SkColorSpace_XYZ* space) {
10749488833428e83c93a7e6002f4d056084fb57112fraftias    switch (space->gammaNamed()) {
10757bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kSRGB_SkGammaNamed:
10767bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case k2Dot2Curve_SkGammaNamed:
10777bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kLinear_SkGammaNamed:
10787bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return 0;
10797bbda991af353fbe6b34132132d211d23a3dba8cmsarett        default: {
10809488833428e83c93a7e6002f4d056084fb57112fraftias            const SkGammas* gammas = space->gammas();
10817bbda991af353fbe6b34132132d211d23a3dba8cmsarett            SkASSERT(gammas);
10827bbda991af353fbe6b34132132d211d23a3dba8cmsarett
10837bbda991af353fbe6b34132132d211d23a3dba8cmsarett            bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
10847bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(1)) &&
10857bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->type(0) == gammas->type(2)) &&
10867bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(2));
10877bbda991af353fbe6b34132132d211d23a3dba8cmsarett
10887bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // It's likely that each component will have the same gamma.  In this case,
10897bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // we only need to build one table.
10907bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return gammasAreMatching ? 1 : 3;
10917bbda991af353fbe6b34132132d211d23a3dba8cmsarett        }
10927bbda991af353fbe6b34132132d211d23a3dba8cmsarett    }
10937bbda991af353fbe6b34132132d211d23a3dba8cmsarett}
10947bbda991af353fbe6b34132132d211d23a3dba8cmsarett
10958bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
1096f489886915034093278353d06c6f1973b2e8b7d2Matt SarettSkColorSpaceXform_XYZ<kSrc, kDst, kCSM>
10979488833428e83c93a7e6002f4d056084fb57112fraftias::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst,
10989488833428e83c93a7e6002f4d056084fb57112fraftias                        SkColorSpace_XYZ* dstSpace)
10993418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1100de68d6c4616d86621373d88100002ddfdb9c08e3brianosman    srcToDst.asColMajorf(fSrcToDst);
11017bbda991af353fbe6b34132132d211d23a3dba8cmsarett
11024be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    const int numSrcTables = num_tables(srcSpace);
1103f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    const size_t srcEntries = numSrcTables * 256;
11047bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const bool srcGammasAreMatching = (1 >= numSrcTables);
1105f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    fSrcStorage.reset(srcEntries);
1106f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear,
1107f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                       srcGammasAreMatching);
1108f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
1109f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    const int numDstTables = num_tables(dstSpace);
11109488833428e83c93a7e6002f4d056084fb57112fraftias    dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables);
11113418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
1112dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
11137bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
11147bbda991af353fbe6b34132132d211d23a3dba8cmsarett
1115cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
1116df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaType alphaType,
1117df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const float* const srcTables[3], const float matrix[16],
1118df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const uint8_t* const dstTables[3]) {
11198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (alphaType) {
11208bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kOpaque_SkAlphaType:
112131d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kOpaque_SkAlphaType, kCSM>
11228bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
112331d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
11248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kPremul_SkAlphaType:
112531d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kPremul_SkAlphaType, kCSM>
11268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
112731d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
11288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kUnpremul_SkAlphaType:
112931d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kUnpremul_SkAlphaType, kCSM>
11308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
113131d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
11328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        default:
113331d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
11348bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
11358bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
11368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
1137cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <SrcGamma kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
1138df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI bool apply_set_src(void* dst, const void* src, int len, SkAlphaType alphaType,
1139df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             const float* const srcTables[3], const float matrix[16],
1140df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             const uint8_t* const dstTables[3],
1141df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             SkColorSpaceXform::ColorFormat srcColorFormat) {
1142cf7b877d62537672b67449bc96858cc1262be5f8msarett    switch (srcColorFormat) {
1143cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kRGBA_8888_ColorFormat:
1144cf7b877d62537672b67449bc96858cc1262be5f8msarett            switch (kSrc) {
1145cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1146cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Linear_SrcFormat, kDst, kCSM>
1147cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1148cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kTable_SrcGamma:
1149cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Table_SrcFormat, kDst, kCSM>
1150cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1151cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1152cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kBGRA_8888_ColorFormat:
1153cf7b877d62537672b67449bc96858cc1262be5f8msarett            switch (kSrc) {
1154cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1155cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Linear_SrcFormat, kDst, kCSM>
1156cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1157cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kTable_SrcGamma:
1158cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Table_SrcFormat, kDst, kCSM>
1159cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1160cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1161cf7b877d62537672b67449bc96858cc1262be5f8msarett        default:
116231d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
11638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
11648bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
11658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
1166df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett#undef AI
1167df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett
11688bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM>
1169f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettbool SkColorSpaceXform_XYZ<kSrc, kDst, kCSM>
117031d097e865f266c8398f45114e4c75c0dfdef058msarett::onApply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, const void* src,
117131d097e865f266c8398f45114e4c75c0dfdef058msarett          int len, SkAlphaType alphaType) const
11723418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1173200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kFull_ColorSpaceMatch == kCSM) {
11748bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        switch (alphaType) {
1175200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            case kPremul_SkAlphaType:
1176200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // We can't skip the xform since we need to perform a premultiply in the
1177200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // linear space.
1178200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                break;
1179200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            default:
1180c0444615ed76360f680619ad4d1f92cda6181a50msarett                switch (dstColorFormat) {
1181c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_8888_ColorFormat:
118231d097e865f266c8398f45114e4c75c0dfdef058msarett                        memcpy(dst, src, len * sizeof(uint32_t));
118331d097e865f266c8398f45114e4c75c0dfdef058msarett                        return true;
1184c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kBGRA_8888_ColorFormat:
118531d097e865f266c8398f45114e4c75c0dfdef058msarett                        SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
118631d097e865f266c8398f45114e4c75c0dfdef058msarett                        return true;
1187c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F16_ColorFormat:
1188c0444615ed76360f680619ad4d1f92cda6181a50msarett                    case kRGBA_F32_ColorFormat:
1189c0444615ed76360f680619ad4d1f92cda6181a50msarett                        // There's still work to do to xform to linear floats.
1190200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        break;
1191200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    default:
119231d097e865f266c8398f45114e4c75c0dfdef058msarett                        return false;
1193200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                }
1194200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1195200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1196200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1197c0444615ed76360f680619ad4d1f92cda6181a50msarett    switch (dstColorFormat) {
1198c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_8888_ColorFormat:
11998bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
12008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1201cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_Linear_DstFormat, kCSM>
1202cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1203cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1205cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_SRGB_DstFormat, kCSM>
1206cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1207cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1209cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_2Dot2_DstFormat, kCSM>
1210cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1211cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1213cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kRGBA_8888_Table_DstFormat, kCSM>
1214cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1215cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1216d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1217c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kBGRA_8888_ColorFormat:
12188bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
12198bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1220cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_Linear_DstFormat, kCSM>
1221cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1222cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1224cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_SRGB_DstFormat, kCSM>
1225cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1226cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1228cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_2Dot2_DstFormat, kCSM>
1229cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1230cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
12318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1232cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kBGRA_8888_Table_DstFormat, kCSM>
1233cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1234cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1235d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1236c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F16_ColorFormat:
12378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            switch (kDst) {
12388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1239cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kF16_Linear_DstFormat, kCSM>
1240cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1241cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1242d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
124331d097e865f266c8398f45114e4c75c0dfdef058msarett                    return false;
1244d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1245c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F32_ColorFormat:
1246c0444615ed76360f680619ad4d1f92cda6181a50msarett            switch (kDst) {
1247c0444615ed76360f680619ad4d1f92cda6181a50msarett                case kLinear_DstGamma:
1248cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_src<kSrc, kF32_Linear_DstFormat, kCSM>
1249cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1250cf7b877d62537672b67449bc96858cc1262be5f8msarett                             srcColorFormat);
1251c0444615ed76360f680619ad4d1f92cda6181a50msarett                default:
125231d097e865f266c8398f45114e4c75c0dfdef058msarett                    return false;
1253c0444615ed76360f680619ad4d1f92cda6181a50msarett            }
1254d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        default:
125531d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
1256d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett    }
12579ce3a543c92a73e6daca420defc042886b3f2019msarett}
12589dc6cf6b8833d36c29a23d2519989b069745fcd5msarett
1259f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettbool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
1260f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                              const void* src, int len, SkAlphaType alphaType) const {
1261f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcColorFormat, src, len,
1262f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                                                     alphaType);
1263f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett}
1264f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
12657bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
12667bbda991af353fbe6b34132132d211d23a3dba8cmsarett
12679488833428e83c93a7e6002f4d056084fb57112fraftiasstd::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) {
1268f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
12698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch>
12709dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                (space, SkMatrix::I(), space));
12719dc6cf6b8833d36c29a23d2519989b069745fcd5msarett}
1272