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