Add definitions of INT64_MIN and INT64_MAX
[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 #include <assert.h>
31
32 #include "pixman-private.h"
33
34 static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
35
36 static void
37 gradient_property_changed (pixman_image_t *image)
38 {
39     gradient_t *gradient = &image->gradient;
40     int n = gradient->n_stops;
41     pixman_gradient_stop_t *stops = gradient->stops;
42     pixman_gradient_stop_t *begin = &(gradient->stops[-1]);
43     pixman_gradient_stop_t *end = &(gradient->stops[n]);
44
45     switch (gradient->common.repeat)
46     {
47     default:
48     case PIXMAN_REPEAT_NONE:
49         begin->x = INT32_MIN;
50         begin->color = transparent_black;
51         end->x = INT32_MAX;
52         end->color = transparent_black;
53         break;
54
55     case PIXMAN_REPEAT_NORMAL:
56         begin->x = stops[n - 1].x - pixman_fixed_1;
57         begin->color = stops[n - 1].color;
58         end->x = stops[0].x + pixman_fixed_1;
59         end->color = stops[0].color;
60         break;
61
62     case PIXMAN_REPEAT_REFLECT:
63         begin->x = - stops[0].x;
64         begin->color = stops[0].color;
65         end->x = pixman_int_to_fixed (2) - stops[n - 1].x;
66         end->color = stops[n - 1].color;
67         break;
68
69     case PIXMAN_REPEAT_PAD:
70         begin->x = INT32_MIN;
71         begin->color = stops[0].color;
72         end->x = INT32_MAX;
73         end->color = stops[n - 1].color;
74         break;
75     }
76 }
77
78 pixman_bool_t
79 _pixman_init_gradient (gradient_t *                  gradient,
80                        const pixman_gradient_stop_t *stops,
81                        int                           n_stops)
82 {
83     return_val_if_fail (n_stops > 0, FALSE);
84
85     /* We allocate two extra stops, one before the beginning of the stop list,
86      * and one after the end. These stops are initialized to whatever color
87      * would be used for positions outside the range of the stop list.
88      *
89      * This saves a bit of computation in the gradient walker.
90      *
91      * The pointer we store in the gradient_t struct still points to the
92      * first user-supplied struct, so when freeing, we will have to
93      * subtract one.
94      */
95     gradient->stops =
96         pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t));
97     if (!gradient->stops)
98         return FALSE;
99
100     gradient->stops += 1;
101     memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t));
102     gradient->n_stops = n_stops;
103
104     gradient->common.property_changed = gradient_property_changed;
105
106     return TRUE;
107 }
108
109 void
110 _pixman_image_init (pixman_image_t *image)
111 {
112     image_common_t *common = &image->common;
113
114     pixman_region32_init (&common->clip_region);
115
116     common->alpha_count = 0;
117     common->have_clip_region = FALSE;
118     common->clip_sources = FALSE;
119     common->transform = NULL;
120     common->repeat = PIXMAN_REPEAT_NONE;
121     common->filter = PIXMAN_FILTER_NEAREST;
122     common->filter_params = NULL;
123     common->n_filter_params = 0;
124     common->alpha_map = NULL;
125     common->component_alpha = FALSE;
126     common->ref_count = 1;
127     common->property_changed = NULL;
128     common->client_clip = FALSE;
129     common->destroy_func = NULL;
130     common->destroy_data = NULL;
131     common->dirty = TRUE;
132 }
133
134 pixman_bool_t
135 _pixman_image_fini (pixman_image_t *image)
136 {
137     image_common_t *common = (image_common_t *)image;
138
139     common->ref_count--;
140
141     if (common->ref_count == 0)
142     {
143         if (image->common.destroy_func)
144             image->common.destroy_func (image, image->common.destroy_data);
145
146         pixman_region32_fini (&common->clip_region);
147
148         if (common->transform)
149             free (common->transform);
150
151         if (common->filter_params)
152             free (common->filter_params);
153
154         if (common->alpha_map)
155             pixman_image_unref ((pixman_image_t *)common->alpha_map);
156
157         if (image->type == LINEAR ||
158             image->type == RADIAL ||
159             image->type == CONICAL)
160         {
161             if (image->gradient.stops)
162             {
163                 /* See _pixman_init_gradient() for an explanation of the - 1 */
164                 free (image->gradient.stops - 1);
165             }
166
167             /* This will trigger if someone adds a property_changed
168              * method to the linear/radial/conical gradient overwriting
169              * the general one.
170              */
171             assert (
172                 image->common.property_changed == gradient_property_changed);
173         }
174
175         if (image->type == BITS && image->bits.free_me)
176             free (image->bits.free_me);
177
178         return TRUE;
179     }
180
181     return FALSE;
182 }
183
184 pixman_image_t *
185 _pixman_image_allocate (void)
186 {
187     pixman_image_t *image = malloc (sizeof (pixman_image_t));
188
189     if (image)
190         _pixman_image_init (image);
191
192     return image;
193 }
194
195 static void
196 image_property_changed (pixman_image_t *image)
197 {
198     image->common.dirty = TRUE;
199 }
200
201 /* Ref Counting */
202 PIXMAN_EXPORT pixman_image_t *
203 pixman_image_ref (pixman_image_t *image)
204 {
205     image->common.ref_count++;
206
207     return image;
208 }
209
210 /* returns TRUE when the image is freed */
211 PIXMAN_EXPORT pixman_bool_t
212 pixman_image_unref (pixman_image_t *image)
213 {
214     if (_pixman_image_fini (image))
215     {
216         free (image);
217         return TRUE;
218     }
219
220     return FALSE;
221 }
222
223 PIXMAN_EXPORT void
224 pixman_image_set_destroy_function (pixman_image_t *            image,
225                                    pixman_image_destroy_func_t func,
226                                    void *                      data)
227 {
228     image->common.destroy_func = func;
229     image->common.destroy_data = data;
230 }
231
232 PIXMAN_EXPORT void *
233 pixman_image_get_destroy_data (pixman_image_t *image)
234 {
235   return image->common.destroy_data;
236 }
237
238 void
239 _pixman_image_reset_clip_region (pixman_image_t *image)
240 {
241     image->common.have_clip_region = FALSE;
242 }
243
244 /* Executive Summary: This function is a no-op that only exists
245  * for historical reasons.
246  *
247  * There used to be a bug in the X server where it would rely on
248  * out-of-bounds accesses when it was asked to composite with a
249  * window as the source. It would create a pixman image pointing
250  * to some bogus position in memory, but then set a clip region
251  * to the position where the actual bits were.
252  *
253  * Due to a bug in old versions of pixman, where it would not clip
254  * against the image bounds when a clip region was set, this would
255  * actually work. So when the pixman bug was fixed, a workaround was
256  * added to allow certain out-of-bound accesses. This function disabled
257  * those workarounds.
258  *
259  * Since 0.21.2, pixman doesn't do these workarounds anymore, so now
260  * this function is a no-op.
261  */
262 PIXMAN_EXPORT void
263 pixman_disable_out_of_bounds_workaround (void)
264 {
265 }
266
267 static void
268 compute_image_info (pixman_image_t *image)
269 {
270     pixman_format_code_t code;
271     uint32_t flags = 0;
272
273     /* Transform */
274     if (!image->common.transform)
275     {
276         flags |= (FAST_PATH_ID_TRANSFORM        |
277                   FAST_PATH_X_UNIT_POSITIVE     |
278                   FAST_PATH_Y_UNIT_ZERO         |
279                   FAST_PATH_AFFINE_TRANSFORM);
280     }
281     else
282     {
283         flags |= FAST_PATH_HAS_TRANSFORM;
284
285         if (image->common.transform->matrix[2][0] == 0                  &&
286             image->common.transform->matrix[2][1] == 0                  &&
287             image->common.transform->matrix[2][2] == pixman_fixed_1)
288         {
289             flags |= FAST_PATH_AFFINE_TRANSFORM;
290
291             if (image->common.transform->matrix[0][1] == 0 &&
292                 image->common.transform->matrix[1][0] == 0)
293             {
294                 if (image->common.transform->matrix[0][0] == -pixman_fixed_1 &&
295                     image->common.transform->matrix[1][1] == -pixman_fixed_1)
296                 {
297                     flags |= FAST_PATH_ROTATE_180_TRANSFORM;
298                 }
299                 flags |= FAST_PATH_SCALE_TRANSFORM;
300             }
301             else if (image->common.transform->matrix[0][0] == 0 &&
302                      image->common.transform->matrix[1][1] == 0)
303             {
304                 pixman_fixed_t m01 = image->common.transform->matrix[0][1];
305                 if (m01 == -image->common.transform->matrix[1][0])
306                 {
307                         if (m01 == -pixman_fixed_1)
308                             flags |= FAST_PATH_ROTATE_90_TRANSFORM;
309                         else if (m01 == pixman_fixed_1)
310                             flags |= FAST_PATH_ROTATE_270_TRANSFORM;
311                 }
312             }
313         }
314
315         if (image->common.transform->matrix[0][0] > 0)
316             flags |= FAST_PATH_X_UNIT_POSITIVE;
317
318         if (image->common.transform->matrix[1][0] == 0)
319             flags |= FAST_PATH_Y_UNIT_ZERO;
320     }
321
322     /* Filter */
323     switch (image->common.filter)
324     {
325     case PIXMAN_FILTER_NEAREST:
326     case PIXMAN_FILTER_FAST:
327         flags |= (FAST_PATH_NEAREST_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
328         break;
329
330     case PIXMAN_FILTER_BILINEAR:
331     case PIXMAN_FILTER_GOOD:
332     case PIXMAN_FILTER_BEST:
333         flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
334
335         /* Here we have a chance to optimize BILINEAR filter to NEAREST if
336          * they are equivalent for the currently used transformation matrix.
337          */
338         if (flags & FAST_PATH_ID_TRANSFORM)
339         {
340             flags |= FAST_PATH_NEAREST_FILTER;
341         }
342         else if (
343             /* affine and integer translation components in matrix ... */
344             ((flags & FAST_PATH_AFFINE_TRANSFORM) &&
345              !pixman_fixed_frac (image->common.transform->matrix[0][2] |
346                                  image->common.transform->matrix[1][2])) &&
347             (
348                 /* ... combined with a simple rotation */
349                 (flags & (FAST_PATH_ROTATE_90_TRANSFORM |
350                           FAST_PATH_ROTATE_180_TRANSFORM |
351                           FAST_PATH_ROTATE_270_TRANSFORM)) ||
352                 /* ... or combined with a simple non-rotated translation */
353                 (image->common.transform->matrix[0][0] == pixman_fixed_1 &&
354                  image->common.transform->matrix[1][1] == pixman_fixed_1 &&
355                  image->common.transform->matrix[0][1] == 0 &&
356                  image->common.transform->matrix[1][0] == 0)
357                 )
358             )
359         {
360             /* FIXME: there are some affine-test failures, showing that
361              * handling of BILINEAR and NEAREST filter is not quite
362              * equivalent when getting close to 32K for the translation
363              * components of the matrix. That's likely some bug, but for
364              * now just skip BILINEAR->NEAREST optimization in this case.
365              */
366             pixman_fixed_t magic_limit = pixman_int_to_fixed (30000);
367             if (image->common.transform->matrix[0][2] <= magic_limit  &&
368                 image->common.transform->matrix[1][2] <= magic_limit  &&
369                 image->common.transform->matrix[0][2] >= -magic_limit &&
370                 image->common.transform->matrix[1][2] >= -magic_limit)
371             {
372                 flags |= FAST_PATH_NEAREST_FILTER;
373             }
374         }
375         break;
376
377     case PIXMAN_FILTER_CONVOLUTION:
378         break;
379
380     default:
381         flags |= FAST_PATH_NO_CONVOLUTION_FILTER;
382         break;
383     }
384
385     /* Repeat mode */
386     switch (image->common.repeat)
387     {
388     case PIXMAN_REPEAT_NONE:
389         flags |=
390             FAST_PATH_NO_REFLECT_REPEAT         |
391             FAST_PATH_NO_PAD_REPEAT             |
392             FAST_PATH_NO_NORMAL_REPEAT;
393         break;
394
395     case PIXMAN_REPEAT_REFLECT:
396         flags |=
397             FAST_PATH_NO_PAD_REPEAT             |
398             FAST_PATH_NO_NONE_REPEAT            |
399             FAST_PATH_NO_NORMAL_REPEAT;
400         break;
401
402     case PIXMAN_REPEAT_PAD:
403         flags |=
404             FAST_PATH_NO_REFLECT_REPEAT         |
405             FAST_PATH_NO_NONE_REPEAT            |
406             FAST_PATH_NO_NORMAL_REPEAT;
407         break;
408
409     default:
410         flags |=
411             FAST_PATH_NO_REFLECT_REPEAT         |
412             FAST_PATH_NO_PAD_REPEAT             |
413             FAST_PATH_NO_NONE_REPEAT;
414         break;
415     }
416
417     /* Component alpha */
418     if (image->common.component_alpha)
419         flags |= FAST_PATH_COMPONENT_ALPHA;
420     else
421         flags |= FAST_PATH_UNIFIED_ALPHA;
422
423     flags |= (FAST_PATH_NO_ACCESSORS | FAST_PATH_NARROW_FORMAT);
424
425     /* Type specific checks */
426     switch (image->type)
427     {
428     case SOLID:
429         code = PIXMAN_solid;
430
431         if (image->solid.color.alpha == 0xffff)
432             flags |= FAST_PATH_IS_OPAQUE;
433         break;
434
435     case BITS:
436         if (image->bits.width == 1      &&
437             image->bits.height == 1     &&
438             image->common.repeat != PIXMAN_REPEAT_NONE)
439         {
440             code = PIXMAN_solid;
441         }
442         else
443         {
444             code = image->bits.format;
445             flags |= FAST_PATH_BITS_IMAGE;
446         }
447
448         if (!PIXMAN_FORMAT_A (image->bits.format)                               &&
449             PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_GRAY         &&
450             PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_COLOR)
451         {
452             flags |= FAST_PATH_SAMPLES_OPAQUE;
453
454             if (image->common.repeat != PIXMAN_REPEAT_NONE)
455                 flags |= FAST_PATH_IS_OPAQUE;
456         }
457
458         if (image->bits.read_func || image->bits.write_func)
459             flags &= ~FAST_PATH_NO_ACCESSORS;
460
461         if (PIXMAN_FORMAT_IS_WIDE (image->bits.format))
462             flags &= ~FAST_PATH_NARROW_FORMAT;
463         break;
464
465     case RADIAL:
466         code = PIXMAN_unknown;
467
468         /*
469          * As explained in pixman-radial-gradient.c, every point of
470          * the plane has a valid associated radius (and thus will be
471          * colored) if and only if a is negative (i.e. one of the two
472          * circles contains the other one).
473          */
474
475         if (image->radial.a >= 0)
476             break;
477
478         /* Fall through */
479
480     case CONICAL:
481     case LINEAR:
482         code = PIXMAN_unknown;
483
484         if (image->common.repeat != PIXMAN_REPEAT_NONE)
485         {
486             int i;
487
488             flags |= FAST_PATH_IS_OPAQUE;
489             for (i = 0; i < image->gradient.n_stops; ++i)
490             {
491                 if (image->gradient.stops[i].color.alpha != 0xffff)
492                 {
493                     flags &= ~FAST_PATH_IS_OPAQUE;
494                     break;
495                 }
496             }
497         }
498         break;
499
500     default:
501         code = PIXMAN_unknown;
502         break;
503     }
504
505     /* Alpha map */
506     if (!image->common.alpha_map)
507     {
508         flags |= FAST_PATH_NO_ALPHA_MAP;
509     }
510     else
511     {
512         if (PIXMAN_FORMAT_IS_WIDE (image->common.alpha_map->format))
513             flags &= ~FAST_PATH_NARROW_FORMAT;
514     }
515
516     /* Both alpha maps and convolution filters can introduce
517      * non-opaqueness in otherwise opaque images. Also
518      * an image with component alpha turned on is only opaque
519      * if all channels are opaque, so we simply turn it off
520      * unconditionally for those images.
521      */
522     if (image->common.alpha_map                                 ||
523         image->common.filter == PIXMAN_FILTER_CONVOLUTION       ||
524         image->common.component_alpha)
525     {
526         flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE);
527     }
528
529     image->common.flags = flags;
530     image->common.extended_format_code = code;
531 }
532
533 void
534 _pixman_image_validate (pixman_image_t *image)
535 {
536     if (image->common.dirty)
537     {
538         compute_image_info (image);
539
540         /* It is important that property_changed is
541          * called *after* compute_image_info() because
542          * property_changed() can make use of the flags
543          * to set up accessors etc.
544          */
545         if (image->common.property_changed)
546             image->common.property_changed (image);
547
548         image->common.dirty = FALSE;
549     }
550
551     if (image->common.alpha_map)
552         _pixman_image_validate ((pixman_image_t *)image->common.alpha_map);
553 }
554
555 PIXMAN_EXPORT pixman_bool_t
556 pixman_image_set_clip_region32 (pixman_image_t *   image,
557                                 pixman_region32_t *region)
558 {
559     image_common_t *common = (image_common_t *)image;
560     pixman_bool_t result;
561
562     if (region)
563     {
564         if ((result = pixman_region32_copy (&common->clip_region, region)))
565             image->common.have_clip_region = TRUE;
566     }
567     else
568     {
569         _pixman_image_reset_clip_region (image);
570
571         result = TRUE;
572     }
573
574     image_property_changed (image);
575
576     return result;
577 }
578
579 PIXMAN_EXPORT pixman_bool_t
580 pixman_image_set_clip_region (pixman_image_t *   image,
581                               pixman_region16_t *region)
582 {
583     image_common_t *common = (image_common_t *)image;
584     pixman_bool_t result;
585
586     if (region)
587     {
588         if ((result = pixman_region32_copy_from_region16 (&common->clip_region, region)))
589             image->common.have_clip_region = TRUE;
590     }
591     else
592     {
593         _pixman_image_reset_clip_region (image);
594
595         result = TRUE;
596     }
597
598     image_property_changed (image);
599
600     return result;
601 }
602
603 PIXMAN_EXPORT void
604 pixman_image_set_has_client_clip (pixman_image_t *image,
605                                   pixman_bool_t   client_clip)
606 {
607     image->common.client_clip = client_clip;
608 }
609
610 PIXMAN_EXPORT pixman_bool_t
611 pixman_image_set_transform (pixman_image_t *          image,
612                             const pixman_transform_t *transform)
613 {
614     static const pixman_transform_t id =
615     {
616         { { pixman_fixed_1, 0, 0 },
617           { 0, pixman_fixed_1, 0 },
618           { 0, 0, pixman_fixed_1 } }
619     };
620
621     image_common_t *common = (image_common_t *)image;
622     pixman_bool_t result;
623
624     if (common->transform == transform)
625         return TRUE;
626
627     if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
628     {
629         free (common->transform);
630         common->transform = NULL;
631         result = TRUE;
632
633         goto out;
634     }
635
636     if (common->transform &&
637         memcmp (common->transform, transform, sizeof (pixman_transform_t) == 0))
638     {
639         return TRUE;
640     }
641
642     if (common->transform == NULL)
643         common->transform = malloc (sizeof (pixman_transform_t));
644
645     if (common->transform == NULL)
646     {
647         result = FALSE;
648
649         goto out;
650     }
651
652     memcpy (common->transform, transform, sizeof(pixman_transform_t));
653
654     result = TRUE;
655
656 out:
657     image_property_changed (image);
658
659     return result;
660 }
661
662 PIXMAN_EXPORT void
663 pixman_image_set_repeat (pixman_image_t *image,
664                          pixman_repeat_t repeat)
665 {
666     if (image->common.repeat == repeat)
667         return;
668
669     image->common.repeat = repeat;
670
671     image_property_changed (image);
672 }
673
674 PIXMAN_EXPORT pixman_bool_t
675 pixman_image_set_filter (pixman_image_t *      image,
676                          pixman_filter_t       filter,
677                          const pixman_fixed_t *params,
678                          int                   n_params)
679 {
680     image_common_t *common = (image_common_t *)image;
681     pixman_fixed_t *new_params;
682
683     if (params == common->filter_params && filter == common->filter)
684         return TRUE;
685
686     new_params = NULL;
687     if (params)
688     {
689         new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t));
690         if (!new_params)
691             return FALSE;
692
693         memcpy (new_params,
694                 params, n_params * sizeof (pixman_fixed_t));
695     }
696
697     common->filter = filter;
698
699     if (common->filter_params)
700         free (common->filter_params);
701
702     common->filter_params = new_params;
703     common->n_filter_params = n_params;
704
705     image_property_changed (image);
706     return TRUE;
707 }
708
709 PIXMAN_EXPORT void
710 pixman_image_set_source_clipping (pixman_image_t *image,
711                                   pixman_bool_t   clip_sources)
712 {
713     if (image->common.clip_sources == clip_sources)
714         return;
715
716     image->common.clip_sources = clip_sources;
717
718     image_property_changed (image);
719 }
720
721 /* Unlike all the other property setters, this function does not
722  * copy the content of indexed. Doing this copying is simply
723  * way, way too expensive.
724  */
725 PIXMAN_EXPORT void
726 pixman_image_set_indexed (pixman_image_t *        image,
727                           const pixman_indexed_t *indexed)
728 {
729     bits_image_t *bits = (bits_image_t *)image;
730
731     if (bits->indexed == indexed)
732         return;
733
734     bits->indexed = indexed;
735
736     image_property_changed (image);
737 }
738
739 PIXMAN_EXPORT void
740 pixman_image_set_alpha_map (pixman_image_t *image,
741                             pixman_image_t *alpha_map,
742                             int16_t         x,
743                             int16_t         y)
744 {
745     image_common_t *common = (image_common_t *)image;
746
747     return_if_fail (!alpha_map || alpha_map->type == BITS);
748
749     if (alpha_map && common->alpha_count > 0)
750     {
751         /* If this image is being used as an alpha map itself,
752          * then you can't give it an alpha map of its own.
753          */
754         return;
755     }
756
757     if (alpha_map && alpha_map->common.alpha_map)
758     {
759         /* If the image has an alpha map of its own,
760          * then it can't be used as an alpha map itself
761          */
762         return;
763     }
764
765     if (common->alpha_map != (bits_image_t *)alpha_map)
766     {
767         if (common->alpha_map)
768         {
769             common->alpha_map->common.alpha_count--;
770
771             pixman_image_unref ((pixman_image_t *)common->alpha_map);
772         }
773
774         if (alpha_map)
775         {
776             common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
777
778             common->alpha_map->common.alpha_count++;
779         }
780         else
781         {
782             common->alpha_map = NULL;
783         }
784     }
785
786     common->alpha_origin_x = x;
787     common->alpha_origin_y = y;
788
789     image_property_changed (image);
790 }
791
792 PIXMAN_EXPORT void
793 pixman_image_set_component_alpha   (pixman_image_t *image,
794                                     pixman_bool_t   component_alpha)
795 {
796     if (image->common.component_alpha == component_alpha)
797         return;
798
799     image->common.component_alpha = component_alpha;
800
801     image_property_changed (image);
802 }
803
804 PIXMAN_EXPORT pixman_bool_t
805 pixman_image_get_component_alpha   (pixman_image_t       *image)
806 {
807     return image->common.component_alpha;
808 }
809
810 PIXMAN_EXPORT void
811 pixman_image_set_accessors (pixman_image_t *           image,
812                             pixman_read_memory_func_t  read_func,
813                             pixman_write_memory_func_t write_func)
814 {
815     return_if_fail (image != NULL);
816
817     if (image->type == BITS)
818     {
819         image->bits.read_func = read_func;
820         image->bits.write_func = write_func;
821
822         image_property_changed (image);
823     }
824 }
825
826 PIXMAN_EXPORT uint32_t *
827 pixman_image_get_data (pixman_image_t *image)
828 {
829     if (image->type == BITS)
830         return image->bits.bits;
831
832     return NULL;
833 }
834
835 PIXMAN_EXPORT int
836 pixman_image_get_width (pixman_image_t *image)
837 {
838     if (image->type == BITS)
839         return image->bits.width;
840
841     return 0;
842 }
843
844 PIXMAN_EXPORT int
845 pixman_image_get_height (pixman_image_t *image)
846 {
847     if (image->type == BITS)
848         return image->bits.height;
849
850     return 0;
851 }
852
853 PIXMAN_EXPORT int
854 pixman_image_get_stride (pixman_image_t *image)
855 {
856     if (image->type == BITS)
857         return image->bits.rowstride * (int) sizeof (uint32_t);
858
859     return 0;
860 }
861
862 PIXMAN_EXPORT int
863 pixman_image_get_depth (pixman_image_t *image)
864 {
865     if (image->type == BITS)
866         return PIXMAN_FORMAT_DEPTH (image->bits.format);
867
868     return 0;
869 }
870
871 PIXMAN_EXPORT pixman_format_code_t
872 pixman_image_get_format (pixman_image_t *image)
873 {
874     if (image->type == BITS)
875         return image->bits.format;
876
877     return 0;
878 }
879
880 uint32_t
881 _pixman_image_get_solid (pixman_implementation_t *imp,
882                          pixman_image_t *         image,
883                          pixman_format_code_t     format)
884 {
885     uint32_t result;
886     pixman_iter_t iter;
887
888     _pixman_implementation_src_iter_init (
889         imp, &iter, image, 0, 0, 1, 1,
890         (uint8_t *)&result, ITER_NARROW);
891
892     result = *iter.get_scanline (&iter, NULL);
893
894     /* If necessary, convert RGB <--> BGR. */
895     if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB)
896     {
897         result = (((result & 0xff000000) >>  0) |
898                   ((result & 0x00ff0000) >> 16) |
899                   ((result & 0x0000ff00) >>  0) |
900                   ((result & 0x000000ff) << 16));
901     }
902
903     return result;
904 }