LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkColorSpaceXform_A2B.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 174 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 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 "SkColorSpaceXform_A2B.h"
       9             : 
      10             : #include "SkColorPriv.h"
      11             : #include "SkColorSpace_A2B.h"
      12             : #include "SkColorSpace_XYZ.h"
      13             : #include "SkColorSpacePriv.h"
      14             : #include "SkColorSpaceXformPriv.h"
      15             : #include "SkMakeUnique.h"
      16             : #include "SkNx.h"
      17             : #include "SkSRGB.h"
      18             : #include "SkTypes.h"
      19             : 
      20           0 : bool SkColorSpaceXform_A2B::onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat,
      21             :                                     const void* src, int count, SkAlphaType alphaType) const {
      22           0 :     SkRasterPipeline pipeline;
      23           0 :     switch (srcFormat) {
      24             :         case kBGRA_8888_ColorFormat:
      25           0 :             pipeline.append(SkRasterPipeline::load_8888, &src);
      26           0 :             pipeline.append(SkRasterPipeline::swap_rb);
      27           0 :             break;
      28             :         case kRGBA_8888_ColorFormat:
      29           0 :             pipeline.append(SkRasterPipeline::load_8888, &src);
      30           0 :             break;
      31             :         case kRGBA_U16_BE_ColorFormat:
      32           0 :             pipeline.append(SkRasterPipeline::load_u16_be, &src);
      33           0 :             break;
      34             :         case kRGB_U16_BE_ColorFormat:
      35           0 :             pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
      36           0 :             break;
      37             :         default:
      38             :             SkCSXformPrintf("F16/F32 sources must be linear.\n");
      39           0 :             return false;
      40             :     }
      41             : 
      42           0 :     pipeline.extend(fElementsPipeline);
      43             : 
      44           0 :     if (kPremul_SkAlphaType == alphaType) {
      45           0 :         pipeline.append(SkRasterPipeline::premul);
      46             :     }
      47             : 
      48           0 :     switch (dstFormat) {
      49             :         case kBGRA_8888_ColorFormat:
      50           0 :             pipeline.append(SkRasterPipeline::swap_rb);
      51           0 :             pipeline.append(SkRasterPipeline::store_8888, &dst);
      52           0 :             break;
      53             :         case kRGBA_8888_ColorFormat:
      54           0 :             pipeline.append(SkRasterPipeline::store_8888, &dst);
      55           0 :             break;
      56             :         case kRGBA_F16_ColorFormat:
      57           0 :             if (!fLinearDstGamma) {
      58           0 :                 return false;
      59             :             }
      60           0 :             pipeline.append(SkRasterPipeline::store_f16, &dst);
      61           0 :             break;
      62             :         case kRGBA_F32_ColorFormat:
      63           0 :             if (!fLinearDstGamma) {
      64           0 :                 return false;
      65             :             }
      66           0 :             pipeline.append(SkRasterPipeline::store_f32, &dst);
      67           0 :             break;
      68             :         case kBGR_565_ColorFormat:
      69           0 :             if (kOpaque_SkAlphaType != alphaType) {
      70           0 :                 return false;
      71             :             }
      72           0 :             pipeline.append(SkRasterPipeline::store_565, &dst);
      73           0 :             break;
      74             :         default:
      75           0 :             return false;
      76             :     }
      77           0 :     pipeline.run(0,count);
      78             : 
      79           0 :     return true;
      80             : }
      81             : 
      82           0 : static inline bool gamma_to_parametric(SkColorSpaceTransferFn* coeffs, const SkGammas& gammas,
      83             :                                        int channel) {
      84           0 :     switch (gammas.type(channel)) {
      85             :         case SkGammas::Type::kNamed_Type:
      86           0 :             return named_to_parametric(coeffs, gammas.data(channel).fNamed);
      87             :         case SkGammas::Type::kValue_Type:
      88           0 :             value_to_parametric(coeffs, gammas.data(channel).fValue);
      89           0 :             return true;
      90             :         case SkGammas::Type::kParam_Type:
      91           0 :             *coeffs = gammas.params(channel);
      92           0 :             return true;
      93             :         default:
      94           0 :             return false;
      95             :     }
      96             : }
      97             : 
      98           0 : SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
      99           0 :                                              SkColorSpace_XYZ* dstSpace)
     100           0 :     : fLinearDstGamma(kLinear_SkGammaNamed == dstSpace->gammaNamed()) {
     101             : #if (SkCSXformPrintfDefined)
     102             :     static const char* debugGammaNamed[4] = {
     103             :         "Linear", "SRGB", "2.2", "NonStandard"
     104             :     };
     105             :     static const char* debugGammas[5] = {
     106             :         "None", "Named", "Value", "Table", "Param"
     107             :     };
     108             : #endif
     109             :     int currentChannels;
     110           0 :     switch (srcSpace->iccType()) {
     111             :         case SkColorSpace_Base::kRGB_ICCTypeFlag:
     112           0 :             currentChannels = 3;
     113           0 :             break;
     114             :         case SkColorSpace_Base::kCMYK_ICCTypeFlag:
     115           0 :             currentChannels = 4;
     116             :             // CMYK images from JPEGs (the only format that supports it) are actually
     117             :             // inverted CMYK, so we need to invert every channel.
     118             :             // TransferFn is y = -x + 1 for x < 1.f, otherwise 0x + 0, ie y = 1 - x for x in [0,1]
     119           0 :             this->addTransferFns({1.f, 0.f, 0.f, -1.f, 1.f, 0.f, 1.f}, 4);
     120           0 :             break;
     121             :         default:
     122           0 :             currentChannels = 0;
     123           0 :             SkASSERT(false);
     124             :     }
     125             :     // add in all input color space -> PCS xforms
     126           0 :     for (int i = 0; i < srcSpace->count(); ++i) {
     127           0 :         const SkColorSpace_A2B::Element& e = srcSpace->element(i);
     128           0 :         SkASSERT(e.inputChannels() == currentChannels);
     129           0 :         currentChannels = e.outputChannels();
     130           0 :         switch (e.type()) {
     131             :             case SkColorSpace_A2B::Element::Type::kGammaNamed:
     132           0 :                 if (kLinear_SkGammaNamed == e.gammaNamed()) {
     133           0 :                     break;
     134             :                 }
     135             : 
     136             :                 // take the fast path for 3-channel named gammas
     137           0 :                 if (3 == currentChannels) {
     138           0 :                     if (k2Dot2Curve_SkGammaNamed == e.gammaNamed()) {
     139             :                         SkCSXformPrintf("fast path from 2.2\n");
     140           0 :                         fElementsPipeline.append(SkRasterPipeline::from_2dot2);
     141           0 :                         break;
     142           0 :                     } else if (kSRGB_SkGammaNamed == e.gammaNamed()) {
     143             :                         SkCSXformPrintf("fast path from sRGB\n");
     144             :                         // Images should always start the pipeline as unpremul
     145           0 :                         fElementsPipeline.append_from_srgb(kUnpremul_SkAlphaType);
     146           0 :                         break;
     147             :                     }
     148             :                 }
     149             : 
     150             :                 SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]);
     151             :                 SkColorSpaceTransferFn fn;
     152           0 :                 SkAssertResult(named_to_parametric(&fn, e.gammaNamed()));
     153           0 :                 this->addTransferFns(fn, currentChannels);
     154           0 :                 break;
     155             :             case SkColorSpace_A2B::Element::Type::kGammas: {
     156           0 :                 const SkGammas& gammas = e.gammas();
     157             :                 SkCSXformPrintf("Gamma stage added:");
     158           0 :                 for (int channel = 0; channel < gammas.channels(); ++channel) {
     159             :                     SkCSXformPrintf("  %s", debugGammas[(int)gammas.type(channel)]);
     160             :                 }
     161             :                 SkCSXformPrintf("\n");
     162           0 :                 bool gammaNeedsRef = false;
     163           0 :                 for (int channel = 0; channel < gammas.channels(); ++channel) {
     164           0 :                     if (SkGammas::Type::kTable_Type == gammas.type(channel)) {
     165             :                         SkTableTransferFn table = {
     166           0 :                                 gammas.table(channel),
     167           0 :                                 gammas.data(channel).fTable.fSize,
     168           0 :                         };
     169             : 
     170           0 :                         this->addTableFn(table, channel);
     171           0 :                         gammaNeedsRef = true;
     172             :                     } else {
     173             :                         SkColorSpaceTransferFn fn;
     174           0 :                         SkAssertResult(gamma_to_parametric(&fn, gammas, channel));
     175           0 :                         this->addTransferFn(fn, channel);
     176             :                     }
     177             :                 }
     178           0 :                 if (gammaNeedsRef) {
     179           0 :                     fGammaRefs.push_back(sk_ref_sp(&gammas));
     180             :                 }
     181           0 :                 break;
     182             :             }
     183             :             case SkColorSpace_A2B::Element::Type::kCLUT:
     184             :                 SkCSXformPrintf("CLUT (%d -> %d) stage added\n", e.colorLUT().inputChannels(),
     185             :                                                                  e.colorLUT().outputChannels());
     186           0 :                 fCLUTs.push_back(sk_ref_sp(&e.colorLUT()));
     187           0 :                 fElementsPipeline.append(SkRasterPipeline::color_lookup_table,
     188           0 :                                          fCLUTs.back().get());
     189           0 :                 break;
     190             :             case SkColorSpace_A2B::Element::Type::kMatrix:
     191           0 :                 if (!e.matrix().isIdentity()) {
     192             :                     SkCSXformPrintf("Matrix stage added\n");
     193           0 :                     addMatrix(e.matrix());
     194             :                 }
     195           0 :                 break;
     196             :         }
     197             :     }
     198             : 
     199             :     // Lab PCS -> XYZ PCS
     200           0 :     if (SkColorSpace_A2B::PCS::kLAB == srcSpace->pcs()) {
     201             :         SkCSXformPrintf("Lab -> XYZ element added\n");
     202           0 :         fElementsPipeline.append(SkRasterPipeline::lab_to_xyz);
     203             :     }
     204             : 
     205             :     // we should now be in XYZ PCS
     206           0 :     SkASSERT(3 == currentChannels);
     207             : 
     208             :     // and XYZ PCS -> output color space xforms
     209           0 :     if (!dstSpace->fromXYZD50()->isIdentity()) {
     210           0 :         addMatrix(*dstSpace->fromXYZD50());
     211             :     }
     212             : 
     213           0 :     switch (dstSpace->gammaNamed()) {
     214             :         case kLinear_SkGammaNamed:
     215             :             // do nothing
     216           0 :             break;
     217             :         case k2Dot2Curve_SkGammaNamed:
     218           0 :             fElementsPipeline.append(SkRasterPipeline::to_2dot2);
     219           0 :             break;
     220             :         case kSRGB_SkGammaNamed:
     221           0 :             fElementsPipeline.append(SkRasterPipeline::to_srgb);
     222           0 :             break;
     223             :         case kNonStandard_SkGammaNamed: {
     224           0 :             for (int channel = 0; channel < 3; ++channel) {
     225           0 :                 const SkGammas& gammas = *dstSpace->gammas();
     226           0 :                 if (SkGammas::Type::kTable_Type == gammas.type(channel)) {
     227             :                     static constexpr int kInvTableSize = 256;
     228           0 :                     std::vector<float> storage(kInvTableSize);
     229           0 :                     invert_table_gamma(storage.data(), nullptr, storage.size(),
     230             :                                        gammas.table(channel),
     231           0 :                                        gammas.data(channel).fTable.fSize);
     232             :                     SkTableTransferFn table = {
     233           0 :                             storage.data(),
     234           0 :                             (int) storage.size(),
     235           0 :                     };
     236           0 :                     fTableStorage.push_front(std::move(storage));
     237             : 
     238           0 :                     this->addTableFn(table, channel);
     239             :                 } else {
     240             :                     SkColorSpaceTransferFn fn;
     241           0 :                     SkAssertResult(gamma_to_parametric(&fn, gammas, channel));
     242           0 :                     this->addTransferFn(fn.invert(), channel);
     243             :                 }
     244             :             }
     245             :         }
     246           0 :         break;
     247             :     }
     248           0 : }
     249             : 
     250           0 : void SkColorSpaceXform_A2B::addTransferFns(const SkColorSpaceTransferFn& fn, int channelCount) {
     251           0 :     for (int i = 0; i < channelCount; ++i) {
     252           0 :         this->addTransferFn(fn, i);
     253             :     }
     254           0 : }
     255             : 
     256           0 : void SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, int channelIndex) {
     257           0 :     fTransferFns.push_front(fn);
     258           0 :     switch (channelIndex) {
     259             :         case 0:
     260           0 :             fElementsPipeline.append(SkRasterPipeline::parametric_r, &fTransferFns.front());
     261           0 :             break;
     262             :         case 1:
     263           0 :             fElementsPipeline.append(SkRasterPipeline::parametric_g, &fTransferFns.front());
     264           0 :             break;
     265             :         case 2:
     266           0 :             fElementsPipeline.append(SkRasterPipeline::parametric_b, &fTransferFns.front());
     267           0 :             break;
     268             :         case 3:
     269           0 :             fElementsPipeline.append(SkRasterPipeline::parametric_a, &fTransferFns.front());
     270           0 :             break;
     271             :         default:
     272           0 :             SkASSERT(false);
     273             :     }
     274           0 : }
     275             : 
     276           0 : void SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, int channelIndex) {
     277           0 :     fTableTransferFns.push_front(fn);
     278           0 :     switch (channelIndex) {
     279             :         case 0:
     280           0 :             fElementsPipeline.append(SkRasterPipeline::table_r, &fTableTransferFns.front());
     281           0 :             break;
     282             :         case 1:
     283           0 :             fElementsPipeline.append(SkRasterPipeline::table_g, &fTableTransferFns.front());
     284           0 :             break;
     285             :         case 2:
     286           0 :             fElementsPipeline.append(SkRasterPipeline::table_b, &fTableTransferFns.front());
     287           0 :             break;
     288             :         case 3:
     289           0 :             fElementsPipeline.append(SkRasterPipeline::table_a, &fTableTransferFns.front());
     290           0 :             break;
     291             :         default:
     292           0 :             SkASSERT(false);
     293             :     }
     294           0 : }
     295             : 
     296           0 : void SkColorSpaceXform_A2B::addMatrix(const SkMatrix44& matrix) {
     297           0 :     fMatrices.push_front(std::vector<float>(12));
     298           0 :     auto& m = fMatrices.front();
     299           0 :     m[ 0] = matrix.get(0, 0);
     300           0 :     m[ 1] = matrix.get(1, 0);
     301           0 :     m[ 2] = matrix.get(2, 0);
     302           0 :     m[ 3] = matrix.get(0, 1);
     303           0 :     m[ 4] = matrix.get(1, 1);
     304           0 :     m[ 5] = matrix.get(2, 1);
     305           0 :     m[ 6] = matrix.get(0, 2);
     306           0 :     m[ 7] = matrix.get(1, 2);
     307           0 :     m[ 8] = matrix.get(2, 2);
     308           0 :     m[ 9] = matrix.get(0, 3);
     309           0 :     m[10] = matrix.get(1, 3);
     310           0 :     m[11] = matrix.get(2, 3);
     311           0 :     SkASSERT(matrix.get(3, 0) == 0.f);
     312           0 :     SkASSERT(matrix.get(3, 1) == 0.f);
     313           0 :     SkASSERT(matrix.get(3, 2) == 0.f);
     314           0 :     SkASSERT(matrix.get(3, 3) == 1.f);
     315           0 :     fElementsPipeline.append(SkRasterPipeline::matrix_3x4, m.data());
     316           0 :     fElementsPipeline.append(SkRasterPipeline::clamp_0);
     317           0 :     fElementsPipeline.append(SkRasterPipeline::clamp_1);
     318           0 : }

Generated by: LCOV version 1.13