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