Move store logic into pixman-image.c
[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 #define WRITE_ACCESS(f) ((image->common.write_func)? f##_accessors : f)
278
279 static void
280 fbStore(bits_image_t * image, int x, int y, int width, uint32_t *buffer)
281 {
282     uint32_t *bits;
283     int32_t stride;
284     storeProc32 store = WRITE_ACCESS(pixman_storeProcForPicture32)(image);
285     const pixman_indexed_t * indexed = image->indexed;
286
287     bits = image->bits;
288     stride = image->rowstride;
289     bits += y*stride;
290     store((pixman_image_t *)image, bits, buffer, x, width, indexed);
291 }
292
293 static void
294 fbStore64(bits_image_t * image, int x, int y, int width, uint64_t *buffer)
295 {
296     uint32_t *bits;
297     int32_t stride;
298     storeProc64 store = WRITE_ACCESS(pixman_storeProcForPicture64)(image);
299     const pixman_indexed_t * indexed = image->indexed;
300
301     bits = image->bits;
302     stride = image->rowstride;
303     bits += y*stride;
304     store((pixman_image_t *)image, bits, buffer, x, width, indexed);
305 }
306
307 scanStoreProc
308 _pixman_image_get_storer (pixman_image_t *image,
309                           int             wide)
310 {
311     if (image->common.alpha_map)
312     {
313         if (wide)
314             return (scanStoreProc)WRITE_ACCESS(fbStoreExternalAlpha64);
315         else
316             return (scanStoreProc)WRITE_ACCESS(fbStoreExternalAlpha);
317     }
318     else
319     {
320         if (wide)
321             return (scanStoreProc)fbStore64;
322         else
323             return (scanStoreProc)fbStore;
324     }
325 }
326
327 /* Ref Counting */
328 PIXMAN_EXPORT pixman_image_t *
329 pixman_image_ref (pixman_image_t *image)
330 {
331     image->common.ref_count++;
332
333     return image;
334 }
335
336 /* returns TRUE when the image is freed */
337 PIXMAN_EXPORT pixman_bool_t
338 pixman_image_unref (pixman_image_t *image)
339 {
340     image_common_t *common = (image_common_t *)image;
341
342     common->ref_count--;
343
344     if (common->ref_count == 0)
345     {
346         pixman_region32_fini (&common->clip_region);
347         pixman_region32_fini (&common->full_region);
348
349         if (common->transform)
350             free (common->transform);
351
352         if (common->filter_params)
353             free (common->filter_params);
354
355         if (common->alpha_map)
356             pixman_image_unref ((pixman_image_t *)common->alpha_map);
357
358 #if 0
359         if (image->type == BITS && image->bits.indexed)
360             free (image->bits.indexed);
361 #endif
362
363 #if 0
364         memset (image, 0xaa, sizeof (pixman_image_t));
365 #endif
366         if (image->type == LINEAR || image->type == RADIAL || image->type == CONICAL)
367         {
368             if (image->gradient.stops)
369                 free (image->gradient.stops);
370         }
371
372
373         if (image->type == BITS && image->bits.free_me)
374             free (image->bits.free_me);
375
376         free (image);
377
378         return TRUE;
379     }
380
381     return FALSE;
382 }
383
384 /* Constructors */
385 PIXMAN_EXPORT pixman_image_t *
386 pixman_image_create_solid_fill (pixman_color_t *color)
387 {
388     pixman_image_t *img = allocate_image();
389     if (!img)
390         return NULL;
391
392     init_source_image (&img->solid.common);
393
394     img->type = SOLID;
395     img->solid.color = color_to_uint32 (color);
396
397     return img;
398 }
399
400 PIXMAN_EXPORT pixman_image_t *
401 pixman_image_create_linear_gradient (pixman_point_fixed_t         *p1,
402                                      pixman_point_fixed_t         *p2,
403                                      const pixman_gradient_stop_t *stops,
404                                      int                           n_stops)
405 {
406     pixman_image_t *image;
407     linear_gradient_t *linear;
408
409     return_val_if_fail (n_stops >= 2, NULL);
410
411     image = allocate_image();
412
413     if (!image)
414         return NULL;
415
416     linear = &image->linear;
417
418     if (!init_gradient (&linear->common, stops, n_stops))
419     {
420         free (image);
421         return NULL;
422     }
423
424     linear->p1 = *p1;
425     linear->p2 = *p2;
426
427     image->type = LINEAR;
428
429     return image;
430 }
431
432
433 PIXMAN_EXPORT pixman_image_t *
434 pixman_image_create_radial_gradient (pixman_point_fixed_t         *inner,
435                                      pixman_point_fixed_t         *outer,
436                                      pixman_fixed_t                inner_radius,
437                                      pixman_fixed_t                outer_radius,
438                                      const pixman_gradient_stop_t *stops,
439                                      int                           n_stops)
440 {
441     pixman_image_t *image;
442     radial_gradient_t *radial;
443
444     return_val_if_fail (n_stops >= 2, NULL);
445
446     image = allocate_image();
447
448     if (!image)
449         return NULL;
450
451     radial = &image->radial;
452
453     if (!init_gradient (&radial->common, stops, n_stops))
454     {
455         free (image);
456         return NULL;
457     }
458
459     image->type = RADIAL;
460
461     radial->c1.x = inner->x;
462     radial->c1.y = inner->y;
463     radial->c1.radius = inner_radius;
464     radial->c2.x = outer->x;
465     radial->c2.y = outer->y;
466     radial->c2.radius = outer_radius;
467     radial->cdx = pixman_fixed_to_double (radial->c2.x - radial->c1.x);
468     radial->cdy = pixman_fixed_to_double (radial->c2.y - radial->c1.y);
469     radial->dr = pixman_fixed_to_double (radial->c2.radius - radial->c1.radius);
470     radial->A = (radial->cdx * radial->cdx
471                  + radial->cdy * radial->cdy
472                  - radial->dr  * radial->dr);
473
474     return image;
475 }
476
477 PIXMAN_EXPORT pixman_image_t *
478 pixman_image_create_conical_gradient (pixman_point_fixed_t *center,
479                                       pixman_fixed_t angle,
480                                       const pixman_gradient_stop_t *stops,
481                                       int n_stops)
482 {
483     pixman_image_t *image = allocate_image();
484     conical_gradient_t *conical;
485
486     if (!image)
487         return NULL;
488
489     conical = &image->conical;
490
491     if (!init_gradient (&conical->common, stops, n_stops))
492     {
493         free (image);
494         return NULL;
495     }
496
497     image->type = CONICAL;
498     conical->center = *center;
499     conical->angle = angle;
500
501     return image;
502 }
503
504 static uint32_t *
505 create_bits (pixman_format_code_t format,
506              int                  width,
507              int                  height,
508              int                 *rowstride_bytes)
509 {
510     int stride;
511     int buf_size;
512     int bpp;
513
514     /* what follows is a long-winded way, avoiding any possibility of integer
515      * overflows, of saying:
516      * stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (uint32_t);
517      */
518
519     bpp = PIXMAN_FORMAT_BPP (format);
520     if (pixman_multiply_overflows_int (width, bpp))
521         return NULL;
522
523     stride = width * bpp;
524     if (pixman_addition_overflows_int (stride, FB_MASK))
525         return NULL;
526
527     stride += FB_MASK;
528     stride >>= FB_SHIFT;
529
530 #if FB_SHIFT < 2
531     if (pixman_multiply_overflows_int (stride, sizeof (uint32_t)))
532         return NULL;
533 #endif
534     stride *= sizeof (uint32_t);
535
536     if (pixman_multiply_overflows_int (height, stride))
537         return NULL;
538
539     buf_size = height * stride;
540
541     if (rowstride_bytes)
542         *rowstride_bytes = stride;
543
544     return calloc (buf_size, 1);
545 }
546
547 static void
548 reset_clip_region (pixman_image_t *image)
549 {
550     pixman_region32_fini (&image->common.clip_region);
551
552     if (image->type == BITS)
553     {
554         pixman_region32_init_rect (&image->common.clip_region, 0, 0,
555                                    image->bits.width, image->bits.height);
556     }
557     else
558     {
559         pixman_region32_init (&image->common.clip_region);
560     }
561 }
562
563 PIXMAN_EXPORT pixman_image_t *
564 pixman_image_create_bits (pixman_format_code_t  format,
565                           int                   width,
566                           int                   height,
567                           uint32_t             *bits,
568                           int                   rowstride_bytes)
569 {
570     pixman_image_t *image;
571     uint32_t *free_me = NULL;
572
573     /* must be a whole number of uint32_t's
574      */
575     return_val_if_fail (bits == NULL ||
576                         (rowstride_bytes % sizeof (uint32_t)) == 0, NULL);
577
578     if (!bits && width && height)
579     {
580         free_me = bits = create_bits (format, width, height, &rowstride_bytes);
581         if (!bits)
582             return NULL;
583     }
584
585     image = allocate_image();
586
587     if (!image) {
588         if (free_me)
589             free (free_me);
590         return NULL;
591     }
592     
593     image->type = BITS;
594     image->bits.format = format;
595     image->bits.width = width;
596     image->bits.height = height;
597     image->bits.bits = bits;
598     image->bits.free_me = free_me;
599
600     image->bits.rowstride = rowstride_bytes / (int) sizeof (uint32_t); /* we store it in number
601                                                                   * of uint32_t's
602                                                                   */
603     image->bits.indexed = NULL;
604
605     pixman_region32_fini (&image->common.full_region);
606     pixman_region32_init_rect (&image->common.full_region, 0, 0,
607                                image->bits.width, image->bits.height);
608
609     reset_clip_region (image);
610     return image;
611 }
612
613 PIXMAN_EXPORT pixman_bool_t
614 pixman_image_set_clip_region32 (pixman_image_t *image,
615                                 pixman_region32_t *region)
616 {
617     image_common_t *common = (image_common_t *)image;
618
619     if (region)
620     {
621         return pixman_region32_copy (&common->clip_region, region);
622     }
623     else
624     {
625         reset_clip_region (image);
626
627         return TRUE;
628     }
629 }
630
631
632 PIXMAN_EXPORT pixman_bool_t
633 pixman_image_set_clip_region (pixman_image_t    *image,
634                               pixman_region16_t *region)
635 {
636     image_common_t *common = (image_common_t *)image;
637
638     if (region)
639     {
640         return pixman_region32_copy_from_region16 (&common->clip_region, region);
641     }
642     else
643     {
644         reset_clip_region (image);
645
646         return TRUE;
647     }
648 }
649
650 /* Sets whether the clip region includes a clip region set by the client
651  */
652 PIXMAN_EXPORT void
653 pixman_image_set_has_client_clip (pixman_image_t *image,
654                                   pixman_bool_t   client_clip)
655 {
656     image->common.has_client_clip = client_clip;
657 }
658
659 PIXMAN_EXPORT pixman_bool_t
660 pixman_image_set_transform (pixman_image_t           *image,
661                             const pixman_transform_t *transform)
662 {
663     static const pixman_transform_t id =
664     {
665         { { pixman_fixed_1, 0, 0 },
666           { 0, pixman_fixed_1, 0 },
667           { 0, 0, pixman_fixed_1 }
668         }
669     };
670
671     image_common_t *common = (image_common_t *)image;
672
673     if (common->transform == transform)
674         return TRUE;
675
676     if (memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
677     {
678         free(common->transform);
679         common->transform = NULL;
680         return TRUE;
681     }
682
683     if (common->transform == NULL)
684         common->transform = malloc (sizeof (pixman_transform_t));
685     if (common->transform == NULL)
686         return FALSE;
687
688     memcpy(common->transform, transform, sizeof(pixman_transform_t));
689
690     return TRUE;
691 }
692
693 PIXMAN_EXPORT void
694 pixman_image_set_repeat (pixman_image_t  *image,
695                          pixman_repeat_t  repeat)
696 {
697     image->common.repeat = repeat;
698 }
699
700 PIXMAN_EXPORT pixman_bool_t
701 pixman_image_set_filter (pixman_image_t       *image,
702                          pixman_filter_t       filter,
703                          const pixman_fixed_t *params,
704                          int                   n_params)
705 {
706     image_common_t *common = (image_common_t *)image;
707     pixman_fixed_t *new_params;
708
709     if (params == common->filter_params && filter == common->filter)
710         return TRUE;
711
712     new_params = NULL;
713     if (params)
714     {
715         new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t));
716         if (!new_params)
717             return FALSE;
718
719         memcpy (new_params,
720                 params, n_params * sizeof (pixman_fixed_t));
721     }
722
723     common->filter = filter;
724
725     if (common->filter_params)
726         free (common->filter_params);
727
728     common->filter_params = new_params;
729     common->n_filter_params = n_params;
730     return TRUE;
731 }
732
733 PIXMAN_EXPORT void
734 pixman_image_set_source_clipping (pixman_image_t  *image,
735                                   pixman_bool_t    source_clipping)
736 {
737     image_common_t *common = &image->common;
738
739     if (source_clipping)
740         common->src_clip = &common->clip_region;
741     else
742         common->src_clip = &common->full_region;
743 }
744
745 /* Unlike all the other property setters, this function does not
746  * copy the content of indexed. Doing this copying is simply
747  * way, way too expensive.
748  */
749 PIXMAN_EXPORT void
750 pixman_image_set_indexed (pixman_image_t         *image,
751                           const pixman_indexed_t *indexed)
752 {
753     bits_image_t *bits = (bits_image_t *)image;
754
755     bits->indexed = indexed;
756 }
757
758 PIXMAN_EXPORT void
759 pixman_image_set_alpha_map (pixman_image_t *image,
760                             pixman_image_t *alpha_map,
761                             int16_t         x,
762                             int16_t         y)
763 {
764     image_common_t *common = (image_common_t *)image;
765
766     return_if_fail (!alpha_map || alpha_map->type == BITS);
767
768     if (common->alpha_map != (bits_image_t *)alpha_map)
769     {
770         if (common->alpha_map)
771             pixman_image_unref ((pixman_image_t *)common->alpha_map);
772
773         if (alpha_map)
774             common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
775         else
776             common->alpha_map = NULL;
777     }
778
779     common->alpha_origin.x = x;
780     common->alpha_origin.y = y;
781 }
782
783 PIXMAN_EXPORT void
784 pixman_image_set_component_alpha   (pixman_image_t       *image,
785                                     pixman_bool_t         component_alpha)
786 {
787     image->common.component_alpha = component_alpha;
788 }
789
790
791 PIXMAN_EXPORT void
792 pixman_image_set_accessors (pixman_image_t             *image,
793                             pixman_read_memory_func_t   read_func,
794                             pixman_write_memory_func_t  write_func)
795 {
796     return_if_fail (image != NULL);
797
798     image->common.read_func = read_func;
799     image->common.write_func = write_func;
800 }
801
802 PIXMAN_EXPORT uint32_t *
803 pixman_image_get_data (pixman_image_t *image)
804 {
805     if (image->type == BITS)
806         return image->bits.bits;
807
808     return NULL;
809 }
810
811 PIXMAN_EXPORT int
812 pixman_image_get_width (pixman_image_t *image)
813 {
814     if (image->type == BITS)
815         return image->bits.width;
816
817     return 0;
818 }
819
820 PIXMAN_EXPORT int
821 pixman_image_get_height (pixman_image_t *image)
822 {
823     if (image->type == BITS)
824         return image->bits.height;
825
826     return 0;
827 }
828
829 PIXMAN_EXPORT int
830 pixman_image_get_stride (pixman_image_t *image)
831 {
832     if (image->type == BITS)
833         return image->bits.rowstride * (int) sizeof (uint32_t);
834
835     return 0;
836 }
837
838 PIXMAN_EXPORT int
839 pixman_image_get_depth (pixman_image_t *image)
840 {
841     if (image->type == BITS)
842         return PIXMAN_FORMAT_DEPTH (image->bits.format);
843
844     return 0;
845 }
846
847 static pixman_bool_t
848 color_to_pixel (pixman_color_t *color,
849                 uint32_t       *pixel,
850                 pixman_format_code_t format)
851 {
852     uint32_t c = color_to_uint32 (color);
853
854     if (!(format == PIXMAN_a8r8g8b8     ||
855           format == PIXMAN_x8r8g8b8     ||
856           format == PIXMAN_a8b8g8r8     ||
857           format == PIXMAN_x8b8g8r8     ||
858           format == PIXMAN_b8g8r8a8     ||
859           format == PIXMAN_b8g8r8x8     ||
860           format == PIXMAN_r5g6b5       ||
861           format == PIXMAN_b5g6r5       ||
862           format == PIXMAN_a8))
863     {
864         return FALSE;
865     }
866
867     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR)
868     {
869         c = ((c & 0xff000000) >>  0) |
870             ((c & 0x00ff0000) >> 16) |
871             ((c & 0x0000ff00) >>  0) |
872             ((c & 0x000000ff) << 16);
873     }
874     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA)
875     {
876         c = ((c & 0xff000000) >> 24) |
877             ((c & 0x00ff0000) >>  8) |
878             ((c & 0x0000ff00) <<  8) |
879             ((c & 0x000000ff) << 24);
880     }
881
882     if (format == PIXMAN_a8)
883         c = c >> 24;
884     else if (format == PIXMAN_r5g6b5 ||
885              format == PIXMAN_b5g6r5)
886         c = cvt8888to0565 (c);
887
888 #if 0
889     printf ("color: %x %x %x %x\n", color->alpha, color->red, color->green, color->blue);
890     printf ("pixel: %x\n", c);
891 #endif
892
893     *pixel = c;
894     return TRUE;
895 }
896
897 PIXMAN_EXPORT pixman_bool_t
898 pixman_image_fill_rectangles (pixman_op_t                   op,
899                               pixman_image_t               *dest,
900                               pixman_color_t               *color,
901                               int                           n_rects,
902                               const pixman_rectangle16_t   *rects)
903 {
904     pixman_image_t *solid;
905     pixman_color_t c;
906     int i;
907
908     if (color->alpha == 0xffff)
909     {
910         if (op == PIXMAN_OP_OVER)
911             op = PIXMAN_OP_SRC;
912     }
913
914     if (op == PIXMAN_OP_CLEAR)
915     {
916         c.red = 0;
917         c.green = 0;
918         c.blue = 0;
919         c.alpha = 0;
920
921         color = &c;
922
923         op = PIXMAN_OP_SRC;
924     }
925
926     if (op == PIXMAN_OP_SRC)
927     {
928         uint32_t pixel;
929
930         if (color_to_pixel (color, &pixel, dest->bits.format))
931         {
932             for (i = 0; i < n_rects; ++i)
933             {
934                 pixman_region32_t fill_region;
935                 int n_boxes, j;
936                 pixman_box32_t *boxes;
937
938                 pixman_region32_init_rect (&fill_region, rects[i].x, rects[i].y, rects[i].width, rects[i].height);
939                 if (!pixman_region32_intersect (&fill_region,
940                                                 &fill_region,
941                                                 &dest->common.clip_region))
942                     return FALSE;
943
944
945                 boxes = pixman_region32_rectangles (&fill_region, &n_boxes);
946                 for (j = 0; j < n_boxes; ++j)
947                 {
948                     const pixman_box32_t *box = &(boxes[j]);
949                     pixman_fill (dest->bits.bits, dest->bits.rowstride, PIXMAN_FORMAT_BPP (dest->bits.format),
950                                  box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1,
951                                  pixel);
952                 }
953
954                 pixman_region32_fini (&fill_region);
955             }
956             return TRUE;
957         }
958     }
959
960     solid = pixman_image_create_solid_fill (color);
961     if (!solid)
962         return FALSE;
963
964     for (i = 0; i < n_rects; ++i)
965     {
966         const pixman_rectangle16_t *rect = &(rects[i]);
967
968         pixman_image_composite (op, solid, NULL, dest,
969                                 0, 0, 0, 0,
970                                 rect->x, rect->y,
971                                 rect->width, rect->height);
972     }
973
974     pixman_image_unref (solid);
975
976     return TRUE;
977 }
978
979 pixman_bool_t
980 pixman_image_can_get_solid (pixman_image_t *image)
981 {
982     if (image->type == SOLID)
983         return TRUE;
984
985     if (image->type != BITS     ||
986         image->bits.width != 1  ||
987         image->bits.height != 1)
988     {
989         return FALSE;
990     }
991
992     if (image->common.repeat != PIXMAN_REPEAT_NORMAL)
993         return FALSE;
994
995     switch (image->bits.format)
996     {
997     case PIXMAN_a8r8g8b8:
998     case PIXMAN_x8r8g8b8:
999     case PIXMAN_a8b8g8r8:
1000     case PIXMAN_x8b8g8r8:
1001     case PIXMAN_b8g8r8a8:
1002     case PIXMAN_b8g8r8x8:
1003     case PIXMAN_r8g8b8:
1004     case PIXMAN_b8g8r8:
1005     case PIXMAN_r5g6b5:
1006     case PIXMAN_b5g6r5:
1007         return TRUE;
1008     default:
1009         return FALSE;
1010     }
1011 }
1012
1013 pixman_bool_t
1014 pixman_image_is_opaque(pixman_image_t *image)
1015 {
1016     int i = 0;
1017     int gradientNumberOfColors = 0;
1018
1019     if(image->common.alpha_map)
1020         return FALSE;
1021
1022     switch(image->type)
1023     {
1024     case BITS:
1025         if(PIXMAN_FORMAT_A(image->bits.format))
1026             return FALSE;
1027         break;
1028
1029     case LINEAR:
1030     case CONICAL:
1031     case RADIAL:
1032         gradientNumberOfColors = image->gradient.n_stops;
1033         i=0;
1034         while(i<gradientNumberOfColors)
1035         {
1036             if(image->gradient.stops[i].color.alpha != 0xffff)
1037                 return FALSE;
1038             i++;
1039         }
1040         break;
1041
1042     case SOLID:
1043          if(Alpha(image->solid.color) != 0xff)
1044             return FALSE;
1045         break;
1046     }
1047
1048     /* Convolution filters can introduce translucency if the sum of the weights
1049        is lower than 1. */
1050     if (image->common.filter == PIXMAN_FILTER_CONVOLUTION)
1051          return FALSE;
1052
1053     if (image->common.repeat == PIXMAN_REPEAT_NONE)
1054     {
1055         if (image->common.filter != PIXMAN_FILTER_NEAREST)
1056             return FALSE;
1057
1058         if (image->common.transform)
1059             return FALSE;
1060
1061         /* Gradients do not necessarily cover the entire compositing area */
1062         if (image->type == LINEAR || image->type == CONICAL || image->type == RADIAL)
1063             return FALSE;
1064     }
1065
1066      return TRUE;
1067 }