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 #define IS_ZERO(f)     (-FLT_MIN < (f) && (f) < FLT_MIN)
46 
47 typedef float (* combine_channel_t) (float sa, float s, float da, float d);
48 
49 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)50 combine_inner (pixman_bool_t component,
51 	       float *dest, const float *src, const float *mask, int n_pixels,
52 	       combine_channel_t combine_a, combine_channel_t combine_c)
53 {
54     int i;
55 
56     if (!mask)
57     {
58 	for (i = 0; i < 4 * n_pixels; i += 4)
59 	{
60 	    float sa = src[i + 0];
61 	    float sr = src[i + 1];
62 	    float sg = src[i + 2];
63 	    float sb = src[i + 3];
64 
65 	    float da = dest[i + 0];
66 	    float dr = dest[i + 1];
67 	    float dg = dest[i + 2];
68 	    float db = dest[i + 3];
69 
70 	    dest[i + 0] = combine_a (sa, sa, da, da);
71 	    dest[i + 1] = combine_c (sa, sr, da, dr);
72 	    dest[i + 2] = combine_c (sa, sg, da, dg);
73 	    dest[i + 3] = combine_c (sa, sb, da, db);
74 	}
75     }
76     else
77     {
78 	for (i = 0; i < 4 * n_pixels; i += 4)
79 	{
80 	    float sa, sr, sg, sb;
81 	    float ma, mr, mg, mb;
82 	    float da, dr, dg, db;
83 
84 	    sa = src[i + 0];
85 	    sr = src[i + 1];
86 	    sg = src[i + 2];
87 	    sb = src[i + 3];
88 
89 	    if (component)
90 	    {
91 		ma = mask[i + 0];
92 		mr = mask[i + 1];
93 		mg = mask[i + 2];
94 		mb = mask[i + 3];
95 
96 		sr *= mr;
97 		sg *= mg;
98 		sb *= mb;
99 
100 		ma *= sa;
101 		mr *= sa;
102 		mg *= sa;
103 		mb *= sa;
104 
105 		sa = ma;
106 	    }
107 	    else
108 	    {
109 		ma = mask[i + 0];
110 
111 		sa *= ma;
112 		sr *= ma;
113 		sg *= ma;
114 		sb *= ma;
115 
116 		ma = mr = mg = mb = sa;
117 	    }
118 
119 	    da = dest[i + 0];
120 	    dr = dest[i + 1];
121 	    dg = dest[i + 2];
122 	    db = dest[i + 3];
123 
124 	    dest[i + 0] = combine_a (ma, sa, da, da);
125 	    dest[i + 1] = combine_c (mr, sr, da, dr);
126 	    dest[i + 2] = combine_c (mg, sg, da, dg);
127 	    dest[i + 3] = combine_c (mb, sb, da, db);
128 	}
129     }
130 }
131 
132 #define MAKE_COMBINER(name, component, combine_a, combine_c)		\
133     static void								\
134     combine_ ## name ## _float (pixman_implementation_t *imp,		\
135 				pixman_op_t              op,		\
136 				float                   *dest,		\
137 				const float             *src,		\
138 				const float             *mask,		\
139 				int		         n_pixels)	\
140     {									\
141 	combine_inner (component, dest, src, mask, n_pixels,		\
142 		       combine_a, combine_c);				\
143     }
144 
145 #define MAKE_COMBINERS(name, combine_a, combine_c)			\
146     MAKE_COMBINER(name ## _ca, TRUE, combine_a, combine_c)		\
147     MAKE_COMBINER(name ## _u, FALSE, combine_a, combine_c)
148 
149 
150 /*
151  * Porter/Duff operators
152  */
153 typedef enum
154 {
155     ZERO,
156     ONE,
157     SRC_ALPHA,
158     DEST_ALPHA,
159     INV_SA,
160     INV_DA,
161     SA_OVER_DA,
162     DA_OVER_SA,
163     INV_SA_OVER_DA,
164     INV_DA_OVER_SA,
165     ONE_MINUS_SA_OVER_DA,
166     ONE_MINUS_DA_OVER_SA,
167     ONE_MINUS_INV_DA_OVER_SA,
168     ONE_MINUS_INV_SA_OVER_DA
169 } combine_factor_t;
170 
171 #define CLAMP(f)					\
172     (((f) < 0)? 0 : (((f) > 1.0) ? 1.0 : (f)))
173 
174 static force_inline float
get_factor(combine_factor_t factor,float sa,float da)175 get_factor (combine_factor_t factor, float sa, float da)
176 {
177     float f = -1;
178 
179     switch (factor)
180     {
181     case ZERO:
182 	f = 0.0f;
183 	break;
184 
185     case ONE:
186 	f = 1.0f;
187 	break;
188 
189     case SRC_ALPHA:
190 	f = sa;
191 	break;
192 
193     case DEST_ALPHA:
194 	f = da;
195 	break;
196 
197     case INV_SA:
198 	f = 1 - sa;
199 	break;
200 
201     case INV_DA:
202 	f = 1 - da;
203 	break;
204 
205     case SA_OVER_DA:
206 	if (IS_ZERO (da))
207 	    f = 1.0f;
208 	else
209 	    f = CLAMP (sa / da);
210 	break;
211 
212     case DA_OVER_SA:
213 	if (IS_ZERO (sa))
214 	    f = 1.0f;
215 	else
216 	    f = CLAMP (da / sa);
217 	break;
218 
219     case INV_SA_OVER_DA:
220 	if (IS_ZERO (da))
221 	    f = 1.0f;
222 	else
223 	    f = CLAMP ((1.0f - sa) / da);
224 	break;
225 
226     case INV_DA_OVER_SA:
227 	if (IS_ZERO (sa))
228 	    f = 1.0f;
229 	else
230 	    f = CLAMP ((1.0f - da) / sa);
231 	break;
232 
233     case ONE_MINUS_SA_OVER_DA:
234 	if (IS_ZERO (da))
235 	    f = 0.0f;
236 	else
237 	    f = CLAMP (1.0f - sa / da);
238 	break;
239 
240     case ONE_MINUS_DA_OVER_SA:
241 	if (IS_ZERO (sa))
242 	    f = 0.0f;
243 	else
244 	    f = CLAMP (1.0f - da / sa);
245 	break;
246 
247     case ONE_MINUS_INV_DA_OVER_SA:
248 	if (IS_ZERO (sa))
249 	    f = 0.0f;
250 	else
251 	    f = CLAMP (1.0f - (1.0f - da) / sa);
252 	break;
253 
254     case ONE_MINUS_INV_SA_OVER_DA:
255 	if (IS_ZERO (da))
256 	    f = 0.0f;
257 	else
258 	    f = CLAMP (1.0f - (1.0f - sa) / da);
259 	break;
260     }
261 
262     return f;
263 }
264 
265 #define MAKE_PD_COMBINERS(name, a, b)					\
266     static float force_inline						\
267     pd_combine_ ## name (float sa, float s, float da, float d)		\
268     {									\
269 	const float fa = get_factor (a, sa, da);			\
270 	const float fb = get_factor (b, sa, da);			\
271 									\
272 	return MIN (1.0f, s * fa + d * fb);				\
273     }									\
274     									\
275     MAKE_COMBINERS(name, pd_combine_ ## name, pd_combine_ ## name)
276 
MAKE_PD_COMBINERS(clear,ZERO,ZERO)277 MAKE_PD_COMBINERS (clear,			ZERO,				ZERO)
278 MAKE_PD_COMBINERS (src,				ONE,				ZERO)
279 MAKE_PD_COMBINERS (dst,				ZERO,				ONE)
280 MAKE_PD_COMBINERS (over,			ONE,				INV_SA)
281 MAKE_PD_COMBINERS (over_reverse,		INV_DA,				ONE)
282 MAKE_PD_COMBINERS (in,				DEST_ALPHA,			ZERO)
283 MAKE_PD_COMBINERS (in_reverse,			ZERO,				SRC_ALPHA)
284 MAKE_PD_COMBINERS (out,				INV_DA,				ZERO)
285 MAKE_PD_COMBINERS (out_reverse,			ZERO,				INV_SA)
286 MAKE_PD_COMBINERS (atop,			DEST_ALPHA,			INV_SA)
287 MAKE_PD_COMBINERS (atop_reverse,		INV_DA,				SRC_ALPHA)
288 MAKE_PD_COMBINERS (xor,				INV_DA,				INV_SA)
289 MAKE_PD_COMBINERS (add,				ONE,				ONE)
290 
291 MAKE_PD_COMBINERS (saturate,			INV_DA_OVER_SA,			ONE)
292 
293 MAKE_PD_COMBINERS (disjoint_clear,		ZERO,				ZERO)
294 MAKE_PD_COMBINERS (disjoint_src,		ONE,				ZERO)
295 MAKE_PD_COMBINERS (disjoint_dst,		ZERO,				ONE)
296 MAKE_PD_COMBINERS (disjoint_over,		ONE,				INV_SA_OVER_DA)
297 MAKE_PD_COMBINERS (disjoint_over_reverse,	INV_DA_OVER_SA,			ONE)
298 MAKE_PD_COMBINERS (disjoint_in,			ONE_MINUS_INV_DA_OVER_SA,	ZERO)
299 MAKE_PD_COMBINERS (disjoint_in_reverse,		ZERO,				ONE_MINUS_INV_SA_OVER_DA)
300 MAKE_PD_COMBINERS (disjoint_out,		INV_DA_OVER_SA,			ZERO)
301 MAKE_PD_COMBINERS (disjoint_out_reverse,	ZERO,				INV_SA_OVER_DA)
302 MAKE_PD_COMBINERS (disjoint_atop,		ONE_MINUS_INV_DA_OVER_SA,	INV_SA_OVER_DA)
303 MAKE_PD_COMBINERS (disjoint_atop_reverse,	INV_DA_OVER_SA,			ONE_MINUS_INV_SA_OVER_DA)
304 MAKE_PD_COMBINERS (disjoint_xor,		INV_DA_OVER_SA,			INV_SA_OVER_DA)
305 
306 MAKE_PD_COMBINERS (conjoint_clear,		ZERO,				ZERO)
307 MAKE_PD_COMBINERS (conjoint_src,		ONE,				ZERO)
308 MAKE_PD_COMBINERS (conjoint_dst,		ZERO,				ONE)
309 MAKE_PD_COMBINERS (conjoint_over,		ONE,				ONE_MINUS_SA_OVER_DA)
310 MAKE_PD_COMBINERS (conjoint_over_reverse,	ONE_MINUS_DA_OVER_SA,		ONE)
311 MAKE_PD_COMBINERS (conjoint_in,			DA_OVER_SA,			ZERO)
312 MAKE_PD_COMBINERS (conjoint_in_reverse,		ZERO,				SA_OVER_DA)
313 MAKE_PD_COMBINERS (conjoint_out,		ONE_MINUS_DA_OVER_SA,		ZERO)
314 MAKE_PD_COMBINERS (conjoint_out_reverse,	ZERO,				ONE_MINUS_SA_OVER_DA)
315 MAKE_PD_COMBINERS (conjoint_atop,		DA_OVER_SA,			ONE_MINUS_SA_OVER_DA)
316 MAKE_PD_COMBINERS (conjoint_atop_reverse,	ONE_MINUS_DA_OVER_SA,		SA_OVER_DA)
317 MAKE_PD_COMBINERS (conjoint_xor,		ONE_MINUS_DA_OVER_SA,		ONE_MINUS_SA_OVER_DA)
318 
319 /*
320  * PDF blend modes:
321  *
322  * The following blend modes have been taken from the PDF ISO 32000
323  * specification, which at this point in time is available from
324  * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf
325  * The relevant chapters are 11.3.5 and 11.3.6.
326  * The formula for computing the final pixel color given in 11.3.6 is:
327  * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs)
328  * with B() being the blend function.
329  * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs
330  *
331  * These blend modes should match the SVG filter draft specification, as
332  * it has been designed to mirror ISO 32000. Note that at the current point
333  * no released draft exists that shows this, as the formulas have not been
334  * updated yet after the release of ISO 32000.
335  *
336  * The default implementation here uses the PDF_SEPARABLE_BLEND_MODE and
337  * PDF_NON_SEPARABLE_BLEND_MODE macros, which take the blend function as an
338  * argument. Note that this implementation operates on premultiplied colors,
339  * while the PDF specification does not. Therefore the code uses the formula
340  * ar.Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as)
341  */
342 
343 #define MAKE_SEPARABLE_PDF_COMBINERS(name)				\
344     static force_inline float						\
345     combine_ ## name ## _a (float sa, float s, float da, float d)	\
346     {									\
347 	return da + sa - da * sa;					\
348     }									\
349     									\
350     static force_inline float						\
351     combine_ ## name ## _c (float sa, float s, float da, float d)	\
352     {									\
353 	float f = (1 - sa) * d + (1 - da) * s;				\
354 									\
355 	return f + blend_ ## name (sa, s, da, d);			\
356     }									\
357     									\
358     MAKE_COMBINERS (name, combine_ ## name ## _a, combine_ ## name ## _c)
359 
360 static force_inline float
361 blend_multiply (float sa, float s, float da, float d)
362 {
363     return d * s;
364 }
365 
366 static force_inline float
blend_screen(float sa,float s,float da,float d)367 blend_screen (float sa, float s, float da, float d)
368 {
369     return d * sa + s * da - s * d;
370 }
371 
372 static force_inline float
blend_overlay(float sa,float s,float da,float d)373 blend_overlay (float sa, float s, float da, float d)
374 {
375     if (2 * d < da)
376 	return 2 * s * d;
377     else
378 	return sa * da - 2 * (da - d) * (sa - s);
379 }
380 
381 static force_inline float
blend_darken(float sa,float s,float da,float d)382 blend_darken (float sa, float s, float da, float d)
383 {
384     s = s * da;
385     d = d * sa;
386 
387     if (s > d)
388 	return d;
389     else
390 	return s;
391 }
392 
393 static force_inline float
blend_lighten(float sa,float s,float da,float d)394 blend_lighten (float sa, float s, float da, float d)
395 {
396     s = s * da;
397     d = d * sa;
398 
399     if (s > d)
400 	return s;
401     else
402 	return d;
403 }
404 
405 static force_inline float
blend_color_dodge(float sa,float s,float da,float d)406 blend_color_dodge (float sa, float s, float da, float d)
407 {
408     if (IS_ZERO (d))
409 	return 0.0f;
410     else if (d * sa >= sa * da - s * da)
411 	return sa * da;
412     else if (IS_ZERO (sa - s))
413 	return sa * da;
414     else
415 	return sa * sa * d / (sa - s);
416 }
417 
418 static force_inline float
blend_color_burn(float sa,float s,float da,float d)419 blend_color_burn (float sa, float s, float da, float d)
420 {
421     if (d >= da)
422 	return sa * da;
423     else if (sa * (da - d) >= s * da)
424 	return 0.0f;
425     else if (IS_ZERO (s))
426 	return 0.0f;
427     else
428 	return sa * (da - sa * (da - d) / s);
429 }
430 
431 static force_inline float
blend_hard_light(float sa,float s,float da,float d)432 blend_hard_light (float sa, float s, float da, float d)
433 {
434     if (2 * s < sa)
435 	return 2 * s * d;
436     else
437 	return sa * da - 2 * (da - d) * (sa - s);
438 }
439 
440 static force_inline float
blend_soft_light(float sa,float s,float da,float d)441 blend_soft_light (float sa, float s, float da, float d)
442 {
443     if (2 * s < sa)
444     {
445 	if (IS_ZERO (da))
446 	    return d * sa;
447 	else
448 	    return d * sa - d * (da - d) * (sa - 2 * s) / da;
449     }
450     else
451     {
452 	if (IS_ZERO (da))
453 	{
454 	    return 0.0f;
455 	}
456 	else
457 	{
458 	    if (4 * d <= da)
459 		return d * sa + (2 * s - sa) * d * ((16 * d / da - 12) * d / da + 3);
460 	    else
461 		return d * sa + (sqrtf (d * da) - d) * (2 * s - sa);
462 	}
463     }
464 }
465 
466 static force_inline float
blend_difference(float sa,float s,float da,float d)467 blend_difference (float sa, float s, float da, float d)
468 {
469     float dsa = d * sa;
470     float sda = s * da;
471 
472     if (sda < dsa)
473 	return dsa - sda;
474     else
475 	return sda - dsa;
476 }
477 
478 static force_inline float
blend_exclusion(float sa,float s,float da,float d)479 blend_exclusion (float sa, float s, float da, float d)
480 {
481     return s * da + d * sa - 2 * d * s;
482 }
483 
484 MAKE_SEPARABLE_PDF_COMBINERS (multiply)
485 MAKE_SEPARABLE_PDF_COMBINERS (screen)
486 MAKE_SEPARABLE_PDF_COMBINERS (overlay)
487 MAKE_SEPARABLE_PDF_COMBINERS (darken)
488 MAKE_SEPARABLE_PDF_COMBINERS (lighten)
489 MAKE_SEPARABLE_PDF_COMBINERS (color_dodge)
490 MAKE_SEPARABLE_PDF_COMBINERS (color_burn)
491 MAKE_SEPARABLE_PDF_COMBINERS (hard_light)
492 MAKE_SEPARABLE_PDF_COMBINERS (soft_light)
493 MAKE_SEPARABLE_PDF_COMBINERS (difference)
494 MAKE_SEPARABLE_PDF_COMBINERS (exclusion)
495 
496 /*
497  * PDF nonseperable blend modes.
498  *
499  * These are implemented using the following functions to operate in Hsl
500  * space, with Cmax, Cmid, Cmin referring to the max, mid and min value
501  * of the red, green and blue components.
502  *
503  * LUM (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue
504  *
505  * clip_color (C):
506  *   l = LUM (C)
507  *   min = Cmin
508  *   max = Cmax
509  *   if n < 0.0
510  *     C = l + (((C – l) × l) ⁄     (l – min))
511  *   if x > 1.0
512  *     C = l + (((C – l) × (1 – l)) (max – l))
513  *   return C
514  *
515  * set_lum (C, l):
516  *   d = l – LUM (C)
517  *   C += d
518  *   return clip_color (C)
519  *
520  * SAT (C) = CH_MAX (C) - CH_MIN (C)
521  *
522  * set_sat (C, s):
523  *  if Cmax > Cmin
524  *    Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) )
525  *    Cmax = s
526  *  else
527  *    Cmid = Cmax = 0.0
528  *  Cmin = 0.0
529  *  return C
530  */
531 
532 /* For premultiplied colors, we need to know what happens when C is
533  * multiplied by a real number. LUM and SAT are linear:
534  *
535  *    LUM (r × C) = r × LUM (C)		SAT (r × C) = r × SAT (C)
536  *
537  * If we extend clip_color with an extra argument a and change
538  *
539  *        if x >= 1.0
540  *
541  * into
542  *
543  *        if x >= a
544  *
545  * then clip_color is also linear:
546  *
547  *     r * clip_color (C, a) = clip_color (r_c, ra);
548  *
549  * for positive r.
550  *
551  * Similarly, we can extend set_lum with an extra argument that is just passed
552  * on to clip_color:
553  *
554  *     r × set_lum ( C, l, a)
555  *
556  *   = r × clip_color ( C + l - LUM (C), a)
557  *
558  *   = clip_color ( r * C + r × l - LUM (r × C), r * a)
559  *
560  *   = set_lum ( r * C, r * l, r * a)
561  *
562  * Finally, set_sat:
563  *
564  *     r * set_sat (C, s) = set_sat (x * C, r * s)
565  *
566  * The above holds for all non-zero x because they x'es in the fraction for
567  * C_mid cancel out. Specifically, it holds for x = r:
568  *
569  *     r * set_sat (C, s) = set_sat (r_c, rs)
570  *
571  *
572  *
573  *
574  * So, for the non-separable PDF blend modes, we have (using s, d for
575  * non-premultiplied colors, and S, D for premultiplied:
576  *
577  *   Color:
578  *
579  *     a_s * a_d * B(s, d)
580  *   = a_s * a_d * set_lum (S/a_s, LUM (D/a_d), 1)
581  *   = set_lum (S * a_d, a_s * LUM (D), a_s * a_d)
582  *
583  *
584  *   Luminosity:
585  *
586  *     a_s * a_d * B(s, d)
587  *   = a_s * a_d * set_lum (D/a_d, LUM(S/a_s), 1)
588  *   = set_lum (a_s * D, a_d * LUM(S), a_s * a_d)
589  *
590  *
591  *   Saturation:
592  *
593  *     a_s * a_d * B(s, d)
594  *   = a_s * a_d * set_lum (set_sat (D/a_d, SAT (S/a_s)), LUM (D/a_d), 1)
595  *   = set_lum (a_s * a_d * set_sat (D/a_d, SAT (S/a_s)),
596  *                                        a_s * LUM (D), a_s * a_d)
597  *   = set_lum (set_sat (a_s * D, a_d * SAT (S), a_s * LUM (D), a_s * a_d))
598  *
599  *   Hue:
600  *
601  *     a_s * a_d * B(s, d)
602  *   = a_s * a_d * set_lum (set_sat (S/a_s, SAT (D/a_d)), LUM (D/a_d), 1)
603  *   = set_lum (set_sat (a_d * S, a_s * SAT (D)), a_s * LUM (D), a_s * a_d)
604  *
605  */
606 
607 typedef struct
608 {
609     float	r;
610     float	g;
611     float	b;
612 } rgb_t;
613 
614 static force_inline float
minf(float a,float b)615 minf (float a, float b)
616 {
617     return a < b? a : b;
618 }
619 
620 static force_inline float
maxf(float a,float b)621 maxf (float a, float b)
622 {
623     return a > b? a : b;
624 }
625 
626 static force_inline float
channel_min(const rgb_t * c)627 channel_min (const rgb_t *c)
628 {
629     return minf (minf (c->r, c->g), c->b);
630 }
631 
632 static force_inline float
channel_max(const rgb_t * c)633 channel_max (const rgb_t *c)
634 {
635     return maxf (maxf (c->r, c->g), c->b);
636 }
637 
638 static force_inline float
get_lum(const rgb_t * c)639 get_lum (const rgb_t *c)
640 {
641     return c->r * 0.3f + c->g * 0.59f + c->b * 0.11f;
642 }
643 
644 static force_inline float
get_sat(const rgb_t * c)645 get_sat (const rgb_t *c)
646 {
647     return channel_max (c) - channel_min (c);
648 }
649 
650 static void
clip_color(rgb_t * color,float a)651 clip_color (rgb_t *color, float a)
652 {
653     float l = get_lum (color);
654     float n = channel_min (color);
655     float x = channel_max (color);
656     float t;
657 
658     if (n < 0.0f)
659     {
660 	t = l - n;
661 	if (IS_ZERO (t))
662 	{
663 	    color->r = 0.0f;
664 	    color->g = 0.0f;
665 	    color->b = 0.0f;
666 	}
667 	else
668 	{
669 	    color->r = l + (((color->r - l) * l) / t);
670 	    color->g = l + (((color->g - l) * l) / t);
671 	    color->b = l + (((color->b - l) * l) / t);
672 	}
673     }
674     if (x > a)
675     {
676 	t = x - l;
677 	if (IS_ZERO (t))
678 	{
679 	    color->r = a;
680 	    color->g = a;
681 	    color->b = a;
682 	}
683 	else
684 	{
685 	    color->r = l + (((color->r - l) * (a - l) / t));
686 	    color->g = l + (((color->g - l) * (a - l) / t));
687 	    color->b = l + (((color->b - l) * (a - l) / t));
688 	}
689     }
690 }
691 
692 static void
set_lum(rgb_t * color,float sa,float l)693 set_lum (rgb_t *color, float sa, float l)
694 {
695     float d = l - get_lum (color);
696 
697     color->r = color->r + d;
698     color->g = color->g + d;
699     color->b = color->b + d;
700 
701     clip_color (color, sa);
702 }
703 
704 static void
set_sat(rgb_t * src,float sat)705 set_sat (rgb_t *src, float sat)
706 {
707     float *max, *mid, *min;
708     float t;
709 
710     if (src->r > src->g)
711     {
712 	if (src->r > src->b)
713 	{
714 	    max = &(src->r);
715 
716 	    if (src->g > src->b)
717 	    {
718 		mid = &(src->g);
719 		min = &(src->b);
720 	    }
721 	    else
722 	    {
723 		mid = &(src->b);
724 		min = &(src->g);
725 	    }
726 	}
727 	else
728 	{
729 	    max = &(src->b);
730 	    mid = &(src->r);
731 	    min = &(src->g);
732 	}
733     }
734     else
735     {
736 	if (src->r > src->b)
737 	{
738 	    max = &(src->g);
739 	    mid = &(src->r);
740 	    min = &(src->b);
741 	}
742 	else
743 	{
744 	    min = &(src->r);
745 
746 	    if (src->g > src->b)
747 	    {
748 		max = &(src->g);
749 		mid = &(src->b);
750 	    }
751 	    else
752 	    {
753 		max = &(src->b);
754 		mid = &(src->g);
755 	    }
756 	}
757     }
758 
759     t = *max - *min;
760 
761     if (IS_ZERO (t))
762     {
763 	*mid = *max = 0.0f;
764     }
765     else
766     {
767 	*mid = ((*mid - *min) * sat) / t;
768 	*max = sat;
769     }
770 
771     *min = 0.0f;
772 }
773 
774 /*
775  * Hue:
776  * B(Cb, Cs) = set_lum (set_sat (Cs, SAT (Cb)), LUM (Cb))
777  */
778 static force_inline void
blend_hsl_hue(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)779 blend_hsl_hue (rgb_t *res,
780 	       const rgb_t *dest, float da,
781 	       const rgb_t *src, float sa)
782 {
783     res->r = src->r * da;
784     res->g = src->g * da;
785     res->b = src->b * da;
786 
787     set_sat (res, get_sat (dest) * sa);
788     set_lum (res, sa * da, get_lum (dest) * sa);
789 }
790 
791 /*
792  * Saturation:
793  * B(Cb, Cs) = set_lum (set_sat (Cb, SAT (Cs)), LUM (Cb))
794  */
795 static force_inline void
blend_hsl_saturation(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)796 blend_hsl_saturation (rgb_t *res,
797 		      const rgb_t *dest, float da,
798 		      const rgb_t *src, float sa)
799 {
800     res->r = dest->r * sa;
801     res->g = dest->g * sa;
802     res->b = dest->b * sa;
803 
804     set_sat (res, get_sat (src) * da);
805     set_lum (res, sa * da, get_lum (dest) * sa);
806 }
807 
808 /*
809  * Color:
810  * B(Cb, Cs) = set_lum (Cs, LUM (Cb))
811  */
812 static force_inline void
blend_hsl_color(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)813 blend_hsl_color (rgb_t *res,
814 		 const rgb_t *dest, float da,
815 		 const rgb_t *src, float sa)
816 {
817     res->r = src->r * da;
818     res->g = src->g * da;
819     res->b = src->b * da;
820 
821     set_lum (res, sa * da, get_lum (dest) * sa);
822 }
823 
824 /*
825  * Luminosity:
826  * B(Cb, Cs) = set_lum (Cb, LUM (Cs))
827  */
828 static force_inline void
blend_hsl_luminosity(rgb_t * res,const rgb_t * dest,float da,const rgb_t * src,float sa)829 blend_hsl_luminosity (rgb_t *res,
830 		      const rgb_t *dest, float da,
831 		      const rgb_t *src, float sa)
832 {
833     res->r = dest->r * sa;
834     res->g = dest->g * sa;
835     res->b = dest->b * sa;
836 
837     set_lum (res, sa * da, get_lum (src) * da);
838 }
839 
840 #define MAKE_NON_SEPARABLE_PDF_COMBINERS(name)				\
841     static void								\
842     combine_ ## name ## _u_float (pixman_implementation_t *imp,		\
843 				  pixman_op_t              op,		\
844 				  float                   *dest,	\
845 				  const float             *src,		\
846 				  const float             *mask,	\
847 				  int		           n_pixels)	\
848     {									\
849     	int i;								\
850 									\
851 	for (i = 0; i < 4 * n_pixels; i += 4)				\
852 	{								\
853 	    float sa, da;						\
854 	    rgb_t sc, dc, rc;						\
855 									\
856 	    sa = src[i + 0];						\
857 	    sc.r = src[i + 1];						\
858 	    sc.g = src[i + 2];						\
859 	    sc.b = src[i + 3];						\
860 									\
861 	    da = dest[i + 0];						\
862 	    dc.r = dest[i + 1];						\
863 	    dc.g = dest[i + 2];						\
864 	    dc.b = dest[i + 3];						\
865 									\
866 	    if (mask)							\
867 	    {								\
868 		float ma = mask[i + 0];					\
869 									\
870 		/* Component alpha is not supported for HSL modes */	\
871 		sa *= ma;						\
872 		sc.r *= ma;						\
873 		sc.g *= ma;						\
874 		sc.g *= ma;						\
875 	    }								\
876 									\
877 	    blend_ ## name (&rc, &dc, da, &sc, sa);			\
878 									\
879 	    dest[i + 0] = sa + da - sa * da;				\
880 	    dest[i + 1] = (1 - sa) * dc.r + (1 - da) * sc.r + rc.r;	\
881 	    dest[i + 2] = (1 - sa) * dc.g + (1 - da) * sc.g + rc.g;	\
882 	    dest[i + 3] = (1 - sa) * dc.b + (1 - da) * sc.b + rc.b;	\
883 	}								\
884     }
885 
886 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_hue)
MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_saturation)887 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_saturation)
888 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_color)
889 MAKE_NON_SEPARABLE_PDF_COMBINERS(hsl_luminosity)
890 
891 void
892 _pixman_setup_combiner_functions_float (pixman_implementation_t *imp)
893 {
894     /* Unified alpha */
895     imp->combine_float[PIXMAN_OP_CLEAR] = combine_clear_u_float;
896     imp->combine_float[PIXMAN_OP_SRC] = combine_src_u_float;
897     imp->combine_float[PIXMAN_OP_DST] = combine_dst_u_float;
898     imp->combine_float[PIXMAN_OP_OVER] = combine_over_u_float;
899     imp->combine_float[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u_float;
900     imp->combine_float[PIXMAN_OP_IN] = combine_in_u_float;
901     imp->combine_float[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u_float;
902     imp->combine_float[PIXMAN_OP_OUT] = combine_out_u_float;
903     imp->combine_float[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u_float;
904     imp->combine_float[PIXMAN_OP_ATOP] = combine_atop_u_float;
905     imp->combine_float[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u_float;
906     imp->combine_float[PIXMAN_OP_XOR] = combine_xor_u_float;
907     imp->combine_float[PIXMAN_OP_ADD] = combine_add_u_float;
908     imp->combine_float[PIXMAN_OP_SATURATE] = combine_saturate_u_float;
909 
910     /* Disjoint, unified */
911     imp->combine_float[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_u_float;
912     imp->combine_float[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_u_float;
913     imp->combine_float[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_u_float;
914     imp->combine_float[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_u_float;
915     imp->combine_float[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_u_float;
916     imp->combine_float[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_u_float;
917     imp->combine_float[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_u_float;
918     imp->combine_float[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_u_float;
919     imp->combine_float[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_u_float;
920     imp->combine_float[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_u_float;
921     imp->combine_float[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_u_float;
922     imp->combine_float[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_u_float;
923 
924     /* Conjoint, unified */
925     imp->combine_float[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_u_float;
926     imp->combine_float[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_u_float;
927     imp->combine_float[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_u_float;
928     imp->combine_float[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_u_float;
929     imp->combine_float[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_u_float;
930     imp->combine_float[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_u_float;
931     imp->combine_float[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_u_float;
932     imp->combine_float[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_u_float;
933     imp->combine_float[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_u_float;
934     imp->combine_float[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_u_float;
935     imp->combine_float[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_u_float;
936     imp->combine_float[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_u_float;
937 
938     /* PDF operators, unified */
939     imp->combine_float[PIXMAN_OP_MULTIPLY] = combine_multiply_u_float;
940     imp->combine_float[PIXMAN_OP_SCREEN] = combine_screen_u_float;
941     imp->combine_float[PIXMAN_OP_OVERLAY] = combine_overlay_u_float;
942     imp->combine_float[PIXMAN_OP_DARKEN] = combine_darken_u_float;
943     imp->combine_float[PIXMAN_OP_LIGHTEN] = combine_lighten_u_float;
944     imp->combine_float[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_u_float;
945     imp->combine_float[PIXMAN_OP_COLOR_BURN] = combine_color_burn_u_float;
946     imp->combine_float[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u_float;
947     imp->combine_float[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_u_float;
948     imp->combine_float[PIXMAN_OP_DIFFERENCE] = combine_difference_u_float;
949     imp->combine_float[PIXMAN_OP_EXCLUSION] = combine_exclusion_u_float;
950 
951     imp->combine_float[PIXMAN_OP_HSL_HUE] = combine_hsl_hue_u_float;
952     imp->combine_float[PIXMAN_OP_HSL_SATURATION] = combine_hsl_saturation_u_float;
953     imp->combine_float[PIXMAN_OP_HSL_COLOR] = combine_hsl_color_u_float;
954     imp->combine_float[PIXMAN_OP_HSL_LUMINOSITY] = combine_hsl_luminosity_u_float;
955 
956     /* Component alpha combiners */
957     imp->combine_float_ca[PIXMAN_OP_CLEAR] = combine_clear_ca_float;
958     imp->combine_float_ca[PIXMAN_OP_SRC] = combine_src_ca_float;
959     imp->combine_float_ca[PIXMAN_OP_DST] = combine_dst_ca_float;
960     imp->combine_float_ca[PIXMAN_OP_OVER] = combine_over_ca_float;
961     imp->combine_float_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca_float;
962     imp->combine_float_ca[PIXMAN_OP_IN] = combine_in_ca_float;
963     imp->combine_float_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca_float;
964     imp->combine_float_ca[PIXMAN_OP_OUT] = combine_out_ca_float;
965     imp->combine_float_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca_float;
966     imp->combine_float_ca[PIXMAN_OP_ATOP] = combine_atop_ca_float;
967     imp->combine_float_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca_float;
968     imp->combine_float_ca[PIXMAN_OP_XOR] = combine_xor_ca_float;
969     imp->combine_float_ca[PIXMAN_OP_ADD] = combine_add_ca_float;
970     imp->combine_float_ca[PIXMAN_OP_SATURATE] = combine_saturate_ca_float;
971 
972     /* Disjoint CA */
973     imp->combine_float_ca[PIXMAN_OP_DISJOINT_CLEAR] = combine_disjoint_clear_ca_float;
974     imp->combine_float_ca[PIXMAN_OP_DISJOINT_SRC] = combine_disjoint_src_ca_float;
975     imp->combine_float_ca[PIXMAN_OP_DISJOINT_DST] = combine_disjoint_dst_ca_float;
976     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER] = combine_disjoint_over_ca_float;
977     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OVER_REVERSE] = combine_disjoint_over_reverse_ca_float;
978     imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN] = combine_disjoint_in_ca_float;
979     imp->combine_float_ca[PIXMAN_OP_DISJOINT_IN_REVERSE] = combine_disjoint_in_reverse_ca_float;
980     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT] = combine_disjoint_out_ca_float;
981     imp->combine_float_ca[PIXMAN_OP_DISJOINT_OUT_REVERSE] = combine_disjoint_out_reverse_ca_float;
982     imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP] = combine_disjoint_atop_ca_float;
983     imp->combine_float_ca[PIXMAN_OP_DISJOINT_ATOP_REVERSE] = combine_disjoint_atop_reverse_ca_float;
984     imp->combine_float_ca[PIXMAN_OP_DISJOINT_XOR] = combine_disjoint_xor_ca_float;
985 
986     /* Conjoint CA */
987     imp->combine_float_ca[PIXMAN_OP_CONJOINT_CLEAR] = combine_conjoint_clear_ca_float;
988     imp->combine_float_ca[PIXMAN_OP_CONJOINT_SRC] = combine_conjoint_src_ca_float;
989     imp->combine_float_ca[PIXMAN_OP_CONJOINT_DST] = combine_conjoint_dst_ca_float;
990     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER] = combine_conjoint_over_ca_float;
991     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OVER_REVERSE] = combine_conjoint_over_reverse_ca_float;
992     imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN] = combine_conjoint_in_ca_float;
993     imp->combine_float_ca[PIXMAN_OP_CONJOINT_IN_REVERSE] = combine_conjoint_in_reverse_ca_float;
994     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT] = combine_conjoint_out_ca_float;
995     imp->combine_float_ca[PIXMAN_OP_CONJOINT_OUT_REVERSE] = combine_conjoint_out_reverse_ca_float;
996     imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP] = combine_conjoint_atop_ca_float;
997     imp->combine_float_ca[PIXMAN_OP_CONJOINT_ATOP_REVERSE] = combine_conjoint_atop_reverse_ca_float;
998     imp->combine_float_ca[PIXMAN_OP_CONJOINT_XOR] = combine_conjoint_xor_ca_float;
999 
1000     /* PDF operators CA */
1001     imp->combine_float_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca_float;
1002     imp->combine_float_ca[PIXMAN_OP_SCREEN] = combine_screen_ca_float;
1003     imp->combine_float_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca_float;
1004     imp->combine_float_ca[PIXMAN_OP_DARKEN] = combine_darken_ca_float;
1005     imp->combine_float_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca_float;
1006     imp->combine_float_ca[PIXMAN_OP_COLOR_DODGE] = combine_color_dodge_ca_float;
1007     imp->combine_float_ca[PIXMAN_OP_COLOR_BURN] = combine_color_burn_ca_float;
1008     imp->combine_float_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca_float;
1009     imp->combine_float_ca[PIXMAN_OP_SOFT_LIGHT] = combine_soft_light_ca_float;
1010     imp->combine_float_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca_float;
1011     imp->combine_float_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca_float;
1012 
1013     /* It is not clear that these make sense, so make them noops for now */
1014     imp->combine_float_ca[PIXMAN_OP_HSL_HUE] = combine_dst_u_float;
1015     imp->combine_float_ca[PIXMAN_OP_HSL_SATURATION] = combine_dst_u_float;
1016     imp->combine_float_ca[PIXMAN_OP_HSL_COLOR] = combine_dst_u_float;
1017     imp->combine_float_ca[PIXMAN_OP_HSL_LUMINOSITY] = combine_dst_u_float;
1018 }
1019