Delete FbIntMult and FbIntDiv macros, and move FbIntAdd to pixman-combine.h
[profile/ivi/pixman.git] / pixman / pixman-combine.c.template
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #include <math.h>
6 #include <string.h>
7
8 #include "pixman-private.h"
9
10 #include "pixman-combine.h"
11
12 #define Red(x) (((x) >> R_SHIFT) & MASK)
13 #define Green(x) (((x) >> G_SHIFT) & MASK)
14 #define Blue(x) ((x) & MASK)
15
16 /*** per channel helper functions ***/
17
18 static void
19 fbCombineMaskC (comp4_t *src, comp4_t *mask)
20 {
21     comp4_t a = *mask;
22
23     comp4_t     x;
24     comp2_t     xa;
25
26     if (!a)
27     {
28         *(src) = 0;
29         return;
30     }
31
32     x = *(src);
33     if (a == ~0)
34     {
35         x = x >> A_SHIFT;
36         x |= x << G_SHIFT;
37         x |= x << R_SHIFT;
38         *(mask) = x;
39         return;
40     }
41
42     xa = x >> A_SHIFT;
43     FbByteMulC(x, a);
44     *(src) = x;
45     FbByteMul(a, xa);
46     *(mask) = a;
47 }
48
49 static void
50 fbCombineMaskValueC (comp4_t *src, const comp4_t *mask)
51 {
52     comp4_t a = *mask;
53     comp4_t     x;
54
55     if (!a)
56     {
57         *(src) = 0;
58         return;
59     }
60
61     if (a == ~0)
62         return;
63
64     x = *(src);
65     FbByteMulC(x, a);
66     *(src) =x;
67 }
68
69 static void
70 fbCombineMaskAlphaC (const comp4_t *src, comp4_t *mask)
71 {
72     comp4_t a = *(mask);
73     comp4_t     x;
74
75     if (!a)
76         return;
77
78     x = *(src) >> A_SHIFT;
79     if (x == MASK)
80         return;
81     if (a == ~0)
82     {
83         x = x >> A_SHIFT;
84         x |= x << G_SHIFT;
85         x |= x << R_SHIFT;
86         *(mask) = x;
87         return;
88     }
89
90     FbByteMul(a, x);
91     *(mask) = a;
92 }
93
94
95
96 /*
97  * There are two ways of handling alpha -- either as a single unified value or
98  * a separate value for each component, hence each macro must have two
99  * versions.  The unified alpha version has a 'U' at the end of the name,
100  * the component version has a 'C'.  Similarly, functions which deal with
101  * this difference will have two versions using the same convention.
102  */
103
104 /*
105  * All of the composing functions
106  */
107
108 static force_inline comp4_t
109 combineMask (const comp4_t *src, const comp4_t *mask, int i)
110 {
111     comp4_t s, m;
112
113     if (mask)
114     {
115         m = *(mask + i) >> A_SHIFT;
116
117         if (!m)
118             return 0;
119     }
120
121     s = *(src + i);
122
123     if (mask)
124         FbByteMul (s, m);
125
126     return s;
127 }
128
129 static void
130 fbCombineClear (pixman_implementation_t *imp, pixman_op_t op,
131                 comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
132 {
133     memset(dest, 0, width*sizeof(comp4_t));
134 }
135
136 static void
137 fbCombineSrcU (pixman_implementation_t *imp, pixman_op_t op,
138                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
139 {
140     int i;
141
142     if (!mask)
143         memcpy (dest, src, width * sizeof (comp4_t));
144     else
145     {
146         for (i = 0; i < width; ++i)
147         {
148             comp4_t s = combineMask (src, mask, i);
149             
150             *(dest + i) = s;
151         }
152     }
153 }
154
155 /* if the Src is opaque, call fbCombineSrcU */
156 static void
157 fbCombineOverU (pixman_implementation_t *imp, pixman_op_t op,
158                 comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
159 {
160     int i;
161     for (i = 0; i < width; ++i) {
162         comp4_t s = combineMask (src, mask, i);
163         comp4_t d = *(dest + i);
164         comp4_t ia = Alpha(~s);
165
166         FbByteMulAdd(d, ia, s);
167         *(dest + i) = d;
168     }
169 }
170
171 /* if the Dst is opaque, this is a noop */
172 static void
173 fbCombineOverReverseU (pixman_implementation_t *imp, pixman_op_t op,
174                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
175 {
176     int i;
177     for (i = 0; i < width; ++i) {
178         comp4_t s = combineMask (src, mask, i);
179         comp4_t d = *(dest + i);
180         comp4_t ia = Alpha(~*(dest + i));
181         FbByteMulAdd(s, ia, d);
182         *(dest + i) = s;
183     }
184 }
185
186 /* if the Dst is opaque, call fbCombineSrcU */
187 static void
188 fbCombineInU (pixman_implementation_t *imp, pixman_op_t op,
189               comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
190 {
191     int i;
192     for (i = 0; i < width; ++i) {
193         comp4_t s = combineMask (src, mask, i);
194         comp4_t a = Alpha(*(dest + i));
195         FbByteMul(s, a);
196         *(dest + i) = s;
197     }
198 }
199
200 /* if the Src is opaque, this is a noop */
201 static void
202 fbCombineInReverseU (pixman_implementation_t *imp, pixman_op_t op,
203                      comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
204 {
205     int i;
206     for (i = 0; i < width; ++i) {
207         comp4_t s = combineMask (src, mask, i);
208         comp4_t d = *(dest + i);
209         comp4_t a = Alpha(s);
210         FbByteMul(d, a);
211         *(dest + i) = d;
212     }
213 }
214
215 /* if the Dst is opaque, call fbCombineClear */
216 static void
217 fbCombineOutU (pixman_implementation_t *imp, pixman_op_t op,
218                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
219 {
220     int i;
221     for (i = 0; i < width; ++i) {
222         comp4_t s = combineMask (src, mask, i);
223         comp4_t a = Alpha(~*(dest + i));
224         FbByteMul(s, a);
225         *(dest + i) = s;
226     }
227 }
228
229 /* if the Src is opaque, call fbCombineClear */
230 static void
231 fbCombineOutReverseU (pixman_implementation_t *imp, pixman_op_t op,
232                       comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
233 {
234     int i;
235     for (i = 0; i < width; ++i) {
236         comp4_t s = combineMask (src, mask, i);
237         comp4_t d = *(dest + i);
238         comp4_t a = Alpha(~s);
239         FbByteMul(d, a);
240         *(dest + i) = d;
241     }
242 }
243
244 /* if the Src is opaque, call fbCombineInU */
245 /* if the Dst is opaque, call fbCombineOverU */
246 /* if both the Src and Dst are opaque, call fbCombineSrcU */
247 static void
248 fbCombineAtopU (pixman_implementation_t *imp, pixman_op_t op,
249                 comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
250 {
251     int i;
252     for (i = 0; i < width; ++i) {
253         comp4_t s = combineMask (src, mask, i);
254         comp4_t d = *(dest + i);
255         comp4_t dest_a = Alpha(d);
256         comp4_t src_ia = Alpha(~s);
257
258         FbByteAddMul(s, dest_a, d, src_ia);
259         *(dest + i) = s;
260     }
261 }
262
263 /* if the Src is opaque, call fbCombineOverReverseU */
264 /* if the Dst is opaque, call fbCombineInReverseU */
265 /* if both the Src and Dst are opaque, call fbCombineDstU */
266 static void
267 fbCombineAtopReverseU (pixman_implementation_t *imp, pixman_op_t op,
268                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
269 {
270     int i;
271     for (i = 0; i < width; ++i) {
272         comp4_t s = combineMask (src, mask, i);
273         comp4_t d = *(dest + i);
274         comp4_t src_a = Alpha(s);
275         comp4_t dest_ia = Alpha(~d);
276
277         FbByteAddMul(s, dest_ia, d, src_a);
278         *(dest + i) = s;
279     }
280 }
281
282 /* if the Src is opaque, call fbCombineOverU */
283 /* if the Dst is opaque, call fbCombineOverReverseU */
284 /* if both the Src and Dst are opaque, call fbCombineClear */
285 static void
286 fbCombineXorU (pixman_implementation_t *imp, pixman_op_t op,
287                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
288 {
289     int i;
290     for (i = 0; i < width; ++i) {
291         comp4_t s = combineMask (src, mask, i);
292         comp4_t d = *(dest + i);
293         comp4_t src_ia = Alpha(~s);
294         comp4_t dest_ia = Alpha(~d);
295
296         FbByteAddMul(s, dest_ia, d, src_ia);
297         *(dest + i) = s;
298     }
299 }
300
301 static void
302 fbCombineAddU (pixman_implementation_t *imp, pixman_op_t op,
303                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
304 {
305     int i;
306     for (i = 0; i < width; ++i) {
307         comp4_t s = combineMask (src, mask, i);
308         comp4_t d = *(dest + i);
309         FbByteAdd(d, s);
310         *(dest + i) = d;
311     }
312 }
313
314 /* if the Src is opaque, call fbCombineAddU */
315 /* if the Dst is opaque, call fbCombineAddU */
316 /* if both the Src and Dst are opaque, call fbCombineAddU */
317 static void
318 fbCombineSaturateU (pixman_implementation_t *imp, pixman_op_t op,
319                     comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
320 {
321     int i;
322     for (i = 0; i < width; ++i) {
323         comp4_t s = combineMask (src, mask, i);
324         comp4_t d = *(dest + i);
325         comp2_t sa, da;
326
327         sa = s >> A_SHIFT;
328         da = ~d >> A_SHIFT;
329         if (sa > da)
330         {
331             sa = IntDiv(da, sa);
332             FbByteMul(s, sa);
333         };
334         FbByteAdd(d, s);
335         *(dest + i) = d;
336     }
337 }
338
339 /* 
340  * PDF blend modes:
341  * The following blend modes have been taken from the PDF ISO 32000
342  * specification, which at this point in time is available from
343  * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf
344  * The relevant chapters are 11.3.5 and 11.3.6.
345  * The formula for computing the final pixel color given in 11.3.6 is:
346  * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs)
347  * with B() being the blend function.
348  * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs
349  *
350  * These blend modes should match the SVG filter draft specification, as 
351  * it has been designed to mirror ISO 32000. Note that at the current point
352  * no released draft exists that shows this, as the formulas have not been
353  * updated yet after the release of ISO 32000.
354  *
355  * The default implementation here uses the PdfSeparableBlendMode and 
356  * PdfNonSeparableBlendMode macros, which take the blend function as an 
357  * argument. Note that this implementation operates on premultiplied colors,
358  * while the PDF specification does not. Therefore the code uses the formula
359  * ar.Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as)
360  */
361
362 /* 
363  * Multiply
364  * B(Dca, ad, Sca, as) = Dca.Sca
365  */
366
367 static void
368 fbCombineMultiplyU (pixman_implementation_t *imp, pixman_op_t op,
369                     comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
370 {
371     int i;
372     for (i = 0; i < width; ++i) {
373         comp4_t s = combineMask (src, mask, i);
374         comp4_t d = *(dest + i);
375         comp4_t ss = s;
376         comp4_t src_ia = Alpha (~s);
377         comp4_t dest_ia = Alpha (~d);
378
379         FbByteAddMul (ss, dest_ia, d, src_ia);
380         FbByteMulC (d, s);
381         FbByteAdd (d, ss);      
382         *(dest + i) = d;
383     }
384 }
385
386 static void
387 fbCombineMultiplyC (pixman_implementation_t *imp, pixman_op_t op,
388                     comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
389 {
390     int i;
391     for (i = 0; i < width; ++i) {
392         comp4_t m = *(mask + i);
393         comp4_t s = *(src + i);
394         comp4_t d = *(dest + i);
395         comp4_t r = d;
396         comp4_t dest_ia = Alpha (~d);
397
398         fbCombineMaskValueC (&s, &m);
399
400         FbByteAddMulC (r, ~m, s, dest_ia);
401         FbByteMulC (d, s);
402         FbByteAdd (r, d);
403
404         *(dest + i) = r;
405     }
406 }
407
408 #define PdfSeparableBlendMode(name)                 \
409 static void                                         \
410 fbCombine ## name ## U (pixman_implementation_t *imp, pixman_op_t op, \
411                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width) \
412 {                                                   \
413     int i;                                          \
414     for (i = 0; i < width; ++i) {                   \
415         comp4_t s = combineMask (src, mask, i);     \
416         comp4_t d = *(dest + i);                    \
417         comp1_t sa = Alpha(s);                      \
418         comp1_t isa = ~sa;                          \
419         comp1_t da = Alpha(d);                      \
420         comp1_t ida = ~da;                          \
421         comp4_t result;                             \
422                                                     \
423         result = d;                                 \
424         FbByteAddMul(result, isa, s, ida);          \
425                                                     \
426         *(dest + i) = result +                      \
427             (DivOne (sa * da) << A_SHIFT) +         \
428             (Blend ## name (Red (d), da, Red (s), sa) << R_SHIFT) + \
429             (Blend ## name (Green (d), da, Green (s), sa) << G_SHIFT) + \
430             (Blend ## name (Blue (d), da, Blue (s), sa)); \
431     }                                               \
432 }                                                   \
433                                                     \
434 static void                                 \
435 fbCombine ## name ## C (pixman_implementation_t *imp, pixman_op_t op, \
436                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width) \
437 {                                                   \
438     int i;                                          \
439     for (i = 0; i < width; ++i) {                   \
440         comp4_t m = *(mask + i);                    \
441         comp4_t s = *(src + i);                     \
442         comp4_t d = *(dest + i);                    \
443         comp1_t da = Alpha(d);                      \
444         comp1_t ida = ~da;                          \
445         comp4_t result;                             \
446                                                     \
447         fbCombineMaskValueC (&s, &m);               \
448                                                     \
449         result = d;                                 \
450         FbByteAddMulC (result, ~m, s, ida);         \
451                                                     \
452         result +=                                   \
453             (DivOne (Alpha (m) * da) << A_SHIFT) +                              \
454             (Blend ## name (Red (d), da, Red (s), Red (m)) << R_SHIFT) +        \
455             (Blend ## name (Green (d), da, Green (s), Green (m)) << G_SHIFT) +  \
456             (Blend ## name (Blue (d), da, Blue (s), Blue (m)));                 \
457                                                     \
458         *(dest + i) = result;                       \
459     }                                               \
460 }
461
462 /*
463  * Screen
464  * B(Dca, ad, Sca, as) = Dca.sa + Sca.da - Dca.Sca
465  */
466
467 static inline comp4_t
468 BlendScreen (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
469 {
470   return DivOne (sca * da + dca * sa - sca * dca);
471 }
472
473 PdfSeparableBlendMode (Screen)
474
475 /*
476  * Overlay
477  * B(Dca, ab, Sca, as) = 
478  *   if 2.Dca < Da
479  *     2.Sca.Dca
480  *   otherwise
481  *     Sa.Da - 2.(Da - Dca).(Sa - Sca)
482  */
483
484 static inline comp4_t
485 BlendOverlay (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
486 {
487     comp4_t rca;
488
489     if (2 * dca < da)
490         rca = 2 * sca * dca;
491     else
492         rca = sa * da - 2 * (da - dca) * (sa - sca);
493     return DivOne (rca);
494 }
495
496 PdfSeparableBlendMode (Overlay)
497
498 /*
499  * Darken
500  * B(Dca, ab, Sca, as) = min (Sca.Da, Dca.Sa)
501  */
502
503 static inline comp4_t
504 BlendDarken (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
505 {
506     comp4_t s, d;
507     
508     s = sca * da;
509     d = dca * sa;
510     return DivOne (s > d ? d : s);
511 }
512
513 PdfSeparableBlendMode (Darken)
514
515 /*
516  * Lighten
517  * B(Dca, ab, Sca, as) = max (Sca.Da, Dca.Sa)
518  */
519
520 static inline comp4_t
521 BlendLighten (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
522 {
523     comp4_t s, d;
524     
525     s = sca * da;
526     d = dca * sa;
527     return DivOne (s > d ? s : d);
528 }
529
530 PdfSeparableBlendMode (Lighten)
531
532 /*
533  * Color dodge
534  * B(Dca, ab, Sca, as) = 
535  *   if Sca == Sa
536  *     (Dca != 0).Sa.Da
537  *   otherwise
538  *     Da.Sa. min (Dca / Da / (1 - Sca/Sa))
539  */ 
540
541 static inline comp4_t
542 BlendColorDodge (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
543 {
544     if (sca >= sa) {
545         return DivOne (sa * da);
546     } else {
547         comp4_t rca = dca * sa * sa / (sa - sca);
548         return DivOne (rca > sa * da ? sa * da : rca);
549     }
550 }
551
552 PdfSeparableBlendMode (ColorDodge)
553
554 /*
555  * Color burn
556  * B(Dca, ab, Sca, as) = 
557  *   if Sca. == 0
558  *     (Da == Dca).SaDa
559  *   otherwise
560  *     Sa.Da.(1 - min (1, (1 - Dca/Da).Sa / Sca))
561  */
562
563 static inline comp4_t
564 BlendColorBurn (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
565 {
566     if (sca == 0) {
567         return 0;
568     } else {
569         comp4_t sada = sa * da;
570         comp4_t rca = (da - dca) * sa * sa / sca;
571         return DivOne (rca > sada ? 0 : sada - rca);
572     }
573 }
574
575 PdfSeparableBlendMode (ColorBurn)
576
577 /*
578  * Hard light
579  * B(Dca, ab, Sca, as) = 
580  *   if 2.Sca < Sa
581  *     2.Sca.Dca
582  *   otherwise
583  *     Sa.Da - 2.(Da - Dca).(Sa - Sca)
584  */
585 static inline comp4_t
586 BlendHardLight (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
587 {
588     if (2 * sca < sa)
589         return DivOne (2 * sca * dca);
590     else
591         return DivOne (sa * da - 2 * (da - dca) * (sa - sca));
592 }
593
594 PdfSeparableBlendMode (HardLight)
595
596 /*
597  * Soft light
598  * B(Dca, ab, Sca, as) = 
599  *   if (2.Sca <= Sa)
600  *     Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa))
601  *   otherwise if Dca.4 <= Da
602  *     Dca.(Sa + (2.Sca - Sa).((16.Dca/Da - 12).Dca/Da + 3)
603  *   otherwise
604  *     (Dca.Sa + (SQRT (Dca/Da).Da - Dca).(2.Sca - Sa))
605  */
606
607 static inline comp4_t
608 BlendSoftLight (comp4_t dca_org, comp4_t da_org, comp4_t sca_org, comp4_t sa_org)
609 {
610     double dca = dca_org * (1.0 / MASK);
611     double da = da_org * (1.0 / MASK);
612     double sca = sca_org * (1.0 / MASK);
613     double sa = sa_org * (1.0 / MASK);
614     double rca;
615
616     if (2 * sca < sa) {
617         if (da == 0)
618             rca = dca * sa;
619         else
620             rca = dca * sa - dca * (da - dca) * (sa - 2 * sca) / da;
621     } else if (da == 0) {
622         rca = 0;
623     } else if (4 * dca <= da) {
624         rca = dca * sa + (2 * sca - sa) * dca * ((16 * dca / da - 12) * dca / da + 3);
625     } else {
626         rca = dca * sa + (sqrt (dca * da) - dca) * (2 * sca - sa);
627     }
628     return rca * MASK + 0.5;
629 }
630
631 PdfSeparableBlendMode (SoftLight)
632
633 /*
634  * Difference
635  * B(Dca, ab, Sca, as) = abs (Dca.Sa - Sca.Da)
636  */
637
638 static inline comp4_t
639 BlendDifference (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
640 {
641     comp4_t dcasa = dca * sa;
642     comp4_t scada = sca * da;
643
644     if (scada < dcasa)
645         return DivOne (dcasa - scada);
646     else
647         return DivOne (scada - dcasa);
648 }
649
650 PdfSeparableBlendMode (Difference)
651
652 /*
653  * Exclusion
654  * B(Dca, ab, Sca, as) = (Sca.Da + Dca.Sa - 2.Sca.Dca)
655  */
656
657 /* This can be made faster by writing it directly and not using
658  * PdfSeparableBlendMode, but that's a performance optimization */
659
660 static inline comp4_t
661 BlendExclusion (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa)
662 {
663     return DivOne (sca * da + dca * sa - 2 * dca * sca);
664 }
665
666 PdfSeparableBlendMode (Exclusion)
667
668 #undef PdfSeparableBlendMode
669
670 /*
671  * PDF nonseperable blend modes are implemented using the following functions
672  * to operate in HSL space, with Cmax, Cmid, Cmin referring to the max, mid 
673  * and min value of the red, green and blue components.
674  * 
675  * Lum (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue
676  *
677  * ClipColor (C):
678  *   l = Lum (C)
679  *   min = Cmin
680  *   max = Cmax
681  *   if n < 0.0
682  *     C = l + ( ( ( C – l ) × l ) ⁄ ( l – min ) )
683  *   if x > 1.0
684  *     C = l + ( ( ( C – l ) × ( 1 – l ) ) ⁄ ( max – l ) )
685  *   return C
686  *
687  * SetLum (C, l):
688  *   d = l – Lum (C)
689  *   C += d
690  *   return ClipColor (C)
691  *
692  * Sat (C) = Max (C) - Min (C)
693  *
694  * SetSat (C, s):
695  *  if Cmax > Cmin
696  *    Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) )
697  *    Cmax = s
698  *  else
699  *    Cmid = Cmax = 0.0
700  *  Cmin = 0.0
701  *  return C
702  */
703
704 /* For premultiplied colors, we need to know what happens when C is
705  * multiplied by a real number. Lum and Sat are linear:
706  *
707  *    Lum (r × C) = r × Lum (C)               Sat (r * C) = r * Sat (C)
708  *
709  * If we extend ClipColor with an extra argument a and change
710  *
711  *        if x >= 1.0
712  *
713  * into
714  *
715  *        if x >= a
716  *
717  * then ClipColor is also linear:
718  *
719  *    r * ClipColor (C, a) = ClipColor (rC, ra);
720  *
721  * for positive r.
722  *
723  * Similarly, we can extend SetLum with an extra argument that is just passed
724  * on to ClipColor:
725  *
726  *   r * SetLum ( C, l, a)
727  *
728  *   = r × ClipColor ( C + l - Lum (C), a)
729  *
730  *   = ClipColor ( r * C + r × l - r * Lum (C), r * a)
731  *
732  *   = SetLum ( r * C, r * l, r * a)
733  *
734  * Finally, SetSat:
735  *
736  *    r * SetSat (C, s) = SetSat (x * C, r * s)
737  *
738  * The above holds for all non-zero x, because they x'es in the fraction for
739  * C_mid cancel out. Specifically, it holds for x = r:
740  *
741  *    r * SetSat (C, s) = SetSat (rC, rs)
742  *  
743  */
744
745 /* So, for the non-separable PDF blend modes, we have (using s, d for non-premultiplied
746  * colors, and S, D for premultiplied:
747  *
748  *   Color:
749  *
750  *     a_s * a_d * B(s, d)
751  *   = a_s * a_d * SetLum (S/a_s, Lum (D/a_d), 1)
752  *   = SetLum (S * a_d, a_s * Lum (D), a_s * a_d)
753  *
754  *
755  *   Luminosity:
756  *
757  *     a_s * a_d * B(s, d)
758  *   = a_s * a_d * SetLum (D/a_d, Lum(S/a_s), 1)
759  *   = SetLum (a_s * D, a_d * Lum(S), a_s * a_d)
760  *
761  *
762  *   Saturation:
763  *
764  *     a_s * a_d * B(s, d)
765  *   = a_s * a_d * SetLum (SetSat (D/a_d, Sat (S/a_s)), Lum (D/a_d), 1)
766  *   = SetLum (a_s * a_d * SetSat (D/a_d, Sat (S/a_s)), a_s * Lum (D), a_s * a_d)
767  *   = SetLum (SetSat (a_s * D, a_d * Sat (S), a_s * Lum (D), a_s * a_d))
768  *
769  *   Hue:
770  *
771  *     a_s * a_d * B(s, d)
772  *   = a_s * a_d * SetLum (SetSat (S/a_s, Sat (D/a_d)), Lum (D/a_d), 1)
773  *   = a_s * a_d * SetLum (SetSat (a_d * S, a_s * Sat (D)), a_s * Lum (D), a_s * a_d)
774  *
775  */
776     
777 #define Min(c) (c[0] < c[1] ? (c[0] < c[2] ? c[0] : c[2]) : (c[1] < c[2] ? c[1] : c[2]))
778 #define Max(c) (c[0] > c[1] ? (c[0] > c[2] ? c[0] : c[2]) : (c[1] > c[2] ? c[1] : c[2]))
779 #define Lum(c) ((c[0] * 30 + c[1] * 59 + c[2] * 11) / 100)
780 #define Sat(c) (Max (c) - Min (c))
781
782 #define PdfNonSeparableBlendMode(name)                                  \
783 static void                                                             \
784 fbCombine ## name ## U (pixman_implementation_t *imp, pixman_op_t op,   \
785                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width) \
786 {                                                                       \
787     int i;                                                              \
788     for (i = 0; i < width; ++i) {                                       \
789         comp4_t s = combineMask (src, mask, i);                         \
790         comp4_t d = *(dest + i);                                        \
791         comp1_t sa = Alpha(s);                                          \
792         comp1_t isa = ~sa;                                              \
793         comp1_t da = Alpha(d);                                          \
794         comp1_t ida = ~da;                                              \
795         comp4_t result;                                                 \
796         comp4_t sc[3], dc[3], c[3];                                     \
797                                                                         \
798         result = d;                                                     \
799         FbByteAddMul(result, isa, s, ida);                              \
800         dc[0] = Red (d);                                                \
801         sc[0] = Red (s);                                                \
802         dc[1] = Green (d);                                              \
803         sc[1] = Green (s);                                              \
804         dc[2] = Blue (d);                                               \
805         sc[2] = Blue (s);                                               \
806         Blend ## name (c, dc, da, sc, sa);                              \
807                                                                         \
808         *(dest + i) = result +                                          \
809             (DivOne (sa * da) << A_SHIFT) +                             \
810             (DivOne (c[0]) << R_SHIFT) +                                \
811             (DivOne (c[1]) << G_SHIFT) +                                \
812             (DivOne (c[2]));                                            \
813     }                                                                   \
814 }                                                                       
815
816 static void
817 SetLum (comp4_t dest[3], comp4_t src[3], comp4_t sa, comp4_t lum)
818 {
819   double a, l, min, max;
820   double tmp[3];
821   
822   a = sa * (1.0 / MASK);
823   l = lum * (1.0 / MASK);
824   tmp[0] = src[0] * (1.0 / MASK);
825   tmp[1] = src[1] * (1.0 / MASK);
826   tmp[2] = src[2] * (1.0 / MASK);
827   l = l - Lum (tmp);
828   tmp[0] += l;
829   tmp[1] += l;
830   tmp[2] += l;
831
832   /* ClipColor */
833   l = Lum (tmp);
834   min = Min (tmp);
835   max = Max (tmp);
836
837   if (min < 0) {
838     tmp[0] = l + (tmp[0] - l) * l / (l - min);
839     tmp[1] = l + (tmp[1] - l) * l / (l - min);
840     tmp[2] = l + (tmp[2] - l) * l / (l - min);
841   }
842   if (max > a) {
843     tmp[0] = l + (tmp[0] - l) * (a - l) / (max - l);
844     tmp[1] = l + (tmp[1] - l) * (a - l) / (max - l);
845     tmp[2] = l + (tmp[2] - l) * (a - l) / (max - l);
846   }
847   dest[0] = tmp[0] * MASK + 0.5;
848   dest[1] = tmp[1] * MASK + 0.5;
849   dest[2] = tmp[2] * MASK + 0.5;
850 }
851
852 static void
853 SetSat (comp4_t dest[3], comp4_t src[3], comp4_t sat)
854 {
855   int id[3];
856   comp4_t min, max;
857
858   if (src[0] > src[1]) {
859     if (src[0] > src[2]) {
860       id[0] = 0;
861       if (src[1] > src[2]) {
862         id[1] = 1;
863         id[2] = 2;
864       } else {
865         id[1] = 2;
866         id[2] = 1;
867       }
868     } else {
869       id[0] = 2;
870       id[1] = 0;
871       id[2] = 1;
872     }
873   } else {
874     if (src[0] > src[2]) {
875       id[0] = 1;
876       id[1] = 0;
877       id[2] = 2;
878     } else {
879       id[2] = 0;
880       if (src[1] > src[2]) {
881         id[0] = 1;
882         id[1] = 2;
883       } else {
884         id[0] = 2;
885         id[1] = 1;
886       }
887     }
888   }
889   max = dest[id[0]];
890   min = dest[id[2]];
891   if (max > min) {
892     dest[id[1]] = (dest[id[1]] - min) * sat / (max - min);
893     dest[id[0]] = sat;
894     dest[id[2]] = 0;
895   } else {
896     dest[0] = dest[1] = dest[2] = 0;
897   }
898 }
899
900 /*
901  * Hue:
902  * B(Cb, Cs) = SetLum (SetSat (Cs, Sat (Cb)), Lum (Cb))
903  */
904 static inline void
905 BlendHSLHue (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa)
906 {
907     c[0] = sc[0] * da;
908     c[1] = sc[1] * da;
909     c[2] = sc[2] * da;
910     SetSat (c, c, Sat (dc) * sa);
911     SetLum (c, c, sa * da, Lum (dc) * sa);
912 }
913
914 PdfNonSeparableBlendMode (HSLHue)
915
916 /*
917  * Saturation:
918  * B(Cb, Cs) = SetLum (SetSat (Cb, Sat (Cs)), Lum (Cb))
919  */
920 static inline void
921 BlendHSLSaturation (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa)
922 {
923     c[0] = dc[0] * sa;
924     c[1] = dc[1] * sa;
925     c[2] = dc[2] * sa;
926     SetSat (c, c, Sat (sc) * da);
927     SetLum (c, c, sa * da, Lum (dc) * sa);
928 }
929
930 PdfNonSeparableBlendMode (HSLSaturation)
931
932 /*
933  * Color:
934  * B(Cb, Cs) = SetLum (Cs, Lum (Cb))
935  */
936 static inline void
937 BlendHSLColor (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa)
938 {
939     c[0] = sc[0] * da;
940     c[1] = sc[1] * da;
941     c[2] = sc[2] * da;
942     SetLum (c, c, sa * da, Lum (dc) * sa);
943 }
944
945 PdfNonSeparableBlendMode (HSLColor)
946
947 /*
948  * Luminosity:
949  * B(Cb, Cs) = SetLum (Cb, Lum (Cs))
950  */
951 static inline void
952 BlendHSLLuminosity (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa)
953 {
954     c[0] = dc[0] * sa;
955     c[1] = dc[1] * sa;
956     c[2] = dc[2] * sa;
957     SetLum (c, c, sa * da, Lum (sc) * da);
958 }
959
960 PdfNonSeparableBlendMode (HSLLuminosity)
961
962 #undef Sat
963 #undef Lum
964 #undef Max
965 #undef Min
966 #undef PdfNonSeparableBlendMode
967
968 /* Overlay
969  *
970  * All of the disjoint composing functions
971
972  The four entries in the first column indicate what source contributions
973  come from each of the four areas of the picture -- areas covered by neither
974  A nor B, areas covered only by A, areas covered only by B and finally
975  areas covered by both A and B.
976
977  Disjoint                       Conjoint
978  Fa             Fb              Fa              Fb
979  (0,0,0,0)      0               0               0               0
980  (0,A,0,A)      1               0               1               0
981  (0,0,B,B)      0               1               0               1
982  (0,A,B,A)      1               min((1-a)/b,1)  1               max(1-a/b,0)
983  (0,A,B,B)      min((1-b)/a,1)  1               max(1-b/a,0)    1
984  (0,0,0,A)      max(1-(1-b)/a,0) 0              min(1,b/a)      0
985  (0,0,0,B)      0               max(1-(1-a)/b,0) 0              min(a/b,1)
986  (0,A,0,0)      min(1,(1-b)/a)  0               max(1-b/a,0)    0
987  (0,0,B,0)      0               min(1,(1-a)/b)  0               max(1-a/b,0)
988  (0,0,B,A)      max(1-(1-b)/a,0) min(1,(1-a)/b)  min(1,b/a)     max(1-a/b,0)
989  (0,A,0,B)      min(1,(1-b)/a)  max(1-(1-a)/b,0) max(1-b/a,0)   min(1,a/b)
990  (0,A,B,0)      min(1,(1-b)/a)  min(1,(1-a)/b)  max(1-b/a,0)    max(1-a/b,0)
991
992 */
993
994 #define CombineAOut 1
995 #define CombineAIn  2
996 #define CombineBOut 4
997 #define CombineBIn  8
998
999 #define CombineClear    0
1000 #define CombineA        (CombineAOut|CombineAIn)
1001 #define CombineB        (CombineBOut|CombineBIn)
1002 #define CombineAOver    (CombineAOut|CombineBOut|CombineAIn)
1003 #define CombineBOver    (CombineAOut|CombineBOut|CombineBIn)
1004 #define CombineAAtop    (CombineBOut|CombineAIn)
1005 #define CombineBAtop    (CombineAOut|CombineBIn)
1006 #define CombineXor      (CombineAOut|CombineBOut)
1007
1008 /* portion covered by a but not b */
1009 static comp1_t
1010 fbCombineDisjointOutPart (comp1_t a, comp1_t b)
1011 {
1012     /* min (1, (1-b) / a) */
1013
1014     b = ~b;                 /* 1 - b */
1015     if (b >= a)             /* 1 - b >= a -> (1-b)/a >= 1 */
1016         return MASK;        /* 1 */
1017     return IntDiv(b,a);     /* (1-b) / a */
1018 }
1019
1020 /* portion covered by both a and b */
1021 static comp1_t
1022 fbCombineDisjointInPart (comp1_t a, comp1_t b)
1023 {
1024     /* max (1-(1-b)/a,0) */
1025     /*  = - min ((1-b)/a - 1, 0) */
1026     /*  = 1 - min (1, (1-b)/a) */
1027
1028     b = ~b;                 /* 1 - b */
1029     if (b >= a)             /* 1 - b >= a -> (1-b)/a >= 1 */
1030         return 0;           /* 1 - 1 */
1031     return ~IntDiv(b,a);    /* 1 - (1-b) / a */
1032 }
1033
1034 /* portion covered by a but not b */
1035 static comp1_t
1036 fbCombineConjointOutPart (comp1_t a, comp1_t b)
1037 {
1038     /* max (1-b/a,0) */
1039     /* = 1-min(b/a,1) */
1040
1041     /* min (1, (1-b) / a) */
1042
1043     if (b >= a)             /* b >= a -> b/a >= 1 */
1044         return 0x00;        /* 0 */
1045     return ~IntDiv(b,a);    /* 1 - b/a */
1046 }
1047
1048 /* portion covered by both a and b */
1049 static comp1_t
1050 fbCombineConjointInPart (comp1_t a, comp1_t b)
1051 {
1052     /* min (1,b/a) */
1053
1054     if (b >= a)             /* b >= a -> b/a >= 1 */
1055         return MASK;        /* 1 */
1056     return IntDiv(b,a);     /* b/a */
1057 }
1058
1059 #define GetComp(v,i)   ((comp2_t) (comp1_t) ((v) >> i))
1060
1061 #define Add(x,y,i,t)   ((t) = GetComp(x,i) + GetComp(y,i),              \
1062                         (comp4_t) ((comp1_t) ((t) | (0 - ((t) >> G_SHIFT)))) << (i))
1063
1064 #define FbGen(x,y,i,ax,ay,t,u,v) ((t) = (IntMult(GetComp(y,i),ay,(u)) + \
1065                                          IntMult(GetComp(x,i),ax,(v))), \
1066                                          (comp4_t) ((comp1_t) ((t) |            \
1067                                          (0 - ((t) >> G_SHIFT)))) << (i))
1068
1069 static void
1070 fbCombineDisjointGeneralU (comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width, comp1_t combine)
1071 {
1072     int i;
1073     for (i = 0; i < width; ++i) {
1074         comp4_t s = combineMask (src, mask, i);
1075         comp4_t d = *(dest + i);
1076         comp4_t m,n,o,p;
1077         comp2_t Fa, Fb, t, u, v;
1078         comp1_t sa = s >> A_SHIFT;
1079         comp1_t da = d >> A_SHIFT;
1080
1081         switch (combine & CombineA) {
1082         default:
1083             Fa = 0;
1084             break;
1085         case CombineAOut:
1086             Fa = fbCombineDisjointOutPart (sa, da);
1087             break;
1088         case CombineAIn:
1089             Fa = fbCombineDisjointInPart (sa, da);
1090             break;
1091         case CombineA:
1092             Fa = MASK;
1093             break;
1094         }
1095
1096         switch (combine & CombineB) {
1097         default:
1098             Fb = 0;
1099             break;
1100         case CombineBOut:
1101             Fb = fbCombineDisjointOutPart (da, sa);
1102             break;
1103         case CombineBIn:
1104             Fb = fbCombineDisjointInPart (da, sa);
1105             break;
1106         case CombineB:
1107             Fb = MASK;
1108             break;
1109         }
1110         m = FbGen (s,d,0,Fa,Fb,t, u, v);
1111         n = FbGen (s,d,G_SHIFT,Fa,Fb,t, u, v);
1112         o = FbGen (s,d,R_SHIFT,Fa,Fb,t, u, v);
1113         p = FbGen (s,d,A_SHIFT,Fa,Fb,t, u, v);
1114         s = m|n|o|p;
1115         *(dest + i) = s;
1116     }
1117 }
1118
1119 static void
1120 fbCombineDisjointOverU (pixman_implementation_t *imp, pixman_op_t op,
1121                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1122 {
1123     int i;
1124     for (i = 0; i < width; ++i) {
1125         comp4_t s = combineMask (src, mask, i);
1126         comp2_t a = s >> A_SHIFT;
1127
1128         if (a != 0x00)
1129         {
1130             if (a != MASK)
1131             {
1132                 comp4_t d = *(dest + i);
1133                 a = fbCombineDisjointOutPart (d >> A_SHIFT, a);
1134                 FbByteMulAdd(d, a, s);
1135                 s = d;
1136             }
1137             *(dest + i) = s;
1138         }
1139     }
1140 }
1141
1142 static void
1143 fbCombineDisjointInU (pixman_implementation_t *imp, pixman_op_t op,
1144                       comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1145 {
1146     fbCombineDisjointGeneralU (dest, src, mask, width, CombineAIn);
1147 }
1148
1149 static void
1150 fbCombineDisjointInReverseU (pixman_implementation_t *imp, pixman_op_t op,
1151                              comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1152 {
1153     fbCombineDisjointGeneralU (dest, src, mask, width, CombineBIn);
1154 }
1155
1156 static void
1157 fbCombineDisjointOutU (pixman_implementation_t *imp, pixman_op_t op,
1158                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1159 {
1160     fbCombineDisjointGeneralU (dest, src, mask, width, CombineAOut);
1161 }
1162
1163 static void
1164 fbCombineDisjointOutReverseU (pixman_implementation_t *imp, pixman_op_t op,
1165                               comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1166 {
1167     fbCombineDisjointGeneralU (dest, src, mask, width, CombineBOut);
1168 }
1169
1170 static void
1171 fbCombineDisjointAtopU (pixman_implementation_t *imp, pixman_op_t op,
1172                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1173 {
1174     fbCombineDisjointGeneralU (dest, src, mask, width, CombineAAtop);
1175 }
1176
1177 static void
1178 fbCombineDisjointAtopReverseU (pixman_implementation_t *imp, pixman_op_t op,
1179                                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1180 {
1181     fbCombineDisjointGeneralU (dest, src, mask, width, CombineBAtop);
1182 }
1183
1184 static void
1185 fbCombineDisjointXorU (pixman_implementation_t *imp, pixman_op_t op,
1186                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1187 {
1188     fbCombineDisjointGeneralU (dest, src, mask, width, CombineXor);
1189 }
1190
1191 static void
1192 fbCombineConjointGeneralU (comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width, comp1_t combine)
1193 {
1194     int i;
1195     for (i = 0; i < width; ++i) {
1196         comp4_t s = combineMask (src, mask, i);
1197         comp4_t d = *(dest + i);
1198         comp4_t m,n,o,p;
1199         comp2_t Fa, Fb, t, u, v;
1200         comp1_t sa = s >> A_SHIFT;
1201         comp1_t da = d >> A_SHIFT;
1202
1203         switch (combine & CombineA) {
1204         default:
1205             Fa = 0;
1206             break;
1207         case CombineAOut:
1208             Fa = fbCombineConjointOutPart (sa, da);
1209             break;
1210         case CombineAIn:
1211             Fa = fbCombineConjointInPart (sa, da);
1212             break;
1213         case CombineA:
1214             Fa = MASK;
1215             break;
1216         }
1217
1218         switch (combine & CombineB) {
1219         default:
1220             Fb = 0;
1221             break;
1222         case CombineBOut:
1223             Fb = fbCombineConjointOutPart (da, sa);
1224             break;
1225         case CombineBIn:
1226             Fb = fbCombineConjointInPart (da, sa);
1227             break;
1228         case CombineB:
1229             Fb = MASK;
1230             break;
1231         }
1232         m = FbGen (s,d,0,Fa,Fb,t, u, v);
1233         n = FbGen (s,d,G_SHIFT,Fa,Fb,t, u, v);
1234         o = FbGen (s,d,R_SHIFT,Fa,Fb,t, u, v);
1235         p = FbGen (s,d,A_SHIFT,Fa,Fb,t, u, v);
1236         s = m|n|o|p;
1237         *(dest + i) = s;
1238     }
1239 }
1240
1241 static void
1242 fbCombineConjointOverU (pixman_implementation_t *imp, pixman_op_t op,
1243                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1244 {
1245     fbCombineConjointGeneralU (dest, src, mask, width, CombineAOver);
1246 }
1247
1248
1249 static void
1250 fbCombineConjointOverReverseU (pixman_implementation_t *imp, pixman_op_t op,
1251                                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1252 {
1253     fbCombineConjointGeneralU (dest, src, mask, width, CombineBOver);
1254 }
1255
1256
1257 static void
1258 fbCombineConjointInU (pixman_implementation_t *imp, pixman_op_t op,
1259                       comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1260 {
1261     fbCombineConjointGeneralU (dest, src, mask, width, CombineAIn);
1262 }
1263
1264
1265 static void
1266 fbCombineConjointInReverseU (pixman_implementation_t *imp, pixman_op_t op,
1267                              comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1268 {
1269     fbCombineConjointGeneralU (dest, src, mask, width, CombineBIn);
1270 }
1271
1272 static void
1273 fbCombineConjointOutU (pixman_implementation_t *imp, pixman_op_t op,
1274                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1275 {
1276     fbCombineConjointGeneralU (dest, src, mask, width, CombineAOut);
1277 }
1278
1279 static void
1280 fbCombineConjointOutReverseU (pixman_implementation_t *imp, pixman_op_t op,
1281                               comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1282 {
1283     fbCombineConjointGeneralU (dest, src, mask, width, CombineBOut);
1284 }
1285
1286 static void
1287 fbCombineConjointAtopU (pixman_implementation_t *imp, pixman_op_t op,
1288                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1289 {
1290     fbCombineConjointGeneralU (dest, src, mask, width, CombineAAtop);
1291 }
1292
1293 static void
1294 fbCombineConjointAtopReverseU (pixman_implementation_t *imp, pixman_op_t op,
1295                                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1296 {
1297     fbCombineConjointGeneralU (dest, src, mask, width, CombineBAtop);
1298 }
1299
1300 static void
1301 fbCombineConjointXorU (pixman_implementation_t *imp, pixman_op_t op,
1302                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1303 {
1304     fbCombineConjointGeneralU (dest, src, mask, width, CombineXor);
1305 }
1306
1307 /********************************************************************************/
1308 /*************************** Per Channel functions ******************************/
1309 /********************************************************************************/
1310
1311 static void
1312 fbCombineClearC (pixman_implementation_t *imp, pixman_op_t op,
1313                  comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1314 {
1315     memset(dest, 0, width*sizeof(comp4_t));
1316 }
1317
1318 static void
1319 fbCombineSrcC (pixman_implementation_t *imp, pixman_op_t op,
1320                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1321 {
1322     int i;
1323
1324     for (i = 0; i < width; ++i) {
1325         comp4_t s = *(src + i);
1326         comp4_t m = *(mask + i);
1327
1328         fbCombineMaskValueC (&s, &m);
1329
1330         *(dest) = s;
1331     }
1332 }
1333
1334 static void
1335 fbCombineOverC (pixman_implementation_t *imp, pixman_op_t op,
1336                 comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1337 {
1338     int i;
1339
1340     for (i = 0; i < width; ++i) {
1341         comp4_t s = *(src + i);
1342         comp4_t m = *(mask + i);
1343         comp4_t a;
1344
1345         fbCombineMaskC (&s, &m);
1346
1347         a = ~m;
1348         if (a != ~0)
1349         {
1350             if (a)
1351             {
1352                 comp4_t d = *(dest + i);
1353                 FbByteMulAddC(d, a, s);
1354                 s = d;
1355             }
1356             *(dest + i) = s;
1357         }
1358     }
1359 }
1360
1361 static void
1362 fbCombineOverReverseC (pixman_implementation_t *imp, pixman_op_t op,
1363                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1364 {
1365     int i;
1366
1367     for (i = 0; i < width; ++i) {
1368         comp4_t d = *(dest + i);
1369         comp4_t a = ~d >> A_SHIFT;
1370
1371         if (a)
1372         {
1373             comp4_t s = *(src + i);
1374             comp4_t m = *(mask + i);
1375
1376             fbCombineMaskValueC (&s, &m);
1377
1378             if (a != MASK)
1379             {
1380                 FbByteMulAdd(s, a, d);
1381             }
1382             *(dest + i) = s;
1383         }
1384     }
1385 }
1386
1387 static void
1388 fbCombineInC (pixman_implementation_t *imp, pixman_op_t op,
1389               comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1390 {
1391     int i;
1392
1393     for (i = 0; i < width; ++i) {
1394         comp4_t d = *(dest + i);
1395         comp2_t a = d >> A_SHIFT;
1396         comp4_t s = 0;
1397         if (a)
1398         {
1399             comp4_t m = *(mask + i);
1400
1401             s = *(src + i);
1402             fbCombineMaskValueC (&s, &m);
1403             if (a != MASK)
1404             {
1405                 FbByteMul(s, a);
1406             }
1407         }
1408         *(dest + i) = s;
1409     }
1410 }
1411
1412 static void
1413 fbCombineInReverseC (pixman_implementation_t *imp, pixman_op_t op,
1414                      comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1415 {
1416     int i;
1417
1418     for (i = 0; i < width; ++i) {
1419         comp4_t s = *(src + i);
1420         comp4_t m = *(mask + i);
1421         comp4_t a;
1422
1423         fbCombineMaskAlphaC (&s, &m);
1424
1425         a = m;
1426         if (a != ~0)
1427         {
1428             comp4_t d = 0;
1429             if (a)
1430             {
1431                 d = *(dest + i);
1432                 FbByteMulC(d, a);
1433             }
1434             *(dest + i) = d;
1435         }
1436     }
1437 }
1438
1439 static void
1440 fbCombineOutC (pixman_implementation_t *imp, pixman_op_t op,
1441                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1442 {
1443     int i;
1444
1445     for (i = 0; i < width; ++i) {
1446         comp4_t d = *(dest + i);
1447         comp2_t a = ~d >> A_SHIFT;
1448         comp4_t s = 0;
1449         if (a)
1450         {
1451             comp4_t m = *(mask + i);
1452
1453             s = *(src + i);
1454             fbCombineMaskValueC (&s, &m);
1455
1456             if (a != MASK)
1457             {
1458                 FbByteMul(s, a);
1459             }
1460         }
1461         *(dest + i) = s;
1462     }
1463 }
1464
1465 static void
1466 fbCombineOutReverseC (pixman_implementation_t *imp, pixman_op_t op,
1467                       comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1468 {
1469     int i;
1470
1471     for (i = 0; i < width; ++i) {
1472         comp4_t s = *(src + i);
1473         comp4_t m = *(mask + i);
1474         comp4_t a;
1475
1476         fbCombineMaskAlphaC (&s, &m);
1477
1478         a = ~m;
1479         if (a != ~0)
1480         {
1481             comp4_t d = 0;
1482             if (a)
1483             {
1484                 d = *(dest + i);
1485                 FbByteMulC(d, a);
1486             }
1487             *(dest + i) = d;
1488         }
1489     }
1490 }
1491
1492 static void
1493 fbCombineAtopC (pixman_implementation_t *imp, pixman_op_t op,
1494                 comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1495 {
1496     int i;
1497
1498     for (i = 0; i < width; ++i) {
1499         comp4_t d = *(dest + i);
1500         comp4_t s = *(src + i);
1501         comp4_t m = *(mask + i);
1502         comp4_t ad;
1503         comp2_t as = d >> A_SHIFT;
1504
1505         fbCombineMaskC (&s, &m);
1506
1507         ad = ~m;
1508
1509         FbByteAddMulC(d, ad, s, as);
1510         *(dest + i) = d;
1511     }
1512 }
1513
1514 static void
1515 fbCombineAtopReverseC (pixman_implementation_t *imp, pixman_op_t op,
1516                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1517 {
1518     int i;
1519
1520     for (i = 0; i < width; ++i) {
1521
1522         comp4_t d = *(dest + i);
1523         comp4_t s = *(src + i);
1524         comp4_t m = *(mask + i);
1525         comp4_t ad;
1526         comp2_t as = ~d >> A_SHIFT;
1527
1528         fbCombineMaskC (&s, &m);
1529
1530         ad = m;
1531
1532         FbByteAddMulC(d, ad, s, as);
1533         *(dest + i) = d;
1534     }
1535 }
1536
1537 static void
1538 fbCombineXorC (pixman_implementation_t *imp, pixman_op_t op,
1539                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1540 {
1541     int i;
1542
1543     for (i = 0; i < width; ++i) {
1544         comp4_t d = *(dest + i);
1545         comp4_t s = *(src + i);
1546         comp4_t m = *(mask + i);
1547         comp4_t ad;
1548         comp2_t as = ~d >> A_SHIFT;
1549
1550         fbCombineMaskC (&s, &m);
1551
1552         ad = ~m;
1553
1554         FbByteAddMulC(d, ad, s, as);
1555         *(dest + i) = d;
1556     }
1557 }
1558
1559 static void
1560 fbCombineAddC (pixman_implementation_t *imp, pixman_op_t op,
1561                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1562 {
1563     int i;
1564
1565     for (i = 0; i < width; ++i) {
1566         comp4_t s = *(src + i);
1567         comp4_t m = *(mask + i);
1568         comp4_t d = *(dest + i);
1569
1570         fbCombineMaskValueC (&s, &m);
1571
1572         FbByteAdd(d, s);
1573         *(dest + i) = d;
1574     }
1575 }
1576
1577 static void
1578 fbCombineSaturateC (pixman_implementation_t *imp, pixman_op_t op,
1579                     comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1580 {
1581     int i;
1582
1583     for (i = 0; i < width; ++i) {
1584         comp4_t s, d;
1585         comp2_t sa, sr, sg, sb, da;
1586         comp2_t t, u, v;
1587         comp4_t m,n,o,p;
1588
1589         d = *(dest + i);
1590         s = *(src + i);
1591         m = *(mask + i);
1592
1593         fbCombineMaskC (&s, &m);
1594
1595         sa = (m >> A_SHIFT);
1596         sr = (m >> R_SHIFT) & MASK;
1597         sg = (m >> G_SHIFT) & MASK;
1598         sb =  m             & MASK;
1599         da = ~d >> A_SHIFT;
1600
1601         if (sb <= da)
1602             m = Add(s,d,0,t);
1603         else
1604             m = FbGen (s, d, 0, (da << G_SHIFT) / sb, MASK, t, u, v);
1605
1606         if (sg <= da)
1607             n = Add(s,d,G_SHIFT,t);
1608         else
1609             n = FbGen (s, d, G_SHIFT, (da << G_SHIFT) / sg, MASK, t, u, v);
1610
1611         if (sr <= da)
1612             o = Add(s,d,R_SHIFT,t);
1613         else
1614             o = FbGen (s, d, R_SHIFT, (da << G_SHIFT) / sr, MASK, t, u, v);
1615
1616         if (sa <= da)
1617             p = Add(s,d,A_SHIFT,t);
1618         else
1619             p = FbGen (s, d, A_SHIFT, (da << G_SHIFT) / sa, MASK, t, u, v);
1620
1621         *(dest + i) = m|n|o|p;
1622     }
1623 }
1624
1625 static void
1626 fbCombineDisjointGeneralC (comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width, comp1_t combine)
1627 {
1628     int i;
1629
1630     for (i = 0; i < width; ++i) {
1631         comp4_t s, d;
1632         comp4_t m,n,o,p;
1633         comp4_t Fa, Fb;
1634         comp2_t t, u, v;
1635         comp4_t sa;
1636         comp1_t da;
1637
1638         s = *(src + i);
1639         m = *(mask + i);
1640         d = *(dest + i);
1641         da = d >> A_SHIFT;
1642
1643         fbCombineMaskC (&s, &m);
1644
1645         sa = m;
1646
1647         switch (combine & CombineA) {
1648         default:
1649             Fa = 0;
1650             break;
1651         case CombineAOut:
1652             m = (comp4_t)fbCombineDisjointOutPart ((comp1_t) (sa >> 0), da);
1653             n = (comp4_t)fbCombineDisjointOutPart ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT;
1654             o = (comp4_t)fbCombineDisjointOutPart ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT;
1655             p = (comp4_t)fbCombineDisjointOutPart ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT;
1656             Fa = m|n|o|p;
1657             break;
1658         case CombineAIn:
1659             m = (comp4_t)fbCombineDisjointInPart ((comp1_t) (sa >> 0), da);
1660             n = (comp4_t)fbCombineDisjointInPart ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT;
1661             o = (comp4_t)fbCombineDisjointInPart ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT;
1662             p = (comp4_t)fbCombineDisjointInPart ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT;
1663             Fa = m|n|o|p;
1664             break;
1665         case CombineA:
1666             Fa = ~0;
1667             break;
1668         }
1669
1670         switch (combine & CombineB) {
1671         default:
1672             Fb = 0;
1673             break;
1674         case CombineBOut:
1675             m = (comp4_t)fbCombineDisjointOutPart (da, (comp1_t) (sa >> 0));
1676             n = (comp4_t)fbCombineDisjointOutPart (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT;
1677             o = (comp4_t)fbCombineDisjointOutPart (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT;
1678             p = (comp4_t)fbCombineDisjointOutPart (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT;
1679             Fb = m|n|o|p;
1680             break;
1681         case CombineBIn:
1682             m = (comp4_t)fbCombineDisjointInPart (da, (comp1_t) (sa >> 0));
1683             n = (comp4_t)fbCombineDisjointInPart (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT;
1684             o = (comp4_t)fbCombineDisjointInPart (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT;
1685             p = (comp4_t)fbCombineDisjointInPart (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT;
1686             Fb = m|n|o|p;
1687             break;
1688         case CombineB:
1689             Fb = ~0;
1690             break;
1691         }
1692         m = FbGen (s,d,0,GetComp(Fa,0),GetComp(Fb,0),t, u, v);
1693         n = FbGen (s,d,G_SHIFT,GetComp(Fa,G_SHIFT),GetComp(Fb,G_SHIFT),t, u, v);
1694         o = FbGen (s,d,R_SHIFT,GetComp(Fa,R_SHIFT),GetComp(Fb,R_SHIFT),t, u, v);
1695         p = FbGen (s,d,A_SHIFT,GetComp(Fa,A_SHIFT),GetComp(Fb,A_SHIFT),t, u, v);
1696         s = m|n|o|p;
1697         *(dest + i) = s;
1698     }
1699 }
1700
1701 static void
1702 fbCombineDisjointOverC (pixman_implementation_t *imp, pixman_op_t op,
1703                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1704 {
1705     fbCombineDisjointGeneralC (dest, src, mask, width, CombineAOver);
1706 }
1707
1708 static void
1709 fbCombineDisjointInC (pixman_implementation_t *imp, pixman_op_t op,
1710                       comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1711 {
1712     fbCombineDisjointGeneralC (dest, src, mask, width, CombineAIn);
1713 }
1714
1715 static void
1716 fbCombineDisjointInReverseC (pixman_implementation_t *imp, pixman_op_t op,
1717                              comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1718 {
1719     fbCombineDisjointGeneralC (dest, src, mask, width, CombineBIn);
1720 }
1721
1722 static void
1723 fbCombineDisjointOutC (pixman_implementation_t *imp, pixman_op_t op,
1724                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1725 {
1726     fbCombineDisjointGeneralC (dest, src, mask, width, CombineAOut);
1727 }
1728
1729 static void
1730 fbCombineDisjointOutReverseC (pixman_implementation_t *imp, pixman_op_t op,
1731                               comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1732 {
1733     fbCombineDisjointGeneralC (dest, src, mask, width, CombineBOut);
1734 }
1735
1736 static void
1737 fbCombineDisjointAtopC (pixman_implementation_t *imp, pixman_op_t op,
1738                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1739 {
1740     fbCombineDisjointGeneralC (dest, src, mask, width, CombineAAtop);
1741 }
1742
1743 static void
1744 fbCombineDisjointAtopReverseC (pixman_implementation_t *imp, pixman_op_t op,
1745                                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1746 {
1747     fbCombineDisjointGeneralC (dest, src, mask, width, CombineBAtop);
1748 }
1749
1750 static void
1751 fbCombineDisjointXorC (pixman_implementation_t *imp, pixman_op_t op,
1752                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1753 {
1754     fbCombineDisjointGeneralC (dest, src, mask, width, CombineXor);
1755 }
1756
1757 static void
1758 fbCombineConjointGeneralC (comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width, comp1_t combine)
1759 {
1760     int i;
1761
1762     for (i = 0; i < width; ++i) {
1763         comp4_t s, d;
1764         comp4_t m,n,o,p;
1765         comp4_t Fa, Fb;
1766         comp2_t t, u, v;
1767         comp4_t sa;
1768         comp1_t da;
1769
1770         s = *(src + i);
1771         m = *(mask + i);
1772         d = *(dest + i);
1773         da = d >> A_SHIFT;
1774
1775         fbCombineMaskC (&s, &m);
1776
1777         sa = m;
1778
1779         switch (combine & CombineA) {
1780         default:
1781             Fa = 0;
1782             break;
1783         case CombineAOut:
1784             m = (comp4_t)fbCombineConjointOutPart ((comp1_t) (sa >> 0), da);
1785             n = (comp4_t)fbCombineConjointOutPart ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT;
1786             o = (comp4_t)fbCombineConjointOutPart ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT;
1787             p = (comp4_t)fbCombineConjointOutPart ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT;
1788             Fa = m|n|o|p;
1789             break;
1790         case CombineAIn:
1791             m = (comp4_t)fbCombineConjointInPart ((comp1_t) (sa >> 0), da);
1792             n = (comp4_t)fbCombineConjointInPart ((comp1_t) (sa >> G_SHIFT), da) << G_SHIFT;
1793             o = (comp4_t)fbCombineConjointInPart ((comp1_t) (sa >> R_SHIFT), da) << R_SHIFT;
1794             p = (comp4_t)fbCombineConjointInPart ((comp1_t) (sa >> A_SHIFT), da) << A_SHIFT;
1795             Fa = m|n|o|p;
1796             break;
1797         case CombineA:
1798             Fa = ~0;
1799             break;
1800         }
1801
1802         switch (combine & CombineB) {
1803         default:
1804             Fb = 0;
1805             break;
1806         case CombineBOut:
1807             m = (comp4_t)fbCombineConjointOutPart (da, (comp1_t) (sa >> 0));
1808             n = (comp4_t)fbCombineConjointOutPart (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT;
1809             o = (comp4_t)fbCombineConjointOutPart (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT;
1810             p = (comp4_t)fbCombineConjointOutPart (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT;
1811             Fb = m|n|o|p;
1812             break;
1813         case CombineBIn:
1814             m = (comp4_t)fbCombineConjointInPart (da, (comp1_t) (sa >> 0));
1815             n = (comp4_t)fbCombineConjointInPart (da, (comp1_t) (sa >> G_SHIFT)) << G_SHIFT;
1816             o = (comp4_t)fbCombineConjointInPart (da, (comp1_t) (sa >> R_SHIFT)) << R_SHIFT;
1817             p = (comp4_t)fbCombineConjointInPart (da, (comp1_t) (sa >> A_SHIFT)) << A_SHIFT;
1818             Fb = m|n|o|p;
1819             break;
1820         case CombineB:
1821             Fb = ~0;
1822             break;
1823         }
1824         m = FbGen (s,d,0,GetComp(Fa,0),GetComp(Fb,0),t, u, v);
1825         n = FbGen (s,d,G_SHIFT,GetComp(Fa,G_SHIFT),GetComp(Fb,G_SHIFT),t, u, v);
1826         o = FbGen (s,d,R_SHIFT,GetComp(Fa,R_SHIFT),GetComp(Fb,R_SHIFT),t, u, v);
1827         p = FbGen (s,d,A_SHIFT,GetComp(Fa,A_SHIFT),GetComp(Fb,A_SHIFT),t, u, v);
1828         s = m|n|o|p;
1829         *(dest + i) = s;
1830     }
1831 }
1832
1833 static void
1834 fbCombineConjointOverC (pixman_implementation_t *imp, pixman_op_t op,
1835                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1836 {
1837     fbCombineConjointGeneralC (dest, src, mask, width, CombineAOver);
1838 }
1839
1840 static void
1841 fbCombineConjointOverReverseC (pixman_implementation_t *imp, pixman_op_t op,
1842                                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1843 {
1844     fbCombineConjointGeneralC (dest, src, mask, width, CombineBOver);
1845 }
1846
1847 static void
1848 fbCombineConjointInC (pixman_implementation_t *imp, pixman_op_t op,
1849                       comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1850 {
1851     fbCombineConjointGeneralC (dest, src, mask, width, CombineAIn);
1852 }
1853
1854 static void
1855 fbCombineConjointInReverseC (pixman_implementation_t *imp, pixman_op_t op,
1856                              comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1857 {
1858     fbCombineConjointGeneralC (dest, src, mask, width, CombineBIn);
1859 }
1860
1861 static void
1862 fbCombineConjointOutC (pixman_implementation_t *imp, pixman_op_t op,
1863                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1864 {
1865     fbCombineConjointGeneralC (dest, src, mask, width, CombineAOut);
1866 }
1867
1868 static void
1869 fbCombineConjointOutReverseC (pixman_implementation_t *imp, pixman_op_t op,
1870                               comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1871 {
1872     fbCombineConjointGeneralC (dest, src, mask, width, CombineBOut);
1873 }
1874
1875 static void
1876 fbCombineConjointAtopC (pixman_implementation_t *imp, pixman_op_t op,
1877                         comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1878 {
1879     fbCombineConjointGeneralC (dest, src, mask, width, CombineAAtop);
1880 }
1881
1882 static void
1883 fbCombineConjointAtopReverseC (pixman_implementation_t *imp, pixman_op_t op,
1884                                comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1885 {
1886     fbCombineConjointGeneralC (dest, src, mask, width, CombineBAtop);
1887 }
1888
1889 static void
1890 fbCombineConjointXorC (pixman_implementation_t *imp, pixman_op_t op,
1891                        comp4_t *dest, const comp4_t *src, const comp4_t *mask, int width)
1892 {
1893     fbCombineConjointGeneralC (dest, src, mask, width, CombineXor);
1894 }
1895
1896 void
1897 _pixman_setup_combiner_functions_width (pixman_implementation_t *imp)
1898 {
1899     /* Unified alpha */
1900     imp->combine_width[PIXMAN_OP_CLEAR] = fbCombineClear;
1901     imp->combine_width[PIXMAN_OP_SRC] = fbCombineSrcU;
1902     /* dest */
1903     imp->combine_width[PIXMAN_OP_OVER] = fbCombineOverU;
1904     imp->combine_width[PIXMAN_OP_OVER_REVERSE] = fbCombineOverReverseU;
1905     imp->combine_width[PIXMAN_OP_IN] = fbCombineInU;
1906     imp->combine_width[PIXMAN_OP_IN_REVERSE] = fbCombineInReverseU;
1907     imp->combine_width[PIXMAN_OP_OUT] = fbCombineOutU;
1908     imp->combine_width[PIXMAN_OP_OUT_REVERSE] = fbCombineOutReverseU;
1909     imp->combine_width[PIXMAN_OP_ATOP] = fbCombineAtopU;
1910     imp->combine_width[PIXMAN_OP_ATOP_REVERSE] = fbCombineAtopReverseU;
1911     imp->combine_width[PIXMAN_OP_XOR] = fbCombineXorU;
1912     imp->combine_width[PIXMAN_OP_ADD] = fbCombineAddU;
1913     imp->combine_width[PIXMAN_OP_SATURATE] = fbCombineSaturateU;
1914
1915     /* Disjoint, unified */
1916     imp->combine_width[PIXMAN_OP_DISJOINT_CLEAR] = fbCombineClear;
1917     imp->combine_width[PIXMAN_OP_DISJOINT_SRC] = fbCombineSrcU;
1918     /* dest */
1919     imp->combine_width[PIXMAN_OP_DISJOINT_OVER] = fbCombineDisjointOverU;
1920     imp->combine_width[PIXMAN_OP_DISJOINT_OVER_REVERSE] = fbCombineSaturateU;
1921     imp->combine_width[PIXMAN_OP_DISJOINT_IN] = fbCombineDisjointInU;
1922     imp->combine_width[PIXMAN_OP_DISJOINT_IN_REVERSE] = fbCombineDisjointInReverseU;
1923     imp->combine_width[PIXMAN_OP_DISJOINT_OUT] = fbCombineDisjointOutU;
1924     imp->combine_width[PIXMAN_OP_DISJOINT_OUT_REVERSE] = fbCombineDisjointOutReverseU;
1925     imp->combine_width[PIXMAN_OP_DISJOINT_ATOP] = fbCombineDisjointAtopU;
1926     imp->combine_width[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = fbCombineDisjointAtopReverseU;
1927     imp->combine_width[PIXMAN_OP_DISJOINT_XOR] = fbCombineDisjointXorU;
1928
1929     /* Conjoint, unified */
1930     imp->combine_width[PIXMAN_OP_CONJOINT_CLEAR] = fbCombineClear;
1931     imp->combine_width[PIXMAN_OP_CONJOINT_SRC] = fbCombineSrcU;
1932     /* dest */
1933     imp->combine_width[PIXMAN_OP_CONJOINT_OVER] = fbCombineConjointOverU;
1934     imp->combine_width[PIXMAN_OP_CONJOINT_OVER_REVERSE] = fbCombineConjointOverReverseU;
1935     imp->combine_width[PIXMAN_OP_CONJOINT_IN] = fbCombineConjointInU;
1936     imp->combine_width[PIXMAN_OP_CONJOINT_IN_REVERSE] = fbCombineConjointInReverseU;
1937     imp->combine_width[PIXMAN_OP_CONJOINT_OUT] = fbCombineConjointOutU;
1938     imp->combine_width[PIXMAN_OP_CONJOINT_OUT_REVERSE] = fbCombineConjointOutReverseU;
1939     imp->combine_width[PIXMAN_OP_CONJOINT_ATOP] = fbCombineConjointAtopU;
1940     imp->combine_width[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = fbCombineConjointAtopReverseU;
1941     imp->combine_width[PIXMAN_OP_CONJOINT_XOR] = fbCombineConjointXorU;
1942
1943     imp->combine_width[PIXMAN_OP_MULTIPLY] = fbCombineMultiplyU;
1944     imp->combine_width[PIXMAN_OP_SCREEN] = fbCombineScreenU;
1945     imp->combine_width[PIXMAN_OP_OVERLAY] = fbCombineOverlayU;
1946     imp->combine_width[PIXMAN_OP_DARKEN] = fbCombineDarkenU;
1947     imp->combine_width[PIXMAN_OP_LIGHTEN] = fbCombineLightenU;
1948     imp->combine_width[PIXMAN_OP_COLOR_DODGE] = fbCombineColorDodgeU;
1949     imp->combine_width[PIXMAN_OP_COLOR_BURN] = fbCombineColorBurnU;
1950     imp->combine_width[PIXMAN_OP_HARD_LIGHT] = fbCombineHardLightU;
1951     imp->combine_width[PIXMAN_OP_SOFT_LIGHT] = fbCombineSoftLightU;
1952     imp->combine_width[PIXMAN_OP_DIFFERENCE] = fbCombineDifferenceU;
1953     imp->combine_width[PIXMAN_OP_EXCLUSION] = fbCombineExclusionU;
1954     imp->combine_width[PIXMAN_OP_HSL_HUE] = fbCombineHSLHueU;
1955     imp->combine_width[PIXMAN_OP_HSL_SATURATION] = fbCombineHSLSaturationU;
1956     imp->combine_width[PIXMAN_OP_HSL_COLOR] = fbCombineHSLColorU;
1957     imp->combine_width[PIXMAN_OP_HSL_LUMINOSITY] = fbCombineHSLLuminosityU;
1958
1959     /* Component alpha combiners */
1960     imp->combine_width_ca[PIXMAN_OP_CLEAR] = fbCombineClearC;
1961     imp->combine_width_ca[PIXMAN_OP_SRC] = fbCombineSrcC;
1962     /* dest */
1963     imp->combine_width_ca[PIXMAN_OP_OVER] = fbCombineOverC;
1964     imp->combine_width_ca[PIXMAN_OP_OVER_REVERSE] = fbCombineOverReverseC;
1965     imp->combine_width_ca[PIXMAN_OP_IN] = fbCombineInC;
1966     imp->combine_width_ca[PIXMAN_OP_IN_REVERSE] = fbCombineInReverseC;
1967     imp->combine_width_ca[PIXMAN_OP_OUT] = fbCombineOutC;
1968     imp->combine_width_ca[PIXMAN_OP_OUT_REVERSE] = fbCombineOutReverseC;
1969     imp->combine_width_ca[PIXMAN_OP_ATOP] = fbCombineAtopC;
1970     imp->combine_width_ca[PIXMAN_OP_ATOP_REVERSE] = fbCombineAtopReverseC;
1971     imp->combine_width_ca[PIXMAN_OP_XOR] = fbCombineXorC;
1972     imp->combine_width_ca[PIXMAN_OP_ADD] = fbCombineAddC;
1973     imp->combine_width_ca[PIXMAN_OP_SATURATE] = fbCombineSaturateC;
1974
1975     /* Disjoint CA */
1976     imp->combine_width_ca[PIXMAN_OP_DISJOINT_CLEAR] = fbCombineClearC;
1977     imp->combine_width_ca[PIXMAN_OP_DISJOINT_SRC] = fbCombineSrcC;
1978     /* dest */
1979     imp->combine_width_ca[PIXMAN_OP_DISJOINT_OVER] = fbCombineDisjointOverC;
1980     imp->combine_width_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = fbCombineSaturateC,
1981     imp->combine_width_ca[PIXMAN_OP_DISJOINT_IN] = fbCombineDisjointInC;
1982     imp->combine_width_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = fbCombineDisjointInReverseC;
1983     imp->combine_width_ca[PIXMAN_OP_DISJOINT_OUT] = fbCombineDisjointOutC;
1984     imp->combine_width_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = fbCombineDisjointOutReverseC;
1985     imp->combine_width_ca[PIXMAN_OP_DISJOINT_ATOP] = fbCombineDisjointAtopC;
1986     imp->combine_width_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = fbCombineDisjointAtopReverseC;
1987     imp->combine_width_ca[PIXMAN_OP_DISJOINT_XOR] = fbCombineDisjointXorC;
1988
1989     /* Conjoint CA */
1990     imp->combine_width_ca[PIXMAN_OP_CONJOINT_CLEAR] = fbCombineClearC;
1991     imp->combine_width_ca[PIXMAN_OP_CONJOINT_SRC] = fbCombineSrcC;
1992     /* dest */
1993     imp->combine_width_ca[PIXMAN_OP_CONJOINT_OVER] = fbCombineConjointOverC;
1994     imp->combine_width_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = fbCombineConjointOverReverseC;
1995     imp->combine_width_ca[PIXMAN_OP_CONJOINT_IN] = fbCombineConjointInC;
1996     imp->combine_width_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = fbCombineConjointInReverseC;
1997     imp->combine_width_ca[PIXMAN_OP_CONJOINT_OUT] = fbCombineConjointOutC;
1998     imp->combine_width_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = fbCombineConjointOutReverseC;
1999     imp->combine_width_ca[PIXMAN_OP_CONJOINT_ATOP] = fbCombineConjointAtopC;
2000     imp->combine_width_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = fbCombineConjointAtopReverseC;
2001     imp->combine_width_ca[PIXMAN_OP_CONJOINT_XOR] = fbCombineConjointXorC;
2002
2003     imp->combine_width_ca[PIXMAN_OP_MULTIPLY] = fbCombineMultiplyC;
2004     imp->combine_width_ca[PIXMAN_OP_SCREEN] = fbCombineScreenC;
2005     imp->combine_width_ca[PIXMAN_OP_OVERLAY] = fbCombineOverlayC;
2006     imp->combine_width_ca[PIXMAN_OP_DARKEN] = fbCombineDarkenC;
2007     imp->combine_width_ca[PIXMAN_OP_LIGHTEN] = fbCombineLightenC;
2008     imp->combine_width_ca[PIXMAN_OP_COLOR_DODGE] = fbCombineColorDodgeC;
2009     imp->combine_width_ca[PIXMAN_OP_COLOR_BURN] = fbCombineColorBurnC;
2010     imp->combine_width_ca[PIXMAN_OP_HARD_LIGHT] = fbCombineHardLightC;
2011     imp->combine_width_ca[PIXMAN_OP_SOFT_LIGHT] = fbCombineSoftLightC;
2012     imp->combine_width_ca[PIXMAN_OP_DIFFERENCE] = fbCombineDifferenceC;
2013     imp->combine_width_ca[PIXMAN_OP_EXCLUSION] = fbCombineExclusionC;
2014     /* It is not clear that these make sense, so leave them out for now */
2015     imp->combine_width_ca[PIXMAN_OP_HSL_HUE] = NULL;
2016     imp->combine_width_ca[PIXMAN_OP_HSL_SATURATION] = NULL;
2017     imp->combine_width_ca[PIXMAN_OP_HSL_COLOR] = NULL;
2018     imp->combine_width_ca[PIXMAN_OP_HSL_LUMINOSITY] = NULL;
2019 }
2020
2021