1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
2 /*
3  * Copyright © 2010, 2012 Soren Sandmann Pedersen
4  * Copyright © 2010, 2012 Red Hat, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Author: Soren Sandmann Pedersen (sandmann@cs.au.dk)
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <math.h>
33 #include <string.h>
34 #include <float.h>
35 
36 #include "pixman-private.h"
37 
38 /* Workaround for http://gcc.gnu.org/PR54965 */
39 /* GCC 4.6 has problems with force_inline, so just use normal inline instead */
40 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 6)
41 #undef force_inline
42 #define force_inline __inline__
43 #endif
44 
45 typedef float (* combine_channel_t) (float sa, float s, float da, float d);
46 
47 static force_inline void
combine_inner(pixman_bool_t component,float * dest,const float * src,const float * mask,int n_pixels,combine_channel_t combine_a,combine_channel_t combine_c)48 combine_inner (pixman_bool_t component,
49 	       float *dest, const float *src, const float *mask, int n_pixels,
50 	       combine_channel_t combine_a, combine_channel_t combine_c)
51 {
52     int i;
53 
54     if (!mask)
55     {
56 	for (i = 0; i < 4 * n_pixels; i += 4)
57 	{
58 	    float sa = src[i + 0];
59 	    float sr = src[i + 1];
60 	    float sg = src[i + 2];
61 	    float sb = src[i + 3];
62 
63 	    float da = dest[i + 0];
64 	    float dr = dest[i + 1];
65 	    float dg = dest[i + 2];
66 	    float db = dest[i + 3];
67 
68 	    dest[i + 0] = combine_a (sa, sa, da, da);
69 	    dest[i + 1] = combine_c (sa, sr, da, dr);
70 	    dest[i + 2] = combine_c (sa, sg, da, dg);
71 	    dest[i + 3] = combine_c (sa, sb, da, db);
72 	}
73     }
74     else
75     {
76 	for (i = 0; i < 4 * n_pixels; i += 4)
77 	{
78 	    float sa, sr, sg, sb;
79 	    float ma, mr, mg, mb;
80 	    float da, dr, dg, db;
81 
82 	    sa = src[i + 0];
83 	    sr = src[i + 1];
84 	    sg = src[i + 2];
85 	    sb = src[i + 3];
86 
87 	    if (component)
88 	    {
89 		ma = mask[i + 0];
90 		mr = mask[i + 1];
91 		mg = mask[i + 2];
92 		mb = mask[i + 3];
93 
94 		sr *= mr;
95 		sg *= mg;
96 		sb *= mb;
97 
98 		ma *= sa;
99 		mr *= sa;
100 		mg *= sa;
101 		mb *= sa;
102 
103 		sa = ma;
104 	    }
105 	    else
106 	    {
107 		ma = mask[i + 0];
108 
109 		sa *= ma;
110 		sr *= ma;
111 		sg *= ma;
112 		sb *= ma;
113 
114 		ma = mr = mg = mb = sa;
115 	    }
116 
117 	    da = dest[i + 0];
118 	    dr = dest[i + 1];
119 	    dg = dest[i + 2];
120 	    db = dest[i + 3];
121 
122 	    dest[i + 0] = combine_a (ma, sa, da, da);
123 	    dest[i + 1] = combine_c (mr, sr, da, dr);
124 	    dest[i + 2] = combine_c (mg, sg, da, dg);
125 	    dest[i + 3] = combine_c (mb, sb, da, db);
126 	}
127     }
128 }
129 
130 #define MAKE_COMBINER(name, component, combine_a, combine_c)		\
131     static void								\
132     combine_ ## name ## _float (pixman_implementation_t *imp,		\
133 				pixman_op_t              op,		\
134 				float                   *dest,		\
135 				const float             *src,		\
136 				const float             *mask,		\
137 				int		         n_pixels)	\
138     {									\
139 	combine_inner (component, dest, src, mask, n_pixels,		\
140 		       combine_a, combine_c);				\
141     }
142 
143 #define MAKE_COMBINERS(name, combine_a, combine_c)			\
144     MAKE_COMBINER(name ## _ca, TRUE, combine_a, combine_c)		\
145     MAKE_COMBINER(name ## _u, FALSE, combine_a, combine_c)
146 
147 
148 /*
149  * Porter/Duff operators
150  */
151 typedef enum
152 {
153     ZERO,
154     ONE,
155     SRC_ALPHA,
156     DEST_ALPHA,
157     INV_SA,
158     INV_DA,
159     SA_OVER_DA,
160     DA_OVER_SA,
161     INV_SA_OVER_DA,
162     INV_DA_OVER_SA,
163     ONE_MINUS_SA_OVER_DA,
164     ONE_MINUS_DA_OVER_SA,
165     ONE_MINUS_INV_DA_OVER_SA,
166     ONE_MINUS_INV_SA_OVER_DA
167 } combine_factor_t;
168 
169 #define CLAMP(f)					\
170     (((f) < 0)? 0 : (((f) > 1.0) ? 1.0 : (f)))
171 
172 static force_inline float
get_factor(combine_factor_t factor,float sa,float da)173 get_factor (combine_factor_t factor, float sa, float da)
174 {
175     float f = -1;
176 
177     switch (factor)
178     {
179     case ZERO:
180 	f = 0.0f;
181 	break;
182 
183     case ONE:
184 	f = 1.0f;
185 	break;
186 
187     case SRC_ALPHA:
188 	f = sa;
189 	break;
190 
191     case DEST_ALPHA:
192 	f = da;
193 	break;
194 
195     case INV_SA:
196 	f = 1 - sa;
197 	break;
198 
199     case INV_DA:
200 	f = 1 - da;
201 	break;
202 
203     case SA_OVER_DA:
204 	if (FLOAT_IS_ZERO (da))
205 	    f = 1.0f;
206 	else
207 	    f = CLAMP (sa / da);
208 	break;
209 
210     case DA_OVER_SA:
211 	if (FLOAT_IS_ZERO (sa))
212 	    f = 1.0f;
213 	else
214 	    f = CLAMP (da / sa);
215 	break;
216 
217     case INV_SA_OVER_DA:
218 	if (FLOAT_IS_ZERO (da))
219 	    f = 1.0f;
220 	else
221 	    f = CLAMP ((1.0f - sa) / da);
222 	break;
223 
224     case INV_DA_OVER_SA:
225 	if (FLOAT_IS_ZERO (sa))
226 	    f = 1.0f;
227 	else
228 	    f = CLAMP ((1.0f - da) / sa);
229 	break;
230 
231     case ONE_MINUS_SA_OVER_DA:
232 	if (FLOAT_IS_ZERO (da))
233 	    f = 0.0f;
234 	else
235 	    f = CLAMP (1.0f - sa / da);
236 	break;
237 
238     case ONE_MINUS_DA_OVER_SA:
239 	if (FLOAT_IS_ZERO (sa))
240 	    f = 0.0f;
241 	else
242 	    f = CLAMP (1.0f - da / sa);
243 	break;
244 
245     case ONE_MINUS_INV_DA_OVER_SA:
246 	if (FLOAT_IS_ZERO (sa))
247 	    f = 0.0f;
248 	else
249 	    f = CLAMP (1.0f - (1.0f - da) / sa);
250 	break;
251 
252     case ONE_MINUS_INV_SA_OVER_DA:
253 	if (FLOAT_IS_ZERO (da))
254 	    f = 0.0f;
255 	else
256 	    f = CLAMP (1.0f - (1.0f - sa) / da);
257 	break;
258     }
259 
260     return f;
261 }
262 
263 #define MAKE_PD_COMBINERS(name, a, b)					\
264     static float force_inline						\
265     pd_combine_ ## name (float sa, float s, float da, float d)		\
266     {									\
267 	const float fa = get_factor (a, sa, da);			\
268 	const float fb = get_factor (b, sa, da);			\
269 									\
270 	return MIN (1.0f, s * fa + d * fb);				\
271     }									\
272     									\
273     MAKE_COMBINERS(name, pd_combine_ ## name, pd_combine_ ## name)
274 
MAKE_PD_COMBINERS(clear,ZERO,ZERO)275 MAKE_PD_COMBINERS (clear,			ZERO,				ZERO)
276 MAKE_PD_COMBINERS (src,				ONE,				ZERO)
277 MAKE_PD_COMBINERS (dst,				ZERO,				ONE)
278 MAKE_PD_COMBINERS (over,			ONE,				INV_SA)
279 MAKE_PD_COMBINERS (over_reverse,		INV_DA,				ONE)
280 MAKE_PD_COMBINERS (in,				DEST_ALPHA,			ZERO)
281 MAKE_PD_COMBINERS (in_reverse,			ZERO,				SRC_ALPHA)
282 MAKE_PD_COMBINERS (out,				INV_DA,				ZERO)
283 MAKE_PD_COMBINERS (out_reverse,			ZERO,				INV_SA)
284 MAKE_PD_COMBINERS (atop,			DEST_ALPHA,			INV_SA)
285 MAKE_PD_COMBINERS (atop_reverse,		INV_DA,				SRC_ALPHA)
286 MAKE_PD_COMBINERS (xor,				INV_DA,				INV_SA)
287 MAKE_PD_COMBINERS (add,				ONE,				ONE)
288 
289 MAKE_PD_COMBINERS (saturate,			INV_DA_OVER_SA,			ONE)
290 
291 MAKE_PD_COMBINERS (disjoint_clear,		ZERO,				ZERO)
292 MAKE_PD_COMBINERS (disjoint_src,		ONE,				ZERO)
293 MAKE_PD_COMBINERS (disjoint_dst,		ZERO,				ONE)
294 MAKE_PD_COMBINERS (disjoint_over,		ONE,				INV_SA_OVER_DA)
295 MAKE_PD_COMBINERS (disjoint_over_reverse,	INV_DA_OVER_SA,			ONE)
296 MAKE_PD_COMBINERS (disjoint_in,			ONE_MINUS_INV_DA_OVER_SA,	ZERO)
297 MAKE_PD_COMBINERS (disjoint_in_reverse,		ZERO,				ONE_MINUS_INV_SA_OVER_DA)
298 MAKE_PD_COMBINERS (disjoint_out,		INV_DA_OVER_SA,			ZERO)
299 MAKE_PD_COMBINERS (disjoint_out_reverse,	ZERO,				INV_SA_OVER_DA)
300 MAKE_PD_COMBINERS (disjoint_atop,		ONE_MINUS_INV_DA_OVER_SA,	INV_SA_OVER_DA)
301 MAKE_PD_COMBINERS (disjoint_atop_reverse,	INV_DA_OVER_SA,			ONE_MINUS_INV_SA_OVER_DA)
302 MAKE_PD_COMBINERS (disjoint_xor,		INV_DA_OVER_SA,			INV_SA_OVER_DA)
303 
304 MAKE_PD_COMBINERS (conjoint_clear,		ZERO,				ZERO)
305 MAKE_PD_COMBINERS (conjoint_src,		ONE,				ZERO)
306 MAKE_PD_COMBINERS (conjoint_dst,		ZERO,				ONE)
307 MAKE_PD_COMBINERS (conjoint_over,		ONE,				ONE_MINUS_SA_OVER_DA)
308 MAKE_PD_COMBINERS (conjoint_over_reverse,	ONE_MINUS_DA_OVER_SA,		ONE)
309 MAKE_PD_COMBINERS (conjoint_in,			DA_OVER_SA,			ZERO)
310 MAKE_PD_COMBINERS (conjoint_in_reverse,		ZERO,				SA_OVER_DA)
311 MAKE_PD_COMBINERS (conjoint_out,		ONE_MINUS_DA_OVER_SA,		ZERO)
312 MAKE_PD_COMBINERS (conjoint_out_reverse,	ZERO,				ONE_MINUS_SA_OVER_DA)
313 MAKE_PD_COMBINERS (conjoint_atop,		DA_OVER_SA,			ONE_MINUS_SA_OVER_DA)
314 MAKE_PD_COMBINERS (conjoint_atop_reverse,	ONE_MINUS_DA_OVER_SA,		SA_OVER_DA)
315 MAKE_PD_COMBINERS (conjoint_xor,		ONE_MINUS_DA_OVER_SA,		ONE_MINUS_SA_OVER_DA)
316 
317 /*
318  * PDF blend modes:
319  *
320  * The following blend modes have been taken from the PDF ISO 32000
321  * specification, which at this point in time is available from
322  *
323  *     http://www.adobe.com/devnet/pdf/pdf_reference.html
324  *
325  * The specific documents of interest are the PDF spec itself:
326  *
327  *     http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf
328  *
329  * chapters 11.3.5 and 11.3.6 and a later supplement for Adobe Acrobat
330  * 9.1 and Reader 9.1:
331  *
332  *     http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000_1.pdf
333  *
334  * that clarifies the specifications for blend modes ColorDodge and
335  * ColorBurn.
336  *
337  * The formula for computing the final pixel color given in 11.3.6 is:
338  *
339  *     αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs)
340  *
341  * with B() is the blend function. When B(Cb, Cs) = Cs, this formula
342  * reduces to the regular OVER operator.
343  *
344  * Cs and Cb are not premultiplied, so in our implementation we instead
345  * use:
346  *
347  *     cr = (1 – αs) × cb  +  (1 – αb) × cs  +  αb × αs × B (cb/αb, cs/αs)
348  *
349  * where cr, cs, and cb are premultiplied colors, and where the
350  *
351  *     αb × αs × B(cb/αb, cs/αs)
352  *
353  * part is first arithmetically simplified under the assumption that αb
354  * and αs are not 0, and then updated to produce a meaningful result when
355  * they are.
356  *
357  * For all the blend mode operators, the alpha channel is given by
358  *
359  *     αr = αs + αb + αb × αs
360  */
361 
362 #define MAKE_SEPARABLE_PDF_COMBINERS(name)				\
363     static force_inline float						\
364     combine_ ## name ## _a (float sa, float s, float da, float d)	\
365     {									\
366 	return da + sa - da * sa;					\
367     }									\
368     									\
369     static force_inline float						\
370     combine_ ## name ## _c (float sa, float s, float da, float d)	\
371     {									\
372 	float f = (1 - sa) * d + (1 - da) * s;				\
373 									\
374 	return f + blend_ ## name (sa, s, da, d);			\
375     }									\
376     									\
377     MAKE_COMBINERS (name, combine_ ## name ## _a, combine_ ## name ## _c)
378 
379 /*
380  * Multiply
381  *
382  *      ad * as * B(d / ad, s / as)
383  *    = ad * as * d/ad * s/as
384  *    = d * s
385  *
386  */
387 static force_inline float
388 blend_multiply (float sa, float s, float da, float d)
389 {
390     return d * s;
391 }
392 
393 /*
394  * Screen
395  *
396  *      ad * as * B(d/ad, s/as)
397  *    = ad * as * (d/ad + s/as - s/as * d/ad)
398  *    = ad * s + as * d - s * d
399  */
400 static force_inline float
blend_screen(float sa,float s,float da,float d)401 blend_screen (float sa, float s, float da, float d)
402 {
403     return d * sa + s * da - s * d;
404 }
405 
406 /*
407  * Overlay
408  *
409  *     ad * as * B(d/ad, s/as)
410  *   = ad * as * Hardlight (s, d)
411  *   = if (d / ad < 0.5)
412  *         as * ad * Multiply (s/as, 2 * d/ad)
413  *     else
414  *         as * ad * Screen (s/as, 2 * d / ad - 1)
415  *   = if (d < 0.5 * ad)
416  *         as * ad * s/as * 2 * d /ad
417  *     else
418  *         as * ad * (s/as + 2 * d / ad - 1 - s / as * (2 * d / ad - 1))
419  *   = if (2 * d < ad)
420  *         2 * s * d
421  *     else
422  *         ad * s + 2 * as * d - as * ad - ad * s * (2 * d / ad - 1)
423  *   = if (2 * d < ad)
424  *         2 * s * d
425  *     else
426  *         as * ad - 2 * (ad - d) * (as - s)
427  */
428 static force_inline float
blend_overlay(float sa,float s,float da,float d)429 blend_overlay (float sa, float s, float da, float d)
430 {
431     if (2 * d < da)
432 	return 2 * s * d;
433     else
434 	return sa * da - 2 * (da - d) * (sa - s);
435 }
436 
437 /*
438  * Darken
439  *
440  *     ad * as * B(d/ad, s/as)
441  *   = ad * as * MIN(d/ad, s/as)
442  *   = MIN (as * d, ad * s)
443  */
444 static force_inline float
blend_darken(float sa,float s,float da,float d)445 blend_darken (float sa, float s, float da, float d)
446 {
447     s = s * da;
448     d = d * sa;
449 
450     if (s > d)
451 	return d;
452     else
453 	return s;
454 }
455 
456 /*
457  * Lighten
458  *
459  *     ad * as * B(d/ad, s/as)
460  *   = ad * as * MAX(d/ad, s/as)
461  *   = MAX (as * d, ad * s)
462  */
463 static force_inline float
blend_lighten(float sa,float s,float da,float d)464 blend_lighten (float sa, float s, float da, float d)
465 {
466     s = s * da;
467     d = d * sa;
468 
469     if (s > d)
470 	return s;
471     else
472 	return d;
473 }
474 
475 /*
476  * Color dodge
477  *
478  *     ad * as * B(d/ad, s/as)
479  *   = if d/ad = 0
480  *         ad * as * 0
481  *     else if (d/ad >= (1 - s/as)
482  *         ad * as * 1
483  *     else
484  *         ad * as * ((d/ad) / (1 - s/as))
485  *   = if d = 0
486  *         0
487  *     elif as * d >= ad * (as - s)
488  *         ad * as
489  *     else
490  *         as * (as * d / (as - s))
491  *
492  */
493 static force_inline float
blend_color_dodge(float sa,float s,float da,float d)494 blend_color_dodge (float sa, float s, float da, float d)
495 {
496     if (FLOAT_IS_ZERO (d))
497 	return 0.0f;
498     else if (d * sa >= sa * da - s * da)
499 	return sa * da;
500     else if (FLOAT_IS_ZERO (sa - s))
501 	return sa * da;
502     else
503 	return sa * sa * d / (sa - s);
504 }
505 
506 /*
507  * Color burn
508  *
509  * We modify the first clause "if d = 1" to "if d >= 1" since with
510  * premultiplied colors d > 1 can actually happen.
511  *
512  *     ad * as * B(d/ad, s/as)
513  *   = if d/ad >= 1
514  *         ad * as * 1
515  *     elif (1 - d/ad) >= s/as
516  *         ad * as * 0
517  *     else
518  *         ad * as * (1 - ((1 - d/ad) / (s/as)))
519  *   = if d >= ad
520  *         ad * as
521  *     elif as * ad - as * d >= ad * s
522  *         0
523  *     else
524  *         ad * as  - as * as * (ad - d) / s
525  */
526 static force_inline float
blend_color_burn(float sa,float s,float da,float d)527 blend_color_burn (float sa, float s, float da, float d)
528 {
529     if (d >= da)
530 	return sa * da;
531     else if (sa * (da - d) >= s * da)
532 	return 0.0f;
533     else if (FLOAT_IS_ZERO (s))
534 	return 0.0f;
535     else
536 	return sa * (da - sa * (da - d) / s);
537 }
538 
539 /*
540  * Hard light
541  *
542  *     ad * as * B(d/ad, s/as)
543  *   = if (s/as <= 0.5)
544  *         ad * as * Multiply (d/ad, 2 * s/as)
545  *     else
546  *         ad * as * Screen (d/ad, 2 * s/as - 1)
547  *   = if 2 * s <= as
548  *         ad * as * d/ad * 2 * s / as
549  *     else
550  *         ad * as * (d/ad + (2 * s/as - 1) + d/ad * (2 * s/as - 1))
551  *   = if 2 * s <= as
552  *         2 * s * d
553  *     else
554  *         as * ad - 2 * (ad - d) * (as - s)
555  */
556 static force_inline float
blend_hard_light(float sa,float s,float da,float d)557 blend_hard_light (float sa, float s, float da, float d)
558 {
559     if (2 * s < sa)
560 	return 2 * s * d;
561     else
562 	return sa * da - 2 * (da - d) * (sa - s);
563 }
564 
565 /*
566  * Soft light
567  *
568  *     ad * as * B(d/ad, s/as)
569  *   = if (s/as <= 0.5)
570  *         ad * as * (d/ad - (1 - 2 * s/as) * d/ad * (1 - d/ad))
571  *     else if (d/ad <= 0.25)
572  *         ad * as * (d/ad + (2 * s/as - 1) * ((((16 * d/ad - 12) * d/ad + 4) * d/ad) - d/ad))
573  *     else
574  *         ad * as * (d/ad + (2 * s/as - 1) * sqrt (d/ad))
575  *   = if (2 * s <= as)
576  *         d * as - d * (ad - d) * (as - 2 * s) / ad;
577  *     else if (4 * d <= ad)
578  *         (2 * s - as) * d * ((16 * d / ad - 12) * d / ad + 3);
579  *     else
580  *         d * as + (sqrt (d * ad) - d) * (2 * s - as);
581  */
582 static force_inline float
blend_soft_light(float sa,float s,float da,float d)583 blend_soft_light (float sa, float s, float da, float d)
584 {
585     if (2 * s <= sa)
586     {
587 	if (FLOAT_IS_ZERO (da))
588 	    return d * sa;
589 	else
590 	    return d * sa - d * (da - d) * (sa - 2 * s) / da;
591     }
592     else
593     {
594 	if (FLOAT_IS_ZERO (da))
595 	{
596 	    return d * sa;
597 	}
598 	else
599 	{
600 	    if (4 * d <= da)
601 		return d * sa + (2 * s - sa) * d * ((16 * d / da - 12) * d / da + 3);
602 	    else
603 		return d * sa + (sqrtf (d * da) - d) * (2 * s - sa);
604 	}
605     }
606 }
607 
608 /*
609  * Difference
610  *
611  *     ad * as * B(s/as, d/ad)
612  *   = ad * as * abs (s/as - d/ad)
613  *   = if (s/as <= d/ad)
614  *         ad * as * (d/ad - s/as)
615  *     else
616  *         ad * as * (s/as - d/ad)
617  *   = if (ad * s <= as * d)
618  *        as * d - ad * s
619  *     else
620  *        ad * s - as * d
621  */
622 static force_inline float
blend_difference(float sa,float s,float da,float d)623 blend_difference (float sa, float s, float da, float d)
624 {
625     float dsa = d * sa;
626     float sda = s * da;
627 
628     if (sda < dsa)
629 	return dsa - sda;
630     else
631 	return sda - dsa;
632 }
633 
634 /*
635  * Exclusion
636  *
637  *     ad * as * B(s/as, d/ad)
638  *   = ad * as * (d/ad + s/as - 2 * d/ad * s/as)
639  *   = as * d + ad * s - 2 * s * d
640  */
641 static force_inline float
blend_exclusion(float sa,float s,float da,float d)642 blend_exclusion (float sa, float s, float da, float d)
643 {
644     return s * da + d * sa - 2 * d * s;
645 }
646 
647 MAKE_SEPARABLE_PDF_COMBINERS (multiply)
648 MAKE_SEPARABLE_PDF_COMBINERS (screen)
649 MAKE_SEPARABLE_PDF_COMBINERS (overlay)
650 MAKE_SEPARABLE_PDF_COMBINERS (darken)
651 MAKE_SEPARABLE_PDF_COMBINERS (lighten)
652 MAKE_SEPARABLE_PDF_COMBINERS (color_dodge)
653 MAKE_SEPARABLE_PDF_COMBINERS (color_burn)
654 MAKE_SEPARABLE_PDF_COMBINERS (hard_light)
655 MAKE_SEPARABLE_PDF_COMBINERS (soft_light)
656 MAKE_SEPARABLE_PDF_COMBINERS (difference)
657 MAKE_SEPARABLE_PDF_COMBINERS (exclusion)
658 
659 /*
660  * PDF nonseperable blend modes are implemented using the following functions
661  * to operate in Hsl space, with Cmax, Cmid, Cmin referring to the max, mid
662  * and min value of the red, green and blue components.
663  *
664  * LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue
665  *
666  * clip_color (C):
667  *     l = LUM (C)
668  *     min = Cmin
669  *     max = Cmax
670  *     if n < 0.0
671  *         C = l + (((C – l) × l) ⁄ (l – min))
672  *     if x > 1.0
673  *         C = l + (((C – l) × (1 – l) ) ⁄ (max – l))
674  *     return C
675  *
676  * set_lum (C, l):
677  *     d = l – LUM (C)
678  *     C += d
679  *     return clip_color (C)
680  *
681  * SAT (C) = CH_MAX (C) - CH_MIN (C)
682  *
683  * set_sat (C, s):
684  *     if Cmax > Cmin
685  *         Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) )
686  *         Cmax = s
687  *     else
688  *         Cmid = Cmax = 0.0
689  *         Cmin = 0.0
690  *     return C
691  */
692 
693 /* For premultiplied colors, we need to know what happens when C is
694  * multiplied by a real number. LUM and SAT are linear:
695  *
696  *     LUM (r × C) = r × LUM (C)	SAT (r * C) = r * SAT (C)
697  *
698  * If we extend clip_color with an extra argument a and change
699  *
700  *     if x >= 1.0
701  *
702  * into
703  *
704  *     if x >= a
705  *
706  * then clip_color is also linear:
707  *
708  *     r * clip_color (C, a) = clip_color (r * C, r * a);
709  *
710  * for positive r.
711  *
712  * Similarly, we can extend set_lum with an extra argument that is just passed
713  * on to clip_color:
714  *
715  *       r * set_lum (C, l, a)
716  *
717  *     = r × clip_color (C + l - LUM (C), a)
718  *
719  *     = clip_color (r * C + r × l - r * LUM (C), r * a)
720  *
721  *     = set_lum (r * C, r * l, r * a)
722  *
723  * Finally, set_sat:
724  *
725  *       r * set_sat (C, s) = set_sat (x * C, r * s)
726  *
727  * The above holds for all non-zero x, because the x'es in the fraction for
728  * C_mid cancel out. Specifically, it holds for x = r:
729  *
730  *       r * set_sat (C, s) = set_sat (r * C, r * s)
731  *
732  */
733 typedef struct
734 {
735     float	r;
736     float	g;
737     float	b;
738 } rgb_t;
739 
740 static force_inline float
minf(float a,float b)741 minf (float a, float b)
742 {
743     return a < b? a : b;
744 }
745 
746 static force_inline float
maxf(float a,float b)747 maxf (float a, float b)
748 {
749     return a > b? a : b;
750 }
751 
752 static force_inline float
channel_min(const rgb_t * c)753 channel_min (const rgb_t *c)
754 {
755     return minf (minf (c->r, c->g), c->b);
756 }
757 
758 static force_inline float
channel_max(const rgb_t * c)759 channel_max (const rgb_t *c)
760 {
761     return maxf (maxf (c->r, c->g), c->b);
762 }
763 
764 static force_inline float
get_lum(const rgb_t * c)765 get_lum (const rgb_t *c)
766 {
767     return c->r * 0.3f + c->g * 0.59f + c->b * 0.11f;
768 }
769 
770 static force_inline float
get_sat(const rgb_t * c)771 get_sat (const rgb_t *c)
772 {
773     return channel_max (c) - channel_min (c);
774 }
775 
776 static void
clip_color(rgb_t * color,float a)777 clip_color (rgb_t *color, float a)
778 {
779     float l = get_lum (color);
780     float n = channel_min (color);
781     float x = channel_max (color);
782     float t;
783 
784     if (n < 0.0f)
785     {
786 	t = l - n;
787 	if (FLOAT_IS_ZERO (t))
788 	{
789 	    color->r = 0.0f;
790 	    color->g = 0.0f;
791 	    color->b = 0.0f;
792 	}
793 	else
794 	{
795 	    color->r = l + (((color->r - l) * l) / t);
796 	    color->g = l + (((color->g - l) * l) / t);
797 	    color->b = l + (((color->b - l) * l) / t);
798 	}
799     }
800     if (x > a)
801     {
802 	t = x - l;
803 	if (FLOAT_IS_ZERO (t))
804 	{
805 	    color->r = a;
806 	    color->g = a;
807 	    color->b = a;
808 	}
809 	else
810 	{
811 	    color->r = l + (((color->r - l) * (a - l) / t));
812 	    color->g = l + (((color->g - l) * (a - l) / t));
813 	    color->b = l + (((color->b - l) * (a - l) / t));
814 	}
815     }
816 }
817 
818 static void
set_lum(rgb_t * color,float sa,float l)819 set_lum (rgb_t *color, float sa, float l)
820 {
821     float d = l - get_lum (color);
822 
823     color->r = color->r + d;
824     color->g = color->g + d;
825     color->b = color->b + d;
826 
827     clip_color (color, sa);
828 }
829 
830 static void
set_sat(rgb_t * src,float sat)831 set_sat (rgb_t *src, float sat)
832 {
833     float *max, *mid, *min;
834     float t;
835 
836     if (src->r > src->g)
837     {
838 	if (src->r > src->b)
839 	{
840 	    max = &(src->r);
841 
842 	    if (src->g > src->b)
843 	    {
844 		mid = &(src->g);
845 		min = &(src->b);
846 	    }
847 	    else
848 	    {
849 		mid = &(src->b);
850 		min = &(src->g);
851 	    }
852 	}
853 	else
854 	{
855 	    max = &(src->b);
856 	    mid = &(src->r);
857 	    min = &(src->g);
858 	}
859     }
860     else
861     {
862 	if (src->r > src->b)
863 	{
864 	    max = &(src->g);
865 	    mid = &(src->r);
866 	    min = &(src->b);
867 	}
868 	else
869 	{
870 	    min = &(src->r);
871 
872 	    if (src->g > src->b)
873 	    {
874 		max = &(src->g);
875 		mid = &(src->b);
876 	    }
877 	    else
878 	    {
879 		max = &(src->b);
880 		mid = &(src->g);
881 	    }
882 	}
883     }
884 
885     t = *max - *min;
886 
887     if (FLOAT_IS_ZERO (t))
888     {
889 	*mid = *max = 0.0f;
890     }
891     else
892     {
893 	*mid = ((*mid - *min) * sat) / t;
894 	*max = sat;
895     }
896 
897     *min = 0.0f;
898 }
899 
900 /* Hue:
901  *
902  *       as * ad * B(s/as, d/as)
903  *     = as * ad * set_lum (set_sat (s/as, SAT (d/ad)), LUM (d/ad), 1)
904  *     = set_lum (set_sat (ad * s, as * SAT (d)), as * LUM (d), as * ad)
905  *
906  */
907 static force_inline void
blend_hsl_hue(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)908 blend_hsl_hue (rgb_t *res,
909 	       const rgb_t *dest, float da,
910 	       const rgb_t *src, float sa)
911 {
912     res->r = src->r * da;
913     res->g = src->g * da;
914     res->b = src->b * da;
915 
916     set_sat (res, get_sat (dest) * sa);
917     set_lum (res, sa * da, get_lum (dest) * sa);
918 }
919 
920 /*
921  * Saturation
922  *
923  *     as * ad * B(s/as, d/ad)
924  *   = as * ad * set_lum (set_sat (d/ad, SAT (s/as)), LUM (d/ad), 1)
925  *   = set_lum (as * ad * set_sat (d/ad, SAT (s/as)),
926  *                                       as * LUM (d), as * ad)
927  *   = set_lum (set_sat (as * d, ad * SAT (s), as * LUM (d), as * ad))
928  */
929 static force_inline void
blend_hsl_saturation(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)930 blend_hsl_saturation (rgb_t *res,
931 		      const rgb_t *dest, float da,
932 		      const rgb_t *src, float sa)
933 {
934     res->r = dest->r * sa;
935     res->g = dest->g * sa;
936     res->b = dest->b * sa;
937 
938     set_sat (res, get_sat (src) * da);
939     set_lum (res, sa * da, get_lum (dest) * sa);
940 }
941 
942 /*
943  * Color
944  *
945  *     as * ad * B(s/as, d/as)
946  *   = as * ad * set_lum (s/as, LUM (d/ad), 1)
947  *   = set_lum (s * ad, as * LUM (d), as * ad)
948  */
949 static force_inline void
blend_hsl_color(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)950 blend_hsl_color (rgb_t *res,
951 		 const rgb_t *dest, float da,
952 		 const rgb_t *src, float sa)
953 {
954     res->r = src->r * da;
955     res->g = src->g * da;
956     res->b = src->b * da;
957 
958     set_lum (res, sa * da, get_lum (dest) * sa);
959 }
960 
961 /*
962  * Luminosity
963  *
964  *     as * ad * B(s/as, d/ad)
965  *   = as * ad * set_lum (d/ad, LUM (s/as), 1)
966  *   = set_lum (as * d, ad * LUM (s), as * ad)
967  */
968 static force_inline void
blend_hsl_luminosity(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)969 blend_hsl_luminosity (rgb_t *res,
970 		      const rgb_t *dest, float da,
971 		      const rgb_t *src, float sa)
972 {
973     res->r = dest->r * sa;
974     res->g = dest->g * sa;
975     res->b = dest->b * sa;
976 
977     set_lum (res, sa * da, get_lum (src) * da);
978 }
979 
980 #define MAKE_NON_SEPARABLE_PDF_COMBINERS(name)				\
981     static void								\
982     combine_ ## name ## _u_float (pixman_implementation_t *imp,		\
983 				  pixman_op_t              op,		\
984 				  float                   *dest,	\
985 				  const float             *src,		\
986 				  const float             *mask,	\
987 				  int		           n_pixels)	\
988     {									\
989     	int i;								\
990 									\
991 	for (i = 0; i < 4 * n_pixels; i += 4)				\
992 	{								\
993 	    float sa, da;						\
994 	    rgb_t sc, dc, rc;						\
995 									\
996 	    sa = src[i + 0];						\
997 	    sc.r = src[i + 1];						\
998 	    sc.g = src[i + 2];						\
999 	    sc.b = src[i + 3];						\
1000 									\
1001 	    da = dest[i + 0];						\
1002 	    dc.r = dest[i + 1];						\
1003 	    dc.g = dest[i + 2];						\
1004 	    dc.b = dest[i + 3];						\
1005 									\
1006 	    if (mask)							\
1007 	    {								\
1008 		float ma = mask[i + 0];					\
1009 									\
1010 		/* Component alpha is not supported for HSL modes */	\
1011 		sa *= ma;						\
1012 		sc.r *= ma;						\
1013 		sc.g *= ma;						\
1014 		sc.g *= ma;						\
1015 	    }								\
1016 									\
1017 	    blend_ ## name (&rc, &dc, da, &sc, sa);			\
1018 									\
1019 	    dest[i + 0] = sa + da - sa * da;				\
1020 	    dest[i + 1] = (1 - sa) * dc.r + (1 - da) * sc.r + rc.r;	\
1021 	    dest[i + 2] = (1 - sa) * dc.g + (1 - da) * sc.g + rc.g;	\
1022 	    dest[i + 3] = (1 - sa) * dc.b + (1 - da) * sc.b + rc.b;	\
1023 	}								\
1024     }
1025 
1026 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_hue)
MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_saturation)1027 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_saturation)
1028 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_color)
1029 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_luminosity)
1030 
1031 void
1032 _pixman_setup_combiner_functions_float (pixman_implementation_t *imp)
1033 {
1034     /* Unified alpha */
1035     imp->combine_float[PIXMAN_OP_CLEAR] = combine_clear_u_float;
1036     imp->combine_float[PIXMAN_OP_SRC] = combine_src_u_float;
1037     imp->combine_float[PIXMAN_OP_DST] = combine_dst_u_float;
1038     imp->combine_float[PIXMAN_OP_OVER] = combine_over_u_float;
1039     imp->combine_float[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u_float;
1040     imp->combine_float[PIXMAN_OP_IN] = combine_in_u_float;
1041     imp->combine_float[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u_float;
1042     imp->combine_float[PIXMAN_OP_OUT] = combine_out_u_float;
1043     imp->combine_float[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u_float;
1044     imp->combine_float[PIXMAN_OP_ATOP] = combine_atop_u_float;
1045     imp->combine_float[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u_float;
1046     imp->combine_float[PIXMAN_OP_XOR] = combine_xor_u_float;
1047     imp->combine_float[PIXMAN_OP_ADD] = combine_add_u_float;
1048     imp->combine_float[PIXMAN_OP_SATURATE] = combine_saturate_u_float;
1049 
1050     /* Disjoint, unified */
1051     imp->combine_float[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_u_float;
1052     imp->combine_float[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_u_float;
1053     imp->combine_float[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_u_float;
1054     imp->combine_float[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u_float;
1055     imp->combine_float[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_u_float;
1056     imp->combine_float[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u_float;
1057     imp->combine_float[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u_float;
1058     imp->combine_float[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u_float;
1059     imp->combine_float[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u_float;
1060     imp->combine_float[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u_float;
1061     imp->combine_float[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u_float;
1062     imp->combine_float[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u_float;
1063 
1064     /* Conjoint, unified */
1065     imp->combine_float[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_u_float;
1066     imp->combine_float[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_u_float;
1067     imp->combine_float[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_u_float;
1068     imp->combine_float[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u_float;
1069     imp->combine_float[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u_float;
1070     imp->combine_float[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u_float;
1071     imp->combine_float[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u_float;
1072     imp->combine_float[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u_float;
1073     imp->combine_float[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u_float;
1074     imp->combine_float[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u_float;
1075     imp->combine_float[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u_float;
1076     imp->combine_float[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u_float;
1077 
1078     /* PDF operators, unified */
1079     imp->combine_float[PIXMAN_OP_MULTIPLY] = combine_multiply_u_float;
1080     imp->combine_float[PIXMAN_OP_SCREEN] = combine_screen_u_float;
1081     imp->combine_float[PIXMAN_OP_OVERLAY] = combine_overlay_u_float;
1082     imp->combine_float[PIXMAN_OP_DARKEN] = combine_darken_u_float;
1083     imp->combine_float[PIXMAN_OP_LIGHTEN] = combine_lighten_u_float;
1084     imp->combine_float[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u_float;
1085     imp->combine_float[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u_float;
1086     imp->combine_float[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u_float;
1087     imp->combine_float[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u_float;
1088     imp->combine_float[PIXMAN_OP_DIFFERENCE] = combine_difference_u_float;
1089     imp->combine_float[PIXMAN_OP_EXCLUSION] = combine_exclusion_u_float;
1090 
1091     imp->combine_float[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u_float;
1092     imp->combine_float[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u_float;
1093     imp->combine_float[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u_float;
1094     imp->combine_float[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u_float;
1095 
1096     /* Component alpha combiners */
1097     imp->combine_float_ca[PIXMAN_OP_CLEAR] = combine_clear_ca_float;
1098     imp->combine_float_ca[PIXMAN_OP_SRC] = combine_src_ca_float;
1099     imp->combine_float_ca[PIXMAN_OP_DST] = combine_dst_ca_float;
1100     imp->combine_float_ca[PIXMAN_OP_OVER] = combine_over_ca_float;
1101     imp->combine_float_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca_float;
1102     imp->combine_float_ca[PIXMAN_OP_IN] = combine_in_ca_float;
1103     imp->combine_float_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca_float;
1104     imp->combine_float_ca[PIXMAN_OP_OUT] = combine_out_ca_float;
1105     imp->combine_float_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca_float;
1106     imp->combine_float_ca[PIXMAN_OP_ATOP] = combine_atop_ca_float;
1107     imp->combine_float_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca_float;
1108     imp->combine_float_ca[PIXMAN_OP_XOR] = combine_xor_ca_float;
1109     imp->combine_float_ca[PIXMAN_OP_ADD] = combine_add_ca_float;
1110     imp->combine_float_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca_float;
1111 
1112     /* Disjoint CA */
1113     imp->combine_float_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_ca_float;
1114     imp->combine_float_ca[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_ca_float;
1115     imp->combine_float_ca[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_ca_float;
1116     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca_float;
1117     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_ca_float;
1118     imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca_float;
1119     imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca_float;
1120     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca_float;
1121     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca_float;
1122     imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca_float;
1123     imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca_float;
1124     imp->combine_float_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca_float;
1125 
1126     /* Conjoint CA */
1127     imp->combine_float_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_ca_float;
1128     imp->combine_float_ca[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_ca_float;
1129     imp->combine_float_ca[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_ca_float;
1130     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca_float;
1131     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca_float;
1132     imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca_float;
1133     imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca_float;
1134     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca_float;
1135     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca_float;
1136     imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca_float;
1137     imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca_float;
1138     imp->combine_float_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca_float;
1139 
1140     /* PDF operators CA */
1141     imp->combine_float_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca_float;
1142     imp->combine_float_ca[PIXMAN_OP_SCREEN] = combine_screen_ca_float;
1143     imp->combine_float_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca_float;
1144     imp->combine_float_ca[PIXMAN_OP_DARKEN] = combine_darken_ca_float;
1145     imp->combine_float_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca_float;
1146     imp->combine_float_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca_float;
1147     imp->combine_float_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca_float;
1148     imp->combine_float_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca_float;
1149     imp->combine_float_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca_float;
1150     imp->combine_float_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca_float;
1151     imp->combine_float_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca_float;
1152 
1153     /* It is not clear that these make sense, so make them noops for now */
1154     imp->combine_float_ca[PIXMAN_OP_HSL_HUE] = combine_dst_u_float;
1155     imp->combine_float_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst_u_float;
1156     imp->combine_float_ca[PIXMAN_OP_HSL_COLOR] = combine_dst_u_float;
1157     imp->combine_float_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst_u_float;
1158 }
1159