Rev 1891 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1891 | serge | 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 |
||
25 | #endif |
||
26 | |||
27 | #include |
||
28 | #include |
||
29 | #include |
||
30 | #include |
||
31 | |||
32 | #include "pixman-private.h" |
||
33 | |||
3931 | Serge | 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 | |||
1891 | serge | 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 | |||
3931 | Serge | 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)); |
||
1891 | serge | 97 | if (!gradient->stops) |
98 | return FALSE; |
||
99 | |||
3931 | Serge | 100 | gradient->stops += 1; |
1891 | serge | 101 | memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t)); |
102 | gradient->n_stops = n_stops; |
||
103 | |||
3931 | Serge | 104 | gradient->common.property_changed = gradient_property_changed; |
1891 | serge | 105 | |
106 | return TRUE; |
||
107 | } |
||
108 | |||
109 | void |
||
3931 | Serge | 110 | _pixman_image_init (pixman_image_t *image) |
1891 | serge | 111 | { |
3931 | Serge | 112 | image_common_t *common = &image->common; |
1891 | serge | 113 | |
3931 | Serge | 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) |
||
1891 | serge | 142 | { |
3931 | Serge | 143 | if (image->common.destroy_func) |
144 | image->common.destroy_func (image, image->common.destroy_data); |
||
1891 | serge | 145 | |
3931 | Serge | 146 | pixman_region32_fini (&common->clip_region); |
1891 | serge | 147 | |
3931 | Serge | 148 | free (common->transform); |
149 | free (common->filter_params); |
||
1891 | serge | 150 | |
3931 | Serge | 151 | if (common->alpha_map) |
152 | pixman_image_unref ((pixman_image_t *)common->alpha_map); |
||
1891 | serge | 153 | |
3931 | Serge | 154 | if (image->type == LINEAR || |
155 | image->type == RADIAL || |
||
156 | image->type == CONICAL) |
||
157 | { |
||
158 | if (image->gradient.stops) |
||
159 | { |
||
160 | /* See _pixman_init_gradient() for an explanation of the - 1 */ |
||
161 | free (image->gradient.stops - 1); |
||
162 | } |
||
163 | |||
164 | /* This will trigger if someone adds a property_changed |
||
165 | * method to the linear/radial/conical gradient overwriting |
||
166 | * the general one. |
||
167 | */ |
||
168 | assert ( |
||
169 | image->common.property_changed == gradient_property_changed); |
||
170 | } |
||
171 | |||
172 | if (image->type == BITS && image->bits.free_me) |
||
173 | free (image->bits.free_me); |
||
174 | |||
175 | return TRUE; |
||
176 | } |
||
177 | |||
178 | return FALSE; |
||
1891 | serge | 179 | } |
180 | |||
181 | pixman_image_t * |
||
182 | _pixman_image_allocate (void) |
||
183 | { |
||
184 | pixman_image_t *image = malloc (sizeof (pixman_image_t)); |
||
185 | |||
186 | if (image) |
||
3931 | Serge | 187 | _pixman_image_init (image); |
1891 | serge | 188 | |
189 | return image; |
||
190 | } |
||
191 | |||
192 | static void |
||
193 | image_property_changed (pixman_image_t *image) |
||
194 | { |
||
195 | image->common.dirty = TRUE; |
||
196 | } |
||
197 | |||
198 | /* Ref Counting */ |
||
199 | PIXMAN_EXPORT pixman_image_t * |
||
200 | pixman_image_ref (pixman_image_t *image) |
||
201 | { |
||
202 | image->common.ref_count++; |
||
203 | |||
204 | return image; |
||
205 | } |
||
206 | |||
207 | /* returns TRUE when the image is freed */ |
||
208 | PIXMAN_EXPORT pixman_bool_t |
||
209 | pixman_image_unref (pixman_image_t *image) |
||
210 | { |
||
3931 | Serge | 211 | if (_pixman_image_fini (image)) |
1891 | serge | 212 | { |
213 | free (image); |
||
214 | return TRUE; |
||
215 | } |
||
216 | |||
217 | return FALSE; |
||
218 | } |
||
219 | |||
220 | PIXMAN_EXPORT void |
||
221 | pixman_image_set_destroy_function (pixman_image_t * image, |
||
222 | pixman_image_destroy_func_t func, |
||
223 | void * data) |
||
224 | { |
||
225 | image->common.destroy_func = func; |
||
226 | image->common.destroy_data = data; |
||
227 | } |
||
228 | |||
229 | PIXMAN_EXPORT void * |
||
230 | pixman_image_get_destroy_data (pixman_image_t *image) |
||
231 | { |
||
232 | return image->common.destroy_data; |
||
233 | } |
||
234 | |||
235 | void |
||
236 | _pixman_image_reset_clip_region (pixman_image_t *image) |
||
237 | { |
||
238 | image->common.have_clip_region = FALSE; |
||
239 | } |
||
240 | |||
3931 | Serge | 241 | /* Executive Summary: This function is a no-op that only exists |
242 | * for historical reasons. |
||
1891 | serge | 243 | * |
3931 | Serge | 244 | * There used to be a bug in the X server where it would rely on |
245 | * out-of-bounds accesses when it was asked to composite with a |
||
246 | * window as the source. It would create a pixman image pointing |
||
247 | * to some bogus position in memory, but then set a clip region |
||
248 | * to the position where the actual bits were. |
||
249 | * |
||
1891 | serge | 250 | * Due to a bug in old versions of pixman, where it would not clip |
251 | * against the image bounds when a clip region was set, this would |
||
3931 | Serge | 252 | * actually work. So when the pixman bug was fixed, a workaround was |
253 | * added to allow certain out-of-bound accesses. This function disabled |
||
254 | * those workarounds. |
||
1891 | serge | 255 | * |
3931 | Serge | 256 | * Since 0.21.2, pixman doesn't do these workarounds anymore, so now |
257 | * this function is a no-op. |
||
1891 | serge | 258 | */ |
259 | PIXMAN_EXPORT void |
||
260 | pixman_disable_out_of_bounds_workaround (void) |
||
261 | { |
||
262 | } |
||
263 | |||
264 | static void |
||
265 | compute_image_info (pixman_image_t *image) |
||
266 | { |
||
267 | pixman_format_code_t code; |
||
268 | uint32_t flags = 0; |
||
269 | |||
270 | /* Transform */ |
||
271 | if (!image->common.transform) |
||
272 | { |
||
273 | flags |= (FAST_PATH_ID_TRANSFORM | |
||
274 | FAST_PATH_X_UNIT_POSITIVE | |
||
275 | FAST_PATH_Y_UNIT_ZERO | |
||
276 | FAST_PATH_AFFINE_TRANSFORM); |
||
277 | } |
||
278 | else |
||
279 | { |
||
280 | flags |= FAST_PATH_HAS_TRANSFORM; |
||
281 | |||
282 | if (image->common.transform->matrix[2][0] == 0 && |
||
283 | image->common.transform->matrix[2][1] == 0 && |
||
284 | image->common.transform->matrix[2][2] == pixman_fixed_1) |
||
285 | { |
||
286 | flags |= FAST_PATH_AFFINE_TRANSFORM; |
||
287 | |||
288 | if (image->common.transform->matrix[0][1] == 0 && |
||
289 | image->common.transform->matrix[1][0] == 0) |
||
290 | { |
||
3931 | Serge | 291 | if (image->common.transform->matrix[0][0] == -pixman_fixed_1 && |
292 | image->common.transform->matrix[1][1] == -pixman_fixed_1) |
||
293 | { |
||
294 | flags |= FAST_PATH_ROTATE_180_TRANSFORM; |
||
295 | } |
||
1891 | serge | 296 | flags |= FAST_PATH_SCALE_TRANSFORM; |
297 | } |
||
3931 | Serge | 298 | else if (image->common.transform->matrix[0][0] == 0 && |
299 | image->common.transform->matrix[1][1] == 0) |
||
300 | { |
||
301 | pixman_fixed_t m01 = image->common.transform->matrix[0][1]; |
||
302 | pixman_fixed_t m10 = image->common.transform->matrix[1][0]; |
||
303 | |||
304 | if (m01 == -pixman_fixed_1 && m10 == pixman_fixed_1) |
||
305 | flags |= FAST_PATH_ROTATE_90_TRANSFORM; |
||
306 | else if (m01 == pixman_fixed_1 && m10 == -pixman_fixed_1) |
||
307 | flags |= FAST_PATH_ROTATE_270_TRANSFORM; |
||
308 | } |
||
1891 | serge | 309 | } |
310 | |||
311 | if (image->common.transform->matrix[0][0] > 0) |
||
312 | flags |= FAST_PATH_X_UNIT_POSITIVE; |
||
313 | |||
314 | if (image->common.transform->matrix[1][0] == 0) |
||
315 | flags |= FAST_PATH_Y_UNIT_ZERO; |
||
316 | } |
||
317 | |||
318 | /* Filter */ |
||
319 | switch (image->common.filter) |
||
320 | { |
||
321 | case PIXMAN_FILTER_NEAREST: |
||
322 | case PIXMAN_FILTER_FAST: |
||
323 | flags |= (FAST_PATH_NEAREST_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER); |
||
324 | break; |
||
325 | |||
326 | case PIXMAN_FILTER_BILINEAR: |
||
327 | case PIXMAN_FILTER_GOOD: |
||
328 | case PIXMAN_FILTER_BEST: |
||
329 | flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER); |
||
3931 | Serge | 330 | |
331 | /* Here we have a chance to optimize BILINEAR filter to NEAREST if |
||
332 | * they are equivalent for the currently used transformation matrix. |
||
333 | */ |
||
334 | if (flags & FAST_PATH_ID_TRANSFORM) |
||
335 | { |
||
336 | flags |= FAST_PATH_NEAREST_FILTER; |
||
337 | } |
||
338 | else if ( |
||
339 | /* affine and integer translation components in matrix ... */ |
||
340 | ((flags & FAST_PATH_AFFINE_TRANSFORM) && |
||
341 | !pixman_fixed_frac (image->common.transform->matrix[0][2] | |
||
342 | image->common.transform->matrix[1][2])) && |
||
343 | ( |
||
344 | /* ... combined with a simple rotation */ |
||
345 | (flags & (FAST_PATH_ROTATE_90_TRANSFORM | |
||
346 | FAST_PATH_ROTATE_180_TRANSFORM | |
||
347 | FAST_PATH_ROTATE_270_TRANSFORM)) || |
||
348 | /* ... or combined with a simple non-rotated translation */ |
||
349 | (image->common.transform->matrix[0][0] == pixman_fixed_1 && |
||
350 | image->common.transform->matrix[1][1] == pixman_fixed_1 && |
||
351 | image->common.transform->matrix[0][1] == 0 && |
||
352 | image->common.transform->matrix[1][0] == 0) |
||
353 | ) |
||
354 | ) |
||
355 | { |
||
356 | /* FIXME: there are some affine-test failures, showing that |
||
357 | * handling of BILINEAR and NEAREST filter is not quite |
||
358 | * equivalent when getting close to 32K for the translation |
||
359 | * components of the matrix. That's likely some bug, but for |
||
360 | * now just skip BILINEAR->NEAREST optimization in this case. |
||
361 | */ |
||
362 | pixman_fixed_t magic_limit = pixman_int_to_fixed (30000); |
||
363 | if (image->common.transform->matrix[0][2] <= magic_limit && |
||
364 | image->common.transform->matrix[1][2] <= magic_limit && |
||
365 | image->common.transform->matrix[0][2] >= -magic_limit && |
||
366 | image->common.transform->matrix[1][2] >= -magic_limit) |
||
367 | { |
||
368 | flags |= FAST_PATH_NEAREST_FILTER; |
||
369 | } |
||
370 | } |
||
1891 | serge | 371 | break; |
372 | |||
373 | case PIXMAN_FILTER_CONVOLUTION: |
||
374 | break; |
||
375 | |||
3931 | Serge | 376 | case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: |
377 | flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER; |
||
378 | break; |
||
379 | |||
1891 | serge | 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; |
||
3931 | Serge | 445 | flags |= FAST_PATH_BITS_IMAGE; |
1891 | serge | 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 | |||
3931 | Serge | 480 | case CONICAL: |
1891 | serge | 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 | */ |
||
3931 | Serge | 522 | if (image->common.alpha_map || |
523 | image->common.filter == PIXMAN_FILTER_CONVOLUTION || |
||
524 | image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION || |
||
1891 | serge | 525 | image->common.component_alpha) |
526 | { |
||
527 | flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE); |
||
528 | } |
||
529 | |||
530 | image->common.flags = flags; |
||
531 | image->common.extended_format_code = code; |
||
532 | } |
||
533 | |||
534 | void |
||
535 | _pixman_image_validate (pixman_image_t *image) |
||
536 | { |
||
537 | if (image->common.dirty) |
||
538 | { |
||
539 | compute_image_info (image); |
||
540 | |||
541 | /* It is important that property_changed is |
||
542 | * called *after* compute_image_info() because |
||
543 | * property_changed() can make use of the flags |
||
544 | * to set up accessors etc. |
||
545 | */ |
||
3931 | Serge | 546 | if (image->common.property_changed) |
547 | image->common.property_changed (image); |
||
1891 | serge | 548 | |
549 | image->common.dirty = FALSE; |
||
550 | } |
||
551 | |||
552 | if (image->common.alpha_map) |
||
553 | _pixman_image_validate ((pixman_image_t *)image->common.alpha_map); |
||
554 | } |
||
555 | |||
556 | PIXMAN_EXPORT pixman_bool_t |
||
557 | pixman_image_set_clip_region32 (pixman_image_t * image, |
||
558 | pixman_region32_t *region) |
||
559 | { |
||
560 | image_common_t *common = (image_common_t *)image; |
||
561 | pixman_bool_t result; |
||
562 | |||
563 | if (region) |
||
564 | { |
||
565 | if ((result = pixman_region32_copy (&common->clip_region, region))) |
||
566 | image->common.have_clip_region = TRUE; |
||
567 | } |
||
568 | else |
||
569 | { |
||
570 | _pixman_image_reset_clip_region (image); |
||
571 | |||
572 | result = TRUE; |
||
573 | } |
||
574 | |||
575 | image_property_changed (image); |
||
576 | |||
577 | return result; |
||
578 | } |
||
579 | |||
580 | PIXMAN_EXPORT pixman_bool_t |
||
581 | pixman_image_set_clip_region (pixman_image_t * image, |
||
582 | pixman_region16_t *region) |
||
583 | { |
||
584 | image_common_t *common = (image_common_t *)image; |
||
585 | pixman_bool_t result; |
||
586 | |||
587 | if (region) |
||
588 | { |
||
589 | if ((result = pixman_region32_copy_from_region16 (&common->clip_region, region))) |
||
590 | image->common.have_clip_region = TRUE; |
||
591 | } |
||
592 | else |
||
593 | { |
||
594 | _pixman_image_reset_clip_region (image); |
||
595 | |||
596 | result = TRUE; |
||
597 | } |
||
598 | |||
599 | image_property_changed (image); |
||
600 | |||
601 | return result; |
||
602 | } |
||
603 | |||
604 | PIXMAN_EXPORT void |
||
605 | pixman_image_set_has_client_clip (pixman_image_t *image, |
||
606 | pixman_bool_t client_clip) |
||
607 | { |
||
608 | image->common.client_clip = client_clip; |
||
609 | } |
||
610 | |||
611 | PIXMAN_EXPORT pixman_bool_t |
||
612 | pixman_image_set_transform (pixman_image_t * image, |
||
613 | const pixman_transform_t *transform) |
||
614 | { |
||
615 | static const pixman_transform_t id = |
||
616 | { |
||
617 | { { pixman_fixed_1, 0, 0 }, |
||
618 | { 0, pixman_fixed_1, 0 }, |
||
619 | { 0, 0, pixman_fixed_1 } } |
||
620 | }; |
||
621 | |||
622 | image_common_t *common = (image_common_t *)image; |
||
623 | pixman_bool_t result; |
||
624 | |||
625 | if (common->transform == transform) |
||
626 | return TRUE; |
||
627 | |||
3931 | Serge | 628 | if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0) |
1891 | serge | 629 | { |
630 | free (common->transform); |
||
631 | common->transform = NULL; |
||
632 | result = TRUE; |
||
633 | |||
634 | goto out; |
||
635 | } |
||
636 | |||
3931 | Serge | 637 | if (common->transform && |
638 | memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0) |
||
639 | { |
||
640 | return TRUE; |
||
641 | } |
||
642 | |||
1891 | serge | 643 | if (common->transform == NULL) |
644 | common->transform = malloc (sizeof (pixman_transform_t)); |
||
645 | |||
646 | if (common->transform == NULL) |
||
647 | { |
||
648 | result = FALSE; |
||
649 | |||
650 | goto out; |
||
651 | } |
||
652 | |||
653 | memcpy (common->transform, transform, sizeof(pixman_transform_t)); |
||
654 | |||
655 | result = TRUE; |
||
656 | |||
657 | out: |
||
658 | image_property_changed (image); |
||
659 | |||
660 | return result; |
||
661 | } |
||
662 | |||
663 | PIXMAN_EXPORT void |
||
664 | pixman_image_set_repeat (pixman_image_t *image, |
||
665 | pixman_repeat_t repeat) |
||
666 | { |
||
3931 | Serge | 667 | if (image->common.repeat == repeat) |
668 | return; |
||
669 | |||
1891 | serge | 670 | image->common.repeat = repeat; |
671 | |||
672 | image_property_changed (image); |
||
673 | } |
||
674 | |||
675 | PIXMAN_EXPORT pixman_bool_t |
||
676 | pixman_image_set_filter (pixman_image_t * image, |
||
677 | pixman_filter_t filter, |
||
678 | const pixman_fixed_t *params, |
||
679 | int n_params) |
||
680 | { |
||
681 | image_common_t *common = (image_common_t *)image; |
||
682 | pixman_fixed_t *new_params; |
||
683 | |||
684 | if (params == common->filter_params && filter == common->filter) |
||
685 | return TRUE; |
||
686 | |||
3931 | Serge | 687 | if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION) |
688 | { |
||
689 | int width = pixman_fixed_to_int (params[0]); |
||
690 | int height = pixman_fixed_to_int (params[1]); |
||
691 | int x_phase_bits = pixman_fixed_to_int (params[2]); |
||
692 | int y_phase_bits = pixman_fixed_to_int (params[3]); |
||
693 | int n_x_phases = (1 << x_phase_bits); |
||
694 | int n_y_phases = (1 << y_phase_bits); |
||
695 | |||
696 | return_val_if_fail ( |
||
697 | n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE); |
||
698 | } |
||
699 | |||
1891 | serge | 700 | new_params = NULL; |
701 | if (params) |
||
702 | { |
||
703 | new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t)); |
||
704 | if (!new_params) |
||
705 | return FALSE; |
||
706 | |||
707 | memcpy (new_params, |
||
708 | params, n_params * sizeof (pixman_fixed_t)); |
||
709 | } |
||
710 | |||
711 | common->filter = filter; |
||
712 | |||
713 | if (common->filter_params) |
||
714 | free (common->filter_params); |
||
715 | |||
716 | common->filter_params = new_params; |
||
717 | common->n_filter_params = n_params; |
||
718 | |||
719 | image_property_changed (image); |
||
720 | return TRUE; |
||
721 | } |
||
722 | |||
723 | PIXMAN_EXPORT void |
||
724 | pixman_image_set_source_clipping (pixman_image_t *image, |
||
725 | pixman_bool_t clip_sources) |
||
726 | { |
||
3931 | Serge | 727 | if (image->common.clip_sources == clip_sources) |
728 | return; |
||
729 | |||
1891 | serge | 730 | image->common.clip_sources = clip_sources; |
731 | |||
732 | image_property_changed (image); |
||
733 | } |
||
734 | |||
735 | /* Unlike all the other property setters, this function does not |
||
736 | * copy the content of indexed. Doing this copying is simply |
||
737 | * way, way too expensive. |
||
738 | */ |
||
739 | PIXMAN_EXPORT void |
||
740 | pixman_image_set_indexed (pixman_image_t * image, |
||
741 | const pixman_indexed_t *indexed) |
||
742 | { |
||
743 | bits_image_t *bits = (bits_image_t *)image; |
||
744 | |||
3931 | Serge | 745 | if (bits->indexed == indexed) |
746 | return; |
||
747 | |||
1891 | serge | 748 | bits->indexed = indexed; |
749 | |||
750 | image_property_changed (image); |
||
751 | } |
||
752 | |||
753 | PIXMAN_EXPORT void |
||
754 | pixman_image_set_alpha_map (pixman_image_t *image, |
||
755 | pixman_image_t *alpha_map, |
||
756 | int16_t x, |
||
757 | int16_t y) |
||
758 | { |
||
759 | image_common_t *common = (image_common_t *)image; |
||
760 | |||
761 | return_if_fail (!alpha_map || alpha_map->type == BITS); |
||
762 | |||
763 | if (alpha_map && common->alpha_count > 0) |
||
764 | { |
||
765 | /* If this image is being used as an alpha map itself, |
||
766 | * then you can't give it an alpha map of its own. |
||
767 | */ |
||
768 | return; |
||
769 | } |
||
770 | |||
771 | if (alpha_map && alpha_map->common.alpha_map) |
||
772 | { |
||
773 | /* If the image has an alpha map of its own, |
||
774 | * then it can't be used as an alpha map itself |
||
775 | */ |
||
776 | return; |
||
777 | } |
||
778 | |||
779 | if (common->alpha_map != (bits_image_t *)alpha_map) |
||
780 | { |
||
781 | if (common->alpha_map) |
||
782 | { |
||
783 | common->alpha_map->common.alpha_count--; |
||
784 | |||
785 | pixman_image_unref ((pixman_image_t *)common->alpha_map); |
||
786 | } |
||
787 | |||
788 | if (alpha_map) |
||
789 | { |
||
790 | common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map); |
||
791 | |||
792 | common->alpha_map->common.alpha_count++; |
||
793 | } |
||
794 | else |
||
795 | { |
||
796 | common->alpha_map = NULL; |
||
797 | } |
||
798 | } |
||
799 | |||
800 | common->alpha_origin_x = x; |
||
801 | common->alpha_origin_y = y; |
||
802 | |||
803 | image_property_changed (image); |
||
804 | } |
||
805 | |||
806 | PIXMAN_EXPORT void |
||
807 | pixman_image_set_component_alpha (pixman_image_t *image, |
||
808 | pixman_bool_t component_alpha) |
||
809 | { |
||
3931 | Serge | 810 | if (image->common.component_alpha == component_alpha) |
811 | return; |
||
812 | |||
1891 | serge | 813 | image->common.component_alpha = component_alpha; |
814 | |||
815 | image_property_changed (image); |
||
816 | } |
||
817 | |||
818 | PIXMAN_EXPORT pixman_bool_t |
||
819 | pixman_image_get_component_alpha (pixman_image_t *image) |
||
820 | { |
||
821 | return image->common.component_alpha; |
||
822 | } |
||
823 | |||
824 | PIXMAN_EXPORT void |
||
825 | pixman_image_set_accessors (pixman_image_t * image, |
||
826 | pixman_read_memory_func_t read_func, |
||
827 | pixman_write_memory_func_t write_func) |
||
828 | { |
||
829 | return_if_fail (image != NULL); |
||
830 | |||
831 | if (image->type == BITS) |
||
832 | { |
||
833 | image->bits.read_func = read_func; |
||
834 | image->bits.write_func = write_func; |
||
835 | |||
836 | image_property_changed (image); |
||
837 | } |
||
838 | } |
||
839 | |||
840 | PIXMAN_EXPORT uint32_t * |
||
841 | pixman_image_get_data (pixman_image_t *image) |
||
842 | { |
||
843 | if (image->type == BITS) |
||
844 | return image->bits.bits; |
||
845 | |||
846 | return NULL; |
||
847 | } |
||
848 | |||
849 | PIXMAN_EXPORT int |
||
850 | pixman_image_get_width (pixman_image_t *image) |
||
851 | { |
||
852 | if (image->type == BITS) |
||
853 | return image->bits.width; |
||
854 | |||
855 | return 0; |
||
856 | } |
||
857 | |||
858 | PIXMAN_EXPORT int |
||
859 | pixman_image_get_height (pixman_image_t *image) |
||
860 | { |
||
861 | if (image->type == BITS) |
||
862 | return image->bits.height; |
||
863 | |||
864 | return 0; |
||
865 | } |
||
866 | |||
867 | PIXMAN_EXPORT int |
||
868 | pixman_image_get_stride (pixman_image_t *image) |
||
869 | { |
||
870 | if (image->type == BITS) |
||
871 | return image->bits.rowstride * (int) sizeof (uint32_t); |
||
872 | |||
873 | return 0; |
||
874 | } |
||
875 | |||
876 | PIXMAN_EXPORT int |
||
877 | pixman_image_get_depth (pixman_image_t *image) |
||
878 | { |
||
879 | if (image->type == BITS) |
||
880 | return PIXMAN_FORMAT_DEPTH (image->bits.format); |
||
881 | |||
882 | return 0; |
||
883 | } |
||
884 | |||
885 | PIXMAN_EXPORT pixman_format_code_t |
||
886 | pixman_image_get_format (pixman_image_t *image) |
||
887 | { |
||
888 | if (image->type == BITS) |
||
889 | return image->bits.format; |
||
890 | |||
3931 | Serge | 891 | return PIXMAN_null; |
1891 | serge | 892 | } |
893 | |||
894 | uint32_t |
||
3931 | Serge | 895 | _pixman_image_get_solid (pixman_implementation_t *imp, |
896 | pixman_image_t * image, |
||
897 | pixman_format_code_t format) |
||
1891 | serge | 898 | { |
899 | uint32_t result; |
||
900 | |||
3931 | Serge | 901 | if (image->type == SOLID) |
902 | { |
||
903 | result = image->solid.color_32; |
||
904 | } |
||
905 | else if (image->type == BITS) |
||
906 | { |
||
907 | if (image->bits.format == PIXMAN_a8r8g8b8) |
||
908 | result = image->bits.bits[0]; |
||
909 | else if (image->bits.format == PIXMAN_x8r8g8b8) |
||
910 | result = image->bits.bits[0] | 0xff000000; |
||
911 | else if (image->bits.format == PIXMAN_a8) |
||
912 | result = (*(uint8_t *)image->bits.bits) << 24; |
||
913 | else |
||
914 | goto otherwise; |
||
915 | } |
||
916 | else |
||
917 | { |
||
918 | pixman_iter_t iter; |
||
1891 | serge | 919 | |
3931 | Serge | 920 | otherwise: |
921 | _pixman_implementation_src_iter_init ( |
||
922 | imp, &iter, image, 0, 0, 1, 1, |
||
923 | (uint8_t *)&result, |
||
924 | ITER_NARROW, image->common.flags); |
||
925 | |||
926 | result = *iter.get_scanline (&iter, NULL); |
||
927 | } |
||
928 | |||
1891 | serge | 929 | /* If necessary, convert RGB <--> BGR. */ |
3931 | Serge | 930 | if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB |
931 | && PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB) |
||
1891 | serge | 932 | { |
933 | result = (((result & 0xff000000) >> 0) | |
||
934 | ((result & 0x00ff0000) >> 16) | |
||
935 | ((result & 0x0000ff00) >> 0) | |
||
936 | ((result & 0x000000ff) << 16)); |
||
937 | } |
||
938 | |||
939 | return result; |
||
940 | }><>-->><>><>><>>=>=> |