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