Merge branch 'master' into refactor
[profile/ivi/pixman.git] / pixman / pixman-image.c
1 /*
2  * Copyright © 2000 SuSE, Inc.
3  * Copyright © 2007 Red Hat, Inc.
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
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "pixman-private.h"
32
33 #define Alpha(x) ((x) >> 24)
34
35 static source_pict_class_t
36 SourcePictureClassify (pixman_image_t *image,
37                        int             x,
38                        int             y,
39                        int             width,
40                        int             height)
41 {
42     source_image_t *pict = &image->source;
43     
44     pict->class = SOURCE_IMAGE_CLASS_UNKNOWN;
45     
46     if (pict->common.type == SOLID)
47     {
48         pict->class = SOURCE_IMAGE_CLASS_HORIZONTAL;
49     }
50     else if (pict->common.type == LINEAR)
51     {
52         linear_gradient_t *linear = (linear_gradient_t *)pict;
53         pixman_vector_t   v;
54         pixman_fixed_32_32_t l;
55         pixman_fixed_48_16_t dx, dy, a, b, off;
56         pixman_fixed_48_16_t factors[4];
57         int          i;
58
59         dx = linear->p2.x - linear->p1.x;
60         dy = linear->p2.y - linear->p1.y;
61         l = dx * dx + dy * dy;
62         if (l)
63         {
64             a = (dx << 32) / l;
65             b = (dy << 32) / l;
66         }
67         else
68         {
69             a = b = 0;
70         }
71
72         off = (-a * linear->p1.x
73                -b * linear->p1.y) >> 16;
74
75         for (i = 0; i < 3; i++)
76         {
77             v.vector[0] = pixman_int_to_fixed ((i % 2) * (width  - 1) + x);
78             v.vector[1] = pixman_int_to_fixed ((i / 2) * (height - 1) + y);
79             v.vector[2] = pixman_fixed_1;
80
81             if (pict->common.transform)
82             {
83                 if (!pixman_transform_point_3d (pict->common.transform, &v))
84                 {
85                     pict->class = SOURCE_IMAGE_CLASS_UNKNOWN;
86                     goto out;
87                 }
88             }
89
90             factors[i] = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
91         }
92
93         if (factors[2] == factors[0])
94             pict->class = SOURCE_IMAGE_CLASS_HORIZONTAL;
95         else if (factors[1] == factors[0])
96             pict->class = SOURCE_IMAGE_CLASS_VERTICAL;
97     }
98
99 out:
100     return pict->class;
101 }
102
103 static void
104 init_source_image (source_image_t *image)
105 {
106     image->class = SOURCE_IMAGE_CLASS_UNKNOWN;
107     image->common.classify = SourcePictureClassify;
108 }
109
110 static pixman_bool_t
111 init_gradient (gradient_t     *gradient,
112                const pixman_gradient_stop_t *stops,
113                int             n_stops)
114 {
115     return_val_if_fail (n_stops > 0, FALSE);
116
117     init_source_image (&gradient->common);
118
119     gradient->stops = pixman_malloc_ab (n_stops, sizeof (pixman_gradient_stop_t));
120     if (!gradient->stops)
121         return FALSE;
122
123     memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t));
124
125     gradient->n_stops = n_stops;
126
127     gradient->stop_range = 0xffff;
128     gradient->color_table = NULL;
129     gradient->color_table_size = 0;
130
131     return TRUE;
132 }
133
134 static uint32_t
135 color_to_uint32 (const pixman_color_t *color)
136 {
137     return
138         (color->alpha >> 8 << 24) |
139         (color->red >> 8 << 16) |
140         (color->green & 0xff00) |
141         (color->blue >> 8);
142 }
143
144 static pixman_image_t *
145 allocate_image (void)
146 {
147     pixman_image_t *image = malloc (sizeof (pixman_image_t));
148
149     if (image)
150     {
151         image_common_t *common = &image->common;
152
153         pixman_region32_init (&common->full_region);
154         pixman_region32_init (&common->clip_region);
155         common->src_clip = &common->full_region;
156         common->has_client_clip = FALSE;
157         common->transform = NULL;
158         common->repeat = PIXMAN_REPEAT_NONE;
159         common->filter = PIXMAN_FILTER_NEAREST;
160         common->filter_params = NULL;
161         common->n_filter_params = 0;
162         common->alpha_map = NULL;
163         common->component_alpha = FALSE;
164         common->ref_count = 1;
165         common->read_func = NULL;
166         common->write_func = NULL;
167         common->classify = NULL;
168     }
169
170     return image;
171 }
172
173 source_pict_class_t
174 _pixman_image_classify (pixman_image_t *image,
175                         int             x,
176                         int             y,
177                         int             width,
178                         int             height)
179 {
180     if (image->common.classify)
181         return image->common.classify (image, x, y, width, height);
182     else
183         return SOURCE_IMAGE_CLASS_UNKNOWN;
184 }
185
186 #define READ_ACCESS(f) ((image->common.read_func)? f##_accessors : f)
187
188 static void fbFetchSolid(bits_image_t * image, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
189 {
190     uint32_t color;
191     uint32_t *end;
192     fetchPixelProc32 fetch = READ_ACCESS(pixman_fetchPixelProcForPicture32)(image);
193
194     color = fetch(image, 0, 0);
195
196     end = buffer + width;
197     while (buffer < end)
198         *(buffer++) = color;
199 }
200
201 static void fbFetchSolid64(bits_image_t * image, int x, int y, int width, uint64_t *buffer, void *unused, uint32_t unused2)
202 {
203     uint64_t color;
204     uint64_t *end;
205     fetchPixelProc64 fetch = READ_ACCESS(pixman_fetchPixelProcForPicture64)(image);
206
207     color = fetch(image, 0, 0);
208
209     end = buffer + width;
210     while (buffer < end)
211         *(buffer++) = color;
212 }
213
214 static void fbFetch(bits_image_t * image, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
215 {
216     fetchProc32 fetch = READ_ACCESS(pixman_fetchProcForPicture32)(image);
217
218     fetch(image, x, y, width, buffer);
219 }
220
221 static void fbFetch64(bits_image_t * image, int x, int y, int width, uint64_t *buffer, void *unused, uint32_t unused2)
222 {
223     fetchProc64 fetch = READ_ACCESS(pixman_fetchProcForPicture64)(image);
224
225     fetch(image, x, y, width, buffer);
226 }
227
228 scanFetchProc
229 _pixman_image_get_fetcher (pixman_image_t *image,
230                            int             wide)
231 {
232     if (IS_SOURCE_IMAGE (image))
233     {
234         if (wide)
235             return (scanFetchProc)pixmanFetchSourcePict64;
236         else
237             return (scanFetchProc)pixmanFetchSourcePict;
238     }
239     else
240     {
241         bits_image_t *bits = (bits_image_t *)image;
242
243         if (bits->common.alpha_map)
244         {
245             if (wide)
246                 return (scanFetchProc)READ_ACCESS(fbFetchExternalAlpha64);
247             else
248                 return (scanFetchProc)READ_ACCESS(fbFetchExternalAlpha);
249         }
250         else if ((bits->common.repeat != PIXMAN_REPEAT_NONE) &&
251                  bits->width == 1 &&
252                  bits->height == 1)
253         {
254             if (wide)
255                 return (scanFetchProc)fbFetchSolid64;
256             else
257                 return (scanFetchProc)fbFetchSolid;
258         }
259         else if (!bits->common.transform && bits->common.filter != PIXMAN_FILTER_CONVOLUTION
260                 && bits->common.repeat != PIXMAN_REPEAT_PAD && bits->common.repeat != PIXMAN_REPEAT_REFLECT)
261         {
262             if (wide)
263                 return (scanFetchProc)fbFetch64;
264             else
265                 return (scanFetchProc)fbFetch;
266         }
267         else
268         {
269             if (wide)
270                 return (scanFetchProc)READ_ACCESS(fbFetchTransformed64);
271             else
272                 return (scanFetchProc)READ_ACCESS(fbFetchTransformed);
273         }
274     }
275 }
276
277
278
279 #define WRITE_ACCESS(f) ((image->common.write_func)? f##_accessors : f)
280
281 static void
282 fbStore(bits_image_t * image, int x, int y, int width, uint32_t *buffer)
283 {
284     uint32_t *bits;
285     int32_t stride;
286     storeProc32 store = WRITE_ACCESS(pixman_storeProcForPicture32)(image);
287     const pixman_indexed_t * indexed = image->indexed;
288
289     bits = image->bits;
290     stride = image->rowstride;
291     bits += y*stride;
292     store((pixman_image_t *)image, bits, buffer, x, width, indexed);
293 }
294
295 static void
296 fbStore64(bits_image_t * image, int x, int y, int width, uint64_t *buffer)
297 {
298     uint32_t *bits;
299     int32_t stride;
300     storeProc64 store = WRITE_ACCESS(pixman_storeProcForPicture64)(image);
301     const pixman_indexed_t * indexed = image->indexed;
302
303     bits = image->bits;
304     stride = image->rowstride;
305     bits += y*stride;
306     store((pixman_image_t *)image, bits, buffer, x, width, indexed);
307 }
308
309 scanStoreProc
310 _pixman_image_get_storer (pixman_image_t *image,
311                           int             wide)
312 {
313     if (image->common.alpha_map)
314     {
315         if (wide)
316             return (scanStoreProc)WRITE_ACCESS(fbStoreExternalAlpha64);
317         else
318             return (scanStoreProc)WRITE_ACCESS(fbStoreExternalAlpha);
319     }
320     else
321     {
322         if (wide)
323             return (scanStoreProc)fbStore64;
324         else
325             return (scanStoreProc)fbStore;
326     }
327 }
328
329 /* Ref Counting */
330 PIXMAN_EXPORT pixman_image_t *
331 pixman_image_ref (pixman_image_t *image)
332 {
333     image->common.ref_count++;
334
335     return image;
336 }
337
338 /* returns TRUE when the image is freed */
339 PIXMAN_EXPORT pixman_bool_t
340 pixman_image_unref (pixman_image_t *image)
341 {
342     image_common_t *common = (image_common_t *)image;
343
344     common->ref_count--;
345
346     if (common->ref_count == 0)
347     {
348         pixman_region32_fini (&common->clip_region);
349         pixman_region32_fini (&common->full_region);
350
351         if (common->transform)
352             free (common->transform);
353
354         if (common->filter_params)
355             free (common->filter_params);
356
357         if (common->alpha_map)
358             pixman_image_unref ((pixman_image_t *)common->alpha_map);
359
360 #if 0
361         if (image->type == BITS && image->bits.indexed)
362             free (image->bits.indexed);
363 #endif
364
365 #if 0
366         memset (image, 0xaa, sizeof (pixman_image_t));
367 #endif
368         if (image->type == LINEAR || image->type == RADIAL || image->type == CONICAL)
369         {
370             if (image->gradient.stops)
371                 free (image->gradient.stops);
372         }
373
374
375         if (image->type == BITS && image->bits.free_me)
376             free (image->bits.free_me);
377
378         free (image);
379
380         return TRUE;
381     }
382
383     return FALSE;
384 }
385
386 /* Constructors */
387 PIXMAN_EXPORT pixman_image_t *
388 pixman_image_create_solid_fill (pixman_color_t *color)
389 {
390     pixman_image_t *img = allocate_image();
391     if (!img)
392         return NULL;
393
394     init_source_image (&img->solid.common);
395
396     img->type = SOLID;
397     img->solid.color = color_to_uint32 (color);
398
399     return img;
400 }
401
402 PIXMAN_EXPORT pixman_image_t *
403 pixman_image_create_linear_gradient (pixman_point_fixed_t         *p1,
404                                      pixman_point_fixed_t         *p2,
405                                      const pixman_gradient_stop_t *stops,
406                                      int                           n_stops)
407 {
408     pixman_image_t *image;
409     linear_gradient_t *linear;
410
411     return_val_if_fail (n_stops >= 2, NULL);
412
413     image = allocate_image();
414
415     if (!image)
416         return NULL;
417
418     linear = &image->linear;
419
420     if (!init_gradient (&linear->common, stops, n_stops))
421     {
422         free (image);
423         return NULL;
424     }
425
426     linear->p1 = *p1;
427     linear->p2 = *p2;
428
429     image->type = LINEAR;
430
431     return image;
432 }
433
434
435 PIXMAN_EXPORT pixman_image_t *
436 pixman_image_create_radial_gradient (pixman_point_fixed_t         *inner,
437                                      pixman_point_fixed_t         *outer,
438                                      pixman_fixed_t                inner_radius,
439                                      pixman_fixed_t                outer_radius,
440                                      const pixman_gradient_stop_t *stops,
441                                      int                           n_stops)
442 {
443     pixman_image_t *image;
444     radial_gradient_t *radial;
445
446     return_val_if_fail (n_stops >= 2, NULL);
447
448     image = allocate_image();
449
450     if (!image)
451         return NULL;
452
453     radial = &image->radial;
454
455     if (!init_gradient (&radial->common, stops, n_stops))
456     {
457         free (image);
458         return NULL;
459     }
460
461     image->type = RADIAL;
462
463     radial->c1.x = inner->x;
464     radial->c1.y = inner->y;
465     radial->c1.radius = inner_radius;
466     radial->c2.x = outer->x;
467     radial->c2.y = outer->y;
468     radial->c2.radius = outer_radius;
469     radial->cdx = pixman_fixed_to_double (radial->c2.x - radial->c1.x);
470     radial->cdy = pixman_fixed_to_double (radial->c2.y - radial->c1.y);
471     radial->dr = pixman_fixed_to_double (radial->c2.radius - radial->c1.radius);
472     radial->A = (radial->cdx * radial->cdx
473                  + radial->cdy * radial->cdy
474                  - radial->dr  * radial->dr);
475
476     return image;
477 }
478
479 PIXMAN_EXPORT pixman_image_t *
480 pixman_image_create_conical_gradient (pixman_point_fixed_t *center,
481                                       pixman_fixed_t angle,
482                                       const pixman_gradient_stop_t *stops,
483                                       int n_stops)
484 {
485     pixman_image_t *image = allocate_image();
486     conical_gradient_t *conical;
487
488     if (!image)
489         return NULL;
490
491     conical = &image->conical;
492
493     if (!init_gradient (&conical->common, stops, n_stops))
494     {
495         free (image);
496         return NULL;
497     }
498
499     image->type = CONICAL;
500     conical->center = *center;
501     conical->angle = angle;
502
503     return image;
504 }
505
506 static uint32_t *
507 create_bits (pixman_format_code_t format,
508              int                  width,
509              int                  height,
510              int                 *rowstride_bytes)
511 {
512     int stride;
513     int buf_size;
514     int bpp;
515
516     /* what follows is a long-winded way, avoiding any possibility of integer
517      * overflows, of saying:
518      * stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (uint32_t);
519      */
520
521     bpp = PIXMAN_FORMAT_BPP (format);
522     if (pixman_multiply_overflows_int (width, bpp))
523         return NULL;
524
525     stride = width * bpp;
526     if (pixman_addition_overflows_int (stride, FB_MASK))
527         return NULL;
528
529     stride += FB_MASK;
530     stride >>= FB_SHIFT;
531
532 #if FB_SHIFT < 2
533     if (pixman_multiply_overflows_int (stride, sizeof (uint32_t)))
534         return NULL;
535 #endif
536     stride *= sizeof (uint32_t);
537
538     if (pixman_multiply_overflows_int (height, stride))
539         return NULL;
540
541     buf_size = height * stride;
542
543     if (rowstride_bytes)
544         *rowstride_bytes = stride;
545
546     return calloc (buf_size, 1);
547 }
548
549 static void
550 reset_clip_region (pixman_image_t *image)
551 {
552     pixman_region32_fini (&image->common.clip_region);
553
554     if (image->type == BITS)
555     {
556         pixman_region32_init_rect (&image->common.clip_region, 0, 0,
557                                    image->bits.width, image->bits.height);
558     }
559     else
560     {
561         pixman_region32_init (&image->common.clip_region);
562     }
563 }
564
565 PIXMAN_EXPORT pixman_image_t *
566 pixman_image_create_bits (pixman_format_code_t  format,
567                           int                   width,
568                           int                   height,
569                           uint32_t             *bits,
570                           int                   rowstride_bytes)
571 {
572     pixman_image_t *image;
573     uint32_t *free_me = NULL;
574
575     /* must be a whole number of uint32_t's
576      */
577     return_val_if_fail (bits == NULL ||
578                         (rowstride_bytes % sizeof (uint32_t)) == 0, NULL);
579
580     if (!bits && width && height)
581     {
582         free_me = bits = create_bits (format, width, height, &rowstride_bytes);
583         if (!bits)
584             return NULL;
585     }
586
587     image = allocate_image();
588
589     if (!image) {
590         if (free_me)
591             free (free_me);
592         return NULL;
593     }
594     
595     image->type = BITS;
596     image->bits.format = format;
597     image->bits.width = width;
598     image->bits.height = height;
599     image->bits.bits = bits;
600     image->bits.free_me = free_me;
601
602     image->bits.rowstride = rowstride_bytes / (int) sizeof (uint32_t); /* we store it in number
603                                                                   * of uint32_t's
604                                                                   */
605     image->bits.indexed = NULL;
606
607     pixman_region32_fini (&image->common.full_region);
608     pixman_region32_init_rect (&image->common.full_region, 0, 0,
609                                image->bits.width, image->bits.height);
610
611     reset_clip_region (image);
612     return image;
613 }
614
615 PIXMAN_EXPORT pixman_bool_t
616 pixman_image_set_clip_region32 (pixman_image_t *image,
617                                 pixman_region32_t *region)
618 {
619     image_common_t *common = (image_common_t *)image;
620
621     if (region)
622     {
623         return pixman_region32_copy (&common->clip_region, region);
624     }
625     else
626     {
627         reset_clip_region (image);
628
629         return TRUE;
630     }
631 }
632
633
634 PIXMAN_EXPORT pixman_bool_t
635 pixman_image_set_clip_region (pixman_image_t    *image,
636                               pixman_region16_t *region)
637 {
638     image_common_t *common = (image_common_t *)image;
639
640     if (region)
641     {
642         return pixman_region32_copy_from_region16 (&common->clip_region, region);
643     }
644     else
645     {
646         reset_clip_region (image);
647
648         return TRUE;
649     }
650 }
651
652 /* Sets whether the clip region includes a clip region set by the client
653  */
654 PIXMAN_EXPORT void
655 pixman_image_set_has_client_clip (pixman_image_t *image,
656                                   pixman_bool_t   client_clip)
657 {
658     image->common.has_client_clip = client_clip;
659 }
660
661 PIXMAN_EXPORT pixman_bool_t
662 pixman_image_set_transform (pixman_image_t           *image,
663                             const pixman_transform_t *transform)
664 {
665     static const pixman_transform_t id =
666     {
667         { { pixman_fixed_1, 0, 0 },
668           { 0, pixman_fixed_1, 0 },
669           { 0, 0, pixman_fixed_1 }
670         }
671     };
672
673     image_common_t *common = (image_common_t *)image;
674
675     if (common->transform == transform)
676         return TRUE;
677
678     if (memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
679     {
680         free(common->transform);
681         common->transform = NULL;
682         return TRUE;
683     }
684
685     if (common->transform == NULL)
686         common->transform = malloc (sizeof (pixman_transform_t));
687     if (common->transform == NULL)
688         return FALSE;
689
690     memcpy(common->transform, transform, sizeof(pixman_transform_t));
691
692     return TRUE;
693 }
694
695 PIXMAN_EXPORT void
696 pixman_image_set_repeat (pixman_image_t  *image,
697                          pixman_repeat_t  repeat)
698 {
699     image->common.repeat = repeat;
700 }
701
702 PIXMAN_EXPORT pixman_bool_t
703 pixman_image_set_filter (pixman_image_t       *image,
704                          pixman_filter_t       filter,
705                          const pixman_fixed_t *params,
706                          int                   n_params)
707 {
708     image_common_t *common = (image_common_t *)image;
709     pixman_fixed_t *new_params;
710
711     if (params == common->filter_params && filter == common->filter)
712         return TRUE;
713
714     new_params = NULL;
715     if (params)
716     {
717         new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t));
718         if (!new_params)
719             return FALSE;
720
721         memcpy (new_params,
722                 params, n_params * sizeof (pixman_fixed_t));
723     }
724
725     common->filter = filter;
726
727     if (common->filter_params)
728         free (common->filter_params);
729
730     common->filter_params = new_params;
731     common->n_filter_params = n_params;
732     return TRUE;
733 }
734
735 PIXMAN_EXPORT void
736 pixman_image_set_source_clipping (pixman_image_t  *image,
737                                   pixman_bool_t    source_clipping)
738 {
739     image_common_t *common = &image->common;
740
741     if (source_clipping)
742         common->src_clip = &common->clip_region;
743     else
744         common->src_clip = &common->full_region;
745 }
746
747 /* Unlike all the other property setters, this function does not
748  * copy the content of indexed. Doing this copying is simply
749  * way, way too expensive.
750  */
751 PIXMAN_EXPORT void
752 pixman_image_set_indexed (pixman_image_t         *image,
753                           const pixman_indexed_t *indexed)
754 {
755     bits_image_t *bits = (bits_image_t *)image;
756
757     bits->indexed = indexed;
758 }
759
760 PIXMAN_EXPORT void
761 pixman_image_set_alpha_map (pixman_image_t *image,
762                             pixman_image_t *alpha_map,
763                             int16_t         x,
764                             int16_t         y)
765 {
766     image_common_t *common = (image_common_t *)image;
767
768     return_if_fail (!alpha_map || alpha_map->type == BITS);
769
770     if (common->alpha_map != (bits_image_t *)alpha_map)
771     {
772         if (common->alpha_map)
773             pixman_image_unref ((pixman_image_t *)common->alpha_map);
774
775         if (alpha_map)
776             common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
777         else
778             common->alpha_map = NULL;
779     }
780
781     common->alpha_origin.x = x;
782     common->alpha_origin.y = y;
783 }
784
785 PIXMAN_EXPORT void
786 pixman_image_set_component_alpha   (pixman_image_t       *image,
787                                     pixman_bool_t         component_alpha)
788 {
789     image->common.component_alpha = component_alpha;
790 }
791
792
793 PIXMAN_EXPORT void
794 pixman_image_set_accessors (pixman_image_t             *image,
795                             pixman_read_memory_func_t   read_func,
796                             pixman_write_memory_func_t  write_func)
797 {
798     return_if_fail (image != NULL);
799
800     image->common.read_func = read_func;
801     image->common.write_func = write_func;
802 }
803
804 PIXMAN_EXPORT uint32_t *
805 pixman_image_get_data (pixman_image_t *image)
806 {
807     if (image->type == BITS)
808         return image->bits.bits;
809
810     return NULL;
811 }
812
813 PIXMAN_EXPORT int
814 pixman_image_get_width (pixman_image_t *image)
815 {
816     if (image->type == BITS)
817         return image->bits.width;
818
819     return 0;
820 }
821
822 PIXMAN_EXPORT int
823 pixman_image_get_height (pixman_image_t *image)
824 {
825     if (image->type == BITS)
826         return image->bits.height;
827
828     return 0;
829 }
830
831 PIXMAN_EXPORT int
832 pixman_image_get_stride (pixman_image_t *image)
833 {
834     if (image->type == BITS)
835         return image->bits.rowstride * (int) sizeof (uint32_t);
836
837     return 0;
838 }
839
840 PIXMAN_EXPORT int
841 pixman_image_get_depth (pixman_image_t *image)
842 {
843     if (image->type == BITS)
844         return PIXMAN_FORMAT_DEPTH (image->bits.format);
845
846     return 0;
847 }
848
849 static pixman_bool_t
850 color_to_pixel (pixman_color_t *color,
851                 uint32_t       *pixel,
852                 pixman_format_code_t format)
853 {
854     uint32_t c = color_to_uint32 (color);
855
856     if (!(format == PIXMAN_a8r8g8b8     ||
857           format == PIXMAN_x8r8g8b8     ||
858           format == PIXMAN_a8b8g8r8     ||
859           format == PIXMAN_x8b8g8r8     ||
860           format == PIXMAN_b8g8r8a8     ||
861           format == PIXMAN_b8g8r8x8     ||
862           format == PIXMAN_r5g6b5       ||
863           format == PIXMAN_b5g6r5       ||
864           format == PIXMAN_a8))
865     {
866         return FALSE;
867     }
868
869     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR)
870     {
871         c = ((c & 0xff000000) >>  0) |
872             ((c & 0x00ff0000) >> 16) |
873             ((c & 0x0000ff00) >>  0) |
874             ((c & 0x000000ff) << 16);
875     }
876     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA)
877     {
878         c = ((c & 0xff000000) >> 24) |
879             ((c & 0x00ff0000) >>  8) |
880             ((c & 0x0000ff00) <<  8) |
881             ((c & 0x000000ff) << 24);
882     }
883
884     if (format == PIXMAN_a8)
885         c = c >> 24;
886     else if (format == PIXMAN_r5g6b5 ||
887              format == PIXMAN_b5g6r5)
888         c = cvt8888to0565 (c);
889
890 #if 0
891     printf ("color: %x %x %x %x\n", color->alpha, color->red, color->green, color->blue);
892     printf ("pixel: %x\n", c);
893 #endif
894
895     *pixel = c;
896     return TRUE;
897 }
898
899 PIXMAN_EXPORT pixman_bool_t
900 pixman_image_fill_rectangles (pixman_op_t                   op,
901                               pixman_image_t               *dest,
902                               pixman_color_t               *color,
903                               int                           n_rects,
904                               const pixman_rectangle16_t   *rects)
905 {
906     pixman_image_t *solid;
907     pixman_color_t c;
908     int i;
909
910     if (color->alpha == 0xffff)
911     {
912         if (op == PIXMAN_OP_OVER)
913             op = PIXMAN_OP_SRC;
914     }
915
916     if (op == PIXMAN_OP_CLEAR)
917     {
918         c.red = 0;
919         c.green = 0;
920         c.blue = 0;
921         c.alpha = 0;
922
923         color = &c;
924
925         op = PIXMAN_OP_SRC;
926     }
927
928     if (op == PIXMAN_OP_SRC)
929     {
930         uint32_t pixel;
931
932         if (color_to_pixel (color, &pixel, dest->bits.format))
933         {
934             for (i = 0; i < n_rects; ++i)
935             {
936                 pixman_region32_t fill_region;
937                 int n_boxes, j;
938                 pixman_box32_t *boxes;
939
940                 pixman_region32_init_rect (&fill_region, rects[i].x, rects[i].y, rects[i].width, rects[i].height);
941                 if (!pixman_region32_intersect (&fill_region,
942                                                 &fill_region,
943                                                 &dest->common.clip_region))
944                     return FALSE;
945
946
947                 boxes = pixman_region32_rectangles (&fill_region, &n_boxes);
948                 for (j = 0; j < n_boxes; ++j)
949                 {
950                     const pixman_box32_t *box = &(boxes[j]);
951                     pixman_fill (dest->bits.bits, dest->bits.rowstride, PIXMAN_FORMAT_BPP (dest->bits.format),
952                                  box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1,
953                                  pixel);
954                 }
955
956                 pixman_region32_fini (&fill_region);
957             }
958             return TRUE;
959         }
960     }
961
962     solid = pixman_image_create_solid_fill (color);
963     if (!solid)
964         return FALSE;
965
966     for (i = 0; i < n_rects; ++i)
967     {
968         const pixman_rectangle16_t *rect = &(rects[i]);
969
970         pixman_image_composite (op, solid, NULL, dest,
971                                 0, 0, 0, 0,
972                                 rect->x, rect->y,
973                                 rect->width, rect->height);
974     }
975
976     pixman_image_unref (solid);
977
978     return TRUE;
979 }
980
981 pixman_bool_t
982 pixman_image_can_get_solid (pixman_image_t *image)
983 {
984     if (image->type == SOLID)
985         return TRUE;
986
987     if (image->type != BITS     ||
988         image->bits.width != 1  ||
989         image->bits.height != 1)
990     {
991         return FALSE;
992     }
993
994     if (image->common.repeat != PIXMAN_REPEAT_NORMAL)
995         return FALSE;
996
997     switch (image->bits.format)
998     {
999     case PIXMAN_a8r8g8b8:
1000     case PIXMAN_x8r8g8b8:
1001     case PIXMAN_a8b8g8r8:
1002     case PIXMAN_x8b8g8r8:
1003     case PIXMAN_b8g8r8a8:
1004     case PIXMAN_b8g8r8x8:
1005     case PIXMAN_r8g8b8:
1006     case PIXMAN_b8g8r8:
1007     case PIXMAN_r5g6b5:
1008     case PIXMAN_b5g6r5:
1009         return TRUE;
1010     default:
1011         return FALSE;
1012     }
1013 }
1014
1015 pixman_bool_t
1016 pixman_image_is_opaque(pixman_image_t *image)
1017 {
1018     int i = 0;
1019     int gradientNumberOfColors = 0;
1020
1021     if(image->common.alpha_map)
1022         return FALSE;
1023
1024     switch(image->type)
1025     {
1026     case BITS:
1027         if(PIXMAN_FORMAT_A(image->bits.format))
1028             return FALSE;
1029         break;
1030
1031     case LINEAR:
1032     case CONICAL:
1033     case RADIAL:
1034         gradientNumberOfColors = image->gradient.n_stops;
1035         i=0;
1036         while(i<gradientNumberOfColors)
1037         {
1038             if(image->gradient.stops[i].color.alpha != 0xffff)
1039                 return FALSE;
1040             i++;
1041         }
1042         break;
1043
1044     case SOLID:
1045          if(Alpha(image->solid.color) != 0xff)
1046             return FALSE;
1047         break;
1048     }
1049
1050     /* Convolution filters can introduce translucency if the sum of the weights
1051        is lower than 1. */
1052     if (image->common.filter == PIXMAN_FILTER_CONVOLUTION)
1053          return FALSE;
1054
1055     if (image->common.repeat == PIXMAN_REPEAT_NONE)
1056     {
1057         if (image->common.filter != PIXMAN_FILTER_NEAREST)
1058             return FALSE;
1059
1060         if (image->common.transform)
1061             return FALSE;
1062
1063         /* Gradients do not necessarily cover the entire compositing area */
1064         if (image->type == LINEAR || image->type == CONICAL || image->type == RADIAL)
1065             return FALSE;
1066     }
1067
1068      return TRUE;
1069 }