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