SkColorSpaceXform_A2B.cpp revision c7be00366bb0171e2d247ea71e291a64e3d10254
12563601fc2b0505619f905f86bd249ae630197ccraftias/*
22563601fc2b0505619f905f86bd249ae630197ccraftias * Copyright 2016 Google Inc.
32563601fc2b0505619f905f86bd249ae630197ccraftias *
42563601fc2b0505619f905f86bd249ae630197ccraftias * Use of this source code is governed by a BSD-style license that can be
52563601fc2b0505619f905f86bd249ae630197ccraftias * found in the LICENSE file.
62563601fc2b0505619f905f86bd249ae630197ccraftias */
72563601fc2b0505619f905f86bd249ae630197ccraftias
82563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXform_A2B.h"
92563601fc2b0505619f905f86bd249ae630197ccraftias
102563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorPriv.h"
112563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpace_A2B.h"
122563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpace_XYZ.h"
132563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpacePriv.h"
142563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXformPriv.h"
152563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkMakeUnique.h"
162563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkNx.h"
172563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkSRGB.h"
182563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkTypes.h"
19c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein#include "../jumper/SkJumper.h"
202563601fc2b0505619f905f86bd249ae630197ccraftias
212563601fc2b0505619f905f86bd249ae630197ccraftiasbool SkColorSpaceXform_A2B::onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat,
222563601fc2b0505619f905f86bd249ae630197ccraftias                                    const void* src, int count, SkAlphaType alphaType) const {
232563601fc2b0505619f905f86bd249ae630197ccraftias    SkRasterPipeline pipeline;
242563601fc2b0505619f905f86bd249ae630197ccraftias    switch (srcFormat) {
252563601fc2b0505619f905f86bd249ae630197ccraftias        case kBGRA_8888_ColorFormat:
26729b58296282da00fb9c0f92db2e2e8a8347d431Mike Klein            pipeline.append(SkRasterPipeline::load_8888, &src);
272563601fc2b0505619f905f86bd249ae630197ccraftias            pipeline.append(SkRasterPipeline::swap_rb);
282563601fc2b0505619f905f86bd249ae630197ccraftias            break;
292563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_8888_ColorFormat:
30729b58296282da00fb9c0f92db2e2e8a8347d431Mike Klein            pipeline.append(SkRasterPipeline::load_8888, &src);
312563601fc2b0505619f905f86bd249ae630197ccraftias            break;
32379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        case kRGBA_U16_BE_ColorFormat:
33379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            pipeline.append(SkRasterPipeline::load_u16_be, &src);
34379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            break;
355bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett        case kRGB_U16_BE_ColorFormat:
365bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett            pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
375bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett            break;
382563601fc2b0505619f905f86bd249ae630197ccraftias        default:
394c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett            SkCSXformPrintf("F16/F32 sources must be linear.\n");
402563601fc2b0505619f905f86bd249ae630197ccraftias            return false;
412563601fc2b0505619f905f86bd249ae630197ccraftias    }
422563601fc2b0505619f905f86bd249ae630197ccraftias
432563601fc2b0505619f905f86bd249ae630197ccraftias    pipeline.extend(fElementsPipeline);
442563601fc2b0505619f905f86bd249ae630197ccraftias
452563601fc2b0505619f905f86bd249ae630197ccraftias    if (kPremul_SkAlphaType == alphaType) {
462563601fc2b0505619f905f86bd249ae630197ccraftias        pipeline.append(SkRasterPipeline::premul);
472563601fc2b0505619f905f86bd249ae630197ccraftias    }
482563601fc2b0505619f905f86bd249ae630197ccraftias
492563601fc2b0505619f905f86bd249ae630197ccraftias    switch (dstFormat) {
502563601fc2b0505619f905f86bd249ae630197ccraftias        case kBGRA_8888_ColorFormat:
512563601fc2b0505619f905f86bd249ae630197ccraftias            pipeline.append(SkRasterPipeline::swap_rb);
522563601fc2b0505619f905f86bd249ae630197ccraftias            pipeline.append(SkRasterPipeline::store_8888, &dst);
532563601fc2b0505619f905f86bd249ae630197ccraftias            break;
542563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_8888_ColorFormat:
552563601fc2b0505619f905f86bd249ae630197ccraftias            pipeline.append(SkRasterPipeline::store_8888, &dst);
562563601fc2b0505619f905f86bd249ae630197ccraftias            break;
572563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_F16_ColorFormat:
582563601fc2b0505619f905f86bd249ae630197ccraftias            if (!fLinearDstGamma) {
592563601fc2b0505619f905f86bd249ae630197ccraftias                return false;
602563601fc2b0505619f905f86bd249ae630197ccraftias            }
612563601fc2b0505619f905f86bd249ae630197ccraftias            pipeline.append(SkRasterPipeline::store_f16, &dst);
622563601fc2b0505619f905f86bd249ae630197ccraftias            break;
632563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_F32_ColorFormat:
642563601fc2b0505619f905f86bd249ae630197ccraftias            if (!fLinearDstGamma) {
652563601fc2b0505619f905f86bd249ae630197ccraftias                return false;
662563601fc2b0505619f905f86bd249ae630197ccraftias            }
672563601fc2b0505619f905f86bd249ae630197ccraftias            pipeline.append(SkRasterPipeline::store_f32, &dst);
682563601fc2b0505619f905f86bd249ae630197ccraftias            break;
693725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett        case kBGR_565_ColorFormat:
703725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett            if (kOpaque_SkAlphaType != alphaType) {
713725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett                return false;
723725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett            }
733725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett            pipeline.append(SkRasterPipeline::store_565, &dst);
743725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett            break;
75379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        default:
76379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            return false;
772563601fc2b0505619f905f86bd249ae630197ccraftias    }
78319ba3d3a177498095c31696e0aec8b3af25f663Mike Klein    pipeline.run(0,count);
792563601fc2b0505619f905f86bd249ae630197ccraftias
802563601fc2b0505619f905f86bd249ae630197ccraftias    return true;
812563601fc2b0505619f905f86bd249ae630197ccraftias}
822563601fc2b0505619f905f86bd249ae630197ccraftias
83113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistrystatic inline bool gamma_to_parametric(SkColorSpaceTransferFn* coeffs, const SkGammas& gammas,
84113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                                       int channel) {
852563601fc2b0505619f905f86bd249ae630197ccraftias    switch (gammas.type(channel)) {
862563601fc2b0505619f905f86bd249ae630197ccraftias        case SkGammas::Type::kNamed_Type:
87113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return named_to_parametric(coeffs, gammas.data(channel).fNamed);
882563601fc2b0505619f905f86bd249ae630197ccraftias        case SkGammas::Type::kValue_Type:
89113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            value_to_parametric(coeffs, gammas.data(channel).fValue);
90113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return true;
912563601fc2b0505619f905f86bd249ae630197ccraftias        case SkGammas::Type::kParam_Type:
92113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            *coeffs = gammas.params(channel);
93113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return true;
942563601fc2b0505619f905f86bd249ae630197ccraftias        default:
95113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return false;
962563601fc2b0505619f905f86bd249ae630197ccraftias    }
972563601fc2b0505619f905f86bd249ae630197ccraftias}
982563601fc2b0505619f905f86bd249ae630197ccraftias
992563601fc2b0505619f905f86bd249ae630197ccraftiasSkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
1002563601fc2b0505619f905f86bd249ae630197ccraftias                                             SkColorSpace_XYZ* dstSpace)
1012563601fc2b0505619f905f86bd249ae630197ccraftias    : fLinearDstGamma(kLinear_SkGammaNamed == dstSpace->gammaNamed()) {
1022563601fc2b0505619f905f86bd249ae630197ccraftias#if (SkCSXformPrintfDefined)
1032563601fc2b0505619f905f86bd249ae630197ccraftias    static const char* debugGammaNamed[4] = {
1042563601fc2b0505619f905f86bd249ae630197ccraftias        "Linear", "SRGB", "2.2", "NonStandard"
1052563601fc2b0505619f905f86bd249ae630197ccraftias    };
1062563601fc2b0505619f905f86bd249ae630197ccraftias    static const char* debugGammas[5] = {
1072563601fc2b0505619f905f86bd249ae630197ccraftias        "None", "Named", "Value", "Table", "Param"
1082563601fc2b0505619f905f86bd249ae630197ccraftias    };
1092563601fc2b0505619f905f86bd249ae630197ccraftias#endif
110523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    int currentChannels;
111523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    switch (srcSpace->iccType()) {
112523116d9fee8b79af09563b55b19cbd267353300Matt Sarett        case SkColorSpace_Base::kRGB_ICCTypeFlag:
1135476128f0a88217414f05e6a7ee518cdb411d026raftias            currentChannels = 3;
1145476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
115c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein        case SkColorSpace_Base::kCMYK_ICCTypeFlag: {
1165476128f0a88217414f05e6a7ee518cdb411d026raftias            currentChannels = 4;
1175476128f0a88217414f05e6a7ee518cdb411d026raftias            // CMYK images from JPEGs (the only format that supports it) are actually
1185476128f0a88217414f05e6a7ee518cdb411d026raftias            // inverted CMYK, so we need to invert every channel.
1195476128f0a88217414f05e6a7ee518cdb411d026raftias            // TransferFn is y = -x + 1 for x < 1.f, otherwise 0x + 0, ie y = 1 - x for x in [0,1]
120c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            SkColorSpaceTransferFn fn = {0,0,0,0,0,0,0};
121c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fG =  1;
122c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fA =  0;
123c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fB =  0;
124c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fC = -1;
125c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fD =  1;
126c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fE =  0;
127c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fF =  1;
128c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            this->addTransferFns(fn,4);
1295476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
130c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein        }
1315476128f0a88217414f05e6a7ee518cdb411d026raftias        default:
132523116d9fee8b79af09563b55b19cbd267353300Matt Sarett            currentChannels = 0;
1335476128f0a88217414f05e6a7ee518cdb411d026raftias            SkASSERT(false);
1345476128f0a88217414f05e6a7ee518cdb411d026raftias    }
1352563601fc2b0505619f905f86bd249ae630197ccraftias    // add in all input color space -> PCS xforms
1362563601fc2b0505619f905f86bd249ae630197ccraftias    for (int i = 0; i < srcSpace->count(); ++i) {
1372563601fc2b0505619f905f86bd249ae630197ccraftias        const SkColorSpace_A2B::Element& e = srcSpace->element(i);
1385476128f0a88217414f05e6a7ee518cdb411d026raftias        SkASSERT(e.inputChannels() == currentChannels);
1395476128f0a88217414f05e6a7ee518cdb411d026raftias        currentChannels = e.outputChannels();
1402563601fc2b0505619f905f86bd249ae630197ccraftias        switch (e.type()) {
1412563601fc2b0505619f905f86bd249ae630197ccraftias            case SkColorSpace_A2B::Element::Type::kGammaNamed:
142113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                if (kLinear_SkGammaNamed == e.gammaNamed()) {
143113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                    break;
144113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                }
145113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
146c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                // Take the fast path for ordinary sRGB.
147c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                if (3 == currentChannels && kSRGB_SkGammaNamed == e.gammaNamed()) {
148c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                    SkCSXformPrintf("fast path from sRGB\n");
149c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                    // Images should always start the pipeline as unpremul
150c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                    fElementsPipeline.append_from_srgb(kUnpremul_SkAlphaType);
151c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                    break;
152975245407a16dba58ee42cb12f70f8db87f02da0raftias                }
153113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
154113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]);
155113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                SkColorSpaceTransferFn fn;
156113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                SkAssertResult(named_to_parametric(&fn, e.gammaNamed()));
157113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                this->addTransferFns(fn, currentChannels);
1582563601fc2b0505619f905f86bd249ae630197ccraftias                break;
1592563601fc2b0505619f905f86bd249ae630197ccraftias            case SkColorSpace_A2B::Element::Type::kGammas: {
160db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                const SkGammas& gammas = e.gammas();
161db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                SkCSXformPrintf("Gamma stage added:");
1625476128f0a88217414f05e6a7ee518cdb411d026raftias                for (int channel = 0; channel < gammas.channels(); ++channel) {
163db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                    SkCSXformPrintf("  %s", debugGammas[(int)gammas.type(channel)]);
164db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                }
165db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                SkCSXformPrintf("\n");
166db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                bool gammaNeedsRef = false;
1675476128f0a88217414f05e6a7ee518cdb411d026raftias                for (int channel = 0; channel < gammas.channels(); ++channel) {
168db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                    if (SkGammas::Type::kTable_Type == gammas.type(channel)) {
169db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                        SkTableTransferFn table = {
170db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                                gammas.table(channel),
171db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                                gammas.data(channel).fTable.fSize,
172db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                        };
173db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett
1745476128f0a88217414f05e6a7ee518cdb411d026raftias                        this->addTableFn(table, channel);
175db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                        gammaNeedsRef = true;
176db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                    } else {
177113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                        SkColorSpaceTransferFn fn;
178113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                        SkAssertResult(gamma_to_parametric(&fn, gammas, channel));
1795476128f0a88217414f05e6a7ee518cdb411d026raftias                        this->addTransferFn(fn, channel);
1802563601fc2b0505619f905f86bd249ae630197ccraftias                    }
1812563601fc2b0505619f905f86bd249ae630197ccraftias                }
182db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                if (gammaNeedsRef) {
183de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    this->copy(sk_ref_sp(&gammas));
184db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                }
1852563601fc2b0505619f905f86bd249ae630197ccraftias                break;
186db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            }
187de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            case SkColorSpace_A2B::Element::Type::kCLUT: {
1885476128f0a88217414f05e6a7ee518cdb411d026raftias                SkCSXformPrintf("CLUT (%d -> %d) stage added\n", e.colorLUT().inputChannels(),
1895476128f0a88217414f05e6a7ee518cdb411d026raftias                                                                 e.colorLUT().outputChannels());
190c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                struct CallbackCtx : SkJumper_CallbackCtx {
191c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    sk_sp<const SkColorLookUpTable> clut;
192c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    // clut->interp() can't always safely alias its arguments,
193c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    // so we allocate a second buffer to hold our results.
194c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    float results[4*SkJumper_kMaxStride];
195c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                };
196c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                auto cb = fAlloc.make<CallbackCtx>();
197c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                cb->clut      = sk_ref_sp(&e.colorLUT());
198c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                cb->read_from = cb->results;
199c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                cb->fn        = [](SkJumper_CallbackCtx* ctx, int active_pixels) {
200c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    auto c = (CallbackCtx*)ctx;
201c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    for (int i = 0; i < active_pixels; i++) {
202c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                        // Look up red, green, and blue for this pixel using 3-4 values from rgba.
203c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                        c->clut->interp(c->results+4*i, c->rgba+4*i);
204c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein
205c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                        // If we used 3 inputs (rgb) preserve the fourth as alpha.
206c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                        // If we used 4 inputs (cmyk) force alpha to 1.
207c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                        c->results[4*i+3] = (3 == c->clut->inputChannels()) ? c->rgba[4*i+3] : 1.0f;
208c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    }
209c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                };
210c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                fElementsPipeline.append(SkRasterPipeline::callback, cb);
2112563601fc2b0505619f905f86bd249ae630197ccraftias                break;
212de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            }
2132563601fc2b0505619f905f86bd249ae630197ccraftias            case SkColorSpace_A2B::Element::Type::kMatrix:
2142563601fc2b0505619f905f86bd249ae630197ccraftias                if (!e.matrix().isIdentity()) {
2152563601fc2b0505619f905f86bd249ae630197ccraftias                    SkCSXformPrintf("Matrix stage added\n");
2162563601fc2b0505619f905f86bd249ae630197ccraftias                    addMatrix(e.matrix());
2172563601fc2b0505619f905f86bd249ae630197ccraftias                }
2182563601fc2b0505619f905f86bd249ae630197ccraftias                break;
2192563601fc2b0505619f905f86bd249ae630197ccraftias        }
2202563601fc2b0505619f905f86bd249ae630197ccraftias    }
2212563601fc2b0505619f905f86bd249ae630197ccraftias
2222563601fc2b0505619f905f86bd249ae630197ccraftias    // Lab PCS -> XYZ PCS
2232563601fc2b0505619f905f86bd249ae630197ccraftias    if (SkColorSpace_A2B::PCS::kLAB == srcSpace->pcs()) {
2242563601fc2b0505619f905f86bd249ae630197ccraftias        SkCSXformPrintf("Lab -> XYZ element added\n");
2252563601fc2b0505619f905f86bd249ae630197ccraftias        fElementsPipeline.append(SkRasterPipeline::lab_to_xyz);
2262563601fc2b0505619f905f86bd249ae630197ccraftias    }
2272563601fc2b0505619f905f86bd249ae630197ccraftias
22891db12d89c214235e24599f3ec18df2f952e99ebraftias    // we should now be in XYZ PCS
22991db12d89c214235e24599f3ec18df2f952e99ebraftias    SkASSERT(3 == currentChannels);
23091db12d89c214235e24599f3ec18df2f952e99ebraftias
2312563601fc2b0505619f905f86bd249ae630197ccraftias    // and XYZ PCS -> output color space xforms
2322563601fc2b0505619f905f86bd249ae630197ccraftias    if (!dstSpace->fromXYZD50()->isIdentity()) {
2332563601fc2b0505619f905f86bd249ae630197ccraftias        addMatrix(*dstSpace->fromXYZD50());
2342563601fc2b0505619f905f86bd249ae630197ccraftias    }
2352563601fc2b0505619f905f86bd249ae630197ccraftias
236975245407a16dba58ee42cb12f70f8db87f02da0raftias    switch (dstSpace->gammaNamed()) {
237975245407a16dba58ee42cb12f70f8db87f02da0raftias        case kLinear_SkGammaNamed:
238975245407a16dba58ee42cb12f70f8db87f02da0raftias            // do nothing
239975245407a16dba58ee42cb12f70f8db87f02da0raftias            break;
240c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein        case k2Dot2Curve_SkGammaNamed: {
241c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            SkColorSpaceTransferFn fn = {0,0,0,0,0,0,0};
242c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fG = 1/2.2f;
243c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fn.fA = 1;
244c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            auto to_2dot2 = this->copy(fn);
245c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_r, to_2dot2);
246c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_g, to_2dot2);
247c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_b, to_2dot2);
248975245407a16dba58ee42cb12f70f8db87f02da0raftias            break;
249c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein        }
250975245407a16dba58ee42cb12f70f8db87f02da0raftias        case kSRGB_SkGammaNamed:
251975245407a16dba58ee42cb12f70f8db87f02da0raftias            fElementsPipeline.append(SkRasterPipeline::to_srgb);
252975245407a16dba58ee42cb12f70f8db87f02da0raftias            break;
253975245407a16dba58ee42cb12f70f8db87f02da0raftias        case kNonStandard_SkGammaNamed: {
254975245407a16dba58ee42cb12f70f8db87f02da0raftias            for (int channel = 0; channel < 3; ++channel) {
255975245407a16dba58ee42cb12f70f8db87f02da0raftias                const SkGammas& gammas = *dstSpace->gammas();
256975245407a16dba58ee42cb12f70f8db87f02da0raftias                if (SkGammas::Type::kTable_Type == gammas.type(channel)) {
257975245407a16dba58ee42cb12f70f8db87f02da0raftias                    static constexpr int kInvTableSize = 256;
258de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    auto storage = fAlloc.makeArray<float>(kInvTableSize);
259de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    invert_table_gamma(storage, nullptr, kInvTableSize,
260975245407a16dba58ee42cb12f70f8db87f02da0raftias                                       gammas.table(channel),
261975245407a16dba58ee42cb12f70f8db87f02da0raftias                                       gammas.data(channel).fTable.fSize);
262de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    SkTableTransferFn table = { storage, kInvTableSize };
263975245407a16dba58ee42cb12f70f8db87f02da0raftias                    this->addTableFn(table, channel);
264975245407a16dba58ee42cb12f70f8db87f02da0raftias                } else {
265113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                    SkColorSpaceTransferFn fn;
266113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                    SkAssertResult(gamma_to_parametric(&fn, gammas, channel));
26773e627074839bc00569117235eb4e7d4fc3cc39fBrian Osman                    this->addTransferFn(fn.invert(), channel);
268975245407a16dba58ee42cb12f70f8db87f02da0raftias                }
2692563601fc2b0505619f905f86bd249ae630197ccraftias            }
2702563601fc2b0505619f905f86bd249ae630197ccraftias        }
271975245407a16dba58ee42cb12f70f8db87f02da0raftias        break;
272db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett    }
273db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett}
274db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett
2755476128f0a88217414f05e6a7ee518cdb411d026raftiasvoid SkColorSpaceXform_A2B::addTransferFns(const SkColorSpaceTransferFn& fn, int channelCount) {
2765476128f0a88217414f05e6a7ee518cdb411d026raftias    for (int i = 0; i < channelCount; ++i) {
2775476128f0a88217414f05e6a7ee518cdb411d026raftias        this->addTransferFn(fn, i);
2785476128f0a88217414f05e6a7ee518cdb411d026raftias    }
2795476128f0a88217414f05e6a7ee518cdb411d026raftias}
2805476128f0a88217414f05e6a7ee518cdb411d026raftias
2815476128f0a88217414f05e6a7ee518cdb411d026raftiasvoid SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, int channelIndex) {
2825476128f0a88217414f05e6a7ee518cdb411d026raftias    switch (channelIndex) {
2835476128f0a88217414f05e6a7ee518cdb411d026raftias        case 0:
284de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_r, this->copy(fn));
285db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            break;
2865476128f0a88217414f05e6a7ee518cdb411d026raftias        case 1:
287de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_g, this->copy(fn));
288db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            break;
2895476128f0a88217414f05e6a7ee518cdb411d026raftias        case 2:
290de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_b, this->copy(fn));
291db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            break;
2925476128f0a88217414f05e6a7ee518cdb411d026raftias        case 3:
293de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_a, this->copy(fn));
2945476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
295db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett        default:
296db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            SkASSERT(false);
2972563601fc2b0505619f905f86bd249ae630197ccraftias    }
2982563601fc2b0505619f905f86bd249ae630197ccraftias}
2992563601fc2b0505619f905f86bd249ae630197ccraftias
3005476128f0a88217414f05e6a7ee518cdb411d026raftiasvoid SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, int channelIndex) {
3015476128f0a88217414f05e6a7ee518cdb411d026raftias    switch (channelIndex) {
3025476128f0a88217414f05e6a7ee518cdb411d026raftias        case 0:
303de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_r, this->copy(fn));
3042563601fc2b0505619f905f86bd249ae630197ccraftias            break;
3055476128f0a88217414f05e6a7ee518cdb411d026raftias        case 1:
306de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_g, this->copy(fn));
3072563601fc2b0505619f905f86bd249ae630197ccraftias            break;
3085476128f0a88217414f05e6a7ee518cdb411d026raftias        case 2:
309de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_b, this->copy(fn));
3102563601fc2b0505619f905f86bd249ae630197ccraftias            break;
3115476128f0a88217414f05e6a7ee518cdb411d026raftias        case 3:
312de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_a, this->copy(fn));
3135476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
3142563601fc2b0505619f905f86bd249ae630197ccraftias        default:
3152563601fc2b0505619f905f86bd249ae630197ccraftias            SkASSERT(false);
3162563601fc2b0505619f905f86bd249ae630197ccraftias    }
3172563601fc2b0505619f905f86bd249ae630197ccraftias}
3182563601fc2b0505619f905f86bd249ae630197ccraftias
319de1cad99b353bad080a04ccfde955a8f3c0af295Mike Kleinvoid SkColorSpaceXform_A2B::addMatrix(const SkMatrix44& m44) {
320de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    auto m = fAlloc.makeArray<float>(12);
321de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[0] = m44.get(0,0); m[ 1] = m44.get(1,0); m[ 2] = m44.get(2,0);
322de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[3] = m44.get(0,1); m[ 4] = m44.get(1,1); m[ 5] = m44.get(2,1);
323de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[6] = m44.get(0,2); m[ 7] = m44.get(1,2); m[ 8] = m44.get(2,2);
324de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[9] = m44.get(0,3); m[10] = m44.get(1,3); m[11] = m44.get(2,3);
325de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein
326de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,0) == 0.0f);
327de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,1) == 0.0f);
328de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,2) == 0.0f);
329de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,3) == 1.0f);
330de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein
331de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    fElementsPipeline.append(SkRasterPipeline::matrix_3x4, m);
3322563601fc2b0505619f905f86bd249ae630197ccraftias    fElementsPipeline.append(SkRasterPipeline::clamp_0);
333db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett    fElementsPipeline.append(SkRasterPipeline::clamp_1);
3342563601fc2b0505619f905f86bd249ae630197ccraftias}
335