SkColorSpaceXform.cpp revision 200877eecaba782e56a1dd9e13a92f36d7b1ba12
19876ac5b3016e5353c072378ac1545a0a2270757msarett/*
29876ac5b3016e5353c072378ac1545a0a2270757msarett * Copyright 2016 Google Inc.
39876ac5b3016e5353c072378ac1545a0a2270757msarett *
49876ac5b3016e5353c072378ac1545a0a2270757msarett * Use of this source code is governed by a BSD-style license that can be
59876ac5b3016e5353c072378ac1545a0a2270757msarett * found in the LICENSE file.
69876ac5b3016e5353c072378ac1545a0a2270757msarett */
79876ac5b3016e5353c072378ac1545a0a2270757msarett
89876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorPriv.h"
99876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorSpace_Base.h"
10200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkColorSpacePriv.h"
119876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorSpaceXform.h"
12200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkHalf.h"
13200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkOpts.h"
14ac41bac40f5a80d2bc5ccec584c23478a6900179mtklein#include "SkSRGB.h"
159876ac5b3016e5353c072378ac1545a0a2270757msarett
166006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic constexpr float sk_linear_from_2dot2[256] = {
17b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
18b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
19b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
20b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
21b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
22b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
23b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
24b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
25b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
26b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
27b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
28b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
29b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
30b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
31b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
32b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
33b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
34b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
35b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
36b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
37b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
38b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
39b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
40b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
41b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
42b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
43b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
44b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
45b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
46b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
47b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
48b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
49b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
50b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
51b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
52b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
53b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
54b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
55b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
56b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
57b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
58b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
59b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
60b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
61b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
62b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
63b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
64b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
65b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
66b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
67b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
68b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
69b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
70b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
71b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
72b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
73b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
74b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
75b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
76b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
77b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
78b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
79b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
80b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
81b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
82b39067696ad08a26bbe49b71a71f0546dc42a075msarett
836006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
846006f678e78af7b6f67a454cd4bc213048983f9dmsarett
85b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic constexpr uint8_t linear_to_srgb[1024] = {
86b39067696ad08a26bbe49b71a71f0546dc42a075msarett          0,   3,   6,  10,  13,  15,  18,  20,  22,  23,  25,  27,  28,  30,  31,  32,  34,  35,
87b39067696ad08a26bbe49b71a71f0546dc42a075msarett         36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  49,  50,  51,  52,
88b39067696ad08a26bbe49b71a71f0546dc42a075msarett         53,  53,  54,  55,  56,  56,  57,  58,  58,  59,  60,  61,  61,  62,  62,  63,  64,  64,
89b39067696ad08a26bbe49b71a71f0546dc42a075msarett         65,  66,  66,  67,  67,  68,  68,  69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,
90b39067696ad08a26bbe49b71a71f0546dc42a075msarett         75,  76,  76,  77,  77,  78,  78,  79,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,
91b39067696ad08a26bbe49b71a71f0546dc42a075msarett         84,  84,  85,  85,  85,  86,  86,  87,  87,  88,  88,  88,  89,  89,  90,  90,  91,  91,
92b39067696ad08a26bbe49b71a71f0546dc42a075msarett         91,  92,  92,  93,  93,  93,  94,  94,  95,  95,  95,  96,  96,  97,  97,  97,  98,  98,
93b39067696ad08a26bbe49b71a71f0546dc42a075msarett         98,  99,  99,  99, 100, 100, 101, 101, 101, 102, 102, 102, 103, 103, 103, 104, 104, 104,
94b39067696ad08a26bbe49b71a71f0546dc42a075msarett        105, 105, 106, 106, 106, 107, 107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110,
95b39067696ad08a26bbe49b71a71f0546dc42a075msarett        111, 111, 111, 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
96b39067696ad08a26bbe49b71a71f0546dc42a075msarett        116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120, 120, 120, 121, 121, 121, 121,
97b39067696ad08a26bbe49b71a71f0546dc42a075msarett        122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 126,
98b39067696ad08a26bbe49b71a71f0546dc42a075msarett        127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131,
99b39067696ad08a26bbe49b71a71f0546dc42a075msarett        131, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135, 136, 136,
100b39067696ad08a26bbe49b71a71f0546dc42a075msarett        136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 140,
101b39067696ad08a26bbe49b71a71f0546dc42a075msarett        140, 141, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 143, 143, 144, 144, 144, 144,
102b39067696ad08a26bbe49b71a71f0546dc42a075msarett        145, 145, 145, 145, 146, 146, 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, 148, 148,
103b39067696ad08a26bbe49b71a71f0546dc42a075msarett        149, 149, 149, 149, 150, 150, 150, 150, 150, 151, 151, 151, 151, 152, 152, 152, 152, 152,
104b39067696ad08a26bbe49b71a71f0546dc42a075msarett        153, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, 155, 155, 155, 156, 156, 156, 156,
105b39067696ad08a26bbe49b71a71f0546dc42a075msarett        156, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 159, 159, 159, 159, 159, 160, 160,
106b39067696ad08a26bbe49b71a71f0546dc42a075msarett        160, 160, 160, 161, 161, 161, 161, 161, 162, 162, 162, 162, 162, 163, 163, 163, 163, 163,
107b39067696ad08a26bbe49b71a71f0546dc42a075msarett        164, 164, 164, 164, 164, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 167, 167, 167,
108b39067696ad08a26bbe49b71a71f0546dc42a075msarett        167, 167, 168, 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170,
109b39067696ad08a26bbe49b71a71f0546dc42a075msarett        171, 171, 171, 171, 171, 171, 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, 173, 174,
110b39067696ad08a26bbe49b71a71f0546dc42a075msarett        174, 174, 174, 174, 175, 175, 175, 175, 175, 175, 176, 176, 176, 176, 176, 177, 177, 177,
111b39067696ad08a26bbe49b71a71f0546dc42a075msarett        177, 177, 177, 178, 178, 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, 180, 180, 180,
112b39067696ad08a26bbe49b71a71f0546dc42a075msarett        180, 180, 181, 181, 181, 181, 181, 181, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183,
113b39067696ad08a26bbe49b71a71f0546dc42a075msarett        183, 183, 184, 184, 184, 184, 184, 184, 185, 185, 185, 185, 185, 185, 186, 186, 186, 186,
114b39067696ad08a26bbe49b71a71f0546dc42a075msarett        186, 186, 187, 187, 187, 187, 187, 187, 188, 188, 188, 188, 188, 188, 189, 189, 189, 189,
115b39067696ad08a26bbe49b71a71f0546dc42a075msarett        189, 189, 190, 190, 190, 190, 190, 190, 191, 191, 191, 191, 191, 191, 191, 192, 192, 192,
116b39067696ad08a26bbe49b71a71f0546dc42a075msarett        192, 192, 192, 193, 193, 193, 193, 193, 193, 194, 194, 194, 194, 194, 194, 194, 195, 195,
117b39067696ad08a26bbe49b71a71f0546dc42a075msarett        195, 195, 195, 195, 196, 196, 196, 196, 196, 196, 197, 197, 197, 197, 197, 197, 197, 198,
118b39067696ad08a26bbe49b71a71f0546dc42a075msarett        198, 198, 198, 198, 198, 199, 199, 199, 199, 199, 199, 199, 200, 200, 200, 200, 200, 200,
119b39067696ad08a26bbe49b71a71f0546dc42a075msarett        200, 201, 201, 201, 201, 201, 201, 202, 202, 202, 202, 202, 202, 202, 203, 203, 203, 203,
120b39067696ad08a26bbe49b71a71f0546dc42a075msarett        203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 205, 205, 205, 205, 205, 205, 206, 206,
121b39067696ad08a26bbe49b71a71f0546dc42a075msarett        206, 206, 206, 206, 206, 207, 207, 207, 207, 207, 207, 207, 208, 208, 208, 208, 208, 208,
122b39067696ad08a26bbe49b71a71f0546dc42a075msarett        208, 209, 209, 209, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210, 210, 211, 211, 211,
123b39067696ad08a26bbe49b71a71f0546dc42a075msarett        211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213,
124b39067696ad08a26bbe49b71a71f0546dc42a075msarett        213, 214, 214, 214, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 216, 216, 216,
125b39067696ad08a26bbe49b71a71f0546dc42a075msarett        216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 218, 218, 218, 218, 218, 218,
126b39067696ad08a26bbe49b71a71f0546dc42a075msarett        218, 219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 221, 221,
127b39067696ad08a26bbe49b71a71f0546dc42a075msarett        221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222, 222, 222, 222, 223, 223, 223, 223,
128b39067696ad08a26bbe49b71a71f0546dc42a075msarett        223, 223, 223, 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 225,
129b39067696ad08a26bbe49b71a71f0546dc42a075msarett        225, 226, 226, 226, 226, 226, 226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228,
130b39067696ad08a26bbe49b71a71f0546dc42a075msarett        228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, 230,
131b39067696ad08a26bbe49b71a71f0546dc42a075msarett        230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232, 232, 232, 232,
132b39067696ad08a26bbe49b71a71f0546dc42a075msarett        232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234,
133b39067696ad08a26bbe49b71a71f0546dc42a075msarett        235, 235, 235, 235, 235, 235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 237,
134b39067696ad08a26bbe49b71a71f0546dc42a075msarett        237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 238, 238, 239, 239, 239,
135b39067696ad08a26bbe49b71a71f0546dc42a075msarett        239, 239, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, 241,
136b39067696ad08a26bbe49b71a71f0546dc42a075msarett        241, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243,
137b39067696ad08a26bbe49b71a71f0546dc42a075msarett        243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245,
138b39067696ad08a26bbe49b71a71f0546dc42a075msarett        245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247,
139b39067696ad08a26bbe49b71a71f0546dc42a075msarett        247, 247, 248, 248, 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249, 249, 249,
140b39067696ad08a26bbe49b71a71f0546dc42a075msarett        249, 249, 250, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251,
141b39067696ad08a26bbe49b71a71f0546dc42a075msarett        251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253,
142b39067696ad08a26bbe49b71a71f0546dc42a075msarett        253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255
143b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
144b39067696ad08a26bbe49b71a71f0546dc42a075msarett
14515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic constexpr uint8_t linear_to_2dot2_table[1024] = {
146b39067696ad08a26bbe49b71a71f0546dc42a075msarett          0,  11,  15,  18,  21,  23,  25,  26,  28,  30,  31,  32,  34,  35,  36,  37,  39,  40,
147b39067696ad08a26bbe49b71a71f0546dc42a075msarett         41,  42,  43,  44,  45,  45,  46,  47,  48,  49,  50,  50,  51,  52,  53,  54,  54,  55,
148b39067696ad08a26bbe49b71a71f0546dc42a075msarett         56,  56,  57,  58,  58,  59,  60,  60,  61,  62,  62,  63,  63,  64,  65,  65,  66,  66,
149b39067696ad08a26bbe49b71a71f0546dc42a075msarett         67,  68,  68,  69,  69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,  75,  75,  76,
150b39067696ad08a26bbe49b71a71f0546dc42a075msarett         76,  77,  77,  78,  78,  79,  79,  80,  80,  81,  81,  81,  82,  82,  83,  83,  84,  84,
151b39067696ad08a26bbe49b71a71f0546dc42a075msarett         84,  85,  85,  86,  86,  87,  87,  87,  88,  88,  89,  89,  89,  90,  90,  91,  91,  91,
152b39067696ad08a26bbe49b71a71f0546dc42a075msarett         92,  92,  93,  93,  93,  94,  94,  94,  95,  95,  96,  96,  96,  97,  97,  97,  98,  98,
153b39067696ad08a26bbe49b71a71f0546dc42a075msarett         98,  99,  99,  99, 100, 100, 101, 101, 101, 102, 102, 102, 103, 103, 103, 104, 104, 104,
154b39067696ad08a26bbe49b71a71f0546dc42a075msarett        105, 105, 105, 106, 106, 106, 107, 107, 107, 108, 108, 108, 108, 109, 109, 109, 110, 110,
155b39067696ad08a26bbe49b71a71f0546dc42a075msarett        110, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115,
156b39067696ad08a26bbe49b71a71f0546dc42a075msarett        116, 116, 116, 117, 117, 117, 117, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 121,
157b39067696ad08a26bbe49b71a71f0546dc42a075msarett        121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125,
158b39067696ad08a26bbe49b71a71f0546dc42a075msarett        126, 126, 126, 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, 129, 129, 130, 130, 130,
159b39067696ad08a26bbe49b71a71f0546dc42a075msarett        130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 135,
160b39067696ad08a26bbe49b71a71f0546dc42a075msarett        135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 138, 138, 139, 139,
161b39067696ad08a26bbe49b71a71f0546dc42a075msarett        139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 142, 142, 142, 142, 142, 143, 143, 143,
162b39067696ad08a26bbe49b71a71f0546dc42a075msarett        143, 144, 144, 144, 144, 144, 145, 145, 145, 145, 146, 146, 146, 146, 146, 147, 147, 147,
163b39067696ad08a26bbe49b71a71f0546dc42a075msarett        147, 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 150, 150, 150, 150, 151, 151, 151,
164b39067696ad08a26bbe49b71a71f0546dc42a075msarett        151, 151, 152, 152, 152, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 154, 155, 155,
165b39067696ad08a26bbe49b71a71f0546dc42a075msarett        155, 155, 155, 156, 156, 156, 156, 156, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158,
166b39067696ad08a26bbe49b71a71f0546dc42a075msarett        159, 159, 159, 159, 159, 160, 160, 160, 160, 160, 161, 161, 161, 161, 161, 162, 162, 162,
167b39067696ad08a26bbe49b71a71f0546dc42a075msarett        162, 162, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 165, 165, 165, 165, 165, 165,
168b39067696ad08a26bbe49b71a71f0546dc42a075msarett        166, 166, 166, 166, 166, 167, 167, 167, 167, 167, 168, 168, 168, 168, 168, 168, 169, 169,
169b39067696ad08a26bbe49b71a71f0546dc42a075msarett        169, 169, 169, 170, 170, 170, 170, 170, 171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
170b39067696ad08a26bbe49b71a71f0546dc42a075msarett        172, 173, 173, 173, 173, 173, 173, 174, 174, 174, 174, 174, 174, 175, 175, 175, 175, 175,
171b39067696ad08a26bbe49b71a71f0546dc42a075msarett        176, 176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 178, 178, 178, 178, 178, 179,
172b39067696ad08a26bbe49b71a71f0546dc42a075msarett        179, 179, 179, 179, 179, 180, 180, 180, 180, 180, 180, 181, 181, 181, 181, 181, 181, 182,
173b39067696ad08a26bbe49b71a71f0546dc42a075msarett        182, 182, 182, 182, 182, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 184, 185, 185,
174b39067696ad08a26bbe49b71a71f0546dc42a075msarett        185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187, 187, 187, 187, 188,
175b39067696ad08a26bbe49b71a71f0546dc42a075msarett        188, 188, 188, 188, 188, 189, 189, 189, 189, 189, 189, 190, 190, 190, 190, 190, 190, 191,
176b39067696ad08a26bbe49b71a71f0546dc42a075msarett        191, 191, 191, 191, 191, 192, 192, 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, 193,
177b39067696ad08a26bbe49b71a71f0546dc42a075msarett        194, 194, 194, 194, 194, 194, 195, 195, 195, 195, 195, 195, 195, 196, 196, 196, 196, 196,
178b39067696ad08a26bbe49b71a71f0546dc42a075msarett        196, 197, 197, 197, 197, 197, 197, 197, 198, 198, 198, 198, 198, 198, 199, 199, 199, 199,
179b39067696ad08a26bbe49b71a71f0546dc42a075msarett        199, 199, 199, 200, 200, 200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 202, 202,
180b39067696ad08a26bbe49b71a71f0546dc42a075msarett        202, 202, 202, 202, 202, 203, 203, 203, 203, 203, 203, 204, 204, 204, 204, 204, 204, 204,
181b39067696ad08a26bbe49b71a71f0546dc42a075msarett        205, 205, 205, 205, 205, 205, 205, 206, 206, 206, 206, 206, 206, 206, 207, 207, 207, 207,
182b39067696ad08a26bbe49b71a71f0546dc42a075msarett        207, 207, 207, 208, 208, 208, 208, 208, 208, 209, 209, 209, 209, 209, 209, 209, 210, 210,
183b39067696ad08a26bbe49b71a71f0546dc42a075msarett        210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 212, 212,
184b39067696ad08a26bbe49b71a71f0546dc42a075msarett        212, 213, 213, 213, 213, 213, 213, 213, 213, 214, 214, 214, 214, 214, 214, 214, 215, 215,
185b39067696ad08a26bbe49b71a71f0546dc42a075msarett        215, 215, 215, 215, 215, 216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217,
186b39067696ad08a26bbe49b71a71f0546dc42a075msarett        217, 218, 218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 220, 220,
187b39067696ad08a26bbe49b71a71f0546dc42a075msarett        220, 220, 220, 220, 220, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222,
188b39067696ad08a26bbe49b71a71f0546dc42a075msarett        222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 224, 224, 224, 225,
189b39067696ad08a26bbe49b71a71f0546dc42a075msarett        225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 226, 226, 227, 227, 227,
190b39067696ad08a26bbe49b71a71f0546dc42a075msarett        227, 227, 227, 227, 228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229,
191b39067696ad08a26bbe49b71a71f0546dc42a075msarett        229, 229, 230, 230, 230, 230, 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 232,
192b39067696ad08a26bbe49b71a71f0546dc42a075msarett        232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 234, 234, 234,
193b39067696ad08a26bbe49b71a71f0546dc42a075msarett        234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235, 236, 236, 236, 236, 236,
194b39067696ad08a26bbe49b71a71f0546dc42a075msarett        236, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 238,
195b39067696ad08a26bbe49b71a71f0546dc42a075msarett        238, 238, 239, 239, 239, 239, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, 240,
196b39067696ad08a26bbe49b71a71f0546dc42a075msarett        241, 241, 241, 241, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243,
197b39067696ad08a26bbe49b71a71f0546dc42a075msarett        243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245,
198b39067696ad08a26bbe49b71a71f0546dc42a075msarett        245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247,
199b39067696ad08a26bbe49b71a71f0546dc42a075msarett        247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249,
200b39067696ad08a26bbe49b71a71f0546dc42a075msarett        249, 249, 249, 249, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251,
201b39067696ad08a26bbe49b71a71f0546dc42a075msarett        251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253,
202b39067696ad08a26bbe49b71a71f0546dc42a075msarett        253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255,
203b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
204b39067696ad08a26bbe49b71a71f0546dc42a075msarett
20515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
20615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
20715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float exponent) {
20815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
20915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = powf(x, exponent);
21015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
21115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
21215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
21315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// Interpolating lookup in a variably sized table.
21415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic float interp_lut(float input, const float* table, int tableSize) {
21515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    float index = input * (tableSize - 1);
21615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    float diff = index - sk_float_floor2int(index);
21715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    return table[(int) sk_float_floor2int(index)] * (1.0f - diff) +
21815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            table[(int) sk_float_ceil2int(index)] * diff;
21915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
22015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
22115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// outTable is always 256 entries, inTable may be larger or smaller.
22215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, const float* inTable,
22315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          int inTableSize) {
22415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    if (256 == inTableSize) {
22515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        memcpy(outTable, inTable, sizeof(float) * 256);
22615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        return;
22715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
22815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
22915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
23015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = interp_lut(x, inTable, inTableSize);
23115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
23215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
23315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
23415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
23515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          float d, float e, float f) {
23615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = (aX + b)^g + c  for X >= d
23715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    // Y = eX + f          otherwise
23815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
23915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        if (x >= d) {
24015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            *outTable++ = powf(a * x + b, g) + c;
24115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        } else {
24215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett            *outTable++ = e * x + f;
24315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        }
24415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
24515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
24615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
24715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
24815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
249a9e878c836994bce695274b4c28890290139dcdfmsarett// Expand range from 0-1 to 0-255, then convert.
250b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic uint8_t clamp_normalized_float_to_byte(float v) {
251dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // The ordering of the logic is a little strange here in order
252dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    // to make sure we convert NaNs to 0.
2539876ac5b3016e5353c072378ac1545a0a2270757msarett    v = v * 255.0f;
254a9e878c836994bce695274b4c28890290139dcdfmsarett    if (v >= 254.5f) {
2559876ac5b3016e5353c072378ac1545a0a2270757msarett        return 255;
256dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else if (v >= 0.5f) {
2579876ac5b3016e5353c072378ac1545a0a2270757msarett        return (uint8_t) (v + 0.5f);
258dea0340cadb759932e53416a657f5ea75fee8b5fmsarett    } else {
259dea0340cadb759932e53416a657f5ea75fee8b5fmsarett        return 0;
2609876ac5b3016e5353c072378ac1545a0a2270757msarett    }
2619876ac5b3016e5353c072378ac1545a0a2270757msarett}
2629876ac5b3016e5353c072378ac1545a0a2270757msarett
2633418c0e797e2ee841d1c031ca9d7a5ba73205f51msarettstatic const int kDstGammaTableSize =
264200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed, kNone_ColorSpaceMatch>
265200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        ::kDstGammaTableSize;
2663418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
2671b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
268b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float toGammaExp = 1.0f / exponent;
269b39067696ad08a26bbe49b71a71f0546dc42a075msarett
2703418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
2713418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
272b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
273b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
274dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
275dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
276dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// Inverse table lookup.  Ex: what index corresponds to the input value?  This will
277dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// have strange results when the table is non-increasing.  But any sane gamma
278dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett// function will be increasing.
2791b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic float inverse_interp_lut(float input, const float* table, int tableSize) {
280dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    if (input <= table[0]) {
281dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        return table[0];
282dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    } else if (input >= table[tableSize - 1]) {
283dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        return 1.0f;
284dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
285dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
286b39067696ad08a26bbe49b71a71f0546dc42a075msarett    for (int i = 1; i < tableSize; i++) {
287dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        if (table[i] >= input) {
288dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            // We are guaranteed that input is greater than table[i - 1].
289dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float diff = input - table[i - 1];
290dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float distance = table[i] - table[i - 1];
291dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            float index = (i - 1) + diff / distance;
292dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett            return index / (tableSize - 1);
293dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett        }
294dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    }
295dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
296dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    // Should be unreachable, since we'll return before the loop if input is
297dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    // larger than the last entry.
298dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    SkASSERT(false);
299dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett    return 0.0f;
300dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
301dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
3021b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
303b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        int inTableSize) {
3043418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
3053418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
306b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_interp_lut(x, inTable, inTableSize);
307b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
308b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
309b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
310dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
311b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
312b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                float f) {
313b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // We need to take the inverse of the following piecewise function.
314b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = (aX + b)^g + c  for X >= d
315b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = eX + f          otherwise
316b39067696ad08a26bbe49b71a71f0546dc42a075msarett
317b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Assume that the gamma function is continuous, or this won't make much sense anyway.
318b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Plug in |d| to the first equation to calculate the new piecewise interval.
319b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Then simply use the inverse of the original functions.
320b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float interval = e * d + f;
321b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (x < interval) {
322b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // X = (Y - F) / E
323b39067696ad08a26bbe49b71a71f0546dc42a075msarett        if (0.0f == e) {
324b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // The gamma curve for this segment is constant, so the inverse is undefined.
325b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // Since this is the lower segment, guess zero.
326b39067696ad08a26bbe49b71a71f0546dc42a075msarett            return 0.0f;
327b39067696ad08a26bbe49b71a71f0546dc42a075msarett        }
328b39067696ad08a26bbe49b71a71f0546dc42a075msarett
329b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return (x - f) / e;
330b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
331b39067696ad08a26bbe49b71a71f0546dc42a075msarett
332b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // X = ((Y - C)^(1 / G) - B) / A
333b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (0.0f == a || 0.0f == g) {
334b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // The gamma curve for this segment is constant, so the inverse is undefined.
335b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // Since this is the upper segment, guess one.
336b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
337b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
338b39067696ad08a26bbe49b71a71f0546dc42a075msarett
339b39067696ad08a26bbe49b71a71f0546dc42a075msarett    return (powf(x - c, 1.0f / g) - b) / a;
340b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
341b39067696ad08a26bbe49b71a71f0546dc42a075msarett
3421b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
343b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        float b, float c, float d, float e, float f) {
3443418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
3453418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
346b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_parametric(x, g, a, b, c, d, e, f);
347b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
348b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
349b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
350b39067696ad08a26bbe49b71a71f0546dc42a075msarett
3516006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
3526006f678e78af7b6f67a454cd4bc213048983f9dmsarett
3531b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
3541b93bd1e6eba3d14593490e4e24a34546638c8damsarettstruct GammaFns {
3551b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* fSRGBTable;
3561b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* f2Dot2Table;
3571b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3581b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromValue)(T*, float);
3591b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromTable)(T*, const float*, int);
3601b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
3611b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
3621b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3631b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<float> kToLinear {
3641b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_srgb,
3651b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_2dot2,
3661b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
3671b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
3681b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
3691b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
3701b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3711b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<uint8_t> kFromLinear {
3721b93bd1e6eba3d14593490e4e24a34546638c8damsarett    linear_to_srgb,
37315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    linear_to_2dot2_table,
3741b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
3751b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
3761b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
3771b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
3781b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3791b93bd1e6eba3d14593490e4e24a34546638c8damsarett// Build tables to transform src gamma to linear.
3801b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
3811b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
3821b93bd1e6eba3d14593490e4e24a34546638c8damsarett                               const sk_sp<SkColorSpace>& space, const GammaFns<T>& fns) {
3831b93bd1e6eba3d14593490e4e24a34546638c8damsarett    switch (space->gammaNamed()) {
3841b93bd1e6eba3d14593490e4e24a34546638c8damsarett        case SkColorSpace::kSRGB_GammaNamed:
3851b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
3861b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
3871b93bd1e6eba3d14593490e4e24a34546638c8damsarett        case SkColorSpace::k2Dot2Curve_GammaNamed:
3881b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
3891b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
3901b93bd1e6eba3d14593490e4e24a34546638c8damsarett        case SkColorSpace::kLinear_GammaNamed:
3911b93bd1e6eba3d14593490e4e24a34546638c8damsarett            (*fns.fBuildFromValue)(gammaTableStorage, 1.0f);
3921b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = gammaTableStorage;
3931b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
3941b93bd1e6eba3d14593490e4e24a34546638c8damsarett        default: {
3951b93bd1e6eba3d14593490e4e24a34546638c8damsarett            const SkGammas* gammas = as_CSB(space)->gammas();
3961b93bd1e6eba3d14593490e4e24a34546638c8damsarett            SkASSERT(gammas);
3971b93bd1e6eba3d14593490e4e24a34546638c8damsarett
3981b93bd1e6eba3d14593490e4e24a34546638c8damsarett            for (int i = 0; i < 3; i++) {
3991b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (i > 0) {
4001b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // Check if this curve matches the first curve.  In this case, we can
4011b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // share the same table pointer.  This should almost always be true.
4021b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // I've never seen a profile where all three gamma curves didn't match.
4031b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    // But it is possible that they won't.
404a714bc39294f19500269c8ec536139f75c4b1f25msarett                    if (gammas->type(0) == gammas->type(i) && gammas->data(0) == gammas->data(i)) {
4051b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        outGammaTables[i] = outGammaTables[0];
4061b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        continue;
4071b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
4081b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
4091b93bd1e6eba3d14593490e4e24a34546638c8damsarett
4101b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (gammas->isNamed(i)) {
4111b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    switch (gammas->data(i).fNamed) {
4121b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        case SkColorSpace::kSRGB_GammaNamed:
4131b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = fns.fSRGBTable;
4141b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4151b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        case SkColorSpace::k2Dot2Curve_GammaNamed:
4161b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = fns.f2Dot2Table;
4171b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4181b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        case SkColorSpace::kLinear_GammaNamed:
4191b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
4201b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4211b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4221b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        default:
4231b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            SkASSERT(false);
4241b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
4251b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
4261b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isValue(i)) {
4271b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
4281b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fValue);
4291b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4301b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isTable(i)) {
4311b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
4321b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fTable.fSize);
4331b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4341b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else {
4351b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    SkASSERT(gammas->isParametric(i));
4361b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    const SkGammas::Params& params = gammas->params(i);
4371b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
4381b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fA, params.fB, params.fC, params.fD, params.fE,
4391b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fF);
4401b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
4411b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
4421b93bd1e6eba3d14593490e4e24a34546638c8damsarett            }
4431b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
4441b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
4451b93bd1e6eba3d14593490e4e24a34546638c8damsarett}
4461b93bd1e6eba3d14593490e4e24a34546638c8damsarett
4471b93bd1e6eba3d14593490e4e24a34546638c8damsarett///////////////////////////////////////////////////////////////////////////////////////////////////
4481b93bd1e6eba3d14593490e4e24a34546638c8damsarett
44915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& srcToXYZ,
45015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                       const SkMatrix44& dstToXYZ) {
45115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    if (!dstToXYZ.invert(srcToDst)) {
45215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        return false;
45315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
45415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
45515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    srcToDst->postConcat(srcToXYZ);
45615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    return true;
45715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
45815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
459200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline bool is_almost_identity(const SkMatrix44& srcToDst) {
460200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    for (int i = 0; i < 4; i++) {
461200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        for (int j = 0; j < 4; j++) {
462200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            float expected = (i == j) ? 1.0f : 0.0f;
463200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) {
464200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                return false;
465200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
466200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
467200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
468200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return true;
469200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
470200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
47115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
47215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
4736006f678e78af7b6f67a454cd4bc213048983f9dmsarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpace>& srcSpace,
4746006f678e78af7b6f67a454cd4bc213048983f9dmsarett                                                          const sk_sp<SkColorSpace>& dstSpace) {
4756006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!srcSpace || !dstSpace) {
4766006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // Invalid input
4776006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
4786006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4796006f678e78af7b6f67a454cd4bc213048983f9dmsarett
480200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    ColorSpaceMatch csm = kNone_ColorSpaceMatch;
4816006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
482200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (SkColorSpace::Equals(srcSpace.get(), dstSpace.get())) {
483200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        srcToDst.setIdentity();
484200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        csm = kFull_ColorSpaceMatch;
485200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    } else if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())) {
4866006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
487200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    } else if (is_almost_identity(srcToDst)) {
488200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        srcToDst.setIdentity();
489200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        csm = kGamut_ColorSpaceMatch;
4906006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
4916006f678e78af7b6f67a454cd4bc213048983f9dmsarett
492200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    switch (csm) {
493200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kNone_ColorSpaceMatch:
494200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            switch (dstSpace->gammaNamed()) {
495200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                case SkColorSpace::kSRGB_GammaNamed:
496200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
497200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::kSRGB_GammaNamed, kNone_ColorSpaceMatch>
498200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
499200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                case SkColorSpace::k2Dot2Curve_GammaNamed:
500200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
501200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::k2Dot2Curve_GammaNamed, kNone_ColorSpaceMatch>
502200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
503200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
504200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
505200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::kNonStandard_GammaNamed, kNone_ColorSpaceMatch>
506200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
507200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
508200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kGamut_ColorSpaceMatch:
509200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            switch (dstSpace->gammaNamed()) {
510200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                case SkColorSpace::kSRGB_GammaNamed:
511200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
512200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::kSRGB_GammaNamed, kGamut_ColorSpaceMatch>
513200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
514200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                case SkColorSpace::k2Dot2Curve_GammaNamed:
515200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
516200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::k2Dot2Curve_GammaNamed, kGamut_ColorSpaceMatch>
517200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
518200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
519200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
520200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::kNonStandard_GammaNamed, kGamut_ColorSpaceMatch>
521200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
522200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
523200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kFull_ColorSpaceMatch:
524200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            switch (dstSpace->gammaNamed()) {
525200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                case SkColorSpace::kSRGB_GammaNamed:
526200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
527200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::kSRGB_GammaNamed, kFull_ColorSpaceMatch>
528200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
529200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                case SkColorSpace::k2Dot2Curve_GammaNamed:
530200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
531200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::k2Dot2Curve_GammaNamed, kFull_ColorSpaceMatch>
532200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
533200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                default:
534200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
535200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            <SkColorSpace::kNonStandard_GammaNamed, kFull_ColorSpaceMatch>
536200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                            (srcSpace, srcToDst, dstSpace));
537200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
5383418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        default:
539200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            SkASSERT(false);
540200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            return nullptr;
5416006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
5426006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
5436006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5446006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
5456006f678e78af7b6f67a454cd4bc213048983f9dmsarett
5460f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarettstatic float byte_to_float(uint8_t byte) {
5470f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    return ((float) byte) * (1.0f / 255.0f);
5480f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett}
5490f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
550b39067696ad08a26bbe49b71a71f0546dc42a075msarett// Clamp to the 0-1 range.
551b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float clamp_normalized_float(float v) {
552b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (v > 1.0f) {
553b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
554b39067696ad08a26bbe49b71a71f0546dc42a075msarett    } else if ((v < 0.0f) || (v != v)) {
555b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 0.0f;
556b39067696ad08a26bbe49b71a71f0546dc42a075msarett    } else {
557b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return v;
558b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
559b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
560b39067696ad08a26bbe49b71a71f0546dc42a075msarett
5610f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarettstatic void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable* colorLUT) {
5620f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Call the src components x, y, and z.
5630f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxX = colorLUT->fGridPoints[0] - 1;
5640f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxY = colorLUT->fGridPoints[1] - 1;
5650f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    uint8_t maxZ = colorLUT->fGridPoints[2] - 1;
5660f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5670f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // An approximate index into each of the three dimensions of the table.
5680f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float x = src[0] * maxX;
5690f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float y = src[1] * maxY;
5700f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float z = src[2] * maxZ;
5710f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5720f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // This gives us the low index for our interpolation.
5730f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int ix = sk_float_floor2int(x);
5740f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int iy = sk_float_floor2int(y);
5750f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    int iz = sk_float_floor2int(z);
5760f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5770f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Make sure the low index is not also the max index.
5780f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    ix = (maxX == ix) ? ix - 1 : ix;
5790f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    iy = (maxY == iy) ? iy - 1 : iy;
5800f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    iz = (maxZ == iz) ? iz - 1 : iz;
5810f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5820f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Weighting factors for the interpolation.
5830f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffX = x - ix;
5840f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffY = y - iy;
5850f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    float diffZ = z - iz;
5860f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5870f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Constants to help us navigate the 3D table.
5880f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Ex: Assume x = a, y = b, z = c.
5890f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    //     table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c].
5900f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n000 = 0;
5910f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2];
5920f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n010 = 3 * colorLUT->fGridPoints[2];
5930f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n011 = n001 + n010;
5940f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n100 = 3;
5950f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n101 = n100 + n001;
5960f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n110 = n100 + n010;
5970f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    const int n111 = n110 + n001;
5980f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
5990f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // Base ptr into the table.
600959d45b43357a40854938586c303177c6aa53220msarett    const float* ptr = &(colorLUT->table()[ix*n001 + iy*n010 + iz*n100]);
6010f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6020f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // The code below performs a tetrahedral interpolation for each of the three
6030f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // dst components.  Once the tetrahedron containing the interpolation point is
6040f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // identified, the interpolation is a weighted sum of grid values at the
6050f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // vertices of the tetrahedron.  The claim is that tetrahedral interpolation
6060f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // provides a more accurate color conversion.
6070f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/
6080f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    //
6090f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // I have one test image, and visually I can't tell the difference between
6100f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral and trilinear interpolation.  In terms of computation, the
6110f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral code requires more branches but less computation.  The
6120f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // SampleICC library provides an option for the client to choose either
6130f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    // tetrahedral or trilinear.
6140f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    for (int i = 0; i < 3; i++) {
6150f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        if (diffZ < diffY) {
6160f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            if (diffZ < diffX) {
6170f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) +
6180f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n010] - ptr[n000]) +
6190f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n111] - ptr[n110]));
6200f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else if (diffY < diffX) {
6210f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
6220f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n011] - ptr[n001]) +
6230f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n001] - ptr[n000]));
6240f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else {
6250f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
6260f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n010] - ptr[n000]) +
6270f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n011] - ptr[n010]));
6280f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            }
6290f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        } else {
6300f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            if (diffZ < diffX) {
6310f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) +
6320f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n111] - ptr[n101]) +
6330f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n001] - ptr[n000]));
6340f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else if (diffY < diffX) {
6350f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
6360f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n111] - ptr[n101]) +
6370f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n101] - ptr[n100]));
6380f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            } else {
6390f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
6400f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffY * (ptr[n110] - ptr[n100]) +
6410f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                                      diffX * (ptr[n111] - ptr[n110]));
6420f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett            }
6430f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        }
6440f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6450f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // Increment the table ptr in order to handle the next component.
6460f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // Note that this is the how table is designed: all of nXXX
6470f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // variables are multiples of 3 because there are 3 output
6480f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        // components.
6490f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        ptr++;
6500f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett    }
6510f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett}
6520f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6533418c0e797e2ee841d1c031ca9d7a5ba73205f51msarettstatic void handle_color_lut(uint32_t* dst, const uint32_t* src, int len,
6543418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett                             SkColorLookUpTable* colorLUT) {
655b39067696ad08a26bbe49b71a71f0546dc42a075msarett    while (len-- > 0) {
6560f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett        uint8_t r = (*src >>  0) & 0xFF,
6570f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                g = (*src >>  8) & 0xFF,
6580f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett                b = (*src >> 16) & 0xFF;
6590f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6603418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float in[3];
6613418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float out[3];
6623418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[0] = byte_to_float(r);
6633418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[1] = byte_to_float(g);
6643418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        in[2] = byte_to_float(b);
6653418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        interp_3d_clut(out, in, colorLUT);
6660f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6673418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        r = sk_float_round2int(255.0f * clamp_normalized_float(out[0]));
6683418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        g = sk_float_round2int(255.0f * clamp_normalized_float(out[1]));
6693418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        b = sk_float_round2int(255.0f * clamp_normalized_float(out[2]));
6703418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        *dst = SkPackARGB_as_RGBA(0xFF, r, g, b);
6710f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
6723418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        src++;
6733418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        dst++;
6743418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    }
6753418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
6760f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
677200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettenum SwapRB {
678200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    kNo_SwapRB,
679200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    kYes_SwapRB,
680200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett};
681200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
682200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_matrix(const float matrix[16],
683200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
684200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rXgXbX = Sk4f::Load(matrix +  0);
685200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rYgYbY = Sk4f::Load(matrix +  4);
686200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rZgZbZ = Sk4f::Load(matrix +  8);
687200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rTgTbT = Sk4f::Load(matrix + 12);
688200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
689200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
690200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables(const uint32_t* src,
691200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
692200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                        const float* const srcTables[3]) {
693200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = { srcTables[0][(src[0] >>  0) & 0xFF],
694200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[1] >>  0) & 0xFF],
695200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[2] >>  0) & 0xFF],
696200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[3] >>  0) & 0xFF], };
697200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = { srcTables[1][(src[0] >>  8) & 0xFF],
698200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[1] >>  8) & 0xFF],
699200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[2] >>  8) & 0xFF],
700200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[3] >>  8) & 0xFF], };
701200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = { srcTables[2][(src[0] >> 16) & 0xFF],
702200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[1] >> 16) & 0xFF],
703200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[2] >> 16) & 0xFF],
704200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[3] >> 16) & 0xFF], };
705200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
706200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
707200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
708200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables(const uint32_t* src,
709200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
710200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                         const float* const srcTables[3]) {
711200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = { srcTables[0][(src[0] >>  0) & 0xFF],
712200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[1] >>  0) & 0xFF],
713200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[2] >>  0) & 0xFF],
714200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[0][(src[3] >>  0) & 0xFF], };
715200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = { srcTables[1][(src[0] >>  8) & 0xFF],
716200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[1] >>  8) & 0xFF],
717200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[2] >>  8) & 0xFF],
718200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[1][(src[3] >>  8) & 0xFF], };
719200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = { srcTables[2][(src[0] >> 16) & 0xFF],
720200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[1] >> 16) & 0xFF],
721200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[2] >> 16) & 0xFF],
722200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          srcTables[2][(src[3] >> 16) & 0xFF], };
723200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
724200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
725200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
726200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgb_from_tables_1(const uint32_t* src,
727200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&,
728200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                          const float* const srcTables[3]) {
729200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // Splat r,g,b across a register each.
730200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = Sk4f(srcTables[0][(*src >>  0) & 0xFF]);
731200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = Sk4f(srcTables[1][(*src >>  8) & 0xFF]);
732200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = Sk4f(srcTables[2][(*src >> 16) & 0xFF]);
733200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
734200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
735200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void load_rgba_from_tables_1(const uint32_t* src,
736200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
737200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                           const float* const srcTables[3]) {
738200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // Splat r,g,b across a register each.
739200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    r = Sk4f(srcTables[0][(*src >>  0) & 0xFF]);
740200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    g = Sk4f(srcTables[1][(*src >>  8) & 0xFF]);
741200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    b = Sk4f(srcTables[2][(*src >> 16) & 0xFF]);
742200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * Sk4f(*src >> 24);
743200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
744200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
745200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
746200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
747200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
748200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
749200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
750200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
751200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    da = a;
752200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
753200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
754200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
755200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
756200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                     Sk4f& rgba) {
757200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
758200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
759200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
760200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
761200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = dr + rTgTbT[0];
762200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = dg + rTgTbT[1];
763200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = db + rTgTbT[2];
764200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
765200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
766200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
767200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rgba + rTgTbT;
768200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
769200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
770200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) {
771200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = da * dr;
772200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = da * dg;
773200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = da * db;
774200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
775200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
776200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void premultiply_1(const Sk4f& a, Sk4f& rgba) {
777200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = a * rgba;
778200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
779200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
780200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb(void* dst, const uint32_t* src,
781200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                              Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
782200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                              const uint8_t* const[3], SwapRB kSwapRB) {
783200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kRShift = 0;
784200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kGShift = 8;
785200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kBShift = 16;
786200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
787200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kBShift = 0;
788200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kRShift = 16;
789200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
790200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
791200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_linear_to_srgb_needs_trunc(dr);
792200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_linear_to_srgb_needs_trunc(dg);
793200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_linear_to_srgb_needs_trunc(db);
794200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
795200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
796200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
797200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
798200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
799200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
800200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
801200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
802200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(dg) << kGShift)
803200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(db) << kBShift)
804200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                           );
805200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
806200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
807200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
808200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_srgb_1(void* dst, const uint32_t* src,
809200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                Sk4f& rgba, const Sk4f&,
810200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                const uint8_t* const[3], SwapRB kSwapRB) {
811200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
812200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
813200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
814200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
815200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
816200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
817200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
818200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
819200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
820200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
821200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
822200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
823200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline Sk4f linear_to_2dot2(const Sk4f& x) {
824200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
825200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    auto x2  = x.rsqrt(),                            // x^(-1/2)
826200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(),   // x^(-1/32)
827200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x64 = x32.rsqrt();                          // x^(+1/64)
828200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
829200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // 29 = 32 - 2 - 1
830200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return 255.0f * x2.invert() * x32 * x64.invert();
831200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
832200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
833200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2(void* dst, const uint32_t* src,
834200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
835200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               const uint8_t* const[3], SwapRB kSwapRB) {
836200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kRShift = 0;
837200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kGShift = 8;
838200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kBShift = 16;
839200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
840200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kBShift = 0;
841200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kRShift = 16;
842200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
843200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
844200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = linear_to_2dot2(dr);
845200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = linear_to_2dot2(dg);
846200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = linear_to_2dot2(db);
847200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
848200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_clamp_0_255(dr);
849200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_clamp_0_255(dg);
850200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_clamp_0_255(db);
851200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
852200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
853200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
854200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
855200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(dg) << kGShift)
856200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(db) << kBShift)
857200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                       );
858200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
859200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
860200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
861200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_2dot2_1(void* dst, const uint32_t* src,
862200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& rgba, const Sk4f&,
863200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 const uint8_t* const[3], SwapRB kSwapRB) {
864200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
865200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
866200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
867200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
868200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
869200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
870200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
871200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
872200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
873200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
874200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
875200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
876200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16(void* dst, const uint32_t* src,
877200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                             Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
878200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                             const uint8_t* const[3], SwapRB) {
879200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4h_store4(dst, SkFloatToHalf_finite(dr),
880200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                     SkFloatToHalf_finite(dg),
881200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                     SkFloatToHalf_finite(db),
882200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                     SkFloatToHalf_finite(da));
883200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
884200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
885200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1(void* dst, const uint32_t* src,
886200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               Sk4f& rgba, const Sk4f& a,
887200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                               const uint8_t* const[3], SwapRB kSwapRB) {
888200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
889200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkFloatToHalf_finite(rgba).store((uint64_t*) dst);
890200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
891200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
892200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_opaque(void* dst, const uint32_t* src,
893200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                    Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
894200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                    const uint8_t* const[3], SwapRB) {
895200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4h_store4(dst, SkFloatToHalf_finite(dr),
896200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                     SkFloatToHalf_finite(dg),
897200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                     SkFloatToHalf_finite(db),
898200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                     SK_Half1);
899200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
900200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
901200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_f16_1_opaque(void* dst, const uint32_t* src,
902200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                      Sk4f& rgba, const Sk4f& a,
903200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                      const uint8_t* const[3], SwapRB kSwapRB) {
904200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint64_t tmp;
905200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkFloatToHalf_finite(rgba).store(&tmp);
906200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp |= static_cast<uint64_t>(SK_Half1) << 48;
907200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *((uint64_t*) dst) = tmp;
908200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
909200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
910200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic(void* dst, const uint32_t* src,
911200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
912200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                 const uint8_t* const dstTables[3], SwapRB kSwapRB) {
913200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kRShift = 0;
914200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kGShift = 8;
915200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    int kBShift = 16;
916200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kYes_SwapRB == kSwapRB) {
917200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kBShift = 0;
918200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        kRShift = 16;
919200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
920200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
921200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
922200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
923200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
924200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
925200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ir = Sk4f_round(dr);
926200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ig = Sk4f_round(dg);
927200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ib = Sk4f_round(db);
928200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
929200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
930200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
931200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t* dst32 = (uint32_t*) dst;
932200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[0] = dstTables[0][ir[0]] << kRShift
933200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[0]] << kGShift
934200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[0]] << kBShift
935200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[0];
936200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[1] = dstTables[0][ir[1]] << kRShift
937200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[1]] << kGShift
938200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[1]] << kBShift
939200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[1];
940200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[2] = dstTables[0][ir[2]] << kRShift
941200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[2]] << kGShift
942200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[2]] << kBShift
943200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[2];
944200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[3] = dstTables[0][ir[3]] << kRShift
945200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[3]] << kGShift
946200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[3]] << kBShift
947200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[3];
948200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
949200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
950200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic inline void store_generic_1(void* dst, const uint32_t* src,
951200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   Sk4f& rgba, const Sk4f&,
952200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                   const uint8_t* const dstTables[3], SwapRB kSwapRB) {
953200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
954200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
955200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i indices = Sk4f_round(rgba);
956200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
957200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *((uint32_t*) dst) = dstTables[0][indices[0]] <<  0
958200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | dstTables[1][indices[1]] <<  8
959200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | dstTables[2][indices[2]] << 16
960200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | (*src & 0xFF000000);
961200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
962200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
963200877eecaba782e56a1dd9e13a92f36d7b1ba12msaretttemplate <SkColorSpace::GammaNamed kDstGamma,
964200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          ColorSpaceMatch kCSM,
965200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          SkAlphaType kAlphaType,
966200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett          SwapRB kSwapRB>
967200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettstatic void color_xform_RGBA(void* dst, const uint32_t* src, int len,
968200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                             const float* const srcTables[3], const float matrix[16],
969200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                             const uint8_t* const dstTables[3]) {
970200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    decltype(store_srgb            )* store;
971200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    decltype(store_srgb_1          )* store_1;
972200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    decltype(load_rgb_from_tables  )* load;
973200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    decltype(load_rgb_from_tables_1)* load_1;
974200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    size_t sizeOfDstPixel;
975200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    switch (kDstGamma) {
976200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case SkColorSpace::kSRGB_GammaNamed:
977200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load    = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_tables :
978200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            load_rgb_from_tables;
979200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load_1  = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_tables_1 :
980200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            load_rgb_from_tables_1;
981200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store   = store_srgb;
982200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store_1 = store_srgb_1;
983200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            sizeOfDstPixel = 4;
984200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            break;
985200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case SkColorSpace::k2Dot2Curve_GammaNamed:
986200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load    = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_tables :
987200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            load_rgb_from_tables;
988200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load_1  = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_tables_1 :
989200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            load_rgb_from_tables_1;
990200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store   = store_2dot2;
991200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store_1 = store_2dot2_1;
992200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            sizeOfDstPixel = 4;
993200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            break;
994200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case SkColorSpace::kLinear_GammaNamed:
995200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load    = load_rgba_from_tables;
996200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load_1  = load_rgba_from_tables_1;
997200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store   = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque :
998200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            store_f16;
999200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque :
1000200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            store_f16_1;
1001200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            sizeOfDstPixel = 8;
1002200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            break;
1003200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case SkColorSpace::kNonStandard_GammaNamed:
1004200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load    = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_tables :
1005200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            load_rgb_from_tables;
1006200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load_1  = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_tables_1 :
1007200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                            load_rgb_from_tables_1;
1008200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store   = store_generic;
1009200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store_1 = store_generic_1;
1010200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            sizeOfDstPixel = 4;
1011200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            break;
1012200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1013200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1014200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
1015200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
1016200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1017200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (len >= 4) {
1018200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        // Naively this would be a loop of load-transform-store, but we found it faster to
1019200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        // move the N+1th load ahead of the Nth store.  We don't bother doing this for N<4.
1020200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f r, g, b, a;
1021200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        load(src, r, g, b, a, srcTables);
1022200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        src += 4;
1023200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        len -= 4;
1024200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1025200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f dr, dg, db, da;
1026200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        while (len >= 4) {
1027200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (kNone_ColorSpaceMatch == kCSM) {
1028200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1029200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                translate_gamut(rTgTbT, dr, dg, db);
1030200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            } else {
1031200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                dr = r;
1032200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                dg = g;
1033200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                db = b;
1034200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                da = a;
1035200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
1036200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1037200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            if (kPremul_SkAlphaType == kAlphaType) {
1038200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                premultiply(dr, dg, db, da);
1039200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            }
1040200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1041200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            load(src, r, g, b, a, srcTables);
1042200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1043200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            store(dst, src - 4, dr, dg, db, da, dstTables, kSwapRB);
1044200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1045200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            src += 4;
1046200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            len -= 4;
1047200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1048200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1049200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kNone_ColorSpaceMatch == kCSM) {
1050200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
1051200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            translate_gamut(rTgTbT, dr, dg, db);
1052200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        } else {
1053200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dr = r;
1054200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            dg = g;
1055200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            db = b;
1056200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            da = a;
1057200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1058200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1059200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kPremul_SkAlphaType == kAlphaType) {
1060200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            premultiply(dr, dg, db, da);
1061200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1062200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1063200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        store(dst, src - 4, dr, dg, db, da, dstTables, kSwapRB);
1064200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
1065200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1066200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1067200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    while (len > 0) {
1068200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f r, g, b, a;
1069200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        load_1(src, r, g, b, a, srcTables);
1070200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1071200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        Sk4f rgba;
1072200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kNone_ColorSpaceMatch == kCSM) {
1073200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
1074200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            translate_gamut_1(rTgTbT, rgba);
1075200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        } else {
1076200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            rgba = Sk4f(r[0], g[0], b[0], a[0]);
1077200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1078200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1079200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        if (kPremul_SkAlphaType == kAlphaType) {
1080200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            premultiply_1(a, rgba);
1081200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1082200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1083200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        store_1(dst, src, rgba, a, dstTables, kSwapRB);
1084200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
1085200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        src += 1;
1086200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        len -= 1;
1087200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
1088200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1089200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
1090200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10913418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett///////////////////////////////////////////////////////////////////////////////////////////////////
10920f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
1093200877eecaba782e56a1dd9e13a92f36d7b1ba12msaretttemplate <SkColorSpace::GammaNamed kDst, ColorSpaceMatch kCSM>
1094200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettSkColorSpaceXform_Base<kDst, kCSM>::SkColorSpaceXform_Base(const sk_sp<SkColorSpace>& srcSpace,
1095200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                           const SkMatrix44& srcToDst,
1096200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                                           const sk_sp<SkColorSpace>& dstSpace)
10973418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT()))
10983418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
10993418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    srcToDst.asRowMajorf(fSrcToDst);
11003418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kToLinear);
1101200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, kDstGammaTableSize, dstSpace,
1102200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       kFromLinear);
11033418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
1104dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
1105200877eecaba782e56a1dd9e13a92f36d7b1ba12msaretttemplate <SkColorSpace::GammaNamed kDst, ColorSpaceMatch kCSM>
1106200877eecaba782e56a1dd9e13a92f36d7b1ba12msarettvoid SkColorSpaceXform_Base<kDst, kCSM>
1107d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett::apply(void* dst, const uint32_t* src, int len, SkColorType dstColorType, SkAlphaType dstAlphaType)
1108d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarettconst
11093418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1110200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kFull_ColorSpaceMatch == kCSM) {
1111200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        switch (dstAlphaType) {
1112200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            case kPremul_SkAlphaType:
1113200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // We can't skip the xform since we need to perform a premultiply in the
1114200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                // linear space.
1115200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                break;
1116200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            default:
1117200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                switch (dstColorType) {
1118200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    case kRGBA_8888_SkColorType:
1119200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        return (void) memcpy(dst, src, len * sizeof(uint32_t));
1120200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    case kBGRA_8888_SkColorType:
1121200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        return SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
1122200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    case kRGBA_F16_SkColorType:
1123200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        // There's still work to do to xform to linear F16.
1124200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        break;
1125200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    default:
1126200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        SkASSERT(false);
1127200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                        return;
1128200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                }
1129200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1130200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1131200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
11323418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    if (fColorLUT) {
1133d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        size_t storageBytes = len * sizeof(uint32_t);
11343418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#if defined(GOOGLE3)
11353418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        // Stack frame size is limited in GOOGLE3.
1136d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        SkAutoSMalloc<256 * sizeof(uint32_t)> storage(storageBytes);
11373418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#else
1138d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        SkAutoSMalloc<1024 * sizeof(uint32_t)> storage(storageBytes);
11393418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett#endif
11403418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1141d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get());
1142d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        src = (const uint32_t*) storage.get();
11433418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    }
11443418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1145d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett    switch (dstAlphaType) {
1146d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        case kPremul_SkAlphaType:
1147d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            switch (dstColorType) {
1148d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kRGBA_8888_SkColorType:
1149200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<kDst, kCSM, kPremul_SkAlphaType, kNo_SwapRB>
1150d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1151d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kBGRA_8888_SkColorType:
1152200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<kDst, kCSM, kPremul_SkAlphaType, kYes_SwapRB>
1153d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1154d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kRGBA_F16_SkColorType:
1155200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<SkColorSpace::kLinear_GammaNamed, kCSM,
1156200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                            kPremul_SkAlphaType, kNo_SwapRB>
1157d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1158d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
1159d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    SkASSERT(false);
1160d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    return;
1161d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1162d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            break;
1163d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        case kUnpremul_SkAlphaType:
1164d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            switch (dstColorType) {
1165d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kRGBA_8888_SkColorType:
1166200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<kDst, kCSM, kUnpremul_SkAlphaType, kNo_SwapRB>
1167d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1168d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kBGRA_8888_SkColorType:
1169200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<kDst, kCSM, kUnpremul_SkAlphaType, kYes_SwapRB>
1170d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1171d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kRGBA_F16_SkColorType:
1172200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<SkColorSpace::kLinear_GammaNamed, kCSM,
1173200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                            kUnpremul_SkAlphaType, kNo_SwapRB>
1174d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1175d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
1176d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    SkASSERT(false);
1177d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    return;
1178d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1179d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        case kOpaque_SkAlphaType:
1180d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            switch (dstColorType) {
1181d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kRGBA_8888_SkColorType:
1182200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<kDst, kCSM, kOpaque_SkAlphaType, kNo_SwapRB>
1183d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1184d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kBGRA_8888_SkColorType:
1185200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<kDst, kCSM, kOpaque_SkAlphaType, kYes_SwapRB>
1186d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1187d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                case kRGBA_F16_SkColorType:
1188200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                    return color_xform_RGBA<SkColorSpace::kLinear_GammaNamed, kCSM,
1189200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                                            kOpaque_SkAlphaType, kNo_SwapRB>
1190d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                            (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
1191d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
1192d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    SkASSERT(false);
1193d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                    return;
1194d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1195d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        default:
1196d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            SkASSERT(false);
1197d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            return;
1198d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett    }
11999ce3a543c92a73e6daca420defc042886b3f2019msarett}
1200