pixman-utils.c revision d0321353
1/*
2 * Copyright © 2000 SuSE, Inc.
3 * Copyright © 1999 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 SuSE not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission.  SuSE makes no representations about the
12 * suitability of this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 *
15 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Author:  Keith Packard, SuSE, Inc.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28#include <stdio.h>
29#include <stdlib.h>
30
31#include "pixman-private.h"
32
33/*
34 * Computing composite region
35 */
36#define BOUND(v)        (int16_t) ((v) < INT16_MIN ? INT16_MIN : (v) > INT16_MAX ? INT16_MAX : (v))
37
38static inline pixman_bool_t
39clip_general_image (pixman_region32_t * region,
40                    pixman_region32_t * clip,
41                    int                 dx,
42                    int                 dy)
43{
44    if (pixman_region32_n_rects (region) == 1 &&
45        pixman_region32_n_rects (clip) == 1)
46    {
47	pixman_box32_t *  rbox = pixman_region32_rectangles (region, NULL);
48	pixman_box32_t *  cbox = pixman_region32_rectangles (clip, NULL);
49	int v;
50
51	if (rbox->x1 < (v = cbox->x1 + dx))
52	    rbox->x1 = BOUND (v);
53	if (rbox->x2 > (v = cbox->x2 + dx))
54	    rbox->x2 = BOUND (v);
55	if (rbox->y1 < (v = cbox->y1 + dy))
56	    rbox->y1 = BOUND (v);
57	if (rbox->y2 > (v = cbox->y2 + dy))
58	    rbox->y2 = BOUND (v);
59	if (rbox->x1 >= rbox->x2 ||
60	    rbox->y1 >= rbox->y2)
61	{
62	    pixman_region32_init (region);
63	}
64    }
65    else if (!pixman_region32_not_empty (clip))
66    {
67	return FALSE;
68    }
69    else
70    {
71	if (dx || dy)
72	    pixman_region32_translate (region, -dx, -dy);
73	if (!pixman_region32_intersect (region, region, clip))
74	    return FALSE;
75	if (dx || dy)
76	    pixman_region32_translate (region, dx, dy);
77    }
78    return pixman_region32_not_empty (region);
79}
80
81static inline pixman_bool_t
82clip_source_image (pixman_region32_t * region,
83                   pixman_image_t *    picture,
84                   int                 dx,
85                   int                 dy)
86{
87    /* The workaround lets certain fast paths run even when they
88     * would normally be rejected because of out-of-bounds access.
89     * We need to clip against the source geometry in that case
90     */
91    if (!picture->common.need_workaround)
92    {
93	/* Source clips are ignored, unless they are explicitly turned on
94	 * and the clip in question was set by an X client. (Because if
95	 * the clip was not set by a client, then it is a hierarchy
96	 * clip and those should always be ignored for sources).
97	 */
98	if (!picture->common.clip_sources || !picture->common.client_clip)
99	    return TRUE;
100    }
101
102    return clip_general_image (region,
103                               &picture->common.clip_region,
104                               dx, dy);
105}
106
107/*
108 * returns FALSE if the final region is empty.  Indistinguishable from
109 * an allocation failure, but rendering ignores those anyways.
110 */
111static pixman_bool_t
112pixman_compute_composite_region32 (pixman_region32_t * region,
113                                   pixman_image_t *    src_image,
114                                   pixman_image_t *    mask_image,
115                                   pixman_image_t *    dst_image,
116                                   int16_t             src_x,
117                                   int16_t             src_y,
118                                   int16_t             mask_x,
119                                   int16_t             mask_y,
120                                   int16_t             dest_x,
121                                   int16_t             dest_y,
122                                   uint16_t            width,
123                                   uint16_t            height)
124{
125    int v;
126
127    region->extents.x1 = dest_x;
128    v = dest_x + width;
129    region->extents.x2 = BOUND (v);
130    region->extents.y1 = dest_y;
131    v = dest_y + height;
132    region->extents.y2 = BOUND (v);
133
134    region->extents.x1 = MAX (region->extents.x1, 0);
135    region->extents.y1 = MAX (region->extents.y1, 0);
136
137    /* Some X servers rely on an old bug, where pixman would just believe the
138     * set clip_region and not clip against the destination geometry. So,
139     * since only X servers set "source clip", we don't clip against
140     * destination geometry when that is set and when the workaround has
141     * not been explicitly disabled by
142     *
143     *      pixman_disable_out_of_bounds_workaround();
144     *
145     */
146    if (!(dst_image->common.need_workaround))
147    {
148	region->extents.x2 = MIN (region->extents.x2, dst_image->bits.width);
149	region->extents.y2 = MIN (region->extents.y2, dst_image->bits.height);
150    }
151
152    region->data = 0;
153
154    /* Check for empty operation */
155    if (region->extents.x1 >= region->extents.x2 ||
156        region->extents.y1 >= region->extents.y2)
157    {
158	pixman_region32_init (region);
159	return FALSE;
160    }
161
162    if (dst_image->common.have_clip_region)
163    {
164	if (!clip_general_image (region, &dst_image->common.clip_region, 0, 0))
165	{
166	    pixman_region32_fini (region);
167	    return FALSE;
168	}
169    }
170
171    if (dst_image->common.alpha_map && dst_image->common.alpha_map->common.have_clip_region)
172    {
173	if (!clip_general_image (region, &dst_image->common.alpha_map->common.clip_region,
174	                         -dst_image->common.alpha_origin_x,
175	                         -dst_image->common.alpha_origin_y))
176	{
177	    pixman_region32_fini (region);
178	    return FALSE;
179	}
180    }
181
182    /* clip against src */
183    if (src_image->common.have_clip_region)
184    {
185	if (!clip_source_image (region, src_image, dest_x - src_x, dest_y - src_y))
186	{
187	    pixman_region32_fini (region);
188	    return FALSE;
189	}
190    }
191    if (src_image->common.alpha_map && src_image->common.alpha_map->common.have_clip_region)
192    {
193	if (!clip_source_image (region, (pixman_image_t *)src_image->common.alpha_map,
194	                        dest_x - (src_x - src_image->common.alpha_origin_x),
195	                        dest_y - (src_y - src_image->common.alpha_origin_y)))
196	{
197	    pixman_region32_fini (region);
198	    return FALSE;
199	}
200    }
201    /* clip against mask */
202    if (mask_image && mask_image->common.have_clip_region)
203    {
204	if (!clip_source_image (region, mask_image, dest_x - mask_x, dest_y - mask_y))
205	{
206	    pixman_region32_fini (region);
207	    return FALSE;
208	}
209	if (mask_image->common.alpha_map && mask_image->common.alpha_map->common.have_clip_region)
210	{
211	    if (!clip_source_image (region, (pixman_image_t *)mask_image->common.alpha_map,
212	                            dest_x - (mask_x - mask_image->common.alpha_origin_x),
213	                            dest_y - (mask_y - mask_image->common.alpha_origin_y)))
214	    {
215		pixman_region32_fini (region);
216		return FALSE;
217	    }
218	}
219    }
220
221    return TRUE;
222}
223
224PIXMAN_EXPORT pixman_bool_t
225pixman_compute_composite_region (pixman_region16_t * region,
226                                 pixman_image_t *    src_image,
227                                 pixman_image_t *    mask_image,
228                                 pixman_image_t *    dst_image,
229                                 int16_t             src_x,
230                                 int16_t             src_y,
231                                 int16_t             mask_x,
232                                 int16_t             mask_y,
233                                 int16_t             dest_x,
234                                 int16_t             dest_y,
235                                 uint16_t            width,
236                                 uint16_t            height)
237{
238    pixman_region32_t r32;
239    pixman_bool_t retval;
240
241    pixman_region32_init (&r32);
242
243    retval = pixman_compute_composite_region32 (
244	&r32, src_image, mask_image, dst_image,
245	src_x, src_y, mask_x, mask_y, dest_x, dest_y,
246	width, height);
247
248    if (retval)
249    {
250	if (!pixman_region16_copy_from_region32 (region, &r32))
251	    retval = FALSE;
252    }
253
254    pixman_region32_fini (&r32);
255    return retval;
256}
257
258pixman_bool_t
259pixman_multiply_overflows_int (unsigned int a,
260                               unsigned int b)
261{
262    return a >= INT32_MAX / b;
263}
264
265pixman_bool_t
266pixman_addition_overflows_int (unsigned int a,
267                               unsigned int b)
268{
269    return a > INT32_MAX - b;
270}
271
272void *
273pixman_malloc_ab (unsigned int a,
274                  unsigned int b)
275{
276    if (a >= INT32_MAX / b)
277	return NULL;
278
279    return malloc (a * b);
280}
281
282void *
283pixman_malloc_abc (unsigned int a,
284                   unsigned int b,
285                   unsigned int c)
286{
287    if (a >= INT32_MAX / b)
288	return NULL;
289    else if (a * b >= INT32_MAX / c)
290	return NULL;
291    else
292	return malloc (a * b * c);
293}
294
295/*
296 * Helper routine to expand a color component from 0 < n <= 8 bits to 16
297 * bits by replication.
298 */
299static inline uint64_t
300expand16 (const uint8_t val, int nbits)
301{
302    /* Start out with the high bit of val in the high bit of result. */
303    uint16_t result = (uint16_t)val << (16 - nbits);
304
305    if (nbits == 0)
306	return 0;
307
308    /* Copy the bits in result, doubling the number of bits each time, until
309     * we fill all 16 bits.
310     */
311    while (nbits < 16)
312    {
313	result |= result >> nbits;
314	nbits *= 2;
315    }
316
317    return result;
318}
319
320/*
321 * This function expands images from ARGB8 format to ARGB16.  To preserve
322 * precision, it needs to know the original source format.  For example, if the
323 * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
324 * the expanded value is 12345123.  To correctly expand this to 16 bits, it
325 * should be 1234512345123451 and not 1234512312345123.
326 */
327void
328pixman_expand (uint64_t *           dst,
329               const uint32_t *     src,
330               pixman_format_code_t format,
331               int                  width)
332{
333    /*
334     * Determine the sizes of each component and the masks and shifts
335     * required to extract them from the source pixel.
336     */
337    const int a_size = PIXMAN_FORMAT_A (format),
338              r_size = PIXMAN_FORMAT_R (format),
339              g_size = PIXMAN_FORMAT_G (format),
340              b_size = PIXMAN_FORMAT_B (format);
341    const int a_shift = 32 - a_size,
342              r_shift = 24 - r_size,
343              g_shift = 16 - g_size,
344              b_shift =  8 - b_size;
345    const uint8_t a_mask = ~(~0 << a_size),
346                  r_mask = ~(~0 << r_size),
347                  g_mask = ~(~0 << g_size),
348                  b_mask = ~(~0 << b_size);
349    int i;
350
351    /* Start at the end so that we can do the expansion in place
352     * when src == dst
353     */
354    for (i = width - 1; i >= 0; i--)
355    {
356	const uint32_t pixel = src[i];
357	const uint8_t a = (pixel >> a_shift) & a_mask,
358	              r = (pixel >> r_shift) & r_mask,
359	              g = (pixel >> g_shift) & g_mask,
360	              b = (pixel >> b_shift) & b_mask;
361	const uint64_t a16 = a_size ? expand16 (a, a_size) : 0xffff,
362	               r16 = expand16 (r, r_size),
363	               g16 = expand16 (g, g_size),
364	               b16 = expand16 (b, b_size);
365
366	dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
367    }
368}
369
370/*
371 * Contracting is easier than expanding.  We just need to truncate the
372 * components.
373 */
374void
375pixman_contract (uint32_t *      dst,
376                 const uint64_t *src,
377                 int             width)
378{
379    int i;
380
381    /* Start at the beginning so that we can do the contraction in
382     * place when src == dst
383     */
384    for (i = 0; i < width; i++)
385    {
386	const uint8_t a = src[i] >> 56,
387	              r = src[i] >> 40,
388	              g = src[i] >> 24,
389	              b = src[i] >> 8;
390
391	dst[i] = a << 24 | r << 16 | g << 8 | b;
392    }
393}
394
395static void
396walk_region_internal (pixman_implementation_t *imp,
397                      pixman_op_t              op,
398                      pixman_image_t *         src_image,
399                      pixman_image_t *         mask_image,
400                      pixman_image_t *         dst_image,
401                      int16_t                  src_x,
402                      int16_t                  src_y,
403                      int16_t                  mask_x,
404                      int16_t                  mask_y,
405                      int16_t                  dest_x,
406                      int16_t                  dest_y,
407                      uint16_t                 width,
408                      uint16_t                 height,
409                      pixman_bool_t            src_repeat,
410                      pixman_bool_t            mask_repeat,
411                      pixman_region32_t *      region,
412                      pixman_composite_func_t  composite_rect)
413{
414    int n;
415    const pixman_box32_t *pbox;
416    int w, h, w_this, h_this;
417    int x_msk, y_msk, x_src, y_src, x_dst, y_dst;
418
419    pbox = pixman_region32_rectangles (region, &n);
420    while (n--)
421    {
422	h = pbox->y2 - pbox->y1;
423	y_src = pbox->y1 - dest_y + src_y;
424	y_msk = pbox->y1 - dest_y + mask_y;
425	y_dst = pbox->y1;
426
427	while (h)
428	{
429	    h_this = h;
430	    w = pbox->x2 - pbox->x1;
431	    x_src = pbox->x1 - dest_x + src_x;
432	    x_msk = pbox->x1 - dest_x + mask_x;
433	    x_dst = pbox->x1;
434
435	    if (mask_repeat)
436	    {
437		y_msk = MOD (y_msk, mask_image->bits.height);
438		if (h_this > mask_image->bits.height - y_msk)
439		    h_this = mask_image->bits.height - y_msk;
440	    }
441
442	    if (src_repeat)
443	    {
444		y_src = MOD (y_src, src_image->bits.height);
445		if (h_this > src_image->bits.height - y_src)
446		    h_this = src_image->bits.height - y_src;
447	    }
448
449	    while (w)
450	    {
451		w_this = w;
452
453		if (mask_repeat)
454		{
455		    x_msk = MOD (x_msk, mask_image->bits.width);
456		    if (w_this > mask_image->bits.width - x_msk)
457			w_this = mask_image->bits.width - x_msk;
458		}
459
460		if (src_repeat)
461		{
462		    x_src = MOD (x_src, src_image->bits.width);
463		    if (w_this > src_image->bits.width - x_src)
464			w_this = src_image->bits.width - x_src;
465		}
466
467		(*composite_rect) (imp, op,
468				   src_image, mask_image, dst_image,
469				   x_src, y_src, x_msk, y_msk, x_dst, y_dst,
470				   w_this, h_this);
471		w -= w_this;
472
473		x_src += w_this;
474		x_msk += w_this;
475		x_dst += w_this;
476	    }
477
478	    h -= h_this;
479	    y_src += h_this;
480	    y_msk += h_this;
481	    y_dst += h_this;
482	}
483
484	pbox++;
485    }
486}
487
488void
489_pixman_walk_composite_region (pixman_implementation_t *imp,
490                               pixman_op_t              op,
491                               pixman_image_t *         src_image,
492                               pixman_image_t *         mask_image,
493                               pixman_image_t *         dst_image,
494                               int16_t                  src_x,
495                               int16_t                  src_y,
496                               int16_t                  mask_x,
497                               int16_t                  mask_y,
498                               int16_t                  dest_x,
499                               int16_t                  dest_y,
500                               uint16_t                 width,
501                               uint16_t                 height,
502                               pixman_composite_func_t  composite_rect)
503{
504    pixman_region32_t region;
505
506    pixman_region32_init (&region);
507
508    if (pixman_compute_composite_region32 (
509            &region, src_image, mask_image, dst_image,
510            src_x, src_y, mask_x, mask_y, dest_x, dest_y,
511            width, height))
512    {
513	walk_region_internal (imp, op,
514	                      src_image, mask_image, dst_image,
515	                      src_x, src_y, mask_x, mask_y, dest_x, dest_y,
516	                      width, height, FALSE, FALSE,
517	                      &region,
518	                      composite_rect);
519
520	pixman_region32_fini (&region);
521    }
522}
523
524static pixman_bool_t
525mask_is_solid (pixman_image_t *mask)
526{
527    if (mask->type == SOLID)
528	return TRUE;
529
530    if (mask->type == BITS &&
531        mask->common.repeat == PIXMAN_REPEAT_NORMAL &&
532        mask->bits.width == 1 &&
533        mask->bits.height == 1)
534    {
535	return TRUE;
536    }
537
538    return FALSE;
539}
540
541static const pixman_fast_path_t *
542get_fast_path (const pixman_fast_path_t *fast_paths,
543               pixman_op_t               op,
544               pixman_image_t *          src_image,
545               pixman_image_t *          mask_image,
546               pixman_image_t *          dst_image,
547               pixman_bool_t             is_pixbuf)
548{
549    const pixman_fast_path_t *info;
550
551    for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++)
552    {
553	pixman_bool_t valid_src = FALSE;
554	pixman_bool_t valid_mask = FALSE;
555
556	if (info->op != op)
557	    continue;
558
559	if ((info->src_format == PIXMAN_solid &&
560	     _pixman_image_is_solid (src_image)) ||
561	    (src_image->type == BITS &&
562	     info->src_format == src_image->bits.format))
563	{
564	    valid_src = TRUE;
565	}
566
567	if (!valid_src)
568	    continue;
569
570	if ((info->mask_format == PIXMAN_null && !mask_image) ||
571	    (mask_image && mask_image->type == BITS &&
572	     info->mask_format == mask_image->bits.format))
573	{
574	    valid_mask = TRUE;
575
576	    if (info->flags & NEED_SOLID_MASK)
577	    {
578		if (!mask_image || !mask_is_solid (mask_image))
579		    valid_mask = FALSE;
580	    }
581
582	    if (info->flags & NEED_COMPONENT_ALPHA)
583	    {
584		if (!mask_image || !mask_image->common.component_alpha)
585		    valid_mask = FALSE;
586	    }
587	}
588
589	if (!valid_mask)
590	    continue;
591
592	if (info->dest_format != dst_image->bits.format)
593	    continue;
594
595	if ((info->flags & NEED_PIXBUF) && !is_pixbuf)
596	    continue;
597
598	return info;
599    }
600
601    return NULL;
602}
603
604static force_inline pixman_bool_t
605image_covers (pixman_image_t *image,
606              pixman_box32_t *extents,
607              int             x,
608              int             y)
609{
610    if (image->common.type == BITS &&
611	image->common.repeat == PIXMAN_REPEAT_NONE)
612    {
613	if (x > extents->x1 || y > extents->y1 ||
614	    x + image->bits.width < extents->x2 ||
615	    y + image->bits.height < extents->y2)
616	{
617	    return FALSE;
618	}
619    }
620
621    return TRUE;
622}
623
624static force_inline pixman_bool_t
625sources_cover (pixman_image_t *src,
626	       pixman_image_t *mask,
627	       pixman_box32_t *extents,
628	       int             src_x,
629	       int             src_y,
630	       int             mask_x,
631	       int             mask_y,
632	       int             dest_x,
633	       int             dest_y)
634{
635    if (!image_covers (src, extents, dest_x - src_x, dest_y - src_y))
636	return FALSE;
637
638    if (!mask)
639	return TRUE;
640
641    if (!image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y))
642	return FALSE;
643
644    return TRUE;
645}
646
647pixman_bool_t
648_pixman_run_fast_path (const pixman_fast_path_t *paths,
649                       pixman_implementation_t * imp,
650                       pixman_op_t               op,
651                       pixman_image_t *          src,
652                       pixman_image_t *          mask,
653                       pixman_image_t *          dest,
654                       int32_t                   src_x,
655                       int32_t                   src_y,
656                       int32_t                   mask_x,
657                       int32_t                   mask_y,
658                       int32_t                   dest_x,
659                       int32_t                   dest_y,
660                       int32_t                   width,
661                       int32_t                   height)
662{
663    pixman_composite_func_t func = NULL;
664    pixman_bool_t src_repeat =
665	src->common.repeat == PIXMAN_REPEAT_NORMAL;
666    pixman_bool_t mask_repeat =
667	mask && mask->common.repeat == PIXMAN_REPEAT_NORMAL;
668    pixman_bool_t result;
669
670    if ((src->type == BITS || _pixman_image_is_solid (src)) &&
671        (!mask || mask->type == BITS)
672        && !src->common.transform && !(mask && mask->common.transform)
673	&& !src->common.alpha_map && !dest->common.alpha_map
674        && !(mask && mask->common.alpha_map)
675        && (src->common.filter != PIXMAN_FILTER_CONVOLUTION)
676        && (src->common.repeat != PIXMAN_REPEAT_PAD)
677        && (src->common.repeat != PIXMAN_REPEAT_REFLECT)
678        && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION &&
679                      mask->common.repeat != PIXMAN_REPEAT_PAD &&
680                      mask->common.repeat != PIXMAN_REPEAT_REFLECT))
681        && !src->common.read_func && !src->common.write_func
682        && !(mask && mask->common.read_func)
683        && !(mask && mask->common.write_func)
684        && !dest->common.read_func
685        && !dest->common.write_func)
686    {
687	const pixman_fast_path_t *info;
688	pixman_bool_t pixbuf;
689
690	pixbuf =
691	    src && src->type == BITS            &&
692	    mask && mask->type == BITS          &&
693	    src->bits.bits == mask->bits.bits   &&
694	    src_x == mask_x                     &&
695	    src_y == mask_y                     &&
696	    !mask->common.component_alpha       &&
697	    !mask_repeat;
698
699	info = get_fast_path (paths, op, src, mask, dest, pixbuf);
700
701	if (info)
702	{
703	    func = info->func;
704
705	    if (info->src_format == PIXMAN_solid)
706		src_repeat = FALSE;
707
708	    if (info->mask_format == PIXMAN_solid ||
709		info->flags & NEED_SOLID_MASK)
710	    {
711		mask_repeat = FALSE;
712	    }
713
714	    if ((src_repeat                     &&
715	         src->bits.width == 1           &&
716	         src->bits.height == 1) ||
717	        (mask_repeat                    &&
718	         mask->bits.width == 1          &&
719	         mask->bits.height == 1))
720	    {
721		/* If src or mask are repeating 1x1 images and src_repeat or
722		 * mask_repeat are still TRUE, it means the fast path we
723		 * selected does not actually handle repeating images.
724		 *
725		 * So rather than call the "fast path" with a zillion
726		 * 1x1 requests, we just fall back to the general code (which
727		 * does do something sensible with 1x1 repeating images).
728		 */
729		func = NULL;
730	    }
731	}
732    }
733
734    result = FALSE;
735
736    if (func)
737    {
738	pixman_region32_t region;
739	pixman_region32_init (&region);
740
741	if (pixman_compute_composite_region32 (
742	        &region, src, mask, dest,
743	        src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
744	{
745	    pixman_box32_t *extents = pixman_region32_extents (&region);
746
747	    if (sources_cover (
748		    src, mask, extents,
749		    src_x, src_y, mask_x, mask_y, dest_x, dest_y))
750	    {
751		walk_region_internal (imp, op,
752		                      src, mask, dest,
753		                      src_x, src_y, mask_x, mask_y,
754		                      dest_x, dest_y,
755		                      width, height,
756		                      src_repeat, mask_repeat,
757		                      &region,
758		                      func);
759
760		result = TRUE;
761	    }
762
763	    pixman_region32_fini (&region);
764	}
765    }
766
767    return result;
768}
769
770#define N_TMP_BOXES (16)
771
772pixman_bool_t
773pixman_region16_copy_from_region32 (pixman_region16_t *dst,
774                                    pixman_region32_t *src)
775{
776    int n_boxes, i;
777    pixman_box32_t *boxes32;
778    pixman_box16_t *boxes16;
779    pixman_bool_t retval;
780
781    boxes32 = pixman_region32_rectangles (src, &n_boxes);
782
783    boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
784
785    if (!boxes16)
786	return FALSE;
787
788    for (i = 0; i < n_boxes; ++i)
789    {
790	boxes16[i].x1 = boxes32[i].x1;
791	boxes16[i].y1 = boxes32[i].y1;
792	boxes16[i].x2 = boxes32[i].x2;
793	boxes16[i].y2 = boxes32[i].y2;
794    }
795
796    pixman_region_fini (dst);
797    retval = pixman_region_init_rects (dst, boxes16, n_boxes);
798    free (boxes16);
799    return retval;
800}
801
802pixman_bool_t
803pixman_region32_copy_from_region16 (pixman_region32_t *dst,
804                                    pixman_region16_t *src)
805{
806    int n_boxes, i;
807    pixman_box16_t *boxes16;
808    pixman_box32_t *boxes32;
809    pixman_box32_t tmp_boxes[N_TMP_BOXES];
810    pixman_bool_t retval;
811
812    boxes16 = pixman_region_rectangles (src, &n_boxes);
813
814    if (n_boxes > N_TMP_BOXES)
815	boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
816    else
817	boxes32 = tmp_boxes;
818
819    if (!boxes32)
820	return FALSE;
821
822    for (i = 0; i < n_boxes; ++i)
823    {
824	boxes32[i].x1 = boxes16[i].x1;
825	boxes32[i].y1 = boxes16[i].y1;
826	boxes32[i].x2 = boxes16[i].x2;
827	boxes32[i].y2 = boxes16[i].y2;
828    }
829
830    pixman_region32_fini (dst);
831    retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
832
833    if (boxes32 != tmp_boxes)
834	free (boxes32);
835
836    return retval;
837}
838