SkMaskGamma.h revision fbfcd5602128ec010c82cb733c9cdc0a3254f9f3
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 */ 23class SkColorSpaceLuminance : SkNoncopyable { 24public: 25 virtual ~SkColorSpaceLuminance() {}; 26 27 /** Converts a color component luminance in the color space to a linear luma. */ 28 virtual SkScalar toLuma(SkScalar luminance) const = 0; 29 /** Converts a linear luma to a color component luminance in the color space. */ 30 virtual SkScalar fromLuma(SkScalar luma) const = 0; 31 32 /** Converts a color to a luminance value. */ 33 U8CPU computeLuminance(SkColor c) const { 34 SkScalar r = toLuma(SkIntToScalar(SkColorGetR(c)) / 255); 35 SkScalar g = toLuma(SkIntToScalar(SkColorGetG(c)) / 255); 36 SkScalar b = toLuma(SkIntToScalar(SkColorGetB(c)) / 255); 37 SkScalar luma = r * SkFloatToScalar(SK_LUM_COEFF_R) + 38 g * SkFloatToScalar(SK_LUM_COEFF_G) + 39 b * SkFloatToScalar(SK_LUM_COEFF_B); 40 SkASSERT(luma <= SK_Scalar1); 41 return SkScalarRoundToInt(fromLuma(luma) * 255); 42 } 43}; 44 45class SkSRGBLuminance : public SkColorSpaceLuminance { 46public: 47 SkScalar toLuma(SkScalar luminance) const SK_OVERRIDE; 48 SkScalar fromLuma(SkScalar luma) const SK_OVERRIDE; 49}; 50 51class SkGammaLuminance : public SkColorSpaceLuminance { 52public: 53 SkGammaLuminance(SkScalar gamma); 54 SkScalar toLuma(SkScalar luminance) const SK_OVERRIDE; 55 SkScalar fromLuma(SkScalar luma) const SK_OVERRIDE; 56private: 57 SkScalar fGamma; 58 SkScalar fGammaInverse; 59}; 60 61///@{ 62/** 63 * Scales base <= 2^N-1 to 2^8-1 64 * @param N [1, 8] the number of bits used by base. 65 * @param base the number to be scaled to [0, 255]. 66 */ 67template<U8CPU N> static inline U8CPU sk_t_scale255(U8CPU base) { 68 base <<= (8 - N); 69 U8CPU lum = base; 70 for (unsigned int i = N; i < 8; i += N) { 71 lum |= base >> i; 72 } 73 return lum; 74} 75template<> /*static*/ inline U8CPU sk_t_scale255<1>(U8CPU base) { 76 return base * 0xFF; 77} 78template<> /*static*/ inline U8CPU sk_t_scale255<2>(U8CPU base) { 79 return base * 0x55; 80} 81template<> /*static*/ inline U8CPU sk_t_scale255<4>(U8CPU base) { 82 return base * 0x11; 83} 84template<> /*static*/ inline U8CPU sk_t_scale255<8>(U8CPU base) { 85 return base; 86} 87///@} 88 89template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskPreBlend; 90 91void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar contrast, 92 const SkColorSpaceLuminance& srcConvert, 93 const SkColorSpaceLuminance& dstConvert); 94 95/** 96 * A regular mask contains linear alpha values. A gamma correcting mask 97 * contains non-linear alpha values in an attempt to create gamma correct blits 98 * in the presence of a gamma incorrect (linear) blend in the blitter. 99 * 100 * SkMaskGamma creates and maintains tables which convert linear alpha values 101 * to gamma correcting alpha values. 102 * @param R The number of luminance bits to use [1, 8] from the red channel. 103 * @param G The number of luminance bits to use [1, 8] from the green channel. 104 * @param B The number of luminance bits to use [1, 8] from the blue channel. 105 */ 106template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskGamma : public SkRefCnt { 107public: 108 SK_DECLARE_INST_COUNT_TEMPLATE(SkTMaskGamma) 109 110 /** 111 * Creates tables to convert linear alpha values to gamma correcting alpha 112 * values. 113 * 114 * @param contrast A value in the range [0.0, 1.0] which indicates the 115 * amount of artificial contrast to add. 116 * @param paint The color space in which the paint color was chosen. 117 * @param device The color space of the target device. 118 */ 119 SkTMaskGamma(SkScalar contrast, 120 const SkColorSpaceLuminance& paint, 121 const SkColorSpaceLuminance& device) { 122 for (U8CPU i = 0; i < (1 << kLuminanceBits_Max); ++i) { 123 U8CPU lum = sk_t_scale255<kLuminanceBits_Max>(i); 124 SkTMaskGamma_build_correcting_lut(fGammaTables[i], lum, contrast, paint, device); 125 } 126 } 127 128 /** Given a color, returns the closest cannonical color. */ 129 SkColor cannonicalColor(SkColor color) { 130 return SkColorSetRGB( 131 sk_t_scale255<kLuminanceBits_R>(SkColorGetR(color) >> (8 - kLuminanceBits_R)), 132 sk_t_scale255<kLuminanceBits_G>(SkColorGetG(color) >> (8 - kLuminanceBits_G)), 133 sk_t_scale255<kLuminanceBits_B>(SkColorGetB(color) >> (8 - kLuminanceBits_B))); 134 } 135 136 /** The type of the mask pre-blend which will be returned from preBlend(SkColor). */ 137 typedef SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS> PreBlend; 138 139 /** 140 * Provides access to the tables appropriate for converting linear alpha 141 * values into gamma correcting alpha values when drawing the given color 142 * through the mask. The destination color will be approximated. 143 */ 144 PreBlend preBlend(SkColor color); 145 146private: 147 enum LuminanceBits { 148 kLuminanceBits_R = R_LUM_BITS, 149 kLuminanceBits_G = G_LUM_BITS, 150 kLuminanceBits_B = B_LUM_BITS, 151 kLuminanceBits_Max = B_LUM_BITS > (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS) 152 ? B_LUM_BITS 153 : (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS) 154 }; 155 uint8_t fGammaTables[1 << kLuminanceBits_Max][256]; 156 157 typedef SkRefCnt INHERITED; 158}; 159 160 161#define MacroComma , 162SK_DEFINE_INST_COUNT_TEMPLATE( 163 template <int R_LUM_BITS MacroComma int G_LUM_BITS MacroComma int B_LUM_BITS>, 164 SkTMaskGamma<R_LUM_BITS MacroComma G_LUM_BITS MacroComma B_LUM_BITS>); 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 */ 171template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskPreBlend { 172private: 173 SkTMaskPreBlend(SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>* parent, 174 const uint8_t* r, 175 const uint8_t* g, 176 const uint8_t* b) 177 : fParent(parent), fR(r), fG(g), fB(b) { 178 parent->ref(); 179 } 180 SkAutoTUnref<SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS> > fParent; 181 friend class SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>; 182public: 183 /** 184 * This copy contructor exists for correctness, but should never be called 185 * when return value optimization is enabled. 186 */ 187 SkTMaskPreBlend(const SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>& that) 188 : fParent(that.fParent.get()), fR(that.fR), fG(that.fG), fB(that.fB) { 189 fParent.get()->ref(); 190 } 191 ~SkTMaskPreBlend() { } 192 const uint8_t* fR; 193 const uint8_t* fG; 194 const uint8_t* fB; 195}; 196 197template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> 198SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS> 199SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>::preBlend(SkColor color) { 200 return SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>( 201 this, 202 fGammaTables[SkColorGetR(color) >> (8 - kLuminanceBits_Max)], 203 fGammaTables[SkColorGetG(color) >> (8 - kLuminanceBits_Max)], 204 fGammaTables[SkColorGetB(color) >> (8 - kLuminanceBits_Max)]); 205} 206 207///@{ 208/** 209 * If APPLY_LUT is false, returns component unchanged. 210 * If APPLY_LUT is true, returns lut[component]. 211 * @param APPLY_LUT whether or not the look-up table should be applied to component. 212 * @component the initial component. 213 * @lut a look-up table which transforms the component. 214 */ 215template<bool APPLY_LUT> static inline U8CPU sk_apply_lut_if(U8CPU component, const uint8_t*) { 216 return component; 217} 218template<> /*static*/ inline U8CPU sk_apply_lut_if<true>(U8CPU component, const uint8_t* lut) { 219 return lut[component]; 220} 221///@} 222 223#endif 224