Line data Source code
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
43 132 : free_memory (void** p)
44 : {
45 : #ifdef PIXMAN_POISON
46 : if (*p) {
47 : #endif
48 132 : free (*p);
49 : #ifdef PIXMAN_POISON
50 : *p = NULL;
51 : }
52 : #endif
53 132 : }
54 :
55 : static void
56 0 : gradient_property_changed (pixman_image_t *image)
57 : {
58 0 : gradient_t *gradient = &image->gradient;
59 0 : int n = gradient->n_stops;
60 0 : pixman_gradient_stop_t *stops = gradient->stops;
61 0 : pixman_gradient_stop_t *begin = &(gradient->stops[-1]);
62 0 : pixman_gradient_stop_t *end = &(gradient->stops[n]);
63 :
64 0 : switch (gradient->common.repeat)
65 : {
66 : default:
67 : case PIXMAN_REPEAT_NONE:
68 0 : begin->x = INT32_MIN;
69 0 : begin->color = transparent_black;
70 0 : end->x = INT32_MAX;
71 0 : end->color = transparent_black;
72 0 : break;
73 :
74 : case PIXMAN_REPEAT_NORMAL:
75 0 : begin->x = stops[n - 1].x - pixman_fixed_1;
76 0 : begin->color = stops[n - 1].color;
77 0 : end->x = stops[0].x + pixman_fixed_1;
78 0 : end->color = stops[0].color;
79 0 : break;
80 :
81 : case PIXMAN_REPEAT_REFLECT:
82 0 : begin->x = - stops[0].x;
83 0 : begin->color = stops[0].color;
84 0 : end->x = pixman_int_to_fixed (2) - stops[n - 1].x;
85 0 : end->color = stops[n - 1].color;
86 0 : break;
87 :
88 : case PIXMAN_REPEAT_PAD:
89 0 : begin->x = INT32_MIN;
90 0 : begin->color = stops[0].color;
91 0 : end->x = INT32_MAX;
92 0 : end->color = stops[n - 1].color;
93 0 : break;
94 : }
95 0 : }
96 :
97 : pixman_bool_t
98 0 : _pixman_init_gradient (gradient_t * gradient,
99 : const pixman_gradient_stop_t *stops,
100 : int n_stops)
101 : {
102 0 : 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 0 : gradient->stops =
115 0 : pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t));
116 0 : if (!gradient->stops)
117 0 : return FALSE;
118 :
119 0 : gradient->stops += 1;
120 0 : memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t));
121 0 : gradient->n_stops = n_stops;
122 :
123 0 : gradient->common.property_changed = gradient_property_changed;
124 :
125 0 : return TRUE;
126 : }
127 :
128 : void
129 94 : _pixman_image_init (pixman_image_t *image)
130 : {
131 94 : image_common_t *common = &image->common;
132 :
133 94 : pixman_region32_init (&common->clip_region);
134 :
135 94 : common->alpha_count = 0;
136 94 : common->have_clip_region = FALSE;
137 94 : common->clip_sources = FALSE;
138 94 : common->transform = NULL;
139 94 : common->repeat = PIXMAN_REPEAT_NONE;
140 94 : common->filter = PIXMAN_FILTER_NEAREST;
141 94 : common->filter_params = NULL;
142 94 : common->n_filter_params = 0;
143 94 : common->alpha_map = NULL;
144 94 : common->component_alpha = FALSE;
145 94 : common->ref_count = 1;
146 94 : common->property_changed = NULL;
147 94 : common->client_clip = FALSE;
148 94 : common->destroy_func = NULL;
149 94 : common->destroy_data = NULL;
150 94 : common->dirty = TRUE;
151 94 : }
152 :
153 : pixman_bool_t
154 44 : _pixman_image_fini (pixman_image_t *image)
155 : {
156 44 : image_common_t *common = (image_common_t *)image;
157 :
158 44 : common->ref_count--;
159 :
160 44 : if (common->ref_count == 0)
161 : {
162 44 : if (image->common.destroy_func)
163 0 : image->common.destroy_func (image, image->common.destroy_data);
164 :
165 44 : pixman_region32_fini (&common->clip_region);
166 :
167 44 : free_memory (&common->transform);
168 44 : free_memory (&common->filter_params);
169 :
170 44 : if (common->alpha_map)
171 0 : pixman_image_unref ((pixman_image_t *)common->alpha_map);
172 :
173 88 : if (image->type == LINEAR ||
174 88 : image->type == RADIAL ||
175 44 : image->type == CONICAL)
176 : {
177 0 : if (image->gradient.stops)
178 : {
179 : /* See _pixman_init_gradient() for an explanation of the - 1 */
180 0 : void *addr = image->gradient.stops - 1;
181 0 : 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 0 : assert (
189 : image->common.property_changed == gradient_property_changed);
190 : }
191 :
192 44 : if (image->type == BITS && image->bits.free_me) {
193 0 : free_memory (&image->bits.free_me);
194 0 : image->bits.bits = NULL;
195 : }
196 :
197 :
198 44 : return TRUE;
199 : }
200 :
201 0 : return FALSE;
202 : }
203 :
204 : pixman_image_t *
205 47 : _pixman_image_allocate (void)
206 : {
207 47 : pixman_image_t *image = malloc (sizeof (pixman_image_t));
208 :
209 47 : if (image)
210 47 : _pixman_image_init (image);
211 :
212 47 : return image;
213 : }
214 :
215 : static void
216 0 : image_property_changed (pixman_image_t *image)
217 : {
218 0 : image->common.dirty = TRUE;
219 0 : }
220 :
221 : /* Ref Counting */
222 : PIXMAN_EXPORT pixman_image_t *
223 0 : pixman_image_ref (pixman_image_t *image)
224 : {
225 0 : image->common.ref_count++;
226 :
227 0 : return image;
228 : }
229 :
230 : /* returns TRUE when the image is freed */
231 : PIXMAN_EXPORT pixman_bool_t
232 44 : pixman_image_unref (pixman_image_t *image)
233 : {
234 44 : if (_pixman_image_fini (image))
235 : {
236 44 : free_memory (&image);
237 44 : return TRUE;
238 : }
239 :
240 0 : return FALSE;
241 : }
242 :
243 : PIXMAN_EXPORT void
244 0 : pixman_image_set_destroy_function (pixman_image_t * image,
245 : pixman_image_destroy_func_t func,
246 : void * data)
247 : {
248 0 : image->common.destroy_func = func;
249 0 : image->common.destroy_data = data;
250 0 : }
251 :
252 : PIXMAN_EXPORT void *
253 0 : pixman_image_get_destroy_data (pixman_image_t *image)
254 : {
255 0 : return image->common.destroy_data;
256 : }
257 :
258 : void
259 47 : _pixman_image_reset_clip_region (pixman_image_t *image)
260 : {
261 47 : image->common.have_clip_region = FALSE;
262 47 : }
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
283 0 : pixman_disable_out_of_bounds_workaround (void)
284 : {
285 0 : }
286 :
287 : static void
288 44 : compute_image_info (pixman_image_t *image)
289 : {
290 : pixman_format_code_t code;
291 44 : uint32_t flags = 0;
292 :
293 : /* Transform */
294 44 : if (!image->common.transform)
295 : {
296 44 : 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 0 : flags |= FAST_PATH_HAS_TRANSFORM;
304 :
305 0 : if (image->common.transform->matrix[2][0] == 0 &&
306 0 : image->common.transform->matrix[2][1] == 0 &&
307 0 : image->common.transform->matrix[2][2] == pixman_fixed_1)
308 : {
309 0 : flags |= FAST_PATH_AFFINE_TRANSFORM;
310 :
311 0 : if (image->common.transform->matrix[0][1] == 0 &&
312 0 : image->common.transform->matrix[1][0] == 0)
313 : {
314 0 : if (image->common.transform->matrix[0][0] == -pixman_fixed_1 &&
315 0 : image->common.transform->matrix[1][1] == -pixman_fixed_1)
316 : {
317 0 : flags |= FAST_PATH_ROTATE_180_TRANSFORM;
318 : }
319 0 : flags |= FAST_PATH_SCALE_TRANSFORM;
320 : }
321 0 : else if (image->common.transform->matrix[0][0] == 0 &&
322 0 : image->common.transform->matrix[1][1] == 0)
323 : {
324 0 : pixman_fixed_t m01 = image->common.transform->matrix[0][1];
325 0 : pixman_fixed_t m10 = image->common.transform->matrix[1][0];
326 :
327 0 : if (m01 == -pixman_fixed_1 && m10 == pixman_fixed_1)
328 0 : flags |= FAST_PATH_ROTATE_90_TRANSFORM;
329 0 : else if (m01 == pixman_fixed_1 && m10 == -pixman_fixed_1)
330 0 : flags |= FAST_PATH_ROTATE_270_TRANSFORM;
331 : }
332 : }
333 :
334 0 : if (image->common.transform->matrix[0][0] > 0)
335 0 : flags |= FAST_PATH_X_UNIT_POSITIVE;
336 :
337 0 : if (image->common.transform->matrix[1][0] == 0)
338 0 : flags |= FAST_PATH_Y_UNIT_ZERO;
339 : }
340 :
341 : /* Filter */
342 44 : switch (image->common.filter)
343 : {
344 : case PIXMAN_FILTER_NEAREST:
345 : case PIXMAN_FILTER_FAST:
346 44 : flags |= (FAST_PATH_NEAREST_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
347 44 : break;
348 :
349 : case PIXMAN_FILTER_BILINEAR:
350 : case PIXMAN_FILTER_GOOD:
351 : case PIXMAN_FILTER_BEST:
352 0 : 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 0 : if (flags & FAST_PATH_ID_TRANSFORM)
358 : {
359 0 : flags |= FAST_PATH_NEAREST_FILTER;
360 : }
361 0 : else if (
362 : /* affine and integer translation components in matrix ... */
363 0 : ((flags & FAST_PATH_AFFINE_TRANSFORM) &&
364 0 : !pixman_fixed_frac (image->common.transform->matrix[0][2] |
365 0 : image->common.transform->matrix[1][2])) &&
366 : (
367 : /* ... combined with a simple rotation */
368 0 : (flags & (FAST_PATH_ROTATE_90_TRANSFORM |
369 : FAST_PATH_ROTATE_180_TRANSFORM |
370 0 : FAST_PATH_ROTATE_270_TRANSFORM)) ||
371 : /* ... or combined with a simple non-rotated translation */
372 0 : (image->common.transform->matrix[0][0] == pixman_fixed_1 &&
373 0 : image->common.transform->matrix[1][1] == pixman_fixed_1 &&
374 0 : image->common.transform->matrix[0][1] == 0 &&
375 0 : 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 0 : pixman_fixed_t magic_limit = pixman_int_to_fixed (30000);
386 0 : if (image->common.transform->matrix[0][2] <= magic_limit &&
387 0 : image->common.transform->matrix[1][2] <= magic_limit &&
388 0 : image->common.transform->matrix[0][2] >= -magic_limit &&
389 0 : image->common.transform->matrix[1][2] >= -magic_limit)
390 : {
391 0 : flags |= FAST_PATH_NEAREST_FILTER;
392 : }
393 : }
394 0 : break;
395 :
396 : case PIXMAN_FILTER_CONVOLUTION:
397 0 : break;
398 :
399 : case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
400 0 : flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER;
401 0 : break;
402 :
403 : default:
404 0 : flags |= FAST_PATH_NO_CONVOLUTION_FILTER;
405 0 : break;
406 : }
407 :
408 : /* Repeat mode */
409 44 : switch (image->common.repeat)
410 : {
411 : case PIXMAN_REPEAT_NONE:
412 44 : flags |=
413 : FAST_PATH_NO_REFLECT_REPEAT |
414 : FAST_PATH_NO_PAD_REPEAT |
415 : FAST_PATH_NO_NORMAL_REPEAT;
416 44 : break;
417 :
418 : case PIXMAN_REPEAT_REFLECT:
419 0 : flags |=
420 : FAST_PATH_NO_PAD_REPEAT |
421 : FAST_PATH_NO_NONE_REPEAT |
422 : FAST_PATH_NO_NORMAL_REPEAT;
423 0 : break;
424 :
425 : case PIXMAN_REPEAT_PAD:
426 0 : flags |=
427 : FAST_PATH_NO_REFLECT_REPEAT |
428 : FAST_PATH_NO_NONE_REPEAT |
429 : FAST_PATH_NO_NORMAL_REPEAT;
430 0 : break;
431 :
432 : default:
433 0 : flags |=
434 : FAST_PATH_NO_REFLECT_REPEAT |
435 : FAST_PATH_NO_PAD_REPEAT |
436 : FAST_PATH_NO_NONE_REPEAT;
437 0 : break;
438 : }
439 :
440 : /* Component alpha */
441 44 : if (image->common.component_alpha)
442 0 : flags |= FAST_PATH_COMPONENT_ALPHA;
443 : else
444 44 : flags |= FAST_PATH_UNIFIED_ALPHA;
445 :
446 44 : flags |= (FAST_PATH_NO_ACCESSORS | FAST_PATH_NARROW_FORMAT);
447 :
448 : /* Type specific checks */
449 44 : switch (image->type)
450 : {
451 : case SOLID:
452 0 : code = PIXMAN_solid;
453 :
454 0 : if (image->solid.color.alpha == 0xffff)
455 0 : flags |= FAST_PATH_IS_OPAQUE;
456 0 : break;
457 :
458 : case BITS:
459 44 : if (image->bits.width == 1 &&
460 0 : image->bits.height == 1 &&
461 0 : image->common.repeat != PIXMAN_REPEAT_NONE)
462 : {
463 0 : code = PIXMAN_solid;
464 : }
465 : else
466 : {
467 44 : code = image->bits.format;
468 44 : flags |= FAST_PATH_BITS_IMAGE;
469 : }
470 :
471 44 : if (!PIXMAN_FORMAT_A (image->bits.format) &&
472 0 : PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_GRAY &&
473 0 : PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_COLOR)
474 : {
475 0 : flags |= FAST_PATH_SAMPLES_OPAQUE;
476 :
477 0 : if (image->common.repeat != PIXMAN_REPEAT_NONE)
478 0 : flags |= FAST_PATH_IS_OPAQUE;
479 : }
480 :
481 44 : if (image->bits.read_func || image->bits.write_func)
482 0 : flags &= ~FAST_PATH_NO_ACCESSORS;
483 :
484 44 : if (PIXMAN_FORMAT_IS_WIDE (image->bits.format))
485 0 : flags &= ~FAST_PATH_NARROW_FORMAT;
486 :
487 44 : if (image->bits.format == PIXMAN_r5g6b5)
488 0 : flags |= FAST_PATH_16_FORMAT;
489 :
490 44 : break;
491 :
492 : case RADIAL:
493 0 : 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 0 : if (image->radial.a >= 0)
503 0 : break;
504 :
505 : /* Fall through */
506 :
507 : case CONICAL:
508 : case LINEAR:
509 0 : code = PIXMAN_unknown;
510 :
511 0 : if (image->common.repeat != PIXMAN_REPEAT_NONE)
512 : {
513 : int i;
514 :
515 0 : flags |= FAST_PATH_IS_OPAQUE;
516 0 : for (i = 0; i < image->gradient.n_stops; ++i)
517 : {
518 0 : if (image->gradient.stops[i].color.alpha != 0xffff)
519 : {
520 0 : flags &= ~FAST_PATH_IS_OPAQUE;
521 0 : break;
522 : }
523 : }
524 : }
525 0 : break;
526 :
527 : default:
528 0 : code = PIXMAN_unknown;
529 0 : break;
530 : }
531 :
532 : /* Alpha map */
533 44 : if (!image->common.alpha_map)
534 : {
535 44 : flags |= FAST_PATH_NO_ALPHA_MAP;
536 : }
537 : else
538 : {
539 0 : if (PIXMAN_FORMAT_IS_WIDE (image->common.alpha_map->format))
540 0 : 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 88 : if (image->common.alpha_map ||
550 88 : image->common.filter == PIXMAN_FILTER_CONVOLUTION ||
551 88 : image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION ||
552 44 : image->common.component_alpha)
553 : {
554 0 : flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE);
555 : }
556 :
557 44 : image->common.flags = flags;
558 44 : image->common.extended_format_code = code;
559 44 : }
560 :
561 : void
562 44 : _pixman_image_validate (pixman_image_t *image)
563 : {
564 44 : if (image->common.dirty)
565 : {
566 44 : 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 44 : if (image->common.property_changed)
574 44 : image->common.property_changed (image);
575 :
576 44 : image->common.dirty = FALSE;
577 : }
578 :
579 44 : if (image->common.alpha_map)
580 0 : _pixman_image_validate ((pixman_image_t *)image->common.alpha_map);
581 44 : }
582 :
583 : PIXMAN_EXPORT pixman_bool_t
584 0 : pixman_image_set_clip_region32 (pixman_image_t * image,
585 : pixman_region32_t *region)
586 : {
587 0 : image_common_t *common = (image_common_t *)image;
588 : pixman_bool_t result;
589 :
590 0 : if (region)
591 : {
592 0 : if ((result = pixman_region32_copy (&common->clip_region, region)))
593 0 : image->common.have_clip_region = TRUE;
594 : }
595 : else
596 : {
597 0 : _pixman_image_reset_clip_region (image);
598 :
599 0 : result = TRUE;
600 : }
601 :
602 0 : image_property_changed (image);
603 :
604 0 : return result;
605 : }
606 :
607 : PIXMAN_EXPORT pixman_bool_t
608 0 : pixman_image_set_clip_region (pixman_image_t * image,
609 : pixman_region16_t *region)
610 : {
611 0 : image_common_t *common = (image_common_t *)image;
612 : pixman_bool_t result;
613 :
614 0 : if (region)
615 : {
616 0 : if ((result = pixman_region32_copy_from_region16 (&common->clip_region, region)))
617 0 : image->common.have_clip_region = TRUE;
618 : }
619 : else
620 : {
621 0 : _pixman_image_reset_clip_region (image);
622 :
623 0 : result = TRUE;
624 : }
625 :
626 0 : image_property_changed (image);
627 :
628 0 : return result;
629 : }
630 :
631 : PIXMAN_EXPORT void
632 0 : pixman_image_set_has_client_clip (pixman_image_t *image,
633 : pixman_bool_t client_clip)
634 : {
635 0 : image->common.client_clip = client_clip;
636 0 : }
637 :
638 : PIXMAN_EXPORT pixman_bool_t
639 0 : 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 0 : image_common_t *common = (image_common_t *)image;
650 : pixman_bool_t result;
651 :
652 0 : if (common->transform == transform)
653 0 : return TRUE;
654 :
655 0 : if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
656 : {
657 0 : free (common->transform);
658 0 : common->transform = NULL;
659 0 : result = TRUE;
660 :
661 0 : goto out;
662 : }
663 :
664 0 : if (common->transform &&
665 0 : memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0)
666 : {
667 0 : return TRUE;
668 : }
669 :
670 0 : if (common->transform == NULL)
671 0 : common->transform = malloc (sizeof (pixman_transform_t));
672 :
673 0 : if (common->transform == NULL)
674 : {
675 0 : result = FALSE;
676 :
677 0 : goto out;
678 : }
679 :
680 0 : memcpy (common->transform, transform, sizeof(pixman_transform_t));
681 :
682 0 : result = TRUE;
683 :
684 : out:
685 0 : image_property_changed (image);
686 :
687 0 : return result;
688 : }
689 :
690 : PIXMAN_EXPORT void
691 0 : pixman_image_set_repeat (pixman_image_t *image,
692 : pixman_repeat_t repeat)
693 : {
694 0 : if (image->common.repeat == repeat)
695 0 : return;
696 :
697 0 : image->common.repeat = repeat;
698 :
699 0 : image_property_changed (image);
700 : }
701 :
702 : PIXMAN_EXPORT pixman_bool_t
703 0 : 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 0 : image_common_t *common = (image_common_t *)image;
709 : pixman_fixed_t *new_params;
710 :
711 0 : if (params == common->filter_params && filter == common->filter)
712 0 : return TRUE;
713 :
714 0 : if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION)
715 : {
716 0 : int width = pixman_fixed_to_int (params[0]);
717 0 : int height = pixman_fixed_to_int (params[1]);
718 0 : int x_phase_bits = pixman_fixed_to_int (params[2]);
719 0 : int y_phase_bits = pixman_fixed_to_int (params[3]);
720 0 : int n_x_phases = (1 << x_phase_bits);
721 0 : int n_y_phases = (1 << y_phase_bits);
722 :
723 0 : return_val_if_fail (
724 : n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE);
725 : }
726 :
727 0 : new_params = NULL;
728 0 : if (params)
729 : {
730 0 : new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t));
731 0 : if (!new_params)
732 0 : return FALSE;
733 :
734 0 : memcpy (new_params,
735 : params, n_params * sizeof (pixman_fixed_t));
736 : }
737 :
738 0 : common->filter = filter;
739 :
740 0 : if (common->filter_params)
741 0 : free (common->filter_params);
742 :
743 0 : common->filter_params = new_params;
744 0 : common->n_filter_params = n_params;
745 :
746 0 : image_property_changed (image);
747 0 : return TRUE;
748 : }
749 :
750 : PIXMAN_EXPORT void
751 0 : pixman_image_set_source_clipping (pixman_image_t *image,
752 : pixman_bool_t clip_sources)
753 : {
754 0 : if (image->common.clip_sources == clip_sources)
755 0 : return;
756 :
757 0 : image->common.clip_sources = clip_sources;
758 :
759 0 : 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
767 0 : pixman_image_set_indexed (pixman_image_t * image,
768 : const pixman_indexed_t *indexed)
769 : {
770 0 : bits_image_t *bits = (bits_image_t *)image;
771 :
772 0 : if (bits->indexed == indexed)
773 0 : return;
774 :
775 0 : bits->indexed = indexed;
776 :
777 0 : image_property_changed (image);
778 : }
779 :
780 : PIXMAN_EXPORT void
781 0 : 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 0 : image_common_t *common = (image_common_t *)image;
787 :
788 0 : return_if_fail (!alpha_map || alpha_map->type == BITS);
789 :
790 0 : 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 0 : return;
796 : }
797 :
798 0 : 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 0 : return;
804 : }
805 :
806 0 : if (common->alpha_map != (bits_image_t *)alpha_map)
807 : {
808 0 : if (common->alpha_map)
809 : {
810 0 : common->alpha_map->common.alpha_count--;
811 :
812 0 : pixman_image_unref ((pixman_image_t *)common->alpha_map);
813 : }
814 :
815 0 : if (alpha_map)
816 : {
817 0 : common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
818 :
819 0 : common->alpha_map->common.alpha_count++;
820 : }
821 : else
822 : {
823 0 : common->alpha_map = NULL;
824 : }
825 : }
826 :
827 0 : common->alpha_origin_x = x;
828 0 : common->alpha_origin_y = y;
829 :
830 0 : image_property_changed (image);
831 : }
832 :
833 : PIXMAN_EXPORT void
834 0 : pixman_image_set_component_alpha (pixman_image_t *image,
835 : pixman_bool_t component_alpha)
836 : {
837 0 : if (image->common.component_alpha == component_alpha)
838 0 : return;
839 :
840 0 : image->common.component_alpha = component_alpha;
841 :
842 0 : image_property_changed (image);
843 : }
844 :
845 : PIXMAN_EXPORT pixman_bool_t
846 0 : pixman_image_get_component_alpha (pixman_image_t *image)
847 : {
848 0 : return image->common.component_alpha;
849 : }
850 :
851 : PIXMAN_EXPORT void
852 0 : 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 0 : return_if_fail (image != NULL);
857 :
858 0 : if (image->type == BITS)
859 : {
860 0 : image->bits.read_func = read_func;
861 0 : image->bits.write_func = write_func;
862 :
863 0 : image_property_changed (image);
864 : }
865 : }
866 :
867 : PIXMAN_EXPORT uint32_t *
868 3 : pixman_image_get_data (pixman_image_t *image)
869 : {
870 3 : if (image->type == BITS)
871 3 : return image->bits.bits;
872 :
873 0 : return NULL;
874 : }
875 :
876 : PIXMAN_EXPORT int
877 3 : pixman_image_get_width (pixman_image_t *image)
878 : {
879 3 : if (image->type == BITS)
880 3 : return image->bits.width;
881 :
882 0 : return 0;
883 : }
884 :
885 : PIXMAN_EXPORT int
886 3 : pixman_image_get_height (pixman_image_t *image)
887 : {
888 3 : if (image->type == BITS)
889 3 : return image->bits.height;
890 :
891 0 : return 0;
892 : }
893 :
894 : PIXMAN_EXPORT int
895 3 : pixman_image_get_stride (pixman_image_t *image)
896 : {
897 3 : if (image->type == BITS)
898 3 : return image->bits.rowstride * (int) sizeof (uint32_t);
899 :
900 0 : return 0;
901 : }
902 :
903 : PIXMAN_EXPORT int
904 3 : pixman_image_get_depth (pixman_image_t *image)
905 : {
906 3 : if (image->type == BITS)
907 3 : return PIXMAN_FORMAT_DEPTH (image->bits.format);
908 :
909 0 : return 0;
910 : }
911 :
912 : PIXMAN_EXPORT pixman_format_code_t
913 0 : pixman_image_get_format (pixman_image_t *image)
914 : {
915 0 : if (image->type == BITS)
916 0 : return image->bits.format;
917 :
918 0 : return PIXMAN_null;
919 : }
920 :
921 : uint32_t
922 0 : _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 0 : if (image->type == SOLID)
929 : {
930 0 : result = image->solid.color_32;
931 : }
932 0 : else if (image->type == BITS)
933 : {
934 0 : if (image->bits.format == PIXMAN_a8r8g8b8)
935 0 : result = image->bits.bits[0];
936 0 : else if (image->bits.format == PIXMAN_x8r8g8b8)
937 0 : result = image->bits.bits[0] | 0xff000000;
938 0 : else if (image->bits.format == PIXMAN_a8)
939 0 : result = (*(uint8_t *)image->bits.bits) << 24;
940 : else
941 0 : goto otherwise;
942 : }
943 : else
944 : {
945 : pixman_iter_t iter;
946 :
947 : otherwise:
948 0 : _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 0 : result = *iter.get_scanline (&iter, NULL);
954 : }
955 :
956 : /* If necessary, convert RGB <--> BGR. */
957 0 : if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB
958 0 : && PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB)
959 : {
960 0 : result = (((result & 0xff000000) >> 0) |
961 0 : ((result & 0x00ff0000) >> 16) |
962 0 : ((result & 0x0000ff00) >> 0) |
963 0 : ((result & 0x000000ff) << 16));
964 : }
965 :
966 0 : return result;
967 : }
|