• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
3  *             2005 Lars Knoll & Zack Rusin, Trolltech
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of Keith Packard not be used in
10  * advertising or publicity pertaining to distribution of the software without
11  * specific, written prior permission.  Keith Packard makes no
12  * representations about the suitability of this software for any purpose.  It
13  * is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
20  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
21  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22  * SOFTWARE.
23  */
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <math.h>
29 #include <string.h>
30 
31 #include "pixman-private.h"
32 #include "pixman-combine32.h"
33 
34 /* component alpha helper functions */
35 
36 static void
combine_mask_ca(uint32_t * src,uint32_t * mask)37 combine_mask_ca (uint32_t *src, uint32_t *mask)
38 {
39     uint32_t a = *mask;
40 
41     uint32_t x;
42     uint16_t xa;
43 
44     if (!a)
45     {
46 	*(src) = 0;
47 	return;
48     }
49 
50     x = *(src);
51     if (a == ~0)
52     {
53 	x = x >> A_SHIFT;
54 	x |= x << G_SHIFT;
55 	x |= x << R_SHIFT;
56 	*(mask) = x;
57 	return;
58     }
59 
60     xa = x >> A_SHIFT;
61     UN8x4_MUL_UN8x4 (x, a);
62     *(src) = x;
63 
64     UN8x4_MUL_UN8 (a, xa);
65     *(mask) = a;
66 }
67 
68 static void
combine_mask_value_ca(uint32_t * src,const uint32_t * mask)69 combine_mask_value_ca (uint32_t *src, const uint32_t *mask)
70 {
71     uint32_t a = *mask;
72     uint32_t x;
73 
74     if (!a)
75     {
76 	*(src) = 0;
77 	return;
78     }
79 
80     if (a == ~0)
81 	return;
82 
83     x = *(src);
84     UN8x4_MUL_UN8x4 (x, a);
85     *(src) = x;
86 }
87 
88 static void
combine_mask_alpha_ca(const uint32_t * src,uint32_t * mask)89 combine_mask_alpha_ca (const uint32_t *src, uint32_t *mask)
90 {
91     uint32_t a = *(mask);
92     uint32_t x;
93 
94     if (!a)
95 	return;
96 
97     x = *(src) >> A_SHIFT;
98     if (x == MASK)
99 	return;
100 
101     if (a == ~0)
102     {
103 	x |= x << G_SHIFT;
104 	x |= x << R_SHIFT;
105 	*(mask) = x;
106 	return;
107     }
108 
109     UN8x4_MUL_UN8 (a, x);
110     *(mask) = a;
111 }
112 
113 /*
114  * There are two ways of handling alpha -- either as a single unified value or
115  * a separate value for each component, hence each macro must have two
116  * versions.  The unified alpha version has a 'u' at the end of the name,
117  * the component version has a 'ca'.  Similarly, functions which deal with
118  * this difference will have two versions using the same convention.
119  */
120 
121 static force_inline uint32_t
combine_mask(const uint32_t * src,const uint32_t * mask,int i)122 combine_mask (const uint32_t *src, const uint32_t *mask, int i)
123 {
124     uint32_t s, m;
125 
126     if (mask)
127     {
128 	m = *(mask + i) >> A_SHIFT;
129 
130 	if (!m)
131 	    return 0;
132     }
133 
134     s = *(src + i);
135 
136     if (mask)
137 	UN8x4_MUL_UN8 (s, m);
138 
139     return s;
140 }
141 
142 static void
combine_clear(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)143 combine_clear (pixman_implementation_t *imp,
144                pixman_op_t              op,
145                uint32_t *               dest,
146                const uint32_t *         src,
147                const uint32_t *         mask,
148                int                      width)
149 {
150     memset (dest, 0, width * sizeof (uint32_t));
151 }
152 
153 static void
combine_dst(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)154 combine_dst (pixman_implementation_t *imp,
155 	     pixman_op_t	      op,
156 	     uint32_t *		      dest,
157 	     const uint32_t *	      src,
158 	     const uint32_t *         mask,
159 	     int		      width)
160 {
161     return;
162 }
163 
164 static void
combine_src_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)165 combine_src_u (pixman_implementation_t *imp,
166                pixman_op_t              op,
167                uint32_t *               dest,
168                const uint32_t *         src,
169                const uint32_t *         mask,
170                int                      width)
171 {
172     int i;
173 
174     if (!mask)
175     {
176 	memcpy (dest, src, width * sizeof (uint32_t));
177     }
178     else
179     {
180 	for (i = 0; i < width; ++i)
181 	{
182 	    uint32_t s = combine_mask (src, mask, i);
183 
184 	    *(dest + i) = s;
185 	}
186     }
187 }
188 
189 static void
combine_over_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)190 combine_over_u (pixman_implementation_t *imp,
191                 pixman_op_t              op,
192                 uint32_t *               dest,
193                 const uint32_t *         src,
194                 const uint32_t *         mask,
195                 int                      width)
196 {
197     int i;
198 
199     if (!mask)
200     {
201 	for (i = 0; i < width; ++i)
202 	{
203 	    uint32_t s = *(src + i);
204 	    uint32_t a = ALPHA_8 (s);
205 	    if (a == 0xFF)
206 	    {
207 		*(dest + i) = s;
208 	    }
209 	    else if (s)
210 	    {
211 		uint32_t d = *(dest + i);
212 		uint32_t ia = a ^ 0xFF;
213 		UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s);
214 		*(dest + i) = d;
215 	    }
216 	}
217     }
218     else
219     {
220 	for (i = 0; i < width; ++i)
221 	{
222 	    uint32_t m = ALPHA_8 (*(mask + i));
223 	    if (m == 0xFF)
224 	    {
225 		uint32_t s = *(src + i);
226 		uint32_t a = ALPHA_8 (s);
227 		if (a == 0xFF)
228 		{
229 		    *(dest + i) = s;
230 		}
231 		else if (s)
232 		{
233 		    uint32_t d = *(dest + i);
234 		    uint32_t ia = a ^ 0xFF;
235 		    UN8x4_MUL_UN8_ADD_UN8x4 (d, ia, s);
236 		    *(dest + i) = d;
237 		}
238 	    }
239 	    else if (m)
240 	    {
241 		uint32_t s = *(src + i);
242 		if (s)
243 		{
244 		    uint32_t d = *(dest + i);
245 		    UN8x4_MUL_UN8 (s, m);
246 		    UN8x4_MUL_UN8_ADD_UN8x4 (d, ALPHA_8 (~s), s);
247 		    *(dest + i) = d;
248 		}
249 	    }
250 	}
251     }
252 }
253 
254 static void
combine_over_reverse_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)255 combine_over_reverse_u (pixman_implementation_t *imp,
256                         pixman_op_t              op,
257                         uint32_t *               dest,
258                         const uint32_t *         src,
259                         const uint32_t *         mask,
260                         int                      width)
261 {
262     int i;
263 
264     for (i = 0; i < width; ++i)
265     {
266 	uint32_t s = combine_mask (src, mask, i);
267 	uint32_t d = *(dest + i);
268 	uint32_t ia = ALPHA_8 (~*(dest + i));
269 	UN8x4_MUL_UN8_ADD_UN8x4 (s, ia, d);
270 	*(dest + i) = s;
271     }
272 }
273 
274 static void
combine_in_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)275 combine_in_u (pixman_implementation_t *imp,
276               pixman_op_t              op,
277               uint32_t *               dest,
278               const uint32_t *         src,
279               const uint32_t *         mask,
280               int                      width)
281 {
282     int i;
283 
284     for (i = 0; i < width; ++i)
285     {
286 	uint32_t s = combine_mask (src, mask, i);
287 	uint32_t a = ALPHA_8 (*(dest + i));
288 	UN8x4_MUL_UN8 (s, a);
289 	*(dest + i) = s;
290     }
291 }
292 
293 static void
combine_in_reverse_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)294 combine_in_reverse_u (pixman_implementation_t *imp,
295                       pixman_op_t              op,
296                       uint32_t *               dest,
297                       const uint32_t *         src,
298                       const uint32_t *         mask,
299                       int                      width)
300 {
301     int i;
302 
303     for (i = 0; i < width; ++i)
304     {
305 	uint32_t s = combine_mask (src, mask, i);
306 	uint32_t d = *(dest + i);
307 	uint32_t a = ALPHA_8 (s);
308 	UN8x4_MUL_UN8 (d, a);
309 	*(dest + i) = d;
310     }
311 }
312 
313 static void
combine_out_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)314 combine_out_u (pixman_implementation_t *imp,
315                pixman_op_t              op,
316                uint32_t *               dest,
317                const uint32_t *         src,
318                const uint32_t *         mask,
319                int                      width)
320 {
321     int i;
322 
323     for (i = 0; i < width; ++i)
324     {
325 	uint32_t s = combine_mask (src, mask, i);
326 	uint32_t a = ALPHA_8 (~*(dest + i));
327 	UN8x4_MUL_UN8 (s, a);
328 	*(dest + i) = s;
329     }
330 }
331 
332 static void
combine_out_reverse_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)333 combine_out_reverse_u (pixman_implementation_t *imp,
334                        pixman_op_t              op,
335                        uint32_t *               dest,
336                        const uint32_t *         src,
337                        const uint32_t *         mask,
338                        int                      width)
339 {
340     int i;
341 
342     for (i = 0; i < width; ++i)
343     {
344 	uint32_t s = combine_mask (src, mask, i);
345 	uint32_t d = *(dest + i);
346 	uint32_t a = ALPHA_8 (~s);
347 	UN8x4_MUL_UN8 (d, a);
348 	*(dest + i) = d;
349     }
350 }
351 
352 static void
combine_atop_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)353 combine_atop_u (pixman_implementation_t *imp,
354                 pixman_op_t              op,
355                 uint32_t *               dest,
356                 const uint32_t *         src,
357                 const uint32_t *         mask,
358                 int                      width)
359 {
360     int i;
361 
362     for (i = 0; i < width; ++i)
363     {
364 	uint32_t s = combine_mask (src, mask, i);
365 	uint32_t d = *(dest + i);
366 	uint32_t dest_a = ALPHA_8 (d);
367 	uint32_t src_ia = ALPHA_8 (~s);
368 
369 	UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_a, d, src_ia);
370 	*(dest + i) = s;
371     }
372 }
373 
374 static void
combine_atop_reverse_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)375 combine_atop_reverse_u (pixman_implementation_t *imp,
376                         pixman_op_t              op,
377                         uint32_t *               dest,
378                         const uint32_t *         src,
379                         const uint32_t *         mask,
380                         int                      width)
381 {
382     int i;
383 
384     for (i = 0; i < width; ++i)
385     {
386 	uint32_t s = combine_mask (src, mask, i);
387 	uint32_t d = *(dest + i);
388 	uint32_t src_a = ALPHA_8 (s);
389 	uint32_t dest_ia = ALPHA_8 (~d);
390 
391 	UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_a);
392 	*(dest + i) = s;
393     }
394 }
395 
396 static void
combine_xor_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)397 combine_xor_u (pixman_implementation_t *imp,
398                pixman_op_t              op,
399                uint32_t *               dest,
400                const uint32_t *         src,
401                const uint32_t *         mask,
402                int                      width)
403 {
404     int i;
405 
406     for (i = 0; i < width; ++i)
407     {
408 	uint32_t s = combine_mask (src, mask, i);
409 	uint32_t d = *(dest + i);
410 	uint32_t src_ia = ALPHA_8 (~s);
411 	uint32_t dest_ia = ALPHA_8 (~d);
412 
413 	UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (s, dest_ia, d, src_ia);
414 	*(dest + i) = s;
415     }
416 }
417 
418 static void
combine_add_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)419 combine_add_u (pixman_implementation_t *imp,
420                pixman_op_t              op,
421                uint32_t *               dest,
422                const uint32_t *         src,
423                const uint32_t *         mask,
424                int                      width)
425 {
426     int i;
427 
428     for (i = 0; i < width; ++i)
429     {
430 	uint32_t s = combine_mask (src, mask, i);
431 	uint32_t d = *(dest + i);
432 	UN8x4_ADD_UN8x4 (d, s);
433 	*(dest + i) = d;
434     }
435 }
436 
437 /*
438  * PDF blend modes:
439  *
440  * The following blend modes have been taken from the PDF ISO 32000
441  * specification, which at this point in time is available from
442  *
443  *     http://www.adobe.com/devnet/pdf/pdf_reference.html
444  *
445  * The specific documents of interest are the PDF spec itself:
446  *
447  *     http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf
448  *
449  * chapters 11.3.5 and 11.3.6 and a later supplement for Adobe Acrobat
450  * 9.1 and Reader 9.1:
451  *
452  *     http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/adobe_supplement_iso32000_1.pdf
453  *
454  * that clarifies the specifications for blend modes ColorDodge and
455  * ColorBurn.
456  *
457  * The formula for computing the final pixel color given in 11.3.6 is:
458  *
459  *     αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs)
460  *
461  * with B() is the blend function. When B(Cb, Cs) = Cs, this formula
462  * reduces to the regular OVER operator.
463  *
464  * Cs and Cb are not premultiplied, so in our implementation we instead
465  * use:
466  *
467  *     cr = (1 – αs) × cb  +  (1 – αb) × cs  +  αb × αs × B (cb/αb, cs/αs)
468  *
469  * where cr, cs, and cb are premultiplied colors, and where the
470  *
471  *     αb × αs × B(cb/αb, cs/αs)
472  *
473  * part is first arithmetically simplified under the assumption that αb
474  * and αs are not 0, and then updated to produce a meaningful result when
475  * they are.
476  *
477  * For all the blend mode operators, the alpha channel is given by
478  *
479  *     αr = αs + αb + αb × αs
480  */
481 
482 /*
483  * Multiply
484  *
485  *      ad * as * B(d / ad, s / as)
486  *    = ad * as * d/ad * s/as
487  *    = d * s
488  *
489  */
490 static void
combine_multiply_u(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)491 combine_multiply_u (pixman_implementation_t *imp,
492                     pixman_op_t              op,
493                     uint32_t *               dest,
494                     const uint32_t *         src,
495                     const uint32_t *         mask,
496                     int                      width)
497 {
498     int i;
499 
500     for (i = 0; i < width; ++i)
501     {
502 	uint32_t s = combine_mask (src, mask, i);
503 	uint32_t d = *(dest + i);
504 	uint32_t ss = s;
505 	uint32_t src_ia = ALPHA_8 (~s);
506 	uint32_t dest_ia = ALPHA_8 (~d);
507 
508 	UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8 (ss, dest_ia, d, src_ia);
509 	UN8x4_MUL_UN8x4 (d, s);
510 	UN8x4_ADD_UN8x4 (d, ss);
511 
512 	*(dest + i) = d;
513     }
514 }
515 
516 static void
combine_multiply_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)517 combine_multiply_ca (pixman_implementation_t *imp,
518                      pixman_op_t              op,
519                      uint32_t *               dest,
520                      const uint32_t *         src,
521                      const uint32_t *         mask,
522                      int                      width)
523 {
524     int i;
525 
526     for (i = 0; i < width; ++i)
527     {
528 	uint32_t m = *(mask + i);
529 	uint32_t s = *(src + i);
530 	uint32_t d = *(dest + i);
531 	uint32_t r = d;
532 	uint32_t dest_ia = ALPHA_8 (~d);
533 
534 	combine_mask_ca (&s, &m);
535 
536 	UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (r, ~m, s, dest_ia);
537 	UN8x4_MUL_UN8x4 (d, s);
538 	UN8x4_ADD_UN8x4 (r, d);
539 
540 	*(dest + i) = r;
541     }
542 }
543 
544 #define CLAMP(v, low, high)						\
545     do									\
546     {									\
547 	if (v < (low))							\
548 	    v = (low);							\
549 	if (v > (high))							\
550 	    v = (high);							\
551     } while (0)
552 
553 #define PDF_SEPARABLE_BLEND_MODE(name)					\
554     static void								\
555     combine_ ## name ## _u (pixman_implementation_t *imp,		\
556 			    pixman_op_t              op,		\
557                             uint32_t *               dest,		\
558 			    const uint32_t *         src,		\
559 			    const uint32_t *         mask,		\
560 			    int                      width)		\
561     {									\
562 	int i;								\
563 	for (i = 0; i < width; ++i)					\
564 	{								\
565 	    uint32_t s = combine_mask (src, mask, i);			\
566 	    uint32_t d = *(dest + i);					\
567 	    uint8_t sa = ALPHA_8 (s);					\
568 	    uint8_t isa = ~sa;						\
569 	    uint8_t da = ALPHA_8 (d);					\
570 	    uint8_t ida = ~da;						\
571 	    uint32_t ra, rr, rg, rb;					\
572 	    								\
573 	    ra = da * 0xff + sa * 0xff - sa * da;			\
574 	    rr = isa * RED_8 (d) + ida * RED_8 (s);			\
575 	    rg = isa * GREEN_8 (d) + ida * GREEN_8 (s);			\
576 	    rb = isa * BLUE_8 (d) + ida * BLUE_8 (s);			\
577 									\
578 	    rr += blend_ ## name (RED_8 (d), da, RED_8 (s), sa);	\
579 	    rg += blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), sa);    \
580 	    rb += blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), sa);	\
581                                                                         \
582 	    CLAMP (ra, 0, 255 * 255);				        \
583 	    CLAMP (rr, 0, 255 * 255);				        \
584 	    CLAMP (rg, 0, 255 * 255);				        \
585 	    CLAMP (rb, 0, 255 * 255);				        \
586 									\
587 	    ra = DIV_ONE_UN8 (ra);					\
588 	    rr = DIV_ONE_UN8 (rr);					\
589 	    rg = DIV_ONE_UN8 (rg);					\
590 	    rb = DIV_ONE_UN8 (rb);					\
591 									\
592 	    *(dest + i) = ra << 24 | rr << 16 | rg << 8 | rb;		\
593 	}								\
594     }									\
595     									\
596     static void								\
597     combine_ ## name ## _ca (pixman_implementation_t *imp,		\
598 			     pixman_op_t              op,		\
599                              uint32_t *               dest,		\
600 			     const uint32_t *         src,		\
601 			     const uint32_t *         mask,		\
602 			     int                      width)		\
603     {									\
604 	int i;								\
605 	for (i = 0; i < width; ++i)					\
606 	{								\
607 	    uint32_t m = *(mask + i);					\
608 	    uint32_t s = *(src + i);					\
609 	    uint32_t d = *(dest + i);					\
610 	    uint8_t da = ALPHA_8 (d);					\
611 	    uint8_t ida = ~da;						\
612 	    uint32_t ra, rr, rg, rb;					\
613 	    uint8_t ira, iga, iba;					\
614 	    								\
615 	    combine_mask_ca (&s, &m);					\
616 	    								\
617 	    ira = ~RED_8 (m);						\
618 	    iga = ~GREEN_8 (m);						\
619 	    iba = ~BLUE_8 (m);						\
620 									\
621 	    ra = da * 0xff + ALPHA_8 (s) * 0xff - ALPHA_8 (s) * da;	\
622 	    rr = ira * RED_8 (d) + ida * RED_8 (s);			\
623 	    rg = iga * GREEN_8 (d) + ida * GREEN_8 (s);			\
624 	    rb = iba * BLUE_8 (d) + ida * BLUE_8 (s);			\
625 									\
626 	    rr += blend_ ## name (RED_8 (d), da, RED_8 (s), RED_8 (m));	\
627 	    rg += blend_ ## name (GREEN_8 (d), da, GREEN_8 (s), GREEN_8 (m)); \
628 	    rb += blend_ ## name (BLUE_8 (d), da, BLUE_8 (s), BLUE_8 (m)); \
629 									\
630 	    CLAMP (ra, 0, 255 * 255);				        \
631 	    CLAMP (rr, 0, 255 * 255);				        \
632 	    CLAMP (rg, 0, 255 * 255);				        \
633 	    CLAMP (rb, 0, 255 * 255);				        \
634 									\
635 	    ra = DIV_ONE_UN8 (ra);					\
636 	    rr = DIV_ONE_UN8 (rr);					\
637 	    rg = DIV_ONE_UN8 (rg);					\
638 	    rb = DIV_ONE_UN8 (rb);					\
639 									\
640 	    *(dest + i) = ra << 24 | rr << 16 | rg << 8 | rb;		\
641 	}								\
642     }
643 
644 /*
645  * Screen
646  *
647  *      ad * as * B(d/ad, s/as)
648  *    = ad * as * (d/ad + s/as - s/as * d/ad)
649  *    = ad * s + as * d - s * d
650  */
651 static inline int32_t
blend_screen(int32_t d,int32_t ad,int32_t s,int32_t as)652 blend_screen (int32_t d, int32_t ad, int32_t s, int32_t as)
653 {
654     return s * ad + d * as - s * d;
655 }
656 
PDF_SEPARABLE_BLEND_MODE(screen)657 PDF_SEPARABLE_BLEND_MODE (screen)
658 
659 /*
660  * Overlay
661  *
662  *     ad * as * B(d/ad, s/as)
663  *   = ad * as * Hardlight (s, d)
664  *   = if (d / ad < 0.5)
665  *         as * ad * Multiply (s/as, 2 * d/ad)
666  *     else
667  *         as * ad * Screen (s/as, 2 * d / ad - 1)
668  *   = if (d < 0.5 * ad)
669  *         as * ad * s/as * 2 * d /ad
670  *     else
671  *         as * ad * (s/as + 2 * d / ad - 1 - s / as * (2 * d / ad - 1))
672  *   = if (2 * d < ad)
673  *         2 * s * d
674  *     else
675  *         ad * s + 2 * as * d - as * ad - ad * s * (2 * d / ad - 1)
676  *   = if (2 * d < ad)
677  *         2 * s * d
678  *     else
679  *         as * ad - 2 * (ad - d) * (as - s)
680  */
681 static inline int32_t
682 blend_overlay (int32_t d, int32_t ad, int32_t s, int32_t as)
683 {
684     uint32_t r;
685 
686     if (2 * d < ad)
687 	r = 2 * s * d;
688     else
689 	r = as * ad - 2 * (ad - d) * (as - s);
690 
691     return r;
692 }
693 
PDF_SEPARABLE_BLEND_MODE(overlay)694 PDF_SEPARABLE_BLEND_MODE (overlay)
695 
696 /*
697  * Darken
698  *
699  *     ad * as * B(d/ad, s/as)
700  *   = ad * as * MIN(d/ad, s/as)
701  *   = MIN (as * d, ad * s)
702  */
703 static inline int32_t
704 blend_darken (int32_t d, int32_t ad, int32_t s, int32_t as)
705 {
706     s = ad * s;
707     d = as * d;
708 
709     return s > d ? d : s;
710 }
711 
PDF_SEPARABLE_BLEND_MODE(darken)712 PDF_SEPARABLE_BLEND_MODE (darken)
713 
714 /*
715  * Lighten
716  *
717  *     ad * as * B(d/ad, s/as)
718  *   = ad * as * MAX(d/ad, s/as)
719  *   = MAX (as * d, ad * s)
720  */
721 static inline int32_t
722 blend_lighten (int32_t d, int32_t ad, int32_t s, int32_t as)
723 {
724     s = ad * s;
725     d = as * d;
726 
727     return s > d ? s : d;
728 }
729 
PDF_SEPARABLE_BLEND_MODE(lighten)730 PDF_SEPARABLE_BLEND_MODE (lighten)
731 
732 /*
733  * Hard light
734  *
735  *     ad * as * B(d/ad, s/as)
736  *   = if (s/as <= 0.5)
737  *         ad * as * Multiply (d/ad, 2 * s/as)
738  *     else
739  *         ad * as * Screen (d/ad, 2 * s/as - 1)
740  *   = if 2 * s <= as
741  *         ad * as * d/ad * 2 * s / as
742  *     else
743  *         ad * as * (d/ad + (2 * s/as - 1) + d/ad * (2 * s/as - 1))
744  *   = if 2 * s <= as
745  *         2 * s * d
746  *     else
747  *         as * ad - 2 * (ad - d) * (as - s)
748  */
749 static inline int32_t
750 blend_hard_light (int32_t d, int32_t ad, int32_t s, int32_t as)
751 {
752     if (2 * s < as)
753 	return 2 * s * d;
754     else
755 	return as * ad - 2 * (ad - d) * (as - s);
756 }
757 
PDF_SEPARABLE_BLEND_MODE(hard_light)758 PDF_SEPARABLE_BLEND_MODE (hard_light)
759 
760 /*
761  * Difference
762  *
763  *     ad * as * B(s/as, d/ad)
764  *   = ad * as * abs (s/as - d/ad)
765  *   = if (s/as <= d/ad)
766  *         ad * as * (d/ad - s/as)
767  *     else
768  *         ad * as * (s/as - d/ad)
769  *   = if (ad * s <= as * d)
770  *        as * d - ad * s
771  *     else
772  *        ad * s - as * d
773  */
774 static inline int32_t
775 blend_difference (int32_t d, int32_t ad, int32_t s, int32_t as)
776 {
777     int32_t das = d * as;
778     int32_t sad = s * ad;
779 
780     if (sad < das)
781 	return das - sad;
782     else
783 	return sad - das;
784 }
785 
PDF_SEPARABLE_BLEND_MODE(difference)786 PDF_SEPARABLE_BLEND_MODE (difference)
787 
788 /*
789  * Exclusion
790  *
791  *     ad * as * B(s/as, d/ad)
792  *   = ad * as * (d/ad + s/as - 2 * d/ad * s/as)
793  *   = as * d + ad * s - 2 * s * d
794  */
795 
796 /* This can be made faster by writing it directly and not using
797  * PDF_SEPARABLE_BLEND_MODE, but that's a performance optimization */
798 
799 static inline int32_t
800 blend_exclusion (int32_t d, int32_t ad, int32_t s, int32_t as)
801 {
802     return s * ad + d * as - 2 * d * s;
803 }
804 
PDF_SEPARABLE_BLEND_MODE(exclusion)805 PDF_SEPARABLE_BLEND_MODE (exclusion)
806 
807 #undef PDF_SEPARABLE_BLEND_MODE
808 
809 /* Component alpha combiners */
810 
811 static void
812 combine_clear_ca (pixman_implementation_t *imp,
813                   pixman_op_t              op,
814                   uint32_t *                dest,
815                   const uint32_t *          src,
816                   const uint32_t *          mask,
817                   int                      width)
818 {
819     memset (dest, 0, width * sizeof(uint32_t));
820 }
821 
822 static void
combine_src_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)823 combine_src_ca (pixman_implementation_t *imp,
824                 pixman_op_t              op,
825                 uint32_t *                dest,
826                 const uint32_t *          src,
827                 const uint32_t *          mask,
828                 int                      width)
829 {
830     int i;
831 
832     for (i = 0; i < width; ++i)
833     {
834 	uint32_t s = *(src + i);
835 	uint32_t m = *(mask + i);
836 
837 	combine_mask_value_ca (&s, &m);
838 
839 	*(dest + i) = s;
840     }
841 }
842 
843 static void
combine_over_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)844 combine_over_ca (pixman_implementation_t *imp,
845                  pixman_op_t              op,
846                  uint32_t *                dest,
847                  const uint32_t *          src,
848                  const uint32_t *          mask,
849                  int                      width)
850 {
851     int i;
852 
853     for (i = 0; i < width; ++i)
854     {
855 	uint32_t s = *(src + i);
856 	uint32_t m = *(mask + i);
857 	uint32_t a;
858 
859 	combine_mask_ca (&s, &m);
860 
861 	a = ~m;
862 	if (a)
863 	{
864 	    uint32_t d = *(dest + i);
865 	    UN8x4_MUL_UN8x4_ADD_UN8x4 (d, a, s);
866 	    s = d;
867 	}
868 
869 	*(dest + i) = s;
870     }
871 }
872 
873 static void
combine_over_reverse_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)874 combine_over_reverse_ca (pixman_implementation_t *imp,
875                          pixman_op_t              op,
876                          uint32_t *                dest,
877                          const uint32_t *          src,
878                          const uint32_t *          mask,
879                          int                      width)
880 {
881     int i;
882 
883     for (i = 0; i < width; ++i)
884     {
885 	uint32_t d = *(dest + i);
886 	uint32_t a = ~d >> A_SHIFT;
887 
888 	if (a)
889 	{
890 	    uint32_t s = *(src + i);
891 	    uint32_t m = *(mask + i);
892 
893 	    UN8x4_MUL_UN8x4 (s, m);
894 	    UN8x4_MUL_UN8_ADD_UN8x4 (s, a, d);
895 
896 	    *(dest + i) = s;
897 	}
898     }
899 }
900 
901 static void
combine_in_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)902 combine_in_ca (pixman_implementation_t *imp,
903                pixman_op_t              op,
904                uint32_t *                dest,
905                const uint32_t *          src,
906                const uint32_t *          mask,
907                int                      width)
908 {
909     int i;
910 
911     for (i = 0; i < width; ++i)
912     {
913 	uint32_t d = *(dest + i);
914 	uint16_t a = d >> A_SHIFT;
915 	uint32_t s = 0;
916 
917 	if (a)
918 	{
919 	    uint32_t m = *(mask + i);
920 
921 	    s = *(src + i);
922 	    combine_mask_value_ca (&s, &m);
923 
924 	    if (a != MASK)
925 		UN8x4_MUL_UN8 (s, a);
926 	}
927 
928 	*(dest + i) = s;
929     }
930 }
931 
932 static void
combine_in_reverse_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)933 combine_in_reverse_ca (pixman_implementation_t *imp,
934                        pixman_op_t              op,
935                        uint32_t *                dest,
936                        const uint32_t *          src,
937                        const uint32_t *          mask,
938                        int                      width)
939 {
940     int i;
941 
942     for (i = 0; i < width; ++i)
943     {
944 	uint32_t s = *(src + i);
945 	uint32_t m = *(mask + i);
946 	uint32_t a;
947 
948 	combine_mask_alpha_ca (&s, &m);
949 
950 	a = m;
951 	if (a != ~0)
952 	{
953 	    uint32_t d = 0;
954 
955 	    if (a)
956 	    {
957 		d = *(dest + i);
958 		UN8x4_MUL_UN8x4 (d, a);
959 	    }
960 
961 	    *(dest + i) = d;
962 	}
963     }
964 }
965 
966 static void
combine_out_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)967 combine_out_ca (pixman_implementation_t *imp,
968                 pixman_op_t              op,
969                 uint32_t *                dest,
970                 const uint32_t *          src,
971                 const uint32_t *          mask,
972                 int                      width)
973 {
974     int i;
975 
976     for (i = 0; i < width; ++i)
977     {
978 	uint32_t d = *(dest + i);
979 	uint16_t a = ~d >> A_SHIFT;
980 	uint32_t s = 0;
981 
982 	if (a)
983 	{
984 	    uint32_t m = *(mask + i);
985 
986 	    s = *(src + i);
987 	    combine_mask_value_ca (&s, &m);
988 
989 	    if (a != MASK)
990 		UN8x4_MUL_UN8 (s, a);
991 	}
992 
993 	*(dest + i) = s;
994     }
995 }
996 
997 static void
combine_out_reverse_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)998 combine_out_reverse_ca (pixman_implementation_t *imp,
999                         pixman_op_t              op,
1000                         uint32_t *                dest,
1001                         const uint32_t *          src,
1002                         const uint32_t *          mask,
1003                         int                      width)
1004 {
1005     int i;
1006 
1007     for (i = 0; i < width; ++i)
1008     {
1009 	uint32_t s = *(src + i);
1010 	uint32_t m = *(mask + i);
1011 	uint32_t a;
1012 
1013 	combine_mask_alpha_ca (&s, &m);
1014 
1015 	a = ~m;
1016 	if (a != ~0)
1017 	{
1018 	    uint32_t d = 0;
1019 
1020 	    if (a)
1021 	    {
1022 		d = *(dest + i);
1023 		UN8x4_MUL_UN8x4 (d, a);
1024 	    }
1025 
1026 	    *(dest + i) = d;
1027 	}
1028     }
1029 }
1030 
1031 static void
combine_atop_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)1032 combine_atop_ca (pixman_implementation_t *imp,
1033                  pixman_op_t              op,
1034                  uint32_t *                dest,
1035                  const uint32_t *          src,
1036                  const uint32_t *          mask,
1037                  int                      width)
1038 {
1039     int i;
1040 
1041     for (i = 0; i < width; ++i)
1042     {
1043 	uint32_t d = *(dest + i);
1044 	uint32_t s = *(src + i);
1045 	uint32_t m = *(mask + i);
1046 	uint32_t ad;
1047 	uint16_t as = d >> A_SHIFT;
1048 
1049 	combine_mask_ca (&s, &m);
1050 
1051 	ad = ~m;
1052 
1053 	UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ad, s, as);
1054 
1055 	*(dest + i) = d;
1056     }
1057 }
1058 
1059 static void
combine_atop_reverse_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)1060 combine_atop_reverse_ca (pixman_implementation_t *imp,
1061                          pixman_op_t              op,
1062                          uint32_t *                dest,
1063                          const uint32_t *          src,
1064                          const uint32_t *          mask,
1065                          int                      width)
1066 {
1067     int i;
1068 
1069     for (i = 0; i < width; ++i)
1070     {
1071 	uint32_t d = *(dest + i);
1072 	uint32_t s = *(src + i);
1073 	uint32_t m = *(mask + i);
1074 	uint32_t ad;
1075 	uint16_t as = ~d >> A_SHIFT;
1076 
1077 	combine_mask_ca (&s, &m);
1078 
1079 	ad = m;
1080 
1081 	UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ad, s, as);
1082 
1083 	*(dest + i) = d;
1084     }
1085 }
1086 
1087 static void
combine_xor_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)1088 combine_xor_ca (pixman_implementation_t *imp,
1089                 pixman_op_t              op,
1090                 uint32_t *                dest,
1091                 const uint32_t *          src,
1092                 const uint32_t *          mask,
1093                 int                      width)
1094 {
1095     int i;
1096 
1097     for (i = 0; i < width; ++i)
1098     {
1099 	uint32_t d = *(dest + i);
1100 	uint32_t s = *(src + i);
1101 	uint32_t m = *(mask + i);
1102 	uint32_t ad;
1103 	uint16_t as = ~d >> A_SHIFT;
1104 
1105 	combine_mask_ca (&s, &m);
1106 
1107 	ad = ~m;
1108 
1109 	UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8 (d, ad, s, as);
1110 
1111 	*(dest + i) = d;
1112     }
1113 }
1114 
1115 static void
combine_add_ca(pixman_implementation_t * imp,pixman_op_t op,uint32_t * dest,const uint32_t * src,const uint32_t * mask,int width)1116 combine_add_ca (pixman_implementation_t *imp,
1117                 pixman_op_t              op,
1118                 uint32_t *                dest,
1119                 const uint32_t *          src,
1120                 const uint32_t *          mask,
1121                 int                      width)
1122 {
1123     int i;
1124 
1125     for (i = 0; i < width; ++i)
1126     {
1127 	uint32_t s = *(src + i);
1128 	uint32_t m = *(mask + i);
1129 	uint32_t d = *(dest + i);
1130 
1131 	combine_mask_value_ca (&s, &m);
1132 
1133 	UN8x4_ADD_UN8x4 (d, s);
1134 
1135 	*(dest + i) = d;
1136     }
1137 }
1138 
1139 void
_pixman_setup_combiner_functions_32(pixman_implementation_t * imp)1140 _pixman_setup_combiner_functions_32 (pixman_implementation_t *imp)
1141 {
1142     /* Unified alpha */
1143     imp->combine_32[PIXMAN_OP_CLEAR] = combine_clear;
1144     imp->combine_32[PIXMAN_OP_SRC] = combine_src_u;
1145     imp->combine_32[PIXMAN_OP_DST] = combine_dst;
1146     imp->combine_32[PIXMAN_OP_OVER] = combine_over_u;
1147     imp->combine_32[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_u;
1148     imp->combine_32[PIXMAN_OP_IN] = combine_in_u;
1149     imp->combine_32[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_u;
1150     imp->combine_32[PIXMAN_OP_OUT] = combine_out_u;
1151     imp->combine_32[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_u;
1152     imp->combine_32[PIXMAN_OP_ATOP] = combine_atop_u;
1153     imp->combine_32[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_u;
1154     imp->combine_32[PIXMAN_OP_XOR] = combine_xor_u;
1155     imp->combine_32[PIXMAN_OP_ADD] = combine_add_u;
1156 
1157     imp->combine_32[PIXMAN_OP_MULTIPLY] = combine_multiply_u;
1158     imp->combine_32[PIXMAN_OP_SCREEN] = combine_screen_u;
1159     imp->combine_32[PIXMAN_OP_OVERLAY] = combine_overlay_u;
1160     imp->combine_32[PIXMAN_OP_DARKEN] = combine_darken_u;
1161     imp->combine_32[PIXMAN_OP_LIGHTEN] = combine_lighten_u;
1162     imp->combine_32[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_u;
1163     imp->combine_32[PIXMAN_OP_DIFFERENCE] = combine_difference_u;
1164     imp->combine_32[PIXMAN_OP_EXCLUSION] = combine_exclusion_u;
1165 
1166     /* Component alpha combiners */
1167     imp->combine_32_ca[PIXMAN_OP_CLEAR] = combine_clear_ca;
1168     imp->combine_32_ca[PIXMAN_OP_SRC] = combine_src_ca;
1169     /* dest */
1170     imp->combine_32_ca[PIXMAN_OP_OVER] = combine_over_ca;
1171     imp->combine_32_ca[PIXMAN_OP_OVER_REVERSE] = combine_over_reverse_ca;
1172     imp->combine_32_ca[PIXMAN_OP_IN] = combine_in_ca;
1173     imp->combine_32_ca[PIXMAN_OP_IN_REVERSE] = combine_in_reverse_ca;
1174     imp->combine_32_ca[PIXMAN_OP_OUT] = combine_out_ca;
1175     imp->combine_32_ca[PIXMAN_OP_OUT_REVERSE] = combine_out_reverse_ca;
1176     imp->combine_32_ca[PIXMAN_OP_ATOP] = combine_atop_ca;
1177     imp->combine_32_ca[PIXMAN_OP_ATOP_REVERSE] = combine_atop_reverse_ca;
1178     imp->combine_32_ca[PIXMAN_OP_XOR] = combine_xor_ca;
1179     imp->combine_32_ca[PIXMAN_OP_ADD] = combine_add_ca;
1180 
1181     imp->combine_32_ca[PIXMAN_OP_MULTIPLY] = combine_multiply_ca;
1182     imp->combine_32_ca[PIXMAN_OP_SCREEN] = combine_screen_ca;
1183     imp->combine_32_ca[PIXMAN_OP_OVERLAY] = combine_overlay_ca;
1184     imp->combine_32_ca[PIXMAN_OP_DARKEN] = combine_darken_ca;
1185     imp->combine_32_ca[PIXMAN_OP_LIGHTEN] = combine_lighten_ca;
1186     imp->combine_32_ca[PIXMAN_OP_HARD_LIGHT] = combine_hard_light_ca;
1187     imp->combine_32_ca[PIXMAN_OP_DIFFERENCE] = combine_difference_ca;
1188     imp->combine_32_ca[PIXMAN_OP_EXCLUSION] = combine_exclusion_ca;
1189 }
1190