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