• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
3  * Copyright © 2004 Keith Packard
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  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include "pixman-private.h"
31 
32 /*
33  * Compute the smallest value greater than or equal to y which is on a
34  * grid row.
35  */
36 
37 PIXMAN_EXPORT pixman_fixed_t
pixman_sample_ceil_y(pixman_fixed_t y,int n)38 pixman_sample_ceil_y (pixman_fixed_t y, int n)
39 {
40     pixman_fixed_t f = pixman_fixed_frac (y);
41     pixman_fixed_t i = pixman_fixed_floor (y);
42 
43     f = DIV (f - Y_FRAC_FIRST (n) + (STEP_Y_SMALL (n) - pixman_fixed_e), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
44 	Y_FRAC_FIRST (n);
45 
46     if (f > Y_FRAC_LAST (n))
47     {
48 	if (pixman_fixed_to_int (i) == 0x7fff)
49 	{
50 	    f = 0xffff; /* saturate */
51 	}
52 	else
53 	{
54 	    f = Y_FRAC_FIRST (n);
55 	    i += pixman_fixed_1;
56 	}
57     }
58     return (i | f);
59 }
60 
61 /*
62  * Compute the largest value strictly less than y which is on a
63  * grid row.
64  */
65 PIXMAN_EXPORT pixman_fixed_t
pixman_sample_floor_y(pixman_fixed_t y,int n)66 pixman_sample_floor_y (pixman_fixed_t y,
67                        int            n)
68 {
69     pixman_fixed_t f = pixman_fixed_frac (y);
70     pixman_fixed_t i = pixman_fixed_floor (y);
71 
72     f = DIV (f - pixman_fixed_e - Y_FRAC_FIRST (n), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
73 	Y_FRAC_FIRST (n);
74 
75     if (f < Y_FRAC_FIRST (n))
76     {
77 	if (pixman_fixed_to_int (i) == 0x8000)
78 	{
79 	    f = 0; /* saturate */
80 	}
81 	else
82 	{
83 	    f = Y_FRAC_LAST (n);
84 	    i -= pixman_fixed_1;
85 	}
86     }
87     return (i | f);
88 }
89 
90 /*
91  * Step an edge by any amount (including negative values)
92  */
93 PIXMAN_EXPORT void
pixman_edge_step(pixman_edge_t * e,int n)94 pixman_edge_step (pixman_edge_t *e,
95                   int            n)
96 {
97     pixman_fixed_48_16_t ne;
98 
99     e->x += n * e->stepx;
100 
101     ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
102 
103     if (n >= 0)
104     {
105 	if (ne > 0)
106 	{
107 	    int nx = (ne + e->dy - 1) / e->dy;
108 	    e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
109 	    e->x += nx * e->signdx;
110 	}
111     }
112     else
113     {
114 	if (ne <= -e->dy)
115 	{
116 	    int nx = (-ne) / e->dy;
117 	    e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
118 	    e->x -= nx * e->signdx;
119 	}
120     }
121 }
122 
123 /*
124  * A private routine to initialize the multi-step
125  * elements of an edge structure
126  */
127 static void
_pixman_edge_multi_init(pixman_edge_t * e,int n,pixman_fixed_t * stepx_p,pixman_fixed_t * dx_p)128 _pixman_edge_multi_init (pixman_edge_t * e,
129                          int             n,
130                          pixman_fixed_t *stepx_p,
131                          pixman_fixed_t *dx_p)
132 {
133     pixman_fixed_t stepx;
134     pixman_fixed_48_16_t ne;
135 
136     ne = n * (pixman_fixed_48_16_t) e->dx;
137     stepx = n * e->stepx;
138 
139     if (ne > 0)
140     {
141 	int nx = ne / e->dy;
142 	ne -= nx * (pixman_fixed_48_16_t)e->dy;
143 	stepx += nx * e->signdx;
144     }
145 
146     *dx_p = ne;
147     *stepx_p = stepx;
148 }
149 
150 /*
151  * Initialize one edge structure given the line endpoints and a
152  * starting y value
153  */
154 PIXMAN_EXPORT void
pixman_edge_init(pixman_edge_t * e,int n,pixman_fixed_t y_start,pixman_fixed_t x_top,pixman_fixed_t y_top,pixman_fixed_t x_bot,pixman_fixed_t y_bot)155 pixman_edge_init (pixman_edge_t *e,
156                   int            n,
157                   pixman_fixed_t y_start,
158                   pixman_fixed_t x_top,
159                   pixman_fixed_t y_top,
160                   pixman_fixed_t x_bot,
161                   pixman_fixed_t y_bot)
162 {
163     pixman_fixed_t dx, dy;
164 
165     e->x = x_top;
166     e->e = 0;
167     dx = x_bot - x_top;
168     dy = y_bot - y_top;
169     e->dy = dy;
170     e->dx = 0;
171 
172     if (dy)
173     {
174 	if (dx >= 0)
175 	{
176 	    e->signdx = 1;
177 	    e->stepx = dx / dy;
178 	    e->dx = dx % dy;
179 	    e->e = -dy;
180 	}
181 	else
182 	{
183 	    e->signdx = -1;
184 	    e->stepx = -(-dx / dy);
185 	    e->dx = -dx % dy;
186 	    e->e = 0;
187 	}
188 
189 	_pixman_edge_multi_init (e, STEP_Y_SMALL (n),
190 				 &e->stepx_small, &e->dx_small);
191 
192 	_pixman_edge_multi_init (e, STEP_Y_BIG (n),
193 				 &e->stepx_big, &e->dx_big);
194     }
195     pixman_edge_step (e, y_start - y_top);
196 }
197 
198 /*
199  * Initialize one edge structure given a line, starting y value
200  * and a pixel offset for the line
201  */
202 PIXMAN_EXPORT void
pixman_line_fixed_edge_init(pixman_edge_t * e,int n,pixman_fixed_t y,const pixman_line_fixed_t * line,int x_off,int y_off)203 pixman_line_fixed_edge_init (pixman_edge_t *            e,
204                              int                        n,
205                              pixman_fixed_t             y,
206                              const pixman_line_fixed_t *line,
207                              int                        x_off,
208                              int                        y_off)
209 {
210     pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off);
211     pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off);
212     const pixman_point_fixed_t *top, *bot;
213 
214     if (line->p1.y <= line->p2.y)
215     {
216 	top = &line->p1;
217 	bot = &line->p2;
218     }
219     else
220     {
221 	top = &line->p2;
222 	bot = &line->p1;
223     }
224 
225     pixman_edge_init (e, n, y,
226                       top->x + x_off_fixed,
227                       top->y + y_off_fixed,
228                       bot->x + x_off_fixed,
229                       bot->y + y_off_fixed);
230 }
231 
232 PIXMAN_EXPORT void
pixman_add_traps(pixman_image_t * image,int16_t x_off,int16_t y_off,int ntrap,const pixman_trap_t * traps)233 pixman_add_traps (pixman_image_t *     image,
234                   int16_t              x_off,
235                   int16_t              y_off,
236                   int                  ntrap,
237                   const pixman_trap_t *traps)
238 {
239     int bpp;
240     int height;
241 
242     pixman_fixed_t x_off_fixed;
243     pixman_fixed_t y_off_fixed;
244     pixman_edge_t l, r;
245     pixman_fixed_t t, b;
246 
247     _pixman_image_validate (image);
248 
249     height = image->bits.height;
250     bpp = PIXMAN_FORMAT_BPP (image->bits.format);
251 
252     x_off_fixed = pixman_int_to_fixed (x_off);
253     y_off_fixed = pixman_int_to_fixed (y_off);
254 
255     while (ntrap--)
256     {
257 	t = traps->top.y + y_off_fixed;
258 	if (t < 0)
259 	    t = 0;
260 	t = pixman_sample_ceil_y (t, bpp);
261 
262 	b = traps->bot.y + y_off_fixed;
263 	if (pixman_fixed_to_int (b) >= height)
264 	    b = pixman_int_to_fixed (height) - 1;
265 	b = pixman_sample_floor_y (b, bpp);
266 
267 	if (b >= t)
268 	{
269 	    /* initialize edge walkers */
270 	    pixman_edge_init (&l, bpp, t,
271 	                      traps->top.l + x_off_fixed,
272 	                      traps->top.y + y_off_fixed,
273 	                      traps->bot.l + x_off_fixed,
274 	                      traps->bot.y + y_off_fixed);
275 
276 	    pixman_edge_init (&r, bpp, t,
277 	                      traps->top.r + x_off_fixed,
278 	                      traps->top.y + y_off_fixed,
279 	                      traps->bot.r + x_off_fixed,
280 	                      traps->bot.y + y_off_fixed);
281 
282 	    pixman_rasterize_edges (image, &l, &r, t, b);
283 	}
284 
285 	traps++;
286     }
287 }
288 
289 #if 0
290 static void
291 dump_image (pixman_image_t *image,
292             const char *    title)
293 {
294     int i, j;
295 
296     if (!image->type == BITS)
297 	printf ("%s is not a regular image\n", title);
298 
299     if (!image->bits.format == PIXMAN_a8)
300 	printf ("%s is not an alpha mask\n", title);
301 
302     printf ("\n\n\n%s: \n", title);
303 
304     for (i = 0; i < image->bits.height; ++i)
305     {
306 	uint8_t *line =
307 	    (uint8_t *)&(image->bits.bits[i * image->bits.rowstride]);
308 
309 	for (j = 0; j < image->bits.width; ++j)
310 	    printf ("%c", line[j] ? '#' : ' ');
311 
312 	printf ("\n");
313     }
314 }
315 #endif
316 
317 PIXMAN_EXPORT void
pixman_add_trapezoids(pixman_image_t * image,int16_t x_off,int y_off,int ntraps,const pixman_trapezoid_t * traps)318 pixman_add_trapezoids (pixman_image_t *          image,
319                        int16_t                   x_off,
320                        int                       y_off,
321                        int                       ntraps,
322                        const pixman_trapezoid_t *traps)
323 {
324     int i;
325 
326 #if 0
327     dump_image (image, "before");
328 #endif
329 
330     for (i = 0; i < ntraps; ++i)
331     {
332 	const pixman_trapezoid_t *trap = &(traps[i]);
333 
334 	if (!pixman_trapezoid_valid (trap))
335 	    continue;
336 
337 	pixman_rasterize_trapezoid (image, trap, x_off, y_off);
338     }
339 
340 #if 0
341     dump_image (image, "after");
342 #endif
343 }
344 
345 PIXMAN_EXPORT void
pixman_rasterize_trapezoid(pixman_image_t * image,const pixman_trapezoid_t * trap,int x_off,int y_off)346 pixman_rasterize_trapezoid (pixman_image_t *          image,
347                             const pixman_trapezoid_t *trap,
348                             int                       x_off,
349                             int                       y_off)
350 {
351     int bpp;
352     int height;
353 
354     pixman_fixed_t y_off_fixed;
355     pixman_edge_t l, r;
356     pixman_fixed_t t, b;
357 
358     return_if_fail (image->type == BITS);
359 
360     _pixman_image_validate (image);
361 
362     if (!pixman_trapezoid_valid (trap))
363 	return;
364 
365     height = image->bits.height;
366     bpp = PIXMAN_FORMAT_BPP (image->bits.format);
367 
368     y_off_fixed = pixman_int_to_fixed (y_off);
369 
370     t = trap->top + y_off_fixed;
371     if (t < 0)
372 	t = 0;
373     t = pixman_sample_ceil_y (t, bpp);
374 
375     b = trap->bottom + y_off_fixed;
376     if (pixman_fixed_to_int (b) >= height)
377 	b = pixman_int_to_fixed (height) - 1;
378     b = pixman_sample_floor_y (b, bpp);
379 
380     if (b >= t)
381     {
382 	/* initialize edge walkers */
383 	pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
384 	pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
385 
386 	pixman_rasterize_edges (image, &l, &r, t, b);
387     }
388 }
389 
390 static const pixman_bool_t zero_src_has_no_effect[PIXMAN_N_OPERATORS] =
391 {
392     FALSE,	/* Clear		0			0    */
393     FALSE,	/* Src			1			0    */
394     TRUE,	/* Dst			0			1    */
395     TRUE,	/* Over			1			1-Aa */
396     TRUE,	/* OverReverse		1-Ab			1    */
397     FALSE,	/* In			Ab			0    */
398     FALSE,	/* InReverse		0			Aa   */
399     FALSE,	/* Out			1-Ab			0    */
400     TRUE,	/* OutReverse		0			1-Aa */
401     TRUE,	/* Atop			Ab			1-Aa */
402     FALSE,	/* AtopReverse		1-Ab			Aa   */
403     TRUE,	/* Xor			1-Ab			1-Aa */
404     TRUE,	/* Add			1			1    */
405 };
406 
407 static pixman_bool_t
get_trap_extents(pixman_op_t op,pixman_image_t * dest,const pixman_trapezoid_t * traps,int n_traps,pixman_box32_t * box)408 get_trap_extents (pixman_op_t op, pixman_image_t *dest,
409 		  const pixman_trapezoid_t *traps, int n_traps,
410 		  pixman_box32_t *box)
411 {
412     int i;
413 
414     /* When the operator is such that a zero source has an
415      * effect on the underlying image, we have to
416      * composite across the entire destination
417      */
418     if (!zero_src_has_no_effect [op])
419     {
420 	box->x1 = 0;
421 	box->y1 = 0;
422 	box->x2 = dest->bits.width;
423 	box->y2 = dest->bits.height;
424 	return TRUE;
425     }
426 
427     box->x1 = INT32_MAX;
428     box->y1 = INT32_MAX;
429     box->x2 = INT32_MIN;
430     box->y2 = INT32_MIN;
431 
432     for (i = 0; i < n_traps; ++i)
433     {
434 	const pixman_trapezoid_t *trap = &(traps[i]);
435 	int y1, y2;
436 
437 	if (!pixman_trapezoid_valid (trap))
438 	    continue;
439 
440 	y1 = pixman_fixed_to_int (trap->top);
441 	if (y1 < box->y1)
442 	    box->y1 = y1;
443 
444 	y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
445 	if (y2 > box->y2)
446 	    box->y2 = y2;
447 
448 #define EXTEND_MIN(x)							\
449 	if (pixman_fixed_to_int ((x)) < box->x1)			\
450 	    box->x1 = pixman_fixed_to_int ((x));
451 #define EXTEND_MAX(x)							\
452 	if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box->x2)	\
453 	    box->x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
454 
455 #define EXTEND(x)							\
456 	EXTEND_MIN(x);							\
457 	EXTEND_MAX(x);
458 
459 	EXTEND(trap->left.p1.x);
460 	EXTEND(trap->left.p2.x);
461 	EXTEND(trap->right.p1.x);
462 	EXTEND(trap->right.p2.x);
463     }
464 
465     if (box->x1 >= box->x2 || box->y1 >= box->y2)
466 	return FALSE;
467 
468     return TRUE;
469 }
470 
471 /*
472  * pixman_composite_trapezoids()
473  *
474  * All the trapezoids are conceptually rendered to an infinitely big image.
475  * The (0, 0) coordinates of this image are then aligned with the (x, y)
476  * coordinates of the source image, and then both images are aligned with
477  * the (x, y) coordinates of the destination. Then these three images are
478  * composited across the entire destination.
479  */
480 PIXMAN_EXPORT void
pixman_composite_trapezoids(pixman_op_t op,pixman_image_t * src,pixman_image_t * dst,pixman_format_code_t mask_format,int x_src,int y_src,int x_dst,int y_dst,int n_traps,const pixman_trapezoid_t * traps)481 pixman_composite_trapezoids (pixman_op_t		op,
482 			     pixman_image_t *		src,
483 			     pixman_image_t *		dst,
484 			     pixman_format_code_t	mask_format,
485 			     int			x_src,
486 			     int			y_src,
487 			     int			x_dst,
488 			     int			y_dst,
489 			     int			n_traps,
490 			     const pixman_trapezoid_t *	traps)
491 {
492     int i;
493 
494     return_if_fail (PIXMAN_FORMAT_TYPE (mask_format) == PIXMAN_TYPE_A);
495 
496     if (n_traps <= 0)
497 	return;
498 
499     _pixman_image_validate (src);
500     _pixman_image_validate (dst);
501 
502     if (op == PIXMAN_OP_ADD &&
503 	(src->common.flags & FAST_PATH_IS_OPAQUE)		&&
504 	(mask_format == dst->common.extended_format_code)	&&
505 	!(dst->common.have_clip_region))
506     {
507 	for (i = 0; i < n_traps; ++i)
508 	{
509 	    const pixman_trapezoid_t *trap = &(traps[i]);
510 
511 	    if (!pixman_trapezoid_valid (trap))
512 		continue;
513 
514 	    pixman_rasterize_trapezoid (dst, trap, x_dst, y_dst);
515 	}
516     }
517     else
518     {
519 	pixman_image_t *tmp;
520 	pixman_box32_t box;
521 	int i;
522 
523 	if (!get_trap_extents (op, dst, traps, n_traps, &box))
524 	    return;
525 
526 	if (!(tmp = pixman_image_create_bits (
527 		  mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1)))
528 	    return;
529 
530 	for (i = 0; i < n_traps; ++i)
531 	{
532 	    const pixman_trapezoid_t *trap = &(traps[i]);
533 
534 	    if (!pixman_trapezoid_valid (trap))
535 		continue;
536 
537 	    pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
538 	}
539 
540 	pixman_image_composite (op, src, tmp, dst,
541 				x_src + box.x1, y_src + box.y1,
542 				0, 0,
543 				x_dst + box.x1, y_dst + box.y1,
544 				box.x2 - box.x1, box.y2 - box.y1);
545 
546 	pixman_image_unref (tmp);
547     }
548 }
549 
550 static int
greater_y(const pixman_point_fixed_t * a,const pixman_point_fixed_t * b)551 greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b)
552 {
553     if (a->y == b->y)
554 	return a->x > b->x;
555     return a->y > b->y;
556 }
557 
558 /*
559  * Note that the definition of this function is a bit odd because
560  * of the X coordinate space (y increasing downwards).
561  */
562 static int
clockwise(const pixman_point_fixed_t * ref,const pixman_point_fixed_t * a,const pixman_point_fixed_t * b)563 clockwise (const pixman_point_fixed_t *ref,
564 	   const pixman_point_fixed_t *a,
565 	   const pixman_point_fixed_t *b)
566 {
567     pixman_point_fixed_t	ad, bd;
568 
569     ad.x = a->x - ref->x;
570     ad.y = a->y - ref->y;
571     bd.x = b->x - ref->x;
572     bd.y = b->y - ref->y;
573 
574     return ((pixman_fixed_32_32_t) bd.y * ad.x -
575 	    (pixman_fixed_32_32_t) ad.y * bd.x) < 0;
576 }
577 
578 static void
triangle_to_trapezoids(const pixman_triangle_t * tri,pixman_trapezoid_t * traps)579 triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps)
580 {
581     const pixman_point_fixed_t *top, *left, *right, *tmp;
582 
583     top = &tri->p1;
584     left = &tri->p2;
585     right = &tri->p3;
586 
587     if (greater_y (top, left))
588     {
589 	tmp = left;
590 	left = top;
591 	top = tmp;
592     }
593 
594     if (greater_y (top, right))
595     {
596 	tmp = right;
597 	right = top;
598 	top = tmp;
599     }
600 
601     if (clockwise (top, right, left))
602     {
603 	tmp = right;
604 	right = left;
605 	left = tmp;
606     }
607 
608     /*
609      * Two cases:
610      *
611      *		+		+
612      *	       / \             / \
613      *	      /   \           /	  \
614      *	     /     +         +	   \
615      *      /    --           --    \
616      *     /   --               --   \
617      *    / ---                   --- \
618      *	 +--                         --+
619      */
620 
621     traps->top = top->y;
622     traps->left.p1 = *top;
623     traps->left.p2 = *left;
624     traps->right.p1 = *top;
625     traps->right.p2 = *right;
626 
627     if (right->y < left->y)
628 	traps->bottom = right->y;
629     else
630 	traps->bottom = left->y;
631 
632     traps++;
633 
634     *traps = *(traps - 1);
635 
636     if (right->y < left->y)
637     {
638 	traps->top = right->y;
639 	traps->bottom = left->y;
640 	traps->right.p1 = *right;
641 	traps->right.p2 = *left;
642     }
643     else
644     {
645 	traps->top = left->y;
646 	traps->bottom = right->y;
647 	traps->left.p1 = *left;
648 	traps->left.p2 = *right;
649     }
650 }
651 
652 static pixman_trapezoid_t *
convert_triangles(int n_tris,const pixman_triangle_t * tris)653 convert_triangles (int n_tris, const pixman_triangle_t *tris)
654 {
655     pixman_trapezoid_t *traps;
656     int i;
657 
658     if (n_tris <= 0)
659 	return NULL;
660 
661     traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t));
662     if (!traps)
663 	return NULL;
664 
665     for (i = 0; i < n_tris; ++i)
666 	triangle_to_trapezoids (&(tris[i]), traps + 2 * i);
667 
668     return traps;
669 }
670 
671 PIXMAN_EXPORT void
pixman_composite_triangles(pixman_op_t op,pixman_image_t * src,pixman_image_t * dst,pixman_format_code_t mask_format,int x_src,int y_src,int x_dst,int y_dst,int n_tris,const pixman_triangle_t * tris)672 pixman_composite_triangles (pixman_op_t			op,
673 			    pixman_image_t *		src,
674 			    pixman_image_t *		dst,
675 			    pixman_format_code_t	mask_format,
676 			    int				x_src,
677 			    int				y_src,
678 			    int				x_dst,
679 			    int				y_dst,
680 			    int				n_tris,
681 			    const pixman_triangle_t *	tris)
682 {
683     pixman_trapezoid_t *traps;
684 
685     if ((traps = convert_triangles (n_tris, tris)))
686     {
687 	pixman_composite_trapezoids (op, src, dst, mask_format,
688 				     x_src, y_src, x_dst, y_dst,
689 				     n_tris * 2, traps);
690 
691 	free (traps);
692     }
693 }
694 
695 PIXMAN_EXPORT void
pixman_add_triangles(pixman_image_t * image,int32_t x_off,int32_t y_off,int n_tris,const pixman_triangle_t * tris)696 pixman_add_triangles (pixman_image_t          *image,
697 		      int32_t	               x_off,
698 		      int32_t	               y_off,
699 		      int	               n_tris,
700 		      const pixman_triangle_t *tris)
701 {
702     pixman_trapezoid_t *traps;
703 
704     if ((traps = convert_triangles (n_tris, tris)))
705     {
706 	pixman_add_trapezoids (image, x_off, y_off,
707 			       n_tris * 2, traps);
708 
709 	free (traps);
710     }
711 }
712