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 */
18enum 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
45static const int kGrBlendEquationCnt = kLast_GrBlendEquation + 1;
46
47
48/**
49 * Coefficients for alpha-blending.
50 */
51enum 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
74static 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 */
82void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
83                                    GrColor srcColor,
84                                    GrColorComponentFlags srcColorFlags,
85                                    GrColor dstColor,
86                                    GrColorComponentFlags dstColorFlags,
87                                    GrColor* outColor,
88                                    GrColorComponentFlags* outFlags);
89
90template<GrBlendCoeff Coeff>
91struct 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
99inline 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
111template<GrBlendCoeff Coeff>
112struct 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
120inline 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
133template<GrBlendCoeff Coeff>
134struct 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
142inline 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
155template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
156struct 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
163template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
164struct 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
171template<GrBlendEquation Equation>
172struct GrTBlendEquationIsAdvanced : skstd::bool_constant<Equation >= kFirstAdvancedGrBlendEquation> {};
173
174#define GR_BLEND_EQUATION_IS_ADVANCED(EQUATION) \
175    GrTBlendEquationIsAdvanced<EQUATION>::value
176
177inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
178    return equation >= kFirstAdvancedGrBlendEquation;
179}
180
181
182template<GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
183struct 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 */
216template<GrBlendEquation Equation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
217struct 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