1// [Blend2D]
2// 2D Vector Graphics Powered by a JIT Compiler.
3//
4// [License]
5// Zlib - See LICENSE.md file in the package.
6
7#include "./blapi-build_p.h"
8#include "./blcompop_p.h"
9
10// ============================================================================
11// [BLCompOpInfo]
12// ============================================================================
13
14struct BLCompOpInfoGen {
15 #define F(VALUE) BL_COMP_OP_FLAG_##VALUE
16
17 static constexpr BLCompOpInfo value(size_t op) noexcept {
18 return BLCompOpInfo {
19 op == BL_COMP_OP_SRC_OVER ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
20 op == BL_COMP_OP_SRC_COPY ? F(TYPE_B) | 0 | 0 | F(SC) | F(SA) | 0 | 0 :
21 op == BL_COMP_OP_SRC_IN ? F(TYPE_B) | 0 | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_0) | 0 :
22 op == BL_COMP_OP_SRC_OUT ? F(TYPE_B) | 0 | F(DA) | F(SC) | F(SA) | 0 | 0 :
23 op == BL_COMP_OP_SRC_ATOP ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_0) | F(NOP_IF_SA_0) :
24 op == BL_COMP_OP_DST_OVER ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_1) | F(NOP_IF_SA_0) :
25 op == BL_COMP_OP_DST_COPY ? F(TYPE_C) | F(DC) | F(DA) | 0 | 0 | F(NOP) | F(NOP) :
26 op == BL_COMP_OP_DST_IN ? F(TYPE_B) | F(DC) | F(DA) | 0 | F(SA) | 0 | F(NOP_IF_SA_1) :
27 op == BL_COMP_OP_DST_OUT ? F(TYPE_A) | F(DC) | F(DA) | 0 | F(SA) | 0 | F(NOP_IF_SA_0) :
28 op == BL_COMP_OP_DST_ATOP ? F(TYPE_B) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | 0 :
29 op == BL_COMP_OP_XOR ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
30 op == BL_COMP_OP_CLEAR ? F(TYPE_C) | 0 | 0 | 0 | 0 | F(NOP_IF_DA_0) | 0 :
31
32 op == BL_COMP_OP_PLUS ? F(TYPE_C) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
33 op == BL_COMP_OP_MINUS ? F(TYPE_C) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
34 op == BL_COMP_OP_MULTIPLY ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | F(NOP_IF_DA_0) | F(NOP_IF_SA_0) :
35 op == BL_COMP_OP_SCREEN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
36 op == BL_COMP_OP_OVERLAY ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
37 op == BL_COMP_OP_DARKEN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
38 op == BL_COMP_OP_LIGHTEN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
39 op == BL_COMP_OP_COLOR_DODGE ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
40 op == BL_COMP_OP_COLOR_BURN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
41 op == BL_COMP_OP_LINEAR_BURN ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
42 op == BL_COMP_OP_LINEAR_LIGHT ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
43 op == BL_COMP_OP_PIN_LIGHT ? F(TYPE_C) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
44 op == BL_COMP_OP_HARD_LIGHT ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
45 op == BL_COMP_OP_SOFT_LIGHT ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
46 op == BL_COMP_OP_DIFFERENCE ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
47 op == BL_COMP_OP_EXCLUSION ? F(TYPE_A) | F(DC) | F(DA) | F(SC) | F(SA) | 0 | F(NOP_IF_SA_0) :
48
49 op == BL_COMP_OP_INTERNAL_ALPHA_SET ? F(TYPE_C) | 0 | 0 | 0 | 0 | F(NOP_IF_SA_1) | 0 :
50 op == BL_COMP_OP_INTERNAL_ALPHA_INV ? F(TYPE_C) | 0 | 0 | 0 | 0 | 0 | 0 : 0
51 };
52 }
53
54 #undef F
55};
56
57const BLLookupTable<BLCompOpInfo, BL_COMP_OP_INTERNAL_COUNT> blCompOpInfo =
58 blLookupTable<BLCompOpInfo, BL_COMP_OP_INTERNAL_COUNT, BLCompOpInfoGen>();
59
60// ============================================================================
61// [BLCompOpSimplifyInfo]
62// ============================================================================
63
64struct BLCompOpSimplifyInfoGen {
65 // Simplify formats as we work with them here a lot.
66 enum Format : uint32_t {
67 NONE = BL_FORMAT_NONE,
68 A8 = BL_FORMAT_A8,
69 PRGB32 = BL_FORMAT_PRGB32,
70 ZERO32 = BL_FORMAT_ZERO32,
71 XRGB32 = BL_FORMAT_XRGB32,
72 FRGB32 = BL_FORMAT_FRGB32
73 };
74
75 enum CompOp : uint32_t {
76 SrcOver = BL_COMP_OP_SRC_OVER,
77 SrcCopy = BL_COMP_OP_SRC_COPY,
78 SrcIn = BL_COMP_OP_SRC_IN,
79 SrcOut = BL_COMP_OP_SRC_OUT,
80 SrcAtop = BL_COMP_OP_SRC_ATOP,
81 DstOver = BL_COMP_OP_DST_OVER,
82 DstCopy = BL_COMP_OP_DST_COPY,
83 DstIn = BL_COMP_OP_DST_IN,
84 DstOut = BL_COMP_OP_DST_OUT,
85 DstAtop = BL_COMP_OP_DST_ATOP,
86 Xor = BL_COMP_OP_XOR,
87 Clear = BL_COMP_OP_CLEAR,
88 Plus = BL_COMP_OP_PLUS,
89 Minus = BL_COMP_OP_MINUS,
90 Multiply = BL_COMP_OP_MULTIPLY,
91 Screen = BL_COMP_OP_SCREEN,
92 Overlay = BL_COMP_OP_OVERLAY,
93 Darken = BL_COMP_OP_DARKEN,
94 Lighten = BL_COMP_OP_LIGHTEN,
95 ColorDodge = BL_COMP_OP_COLOR_DODGE,
96 ColorBurn = BL_COMP_OP_COLOR_BURN,
97 LinearBurn = BL_COMP_OP_LINEAR_BURN,
98 LinearLight = BL_COMP_OP_LINEAR_LIGHT,
99 PinLight = BL_COMP_OP_PIN_LIGHT,
100 HardLight = BL_COMP_OP_HARD_LIGHT,
101 SoftLight = BL_COMP_OP_SOFT_LIGHT,
102 Difference = BL_COMP_OP_DIFFERENCE,
103 Exclusion = BL_COMP_OP_EXCLUSION
104 };
105
106 // Legend:
107 //
108 // - Sca - Source color, premultiplied: `Sc * Sa`.
109 // - Sc - Source color.
110 // - Sa - Source alpha.
111 //
112 // - Dca - Destination color, premultiplied: `Dc * Da`.
113 // - Dc - Destination color.
114 // - Da - Destination alpha.
115 //
116 // - Dca' - Resulting color, premultiplied.
117 // - Da' - Resulting alpha.
118 //
119 // - m - Mask (if used).
120 //
121 // Blending function F(Sc, Dc) is used in the following way if destination
122 // or source contains alpha channel (otherwise it's assumed to be `1.0`):
123 //
124 // - Dca' = Func(Sc, Dc) * Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
125 // - Da' = Da + Sa.(1 - Da)
126
127 static constexpr BLCompOpSimplifyInfo makeOp(uint32_t compOp, uint32_t d, uint32_t s) noexcept {
128 return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_NONE), uint8_t(d), uint8_t(s) };
129 }
130
131 static constexpr BLCompOpSimplifyInfo transparent(uint32_t compOp, uint32_t d, uint32_t s) noexcept {
132 return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_TRANSPARENT), uint8_t(d), uint8_t(s) };
133 }
134
135 static constexpr BLCompOpSimplifyInfo opaqueBlack(uint32_t compOp, uint32_t d, uint32_t s) noexcept {
136 return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_OPAQUE_BLACK), uint8_t(d), uint8_t(s) };
137 }
138
139 static constexpr BLCompOpSimplifyInfo opaqueWhite(uint32_t compOp, uint32_t d, uint32_t s) noexcept {
140 return BLCompOpSimplifyInfo { uint8_t(compOp), uint8_t(BL_COMP_OP_SOLID_ID_OPAQUE_WHITE), uint8_t(d), uint8_t(s) };
141 }
142
143 // Clear
144 // -----
145 //
146 // [Clear PRGBxPRGB]
147 // Dca' = 0 Dca' = Dca.(1 - m)
148 // Da' = 0 Da' = Da .(1 - m)
149 //
150 // [Clear XRGBxPRGB]
151 // Dc' = 0 Dc' = Dca.(1 - m)
152 //
153 // [Clear PRGBxXRGB] ~= [Clear PRGBxPRGB]
154 // [Clear XRGBxXRGB] ~= [Clear XRGBxPRGB]
155 static constexpr BLCompOpSimplifyInfo clear(uint32_t d, uint32_t s) noexcept {
156 return d == PRGB32 ? transparent(SrcCopy, PRGB32, PRGB32) :
157 d == XRGB32 ? opaqueBlack(SrcCopy, PRGB32, PRGB32) : makeOp(Clear, d, s);
158 }
159
160 // SrcCopy
161 // -------
162 //
163 // [Src PRGBxPRGB]
164 // Dca' = Sca Dca' = Sca.m + Dca.(1 - m)
165 // Da' = Sa Da' = Sa .m + Da .(1 - m)
166 //
167 // [Src PRGBxXRGB] ~= [Src PRGBxPRGB]
168 // Dca' = Sc Dca' = Sc.m + Dca.(1 - m)
169 // Da' = 1 Da' = 1 .m + Da .(1 - m)
170 //
171 // [Src XRGBxPRGB] ~= [Src PRGBxPRGB]
172 // Dc' = Sca Dc' = Sca.m + Dc.(1 - m)
173 //
174 // [Src XRGBxXRGB] ~= [Src PRGBxPRGB]
175 // Dc' = Sc Dc' = Sc.m + Dc.(1 - m)
176 static constexpr BLCompOpSimplifyInfo srcCopy(uint32_t d, uint32_t s) noexcept {
177 return d == PRGB32 && s == ZERO32 ? makeOp(SrcCopy, PRGB32, PRGB32) :
178 d == PRGB32 && s == FRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) :
179 d == XRGB32 && s == PRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) :
180 d == XRGB32 && s == ZERO32 ? makeOp(SrcCopy, PRGB32, PRGB32) :
181 d == XRGB32 && s == XRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) :
182 d == XRGB32 && s == FRGB32 ? makeOp(SrcCopy, PRGB32, PRGB32) : makeOp(SrcCopy, d, s);
183 }
184
185 // DstCopy
186 // -------
187 //
188 // [DstCopy ANYxANY]
189 // Dca' = Dca
190 // Da = Da
191 static constexpr BLCompOpSimplifyInfo dstCopy(uint32_t d, uint32_t s) noexcept {
192 return transparent(DstCopy, d, s);
193 }
194
195 // SrcOver
196 // -------
197 //
198 // [SrcOver PRGBxPRGB]
199 // Dca' = Sca + Dca.(1 - Sa) Dca' = Sca.m + Dca.(1 - Sa.m)
200 // Da' = Sa + Da .(1 - Sa) Da' = Sa .m + Da .(1 - Sa.m)
201 //
202 // [SrcOver PRGBxXRGB] ~= [Src PRGBxPRGB]
203 // Dca' = Sc Dca' = Sc.m + Dca.(1 - m)
204 // Da' = 1 Da' = 1 .m + Da .(1 - m)
205 //
206 // [SrcOver XRGBxPRGB] ~= [SrcOver PRGBxPRGB]
207 // Dc' = Sca + Dc.(1 - Sa ) Dc' = Sca.m + Dc.(1 - Sa.m)
208 //
209 // [SrcOver XRGBxXRGB] ~= [Src PRGBxPRGB]
210 // Dc' = Sc Dc' = Sc.m + Dc.(1 - m)
211 static constexpr BLCompOpSimplifyInfo srcOver(uint32_t d, uint32_t s) noexcept {
212 return d == PRGB32 && s == ZERO32 ? dstCopy(PRGB32, PRGB32) :
213 d == PRGB32 && s == XRGB32 ? srcCopy(PRGB32, XRGB32) :
214 d == PRGB32 && s == FRGB32 ? srcCopy(PRGB32, FRGB32) :
215 d == XRGB32 && s == PRGB32 ? srcOver(PRGB32, PRGB32) :
216 d == XRGB32 && s == ZERO32 ? dstCopy(PRGB32, PRGB32) :
217 d == XRGB32 && s == XRGB32 ? srcCopy(PRGB32, XRGB32) :
218 d == XRGB32 && s == FRGB32 ? makeOp(SrcOver, PRGB32, FRGB32) : makeOp(SrcOver, d, s);
219 }
220
221 // DstOver
222 // -------
223 //
224 // [DstOver PRGBxPRGB]
225 // Dca' = Dca + Sca.(1 - Da) Dca' = Dca + Sca.m.(1 - Da)
226 // Da' = Da + Sa .(1 - Da) Da' = Da + Sa .m.(1 - Da)
227 //
228 // [DstOver PRGBxXRGB] ~= [DstOver PRGBxPRGB]
229 // Dca' = Dca + Sc.(1 - Da) Dca' = Dca + Sc.m.(1 - Da)
230 // Da' = Da + 1 .(1 - Da) Da' = Da + 1 .m.(1 - Da)
231 //
232 // [DstOver XRGBxPRGB] ~= [Dst]
233 // Dc' = Dc
234 //
235 // [DstOver XRGBxXRGB] ~= [Dst]
236 // Dc' = Dc
237 static constexpr BLCompOpSimplifyInfo dstOver(uint32_t d, uint32_t s) noexcept {
238 return d == PRGB32 && s == ZERO32 ? dstCopy(PRGB32, PRGB32) :
239 d == PRGB32 && s == FRGB32 ? dstOver(PRGB32, PRGB32) :
240 d == XRGB32 ? dstCopy(d, s) : makeOp(DstOver, d, s);
241 }
242
243 // SrcIn
244 // -----
245 //
246 // [SrcIn PRGBxPRGB]
247 // Dca' = Sca.Da Dca' = Sca.Da.m + Dca.(1 - m)
248 // Da' = Sa .Da Da' = Sa .Da.m + Da .(1 - m)
249 //
250 // [SrcIn PRGBxXRGB] ~= [SrcIn PRGBxPRGB]
251 // Dca' = Sc.Da Dca' = Sc.Da.m + Dca.(1 - m)
252 // Da' = 1 .Da Da' = 1 .Da.m + Da .(1 - m)
253 //
254 // [SrcIn XRGBxPRGB]
255 // Dc' = Sca Dc' = Sca.m + Dc.(1 - m)
256 //
257 // [SrcIn XRGBxXRGB] ~= [SrcCopy XRGBxXRGB]
258 // Dc' = Sc Dc' = Sc.m + Dc.(1 - m)
259 static constexpr BLCompOpSimplifyInfo srcIn(uint32_t d, uint32_t s) noexcept {
260 return d == PRGB32 && s == ZERO32 ? srcIn(PRGB32, PRGB32) :
261 d == PRGB32 && s == FRGB32 ? srcIn(PRGB32, PRGB32) :
262 d == XRGB32 ? srcCopy(d, s) : makeOp(SrcIn, d, s);
263 }
264
265 // DstIn
266 // -----
267 //
268 // [DstIn PRGBxPRGB]
269 // Dca' = Dca.Sa Dca' = Dca.Sa.m + Dca.(1 - m)
270 // Da' = Da .Sa Da' = Da .Sa.m + Da .(1 - m)
271 //
272 // [DstIn PRGBxXRGB] ~= [Dst]
273 // Dca' = Dca
274 // Da' = Da
275 //
276 // [DstIn XRGBxPRGB]
277 // Dc' = Dc.Sa Dc' = Dc.Sa.m + Dc.(1 - m)
278 //
279 // [DstIn XRGBxXRGB] ~= [Dst]
280 // Dc' = Dc
281 static constexpr BLCompOpSimplifyInfo dstIn(uint32_t d, uint32_t s) noexcept {
282 return d == PRGB32 && s == ZERO32 ? srcCopy(d, s) :
283 d == PRGB32 && s == XRGB32 ? dstCopy(d, s) :
284 d == PRGB32 && s == FRGB32 ? dstCopy(d, s) :
285 d == XRGB32 && s == PRGB32 ? dstIn(PRGB32, PRGB32) :
286 d == XRGB32 && s == ZERO32 ? dstIn(PRGB32, FRGB32) :
287 d == XRGB32 && s == FRGB32 ? dstCopy(d, s) :
288 d == XRGB32 && s == XRGB32 ? dstCopy(d, s) : makeOp(DstIn, d, s);
289 }
290
291 // SrcOut
292 // ------
293 //
294 // [SrcOut PRGBxPRGB]
295 // Dca' = Sca.(1 - Da) Dca' = Sca.m.(1 - Da) + Dca.(1 - m)
296 // Da' = Sa .(1 - Da) Da' = Sa .m.(1 - Da) + Da .(1 - m)
297 //
298 // [SrcOut PRGBxXRGB] ~= [SrcOut PRGBxPRGB]
299 // Dca' = Sc.(1 - Da) Dca' = Sc.m.(1 - Da) + Dca.(1 - m)
300 // Da' = 1 .(1 - Da) Da' = 1 .m.(1 - Da) + Da .(1 - m)
301 //
302 // [SrcOut XRGBxPRGB] ~= [Clear XRGBxPRGB]
303 // Dc' = 0 Dc' = Dc.(1 - m)
304 //
305 // [SrcOut XRGBxXRGB] ~= [Clear XRGBxPRGB]
306 // Dc' = 0 Dc' = Dc.(1 - m)
307 static constexpr BLCompOpSimplifyInfo srcOut(uint32_t d, uint32_t s) noexcept {
308 return d == PRGB32 && s == ZERO32 ? clear(d, s) :
309 d == PRGB32 && s == FRGB32 ? srcOut(PRGB32, PRGB32) :
310 d == XRGB32 ? clear(d, s) : makeOp(SrcOut, d, s);
311 }
312
313 // DstOut
314 // ------
315 //
316 // [DstOut PRGBxPRGB]
317 // Dca' = Dca.(1 - Sa) Dca' = Dca.(1 - Sa.m)
318 // Da' = Da .(1 - Sa) Da' = Da .(1 - Sa.m)
319 //
320 // [DstOut PRGBxXRGB] ~= [Clear PRGBxPRGB]
321 // Dca' = 0
322 // Da' = 0
323 //
324 // [DstOut XRGBxPRGB]
325 // Dc' = Dc.(1 - Sa) Dc' = Dc.(1 - Sa.m)
326 //
327 // [DstOut XRGBxXRGB] ~= [Clear XRGBxPRGB]
328 // Dc' = 0
329 static constexpr BLCompOpSimplifyInfo dstOut(uint32_t d, uint32_t s) noexcept {
330 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
331 d == PRGB32 && s == FRGB32 ? clear(d, s) :
332 d == PRGB32 && s == XRGB32 ? clear(d, s) :
333 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
334 d == XRGB32 && s == FRGB32 ? clear(d, s) :
335 d == XRGB32 && s == XRGB32 ? clear(d, s) : makeOp(DstOut, d, s);
336 }
337
338 // SrcAtop
339 // -------
340 //
341 // [SrcAtop PRGBxPRGB]
342 // Dca' = Sca.Da + Dca.(1 - Sa) Dca' = Sca.Da.m + Dca.(1 - Sa.m)
343 // Da' = Sa .Da + Da .(1 - Sa) = Da Da' = Sa .Da.m + Da .(1 - Sa.m) = Da
344 //
345 // [SrcAtop PRGBxXRGB] ~= [SrcIn PRGBxPRGB]
346 // Dca' = Sc.Da Dca' = Sc.Da.m + Dca.(1 - m)
347 // Da' = 1 .Da Da' = 1 .Da.m + Da .(1 - m)
348 //
349 // [SrcAtop XRGBxPRGB] ~= [SrcOver PRGBxPRGB]
350 // Dc' = Sca + Dc.(1 - Sa) Dc' = Sca.m + Dc.(1 - Sa.m)
351 //
352 // [SrcAtop XRGBxXRGB] ~= [Src PRGBxPRGB]
353 // Dc' = Sc Dc' = Sc.m + Dc.(1 - m)
354 static constexpr BLCompOpSimplifyInfo srcAtop(uint32_t d, uint32_t s) noexcept {
355 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
356 d == PRGB32 && s == FRGB32 ? srcIn(d, s) :
357 d == PRGB32 && s == XRGB32 ? srcIn(d, s) :
358 d == XRGB32 && s == PRGB32 ? srcOver(d, s) :
359 d == XRGB32 && s == ZERO32 ? srcOver(d, s) :
360 d == XRGB32 && s == FRGB32 ? srcCopy(d, s) :
361 d == XRGB32 && s == XRGB32 ? srcCopy(d, s) : makeOp(SrcAtop, d, s);
362 }
363
364 // DstAtop
365 // -------
366 //
367 // [DstAtop PRGBxPRGB]
368 // Dca' = Dca.Sa + Sca.(1 - Da) Dca' = Dca.(1 - m.(1 - Sa)) + Sca.m.(1 - Da)
369 // Da' = Da .Sa + Sa .(1 - Da) = Sa Da' = Da .(1 - m.(1 - Sa)) + Sa .m.(1 - Da)
370 //
371 // [DstAtop PRGBxXRGB] ~= [DstOver PRGBxPRGB]
372 // Dca' = Dca + Sc.(1 - Da) Dca' = Dca + Sc.m.(1 - Da)
373 // Da' = Da + 1 .(1 - Da) = 1 Da' = Da + 1 .m.(1 - Da)
374 //
375 // [DstAtop XRGBxPRGB] ~= [DstIn XRGBxPRGB]
376 // Dc' = Dc.Sa Dc' = Dc.(1 - m.(1 - Sa)) = Dc.(1 - m) + Dc.Sa.m
377 //
378 // [DstAtop XRGBxXRGB] ~= [Dst]
379 // Dc' = Dc
380 static constexpr BLCompOpSimplifyInfo dstAtop(uint32_t d, uint32_t s) noexcept {
381 return d == PRGB32 && s == ZERO32 ? clear(d, s) :
382 d == PRGB32 && s == FRGB32 ? dstOver(d, s) :
383 d == PRGB32 && s == XRGB32 ? dstOver(d, s) :
384 d == XRGB32 && s == PRGB32 ? dstIn(d, s) :
385 d == XRGB32 && s == ZERO32 ? clear(d, s) :
386 d == XRGB32 && s == FRGB32 ? dstCopy(d, s) :
387 d == XRGB32 && s == XRGB32 ? dstCopy(d, s) : makeOp(DstAtop, d, s);
388 }
389
390 // Xor
391 // ---
392 //
393 // [Xor PRGBxPRGB]
394 // Dca' = Dca.(1 - Sa) + Sca.(1 - Da) Dca' = Dca.(1 - Sa.m) + Sca.m.(1 - Da)
395 // Da' = Da .(1 - Sa) + Sa .(1 - Da) Da' = Da .(1 - Sa.m) + Sa .m.(1 - Da)
396 //
397 // [Xor PRGBxXRGB] ~= [SrcOut PRGBxPRGB]
398 // Dca' = Sca.(1 - Da) Dca' = Sca.m.(1 - Da) + Dca.(1 - m)
399 // Da' = 1 .(1 - Da) Da' = 1 .m.(1 - Da) + Da .(1 - m)
400 //
401 // [Xor XRGBxPRGB] ~= [DstOut XRGBxPRGB]
402 // Dc' = Dc.(1 - Sa) Dc' = Dc.(1 - Sa.m)
403 //
404 // [Xor XRGBxXRGB] ~= [Clear XRGBxPRGB]
405 // Dc' = 0 Dc' = Dc.(1 - m)
406 static constexpr BLCompOpSimplifyInfo xor_(uint32_t d, uint32_t s) noexcept {
407 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
408 d == PRGB32 && s == FRGB32 ? srcOut(d, s) :
409 d == PRGB32 && s == XRGB32 ? srcOut(d, s) :
410 d == XRGB32 && s == PRGB32 ? dstOut(d, s) :
411 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
412 d == XRGB32 && s == FRGB32 ? clear(d, s) :
413 d == XRGB32 && s == XRGB32 ? clear(d, s) : makeOp(Xor, d, s);
414 }
415
416 // Plus
417 // ----
418 //
419 // [Plus PRGBxPRGB]
420 // Dca' = Clamp(Dca + Sca) Dca' = Clamp(Dca + Sca.m)
421 // Da' = Clamp(Da + Sa ) Da' = Clamp(Da + Sa .m)
422 //
423 // [Plus PRGBxXRGB] ~= [Plus PRGBxPRGB]
424 // Dca' = Clamp(Dca + Sc) Dca' = Clamp(Dca + Sc.m)
425 // Da' = Clamp(Da + 1 ) Da' = Clamp(Da + 1 .m)
426 //
427 // [Plus XRGBxPRGB] ~= [Plus PRGBxPRGB]
428 // Dc' = Clamp(Dc + Sca) Dc' = Clamp(Dc + Sca.m)
429 //
430 // [Plus XRGBxXRGB] ~= [Plus PRGBxPRGB]
431 // Dc' = Clamp(Dc + Sc) Dc' = Clamp(Dc + Sc.m)
432 static constexpr BLCompOpSimplifyInfo plus(uint32_t d, uint32_t s) noexcept {
433 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
434 d == PRGB32 && s == FRGB32 ? plus(PRGB32, PRGB32) :
435 d == XRGB32 && s == PRGB32 ? plus(PRGB32, PRGB32) :
436 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
437 d == XRGB32 && s == FRGB32 ? plus(PRGB32, PRGB32) :
438 d == XRGB32 && s == XRGB32 ? plus(PRGB32, PRGB32) : makeOp(Plus, d, s);
439 }
440
441 // Minus
442 // -----
443 //
444 // [Minus PRGBxPRGB]
445 // Dca' = Clamp(Dca - Sca) Dca' = Clamp(Dca - Sca).m + Dca.(1 - m)
446 // Da' = Da + Sa.(1 - Da) Da' = Da + Sa.m(1 - Da)
447 //
448 // [Minus PRGBxXRGB] ~= [Minus PRGBxPRGB]
449 // Dca' = Clamp(Dca - Sc) Dca' = Clamp(Dca - Sc).m + Dca.(1 - m)
450 // Da' = Da + 1.(1 - Da) = 1 Da' = Da + 1.m(1 - Da)
451 //
452 // [Minus XRGBxPRGB]
453 // Dc' = Clamp(Dc - Sca) Dc' = Clamp(Dc - Sca).m + Dc.(1 - m)
454 //
455 // [Minus XRGBxXRGB] ~= [Minus XRGBxPRGB]
456 // Dc' = Clamp(Dc - Sc) Dc' = Clamp(Dc - Sc).m + Dc.(1 - m)
457 //
458 // NOTE:
459 // `Clamp(a - b)` == `Max(a - b, 0)` == `1 - Min(1 - a + b, 1)`
460 static constexpr BLCompOpSimplifyInfo minus(uint32_t d, uint32_t s) noexcept {
461 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
462 d == PRGB32 && s == FRGB32 ? minus(PRGB32, PRGB32) :
463 d == XRGB32 && s == PRGB32 ? minus(PRGB32, PRGB32) :
464 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
465 d == XRGB32 && s == FRGB32 ? minus(PRGB32, PRGB32) :
466 d == XRGB32 && s == XRGB32 ? minus(PRGB32, PRGB32) : makeOp(Minus, d, s);
467 }
468
469 // Multiply
470 // --------
471 //
472 // [Multiply PRGBxPRGB]
473 // Dca' = Dca.(Sca + 1 - Sa) + Sca.(1 - Da)
474 // Da' = Da .(Sa + 1 - Sa) + Sa .(1 - Da) = Da + Sa.(1 - Da)
475 //
476 // Dca' = Dca.(Sca.m + 1 - Sa.m) + Sca.m(1 - Da)
477 // Da' = Da .(Sa .m + 1 - Sa.m) + Sa .m(1 - Da) = Da + Sa.m(1 - Da)
478 //
479 // [Multiply PRGBxXRGB]
480 // Dca' = Sc.(Dca + 1 - Da)
481 // Da' = 1 .(Da + 1 - Da) = 1
482 //
483 // Dca' = Dca.(Sc.m + 1 - 1.m) + Sc.m(1 - Da)
484 // Da' = Da .(1 .m + 1 - 1.m) + 1 .m(1 - Da) = Da + Sa.m(1 - Da)
485 //
486 // [Multiply XRGBxPRGB]
487 // Dc' = Dc.(Sca + 1 - Sa )
488 // Dc' = Dc.(Sca.m + 1 - Sa.m)
489 //
490 // [Multiply XRGBxXRGB]
491 // Dc' = Dc.(Sc + 1 - 1 )
492 // Dc' = Dc.(Sc.m + 1 - 1.m)
493 static constexpr BLCompOpSimplifyInfo multiply(uint32_t d, uint32_t s) noexcept {
494 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
495 d == PRGB32 && s == FRGB32 ? minus(PRGB32, XRGB32) :
496 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
497 d == XRGB32 && s == FRGB32 ? minus(XRGB32, XRGB32) : makeOp(Multiply, d, s);
498 }
499
500 // Screen
501 // ------
502 //
503 // [Screen PRGBxPRGB]
504 // Dca' = Dca + Sca.(1 - Dca)
505 // Da' = Da + Sa .(1 - Da )
506 //
507 // Dca' = Dca + Sca.m.(1 - Dca)
508 // Da' = Da + Sa .m.(1 - Da )
509 //
510 // [Screen PRGBxXRGB] ~= [Screen PRGBxPRGB]
511 // Dca' = Dca + Sc.(1 - Dca)
512 // Da' = Da + 1 .(1 - Da )
513 //
514 // Dca' = Dca + Sc.m.(1 - Dca)
515 // Da' = Da + 1 .m.(1 - Da )
516 //
517 // [Screen XRGBxPRGB] ~= [Screen PRGBxPRGB]
518 // Dc' = Dc + Sca .(1 - Dca)
519 // Dc' = Dc + Sca.m.(1 - Dca)
520 //
521 // [Screen PRGBxPRGB] ~= [Screen PRGBxPRGB]
522 // Dc' = Dc + Sc .(1 - Dc)
523 // Dc' = Dc + Sc.m.(1 - Dc)
524 static constexpr BLCompOpSimplifyInfo screen(uint32_t d, uint32_t s) noexcept {
525 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
526 d == PRGB32 && s == FRGB32 ? screen(PRGB32, PRGB32) :
527 d == XRGB32 && s == PRGB32 ? screen(PRGB32, PRGB32) :
528 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
529 d == XRGB32 && s == FRGB32 ? screen(PRGB32, PRGB32) :
530 d == XRGB32 && s == XRGB32 ? screen(PRGB32, XRGB32) : makeOp(Screen, d, s);
531 }
532
533 // Overlay
534 // -------
535 //
536 // [Overlay PRGBxPRGB]
537 // if (2.Dca < Da)
538 // Dca' = Dca + Sca - (Dca.Sa + Sca.Da - 2.Sca.Dca)
539 // Da' = Da + Sa - Sa.Da
540 // else
541 // Dca' = Dca + Sca + (Dca.Sa + Sca.Da - 2.Sca.Dca) - Sa.Da
542 // Da' = Da + Sa - Sa.Da
543 //
544 // [Overlay PRGBxXRGB]
545 // if (2.Dca - Da < 0)
546 // Dca' = Sc.(2.Dca - Da + 1)
547 // Da' = 1
548 // else
549 // Dca' = 2.Dca - Da - Sc.(1 - (2.Dca - Da))
550 // Da' = 1
551 //
552 // [Overlay XRGBxPRGB]
553 // if (2.Dca < Da)
554 // Dc' = Dc - (Dc.Sa - 2.Sca.Dc)
555 // else
556 // Dc' = Dc + 2.Sca - Sa + (Dca.Sa - 2.Sca.Dc)
557 //
558 // [Overlay XRGBxXRGB]
559 // if (2.Dc - 1 < 0)
560 // Dc' = 2.Dc.Sc
561 // else
562 // Dc' = 2.(Dc + Sc) - 2.Sc.Dc - 1
563 static constexpr BLCompOpSimplifyInfo overlay(uint32_t d, uint32_t s) noexcept {
564 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
565 d == PRGB32 && s == FRGB32 ? overlay(PRGB32, XRGB32) :
566 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
567 d == XRGB32 && s == FRGB32 ? overlay(XRGB32, XRGB32) : makeOp(Screen, d, s);
568 }
569
570 // Darken
571 // ------
572 //
573 // [Darken PRGBxPRGB]
574 // Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
575 // Da' = min(Sa .Da, Da .Sa) + Sa .(1 - Da) + Da .(1 - Sa)
576 // = Sa + Da - Sa.Da
577 //
578 // Dca' = min(Sca.m.Da, Dca.Sa.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
579 // Da' = min(Sa .m.Da, Da .Sa.m) + Sa .m.(1 - Da) + Da .(1 - Sa.m)
580 // = Sa.m + Da - Sa.m.Da
581 //
582 // [Darken PRGBxXRGB]
583 // Dca' = min(Sc.Da, Dca) + Sc.(1 - Da)
584 // Da' = min(1 .Da, Da ) + 1 .(1 - Da)
585 // = Sa + Da - Sa.Da
586 //
587 // Dca' = min(Sc.m.Da, Dca.m) + Sc.m.(1 - Da) + Dca.(1 - 1.m)
588 // Da' = min(1 .m.Da, Da .m) + 1 .m.(1 - Da) + Da .(1 - 1.m)
589 // = 1.m + Da - 1.m.Da
590 //
591 // [Darken XRGBxPRGB]
592 // Dc' = min(Sca , Dc.Sa ) + Dc.(1 - Sa )
593 // Dc' = min(Sca.m, Dc.Sa.m) + Dc.(1 - Sa.m)
594 //
595 // [Darken XRGBxXRGB]
596 // Dc' = min(Sc, Dc)
597 // Dc' = min(Sc, Dc).m + Dc.(1 - m)
598 static constexpr BLCompOpSimplifyInfo darken(uint32_t d, uint32_t s) noexcept {
599 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
600 d == PRGB32 && s == FRGB32 ? darken(PRGB32, XRGB32) :
601 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
602 d == XRGB32 && s == FRGB32 ? darken(XRGB32, XRGB32) : makeOp(Darken, d, s);
603 }
604
605 // Lighten
606 // -------
607 //
608 // [Lighten PRGBxPRGB]
609 // Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
610 // Da' = max(Sa .Da, Da .Sa) + Sa .(1 - Da) + Da .(1 - Sa)
611 // = Sa + Da - Sa.Da
612 //
613 // Dca' = max(Sca.m.Da, Dca.Sa.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
614 // Da' = max(Sa .m.Da, Da .Sa.m) + Sa .m.(1 - Da) + Da .(1 - Sa.m)
615 // = Sa.m + Da - Sa.m.Da
616 //
617 // [Lighten PRGBxXRGB]
618 // Dca' = max(Sc.Da, Dca) + Sc.(1 - Da)
619 // Da' = max(1 .Da, Da ) + 1 .(1 - Da)
620 // = Sa + Da - Sa.Da
621 //
622 // Dca' = max(Sc.m.Da, Dca.m) + Sc.m.(1 - Da) + Dca.(1 - 1.m)
623 // Da' = max(1 .m.Da, Da .m) + 1 .m.(1 - Da) + Da .(1 - 1.m)
624 // = 1.m + Da - 1.m.Da
625 //
626 // [Lighten XRGBxPRGB]
627 // Dc' = max(Sca , Dc.Sa ) + Dc.(1 - Sa )
628 // Dc' = max(Sca.m, Dc.Sa.m) + Dc.(1 - Sa.m)
629 //
630 // [Lighten XRGBxXRGB]
631 // Dc' = max(Sc, Dc)
632 // Dc' = max(Sc, Dc).m + Dc.(1 - m)
633 static constexpr BLCompOpSimplifyInfo lighten(uint32_t d, uint32_t s) noexcept {
634 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
635 d == PRGB32 && s == FRGB32 ? lighten(PRGB32, XRGB32) :
636 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
637 d == XRGB32 && s == FRGB32 ? lighten(XRGB32, XRGB32) : makeOp(Lighten, d, s);
638 }
639
640 // ColorDodge
641 // ----------
642 //
643 // [ColorDodge PRGBxPRGB]
644 // Dca' = min(Dca.Sa.Sa / max(Sa - Sca, 0.001), Da.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
645 // Da' = Sa + Da - Sa.Da
646 //
647 // Dca' = min(Dca.Sa.m.Sa.m / max(Sa.m - Sca.m, 0.001), Da.Sa.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
648 // Da' = Sa.m + Da - Sa.m.Da
649 //
650 // [ColorDodge PRGBxXRGB]
651 // Dca' = min(Dca / max(1 - Sc, 0.001), Da) + Sc.(1 - Da)
652 // Da' = 1
653 //
654 // Dca' = min(Dca.1.m.1.m / max(1.m - Sc.m, 0.001), Da.1.m) + Sc.m.(1 - Da) + Dca.(1 - 1.m)
655 // Da' = 1.m + Da - 1.m.Da
656 //
657 // [ColorDodge XRGBxPRGB]
658 // Dc' = min(Dc.Sa .Sa / max(Sa - Sca , 0.001), Sa) + Dc.(1 - Sa)
659 // Dc' = min(Dc.Sa.m.Sa.m / max(Sa.m - Sca.m, 0.001), Sa.m) + Dc.(1 - Sa.m)
660 //
661 // [ColorDodge XRGBxXRGB]
662 // Dc' = min(Dc / max(1 - Sc, 0.001), 1)
663 // Dc' = min(Dc / max(1 - Sc, 0.001), 1).m + Dc.(1 - m)
664 static constexpr BLCompOpSimplifyInfo colorDodge(uint32_t d, uint32_t s) noexcept {
665 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
666 d == PRGB32 && s == FRGB32 ? colorDodge(PRGB32, PRGB32) :
667 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
668 d == XRGB32 && s == FRGB32 ? colorDodge(XRGB32, XRGB32) : makeOp(ColorDodge, d, s);
669 }
670
671 // ColorBurn
672 // ---------
673 //
674 // [ColorBurn PRGBxPRGB]
675 // Dca' = Sa.Da - min(Sa.Da, (Da - Dca).Sa.Sa / max(Sca, 0.001)) + Sca.(1 - Da) + Dca.(1 - Sa)
676 // Da' = Sa + Da - Sa.Da
677 //
678 // Dca' = Sa.m.Da - min(Sa.m.Da, (Da - Dca).Sa.m.Sa.m / max(Sca.m, 0.001)) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
679 // Da' = Sa.m + Da - Sa.m.Da
680 //
681 // [ColorBurn PRGBxXRGB]
682 // Dca' = 1.Da - min(Da, (Da - Dca) / max(Sc, 0.001)) + Sc.(1 - Da)
683 // Da' = 1
684 //
685 // Dca' = m.Da - min(1.m.Da, (Da - Dca).1.m.1.m / max(Sc.m, 0.001)) + Sc.m.(1 - Da) + Dca.(1 - 1.m)
686 // Da' = 1.m + Da - 1.m.Da
687 //
688 // [ColorBurn XRGBxPRGB]
689 // Dc' = Sa - min(Sa , (1 - Dc).Sa .Sa / max(Sca , 0.001)) + Dc.(1 - Sa)
690 // Dc' = Sa.m - min(Sa.m, (1 - Dc).Sa.m.Sa.m / max(Sca.m, 0.001)) + Dc.(1 - Sa.m)
691 //
692 // [ColorBurn XRGBxXRGB]
693 // Dc' = (1 - min(1, (1 - Dc) / max(Sc, 0.001)))
694 // Dc' = (1 - min(1, (1 - Dc) / max(Sc, 0.001))).m + Dc.(1 - m)
695 static constexpr BLCompOpSimplifyInfo colorBurn(uint32_t d, uint32_t s) noexcept {
696 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
697 d == PRGB32 && s == FRGB32 ? colorBurn(PRGB32, XRGB32) :
698 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
699 d == XRGB32 && s == FRGB32 ? colorBurn(XRGB32, XRGB32) : makeOp(ColorBurn, d, s);
700 }
701
702 // LinearBurn
703 // ----------
704 //
705 // [LinearBurn PRGBxPRGB]
706 // Dca' = Clamp(Dca + Sca - Sa.Da)
707 // Da' = Da + Sa - Sa.Da
708 //
709 // Dca' = Clamp(Dca + Sca - Sa.Da).m + Dca.(1 - m)
710 // Da' = Sa.m.(1 - Da) + Da
711 //
712 // [LinearBurn PRGBxXRGB]
713 // Dca' = Clamp(Dca + Sc - Da)
714 // Da' = 1
715 //
716 // Dca' = Clamp(Dca + Sc - Da).m + Dca.(1 - m)
717 // Da' = Da + Sa - Sa.Da
718 //
719 // [LinearBurn XRGBxPRGB]
720 // Dc' = Clamp(Dc + Sca - Sa)
721 // Dc' = Clamp(Dc + Sca - Sa).m + Dc.(1 - m)
722 //
723 // [LinearBurn XRGBxXRGB]
724 // Dc' = Clamp(Dc + Sc - 1)
725 // Dc' = Clamp(Dc + Sc - 1).m + Dc.(1 - m)
726 static constexpr BLCompOpSimplifyInfo linearBurn(uint32_t d, uint32_t s) noexcept {
727 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
728 d == PRGB32 && s == FRGB32 ? linearBurn(PRGB32, XRGB32) :
729 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
730 d == XRGB32 && s == FRGB32 ? linearBurn(XRGB32, XRGB32) : makeOp(LinearBurn, d, s);
731 }
732
733 // LinearLight
734 // -----------
735 //
736 // [LinearLight PRGBxPRGB]
737 // Dca' = min(max((Dca.Sa + 2.Sca.Da - Sa.Da), 0), Sa.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
738 // Da' = Da + Sa - Sa.Da
739 //
740 // Dca' = min(max((Dca.Sa.m + 2.Sca.m.Da - Sa.m.Da), 0), Sa.m.Da) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
741 // Da' = Da + Sa.m - Sa.m.Da
742 //
743 // [LinearLight PRGBxXRGB]
744 // Dca' = min(max((Dca + 2.Sc.Da - Da), 0), Da) + Sc.(1 - Da)
745 // Da' = 1
746 //
747 // Dca' = min(max((Dca.1.m + 2.Sc.m.Da - 1.m.Da), 0), 1.m.Da) + Sc.m.(1 - Da) + Dca.(1 - m)
748 // Da' = Da + Sa.m - Sa.m.Da
749 //
750 // [LinearLight XRGBxPRGB]
751 // Dca' = min(max((Dc.Sa + 2.Sca - Sa ), 0), Sa ) + Dca.(1 - Sa)
752 // Dca' = min(max((Dc.Sa.m + 2.Sca.m - Sa.m), 0), Sa.m) + Dca.(1 - Sa.m)
753 //
754 // [LinearLight XRGBxXRGB]
755 // Dc' = min(max((Dc + 2.Sc - 1), 0), 1)
756 // Dc' = min(max((Dc + 2.Sc - 1), 0), 1).m + Dca.(1 - m)
757 static constexpr BLCompOpSimplifyInfo linearLight(uint32_t d, uint32_t s) noexcept {
758 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
759 d == PRGB32 && s == FRGB32 ? linearLight(PRGB32, XRGB32) :
760 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
761 d == XRGB32 && s == FRGB32 ? linearLight(XRGB32, XRGB32) : makeOp(LinearLight, d, s);
762 }
763
764 // PinLight
765 // --------
766 //
767 // [PinLight PRGBxPRGB]
768 // if 2.Sca <= Sa
769 // Dca' = min(Dca.Sa, 2.Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
770 // Da' = Da + Sa.(1 - Da)
771 // else
772 // Dca' = max(Dca.Sa, 2.Sca.Da - Sa.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
773 // Da' = Da + Sa.(1 - Da)
774 //
775 // if 2.Sca.m <= Sa.m
776 // Dca' = min(Dca.Sa.m, 2.Sca.m.Da) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
777 // Da' = Da + Sa.m.(1 - Da)
778 // else
779 // Dca' = max(Dca.Sa.m, 2.Sca.m.Da - Sa.m.Da) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
780 // Da' = Da + Sa.m.(1 - Da)
781 //
782 // [PinLight PRGBxXRGB]
783 // if 2.Sc <= 1
784 // Dca' = min(Dca, 2.Sc.Da) + Sc.(1 - Da)
785 // Da' = 1
786 // else
787 // Dca' = max(Dca, 2.Sc.Da - Da) + Sc.(1 - Da)
788 // Da' = 1
789 //
790 // if 2.Sc.m <= 1.m
791 // Dca' = min(Dca.m, 2.Sc.m.Da) + Sc.m.(1 - Da) + Dca.(1 - m)
792 // Da' = Da + m.(1 - Da)
793 // else
794 // Dca' = max(Dca.m, 2.Sc.m.Da - m.Da) + Sc.m.(1 - Da) + Dc.(1 - m)
795 // Da' = Da + m.(1 - Da)
796 //
797 // [PinLight XRGBxPRGB]
798 // if 2.Sca <= Sa
799 // Dc' = min(Dc.Sa, 2.Sca) + Dc.(1 - Sa)
800 // else
801 // Dc' = max(Dc.Sa, 2.Sca - Sa) + Dc.(1 - Sa)
802 //
803 // if 2.Sca.m <= Sa.m
804 // Dc' = min(Dc.Sa.m, 2.Sca.m) + Dc.(1 - Sa.m)
805 // else
806 // Dc' = max(Dc.Sa.m, 2.Sca.m - Sa.m) + Dc.(1 - Sa.m)
807 //
808 // [PinLight XRGBxXRGB]
809 // if 2.Sc <= 1
810 // Dc' = min(Dc, 2.Sc)
811 // else
812 // Dc' = max(Dc, 2.Sc - 1)
813 //
814 // if 2.Sca.m <= Sa.m
815 // Dc' = min(Dc, 2.Sc).m + Dca.(1 - m)
816 // else
817 // Dc' = max(Dc, 2.Sc - 1).m + Dca.(1 - m)
818 static constexpr BLCompOpSimplifyInfo pinLight(uint32_t d, uint32_t s) noexcept {
819 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
820 d == PRGB32 && s == FRGB32 ? pinLight(PRGB32, XRGB32) :
821 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
822 d == XRGB32 && s == FRGB32 ? pinLight(XRGB32, XRGB32) : makeOp(PinLight, d, s);
823 }
824
825 // HardLight
826 // ---------
827 //
828 // [HardLight PRGBxPRGB]
829 // if (2.Sca <= Sa)
830 // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
831 // Da' = Sa + Da - Sa.Da
832 // else
833 // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa)
834 // Da' = Sa + Da - Sa.Da
835 //
836 // if (2.Sca.m <= Sa.m)
837 // Dca' = 2.Sca.m.Dca + Sca.m(1 - Da) + Dca.(1 - Sa.m)
838 // Da' = Sa.m + Da - Sa.m.Da
839 // else
840 // Dca' = Sa.m.Da - 2.(Da - Dca).(Sa.m - Sca.m) + Sca.m.(1 - Da) + Dca.(1 - Sa.m)
841 // Da' = Sa.m + Da - Sa.m.Da
842 //
843 // [HardLight PRGBxXRGB]
844 // if (2.Sc <= 1)
845 // Dca' = 2.Sc.Dca + Sc.(1 - Da)
846 // Da' = 1
847 // else
848 // Dca' = Da - 2.(Da - Dca).(1 - Sc) + Sc.(1 - Da)
849 // Da' = 1
850 //
851 // if (2.Sc.m <= m)
852 // Dca' = 2.Sc.m.Dca + Sc.m(1 - Da) + Dca.(1 - m)
853 // Da' = Da + m.(1 - Da)
854 // else
855 // Dca' = 1.m.Da - 2.(Da - Dca).((1 - Sc).m) + Sc.m.(1 - Da) + Dca.(1 - m)
856 // Da' = Da + m.(1 - Da)
857 //
858 // [HardLight XRGBxPRGB]
859 // if (2.Sca <= Sa)
860 // Dc' = 2.Sca.Dc + Dc.(1 - Sa)
861 // else
862 // Dc' = Sa - 2.(1 - Dc).(Sa - Sca) + Dc.(1 - Sa)
863 //
864 // if (2.Sca.m <= Sa.m)
865 // Dc' = 2.Sca.m.Dc + Dc.(1 - Sa.m)
866 // else
867 // Dc' = Sa.m - 2.(1 - Dc).(Sa.m - Sca.m) + Dc.(1 - Sa.m)
868 //
869 // [HardLight XRGBxXRGB]
870 // if (2.Sc <= 1)
871 // Dc' = 2.Sc.Dc
872 // else
873 // Dc' = 1 - 2.(1 - Dc).(1 - Sc)
874 //
875 // if (2.Sc.m <= 1.m)
876 // Dc' = 2.Sc.Dc.m + Dc.(1 - m)
877 // else
878 // Dc' = (1 - 2.(1 - Dc).(1 - Sc)).m - Dc.(1 - m)
879 static constexpr BLCompOpSimplifyInfo hardLight(uint32_t d, uint32_t s) noexcept {
880 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
881 d == PRGB32 && s == FRGB32 ? hardLight(PRGB32, XRGB32) :
882 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
883 d == XRGB32 && s == FRGB32 ? hardLight(XRGB32, XRGB32) : makeOp(HardLight, d, s);
884 }
885
886 // SoftLight
887 // ---------
888 //
889 // [SoftLight PRGBxPRGB]
890 // Dc = Dca/Da
891 // if 2.Sca - Sa <= 0
892 // Dca' = Dca + Sca.(1 - Da) + (2.Sca - Sa).Da.[[ Dc.(1 - Dc) ]]
893 // Da' = Da + Sa - Sa.Da
894 // else if 2.Sca - Sa > 0 and 4.Dc <= 1
895 // Dca' = Dca + Sca.(1 - Da) + (2.Sca - Sa).Da.[[ 4.Dc.(4.Dc.Dc + Dc - 4.Dc + 1) - Dc]]
896 // Da' = Da + Sa - Sa.Da
897 // else
898 // Dca' = Dca + Sca.(1 - Da) + (2.Sca - Sa).Da.[[ sqrt(Dc) - Dc ]]
899 // Da' = Da + Sa - Sa.Da
900 //
901 // [SoftLight XRGBxXRGB]
902 // if 2.Sc <= 1
903 // Dc' = Dc + (2.Sc - 1).[[ Dc.(1 - Dc) ]]
904 // else if 2.Sc > 1 and 4.Dc <= 1
905 // Dc' = Dc + (2.Sc - 1).[[ 4.Dc.(4.Dc.Dc + Dc - 4.Dc + 1) - Dc]]
906 // else
907 // Dc' = Dc + (2.Sc - 1).[[ sqrt(Dc) - Dc ]]
908 static constexpr BLCompOpSimplifyInfo softLight(uint32_t d, uint32_t s) noexcept {
909 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
910 d == PRGB32 && s == FRGB32 ? softLight(PRGB32, XRGB32) :
911 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
912 d == XRGB32 && s == FRGB32 ? softLight(XRGB32, XRGB32) : makeOp(SoftLight, d, s);
913 }
914
915 // Difference
916 // ----------
917 //
918 // [Difference PRGBxPRGB]
919 // Dca' = Dca + Sca - 2.min(Sca.Da, Dca.Sa)
920 // Da' = Sa + Da - Sa.Da
921 //
922 // Dca' = Dca + Sca.m - 2.min(Sca.m.Da, Dca.Sa.m)
923 // Da' = Sa.m + Da - Sa.m.Da
924 //
925 // [Difference PRGBxXRGB]
926 // Dca' = Dca + Sc - 2.min(Sc.Da, Dca)
927 // Da' = 1
928 //
929 // Dca' = Dca + Sc.m - 2.min(Sc.m.Da, Dca)
930 // Da' = Da + 1.m - m.Da
931 //
932 // [Difference XRGBxPRGB]
933 // Dc' = Dc + Sca - 2.min(Sca , Dc.Sa)
934 // Dc' = Dc + Sca.m - 2.min(Sca.m, Dc.Sa.m)
935 //
936 // [Difference XRGBxXRGB]
937 // Dc' = Dc + Sc - 2.min(Sc , Dc )
938 // Dc' = Dc + Sc.m - 2.min(Sc.m, Dc.m)
939 static constexpr BLCompOpSimplifyInfo difference(uint32_t d, uint32_t s) noexcept {
940 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
941 d == PRGB32 && s == FRGB32 ? difference(PRGB32, PRGB32) :
942 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
943 d == XRGB32 && s == FRGB32 ? difference(XRGB32, PRGB32) : makeOp(Difference, d, s);
944 }
945
946 // Exclusion
947 // ---------
948 //
949 // [Exclusion PRGBxPRGB]
950 // Dca' = Dca + Sca.(Da - 2.Dca)
951 // Da' = Da + Sa - Sa.Da
952 //
953 // Dca' = Dca + Sca.m.(Da - 2.Dca)
954 // Da' = Da + Sa.m - Sa.m.Da
955 //
956 // [Exclusion PRGBxXRGB] ~= [Exclusion PRGBxPRGB]
957 // Dca' = Dca + Sc.(Da - 2.Dca)
958 // Da' = Da + 1 - 1.Da
959 //
960 // Dca' = Dca + Sc.m.(Da - 2.Dca)
961 // Da' = Da + 1.m - 1.m.Da
962 //
963 // [Exclusion XRGBxPRGB]
964 // Dc' = Dc + Sca .(1 - 2.Dc)
965 // Dc' = Dc + Sca.m.(1 - 2.Dc)
966 //
967 // [Exclusion XRGBxXRGB] ~= [Exclusion XRGBxPRGB]
968 // Dc' = Dc + Sc .(1 - 2.Dc)
969 // Dc' = Dc + Sc.m.(1 - 2.Dc)
970 static constexpr BLCompOpSimplifyInfo exclusion(uint32_t d, uint32_t s) noexcept {
971 return d == PRGB32 && s == ZERO32 ? dstCopy(d, s) :
972 d == PRGB32 && s == FRGB32 ? exclusion(PRGB32, PRGB32) :
973 d == XRGB32 && s == ZERO32 ? dstCopy(d, s) :
974 d == XRGB32 && s == FRGB32 ? exclusion(XRGB32, PRGB32) : makeOp(Exclusion, d, s);
975 }
976
977 // HACK: MSVC has a problem with code that does multiple ternary operations (? :)
978 // so we had to split it so Blend2D can compile. So please don't be active
979 // here and don't try to join these functions otherwise you break MSVC builds.
980 static constexpr BLCompOpSimplifyInfo valueDecomposed_1(uint32_t compOp, uint32_t d, uint32_t s) noexcept {
981 return compOp == BL_COMP_OP_SRC_COPY ? srcCopy(d, s) :
982 compOp == BL_COMP_OP_SRC_OVER ? srcOver(d, s) :
983 compOp == BL_COMP_OP_SRC_IN ? srcIn(d, s) :
984 compOp == BL_COMP_OP_SRC_OUT ? srcOut(d, s) :
985 compOp == BL_COMP_OP_SRC_ATOP ? srcAtop(d, s) :
986 compOp == BL_COMP_OP_DST_COPY ? dstCopy(d, s) :
987 compOp == BL_COMP_OP_DST_OVER ? dstOver(d, s) :
988 compOp == BL_COMP_OP_DST_IN ? dstIn(d, s) :
989 compOp == BL_COMP_OP_DST_OUT ? dstOut(d, s) :
990 compOp == BL_COMP_OP_DST_ATOP ? dstAtop(d, s) : dstCopy(d, s);
991 }
992
993 static constexpr BLCompOpSimplifyInfo valueDecomposed_2(uint32_t compOp, uint32_t d, uint32_t s) noexcept {
994 return compOp == BL_COMP_OP_XOR ? xor_(d, s) :
995 compOp == BL_COMP_OP_CLEAR ? clear(d, s) :
996 compOp == BL_COMP_OP_CLEAR ? clear(d, s) :
997 compOp == BL_COMP_OP_PLUS ? plus(d, s) :
998 compOp == BL_COMP_OP_MINUS ? minus(d, s) :
999 compOp == BL_COMP_OP_MULTIPLY ? multiply(d, s) :
1000 compOp == BL_COMP_OP_SCREEN ? screen(d, s) :
1001 compOp == BL_COMP_OP_OVERLAY ? overlay(d, s) :
1002 compOp == BL_COMP_OP_DARKEN ? darken(d, s) :
1003 compOp == BL_COMP_OP_LIGHTEN ? lighten(d, s) : valueDecomposed_1(compOp, d, s);
1004 }
1005
1006 // Just dispatches to the respective composition operator.
1007 static constexpr BLCompOpSimplifyInfo valueDecomposed_3(uint32_t compOp, uint32_t d, uint32_t s) noexcept {
1008 return compOp == BL_COMP_OP_COLOR_DODGE ? colorDodge(d, s) :
1009 compOp == BL_COMP_OP_COLOR_BURN ? colorBurn(d, s) :
1010 compOp == BL_COMP_OP_LINEAR_BURN ? linearBurn(d, s) :
1011 compOp == BL_COMP_OP_LINEAR_LIGHT ? linearLight(d, s) :
1012 compOp == BL_COMP_OP_PIN_LIGHT ? pinLight(d, s) :
1013 compOp == BL_COMP_OP_HARD_LIGHT ? hardLight(d, s) :
1014 compOp == BL_COMP_OP_SOFT_LIGHT ? softLight(d, s) :
1015 compOp == BL_COMP_OP_DIFFERENCE ? difference(d, s) :
1016 compOp == BL_COMP_OP_EXCLUSION ? exclusion(d, s) : valueDecomposed_2(compOp, d, s);
1017 }
1018
1019 // Function called by the table generator, decompose and continue...
1020 static constexpr BLCompOpSimplifyInfo value(size_t index) noexcept {
1021 return valueDecomposed_3(uint32_t((index / BL_FORMAT_RESERVED_COUNT) % BL_COMP_OP_INTERNAL_COUNT),
1022 uint32_t(index / (BL_COMP_OP_INTERNAL_COUNT * BL_FORMAT_RESERVED_COUNT)),
1023 uint32_t(index % BL_FORMAT_RESERVED_COUNT));
1024 }
1025};
1026
1027template<uint32_t DstFormat>
1028struct BLSimplifyInfoRecordSetGen {
1029 // Function called by the table generator, decompose and continue...
1030 static constexpr BLCompOpSimplifyInfo value(size_t index) noexcept {
1031 return BLCompOpSimplifyInfoGen::valueDecomposed_3(uint32_t(index / BL_FORMAT_RESERVED_COUNT), DstFormat, uint32_t(index % BL_FORMAT_RESERVED_COUNT));
1032 }
1033};
1034
1035// HACK: MSVC doesn't honor constexpr functions and sometimes outputs initialization
1036// code even when the expression can be calculated at compile time. To fix this
1037// we go throught an additional constexpr to force the compiler to always generate
1038// our lookup tables at compile time.
1039//
1040// Additionally, if there is a mistake leading to recursion the compiler would catch it
1041// at compile-time instead of hitting it at runtime during initialization.
1042static_assert(BL_FORMAT_COUNT == 4, "Don't forget to add new formats to blCompOpSimplifyInfoTable");
1043static constexpr const BLCompOpSimplifyInfoTable blCompOpSimplifyInfoTable_ = {{
1044 blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<0>>(),
1045 blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<1>>(),
1046 blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<2>>(),
1047 blLookupTable<BLCompOpSimplifyInfo, BL_COMP_OP_SIMPLIFY_RECORD_SIZE, BLSimplifyInfoRecordSetGen<3>>()
1048}};
1049const BLCompOpSimplifyInfoTable blCompOpSimplifyInfoTable = blCompOpSimplifyInfoTable_;
1050