1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkMaskGamma.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,124 @@ 1.4 +/* 1.5 + * Copyright 2012 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkTypes.h" 1.12 + 1.13 +#include "SkColor.h" 1.14 +#include "SkFloatingPoint.h" 1.15 +#include "SkMaskGamma.h" 1.16 + 1.17 +class SkLinearColorSpaceLuminance : public SkColorSpaceLuminance { 1.18 + virtual SkScalar toLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luminance) const SK_OVERRIDE { 1.19 + SkASSERT(SK_Scalar1 == gamma); 1.20 + return luminance; 1.21 + } 1.22 + virtual SkScalar fromLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luma) const SK_OVERRIDE { 1.23 + SkASSERT(SK_Scalar1 == gamma); 1.24 + return luma; 1.25 + } 1.26 +}; 1.27 + 1.28 +class SkGammaColorSpaceLuminance : public SkColorSpaceLuminance { 1.29 + virtual SkScalar toLuma(SkScalar gamma, SkScalar luminance) const SK_OVERRIDE { 1.30 + return SkScalarPow(luminance, gamma); 1.31 + } 1.32 + virtual SkScalar fromLuma(SkScalar gamma, SkScalar luma) const SK_OVERRIDE { 1.33 + return SkScalarPow(luma, SkScalarInvert(gamma)); 1.34 + } 1.35 +}; 1.36 + 1.37 +class SkSRGBColorSpaceLuminance : public SkColorSpaceLuminance { 1.38 + virtual SkScalar toLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luminance) const SK_OVERRIDE { 1.39 + SkASSERT(0 == gamma); 1.40 + //The magic numbers are derived from the sRGB specification. 1.41 + //See http://www.color.org/chardata/rgb/srgb.xalter . 1.42 + if (luminance <= 0.04045f) { 1.43 + return luminance / 12.92f; 1.44 + } 1.45 + return SkScalarPow((luminance + 0.055f) / 1.055f, 1.46 + 2.4f); 1.47 + } 1.48 + virtual SkScalar fromLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luma) const SK_OVERRIDE { 1.49 + SkASSERT(0 == gamma); 1.50 + //The magic numbers are derived from the sRGB specification. 1.51 + //See http://www.color.org/chardata/rgb/srgb.xalter . 1.52 + if (luma <= 0.0031308f) { 1.53 + return luma * 12.92f; 1.54 + } 1.55 + return 1.055f * SkScalarPow(luma, SkScalarInvert(2.4f)) 1.56 + - 0.055f; 1.57 + } 1.58 +}; 1.59 + 1.60 +/*static*/ const SkColorSpaceLuminance& SkColorSpaceLuminance::Fetch(SkScalar gamma) { 1.61 + static SkLinearColorSpaceLuminance gSkLinearColorSpaceLuminance; 1.62 + static SkGammaColorSpaceLuminance gSkGammaColorSpaceLuminance; 1.63 + static SkSRGBColorSpaceLuminance gSkSRGBColorSpaceLuminance; 1.64 + 1.65 + if (0 == gamma) { 1.66 + return gSkSRGBColorSpaceLuminance; 1.67 + } else if (SK_Scalar1 == gamma) { 1.68 + return gSkLinearColorSpaceLuminance; 1.69 + } else { 1.70 + return gSkGammaColorSpaceLuminance; 1.71 + } 1.72 +} 1.73 + 1.74 +static float apply_contrast(float srca, float contrast) { 1.75 + return srca + ((1.0f - srca) * contrast * srca); 1.76 +} 1.77 + 1.78 +void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar contrast, 1.79 + const SkColorSpaceLuminance& srcConvert, SkScalar srcGamma, 1.80 + const SkColorSpaceLuminance& dstConvert, SkScalar dstGamma) { 1.81 + const float src = (float)srcI / 255.0f; 1.82 + const float linSrc = srcConvert.toLuma(srcGamma, src); 1.83 + //Guess at the dst. The perceptual inverse provides smaller visual 1.84 + //discontinuities when slight changes to desaturated colors cause a channel 1.85 + //to map to a different correcting lut with neighboring srcI. 1.86 + //See https://code.google.com/p/chromium/issues/detail?id=141425#c59 . 1.87 + const float dst = 1.0f - src; 1.88 + const float linDst = dstConvert.toLuma(dstGamma, dst); 1.89 + 1.90 + //Contrast value tapers off to 0 as the src luminance becomes white 1.91 + const float adjustedContrast = SkScalarToFloat(contrast) * linDst; 1.92 + 1.93 + //Remove discontinuity and instability when src is close to dst. 1.94 + //The value 1/256 is arbitrary and appears to contain the instability. 1.95 + if (fabs(src - dst) < (1.0f / 256.0f)) { 1.96 + float ii = 0.0f; 1.97 + for (int i = 0; i < 256; ++i, ii += 1.0f) { 1.98 + float rawSrca = ii / 255.0f; 1.99 + float srca = apply_contrast(rawSrca, adjustedContrast); 1.100 + table[i] = SkToU8(sk_float_round2int(255.0f * srca)); 1.101 + } 1.102 + } else { 1.103 + // Avoid slow int to float conversion. 1.104 + float ii = 0.0f; 1.105 + for (int i = 0; i < 256; ++i, ii += 1.0f) { 1.106 + // 'rawSrca += 1.0f / 255.0f' and even 1.107 + // 'rawSrca = i * (1.0f / 255.0f)' can add up to more than 1.0f. 1.108 + // When this happens the table[255] == 0x0 instead of 0xff. 1.109 + // See http://code.google.com/p/chromium/issues/detail?id=146466 1.110 + float rawSrca = ii / 255.0f; 1.111 + float srca = apply_contrast(rawSrca, adjustedContrast); 1.112 + SkASSERT(srca <= 1.0f); 1.113 + float dsta = 1.0f - srca; 1.114 + 1.115 + //Calculate the output we want. 1.116 + float linOut = (linSrc * srca + dsta * linDst); 1.117 + SkASSERT(linOut <= 1.0f); 1.118 + float out = dstConvert.fromLuma(dstGamma, linOut); 1.119 + 1.120 + //Undo what the blit blend will do. 1.121 + float result = (out - dst) / (src - dst); 1.122 + SkASSERT(sk_float_round2int(255.0f * result) <= 255); 1.123 + 1.124 + table[i] = SkToU8(sk_float_round2int(255.0f * result)); 1.125 + } 1.126 + } 1.127 +}