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
10a4083c97d48e8a4f88e2797d7363f141e3d42553Cary Clark#include "SkColorData.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 {
23b24704d35f67f5b460be9c92794892e06adceb46Mike Klein    SkRasterPipeline_<256> pipeline;
2445c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein
2545c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein    SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
2645c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein                       dst_ctx = { (void*)dst, 0 };
2745c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein
282563601fc2b0505619f905f86bd249ae630197ccraftias    switch (srcFormat) {
292563601fc2b0505619f905f86bd249ae630197ccraftias        case kBGRA_8888_ColorFormat:
3045c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::load_bgra, &src_ctx);
312563601fc2b0505619f905f86bd249ae630197ccraftias            break;
322563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_8888_ColorFormat:
3345c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::load_8888, &src_ctx);
342563601fc2b0505619f905f86bd249ae630197ccraftias            break;
35379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        case kRGBA_U16_BE_ColorFormat:
3645c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::load_u16_be, &src_ctx);
37379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            break;
385bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett        case kRGB_U16_BE_ColorFormat:
3945c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src_ctx);
405bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett            break;
412563601fc2b0505619f905f86bd249ae630197ccraftias        default:
424c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett            SkCSXformPrintf("F16/F32 sources must be linear.\n");
432563601fc2b0505619f905f86bd249ae630197ccraftias            return false;
442563601fc2b0505619f905f86bd249ae630197ccraftias    }
452563601fc2b0505619f905f86bd249ae630197ccraftias
462563601fc2b0505619f905f86bd249ae630197ccraftias    pipeline.extend(fElementsPipeline);
472563601fc2b0505619f905f86bd249ae630197ccraftias
482563601fc2b0505619f905f86bd249ae630197ccraftias    if (kPremul_SkAlphaType == alphaType) {
492563601fc2b0505619f905f86bd249ae630197ccraftias        pipeline.append(SkRasterPipeline::premul);
502563601fc2b0505619f905f86bd249ae630197ccraftias    }
512563601fc2b0505619f905f86bd249ae630197ccraftias
522563601fc2b0505619f905f86bd249ae630197ccraftias    switch (dstFormat) {
532563601fc2b0505619f905f86bd249ae630197ccraftias        case kBGRA_8888_ColorFormat:
5445c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::store_bgra, &dst_ctx);
552563601fc2b0505619f905f86bd249ae630197ccraftias            break;
562563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_8888_ColorFormat:
5745c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::store_8888, &dst_ctx);
582563601fc2b0505619f905f86bd249ae630197ccraftias            break;
592563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_F16_ColorFormat:
602563601fc2b0505619f905f86bd249ae630197ccraftias            if (!fLinearDstGamma) {
612563601fc2b0505619f905f86bd249ae630197ccraftias                return false;
622563601fc2b0505619f905f86bd249ae630197ccraftias            }
6345c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::store_f16, &dst_ctx);
642563601fc2b0505619f905f86bd249ae630197ccraftias            break;
652563601fc2b0505619f905f86bd249ae630197ccraftias        case kRGBA_F32_ColorFormat:
662563601fc2b0505619f905f86bd249ae630197ccraftias            if (!fLinearDstGamma) {
672563601fc2b0505619f905f86bd249ae630197ccraftias                return false;
682563601fc2b0505619f905f86bd249ae630197ccraftias            }
6945c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::store_f32, &dst_ctx);
702563601fc2b0505619f905f86bd249ae630197ccraftias            break;
713725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett        case kBGR_565_ColorFormat:
723725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett            if (kOpaque_SkAlphaType != alphaType) {
733725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett                return false;
743725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett            }
7545c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein            pipeline.append(SkRasterPipeline::store_565, &dst_ctx);
763725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett            break;
77379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        default:
78379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            return false;
792563601fc2b0505619f905f86bd249ae630197ccraftias    }
8045c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein    pipeline.run(0,0, count,1);
812563601fc2b0505619f905f86bd249ae630197ccraftias
822563601fc2b0505619f905f86bd249ae630197ccraftias    return true;
832563601fc2b0505619f905f86bd249ae630197ccraftias}
842563601fc2b0505619f905f86bd249ae630197ccraftias
85113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistrystatic inline bool gamma_to_parametric(SkColorSpaceTransferFn* coeffs, const SkGammas& gammas,
86113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                                       int channel) {
872563601fc2b0505619f905f86bd249ae630197ccraftias    switch (gammas.type(channel)) {
882563601fc2b0505619f905f86bd249ae630197ccraftias        case SkGammas::Type::kNamed_Type:
89113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return named_to_parametric(coeffs, gammas.data(channel).fNamed);
902563601fc2b0505619f905f86bd249ae630197ccraftias        case SkGammas::Type::kValue_Type:
91113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            value_to_parametric(coeffs, gammas.data(channel).fValue);
92113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return true;
932563601fc2b0505619f905f86bd249ae630197ccraftias        case SkGammas::Type::kParam_Type:
94113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            *coeffs = gammas.params(channel);
95113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return true;
962563601fc2b0505619f905f86bd249ae630197ccraftias        default:
97113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry            return false;
982563601fc2b0505619f905f86bd249ae630197ccraftias    }
992563601fc2b0505619f905f86bd249ae630197ccraftias}
1002563601fc2b0505619f905f86bd249ae630197ccraftias
1012563601fc2b0505619f905f86bd249ae630197ccraftiasSkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
1022563601fc2b0505619f905f86bd249ae630197ccraftias                                             SkColorSpace_XYZ* dstSpace)
103b24704d35f67f5b460be9c92794892e06adceb46Mike Klein    : fElementsPipeline(&fAlloc)
104b24704d35f67f5b460be9c92794892e06adceb46Mike Klein    , fLinearDstGamma(kLinear_SkGammaNamed == dstSpace->gammaNamed()) {
1052563601fc2b0505619f905f86bd249ae630197ccraftias#if (SkCSXformPrintfDefined)
1062563601fc2b0505619f905f86bd249ae630197ccraftias    static const char* debugGammaNamed[4] = {
1072563601fc2b0505619f905f86bd249ae630197ccraftias        "Linear", "SRGB", "2.2", "NonStandard"
1082563601fc2b0505619f905f86bd249ae630197ccraftias    };
1092563601fc2b0505619f905f86bd249ae630197ccraftias    static const char* debugGammas[5] = {
1102563601fc2b0505619f905f86bd249ae630197ccraftias        "None", "Named", "Value", "Table", "Param"
1112563601fc2b0505619f905f86bd249ae630197ccraftias    };
1122563601fc2b0505619f905f86bd249ae630197ccraftias#endif
113523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    int currentChannels;
114523116d9fee8b79af09563b55b19cbd267353300Matt Sarett    switch (srcSpace->iccType()) {
115f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III        case SkColorSpace::kRGB_Type:
1165476128f0a88217414f05e6a7ee518cdb411d026raftias            currentChannels = 3;
1175476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
118f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III        case SkColorSpace::kCMYK_Type: {
1195476128f0a88217414f05e6a7ee518cdb411d026raftias            currentChannels = 4;
1205476128f0a88217414f05e6a7ee518cdb411d026raftias            // CMYK images from JPEGs (the only format that supports it) are actually
1215476128f0a88217414f05e6a7ee518cdb411d026raftias            // inverted CMYK, so we need to invert every channel.
12250d0d053576a4895bdd4c837bf990b499da209cbMike Klein            fElementsPipeline.append(SkRasterPipeline::invert);
1235476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
124c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein        }
1255476128f0a88217414f05e6a7ee518cdb411d026raftias        default:
126523116d9fee8b79af09563b55b19cbd267353300Matt Sarett            currentChannels = 0;
1275476128f0a88217414f05e6a7ee518cdb411d026raftias            SkASSERT(false);
1285476128f0a88217414f05e6a7ee518cdb411d026raftias    }
1292563601fc2b0505619f905f86bd249ae630197ccraftias    // add in all input color space -> PCS xforms
1302563601fc2b0505619f905f86bd249ae630197ccraftias    for (int i = 0; i < srcSpace->count(); ++i) {
1312563601fc2b0505619f905f86bd249ae630197ccraftias        const SkColorSpace_A2B::Element& e = srcSpace->element(i);
1325476128f0a88217414f05e6a7ee518cdb411d026raftias        SkASSERT(e.inputChannels() == currentChannels);
1335476128f0a88217414f05e6a7ee518cdb411d026raftias        currentChannels = e.outputChannels();
1342563601fc2b0505619f905f86bd249ae630197ccraftias        switch (e.type()) {
13550d0d053576a4895bdd4c837bf990b499da209cbMike Klein            case SkColorSpace_A2B::Element::Type::kGammaNamed: {
136113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                if (kLinear_SkGammaNamed == e.gammaNamed()) {
137113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                    break;
138113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                }
139113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
140c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                // Take the fast path for ordinary sRGB.
141c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                if (3 == currentChannels && kSRGB_SkGammaNamed == e.gammaNamed()) {
142c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                    SkCSXformPrintf("fast path from sRGB\n");
143f1f1162273b382db99f8609e5bbfff24f5594821Mike Klein                    fElementsPipeline.append(SkRasterPipeline::from_srgb);
144c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein                    break;
145975245407a16dba58ee42cb12f70f8db87f02da0raftias                }
146113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry
147113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]);
14850d0d053576a4895bdd4c837bf990b499da209cbMike Klein                auto fn = fAlloc.make<SkColorSpaceTransferFn>();
14950d0d053576a4895bdd4c837bf990b499da209cbMike Klein                SkAssertResult(named_to_parametric(fn, e.gammaNamed()));
15050d0d053576a4895bdd4c837bf990b499da209cbMike Klein
151a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein                if (is_just_gamma(*fn)) {
152a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein                    fElementsPipeline.append(SkRasterPipeline::gamma, &fn->fG);
153a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein                } else {
154a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein                    fElementsPipeline.append(SkRasterPipeline::parametric_r, fn);
155a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein                    fElementsPipeline.append(SkRasterPipeline::parametric_g, fn);
156a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein                    fElementsPipeline.append(SkRasterPipeline::parametric_b, fn);
157a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein                }
1582563601fc2b0505619f905f86bd249ae630197ccraftias                break;
15950d0d053576a4895bdd4c837bf990b499da209cbMike Klein            }
1602563601fc2b0505619f905f86bd249ae630197ccraftias            case SkColorSpace_A2B::Element::Type::kGammas: {
161db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                const SkGammas& gammas = e.gammas();
162db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                SkCSXformPrintf("Gamma stage added:");
1635476128f0a88217414f05e6a7ee518cdb411d026raftias                for (int channel = 0; channel < gammas.channels(); ++channel) {
164db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                    SkCSXformPrintf("  %s", debugGammas[(int)gammas.type(channel)]);
165db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                }
166db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                SkCSXformPrintf("\n");
167db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                bool gammaNeedsRef = false;
1685476128f0a88217414f05e6a7ee518cdb411d026raftias                for (int channel = 0; channel < gammas.channels(); ++channel) {
169db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                    if (SkGammas::Type::kTable_Type == gammas.type(channel)) {
170db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                        SkTableTransferFn table = {
171db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                                gammas.table(channel),
172db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                                gammas.data(channel).fTable.fSize,
173db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                        };
174db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett
1759d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett                        gammaNeedsRef |= !this->buildTableFn(&table);
1765476128f0a88217414f05e6a7ee518cdb411d026raftias                        this->addTableFn(table, channel);
177db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                    } else {
178113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                        SkColorSpaceTransferFn fn;
179113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                        SkAssertResult(gamma_to_parametric(&fn, gammas, channel));
1805476128f0a88217414f05e6a7ee518cdb411d026raftias                        this->addTransferFn(fn, channel);
1812563601fc2b0505619f905f86bd249ae630197ccraftias                    }
1822563601fc2b0505619f905f86bd249ae630197ccraftias                }
183db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                if (gammaNeedsRef) {
184de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    this->copy(sk_ref_sp(&gammas));
185db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett                }
1862563601fc2b0505619f905f86bd249ae630197ccraftias                break;
187db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            }
188de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            case SkColorSpace_A2B::Element::Type::kCLUT: {
1895476128f0a88217414f05e6a7ee518cdb411d026raftias                SkCSXformPrintf("CLUT (%d -> %d) stage added\n", e.colorLUT().inputChannels(),
1905476128f0a88217414f05e6a7ee518cdb411d026raftias                                                                 e.colorLUT().outputChannels());
191c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein
192c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                struct Ctx : SkJumper_ColorLookupTableCtx {
193c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                    sk_sp<const SkColorLookUpTable> clut;
194c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein                };
195c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                auto ctx = fAlloc.make<Ctx>();
196c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                ctx->clut  = sk_ref_sp(&e.colorLUT());
197c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                ctx->table = ctx->clut->table();
198c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                for (int i = 0; i < ctx->clut->inputChannels(); i++) {
199c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                    ctx->limits[i] = ctx->clut->gridPoints(i);
200c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                }
201c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein
202c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                switch  (e.colorLUT().inputChannels()) {
203c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                    case 3: fElementsPipeline.append(SkRasterPipeline::clut_3D, ctx); break;
204c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                    case 4: fElementsPipeline.append(SkRasterPipeline::clut_4D, ctx); break;
205c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                    default: SkDEBUGFAIL("need to handle 1 or 2 channel color lookup tables.");
206c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                }
207c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                fElementsPipeline.append(SkRasterPipeline::clamp_0);
208c2f876bb8d8991e428467c1d7d24152eea629770Mike Klein                fElementsPipeline.append(SkRasterPipeline::clamp_1);
2092563601fc2b0505619f905f86bd249ae630197ccraftias                break;
210de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            }
2112563601fc2b0505619f905f86bd249ae630197ccraftias            case SkColorSpace_A2B::Element::Type::kMatrix:
2122563601fc2b0505619f905f86bd249ae630197ccraftias                if (!e.matrix().isIdentity()) {
2132563601fc2b0505619f905f86bd249ae630197ccraftias                    SkCSXformPrintf("Matrix stage added\n");
2142563601fc2b0505619f905f86bd249ae630197ccraftias                    addMatrix(e.matrix());
2152563601fc2b0505619f905f86bd249ae630197ccraftias                }
2162563601fc2b0505619f905f86bd249ae630197ccraftias                break;
2172563601fc2b0505619f905f86bd249ae630197ccraftias        }
2182563601fc2b0505619f905f86bd249ae630197ccraftias    }
2192563601fc2b0505619f905f86bd249ae630197ccraftias
2202563601fc2b0505619f905f86bd249ae630197ccraftias    // Lab PCS -> XYZ PCS
2212563601fc2b0505619f905f86bd249ae630197ccraftias    if (SkColorSpace_A2B::PCS::kLAB == srcSpace->pcs()) {
2222563601fc2b0505619f905f86bd249ae630197ccraftias        SkCSXformPrintf("Lab -> XYZ element added\n");
2232563601fc2b0505619f905f86bd249ae630197ccraftias        fElementsPipeline.append(SkRasterPipeline::lab_to_xyz);
2242563601fc2b0505619f905f86bd249ae630197ccraftias    }
2252563601fc2b0505619f905f86bd249ae630197ccraftias
22691db12d89c214235e24599f3ec18df2f952e99ebraftias    // we should now be in XYZ PCS
22791db12d89c214235e24599f3ec18df2f952e99ebraftias    SkASSERT(3 == currentChannels);
22891db12d89c214235e24599f3ec18df2f952e99ebraftias
2292563601fc2b0505619f905f86bd249ae630197ccraftias    // and XYZ PCS -> output color space xforms
2302563601fc2b0505619f905f86bd249ae630197ccraftias    if (!dstSpace->fromXYZD50()->isIdentity()) {
2312563601fc2b0505619f905f86bd249ae630197ccraftias        addMatrix(*dstSpace->fromXYZD50());
2322563601fc2b0505619f905f86bd249ae630197ccraftias    }
2332563601fc2b0505619f905f86bd249ae630197ccraftias
234975245407a16dba58ee42cb12f70f8db87f02da0raftias    switch (dstSpace->gammaNamed()) {
235975245407a16dba58ee42cb12f70f8db87f02da0raftias        case kLinear_SkGammaNamed:
236975245407a16dba58ee42cb12f70f8db87f02da0raftias            // do nothing
237975245407a16dba58ee42cb12f70f8db87f02da0raftias            break;
238c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein        case k2Dot2Curve_SkGammaNamed: {
239a07e4302cfefc282d8d235edfbc20a54c75afa88Mike Klein            fElementsPipeline.append(SkRasterPipeline::gamma, this->copy(1/2.2f));
240975245407a16dba58ee42cb12f70f8db87f02da0raftias            break;
241c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein        }
242975245407a16dba58ee42cb12f70f8db87f02da0raftias        case kSRGB_SkGammaNamed:
243975245407a16dba58ee42cb12f70f8db87f02da0raftias            fElementsPipeline.append(SkRasterPipeline::to_srgb);
244975245407a16dba58ee42cb12f70f8db87f02da0raftias            break;
245975245407a16dba58ee42cb12f70f8db87f02da0raftias        case kNonStandard_SkGammaNamed: {
246975245407a16dba58ee42cb12f70f8db87f02da0raftias            for (int channel = 0; channel < 3; ++channel) {
247975245407a16dba58ee42cb12f70f8db87f02da0raftias                const SkGammas& gammas = *dstSpace->gammas();
248975245407a16dba58ee42cb12f70f8db87f02da0raftias                if (SkGammas::Type::kTable_Type == gammas.type(channel)) {
249975245407a16dba58ee42cb12f70f8db87f02da0raftias                    static constexpr int kInvTableSize = 256;
250de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    auto storage = fAlloc.makeArray<float>(kInvTableSize);
251de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    invert_table_gamma(storage, nullptr, kInvTableSize,
252975245407a16dba58ee42cb12f70f8db87f02da0raftias                                       gammas.table(channel),
253975245407a16dba58ee42cb12f70f8db87f02da0raftias                                       gammas.data(channel).fTable.fSize);
254de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein                    SkTableTransferFn table = { storage, kInvTableSize };
255975245407a16dba58ee42cb12f70f8db87f02da0raftias                    this->addTableFn(table, channel);
256975245407a16dba58ee42cb12f70f8db87f02da0raftias                } else {
257113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                    SkColorSpaceTransferFn fn;
258113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry                    SkAssertResult(gamma_to_parametric(&fn, gammas, channel));
25973e627074839bc00569117235eb4e7d4fc3cc39fBrian Osman                    this->addTransferFn(fn.invert(), channel);
260975245407a16dba58ee42cb12f70f8db87f02da0raftias                }
2612563601fc2b0505619f905f86bd249ae630197ccraftias            }
2622563601fc2b0505619f905f86bd249ae630197ccraftias        }
263975245407a16dba58ee42cb12f70f8db87f02da0raftias        break;
264db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett    }
265db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett}
266db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett
2675476128f0a88217414f05e6a7ee518cdb411d026raftiasvoid SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, int channelIndex) {
2685476128f0a88217414f05e6a7ee518cdb411d026raftias    switch (channelIndex) {
2695476128f0a88217414f05e6a7ee518cdb411d026raftias        case 0:
270de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_r, this->copy(fn));
271db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            break;
2725476128f0a88217414f05e6a7ee518cdb411d026raftias        case 1:
273de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_g, this->copy(fn));
274db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            break;
2755476128f0a88217414f05e6a7ee518cdb411d026raftias        case 2:
276de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_b, this->copy(fn));
277db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            break;
2785476128f0a88217414f05e6a7ee518cdb411d026raftias        case 3:
279de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::parametric_a, this->copy(fn));
2805476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
281db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett        default:
282db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett            SkASSERT(false);
2832563601fc2b0505619f905f86bd249ae630197ccraftias    }
2842563601fc2b0505619f905f86bd249ae630197ccraftias}
2852563601fc2b0505619f905f86bd249ae630197ccraftias
2869d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett/**
2879d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett *  |fn| is an in-out parameter.  If the table is too small to perform reasonable table-lookups
2889d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett *  without interpolation, we will build a bigger table.
2899d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett *
2909d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett *  This returns false if we use the original table, meaning we do nothing here but need to keep
2919d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett *  a reference to the original table.  This returns true if we build a new table and the original
2929d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett *  table can be discarded.
2939d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett */
2949d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarettbool SkColorSpaceXform_A2B::buildTableFn(SkTableTransferFn* fn) {
2959d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    // Arbitrary, but seems like a reasonable guess.
2969d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    static constexpr int kMinTableSize = 256;
2979d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett
2989d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    if (fn->fSize >= kMinTableSize) {
2999d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett        return false;
3009d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    }
3019d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett
3029d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    float* outTable = fAlloc.makeArray<float>(kMinTableSize);
3039d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    float step = 1.0f / (kMinTableSize - 1);
3049d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    for (int i = 0; i < kMinTableSize; i++) {
3059d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett        outTable[i] = interp_lut(i * step, fn->fData, fn->fSize);
3069d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    }
3079d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett
3089d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    fn->fData = outTable;
3099d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    fn->fSize = kMinTableSize;
3109d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett    return true;
3119d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett}
3129d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett
3135476128f0a88217414f05e6a7ee518cdb411d026raftiasvoid SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, int channelIndex) {
3145476128f0a88217414f05e6a7ee518cdb411d026raftias    switch (channelIndex) {
3155476128f0a88217414f05e6a7ee518cdb411d026raftias        case 0:
316de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_r, this->copy(fn));
3172563601fc2b0505619f905f86bd249ae630197ccraftias            break;
3185476128f0a88217414f05e6a7ee518cdb411d026raftias        case 1:
319de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_g, this->copy(fn));
3202563601fc2b0505619f905f86bd249ae630197ccraftias            break;
3215476128f0a88217414f05e6a7ee518cdb411d026raftias        case 2:
322de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_b, this->copy(fn));
3232563601fc2b0505619f905f86bd249ae630197ccraftias            break;
3245476128f0a88217414f05e6a7ee518cdb411d026raftias        case 3:
325de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein            fElementsPipeline.append(SkRasterPipeline::table_a, this->copy(fn));
3265476128f0a88217414f05e6a7ee518cdb411d026raftias            break;
3272563601fc2b0505619f905f86bd249ae630197ccraftias        default:
3282563601fc2b0505619f905f86bd249ae630197ccraftias            SkASSERT(false);
3292563601fc2b0505619f905f86bd249ae630197ccraftias    }
3302563601fc2b0505619f905f86bd249ae630197ccraftias}
3312563601fc2b0505619f905f86bd249ae630197ccraftias
332de1cad99b353bad080a04ccfde955a8f3c0af295Mike Kleinvoid SkColorSpaceXform_A2B::addMatrix(const SkMatrix44& m44) {
333de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    auto m = fAlloc.makeArray<float>(12);
334de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[0] = m44.get(0,0); m[ 1] = m44.get(1,0); m[ 2] = m44.get(2,0);
335de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[3] = m44.get(0,1); m[ 4] = m44.get(1,1); m[ 5] = m44.get(2,1);
336de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[6] = m44.get(0,2); m[ 7] = m44.get(1,2); m[ 8] = m44.get(2,2);
337de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    m[9] = m44.get(0,3); m[10] = m44.get(1,3); m[11] = m44.get(2,3);
338de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein
339de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,0) == 0.0f);
340de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,1) == 0.0f);
341de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,2) == 0.0f);
342de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    SkASSERT(m44.get(3,3) == 1.0f);
343de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein
344de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein    fElementsPipeline.append(SkRasterPipeline::matrix_3x4, m);
3452563601fc2b0505619f905f86bd249ae630197ccraftias    fElementsPipeline.append(SkRasterPipeline::clamp_0);
346db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett    fElementsPipeline.append(SkRasterPipeline::clamp_1);
3472563601fc2b0505619f905f86bd249ae630197ccraftias}
348