1 
2 /*
3  * Copyright 2013 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 #ifndef GrBlend_DEFINED
10 #define GrBlend_DEFINED
11 
12 #include "GrColor.h"
13 #include "../private/SkTLogic.h"
14 
15 /**
16  * Equations for alpha-blending.
17  */
18 enum GrBlendEquation {
19     // Basic blend equations.
20     kAdd_GrBlendEquation,             //<! Cs*S + Cd*D
21     kSubtract_GrBlendEquation,        //<! Cs*S - Cd*D
22     kReverseSubtract_GrBlendEquation, //<! Cd*D - Cs*S
23 
24     // Advanced blend equations. These are described in the SVG and PDF specs.
25     kScreen_GrBlendEquation,
26     kOverlay_GrBlendEquation,
27     kDarken_GrBlendEquation,
28     kLighten_GrBlendEquation,
29     kColorDodge_GrBlendEquation,
30     kColorBurn_GrBlendEquation,
31     kHardLight_GrBlendEquation,
32     kSoftLight_GrBlendEquation,
33     kDifference_GrBlendEquation,
34     kExclusion_GrBlendEquation,
35     kMultiply_GrBlendEquation,
36     kHSLHue_GrBlendEquation,
37     kHSLSaturation_GrBlendEquation,
38     kHSLColor_GrBlendEquation,
39     kHSLLuminosity_GrBlendEquation,
40 
41     kFirstAdvancedGrBlendEquation = kScreen_GrBlendEquation,
42     kLast_GrBlendEquation = kHSLLuminosity_GrBlendEquation
43 };
44 
45 static const int kGrBlendEquationCnt = kLast_GrBlendEquation + 1;
46 
47 
48 /**
49  * Coefficients for alpha-blending.
50  */
51 enum GrBlendCoeff {
52     kZero_GrBlendCoeff,    //<! 0
53     kOne_GrBlendCoeff,     //<! 1
54     kSC_GrBlendCoeff,      //<! src color
55     kISC_GrBlendCoeff,     //<! one minus src color
56     kDC_GrBlendCoeff,      //<! dst color
57     kIDC_GrBlendCoeff,     //<! one minus dst color
58     kSA_GrBlendCoeff,      //<! src alpha
59     kISA_GrBlendCoeff,     //<! one minus src alpha
60     kDA_GrBlendCoeff,      //<! dst alpha
61     kIDA_GrBlendCoeff,     //<! one minus dst alpha
62     kConstC_GrBlendCoeff,  //<! constant color
63     kIConstC_GrBlendCoeff, //<! one minus constant color
64     kConstA_GrBlendCoeff,  //<! constant color alpha
65     kIConstA_GrBlendCoeff, //<! one minus constant color alpha
66     kS2C_GrBlendCoeff,
67     kIS2C_GrBlendCoeff,
68     kS2A_GrBlendCoeff,
69     kIS2A_GrBlendCoeff,
70 
71     kLast_GrBlendCoeff = kIS2A_GrBlendCoeff
72 };
73 
74 static const int kGrBlendCoeffCnt = kLast_GrBlendCoeff + 1;
75 
76 /**
77  * Given a known blend equation in the form of srcCoeff * srcColor + dstCoeff * dstColor where
78  * there may be partial knowledge of the srcColor and dstColor component values, determine what
79  * components of the blended output color are known. Coeffs must not refer to the constant or
80  * secondary src color.
81  */
82 void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
83                                     GrColor srcColor,
84                                     GrColorComponentFlags srcColorFlags,
85                                     GrColor dstColor,
86                                     GrColorComponentFlags dstColorFlags,
87                                     GrColor* outColor,
88                                     GrColorComponentFlags* outFlags);
89 
90 template<GrBlendCoeff Coeff>
91 struct GrTBlendCoeffRefsSrc : skstd::bool_constant<kSC_GrBlendCoeff == Coeff ||
92                                                    kISC_GrBlendCoeff == Coeff ||
93                                                    kSA_GrBlendCoeff == Coeff ||
94                                                    kISA_GrBlendCoeff == Coeff> {};
95 
96 #define GR_BLEND_COEFF_REFS_SRC(COEFF) \
97     GrTBlendCoeffRefsSrc<COEFF>::value
98 
GrBlendCoeffRefsSrc(GrBlendCoeff coeff)99 inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
100     switch (coeff) {
101         case kSC_GrBlendCoeff:
102         case kISC_GrBlendCoeff:
103         case kSA_GrBlendCoeff:
104         case kISA_GrBlendCoeff:
105             return true;
106         default:
107             return false;
108     }
109 }
110 
111 template<GrBlendCoeff Coeff>
112 struct GrTBlendCoeffRefsDst : skstd::bool_constant<kDC_GrBlendCoeff == Coeff ||
113                                                    kIDC_GrBlendCoeff == Coeff ||
114                                                    kDA_GrBlendCoeff == Coeff ||
115                                                    kIDA_GrBlendCoeff == Coeff> {};
116 
117 #define GR_BLEND_COEFF_REFS_DST(COEFF) \
118     GrTBlendCoeffRefsDst<COEFF>::value
119 
GrBlendCoeffRefsDst(GrBlendCoeff coeff)120 inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) {
121     switch (coeff) {
122         case kDC_GrBlendCoeff:
123         case kIDC_GrBlendCoeff:
124         case kDA_GrBlendCoeff:
125         case kIDA_GrBlendCoeff:
126             return true;
127         default:
128             return false;
129     }
130 }
131 
132 
133 template<GrBlendCoeff Coeff>
134 struct GrTBlendCoeffRefsSrc2 : skstd::bool_constant<kS2C_GrBlendCoeff == Coeff ||
135                                                     kIS2C_GrBlendCoeff == Coeff ||
136                                                     kS2A_GrBlendCoeff == Coeff ||
137                                                     kIS2A_GrBlendCoeff == Coeff> {};
138 
139 #define GR_BLEND_COEFF_REFS_SRC2(COEFF) \
140     GrTBlendCoeffRefsSrc2<COEFF>::value
141 
GrBlendCoeffRefsSrc2(GrBlendCoeff coeff)142 inline bool GrBlendCoeffRefsSrc2(GrBlendCoeff coeff) {
143     switch (coeff) {
144         case kS2C_GrBlendCoeff:
145         case kIS2C_GrBlendCoeff:
146         case kS2A_GrBlendCoeff:
147         case kIS2A_GrBlendCoeff:
148             return true;
149         default:
150             return false;
151     }
152 }
153 
154 
155 template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
156 struct GrTBlendCoeffsUseSrcColor : skstd::bool_constant<kZero_GrBlendCoeff != SrcCoeff ||
157                                                         GR_BLEND_COEFF_REFS_SRC(DstCoeff)> {};
158 
159 #define GR_BLEND_COEFFS_USE_SRC_COLOR(SRC_COEFF, DST_COEFF) \
160     GrTBlendCoeffsUseSrcColor<SRC_COEFF, DST_COEFF>::value
161 
162 
163 template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
164 struct GrTBlendCoeffsUseDstColor : skstd::bool_constant<GR_BLEND_COEFF_REFS_DST(SrcCoeff) ||
165                                                         kZero_GrBlendCoeff != DstCoeff> {};
166 
167 #define GR_BLEND_COEFFS_USE_DST_COLOR(SRC_COEFF, DST_COEFF) \
168     GrTBlendCoeffsUseDstColor<SRC_COEFF, DST_COEFF>::value
169 
170 
171 template<GrBlendEquation Equation>
172 struct GrTBlendEquationIsAdvanced : skstd::bool_constant<Equation >= kFirstAdvancedGrBlendEquation> {};
173 
174 #define GR_BLEND_EQUATION_IS_ADVANCED(EQUATION) \
175     GrTBlendEquationIsAdvanced<EQUATION>::value
176 
GrBlendEquationIsAdvanced(GrBlendEquation equation)177 inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
178     return equation >= kFirstAdvancedGrBlendEquation;
179 }
180 
181 
182 template<GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
183 struct GrTBlendModifiesDst : skstd::bool_constant<
184     (kAdd_GrBlendEquation != BlendEquation && kReverseSubtract_GrBlendEquation != BlendEquation) ||
185      kZero_GrBlendCoeff != SrcCoeff ||
186      kOne_GrBlendCoeff != DstCoeff> {};
187 
188 #define GR_BLEND_MODIFIES_DST(EQUATION, SRC_COEFF, DST_COEFF) \
189     GrTBlendModifiesDst<EQUATION, SRC_COEFF, DST_COEFF>::value
190 
191 
192 /**
193  * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp)
194  *
195  * For "add" and "reverse subtract" the blend equation with f=coverage is:
196  *
197  *   D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
198  *      = f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
199  *
200  * (Let srcCoeff be negative for reverse subtract.) We can tweak alpha for coverage when the
201  * following relationship holds:
202  *
203  *   (f*S) * srcCoeff' + D * dstCoeff' == f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
204  *
205  * (Where srcCoeff' and dstCoeff' have any reference to S pre-multiplied by f.)
206  *
207  * It's easy to see this works for the src term as long as srcCoeff' == srcCoeff (meaning srcCoeff
208  * does not reference S). For the dst term, this will work as long as the following is true:
209  *|
210  *   dstCoeff' == f * dstCoeff + (1 - f)
211  *   dstCoeff' == 1 - f * (1 - dstCoeff)
212  *
213  * By inspection we can see this will work as long as dstCoeff has a 1, and any other term in
214  * dstCoeff references S.
215  */
216 template<GrBlendEquation Equation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
217 struct GrTBlendCanTweakAlphaForCoverage : skstd::bool_constant<
218     GR_BLEND_EQUATION_IS_ADVANCED(Equation) ||
219     ((kAdd_GrBlendEquation == Equation || kReverseSubtract_GrBlendEquation == Equation) &&
220       !GR_BLEND_COEFF_REFS_SRC(SrcCoeff) &&
221       (kOne_GrBlendCoeff == DstCoeff ||
222        kISC_GrBlendCoeff == DstCoeff ||
223        kISA_GrBlendCoeff == DstCoeff))> {};
224 
225 #define GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(EQUATION, SRC_COEFF, DST_COEFF) \
226     GrTBlendCanTweakAlphaForCoverage<EQUATION, SRC_COEFF, DST_COEFF>::value
227 
228 #endif
229