LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkColorSpaceXform.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 625 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 277 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkColorPriv.h"
       9             : #include "SkColorSpace_A2B.h"
      10             : #include "SkColorSpace_Base.h"
      11             : #include "SkColorSpace_XYZ.h"
      12             : #include "SkColorSpacePriv.h"
      13             : #include "SkColorSpaceXform_A2B.h"
      14             : #include "SkColorSpaceXform_Base.h"
      15             : #include "SkColorSpaceXformPriv.h"
      16             : #include "SkHalf.h"
      17             : #include "SkOpts.h"
      18             : #include "SkPM4fPriv.h"
      19             : #include "SkRasterPipeline.h"
      20             : #include "SkSRGB.h"
      21             : 
      22             : static constexpr float sk_linear_from_2dot2[256] = {
      23             :         0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
      24             :         0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
      25             :         0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
      26             :         0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
      27             :         0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
      28             :         0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
      29             :         0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
      30             :         0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
      31             :         0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
      32             :         0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
      33             :         0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
      34             :         0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
      35             :         0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
      36             :         0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
      37             :         0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
      38             :         0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
      39             :         0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
      40             :         0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
      41             :         0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
      42             :         0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
      43             :         0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
      44             :         0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
      45             :         0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
      46             :         0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
      47             :         0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
      48             :         0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
      49             :         0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
      50             :         0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
      51             :         0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
      52             :         0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
      53             :         0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
      54             :         0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
      55             :         0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
      56             :         0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
      57             :         0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
      58             :         0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
      59             :         0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
      60             :         0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
      61             :         0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
      62             :         0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
      63             :         0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
      64             :         0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
      65             :         0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
      66             :         0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
      67             :         0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
      68             :         0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
      69             :         0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
      70             :         0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
      71             :         0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
      72             :         0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
      73             :         0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
      74             :         0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
      75             :         0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
      76             :         0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
      77             :         0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
      78             :         0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
      79             :         0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
      80             :         0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
      81             :         0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
      82             :         0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
      83             :         0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
      84             :         0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
      85             :         0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
      86             :         0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
      87             : };
      88             : 
      89             : ///////////////////////////////////////////////////////////////////////////////////////////////////
      90             : 
      91           0 : static void build_table_linear_from_gamma(float* outTable, float exponent) {
      92           0 :     for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
      93           0 :         *outTable++ = powf(x, exponent);
      94             :     }
      95           0 : }
      96             : 
      97             : // outTable is always 256 entries, inTable may be larger or smaller.
      98           0 : static void build_table_linear_from_gamma(float* outTable, const float* inTable,
      99             :                                           int inTableSize) {
     100           0 :     if (256 == inTableSize) {
     101           0 :         memcpy(outTable, inTable, sizeof(float) * 256);
     102           0 :         return;
     103             :     }
     104             : 
     105           0 :     for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
     106           0 :         *outTable++ = interp_lut(x, inTable, inTableSize);
     107             :     }
     108             : }
     109             : 
     110             : 
     111           0 : static void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
     112             :                                           float d, float e, float f) {
     113             :     // Y = (aX + b)^g + e  for X >= d
     114             :     // Y = cX + f          otherwise
     115           0 :     for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
     116           0 :         if (x >= d) {
     117           0 :             *outTable++ = clamp_0_1(powf(a * x + b, g) + e);
     118             :         } else {
     119           0 :             *outTable++ = clamp_0_1(c * x + f);
     120             :         }
     121             :     }
     122           0 : }
     123             : 
     124             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     125             : 
     126             : static const int kDstGammaTableSize = SkColorSpaceXform_Base::kDstGammaTableSize;
     127             : 
     128           0 : static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
     129           0 :     float toGammaExp = 1.0f / exponent;
     130             : 
     131           0 :     for (int i = 0; i < kDstGammaTableSize; i++) {
     132           0 :         float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
     133           0 :         outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
     134             :     }
     135           0 : }
     136             : 
     137           0 : static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
     138             :                                         int inTableSize) {
     139           0 :     invert_table_gamma(nullptr, outTable, kDstGammaTableSize, inTable, inTableSize);
     140           0 : }
     141             : 
     142           0 : static float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
     143             :                                 float f) {
     144             :     // We need to take the inverse of the following piecewise function.
     145             :     // Y = (aX + b)^g + c  for X >= d
     146             :     // Y = eX + f          otherwise
     147             : 
     148             :     // Assume that the gamma function is continuous, or this won't make much sense anyway.
     149             :     // Plug in |d| to the first equation to calculate the new piecewise interval.
     150             :     // Then simply use the inverse of the original functions.
     151           0 :     float interval = c * d + f;
     152           0 :     if (x < interval) {
     153             :         // X = (Y - F) / C
     154           0 :         if (0.0f == c) {
     155             :             // The gamma curve for this segment is constant, so the inverse is undefined.
     156             :             // Since this is the lower segment, guess zero.
     157           0 :             return 0.0f;
     158             :         }
     159             : 
     160           0 :         return (x - f) / c;
     161             :     }
     162             : 
     163             :     // X = ((Y - E)^(1 / G) - B) / A
     164           0 :     if (0.0f == a || 0.0f == g) {
     165             :         // The gamma curve for this segment is constant, so the inverse is undefined.
     166             :         // Since this is the upper segment, guess one.
     167           0 :         return 1.0f;
     168             :     }
     169             : 
     170           0 :     return (powf(x - e, 1.0f / g) - b) / a;
     171             : }
     172             : 
     173           0 : static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
     174             :                                         float b, float c, float d, float e, float f) {
     175           0 :     for (int i = 0; i < kDstGammaTableSize; i++) {
     176           0 :         float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
     177           0 :         float y = inverse_parametric(x, g, a, b, c, d, e, f);
     178           0 :         outTable[i] = clamp_normalized_float_to_byte(y);
     179             :     }
     180           0 : }
     181             : 
     182             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     183             : 
     184             : template <typename T>
     185             : struct GammaFns {
     186             :     const T* fSRGBTable;
     187             :     const T* f2Dot2Table;
     188             :     void (*fBuildFromValue)(T*, float);
     189             :     void (*fBuildFromTable)(T*, const float*, int);
     190             :     void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
     191             : };
     192             : 
     193             : static const GammaFns<float> kToLinear {
     194             :     sk_linear_from_srgb,
     195             :     sk_linear_from_2dot2,
     196             :     &build_table_linear_from_gamma,
     197             :     &build_table_linear_from_gamma,
     198             :     &build_table_linear_from_gamma,
     199             : };
     200             : 
     201             : static const GammaFns<uint8_t> kFromLinear {
     202             :     nullptr,
     203             :     nullptr,
     204             :     &build_table_linear_to_gamma,
     205             :     &build_table_linear_to_gamma,
     206             :     &build_table_linear_to_gamma,
     207             : };
     208             : 
     209             : // Build tables to transform src gamma to linear.
     210             : template <typename T>
     211           0 : static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
     212             :                                const SkColorSpace_XYZ* space, const GammaFns<T>& fns,
     213             :                                bool gammasAreMatching)
     214             : {
     215           0 :     switch (space->gammaNamed()) {
     216             :         case kSRGB_SkGammaNamed:
     217           0 :             outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
     218           0 :             break;
     219             :         case k2Dot2Curve_SkGammaNamed:
     220           0 :             outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
     221           0 :             break;
     222             :         case kLinear_SkGammaNamed:
     223           0 :             outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr;
     224           0 :             break;
     225             :         default: {
     226           0 :             const SkGammas* gammas = space->gammas();
     227           0 :             SkASSERT(gammas);
     228             : 
     229           0 :             auto build_table = [=](int i) {
     230           0 :                 if (gammas->isNamed(i)) {
     231           0 :                     switch (gammas->data(i).fNamed) {
     232             :                         case kSRGB_SkGammaNamed:
     233           0 :                             (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f,
     234             :                                                    (1.0f / 1.055f), (0.055f / 1.055f),
     235             :                                                    (1.0f / 12.92f), 0.04045f, 0.0f, 0.0f);
     236           0 :                             outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
     237           0 :                             break;
     238             :                         case k2Dot2Curve_SkGammaNamed:
     239           0 :                             (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f);
     240           0 :                             outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
     241           0 :                             break;
     242             :                         case kLinear_SkGammaNamed:
     243           0 :                             (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
     244           0 :                             outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
     245           0 :                             break;
     246             :                         default:
     247           0 :                             SkASSERT(false);
     248           0 :                             break;
     249             :                     }
     250           0 :                 } else if (gammas->isValue(i)) {
     251           0 :                     (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
     252           0 :                                            gammas->data(i).fValue);
     253           0 :                     outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
     254           0 :                 } else if (gammas->isTable(i)) {
     255           0 :                     (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
     256           0 :                                            gammas->data(i).fTable.fSize);
     257           0 :                     outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
     258             :                 } else {
     259           0 :                     SkASSERT(gammas->isParametric(i));
     260           0 :                     const SkColorSpaceTransferFn& params = gammas->params(i);
     261           0 :                     (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
     262           0 :                                            params.fA, params.fB, params.fC, params.fD, params.fE,
     263           0 :                                            params.fF);
     264           0 :                     outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
     265             :                 }
     266           0 :             };
     267             : 
     268           0 :             if (gammasAreMatching) {
     269           0 :                 build_table(0);
     270           0 :                 outGammaTables[1] = outGammaTables[0];
     271           0 :                 outGammaTables[2] = outGammaTables[0];
     272             :             } else {
     273           0 :                 build_table(0);
     274           0 :                 build_table(1);
     275           0 :                 build_table(2);
     276             :             }
     277             : 
     278           0 :             break;
     279             :         }
     280             :     }
     281           0 : }
     282             : 
     283           0 : void SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3],
     284             :                                                  uint8_t* dstStorage,
     285             :                                                  const SkColorSpace_XYZ* space,
     286             :                                                  bool gammasAreMatching) {
     287           0 :     build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear,
     288           0 :                        gammasAreMatching);
     289           0 : }
     290             : 
     291             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     292             : 
     293           0 : std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace,
     294             :                                                           SkColorSpace* dstSpace) {
     295           0 :     return SkColorSpaceXform_Base::New(srcSpace, dstSpace, SkTransferFunctionBehavior::kRespect);
     296             : }
     297             : 
     298           0 : std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform_Base::New(SkColorSpace* srcSpace,
     299             :         SkColorSpace* dstSpace, SkTransferFunctionBehavior premulBehavior) {
     300             : 
     301           0 :     if (!srcSpace || !dstSpace) {
     302             :         // Invalid input
     303           0 :         return nullptr;
     304             :     }
     305             : 
     306           0 :     if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) {
     307             :         SkCSXformPrintf("A2B destinations not supported\n");
     308           0 :         return nullptr;
     309             :     }
     310             : 
     311           0 :     if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) {
     312           0 :         SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace);
     313           0 :         SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace);
     314           0 :         return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(src, dst));
     315             :     }
     316           0 :     SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace);
     317           0 :     SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace);
     318             : 
     319           0 :     ColorSpaceMatch csm = kNone_ColorSpaceMatch;
     320           0 :     SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
     321           0 :     if (SkColorSpace::Equals(srcSpace, dstSpace)) {
     322           0 :         srcToDst.setIdentity();
     323           0 :         csm = kFull_ColorSpaceMatch;
     324             :     } else {
     325           0 :         if (srcSpaceXYZ->toXYZD50Hash() == dstSpaceXYZ->toXYZD50Hash()) {
     326           0 :             SkASSERT(*srcSpaceXYZ->toXYZD50() == *dstSpaceXYZ->toXYZD50() && "Hash collision");
     327           0 :             srcToDst.setIdentity();
     328           0 :             csm = kGamut_ColorSpaceMatch;
     329             :         } else {
     330           0 :             srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50());
     331             :         }
     332             :     }
     333             : 
     334           0 :     switch (csm) {
     335             :         case kNone_ColorSpaceMatch:
     336             :             return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
     337           0 :                     <kNone_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
     338             :         case kGamut_ColorSpaceMatch:
     339             :             return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
     340           0 :                     <kGamut_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
     341             :         case kFull_ColorSpaceMatch:
     342             :             return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
     343           0 :                     <kFull_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
     344             :         default:
     345           0 :             SkASSERT(false);
     346           0 :             return nullptr;
     347             :     }
     348             : }
     349             : 
     350             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     351             : 
     352             : #define AI SK_ALWAYS_INLINE
     353             : 
     354             : static AI void load_matrix(const float matrix[13],
     355             :                            Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
     356           0 :     rXgXbX = Sk4f::Load(matrix + 0);
     357           0 :     rYgYbY = Sk4f::Load(matrix + 3);
     358           0 :     rZgZbZ = Sk4f::Load(matrix + 6);
     359           0 :     rTgTbT = Sk4f::Load(matrix + 9);
     360             : }
     361             : 
     362             : enum Order {
     363             :     kRGBA_Order,
     364             :     kBGRA_Order,
     365             : };
     366             : 
     367             : static AI void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) {
     368           0 :     if (kRGBA_Order == kOrder) {
     369           0 :         *kRShift = 0;
     370           0 :         *kBShift = 16;
     371             :     } else {
     372           0 :         *kRShift = 16;
     373           0 :         *kBShift = 0;
     374             :     }
     375             : }
     376             : 
     377             : template <Order kOrder>
     378           0 : static AI void load_rgb_from_tables(const uint32_t* src,
     379             :                                     Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     380             :                                     const float* const srcTables[3]) {
     381           0 :     int kRShift, kGShift = 8, kBShift;
     382             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     383           0 :     r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
     384           0 :           srcTables[0][(src[1] >> kRShift) & 0xFF],
     385           0 :           srcTables[0][(src[2] >> kRShift) & 0xFF],
     386           0 :           srcTables[0][(src[3] >> kRShift) & 0xFF], };
     387           0 :     g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
     388           0 :           srcTables[1][(src[1] >> kGShift) & 0xFF],
     389           0 :           srcTables[1][(src[2] >> kGShift) & 0xFF],
     390           0 :           srcTables[1][(src[3] >> kGShift) & 0xFF], };
     391           0 :     b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
     392           0 :           srcTables[2][(src[1] >> kBShift) & 0xFF],
     393           0 :           srcTables[2][(src[2] >> kBShift) & 0xFF],
     394           0 :           srcTables[2][(src[3] >> kBShift) & 0xFF], };
     395           0 :     a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
     396           0 : }
     397             : 
     398             : template <Order kOrder>
     399           0 : static AI void load_rgba_from_tables(const uint32_t* src,
     400             :                                      Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     401             :                                      const float* const srcTables[3]) {
     402           0 :     int kRShift, kGShift = 8, kBShift;
     403             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     404           0 :     r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
     405           0 :           srcTables[0][(src[1] >> kRShift) & 0xFF],
     406           0 :           srcTables[0][(src[2] >> kRShift) & 0xFF],
     407           0 :           srcTables[0][(src[3] >> kRShift) & 0xFF], };
     408           0 :     g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
     409           0 :           srcTables[1][(src[1] >> kGShift) & 0xFF],
     410           0 :           srcTables[1][(src[2] >> kGShift) & 0xFF],
     411           0 :           srcTables[1][(src[3] >> kGShift) & 0xFF], };
     412           0 :     b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
     413           0 :           srcTables[2][(src[1] >> kBShift) & 0xFF],
     414           0 :           srcTables[2][(src[2] >> kBShift) & 0xFF],
     415           0 :           srcTables[2][(src[3] >> kBShift) & 0xFF], };
     416           0 :     a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
     417           0 : }
     418             : 
     419             : template <Order kOrder>
     420           0 : static AI void load_rgb_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     421             :                                const float* const[3]) {
     422           0 :     int kRShift, kGShift = 8, kBShift;
     423             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     424           0 :     r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
     425           0 :     g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
     426           0 :     b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
     427           0 :     a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
     428           0 : }
     429             : 
     430             : template <Order kOrder>
     431           0 : static AI void load_rgba_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     432             :                                 const float* const[3]) {
     433           0 :     int kRShift, kGShift = 8, kBShift;
     434             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     435           0 :     r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
     436           0 :     g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
     437           0 :     b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
     438           0 :     a = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 24));
     439           0 : }
     440             : 
     441             : template <Order kOrder>
     442           0 : static AI void load_rgb_from_tables_1(const uint32_t* src,
     443             :                                       Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     444             :                                       const float* const srcTables[3]) {
     445           0 :     int kRShift, kGShift = 8, kBShift;
     446             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     447           0 :     r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
     448           0 :     g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
     449           0 :     b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
     450           0 :     a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
     451           0 : }
     452             : 
     453             : template <Order kOrder>
     454           0 : static AI void load_rgba_from_tables_1(const uint32_t* src,
     455             :                                        Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     456             :                                        const float* const srcTables[3]) {
     457           0 :     int kRShift, kGShift = 8, kBShift;
     458             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     459           0 :     r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
     460           0 :     g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
     461           0 :     b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
     462           0 :     a = (1.0f / 255.0f) * Sk4f(*src >> 24);
     463           0 : }
     464             : 
     465             : template <Order kOrder>
     466           0 : static AI void load_rgb_linear_1(const uint32_t* src,
     467             :                                  Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     468             :                                  const float* const srcTables[3]) {
     469           0 :     int kRShift, kGShift = 8, kBShift;
     470             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     471           0 :     r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
     472           0 :     g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
     473           0 :     b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
     474           0 :     a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
     475           0 : }
     476             : 
     477             : template <Order kOrder>
     478           0 : static AI void load_rgba_linear_1(const uint32_t* src,
     479             :                                   Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
     480             :                                   const float* const srcTables[3]) {
     481           0 :     int kRShift, kGShift = 8, kBShift;
     482             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     483           0 :     r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
     484           0 :     g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
     485           0 :     b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
     486           0 :     a = Sk4f((1.0f / 255.0f) * ((*src >> 24)));
     487           0 : }
     488             : 
     489             : static AI void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
     490             :                                const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
     491             :                                Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
     492           0 :     dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
     493           0 :     dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
     494           0 :     db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
     495           0 :     da = a;
     496             : }
     497             : 
     498             : static AI void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
     499             :                                  const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
     500             :                                  Sk4f& rgba) {
     501           0 :     rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
     502             : }
     503             : 
     504             : static AI void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
     505           0 :     dr = dr + rTgTbT[0];
     506           0 :     dg = dg + rTgTbT[1];
     507           0 :     db = db + rTgTbT[2];
     508             : }
     509             : 
     510             : static AI void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
     511           0 :     rgba = rgba + rTgTbT;
     512             : }
     513             : 
     514             : template <Order kOrder>
     515           0 : static AI void store_srgb(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
     516             :                           const uint8_t* const[3]) {
     517           0 :     int kRShift, kGShift = 8, kBShift;
     518             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     519           0 :     dr = sk_linear_to_srgb_needs_trunc(dr);
     520           0 :     dg = sk_linear_to_srgb_needs_trunc(dg);
     521           0 :     db = sk_linear_to_srgb_needs_trunc(db);
     522             : 
     523           0 :     dr = sk_clamp_0_255(dr);
     524           0 :     dg = sk_clamp_0_255(dg);
     525           0 :     db = sk_clamp_0_255(db);
     526             : 
     527           0 :     Sk4i da = Sk4i::Load(src) & 0xFF000000;
     528             : 
     529           0 :     Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
     530           0 :               | (SkNx_cast<int>(dg) << kGShift)
     531           0 :               | (SkNx_cast<int>(db) << kBShift)
     532           0 :               | (da                           );
     533             :     rgba.store(dst);
     534           0 : }
     535             : 
     536             : template <Order kOrder>
     537           0 : static AI void store_srgb_1(void* dst, const uint32_t* src,
     538             :                             Sk4f& rgba, const Sk4f&,
     539             :                             const uint8_t* const[3]) {
     540           0 :     rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
     541             : 
     542             :     uint32_t tmp;
     543           0 :     SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
     544           0 :     tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
     545             :     if (kBGRA_Order == kOrder) {
     546           0 :         tmp = SkSwizzle_RB(tmp);
     547             :     }
     548             : 
     549           0 :     *(uint32_t*)dst = tmp;
     550           0 : }
     551             : 
     552             : static AI Sk4f linear_to_2dot2(const Sk4f& x) {
     553             :     // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
     554           0 :     auto x2  = x.rsqrt(),                            // x^(-1/2)
     555           0 :          x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(),   // x^(-1/32)
     556           0 :          x64 = x32.rsqrt();                          // x^(+1/64)
     557             : 
     558             :     // 29 = 32 - 2 - 1
     559           0 :     return 255.0f * x2.invert() * x32 * x64.invert();
     560             : }
     561             : 
     562             : template <Order kOrder>
     563           0 : static AI void store_2dot2(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
     564             :                            const uint8_t* const[3]) {
     565           0 :     int kRShift, kGShift = 8, kBShift;
     566             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     567           0 :     dr = linear_to_2dot2(dr);
     568           0 :     dg = linear_to_2dot2(dg);
     569           0 :     db = linear_to_2dot2(db);
     570             : 
     571           0 :     dr = sk_clamp_0_255(dr);
     572           0 :     dg = sk_clamp_0_255(dg);
     573           0 :     db = sk_clamp_0_255(db);
     574             : 
     575           0 :     Sk4i da = Sk4i::Load(src) & 0xFF000000;
     576             : 
     577           0 :     Sk4i rgba = (Sk4f_round(dr) << kRShift)
     578           0 :               | (Sk4f_round(dg) << kGShift)
     579           0 :               | (Sk4f_round(db) << kBShift)
     580           0 :               | (da                       );
     581             :     rgba.store(dst);
     582           0 : }
     583             : 
     584             : template <Order kOrder>
     585           0 : static AI void store_2dot2_1(void* dst, const uint32_t* src,
     586             :                              Sk4f& rgba, const Sk4f&,
     587             :                              const uint8_t* const[3]) {
     588           0 :     rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
     589             : 
     590             :     uint32_t tmp;
     591           0 :     SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
     592           0 :     tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
     593             :     if (kBGRA_Order == kOrder) {
     594           0 :         tmp = SkSwizzle_RB(tmp);
     595             :     }
     596             : 
     597           0 :     *(uint32_t*)dst = tmp;
     598           0 : }
     599             : 
     600             : template <Order kOrder>
     601           0 : static AI void store_linear(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
     602             :                             const uint8_t* const[3]) {
     603           0 :     int kRShift, kGShift = 8, kBShift;
     604             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     605           0 :     dr = sk_clamp_0_255(255.0f * dr);
     606           0 :     dg = sk_clamp_0_255(255.0f * dg);
     607           0 :     db = sk_clamp_0_255(255.0f * db);
     608             : 
     609           0 :     Sk4i da = Sk4i::Load(src) & 0xFF000000;
     610             : 
     611           0 :     Sk4i rgba = (Sk4f_round(dr) << kRShift)
     612           0 :               | (Sk4f_round(dg) << kGShift)
     613           0 :               | (Sk4f_round(db) << kBShift)
     614           0 :               | (da                       );
     615             :     rgba.store(dst);
     616           0 : }
     617             : 
     618             : template <Order kOrder>
     619           0 : static AI void store_linear_1(void* dst, const uint32_t* src,
     620             :                               Sk4f& rgba, const Sk4f&,
     621             :                               const uint8_t* const[3]) {
     622           0 :     rgba = sk_clamp_0_255(255.0f * rgba);
     623             : 
     624             :     uint32_t tmp;
     625           0 :     SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
     626           0 :     tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
     627             :     if (kBGRA_Order == kOrder) {
     628           0 :         tmp = SkSwizzle_RB(tmp);
     629             :     }
     630             : 
     631           0 :     *(uint32_t*)dst = tmp;
     632           0 : }
     633             : 
     634             : template <Order kOrder>
     635           0 : static AI void store_f16(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
     636             :                          const uint8_t* const[3]) {
     637           0 :     Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
     638           0 :                       SkFloatToHalf_finite_ftz(dg),
     639           0 :                       SkFloatToHalf_finite_ftz(db),
     640           0 :                       SkFloatToHalf_finite_ftz(da));
     641           0 : }
     642             : 
     643             : template <Order kOrder>
     644           0 : static AI void store_f16_1(void* dst, const uint32_t* src,
     645             :                            Sk4f& rgba, const Sk4f& a,
     646             :                            const uint8_t* const[3]) {
     647           0 :     rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
     648           0 :     SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst);
     649           0 : }
     650             : 
     651             : template <Order kOrder>
     652           0 : static AI void store_f16_opaque(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db,
     653             :                                 Sk4f&, const uint8_t* const[3]) {
     654           0 :     Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
     655           0 :                       SkFloatToHalf_finite_ftz(dg),
     656           0 :                       SkFloatToHalf_finite_ftz(db),
     657             :                       SK_Half1);
     658           0 : }
     659             : 
     660             : template <Order kOrder>
     661           0 : static AI void store_f16_1_opaque(void* dst, const uint32_t* src,
     662             :                                   Sk4f& rgba, const Sk4f&,
     663             :                                   const uint8_t* const[3]) {
     664             :     uint64_t tmp;
     665           0 :     SkFloatToHalf_finite_ftz(rgba).store(&tmp);
     666           0 :     tmp &= 0x0000FFFFFFFFFFFF;
     667           0 :     tmp |= static_cast<uint64_t>(SK_Half1) << 48;
     668           0 :     *((uint64_t*) dst) = tmp;
     669           0 : }
     670             : 
     671             : template <Order kOrder>
     672           0 : static AI void store_generic(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
     673             :                              const uint8_t* const dstTables[3]) {
     674           0 :     int kRShift, kGShift = 8, kBShift;
     675             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     676           0 :     dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
     677           0 :     dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
     678           0 :     db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
     679             : 
     680           0 :     Sk4i ir = Sk4f_round(dr);
     681           0 :     Sk4i ig = Sk4f_round(dg);
     682           0 :     Sk4i ib = Sk4f_round(db);
     683             : 
     684           0 :     Sk4i da = Sk4i::Load(src) & 0xFF000000;
     685             : 
     686           0 :     uint32_t* dst32 = (uint32_t*) dst;
     687           0 :     dst32[0] = dstTables[0][ir[0]] << kRShift
     688           0 :              | dstTables[1][ig[0]] << kGShift
     689           0 :              | dstTables[2][ib[0]] << kBShift
     690           0 :              | da[0];
     691           0 :     dst32[1] = dstTables[0][ir[1]] << kRShift
     692           0 :              | dstTables[1][ig[1]] << kGShift
     693           0 :              | dstTables[2][ib[1]] << kBShift
     694           0 :              | da[1];
     695           0 :     dst32[2] = dstTables[0][ir[2]] << kRShift
     696           0 :              | dstTables[1][ig[2]] << kGShift
     697           0 :              | dstTables[2][ib[2]] << kBShift
     698           0 :              | da[2];
     699           0 :     dst32[3] = dstTables[0][ir[3]] << kRShift
     700           0 :              | dstTables[1][ig[3]] << kGShift
     701           0 :              | dstTables[2][ib[3]] << kBShift
     702           0 :              | da[3];
     703           0 : }
     704             : 
     705             : template <Order kOrder>
     706           0 : static AI void store_generic_1(void* dst, const uint32_t* src,
     707             :                                Sk4f& rgba, const Sk4f&,
     708             :                                const uint8_t* const dstTables[3]) {
     709           0 :     int kRShift, kGShift = 8, kBShift;
     710             :     set_rb_shifts(kOrder, &kRShift, &kBShift);
     711           0 :     rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
     712             : 
     713           0 :     Sk4i indices = Sk4f_round(rgba);
     714             : 
     715           0 :     *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
     716           0 :                        | dstTables[1][indices[1]] << kGShift
     717           0 :                        | dstTables[2][indices[2]] << kBShift
     718           0 :                        | (*src & 0xFF000000);
     719           0 : }
     720             : 
     721             : typedef decltype(load_rgb_from_tables<kRGBA_Order>  )* LoadFn;
     722             : typedef decltype(load_rgb_from_tables_1<kRGBA_Order>)* Load1Fn;
     723             : typedef decltype(store_generic<kRGBA_Order>         )* StoreFn;
     724             : typedef decltype(store_generic_1<kRGBA_Order>       )* Store1Fn;
     725             : 
     726             : enum SrcFormat {
     727             :     kRGBA_8888_Linear_SrcFormat,
     728             :     kRGBA_8888_Table_SrcFormat,
     729             :     kBGRA_8888_Linear_SrcFormat,
     730             :     kBGRA_8888_Table_SrcFormat,
     731             : };
     732             : 
     733             : enum DstFormat {
     734             :     kRGBA_8888_Linear_DstFormat,
     735             :     kRGBA_8888_SRGB_DstFormat,
     736             :     kRGBA_8888_2Dot2_DstFormat,
     737             :     kRGBA_8888_Table_DstFormat,
     738             :     kBGRA_8888_Linear_DstFormat,
     739             :     kBGRA_8888_SRGB_DstFormat,
     740             :     kBGRA_8888_2Dot2_DstFormat,
     741             :     kBGRA_8888_Table_DstFormat,
     742             :     kF16_Linear_DstFormat,
     743             : };
     744             : 
     745             : template <SrcFormat kSrc,
     746             :           DstFormat kDst,
     747             :           SkAlphaType kAlphaType,
     748             :           ColorSpaceMatch kCSM>
     749           0 : static void color_xform_RGBA(void* dst, const void* vsrc, int len,
     750             :                              const float* const srcTables[3], const float matrix[13],
     751             :                              const uint8_t* const dstTables[3]) {
     752             :     LoadFn load;
     753             :     Load1Fn load_1;
     754           0 :     const bool kLoadAlpha = kF16_Linear_DstFormat == kDst && kOpaque_SkAlphaType != kAlphaType;
     755             :     switch (kSrc) {
     756             :         case kRGBA_8888_Linear_SrcFormat:
     757             :             if (kLoadAlpha) {
     758           0 :                 load = load_rgba_linear<kRGBA_Order>;
     759           0 :                 load_1 = load_rgba_linear_1<kRGBA_Order>;
     760             :             } else {
     761           0 :                 load = load_rgb_linear<kRGBA_Order>;
     762           0 :                 load_1 = load_rgb_linear_1<kRGBA_Order>;
     763             :             }
     764           0 :             break;
     765             :         case kRGBA_8888_Table_SrcFormat:
     766             :             if (kLoadAlpha) {
     767           0 :                 load = load_rgba_from_tables<kRGBA_Order>;
     768           0 :                 load_1 = load_rgba_from_tables_1<kRGBA_Order>;
     769             :             } else {
     770           0 :                 load = load_rgb_from_tables<kRGBA_Order>;
     771           0 :                 load_1 = load_rgb_from_tables_1<kRGBA_Order>;
     772             :             }
     773           0 :             break;
     774             :         case kBGRA_8888_Linear_SrcFormat:
     775             :             if (kLoadAlpha) {
     776           0 :                 load = load_rgba_linear<kBGRA_Order>;
     777           0 :                 load_1 = load_rgba_linear_1<kBGRA_Order>;
     778             :             } else {
     779           0 :                 load = load_rgb_linear<kBGRA_Order>;
     780           0 :                 load_1 = load_rgb_linear_1<kBGRA_Order>;
     781             :             }
     782           0 :             break;
     783             :         case kBGRA_8888_Table_SrcFormat:
     784             :             if (kLoadAlpha) {
     785           0 :                 load = load_rgba_from_tables<kBGRA_Order>;
     786           0 :                 load_1 = load_rgba_from_tables_1<kBGRA_Order>;
     787             :             } else {
     788           0 :                 load = load_rgb_from_tables<kBGRA_Order>;
     789           0 :                 load_1 = load_rgb_from_tables_1<kBGRA_Order>;
     790             :             }
     791           0 :             break;
     792             :     }
     793             : 
     794             :     StoreFn store;
     795             :     Store1Fn store_1;
     796             :     size_t sizeOfDstPixel;
     797             :     switch (kDst) {
     798             :         case kRGBA_8888_Linear_DstFormat:
     799           0 :             store   = store_linear<kRGBA_Order>;
     800           0 :             store_1 = store_linear_1<kRGBA_Order>;
     801           0 :             sizeOfDstPixel = 4;
     802           0 :             break;
     803             :         case kRGBA_8888_SRGB_DstFormat:
     804           0 :             store   = store_srgb<kRGBA_Order>;
     805           0 :             store_1 = store_srgb_1<kRGBA_Order>;
     806           0 :             sizeOfDstPixel = 4;
     807           0 :             break;
     808             :         case kRGBA_8888_2Dot2_DstFormat:
     809           0 :             store   = store_2dot2<kRGBA_Order>;
     810           0 :             store_1 = store_2dot2_1<kRGBA_Order>;
     811           0 :             sizeOfDstPixel = 4;
     812           0 :             break;
     813             :         case kRGBA_8888_Table_DstFormat:
     814           0 :             store   = store_generic<kRGBA_Order>;
     815           0 :             store_1 = store_generic_1<kRGBA_Order>;
     816           0 :             sizeOfDstPixel = 4;
     817           0 :             break;
     818             :         case kBGRA_8888_Linear_DstFormat:
     819           0 :             store   = store_linear<kBGRA_Order>;
     820           0 :             store_1 = store_linear_1<kBGRA_Order>;
     821           0 :             sizeOfDstPixel = 4;
     822           0 :             break;
     823             :         case kBGRA_8888_SRGB_DstFormat:
     824           0 :             store   = store_srgb<kBGRA_Order>;
     825           0 :             store_1 = store_srgb_1<kBGRA_Order>;
     826           0 :             sizeOfDstPixel = 4;
     827           0 :             break;
     828             :         case kBGRA_8888_2Dot2_DstFormat:
     829           0 :             store   = store_2dot2<kBGRA_Order>;
     830           0 :             store_1 = store_2dot2_1<kBGRA_Order>;
     831           0 :             sizeOfDstPixel = 4;
     832           0 :             break;
     833             :         case kBGRA_8888_Table_DstFormat:
     834           0 :             store   = store_generic<kBGRA_Order>;
     835           0 :             store_1 = store_generic_1<kBGRA_Order>;
     836           0 :             sizeOfDstPixel = 4;
     837           0 :             break;
     838             :         case kF16_Linear_DstFormat:
     839           0 :             store   = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque<kRGBA_Order> :
     840             :                                                             store_f16<kRGBA_Order>;
     841           0 :             store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque<kRGBA_Order> :
     842             :                                                             store_f16_1<kRGBA_Order>;
     843           0 :             sizeOfDstPixel = 8;
     844           0 :             break;
     845             :     }
     846             : 
     847           0 :     const uint32_t* src = (const uint32_t*) vsrc;
     848             :     Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
     849             :     load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
     850             : 
     851           0 :     if (len >= 4) {
     852             :         // Naively this would be a loop of load-transform-store, but we found it faster to
     853             :         // move the N+1th load ahead of the Nth store.  We don't bother doing this for N<4.
     854             :         Sk4f r, g, b, a;
     855           0 :         load(src, r, g, b, a, srcTables);
     856           0 :         src += 4;
     857           0 :         len -= 4;
     858             : 
     859             :         Sk4f dr, dg, db, da;
     860           0 :         while (len >= 4) {
     861             :             if (kNone_ColorSpaceMatch == kCSM) {
     862             :                 transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
     863             :                 translate_gamut(rTgTbT, dr, dg, db);
     864             :             } else {
     865           0 :                 dr = r;
     866           0 :                 dg = g;
     867           0 :                 db = b;
     868           0 :                 da = a;
     869             :             }
     870             : 
     871           0 :             load(src, r, g, b, a, srcTables);
     872             : 
     873           0 :             store(dst, src - 4, dr, dg, db, da, dstTables);
     874           0 :             dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
     875           0 :             src += 4;
     876           0 :             len -= 4;
     877             :         }
     878             : 
     879             :         if (kNone_ColorSpaceMatch == kCSM) {
     880             :             transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
     881             :             translate_gamut(rTgTbT, dr, dg, db);
     882             :         } else {
     883           0 :             dr = r;
     884           0 :             dg = g;
     885           0 :             db = b;
     886           0 :             da = a;
     887             :         }
     888             : 
     889           0 :         store(dst, src - 4, dr, dg, db, da, dstTables);
     890           0 :         dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
     891             :     }
     892             : 
     893           0 :     while (len > 0) {
     894             :         Sk4f r, g, b, a;
     895           0 :         load_1(src, r, g, b, a, srcTables);
     896             : 
     897             :         Sk4f rgba;
     898             :         if (kNone_ColorSpaceMatch == kCSM) {
     899             :             transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
     900             :             translate_gamut_1(rTgTbT, rgba);
     901             :         } else {
     902           0 :             rgba = Sk4f(r[0], g[0], b[0], a[0]);
     903             :         }
     904             : 
     905           0 :         store_1(dst, src, rgba, a, dstTables);
     906             : 
     907           0 :         src += 1;
     908           0 :         len -= 1;
     909           0 :         dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
     910             :     }
     911           0 : }
     912             : 
     913             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     914             : 
     915             : static AI int num_tables(SkColorSpace_XYZ* space) {
     916           0 :     switch (space->gammaNamed()) {
     917             :         case kSRGB_SkGammaNamed:
     918             :         case k2Dot2Curve_SkGammaNamed:
     919             :         case kLinear_SkGammaNamed:
     920           0 :             return 0;
     921             :         default: {
     922           0 :             const SkGammas* gammas = space->gammas();
     923           0 :             SkASSERT(gammas);
     924             : 
     925           0 :             bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
     926           0 :                                      (gammas->data(0) == gammas->data(1)) &&
     927           0 :                                      (gammas->type(0) == gammas->type(2)) &&
     928           0 :                                      (gammas->data(0) == gammas->data(2));
     929             : 
     930             :             // It's likely that each component will have the same gamma.  In this case,
     931             :             // we only need to build one table.
     932           0 :             return gammasAreMatching ? 1 : 3;
     933             :         }
     934             :     }
     935             : }
     936             : 
     937             : template <ColorSpaceMatch kCSM>
     938           0 : SkColorSpaceXform_XYZ<kCSM>
     939             : ::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst,
     940             :                         SkColorSpace_XYZ* dstSpace, SkTransferFunctionBehavior premulBehavior)
     941           0 :     : fPremulBehavior(premulBehavior)
     942             : {
     943           0 :     fSrcToDst[ 0] = srcToDst.get(0, 0);
     944           0 :     fSrcToDst[ 1] = srcToDst.get(1, 0);
     945           0 :     fSrcToDst[ 2] = srcToDst.get(2, 0);
     946           0 :     fSrcToDst[ 3] = srcToDst.get(0, 1);
     947           0 :     fSrcToDst[ 4] = srcToDst.get(1, 1);
     948           0 :     fSrcToDst[ 5] = srcToDst.get(2, 1);
     949           0 :     fSrcToDst[ 6] = srcToDst.get(0, 2);
     950           0 :     fSrcToDst[ 7] = srcToDst.get(1, 2);
     951           0 :     fSrcToDst[ 8] = srcToDst.get(2, 2);
     952           0 :     fSrcToDst[ 9] = srcToDst.get(0, 3);
     953           0 :     fSrcToDst[10] = srcToDst.get(1, 3);
     954           0 :     fSrcToDst[11] = srcToDst.get(2, 3);
     955           0 :     fSrcToDst[12] = 0.0f;
     956             : 
     957           0 :     const int numSrcTables = num_tables(srcSpace);
     958           0 :     const size_t srcEntries = numSrcTables * 256;
     959           0 :     const bool srcGammasAreMatching = (1 >= numSrcTables);
     960           0 :     fSrcStorage.reset(srcEntries);
     961           0 :     build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear,
     962             :                        srcGammasAreMatching);
     963             : 
     964           0 :     const int numDstTables = num_tables(dstSpace);
     965           0 :     dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables);
     966             : 
     967           0 :     if (srcSpace->gammaIsLinear()) {
     968           0 :         fSrcGamma = kLinear_SrcGamma;
     969           0 :     } else if (kSRGB_SkGammaNamed == srcSpace->gammaNamed()) {
     970           0 :         fSrcGamma = kSRGB_SrcGamma;
     971             :     } else {
     972           0 :         fSrcGamma = kTable_SrcGamma;
     973             :     }
     974             : 
     975           0 :     switch (dstSpace->gammaNamed()) {
     976             :         case kSRGB_SkGammaNamed:
     977           0 :             fDstGamma = kSRGB_DstGamma;
     978           0 :             break;
     979             :         case k2Dot2Curve_SkGammaNamed:
     980           0 :             fDstGamma = k2Dot2_DstGamma;
     981           0 :             break;
     982             :         case kLinear_SkGammaNamed:
     983           0 :             fDstGamma = kLinear_DstGamma;
     984           0 :             break;
     985             :         default:
     986           0 :             fDstGamma = kTable_DstGamma;
     987           0 :             break;
     988             :     }
     989           0 : }
     990             : 
     991             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     992             : 
     993             : template <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
     994             : static AI bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaType alphaType,
     995             :                                const float* const srcTables[3], const float matrix[13],
     996             :                                const uint8_t* const dstTables[3]) {
     997           0 :     switch (alphaType) {
     998             :         case kOpaque_SkAlphaType:
     999           0 :             color_xform_RGBA<kSrc, kDst, kOpaque_SkAlphaType, kCSM>
    1000             :                     (dst, src, len, srcTables, matrix, dstTables);
    1001           0 :             return true;
    1002             :         case kUnpremul_SkAlphaType:
    1003           0 :             color_xform_RGBA<kSrc, kDst, kUnpremul_SkAlphaType, kCSM>
    1004             :                     (dst, src, len, srcTables, matrix, dstTables);
    1005           0 :             return true;
    1006             :         default:
    1007           0 :             return false;
    1008             :     }
    1009             : }
    1010             : 
    1011             : template <DstFormat kDst, ColorSpaceMatch kCSM>
    1012             : static AI bool apply_set_src(void* dst, const void* src, int len, SkAlphaType alphaType,
    1013             :                              const float* const srcTables[3], const float matrix[13],
    1014             :                              const uint8_t* const dstTables[3],
    1015             :                              SkColorSpaceXform::ColorFormat srcColorFormat,
    1016             :                              SrcGamma srcGamma) {
    1017           0 :     switch (srcColorFormat) {
    1018             :         case SkColorSpaceXform::kRGBA_8888_ColorFormat:
    1019           0 :             switch (srcGamma) {
    1020             :                 case kLinear_SrcGamma:
    1021             :                     return apply_set_alpha<kRGBA_8888_Linear_SrcFormat, kDst, kCSM>
    1022           0 :                             (dst, src, len, alphaType, nullptr, matrix, dstTables);
    1023             :                 default:
    1024             :                     return apply_set_alpha<kRGBA_8888_Table_SrcFormat, kDst, kCSM>
    1025           0 :                             (dst, src, len, alphaType, srcTables, matrix, dstTables);
    1026             :             }
    1027             :         case SkColorSpaceXform::kBGRA_8888_ColorFormat:
    1028           0 :             switch (srcGamma) {
    1029             :                 case kLinear_SrcGamma:
    1030             :                     return apply_set_alpha<kBGRA_8888_Linear_SrcFormat, kDst, kCSM>
    1031           0 :                             (dst, src, len, alphaType, nullptr, matrix, dstTables);
    1032             :                 default:
    1033             :                     return apply_set_alpha<kBGRA_8888_Table_SrcFormat, kDst, kCSM>
    1034           0 :                             (dst, src, len, alphaType, srcTables, matrix, dstTables);
    1035             :             }
    1036             :         default:
    1037           0 :             return false;
    1038             :     }
    1039             : }
    1040             : 
    1041             : #undef AI
    1042             : 
    1043             : template <ColorSpaceMatch kCSM>
    1044           0 : bool SkColorSpaceXform_XYZ<kCSM>
    1045             : ::onApply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, const void* src,
    1046             :           int len, SkAlphaType alphaType) const
    1047             : {
    1048             :     if (kFull_ColorSpaceMatch == kCSM) {
    1049           0 :         if (kPremul_SkAlphaType != alphaType) {
    1050           0 :             if ((kRGBA_8888_ColorFormat == dstColorFormat &&
    1051           0 :                  kRGBA_8888_ColorFormat == srcColorFormat) ||
    1052           0 :                 (kBGRA_8888_ColorFormat == dstColorFormat &&
    1053             :                  kBGRA_8888_ColorFormat == srcColorFormat))
    1054             :             {
    1055           0 :                 memcpy(dst, src, len * sizeof(uint32_t));
    1056           0 :                 return true;
    1057             :             }
    1058           0 :             if ((kRGBA_8888_ColorFormat == dstColorFormat &&
    1059           0 :                  kBGRA_8888_ColorFormat == srcColorFormat) ||
    1060           0 :                 (kBGRA_8888_ColorFormat == dstColorFormat &&
    1061             :                  kRGBA_8888_ColorFormat == srcColorFormat))
    1062             :             {
    1063           0 :                 SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
    1064           0 :                 return true;
    1065             :             }
    1066             :         }
    1067             :     }
    1068             : 
    1069           0 :     if (kRGBA_F32_ColorFormat == dstColorFormat ||
    1070           0 :         kBGR_565_ColorFormat == dstColorFormat ||
    1071           0 :         kRGBA_F32_ColorFormat == srcColorFormat ||
    1072           0 :         kRGBA_F16_ColorFormat == srcColorFormat ||
    1073           0 :         kRGBA_U16_BE_ColorFormat == srcColorFormat ||
    1074           0 :         kRGB_U16_BE_ColorFormat == srcColorFormat ||
    1075             :         kPremul_SkAlphaType == alphaType)
    1076             :     {
    1077           0 :         return this->applyPipeline(dstColorFormat, dst, srcColorFormat, src, len, alphaType);
    1078             :     }
    1079             : 
    1080           0 :     switch (dstColorFormat) {
    1081             :         case kRGBA_8888_ColorFormat:
    1082           0 :             switch (fDstGamma) {
    1083             :                 case kLinear_DstGamma:
    1084             :                     return apply_set_src<kRGBA_8888_Linear_DstFormat, kCSM>
    1085           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
    1086           0 :                              srcColorFormat, fSrcGamma);
    1087             :                 case kSRGB_DstGamma:
    1088             :                     return apply_set_src<kRGBA_8888_SRGB_DstFormat, kCSM>
    1089           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
    1090           0 :                              srcColorFormat, fSrcGamma);
    1091             :                 case k2Dot2_DstGamma:
    1092             :                     return apply_set_src<kRGBA_8888_2Dot2_DstFormat, kCSM>
    1093           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
    1094           0 :                              srcColorFormat, fSrcGamma);
    1095             :                 case kTable_DstGamma:
    1096             :                     return apply_set_src<kRGBA_8888_Table_DstFormat, kCSM>
    1097           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
    1098           0 :                              srcColorFormat, fSrcGamma);
    1099             :             }
    1100             :         case kBGRA_8888_ColorFormat:
    1101           0 :             switch (fDstGamma) {
    1102             :                 case kLinear_DstGamma:
    1103             :                     return apply_set_src<kBGRA_8888_Linear_DstFormat, kCSM>
    1104           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
    1105           0 :                              srcColorFormat, fSrcGamma);
    1106             :                 case kSRGB_DstGamma:
    1107             :                     return apply_set_src<kBGRA_8888_SRGB_DstFormat, kCSM>
    1108           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
    1109           0 :                              srcColorFormat, fSrcGamma);
    1110             :                 case k2Dot2_DstGamma:
    1111             :                     return apply_set_src<kBGRA_8888_2Dot2_DstFormat, kCSM>
    1112           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
    1113           0 :                              srcColorFormat, fSrcGamma);
    1114             :                 case kTable_DstGamma:
    1115             :                     return apply_set_src<kBGRA_8888_Table_DstFormat, kCSM>
    1116           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
    1117           0 :                              srcColorFormat, fSrcGamma);
    1118             :             }
    1119             :         case kRGBA_F16_ColorFormat:
    1120           0 :             switch (fDstGamma) {
    1121             :                 case kLinear_DstGamma:
    1122             :                     return apply_set_src<kF16_Linear_DstFormat, kCSM>
    1123           0 :                             (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
    1124           0 :                              srcColorFormat, fSrcGamma);
    1125             :                 default:
    1126           0 :                     return false;
    1127             :             }
    1128             :         default:
    1129           0 :             SkASSERT(false);
    1130           0 :             return false;
    1131             :     }
    1132             : }
    1133             : 
    1134           0 : bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
    1135             :                               const void* src, int len, SkAlphaType alphaType) const {
    1136             :     return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcColorFormat, src, len,
    1137           0 :                                                      alphaType);
    1138             : }
    1139             : 
    1140             : ///////////////////////////////////////////////////////////////////////////////////////////////////
    1141             : 
    1142             : template <ColorSpaceMatch kCSM>
    1143           0 : bool SkColorSpaceXform_XYZ<kCSM>
    1144             : ::applyPipeline(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
    1145             :                 const void* src, int len, SkAlphaType alphaType) const {
    1146           0 :     SkRasterPipeline pipeline;
    1147             : 
    1148             :     LoadTablesContext loadTables;
    1149           0 :     switch (srcColorFormat) {
    1150             :         case kRGBA_8888_ColorFormat:
    1151           0 :             if (kLinear_SrcGamma == fSrcGamma) {
    1152           0 :                 pipeline.append(SkRasterPipeline::load_8888, &src);
    1153             :             } else {
    1154           0 :                 loadTables.fSrc = src;
    1155           0 :                 loadTables.fR = fSrcGammaTables[0];
    1156           0 :                 loadTables.fG = fSrcGammaTables[1];
    1157           0 :                 loadTables.fB = fSrcGammaTables[2];
    1158           0 :                 pipeline.append(SkRasterPipeline::load_tables, &loadTables);
    1159             :             }
    1160             : 
    1161           0 :             break;
    1162             :         case kBGRA_8888_ColorFormat:
    1163           0 :             if (kLinear_SrcGamma == fSrcGamma) {
    1164           0 :                 pipeline.append(SkRasterPipeline::load_8888, &src);
    1165             :             } else {
    1166           0 :                 loadTables.fSrc = src;
    1167           0 :                 loadTables.fR = fSrcGammaTables[2];
    1168           0 :                 loadTables.fG = fSrcGammaTables[1];
    1169           0 :                 loadTables.fB = fSrcGammaTables[0];
    1170           0 :                 pipeline.append(SkRasterPipeline::load_tables, &loadTables);
    1171             :             }
    1172             : 
    1173           0 :             pipeline.append(SkRasterPipeline::swap_rb);
    1174           0 :             break;
    1175             :         case kRGBA_F16_ColorFormat:
    1176           0 :             if (kLinear_SrcGamma != fSrcGamma) {
    1177           0 :                 return false;
    1178             :             }
    1179           0 :             pipeline.append(SkRasterPipeline::load_f16, &src);
    1180           0 :             break;
    1181             :         case kRGBA_F32_ColorFormat:
    1182           0 :             if (kLinear_SrcGamma != fSrcGamma) {
    1183           0 :                 return false;
    1184             :             }
    1185           0 :             pipeline.append(SkRasterPipeline::load_f32, &src);
    1186           0 :             break;
    1187             :         case kRGBA_U16_BE_ColorFormat:
    1188           0 :             switch (fSrcGamma) {
    1189             :                 case kLinear_SrcGamma:
    1190           0 :                     pipeline.append(SkRasterPipeline::load_u16_be, &src);
    1191           0 :                     break;
    1192             :                 case kSRGB_SrcGamma:
    1193           0 :                     pipeline.append(SkRasterPipeline::load_u16_be, &src);
    1194           0 :                     pipeline.append_from_srgb(kUnpremul_SkAlphaType);
    1195           0 :                     break;
    1196             :                 case kTable_SrcGamma:
    1197           0 :                     loadTables.fSrc = src;
    1198           0 :                     loadTables.fR = fSrcGammaTables[0];
    1199           0 :                     loadTables.fG = fSrcGammaTables[1];
    1200           0 :                     loadTables.fB = fSrcGammaTables[2];
    1201           0 :                     pipeline.append(SkRasterPipeline::load_tables_u16_be, &loadTables);
    1202           0 :                     break;
    1203             :             }
    1204           0 :             break;
    1205             :         case kRGB_U16_BE_ColorFormat:
    1206           0 :             switch (fSrcGamma) {
    1207             :                 case kLinear_SrcGamma:
    1208           0 :                     pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
    1209           0 :                     break;
    1210             :                 case kSRGB_SrcGamma:
    1211           0 :                     pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
    1212           0 :                     pipeline.append_from_srgb(kUnpremul_SkAlphaType);
    1213           0 :                     break;
    1214             :                 case kTable_SrcGamma:
    1215           0 :                     loadTables.fSrc = src;
    1216           0 :                     loadTables.fR = fSrcGammaTables[0];
    1217           0 :                     loadTables.fG = fSrcGammaTables[1];
    1218           0 :                     loadTables.fB = fSrcGammaTables[2];
    1219           0 :                     pipeline.append(SkRasterPipeline::load_tables_rgb_u16_be, &loadTables);
    1220           0 :                     break;
    1221             :             }
    1222           0 :             break;
    1223             :         default:
    1224           0 :             return false;
    1225             :     }
    1226             : 
    1227             :     if (kNone_ColorSpaceMatch == kCSM) {
    1228           0 :         pipeline.append(SkRasterPipeline::matrix_3x4, fSrcToDst);
    1229             : 
    1230           0 :         if (kRGBA_F16_ColorFormat != dstColorFormat &&
    1231             :             kRGBA_F32_ColorFormat != dstColorFormat)
    1232             :         {
    1233             :             bool need_clamp_0, need_clamp_1;
    1234           0 :             analyze_3x4_matrix(fSrcToDst, &need_clamp_0, &need_clamp_1);
    1235             : 
    1236           0 :             if (need_clamp_0) { pipeline.append(SkRasterPipeline::clamp_0); }
    1237           0 :             if (need_clamp_1) { pipeline.append(SkRasterPipeline::clamp_1); }
    1238             :         }
    1239             :     }
    1240             : 
    1241           0 :     if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kRespect == fPremulBehavior)
    1242             :     {
    1243           0 :         pipeline.append(SkRasterPipeline::premul);
    1244             :     }
    1245             : 
    1246             :     TablesContext tables;
    1247           0 :     switch (fDstGamma) {
    1248             :         case kSRGB_DstGamma:
    1249           0 :             pipeline.append(SkRasterPipeline::to_srgb);
    1250           0 :             break;
    1251             :         case k2Dot2_DstGamma:
    1252           0 :             pipeline.append(SkRasterPipeline::to_2dot2);
    1253           0 :             break;
    1254             :         case kTable_DstGamma:
    1255           0 :             tables.fR = fDstGammaTables[0];
    1256           0 :             tables.fG = fDstGammaTables[1];
    1257           0 :             tables.fB = fDstGammaTables[2];
    1258           0 :             tables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize;
    1259           0 :             pipeline.append(SkRasterPipeline::byte_tables_rgb, &tables);
    1260             :         default:
    1261           0 :             break;
    1262             :     }
    1263             : 
    1264           0 :     if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kIgnore == fPremulBehavior)
    1265             :     {
    1266           0 :         pipeline.append(SkRasterPipeline::premul);
    1267             :     }
    1268             : 
    1269           0 :     switch (dstColorFormat) {
    1270             :         case kRGBA_8888_ColorFormat:
    1271           0 :              pipeline.append(SkRasterPipeline::store_8888, &dst);
    1272           0 :             break;
    1273             :         case kBGRA_8888_ColorFormat:
    1274           0 :             pipeline.append(SkRasterPipeline::swap_rb);
    1275           0 :             pipeline.append(SkRasterPipeline::store_8888, &dst);
    1276           0 :             break;
    1277             :         case kRGBA_F16_ColorFormat:
    1278           0 :             if (kLinear_DstGamma != fDstGamma) {
    1279           0 :                 return false;
    1280             :             }
    1281           0 :             pipeline.append(SkRasterPipeline::store_f16, &dst);
    1282           0 :             break;
    1283             :         case kRGBA_F32_ColorFormat:
    1284           0 :             if (kLinear_DstGamma != fDstGamma) {
    1285           0 :                 return false;
    1286             :             }
    1287           0 :             pipeline.append(SkRasterPipeline::store_f32, &dst);
    1288           0 :             break;
    1289             :         case kBGR_565_ColorFormat:
    1290           0 :             if (kOpaque_SkAlphaType != alphaType) {
    1291           0 :                 return false;
    1292             :             }
    1293           0 :             pipeline.append(SkRasterPipeline::store_565, &dst);
    1294           0 :             break;
    1295             :         default:
    1296           0 :             return false;
    1297             :     }
    1298             : 
    1299           0 :     pipeline.run(0, len);
    1300           0 :     return true;
    1301             : }
    1302             : 
    1303             : ///////////////////////////////////////////////////////////////////////////////////////////////////
    1304             : 
    1305           0 : std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) {
    1306             :     return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ<kNone_ColorSpaceMatch>
    1307           0 :             (space, SkMatrix::I(), space, SkTransferFunctionBehavior::kRespect));
    1308             : }

Generated by: LCOV version 1.13