1 : /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
2 : /*
3 : * Copyright © 2000 SuSE, Inc.
4 : * Copyright © 2007 Red Hat, Inc.
5 : *
6 : * Permission to use, copy, modify, distribute, and sell this software and its
7 : * documentation for any purpose is hereby granted without fee, provided that
8 : * the above copyright notice appear in all copies and that both that
9 : * copyright notice and this permission notice appear in supporting
10 : * documentation, and that the name of SuSE not be used in advertising or
11 : * publicity pertaining to distribution of the software without specific,
12 : * written prior permission. SuSE makes no representations about the
13 : * suitability of this software for any purpose. It is provided "as is"
14 : * without express or implied warranty.
15 : *
16 : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
18 : * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 : * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 : * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 : *
23 : * Author: Keith Packard, SuSE, Inc.
24 : */
25 :
26 : #ifdef HAVE_CONFIG_H
27 : #include <config.h>
28 : #endif
29 : #include "pixman-private.h"
30 :
31 : #include <stdlib.h>
32 :
33 : static pixman_implementation_t *global_implementation;
34 :
35 : #ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
36 : static void __attribute__((constructor))
37 : pixman_constructor (void)
38 : {
39 : global_implementation = _pixman_choose_implementation ();
40 : }
41 : #endif
42 :
43 : static force_inline pixman_implementation_t *
44 : get_implementation (void)
45 : {
46 : #ifndef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
47 30 : if (!global_implementation)
48 4 : global_implementation = _pixman_choose_implementation ();
49 : #endif
50 30 : return global_implementation;
51 : }
52 :
53 : typedef struct operator_info_t operator_info_t;
54 :
55 : struct operator_info_t
56 : {
57 : uint8_t opaque_info[4];
58 : };
59 :
60 : #define PACK(neither, src, dest, both) \
61 : {{ (uint8_t)PIXMAN_OP_ ## neither, \
62 : (uint8_t)PIXMAN_OP_ ## src, \
63 : (uint8_t)PIXMAN_OP_ ## dest, \
64 : (uint8_t)PIXMAN_OP_ ## both }}
65 :
66 : static const operator_info_t operator_table[] =
67 : {
68 : /* Neither Opaque Src Opaque Dst Opaque Both Opaque */
69 : PACK (CLEAR, CLEAR, CLEAR, CLEAR),
70 : PACK (SRC, SRC, SRC, SRC),
71 : PACK (DST, DST, DST, DST),
72 : PACK (OVER, SRC, OVER, SRC),
73 : PACK (OVER_REVERSE, OVER_REVERSE, DST, DST),
74 : PACK (IN, IN, SRC, SRC),
75 : PACK (IN_REVERSE, DST, IN_REVERSE, DST),
76 : PACK (OUT, OUT, CLEAR, CLEAR),
77 : PACK (OUT_REVERSE, CLEAR, OUT_REVERSE, CLEAR),
78 : PACK (ATOP, IN, OVER, SRC),
79 : PACK (ATOP_REVERSE, OVER_REVERSE, IN_REVERSE, DST),
80 : PACK (XOR, OUT, OUT_REVERSE, CLEAR),
81 : PACK (ADD, ADD, ADD, ADD),
82 : PACK (SATURATE, OVER_REVERSE, DST, DST),
83 :
84 : {{ 0 /* 0x0e */ }},
85 : {{ 0 /* 0x0f */ }},
86 :
87 : PACK (CLEAR, CLEAR, CLEAR, CLEAR),
88 : PACK (SRC, SRC, SRC, SRC),
89 : PACK (DST, DST, DST, DST),
90 : PACK (DISJOINT_OVER, DISJOINT_OVER, DISJOINT_OVER, DISJOINT_OVER),
91 : PACK (DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE),
92 : PACK (DISJOINT_IN, DISJOINT_IN, DISJOINT_IN, DISJOINT_IN),
93 : PACK (DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE),
94 : PACK (DISJOINT_OUT, DISJOINT_OUT, DISJOINT_OUT, DISJOINT_OUT),
95 : PACK (DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE),
96 : PACK (DISJOINT_ATOP, DISJOINT_ATOP, DISJOINT_ATOP, DISJOINT_ATOP),
97 : PACK (DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE),
98 : PACK (DISJOINT_XOR, DISJOINT_XOR, DISJOINT_XOR, DISJOINT_XOR),
99 :
100 : {{ 0 /* 0x1c */ }},
101 : {{ 0 /* 0x1d */ }},
102 : {{ 0 /* 0x1e */ }},
103 : {{ 0 /* 0x1f */ }},
104 :
105 : PACK (CLEAR, CLEAR, CLEAR, CLEAR),
106 : PACK (SRC, SRC, SRC, SRC),
107 : PACK (DST, DST, DST, DST),
108 : PACK (CONJOINT_OVER, CONJOINT_OVER, CONJOINT_OVER, CONJOINT_OVER),
109 : PACK (CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE),
110 : PACK (CONJOINT_IN, CONJOINT_IN, CONJOINT_IN, CONJOINT_IN),
111 : PACK (CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE),
112 : PACK (CONJOINT_OUT, CONJOINT_OUT, CONJOINT_OUT, CONJOINT_OUT),
113 : PACK (CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE),
114 : PACK (CONJOINT_ATOP, CONJOINT_ATOP, CONJOINT_ATOP, CONJOINT_ATOP),
115 : PACK (CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE),
116 : PACK (CONJOINT_XOR, CONJOINT_XOR, CONJOINT_XOR, CONJOINT_XOR),
117 :
118 : {{ 0 /* 0x2c */ }},
119 : {{ 0 /* 0x2d */ }},
120 : {{ 0 /* 0x2e */ }},
121 : {{ 0 /* 0x2f */ }},
122 :
123 : PACK (MULTIPLY, MULTIPLY, MULTIPLY, MULTIPLY),
124 : PACK (SCREEN, SCREEN, SCREEN, SCREEN),
125 : PACK (OVERLAY, OVERLAY, OVERLAY, OVERLAY),
126 : PACK (DARKEN, DARKEN, DARKEN, DARKEN),
127 : PACK (LIGHTEN, LIGHTEN, LIGHTEN, LIGHTEN),
128 : PACK (COLOR_DODGE, COLOR_DODGE, COLOR_DODGE, COLOR_DODGE),
129 : PACK (COLOR_BURN, COLOR_BURN, COLOR_BURN, COLOR_BURN),
130 : PACK (HARD_LIGHT, HARD_LIGHT, HARD_LIGHT, HARD_LIGHT),
131 : PACK (SOFT_LIGHT, SOFT_LIGHT, SOFT_LIGHT, SOFT_LIGHT),
132 : PACK (DIFFERENCE, DIFFERENCE, DIFFERENCE, DIFFERENCE),
133 : PACK (EXCLUSION, EXCLUSION, EXCLUSION, EXCLUSION),
134 : PACK (HSL_HUE, HSL_HUE, HSL_HUE, HSL_HUE),
135 : PACK (HSL_SATURATION, HSL_SATURATION, HSL_SATURATION, HSL_SATURATION),
136 : PACK (HSL_COLOR, HSL_COLOR, HSL_COLOR, HSL_COLOR),
137 : PACK (HSL_LUMINOSITY, HSL_LUMINOSITY, HSL_LUMINOSITY, HSL_LUMINOSITY),
138 : };
139 :
140 : /*
141 : * Optimize the current operator based on opacity of source or destination
142 : * The output operator should be mathematically equivalent to the source.
143 : */
144 : static pixman_op_t
145 47 : optimize_operator (pixman_op_t op,
146 : uint32_t src_flags,
147 : uint32_t mask_flags,
148 : uint32_t dst_flags)
149 : {
150 : pixman_bool_t is_source_opaque, is_dest_opaque;
151 :
152 : #define OPAQUE_SHIFT 13
153 :
154 : COMPILE_TIME_ASSERT (FAST_PATH_IS_OPAQUE == (1 << OPAQUE_SHIFT));
155 :
156 47 : is_dest_opaque = (dst_flags & FAST_PATH_IS_OPAQUE);
157 47 : is_source_opaque = ((src_flags & mask_flags) & FAST_PATH_IS_OPAQUE);
158 :
159 47 : is_dest_opaque >>= OPAQUE_SHIFT - 1;
160 47 : is_source_opaque >>= OPAQUE_SHIFT;
161 :
162 47 : return operator_table[op].opaque_info[is_dest_opaque | is_source_opaque];
163 : }
164 :
165 : /*
166 : * Computing composite region
167 : */
168 : static inline pixman_bool_t
169 0 : clip_general_image (pixman_region32_t * region,
170 : pixman_region32_t * clip,
171 : int dx,
172 : int dy)
173 : {
174 0 : if (pixman_region32_n_rects (region) == 1 &&
175 0 : pixman_region32_n_rects (clip) == 1)
176 0 : {
177 0 : pixman_box32_t * rbox = pixman_region32_rectangles (region, NULL);
178 0 : pixman_box32_t * cbox = pixman_region32_rectangles (clip, NULL);
179 : int v;
180 :
181 0 : if (rbox->x1 < (v = cbox->x1 + dx))
182 0 : rbox->x1 = v;
183 0 : if (rbox->x2 > (v = cbox->x2 + dx))
184 0 : rbox->x2 = v;
185 0 : if (rbox->y1 < (v = cbox->y1 + dy))
186 0 : rbox->y1 = v;
187 0 : if (rbox->y2 > (v = cbox->y2 + dy))
188 0 : rbox->y2 = v;
189 0 : if (rbox->x1 >= rbox->x2 || rbox->y1 >= rbox->y2)
190 : {
191 0 : pixman_region32_init (region);
192 0 : return FALSE;
193 : }
194 : }
195 0 : else if (!pixman_region32_not_empty (clip))
196 : {
197 0 : return FALSE;
198 : }
199 : else
200 : {
201 0 : if (dx || dy)
202 0 : pixman_region32_translate (region, -dx, -dy);
203 :
204 0 : if (!pixman_region32_intersect (region, region, clip))
205 0 : return FALSE;
206 :
207 0 : if (dx || dy)
208 0 : pixman_region32_translate (region, dx, dy);
209 : }
210 :
211 0 : return pixman_region32_not_empty (region);
212 : }
213 :
214 : static inline pixman_bool_t
215 0 : clip_source_image (pixman_region32_t * region,
216 : pixman_image_t * image,
217 : int dx,
218 : int dy)
219 : {
220 : /* Source clips are ignored, unless they are explicitly turned on
221 : * and the clip in question was set by an X client. (Because if
222 : * the clip was not set by a client, then it is a hierarchy
223 : * clip and those should always be ignored for sources).
224 : */
225 0 : if (!image->common.clip_sources || !image->common.client_clip)
226 0 : return TRUE;
227 :
228 0 : return clip_general_image (region,
229 : &image->common.clip_region,
230 : dx, dy);
231 : }
232 :
233 : /*
234 : * returns FALSE if the final region is empty. Indistinguishable from
235 : * an allocation failure, but rendering ignores those anyways.
236 : */
237 : static pixman_bool_t
238 47 : pixman_compute_composite_region32 (pixman_region32_t * region,
239 : pixman_image_t * src_image,
240 : pixman_image_t * mask_image,
241 : pixman_image_t * dst_image,
242 : int32_t src_x,
243 : int32_t src_y,
244 : int32_t mask_x,
245 : int32_t mask_y,
246 : int32_t dest_x,
247 : int32_t dest_y,
248 : int32_t width,
249 : int32_t height)
250 : {
251 47 : region->extents.x1 = dest_x;
252 47 : region->extents.x2 = dest_x + width;
253 47 : region->extents.y1 = dest_y;
254 47 : region->extents.y2 = dest_y + height;
255 :
256 47 : region->extents.x1 = MAX (region->extents.x1, 0);
257 47 : region->extents.y1 = MAX (region->extents.y1, 0);
258 47 : region->extents.x2 = MIN (region->extents.x2, dst_image->bits.width);
259 47 : region->extents.y2 = MIN (region->extents.y2, dst_image->bits.height);
260 :
261 47 : region->data = 0;
262 :
263 : /* Check for empty operation */
264 94 : if (region->extents.x1 >= region->extents.x2 ||
265 47 : region->extents.y1 >= region->extents.y2)
266 : {
267 0 : region->extents.x1 = 0;
268 0 : region->extents.x2 = 0;
269 0 : region->extents.y1 = 0;
270 0 : region->extents.y2 = 0;
271 0 : return FALSE;
272 : }
273 :
274 47 : if (dst_image->common.have_clip_region)
275 : {
276 0 : if (!clip_general_image (region, &dst_image->common.clip_region, 0, 0))
277 0 : return FALSE;
278 : }
279 :
280 47 : if (dst_image->common.alpha_map)
281 : {
282 0 : if (!pixman_region32_intersect_rect (region, region,
283 : dst_image->common.alpha_origin_x,
284 : dst_image->common.alpha_origin_y,
285 0 : dst_image->common.alpha_map->width,
286 0 : dst_image->common.alpha_map->height))
287 : {
288 0 : return FALSE;
289 : }
290 0 : if (!pixman_region32_not_empty (region))
291 0 : return FALSE;
292 0 : if (dst_image->common.alpha_map->common.have_clip_region)
293 : {
294 0 : if (!clip_general_image (region, &dst_image->common.alpha_map->common.clip_region,
295 0 : -dst_image->common.alpha_origin_x,
296 0 : -dst_image->common.alpha_origin_y))
297 : {
298 0 : return FALSE;
299 : }
300 : }
301 : }
302 :
303 : /* clip against src */
304 47 : if (src_image->common.have_clip_region)
305 : {
306 0 : if (!clip_source_image (region, src_image, dest_x - src_x, dest_y - src_y))
307 0 : return FALSE;
308 : }
309 47 : if (src_image->common.alpha_map && src_image->common.alpha_map->common.have_clip_region)
310 : {
311 0 : if (!clip_source_image (region, (pixman_image_t *)src_image->common.alpha_map,
312 0 : dest_x - (src_x - src_image->common.alpha_origin_x),
313 0 : dest_y - (src_y - src_image->common.alpha_origin_y)))
314 : {
315 0 : return FALSE;
316 : }
317 : }
318 : /* clip against mask */
319 47 : if (mask_image && mask_image->common.have_clip_region)
320 : {
321 0 : if (!clip_source_image (region, mask_image, dest_x - mask_x, dest_y - mask_y))
322 0 : return FALSE;
323 :
324 0 : if (mask_image->common.alpha_map && mask_image->common.alpha_map->common.have_clip_region)
325 : {
326 0 : if (!clip_source_image (region, (pixman_image_t *)mask_image->common.alpha_map,
327 0 : dest_x - (mask_x - mask_image->common.alpha_origin_x),
328 0 : dest_y - (mask_y - mask_image->common.alpha_origin_y)))
329 : {
330 0 : return FALSE;
331 : }
332 : }
333 : }
334 :
335 47 : return TRUE;
336 : }
337 :
338 : static void
339 47 : walk_region_internal (pixman_implementation_t *imp,
340 : pixman_op_t op,
341 : pixman_image_t * src_image,
342 : pixman_image_t * mask_image,
343 : pixman_image_t * dst_image,
344 : int32_t src_x,
345 : int32_t src_y,
346 : int32_t mask_x,
347 : int32_t mask_y,
348 : int32_t dest_x,
349 : int32_t dest_y,
350 : int32_t width,
351 : int32_t height,
352 : pixman_bool_t src_repeat,
353 : pixman_bool_t mask_repeat,
354 : pixman_region32_t * region,
355 : pixman_composite_func_t composite_rect)
356 : {
357 : int w, h, w_this, h_this;
358 : int x_msk, y_msk, x_src, y_src, x_dst, y_dst;
359 47 : int src_dy = src_y - dest_y;
360 47 : int src_dx = src_x - dest_x;
361 47 : int mask_dy = mask_y - dest_y;
362 47 : int mask_dx = mask_x - dest_x;
363 : const pixman_box32_t *pbox;
364 : int n;
365 :
366 47 : pbox = pixman_region32_rectangles (region, &n);
367 :
368 : /* Fast path for non-repeating sources */
369 47 : if (!src_repeat && !mask_repeat)
370 : {
371 141 : while (n--)
372 : {
373 282 : (*composite_rect) (imp, op,
374 : src_image, mask_image, dst_image,
375 47 : pbox->x1 + src_dx,
376 47 : pbox->y1 + src_dy,
377 47 : pbox->x1 + mask_dx,
378 47 : pbox->y1 + mask_dy,
379 : pbox->x1,
380 : pbox->y1,
381 47 : pbox->x2 - pbox->x1,
382 47 : pbox->y2 - pbox->y1);
383 :
384 47 : pbox++;
385 : }
386 :
387 47 : return;
388 : }
389 :
390 0 : while (n--)
391 : {
392 0 : h = pbox->y2 - pbox->y1;
393 0 : y_src = pbox->y1 + src_dy;
394 0 : y_msk = pbox->y1 + mask_dy;
395 0 : y_dst = pbox->y1;
396 :
397 0 : while (h)
398 : {
399 0 : h_this = h;
400 0 : w = pbox->x2 - pbox->x1;
401 0 : x_src = pbox->x1 + src_dx;
402 0 : x_msk = pbox->x1 + mask_dx;
403 0 : x_dst = pbox->x1;
404 :
405 0 : if (mask_repeat)
406 : {
407 0 : y_msk = MOD (y_msk, mask_image->bits.height);
408 0 : if (h_this > mask_image->bits.height - y_msk)
409 0 : h_this = mask_image->bits.height - y_msk;
410 : }
411 :
412 0 : if (src_repeat)
413 : {
414 0 : y_src = MOD (y_src, src_image->bits.height);
415 0 : if (h_this > src_image->bits.height - y_src)
416 0 : h_this = src_image->bits.height - y_src;
417 : }
418 :
419 0 : while (w)
420 : {
421 0 : w_this = w;
422 :
423 0 : if (mask_repeat)
424 : {
425 0 : x_msk = MOD (x_msk, mask_image->bits.width);
426 0 : if (w_this > mask_image->bits.width - x_msk)
427 0 : w_this = mask_image->bits.width - x_msk;
428 : }
429 :
430 0 : if (src_repeat)
431 : {
432 0 : x_src = MOD (x_src, src_image->bits.width);
433 0 : if (w_this > src_image->bits.width - x_src)
434 0 : w_this = src_image->bits.width - x_src;
435 : }
436 :
437 0 : (*composite_rect) (imp, op,
438 : src_image, mask_image, dst_image,
439 : x_src, y_src, x_msk, y_msk, x_dst, y_dst,
440 : w_this, h_this);
441 0 : w -= w_this;
442 :
443 0 : x_src += w_this;
444 0 : x_msk += w_this;
445 0 : x_dst += w_this;
446 : }
447 :
448 0 : h -= h_this;
449 0 : y_src += h_this;
450 0 : y_msk += h_this;
451 0 : y_dst += h_this;
452 : }
453 :
454 0 : pbox++;
455 : }
456 : }
457 :
458 : #define N_CACHED_FAST_PATHS 8
459 :
460 : typedef struct
461 : {
462 : struct
463 : {
464 : pixman_implementation_t * imp;
465 : pixman_fast_path_t fast_path;
466 : } cache [N_CACHED_FAST_PATHS];
467 : } cache_t;
468 :
469 : PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
470 :
471 : static force_inline pixman_bool_t
472 : lookup_composite_function (pixman_op_t op,
473 : pixman_format_code_t src_format,
474 : uint32_t src_flags,
475 : pixman_format_code_t mask_format,
476 : uint32_t mask_flags,
477 : pixman_format_code_t dest_format,
478 : uint32_t dest_flags,
479 : pixman_implementation_t **out_imp,
480 : pixman_composite_func_t *out_func)
481 : {
482 : pixman_implementation_t *imp;
483 : cache_t *cache;
484 : int i;
485 :
486 : /* Check cache for fast paths */
487 47 : cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
488 :
489 197 : for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
490 : {
491 184 : const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
492 :
493 : /* Note that we check for equality here, not whether
494 : * the cached fast path matches. This is to prevent
495 : * us from selecting an overly general fast path
496 : * when a more specific one would work.
497 : */
498 289 : if (info->op == op &&
499 170 : info->src_format == src_format &&
500 130 : info->mask_format == mask_format &&
501 117 : info->dest_format == dest_format &&
502 86 : info->src_flags == src_flags &&
503 68 : info->mask_flags == mask_flags &&
504 68 : info->dest_flags == dest_flags &&
505 34 : info->func)
506 : {
507 34 : *out_imp = cache->cache[i].imp;
508 34 : *out_func = cache->cache[i].fast_path.func;
509 :
510 : goto update_cache;
511 : }
512 : }
513 :
514 0 : for (imp = get_implementation (); imp != NULL; imp = imp->delegate)
515 : {
516 13 : const pixman_fast_path_t *info = imp->fast_paths;
517 :
518 945 : while (info->op != PIXMAN_OP_NONE)
519 : {
520 1080 : if ((info->op == op || info->op == PIXMAN_OP_any) &&
521 : /* Formats */
522 243 : ((info->src_format == src_format) ||
523 135 : (info->src_format == PIXMAN_any)) &&
524 27 : ((info->mask_format == mask_format) ||
525 27 : (info->mask_format == PIXMAN_any)) &&
526 35 : ((info->dest_format == dest_format) ||
527 27 : (info->dest_format == PIXMAN_any)) &&
528 : /* Flags */
529 32 : (info->src_flags & src_flags) == info->src_flags &&
530 26 : (info->mask_flags & mask_flags) == info->mask_flags &&
531 13 : (info->dest_flags & dest_flags) == info->dest_flags)
532 : {
533 13 : *out_imp = imp;
534 13 : *out_func = info->func;
535 :
536 : /* Set i to the last spot in the cache so that the
537 : * move-to-front code below will work
538 : */
539 13 : i = N_CACHED_FAST_PATHS - 1;
540 :
541 : goto update_cache;
542 : }
543 :
544 932 : ++info;
545 : }
546 : }
547 0 : return FALSE;
548 :
549 : update_cache:
550 47 : if (i)
551 : {
552 170 : while (i--)
553 137 : cache->cache[i + 1] = cache->cache[i];
554 :
555 33 : cache->cache[0].imp = *out_imp;
556 33 : cache->cache[0].fast_path.op = op;
557 33 : cache->cache[0].fast_path.src_format = src_format;
558 33 : cache->cache[0].fast_path.src_flags = src_flags;
559 33 : cache->cache[0].fast_path.mask_format = mask_format;
560 33 : cache->cache[0].fast_path.mask_flags = mask_flags;
561 33 : cache->cache[0].fast_path.dest_format = dest_format;
562 33 : cache->cache[0].fast_path.dest_flags = dest_flags;
563 33 : cache->cache[0].fast_path.func = *out_func;
564 : }
565 :
566 47 : return TRUE;
567 : }
568 :
569 : static pixman_bool_t
570 20 : compute_sample_extents (pixman_transform_t *transform,
571 : pixman_box32_t *extents, int x, int y,
572 : pixman_fixed_t x_off, pixman_fixed_t y_off,
573 : pixman_fixed_t width, pixman_fixed_t height)
574 : {
575 : pixman_fixed_t x1, y1, x2, y2;
576 : pixman_fixed_48_16_t tx1, ty1, tx2, ty2;
577 :
578 : /* We have checked earlier that (extents->x1 - x) etc. fit in a pixman_fixed_t */
579 20 : x1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x1 - x) + pixman_fixed_1 / 2;
580 20 : y1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y1 - y) + pixman_fixed_1 / 2;
581 20 : x2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x2 - x) - pixman_fixed_1 / 2;
582 20 : y2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y2 - y) - pixman_fixed_1 / 2;
583 :
584 20 : if (!transform)
585 : {
586 0 : tx1 = (pixman_fixed_48_16_t)x1;
587 0 : ty1 = (pixman_fixed_48_16_t)y1;
588 0 : tx2 = (pixman_fixed_48_16_t)x2;
589 0 : ty2 = (pixman_fixed_48_16_t)y2;
590 : }
591 : else
592 : {
593 : int i;
594 :
595 : /* Silence GCC */
596 20 : tx1 = ty1 = tx2 = ty2 = 0;
597 :
598 100 : for (i = 0; i < 4; ++i)
599 : {
600 : pixman_fixed_48_16_t tx, ty;
601 : pixman_vector_t v;
602 :
603 80 : v.vector[0] = (i & 0x01)? x1 : x2;
604 80 : v.vector[1] = (i & 0x02)? y1 : y2;
605 80 : v.vector[2] = pixman_fixed_1;
606 :
607 80 : if (!pixman_transform_point (transform, &v))
608 0 : return FALSE;
609 :
610 80 : tx = (pixman_fixed_48_16_t)v.vector[0];
611 80 : ty = (pixman_fixed_48_16_t)v.vector[1];
612 :
613 80 : if (i == 0)
614 : {
615 20 : tx1 = tx;
616 20 : ty1 = ty;
617 20 : tx2 = tx;
618 20 : ty2 = ty;
619 : }
620 : else
621 : {
622 60 : if (tx < tx1)
623 20 : tx1 = tx;
624 60 : if (ty < ty1)
625 20 : ty1 = ty;
626 60 : if (tx > tx2)
627 0 : tx2 = tx;
628 60 : if (ty > ty2)
629 0 : ty2 = ty;
630 : }
631 : }
632 : }
633 :
634 : /* Expand the source area by a tiny bit so account of different rounding that
635 : * may happen during sampling. Note that (8 * pixman_fixed_e) is very far from
636 : * 0.5 so this won't cause the area computed to be overly pessimistic.
637 : */
638 20 : tx1 += x_off - 8 * pixman_fixed_e;
639 20 : ty1 += y_off - 8 * pixman_fixed_e;
640 20 : tx2 += x_off + width + 8 * pixman_fixed_e;
641 20 : ty2 += y_off + height + 8 * pixman_fixed_e;
642 :
643 20 : if (tx1 < pixman_min_fixed_48_16 || tx1 > pixman_max_fixed_48_16 ||
644 20 : ty1 < pixman_min_fixed_48_16 || ty1 > pixman_max_fixed_48_16 ||
645 20 : tx2 < pixman_min_fixed_48_16 || tx2 > pixman_max_fixed_48_16 ||
646 20 : ty2 < pixman_min_fixed_48_16 || ty2 > pixman_max_fixed_48_16)
647 : {
648 0 : return FALSE;
649 : }
650 : else
651 : {
652 20 : extents->x1 = pixman_fixed_to_int (tx1);
653 20 : extents->y1 = pixman_fixed_to_int (ty1);
654 20 : extents->x2 = pixman_fixed_to_int (tx2) + 1;
655 20 : extents->y2 = pixman_fixed_to_int (ty2) + 1;
656 :
657 20 : return TRUE;
658 : }
659 : }
660 :
661 : #define IS_16BIT(x) (((x) >= INT16_MIN) && ((x) <= INT16_MAX))
662 :
663 : static pixman_bool_t
664 94 : analyze_extent (pixman_image_t *image, int x, int y,
665 : const pixman_box32_t *extents, uint32_t *flags)
666 : {
667 : pixman_transform_t *transform;
668 : pixman_fixed_t *params;
669 : pixman_fixed_t x_off, y_off;
670 : pixman_fixed_t width, height;
671 : pixman_box32_t ex;
672 :
673 94 : if (!image)
674 47 : return TRUE;
675 :
676 : /* Some compositing functions walk one step
677 : * outside the destination rectangle, so we
678 : * check here that the expanded-by-one source
679 : * extents in destination space fits in 16 bits
680 : */
681 94 : if (!IS_16BIT (extents->x1 - x - 1) ||
682 141 : !IS_16BIT (extents->y1 - y - 1) ||
683 141 : !IS_16BIT (extents->x2 - x + 1) ||
684 94 : !IS_16BIT (extents->y2 - y + 1))
685 : {
686 0 : return FALSE;
687 : }
688 :
689 47 : transform = image->common.transform;
690 47 : if (image->common.type == BITS)
691 : {
692 : /* During repeat mode calculations we might convert the
693 : * width/height of an image to fixed 16.16, so we need
694 : * them to be smaller than 16 bits.
695 : */
696 47 : if (image->bits.width >= 0x7fff || image->bits.height >= 0x7fff)
697 0 : return FALSE;
698 :
699 : #define ID_AND_NEAREST (FAST_PATH_ID_TRANSFORM | FAST_PATH_NEAREST_FILTER)
700 :
701 84 : if ((image->common.flags & ID_AND_NEAREST) == ID_AND_NEAREST &&
702 74 : extents->x1 - x >= 0 &&
703 74 : extents->y1 - y >= 0 &&
704 74 : extents->x2 - x <= image->bits.width &&
705 37 : extents->y2 - y <= image->bits.height)
706 : {
707 37 : *flags |= FAST_PATH_SAMPLES_COVER_CLIP;
708 37 : return TRUE;
709 : }
710 :
711 10 : switch (image->common.filter)
712 : {
713 : case PIXMAN_FILTER_CONVOLUTION:
714 0 : params = image->common.filter_params;
715 0 : x_off = - pixman_fixed_e - ((params[0] - pixman_fixed_1) >> 1);
716 0 : y_off = - pixman_fixed_e - ((params[1] - pixman_fixed_1) >> 1);
717 0 : width = params[0];
718 0 : height = params[1];
719 0 : break;
720 :
721 : case PIXMAN_FILTER_GOOD:
722 : case PIXMAN_FILTER_BEST:
723 : case PIXMAN_FILTER_BILINEAR:
724 10 : x_off = - pixman_fixed_1 / 2;
725 10 : y_off = - pixman_fixed_1 / 2;
726 10 : width = pixman_fixed_1;
727 10 : height = pixman_fixed_1;
728 10 : break;
729 :
730 : case PIXMAN_FILTER_FAST:
731 : case PIXMAN_FILTER_NEAREST:
732 0 : x_off = - pixman_fixed_e;
733 0 : y_off = - pixman_fixed_e;
734 0 : width = 0;
735 0 : height = 0;
736 0 : break;
737 :
738 : default:
739 0 : return FALSE;
740 : }
741 :
742 : /* Check whether the non-expanded, transformed extent is entirely within
743 : * the source image, and set the FAST_PATH_SAMPLES_COVER_CLIP if it is.
744 : */
745 10 : ex = *extents;
746 20 : if (compute_sample_extents (transform, &ex, x, y, x_off, y_off, width, height) &&
747 23 : ex.x1 >= 0 && ex.y1 >= 0 &&
748 12 : ex.x2 <= image->bits.width && ex.y2 <= image->bits.height)
749 : {
750 6 : *flags |= FAST_PATH_SAMPLES_COVER_CLIP;
751 : }
752 : }
753 : else
754 : {
755 0 : x_off = 0;
756 0 : y_off = 0;
757 0 : width = 0;
758 0 : height = 0;
759 : }
760 :
761 : /* Check that the extents expanded by one don't overflow. This ensures that
762 : * compositing functions can simply walk the source space using 16.16
763 : * variables without worrying about overflow.
764 : */
765 10 : ex.x1 = extents->x1 - 1;
766 10 : ex.y1 = extents->y1 - 1;
767 10 : ex.x2 = extents->x2 + 1;
768 10 : ex.y2 = extents->y2 + 1;
769 :
770 10 : if (!compute_sample_extents (transform, &ex, x, y, x_off, y_off, width, height))
771 0 : return FALSE;
772 :
773 10 : return TRUE;
774 : }
775 :
776 : /*
777 : * Work around GCC bug causing crashes in Mozilla with SSE2
778 : *
779 : * When using -msse, gcc generates movdqa instructions assuming that
780 : * the stack is 16 byte aligned. Unfortunately some applications, such
781 : * as Mozilla and Mono, end up aligning the stack to 4 bytes, which
782 : * causes the movdqa instructions to fail.
783 : *
784 : * The __force_align_arg_pointer__ makes gcc generate a prologue that
785 : * realigns the stack pointer to 16 bytes.
786 : *
787 : * On x86-64 this is not necessary because the standard ABI already
788 : * calls for a 16 byte aligned stack.
789 : *
790 : * See https://bugs.freedesktop.org/show_bug.cgi?id=15693
791 : */
792 : #if defined (USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
793 : __attribute__((__force_align_arg_pointer__))
794 : #endif
795 : PIXMAN_EXPORT void
796 47 : pixman_image_composite32 (pixman_op_t op,
797 : pixman_image_t * src,
798 : pixman_image_t * mask,
799 : pixman_image_t * dest,
800 : int32_t src_x,
801 : int32_t src_y,
802 : int32_t mask_x,
803 : int32_t mask_y,
804 : int32_t dest_x,
805 : int32_t dest_y,
806 : int32_t width,
807 : int32_t height)
808 : {
809 : pixman_format_code_t src_format, mask_format, dest_format;
810 : uint32_t src_flags, mask_flags, dest_flags;
811 : pixman_region32_t region;
812 : pixman_box32_t *extents;
813 : pixman_implementation_t *imp;
814 : pixman_composite_func_t func;
815 :
816 47 : _pixman_image_validate (src);
817 47 : if (mask)
818 0 : _pixman_image_validate (mask);
819 47 : _pixman_image_validate (dest);
820 :
821 47 : src_format = src->common.extended_format_code;
822 47 : src_flags = src->common.flags;
823 :
824 47 : if (mask)
825 : {
826 0 : mask_format = mask->common.extended_format_code;
827 0 : mask_flags = mask->common.flags;
828 : }
829 : else
830 : {
831 47 : mask_format = PIXMAN_null;
832 47 : mask_flags = FAST_PATH_IS_OPAQUE;
833 : }
834 :
835 47 : dest_format = dest->common.extended_format_code;
836 47 : dest_flags = dest->common.flags;
837 :
838 : /* Check for pixbufs */
839 47 : if ((mask_format == PIXMAN_a8r8g8b8 || mask_format == PIXMAN_a8b8g8r8) &&
840 0 : (src->type == BITS && src->bits.bits == mask->bits.bits) &&
841 0 : (src->common.repeat == mask->common.repeat) &&
842 0 : (src_x == mask_x && src_y == mask_y))
843 : {
844 0 : if (src_format == PIXMAN_x8b8g8r8)
845 0 : src_format = mask_format = PIXMAN_pixbuf;
846 0 : else if (src_format == PIXMAN_x8r8g8b8)
847 0 : src_format = mask_format = PIXMAN_rpixbuf;
848 : }
849 :
850 47 : pixman_region32_init (®ion);
851 :
852 47 : if (!pixman_compute_composite_region32 (
853 : ®ion, src, mask, dest,
854 : src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
855 : {
856 0 : goto out;
857 : }
858 :
859 47 : extents = pixman_region32_extents (®ion);
860 :
861 47 : if (!analyze_extent (src, dest_x - src_x, dest_y - src_y, extents, &src_flags))
862 0 : goto out;
863 :
864 47 : if (!analyze_extent (mask, dest_x - mask_x, dest_y - mask_y, extents, &mask_flags))
865 0 : goto out;
866 :
867 : /* If the clip is within the source samples, and the samples are opaque,
868 : * then the source is effectively opaque.
869 : */
870 : #define BOTH (FAST_PATH_SAMPLES_OPAQUE | FAST_PATH_SAMPLES_COVER_CLIP)
871 :
872 47 : if ((src_flags & BOTH) == BOTH)
873 17 : src_flags |= FAST_PATH_IS_OPAQUE;
874 :
875 47 : if ((mask_flags & BOTH) == BOTH)
876 0 : mask_flags |= FAST_PATH_IS_OPAQUE;
877 :
878 : /*
879 : * Check if we can replace our operator by a simpler one
880 : * if the src or dest are opaque. The output operator should be
881 : * mathematically equivalent to the source.
882 : */
883 47 : op = optimize_operator (op, src_flags, mask_flags, dest_flags);
884 47 : if (op == PIXMAN_OP_DST)
885 0 : goto out;
886 :
887 94 : if (lookup_composite_function (op,
888 : src_format, src_flags,
889 : mask_format, mask_flags,
890 : dest_format, dest_flags,
891 : &imp, &func))
892 : {
893 47 : walk_region_internal (imp, op,
894 : src, mask, dest,
895 : src_x, src_y, mask_x, mask_y,
896 : dest_x, dest_y,
897 : width, height,
898 : (src_flags & FAST_PATH_SIMPLE_REPEAT),
899 : (mask_flags & FAST_PATH_SIMPLE_REPEAT),
900 : ®ion, func);
901 : }
902 :
903 : out:
904 47 : pixman_region32_fini (®ion);
905 47 : }
906 :
907 : PIXMAN_EXPORT void
908 0 : pixman_image_composite (pixman_op_t op,
909 : pixman_image_t * src,
910 : pixman_image_t * mask,
911 : pixman_image_t * dest,
912 : int16_t src_x,
913 : int16_t src_y,
914 : int16_t mask_x,
915 : int16_t mask_y,
916 : int16_t dest_x,
917 : int16_t dest_y,
918 : uint16_t width,
919 : uint16_t height)
920 : {
921 0 : pixman_image_composite32 (op, src, mask, dest, src_x, src_y,
922 : mask_x, mask_y, dest_x, dest_y, width, height);
923 0 : }
924 :
925 : PIXMAN_EXPORT pixman_bool_t
926 0 : pixman_blt (uint32_t *src_bits,
927 : uint32_t *dst_bits,
928 : int src_stride,
929 : int dst_stride,
930 : int src_bpp,
931 : int dst_bpp,
932 : int src_x,
933 : int src_y,
934 : int dst_x,
935 : int dst_y,
936 : int width,
937 : int height)
938 : {
939 0 : return _pixman_implementation_blt (get_implementation(),
940 : src_bits, dst_bits, src_stride, dst_stride,
941 : src_bpp, dst_bpp,
942 : src_x, src_y,
943 : dst_x, dst_y,
944 : width, height);
945 : }
946 :
947 : PIXMAN_EXPORT pixman_bool_t
948 17 : pixman_fill (uint32_t *bits,
949 : int stride,
950 : int bpp,
951 : int x,
952 : int y,
953 : int width,
954 : int height,
955 : uint32_t xor)
956 : {
957 17 : return _pixman_implementation_fill (
958 : get_implementation(), bits, stride, bpp, x, y, width, height, xor);
959 : }
960 :
961 : static uint32_t
962 0 : color_to_uint32 (const pixman_color_t *color)
963 : {
964 0 : return
965 0 : (color->alpha >> 8 << 24) |
966 0 : (color->red >> 8 << 16) |
967 0 : (color->green & 0xff00) |
968 0 : (color->blue >> 8);
969 : }
970 :
971 : static pixman_bool_t
972 0 : color_to_pixel (pixman_color_t * color,
973 : uint32_t * pixel,
974 : pixman_format_code_t format)
975 : {
976 0 : uint32_t c = color_to_uint32 (color);
977 :
978 0 : if (!(format == PIXMAN_a8r8g8b8 ||
979 0 : format == PIXMAN_x8r8g8b8 ||
980 0 : format == PIXMAN_a8b8g8r8 ||
981 0 : format == PIXMAN_x8b8g8r8 ||
982 0 : format == PIXMAN_b8g8r8a8 ||
983 0 : format == PIXMAN_b8g8r8x8 ||
984 0 : format == PIXMAN_r8g8b8a8 ||
985 0 : format == PIXMAN_r8g8b8x8 ||
986 0 : format == PIXMAN_r5g6b5 ||
987 0 : format == PIXMAN_b5g6r5 ||
988 : format == PIXMAN_a8 ||
989 : format == PIXMAN_a1))
990 : {
991 0 : return FALSE;
992 : }
993 :
994 0 : if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR)
995 : {
996 0 : c = ((c & 0xff000000) >> 0) |
997 0 : ((c & 0x00ff0000) >> 16) |
998 0 : ((c & 0x0000ff00) >> 0) |
999 0 : ((c & 0x000000ff) << 16);
1000 : }
1001 0 : if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA)
1002 : {
1003 0 : c = ((c & 0xff000000) >> 24) |
1004 0 : ((c & 0x00ff0000) >> 8) |
1005 0 : ((c & 0x0000ff00) << 8) |
1006 0 : ((c & 0x000000ff) << 24);
1007 : }
1008 0 : if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_RGBA)
1009 0 : c = ((c & 0xff000000) >> 24) | (c << 8);
1010 :
1011 0 : if (format == PIXMAN_a1)
1012 0 : c = c >> 31;
1013 0 : else if (format == PIXMAN_a8)
1014 0 : c = c >> 24;
1015 0 : else if (format == PIXMAN_r5g6b5 ||
1016 : format == PIXMAN_b5g6r5)
1017 0 : c = CONVERT_8888_TO_0565 (c);
1018 :
1019 : #if 0
1020 : printf ("color: %x %x %x %x\n", color->alpha, color->red, color->green, color->blue);
1021 : printf ("pixel: %x\n", c);
1022 : #endif
1023 :
1024 0 : *pixel = c;
1025 0 : return TRUE;
1026 : }
1027 :
1028 : PIXMAN_EXPORT pixman_bool_t
1029 0 : pixman_image_fill_rectangles (pixman_op_t op,
1030 : pixman_image_t * dest,
1031 : pixman_color_t * color,
1032 : int n_rects,
1033 : const pixman_rectangle16_t *rects)
1034 : {
1035 : pixman_box32_t stack_boxes[6];
1036 : pixman_box32_t *boxes;
1037 : pixman_bool_t result;
1038 : int i;
1039 :
1040 0 : if (n_rects > 6)
1041 : {
1042 0 : boxes = pixman_malloc_ab (sizeof (pixman_box32_t), n_rects);
1043 0 : if (boxes == NULL)
1044 0 : return FALSE;
1045 : }
1046 : else
1047 : {
1048 0 : boxes = stack_boxes;
1049 : }
1050 :
1051 0 : for (i = 0; i < n_rects; ++i)
1052 : {
1053 0 : boxes[i].x1 = rects[i].x;
1054 0 : boxes[i].y1 = rects[i].y;
1055 0 : boxes[i].x2 = boxes[i].x1 + rects[i].width;
1056 0 : boxes[i].y2 = boxes[i].y1 + rects[i].height;
1057 : }
1058 :
1059 0 : result = pixman_image_fill_boxes (op, dest, color, n_rects, boxes);
1060 :
1061 0 : if (boxes != stack_boxes)
1062 0 : free (boxes);
1063 :
1064 0 : return result;
1065 : }
1066 :
1067 : PIXMAN_EXPORT pixman_bool_t
1068 0 : pixman_image_fill_boxes (pixman_op_t op,
1069 : pixman_image_t * dest,
1070 : pixman_color_t * color,
1071 : int n_boxes,
1072 : const pixman_box32_t *boxes)
1073 : {
1074 : pixman_image_t *solid;
1075 : pixman_color_t c;
1076 : int i;
1077 :
1078 0 : _pixman_image_validate (dest);
1079 :
1080 0 : if (color->alpha == 0xffff)
1081 : {
1082 0 : if (op == PIXMAN_OP_OVER)
1083 0 : op = PIXMAN_OP_SRC;
1084 : }
1085 :
1086 0 : if (op == PIXMAN_OP_CLEAR)
1087 : {
1088 0 : c.red = 0;
1089 0 : c.green = 0;
1090 0 : c.blue = 0;
1091 0 : c.alpha = 0;
1092 :
1093 0 : color = &c;
1094 :
1095 0 : op = PIXMAN_OP_SRC;
1096 : }
1097 :
1098 0 : if (op == PIXMAN_OP_SRC)
1099 : {
1100 : uint32_t pixel;
1101 :
1102 0 : if (color_to_pixel (color, &pixel, dest->bits.format))
1103 : {
1104 : pixman_region32_t fill_region;
1105 : int n_rects, j;
1106 : pixman_box32_t *rects;
1107 :
1108 0 : if (!pixman_region32_init_rects (&fill_region, boxes, n_boxes))
1109 0 : return FALSE;
1110 :
1111 0 : if (dest->common.have_clip_region)
1112 : {
1113 0 : if (!pixman_region32_intersect (&fill_region,
1114 : &fill_region,
1115 : &dest->common.clip_region))
1116 0 : return FALSE;
1117 : }
1118 :
1119 0 : rects = pixman_region32_rectangles (&fill_region, &n_rects);
1120 0 : for (j = 0; j < n_rects; ++j)
1121 : {
1122 0 : const pixman_box32_t *rect = &(rects[j]);
1123 0 : pixman_fill (dest->bits.bits, dest->bits.rowstride, PIXMAN_FORMAT_BPP (dest->bits.format),
1124 0 : rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1,
1125 : pixel);
1126 : }
1127 :
1128 0 : pixman_region32_fini (&fill_region);
1129 0 : return TRUE;
1130 : }
1131 : }
1132 :
1133 0 : solid = pixman_image_create_solid_fill (color);
1134 0 : if (!solid)
1135 0 : return FALSE;
1136 :
1137 0 : for (i = 0; i < n_boxes; ++i)
1138 : {
1139 0 : const pixman_box32_t *box = &(boxes[i]);
1140 :
1141 0 : pixman_image_composite32 (op, solid, NULL, dest,
1142 : 0, 0, 0, 0,
1143 : box->x1, box->y1,
1144 0 : box->x2 - box->x1, box->y2 - box->y1);
1145 : }
1146 :
1147 0 : pixman_image_unref (solid);
1148 :
1149 0 : return TRUE;
1150 : }
1151 :
1152 : /**
1153 : * pixman_version:
1154 : *
1155 : * Returns the version of the pixman library encoded in a single
1156 : * integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that
1157 : * later versions compare greater than earlier versions.
1158 : *
1159 : * A run-time comparison to check that pixman's version is greater than
1160 : * or equal to version X.Y.Z could be performed as follows:
1161 : *
1162 : * <informalexample><programlisting>
1163 : * if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...}
1164 : * </programlisting></informalexample>
1165 : *
1166 : * See also pixman_version_string() as well as the compile-time
1167 : * equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING.
1168 : *
1169 : * Return value: the encoded version.
1170 : **/
1171 : PIXMAN_EXPORT int
1172 0 : pixman_version (void)
1173 : {
1174 0 : return PIXMAN_VERSION;
1175 : }
1176 :
1177 : /**
1178 : * pixman_version_string:
1179 : *
1180 : * Returns the version of the pixman library as a human-readable string
1181 : * of the form "X.Y.Z".
1182 : *
1183 : * See also pixman_version() as well as the compile-time equivalents
1184 : * %PIXMAN_VERSION_STRING and %PIXMAN_VERSION.
1185 : *
1186 : * Return value: a string containing the version.
1187 : **/
1188 : PIXMAN_EXPORT const char*
1189 0 : pixman_version_string (void)
1190 : {
1191 0 : return PIXMAN_VERSION_STRING;
1192 : }
1193 :
1194 : /**
1195 : * pixman_format_supported_source:
1196 : * @format: A pixman_format_code_t format
1197 : *
1198 : * Return value: whether the provided format code is a supported
1199 : * format for a pixman surface used as a source in
1200 : * rendering.
1201 : *
1202 : * Currently, all pixman_format_code_t values are supported.
1203 : **/
1204 : PIXMAN_EXPORT pixman_bool_t
1205 0 : pixman_format_supported_source (pixman_format_code_t format)
1206 : {
1207 0 : switch (format)
1208 : {
1209 : /* 32 bpp formats */
1210 : case PIXMAN_a2b10g10r10:
1211 : case PIXMAN_x2b10g10r10:
1212 : case PIXMAN_a2r10g10b10:
1213 : case PIXMAN_x2r10g10b10:
1214 : case PIXMAN_a8r8g8b8:
1215 : case PIXMAN_x8r8g8b8:
1216 : case PIXMAN_a8b8g8r8:
1217 : case PIXMAN_x8b8g8r8:
1218 : case PIXMAN_b8g8r8a8:
1219 : case PIXMAN_b8g8r8x8:
1220 : case PIXMAN_r8g8b8a8:
1221 : case PIXMAN_r8g8b8x8:
1222 : case PIXMAN_r8g8b8:
1223 : case PIXMAN_b8g8r8:
1224 : case PIXMAN_r5g6b5:
1225 : case PIXMAN_b5g6r5:
1226 : case PIXMAN_x14r6g6b6:
1227 : /* 16 bpp formats */
1228 : case PIXMAN_a1r5g5b5:
1229 : case PIXMAN_x1r5g5b5:
1230 : case PIXMAN_a1b5g5r5:
1231 : case PIXMAN_x1b5g5r5:
1232 : case PIXMAN_a4r4g4b4:
1233 : case PIXMAN_x4r4g4b4:
1234 : case PIXMAN_a4b4g4r4:
1235 : case PIXMAN_x4b4g4r4:
1236 : /* 8bpp formats */
1237 : case PIXMAN_a8:
1238 : case PIXMAN_r3g3b2:
1239 : case PIXMAN_b2g3r3:
1240 : case PIXMAN_a2r2g2b2:
1241 : case PIXMAN_a2b2g2r2:
1242 : case PIXMAN_c8:
1243 : case PIXMAN_g8:
1244 : case PIXMAN_x4a4:
1245 : /* Collides with PIXMAN_c8
1246 : case PIXMAN_x4c4:
1247 : */
1248 : /* Collides with PIXMAN_g8
1249 : case PIXMAN_x4g4:
1250 : */
1251 : /* 4bpp formats */
1252 : case PIXMAN_a4:
1253 : case PIXMAN_r1g2b1:
1254 : case PIXMAN_b1g2r1:
1255 : case PIXMAN_a1r1g1b1:
1256 : case PIXMAN_a1b1g1r1:
1257 : case PIXMAN_c4:
1258 : case PIXMAN_g4:
1259 : /* 1bpp formats */
1260 : case PIXMAN_a1:
1261 : case PIXMAN_g1:
1262 : /* YUV formats */
1263 : case PIXMAN_yuy2:
1264 : case PIXMAN_yv12:
1265 0 : return TRUE;
1266 :
1267 : default:
1268 0 : return FALSE;
1269 : }
1270 : }
1271 :
1272 : /**
1273 : * pixman_format_supported_destination:
1274 : * @format: A pixman_format_code_t format
1275 : *
1276 : * Return value: whether the provided format code is a supported
1277 : * format for a pixman surface used as a destination in
1278 : * rendering.
1279 : *
1280 : * Currently, all pixman_format_code_t values are supported
1281 : * except for the YUV formats.
1282 : **/
1283 : PIXMAN_EXPORT pixman_bool_t
1284 0 : pixman_format_supported_destination (pixman_format_code_t format)
1285 : {
1286 : /* YUV formats cannot be written to at the moment */
1287 0 : if (format == PIXMAN_yuy2 || format == PIXMAN_yv12)
1288 0 : return FALSE;
1289 :
1290 0 : return pixman_format_supported_source (format);
1291 : }
1292 :
1293 : PIXMAN_EXPORT pixman_bool_t
1294 0 : pixman_compute_composite_region (pixman_region16_t * region,
1295 : pixman_image_t * src_image,
1296 : pixman_image_t * mask_image,
1297 : pixman_image_t * dst_image,
1298 : int16_t src_x,
1299 : int16_t src_y,
1300 : int16_t mask_x,
1301 : int16_t mask_y,
1302 : int16_t dest_x,
1303 : int16_t dest_y,
1304 : uint16_t width,
1305 : uint16_t height)
1306 : {
1307 : pixman_region32_t r32;
1308 : pixman_bool_t retval;
1309 :
1310 0 : pixman_region32_init (&r32);
1311 :
1312 0 : retval = pixman_compute_composite_region32 (
1313 : &r32, src_image, mask_image, dst_image,
1314 : src_x, src_y, mask_x, mask_y, dest_x, dest_y,
1315 : width, height);
1316 :
1317 0 : if (retval)
1318 : {
1319 0 : if (!pixman_region16_copy_from_region32 (region, &r32))
1320 0 : retval = FALSE;
1321 : }
1322 :
1323 0 : pixman_region32_fini (&r32);
1324 0 : return retval;
1325 : }
|