LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkMaskGamma.h (source / functions) Hit Total Coverage
Test: output.info Lines: 16 39 41.0 %
Date: 2017-07-14 16:53:18 Functions: 7 18 38.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 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             : #ifndef SkMaskGamma_DEFINED
       9             : #define SkMaskGamma_DEFINED
      10             : 
      11             : #include "SkTypes.h"
      12             : #include "SkColor.h"
      13             : #include "SkColorPriv.h"
      14             : #include "SkRefCnt.h"
      15             : 
      16             : /**
      17             :  * SkColorSpaceLuminance is used to convert luminances to and from linear and
      18             :  * perceptual color spaces.
      19             :  *
      20             :  * Luma is used to specify a linear luminance value [0.0, 1.0].
      21             :  * Luminance is used to specify a luminance value in an arbitrary color space [0.0, 1.0].
      22             :  */
      23           0 : class SkColorSpaceLuminance : SkNoncopyable {
      24             : public:
      25           0 :     virtual ~SkColorSpaceLuminance() { }
      26             : 
      27             :     /** Converts a color component luminance in the color space to a linear luma. */
      28             :     virtual SkScalar toLuma(SkScalar gamma, SkScalar luminance) const = 0;
      29             :     /** Converts a linear luma to a color component luminance in the color space. */
      30             :     virtual SkScalar fromLuma(SkScalar gamma, SkScalar luma) const = 0;
      31             : 
      32             :     /** Converts a color to a luminance value. */
      33             :     static U8CPU computeLuminance(SkScalar gamma, SkColor c) {
      34             :         const SkColorSpaceLuminance& luminance = Fetch(gamma);
      35             :         SkScalar r = luminance.toLuma(gamma, SkIntToScalar(SkColorGetR(c)) / 255);
      36             :         SkScalar g = luminance.toLuma(gamma, SkIntToScalar(SkColorGetG(c)) / 255);
      37             :         SkScalar b = luminance.toLuma(gamma, SkIntToScalar(SkColorGetB(c)) / 255);
      38             :         SkScalar luma = r * SK_LUM_COEFF_R +
      39             :                         g * SK_LUM_COEFF_G +
      40             :                         b * SK_LUM_COEFF_B;
      41             :         SkASSERT(luma <= SK_Scalar1);
      42             :         return SkScalarRoundToInt(luminance.fromLuma(gamma, luma) * 255);
      43             :     }
      44             : 
      45             :     /** Retrieves the SkColorSpaceLuminance for the given gamma. */
      46             :     static const SkColorSpaceLuminance& Fetch(SkScalar gamma);
      47             : };
      48             : 
      49             : ///@{
      50             : /**
      51             :  * Scales base <= 2^N-1 to 2^8-1
      52             :  * @param N [1, 8] the number of bits used by base.
      53             :  * @param base the number to be scaled to [0, 255].
      54             :  */
      55          63 : template<U8CPU N> static inline U8CPU sk_t_scale255(U8CPU base) {
      56          63 :     base <<= (8 - N);
      57          63 :     U8CPU lum = base;
      58         189 :     for (unsigned int i = N; i < 8; i += N) {
      59         126 :         lum |= base >> i;
      60             :     }
      61          63 :     return lum;
      62             : }
      63             : template<> /*static*/ inline U8CPU sk_t_scale255<1>(U8CPU base) {
      64             :     return base * 0xFF;
      65             : }
      66             : template<> /*static*/ inline U8CPU sk_t_scale255<2>(U8CPU base) {
      67             :     return base * 0x55;
      68             : }
      69             : template<> /*static*/ inline U8CPU sk_t_scale255<4>(U8CPU base) {
      70             :     return base * 0x11;
      71             : }
      72             : template<> /*static*/ inline U8CPU sk_t_scale255<8>(U8CPU base) {
      73             :     return base;
      74             : }
      75             : ///@}
      76             : 
      77             : template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskPreBlend;
      78             : 
      79             : void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar contrast,
      80             :                                        const SkColorSpaceLuminance& srcConvert, SkScalar srcGamma,
      81             :                                        const SkColorSpaceLuminance& dstConvert, SkScalar dstGamma);
      82             : 
      83             : /**
      84             :  * A regular mask contains linear alpha values. A gamma correcting mask
      85             :  * contains non-linear alpha values in an attempt to create gamma correct blits
      86             :  * in the presence of a gamma incorrect (linear) blend in the blitter.
      87             :  *
      88             :  * SkMaskGamma creates and maintains tables which convert linear alpha values
      89             :  * to gamma correcting alpha values.
      90             :  * @param R The number of luminance bits to use [1, 8] from the red channel.
      91             :  * @param G The number of luminance bits to use [1, 8] from the green channel.
      92             :  * @param B The number of luminance bits to use [1, 8] from the blue channel.
      93             :  */
      94           0 : template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskGamma : public SkRefCnt {
      95             : 
      96             : public:
      97             : 
      98             :     /** Creates a linear SkTMaskGamma. */
      99           2 :     SkTMaskGamma() : fIsLinear(true) { }
     100             : 
     101             :     /**
     102             :      * Creates tables to convert linear alpha values to gamma correcting alpha
     103             :      * values.
     104             :      *
     105             :      * @param contrast A value in the range [0.0, 1.0] which indicates the
     106             :      *                 amount of artificial contrast to add.
     107             :      * @param paint The color space in which the paint color was chosen.
     108             :      * @param device The color space of the target device.
     109             :      */
     110           0 :     SkTMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) : fIsLinear(false) {
     111           0 :         const SkColorSpaceLuminance& paintConvert = SkColorSpaceLuminance::Fetch(paintGamma);
     112           0 :         const SkColorSpaceLuminance& deviceConvert = SkColorSpaceLuminance::Fetch(deviceGamma);
     113           0 :         for (U8CPU i = 0; i < (1 << MAX_LUM_BITS); ++i) {
     114           0 :             U8CPU lum = sk_t_scale255<MAX_LUM_BITS>(i);
     115           0 :             SkTMaskGamma_build_correcting_lut(fGammaTables[i], lum, contrast,
     116             :                                               paintConvert, paintGamma,
     117             :                                               deviceConvert, deviceGamma);
     118             :         }
     119           0 :     }
     120             : 
     121             :     /** Given a color, returns the closest canonical color. */
     122          21 :     static SkColor CanonicalColor(SkColor color) {
     123          21 :         return SkColorSetRGB(
     124             :                    sk_t_scale255<R_LUM_BITS>(SkColorGetR(color) >> (8 - R_LUM_BITS)),
     125             :                    sk_t_scale255<G_LUM_BITS>(SkColorGetG(color) >> (8 - G_LUM_BITS)),
     126             :                    sk_t_scale255<B_LUM_BITS>(SkColorGetB(color) >> (8 - B_LUM_BITS)));
     127             :     }
     128             : 
     129             :     /** The type of the mask pre-blend which will be returned from preBlend(SkColor). */
     130             :     typedef SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS> PreBlend;
     131             : 
     132             :     /**
     133             :      * Provides access to the tables appropriate for converting linear alpha
     134             :      * values into gamma correcting alpha values when drawing the given color
     135             :      * through the mask. The destination color will be approximated.
     136             :      */
     137             :     PreBlend preBlend(SkColor color) const;
     138             : 
     139             :     /**
     140             :      * Get dimensions for the full table set, so it can be allocated as a block.
     141             :      */
     142           0 :     void getGammaTableDimensions(int* tableWidth, int* numTables) const {
     143           0 :         *tableWidth = 256;
     144           0 :         *numTables = (1 << MAX_LUM_BITS);
     145           0 :     }
     146             : 
     147             :     /**
     148             :      * Provides direct access to the full table set, so it can be uploaded
     149             :      * into a texture.
     150             :      */
     151           0 :     const uint8_t* getGammaTables() const {
     152           0 :         return (const uint8_t*) fGammaTables;
     153             :     }
     154             : 
     155             : private:
     156             :     static const int MAX_LUM_BITS =
     157             :           B_LUM_BITS > (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS)
     158             :         ? B_LUM_BITS : (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS);
     159             :     uint8_t fGammaTables[1 << MAX_LUM_BITS][256];
     160             :     bool fIsLinear;
     161             : 
     162             :     typedef SkRefCnt INHERITED;
     163             : };
     164             : 
     165             : 
     166             : /**
     167             :  * SkTMaskPreBlend is a tear-off of SkTMaskGamma. It provides the tables to
     168             :  * convert a linear alpha value for a given channel to a gamma correcting alpha
     169             :  * value for that channel. This class is immutable.
     170             :  *
     171             :  * If fR, fG, or fB is nullptr, all of them will be. This indicates that no mask
     172             :  * pre blend should be applied. SkTMaskPreBlend::isApplicable() is provided as
     173             :  * a convenience function to test for the absence of this case.
     174             :  */
     175             : template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskPreBlend {
     176             : private:
     177           0 :     SkTMaskPreBlend(sk_sp<const SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>> parent,
     178             :                     const uint8_t* r, const uint8_t* g, const uint8_t* b)
     179           0 :     : fParent(std::move(parent)), fR(r), fG(g), fB(b) { }
     180             : 
     181             :     sk_sp<const SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>> fParent;
     182             :     friend class SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>;
     183             : public:
     184             :     /** Creates a non applicable SkTMaskPreBlend. */
     185           4 :     SkTMaskPreBlend() : fParent(), fR(nullptr), fG(nullptr), fB(nullptr) { }
     186             : 
     187             :     /**
     188             :      * This copy contructor exists for correctness, but should never be called
     189             :      * when return value optimization is enabled.
     190             :      */
     191             :     SkTMaskPreBlend(const SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>& that)
     192             :     : fParent(that.fParent), fR(that.fR), fG(that.fG), fB(that.fB) { }
     193             : 
     194           0 :     ~SkTMaskPreBlend() { }
     195             : 
     196             :     /** True if this PreBlend should be applied. When false, fR, fG, and fB are nullptr. */
     197          58 :     bool isApplicable() const { return SkToBool(this->fG); }
     198             : 
     199             :     const uint8_t* fR;
     200             :     const uint8_t* fG;
     201             :     const uint8_t* fB;
     202             : };
     203             : 
     204             : template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS>
     205             : SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>
     206           2 : SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>::preBlend(SkColor color) const {
     207           2 :     return fIsLinear ? SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>()
     208             :                      : SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>(sk_ref_sp(this),
     209           0 :                          fGammaTables[SkColorGetR(color) >> (8 - MAX_LUM_BITS)],
     210           0 :                          fGammaTables[SkColorGetG(color) >> (8 - MAX_LUM_BITS)],
     211           2 :                          fGammaTables[SkColorGetB(color) >> (8 - MAX_LUM_BITS)]);
     212             : }
     213             : 
     214             : ///@{
     215             : /**
     216             :  *  If APPLY_LUT is false, returns component unchanged.
     217             :  *  If APPLY_LUT is true, returns lut[component].
     218             :  *  @param APPLY_LUT whether or not the look-up table should be applied to component.
     219             :  *  @component the initial component.
     220             :  *  @lut a look-up table which transforms the component.
     221             :  */
     222       51573 : template<bool APPLY_LUT> static inline U8CPU sk_apply_lut_if(U8CPU component, const uint8_t*) {
     223       51573 :     return component;
     224             : }
     225           0 : template<> /*static*/ inline U8CPU sk_apply_lut_if<true>(U8CPU component, const uint8_t* lut) {
     226           0 :     return lut[component];
     227             : }
     228             : ///@}
     229             : 
     230             : #endif

Generated by: LCOV version 1.13