Line data Source code
1 : /*
2 : * Copyright 2010, 2012, Soren Sandmann <sandmann@cs.au.dk>
3 : * Copyright 2010, 2011, 2012, Red Hat, Inc
4 : *
5 : * Permission is hereby granted, free of charge, to any person obtaining a
6 : * copy of this software and associated documentation files (the "Software"),
7 : * to deal in the Software without restriction, including without limitation
8 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 : * and/or sell copies of the Software, and to permit persons to whom the
10 : * Software is furnished to do so, subject to the following conditions:
11 : *
12 : * The above copyright notice and this permission notice (including the next
13 : * paragraph) shall be included in all copies or substantial portions of the
14 : * Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 : * DEALINGS IN THE SOFTWARE.
23 : *
24 : * Author: Soren Sandmann <sandmann@cs.au.dk>
25 : */
26 :
27 : #ifdef HAVE_CONFIG_H
28 : #include <config.h>
29 : #endif
30 : #include "pixman-private.h"
31 :
32 : #include <stdlib.h>
33 :
34 : typedef struct glyph_metrics_t glyph_metrics_t;
35 : typedef struct glyph_t glyph_t;
36 :
37 : #define TOMBSTONE ((glyph_t *)0x1)
38 :
39 : /* XXX: These numbers are arbitrary---we've never done any measurements.
40 : */
41 : #define N_GLYPHS_HIGH_WATER (16384)
42 : #define N_GLYPHS_LOW_WATER (8192)
43 : #define HASH_SIZE (2 * N_GLYPHS_HIGH_WATER)
44 : #define HASH_MASK (HASH_SIZE - 1)
45 :
46 : struct glyph_t
47 : {
48 : void * font_key;
49 : void * glyph_key;
50 : int origin_x;
51 : int origin_y;
52 : pixman_image_t * image;
53 : pixman_link_t mru_link;
54 : };
55 :
56 : struct pixman_glyph_cache_t
57 : {
58 : int n_glyphs;
59 : int n_tombstones;
60 : int freeze_count;
61 : pixman_list_t mru;
62 : glyph_t * glyphs[HASH_SIZE];
63 : };
64 :
65 : static void
66 0 : free_glyph (glyph_t *glyph)
67 : {
68 0 : pixman_list_unlink (&glyph->mru_link);
69 0 : pixman_image_unref (glyph->image);
70 0 : free (glyph);
71 0 : }
72 :
73 : static unsigned int
74 0 : hash (const void *font_key, const void *glyph_key)
75 : {
76 0 : size_t key = (size_t)font_key + (size_t)glyph_key;
77 :
78 : /* This hash function is based on one found on Thomas Wang's
79 : * web page at
80 : *
81 : * http://www.concentric.net/~Ttwang/tech/inthash.htm
82 : *
83 : */
84 0 : key = (key << 15) - key - 1;
85 0 : key = key ^ (key >> 12);
86 0 : key = key + (key << 2);
87 0 : key = key ^ (key >> 4);
88 0 : key = key + (key << 3) + (key << 11);
89 0 : key = key ^ (key >> 16);
90 :
91 0 : return key;
92 : }
93 :
94 : static glyph_t *
95 0 : lookup_glyph (pixman_glyph_cache_t *cache,
96 : void *font_key,
97 : void *glyph_key)
98 : {
99 : unsigned idx;
100 : glyph_t *g;
101 :
102 0 : idx = hash (font_key, glyph_key);
103 0 : while ((g = cache->glyphs[idx++ & HASH_MASK]))
104 : {
105 0 : if (g != TOMBSTONE &&
106 0 : g->font_key == font_key &&
107 0 : g->glyph_key == glyph_key)
108 : {
109 0 : return g;
110 : }
111 : }
112 :
113 0 : return NULL;
114 : }
115 :
116 : static void
117 0 : insert_glyph (pixman_glyph_cache_t *cache,
118 : glyph_t *glyph)
119 : {
120 : unsigned idx;
121 : glyph_t **loc;
122 :
123 0 : idx = hash (glyph->font_key, glyph->glyph_key);
124 :
125 : /* Note: we assume that there is room in the table. If there isn't,
126 : * this will be an infinite loop.
127 : */
128 : do
129 : {
130 0 : loc = &cache->glyphs[idx++ & HASH_MASK];
131 0 : } while (*loc && *loc != TOMBSTONE);
132 :
133 0 : if (*loc == TOMBSTONE)
134 0 : cache->n_tombstones--;
135 0 : cache->n_glyphs++;
136 :
137 0 : *loc = glyph;
138 0 : }
139 :
140 : static void
141 0 : remove_glyph (pixman_glyph_cache_t *cache,
142 : glyph_t *glyph)
143 : {
144 : unsigned idx;
145 :
146 0 : idx = hash (glyph->font_key, glyph->glyph_key);
147 0 : while (cache->glyphs[idx & HASH_MASK] != glyph)
148 0 : idx++;
149 :
150 0 : cache->glyphs[idx & HASH_MASK] = TOMBSTONE;
151 0 : cache->n_tombstones++;
152 0 : cache->n_glyphs--;
153 :
154 : /* Eliminate tombstones if possible */
155 0 : if (cache->glyphs[(idx + 1) & HASH_MASK] == NULL)
156 : {
157 0 : while (cache->glyphs[idx & HASH_MASK] == TOMBSTONE)
158 : {
159 0 : cache->glyphs[idx & HASH_MASK] = NULL;
160 0 : cache->n_tombstones--;
161 0 : idx--;
162 : }
163 : }
164 0 : }
165 :
166 : static void
167 0 : clear_table (pixman_glyph_cache_t *cache)
168 : {
169 : int i;
170 :
171 0 : for (i = 0; i < HASH_SIZE; ++i)
172 : {
173 0 : glyph_t *glyph = cache->glyphs[i];
174 :
175 0 : if (glyph && glyph != TOMBSTONE)
176 0 : free_glyph (glyph);
177 :
178 0 : cache->glyphs[i] = NULL;
179 : }
180 :
181 0 : cache->n_glyphs = 0;
182 0 : cache->n_tombstones = 0;
183 0 : }
184 :
185 : PIXMAN_EXPORT pixman_glyph_cache_t *
186 0 : pixman_glyph_cache_create (void)
187 : {
188 : pixman_glyph_cache_t *cache;
189 :
190 0 : if (!(cache = malloc (sizeof *cache)))
191 0 : return NULL;
192 :
193 0 : memset (cache->glyphs, 0, sizeof (cache->glyphs));
194 0 : cache->n_glyphs = 0;
195 0 : cache->n_tombstones = 0;
196 0 : cache->freeze_count = 0;
197 :
198 0 : pixman_list_init (&cache->mru);
199 :
200 0 : return cache;
201 : }
202 :
203 : PIXMAN_EXPORT void
204 0 : pixman_glyph_cache_destroy (pixman_glyph_cache_t *cache)
205 : {
206 0 : return_if_fail (cache->freeze_count == 0);
207 :
208 0 : clear_table (cache);
209 :
210 0 : free (cache);
211 : }
212 :
213 : PIXMAN_EXPORT void
214 0 : pixman_glyph_cache_freeze (pixman_glyph_cache_t *cache)
215 : {
216 0 : cache->freeze_count++;
217 0 : }
218 :
219 : PIXMAN_EXPORT void
220 0 : pixman_glyph_cache_thaw (pixman_glyph_cache_t *cache)
221 : {
222 0 : if (--cache->freeze_count == 0 &&
223 0 : cache->n_glyphs + cache->n_tombstones > N_GLYPHS_HIGH_WATER)
224 : {
225 0 : if (cache->n_tombstones > N_GLYPHS_HIGH_WATER)
226 : {
227 : /* More than half the entries are
228 : * tombstones. Just dump the whole table.
229 : */
230 0 : clear_table (cache);
231 : }
232 :
233 0 : while (cache->n_glyphs > N_GLYPHS_LOW_WATER)
234 : {
235 0 : glyph_t *glyph = CONTAINER_OF (glyph_t, mru_link, cache->mru.tail);
236 :
237 0 : remove_glyph (cache, glyph);
238 0 : free_glyph (glyph);
239 : }
240 : }
241 0 : }
242 :
243 : PIXMAN_EXPORT const void *
244 0 : pixman_glyph_cache_lookup (pixman_glyph_cache_t *cache,
245 : void *font_key,
246 : void *glyph_key)
247 : {
248 0 : return lookup_glyph (cache, font_key, glyph_key);
249 : }
250 :
251 : PIXMAN_EXPORT const void *
252 0 : pixman_glyph_cache_insert (pixman_glyph_cache_t *cache,
253 : void *font_key,
254 : void *glyph_key,
255 : int origin_x,
256 : int origin_y,
257 : pixman_image_t *image)
258 : {
259 : glyph_t *glyph;
260 : int32_t width, height;
261 :
262 0 : return_val_if_fail (cache->freeze_count > 0, NULL);
263 0 : return_val_if_fail (image->type == BITS, NULL);
264 :
265 0 : width = image->bits.width;
266 0 : height = image->bits.height;
267 :
268 0 : if (cache->n_glyphs >= HASH_SIZE)
269 0 : return NULL;
270 :
271 0 : if (!(glyph = malloc (sizeof *glyph)))
272 0 : return NULL;
273 :
274 0 : glyph->font_key = font_key;
275 0 : glyph->glyph_key = glyph_key;
276 0 : glyph->origin_x = origin_x;
277 0 : glyph->origin_y = origin_y;
278 :
279 0 : if (!(glyph->image = pixman_image_create_bits (
280 : image->bits.format, width, height, NULL, -1)))
281 : {
282 0 : free (glyph);
283 0 : return NULL;
284 : }
285 :
286 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
287 : image, NULL, glyph->image, 0, 0, 0, 0, 0, 0,
288 : width, height);
289 :
290 0 : if (PIXMAN_FORMAT_A (glyph->image->bits.format) != 0 &&
291 0 : PIXMAN_FORMAT_RGB (glyph->image->bits.format) != 0)
292 : {
293 0 : pixman_image_set_component_alpha (glyph->image, TRUE);
294 : }
295 :
296 0 : pixman_list_prepend (&cache->mru, &glyph->mru_link);
297 :
298 0 : _pixman_image_validate (glyph->image);
299 0 : insert_glyph (cache, glyph);
300 :
301 0 : return glyph;
302 : }
303 :
304 : PIXMAN_EXPORT void
305 0 : pixman_glyph_cache_remove (pixman_glyph_cache_t *cache,
306 : void *font_key,
307 : void *glyph_key)
308 : {
309 : glyph_t *glyph;
310 :
311 0 : if ((glyph = lookup_glyph (cache, font_key, glyph_key)))
312 : {
313 0 : remove_glyph (cache, glyph);
314 :
315 0 : free_glyph (glyph);
316 : }
317 0 : }
318 :
319 : PIXMAN_EXPORT void
320 0 : pixman_glyph_get_extents (pixman_glyph_cache_t *cache,
321 : int n_glyphs,
322 : pixman_glyph_t *glyphs,
323 : pixman_box32_t *extents)
324 : {
325 : int i;
326 :
327 0 : extents->x1 = extents->y1 = INT32_MAX;
328 0 : extents->x2 = extents->y2 = INT32_MIN;
329 :
330 0 : for (i = 0; i < n_glyphs; ++i)
331 : {
332 0 : glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
333 : int x1, y1, x2, y2;
334 :
335 0 : x1 = glyphs[i].x - glyph->origin_x;
336 0 : y1 = glyphs[i].y - glyph->origin_y;
337 0 : x2 = glyphs[i].x - glyph->origin_x + glyph->image->bits.width;
338 0 : y2 = glyphs[i].y - glyph->origin_y + glyph->image->bits.height;
339 :
340 0 : if (x1 < extents->x1)
341 0 : extents->x1 = x1;
342 0 : if (y1 < extents->y1)
343 0 : extents->y1 = y1;
344 0 : if (x2 > extents->x2)
345 0 : extents->x2 = x2;
346 0 : if (y2 > extents->y2)
347 0 : extents->y2 = y2;
348 : }
349 0 : }
350 :
351 : /* This function returns a format that is suitable for use as a mask for the
352 : * set of glyphs in question.
353 : */
354 : PIXMAN_EXPORT pixman_format_code_t
355 0 : pixman_glyph_get_mask_format (pixman_glyph_cache_t *cache,
356 : int n_glyphs,
357 : const pixman_glyph_t *glyphs)
358 : {
359 0 : pixman_format_code_t format = PIXMAN_a1;
360 : int i;
361 :
362 0 : for (i = 0; i < n_glyphs; ++i)
363 : {
364 0 : const glyph_t *glyph = glyphs[i].glyph;
365 0 : pixman_format_code_t glyph_format = glyph->image->bits.format;
366 :
367 0 : if (PIXMAN_FORMAT_TYPE (glyph_format) == PIXMAN_TYPE_A)
368 : {
369 0 : if (PIXMAN_FORMAT_A (glyph_format) > PIXMAN_FORMAT_A (format))
370 0 : format = glyph_format;
371 : }
372 : else
373 : {
374 0 : return PIXMAN_a8r8g8b8;
375 : }
376 : }
377 :
378 0 : return format;
379 : }
380 :
381 : static pixman_bool_t
382 0 : box32_intersect (pixman_box32_t *dest,
383 : const pixman_box32_t *box1,
384 : const pixman_box32_t *box2)
385 : {
386 0 : dest->x1 = MAX (box1->x1, box2->x1);
387 0 : dest->y1 = MAX (box1->y1, box2->y1);
388 0 : dest->x2 = MIN (box1->x2, box2->x2);
389 0 : dest->y2 = MIN (box1->y2, box2->y2);
390 :
391 0 : return dest->x2 > dest->x1 && dest->y2 > dest->y1;
392 : }
393 :
394 : PIXMAN_EXPORT void
395 0 : pixman_composite_glyphs_no_mask (pixman_op_t op,
396 : pixman_image_t *src,
397 : pixman_image_t *dest,
398 : int32_t src_x,
399 : int32_t src_y,
400 : int32_t dest_x,
401 : int32_t dest_y,
402 : pixman_glyph_cache_t *cache,
403 : int n_glyphs,
404 : const pixman_glyph_t *glyphs)
405 : {
406 : pixman_region32_t region;
407 0 : pixman_format_code_t glyph_format = PIXMAN_null;
408 0 : uint32_t glyph_flags = 0;
409 : pixman_format_code_t dest_format;
410 : uint32_t dest_flags;
411 0 : pixman_composite_func_t func = NULL;
412 0 : pixman_implementation_t *implementation = NULL;
413 : pixman_composite_info_t info;
414 : int i;
415 :
416 0 : _pixman_image_validate (src);
417 0 : _pixman_image_validate (dest);
418 :
419 0 : dest_format = dest->common.extended_format_code;
420 0 : dest_flags = dest->common.flags;
421 :
422 0 : pixman_region32_init (®ion);
423 0 : if (!_pixman_compute_composite_region32 (
424 : ®ion,
425 : src, NULL, dest,
426 : src_x - dest_x, src_y - dest_y, 0, 0, 0, 0,
427 : dest->bits.width, dest->bits.height))
428 : {
429 0 : goto out;
430 : }
431 :
432 0 : info.op = op;
433 0 : info.src_image = src;
434 0 : info.dest_image = dest;
435 0 : info.src_flags = src->common.flags;
436 0 : info.dest_flags = dest->common.flags;
437 :
438 0 : for (i = 0; i < n_glyphs; ++i)
439 : {
440 0 : glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
441 0 : pixman_image_t *glyph_img = glyph->image;
442 : pixman_box32_t glyph_box;
443 : pixman_box32_t *pbox;
444 0 : uint32_t extra = FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
445 : pixman_box32_t composite_box;
446 : int n;
447 :
448 0 : glyph_box.x1 = dest_x + glyphs[i].x - glyph->origin_x;
449 0 : glyph_box.y1 = dest_y + glyphs[i].y - glyph->origin_y;
450 0 : glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
451 0 : glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
452 :
453 0 : pbox = pixman_region32_rectangles (®ion, &n);
454 :
455 0 : info.mask_image = glyph_img;
456 :
457 0 : while (n--)
458 : {
459 0 : if (box32_intersect (&composite_box, pbox, &glyph_box))
460 : {
461 0 : if (glyph_img->common.extended_format_code != glyph_format ||
462 0 : glyph_img->common.flags != glyph_flags)
463 : {
464 0 : glyph_format = glyph_img->common.extended_format_code;
465 0 : glyph_flags = glyph_img->common.flags;
466 :
467 0 : _pixman_implementation_lookup_composite (
468 : get_implementation(), op,
469 : src->common.extended_format_code, src->common.flags,
470 : glyph_format, glyph_flags | extra,
471 : dest_format, dest_flags,
472 : &implementation, &func);
473 : }
474 :
475 0 : info.src_x = src_x + composite_box.x1 - dest_x;
476 0 : info.src_y = src_y + composite_box.y1 - dest_y;
477 0 : info.mask_x = composite_box.x1 - (dest_x + glyphs[i].x - glyph->origin_x);
478 0 : info.mask_y = composite_box.y1 - (dest_y + glyphs[i].y - glyph->origin_y);
479 0 : info.dest_x = composite_box.x1;
480 0 : info.dest_y = composite_box.y1;
481 0 : info.width = composite_box.x2 - composite_box.x1;
482 0 : info.height = composite_box.y2 - composite_box.y1;
483 :
484 0 : info.mask_flags = glyph_flags;
485 :
486 0 : func (implementation, &info);
487 : }
488 :
489 0 : pbox++;
490 : }
491 0 : pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
492 : }
493 :
494 : out:
495 0 : pixman_region32_fini (®ion);
496 0 : }
497 :
498 : static void
499 0 : add_glyphs (pixman_glyph_cache_t *cache,
500 : pixman_image_t *dest,
501 : int off_x, int off_y,
502 : int n_glyphs, const pixman_glyph_t *glyphs)
503 : {
504 0 : pixman_format_code_t glyph_format = PIXMAN_null;
505 0 : uint32_t glyph_flags = 0;
506 0 : pixman_composite_func_t func = NULL;
507 0 : pixman_implementation_t *implementation = NULL;
508 : pixman_format_code_t dest_format;
509 : uint32_t dest_flags;
510 : pixman_box32_t dest_box;
511 : pixman_composite_info_t info;
512 0 : pixman_image_t *white_img = NULL;
513 0 : pixman_bool_t white_src = FALSE;
514 : int i;
515 :
516 0 : _pixman_image_validate (dest);
517 :
518 0 : dest_format = dest->common.extended_format_code;
519 0 : dest_flags = dest->common.flags;
520 :
521 0 : info.op = PIXMAN_OP_ADD;
522 0 : info.dest_image = dest;
523 0 : info.src_x = 0;
524 0 : info.src_y = 0;
525 0 : info.dest_flags = dest_flags;
526 :
527 0 : dest_box.x1 = 0;
528 0 : dest_box.y1 = 0;
529 0 : dest_box.x2 = dest->bits.width;
530 0 : dest_box.y2 = dest->bits.height;
531 :
532 0 : for (i = 0; i < n_glyphs; ++i)
533 : {
534 0 : glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
535 0 : pixman_image_t *glyph_img = glyph->image;
536 : pixman_box32_t glyph_box;
537 : pixman_box32_t composite_box;
538 :
539 0 : if (glyph_img->common.extended_format_code != glyph_format ||
540 0 : glyph_img->common.flags != glyph_flags)
541 : {
542 : pixman_format_code_t src_format, mask_format;
543 :
544 0 : glyph_format = glyph_img->common.extended_format_code;
545 0 : glyph_flags = glyph_img->common.flags;
546 :
547 0 : if (glyph_format == dest->bits.format)
548 : {
549 0 : src_format = glyph_format;
550 0 : mask_format = PIXMAN_null;
551 0 : info.src_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
552 0 : info.mask_flags = FAST_PATH_IS_OPAQUE;
553 0 : info.mask_image = NULL;
554 0 : white_src = FALSE;
555 : }
556 : else
557 : {
558 0 : if (!white_img)
559 : {
560 : static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
561 :
562 0 : if (!(white_img = pixman_image_create_solid_fill (&white)))
563 0 : goto out;
564 :
565 0 : _pixman_image_validate (white_img);
566 : }
567 :
568 0 : src_format = PIXMAN_solid;
569 0 : mask_format = glyph_format;
570 0 : info.src_flags = white_img->common.flags;
571 0 : info.mask_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
572 0 : info.src_image = white_img;
573 0 : white_src = TRUE;
574 : }
575 :
576 0 : _pixman_implementation_lookup_composite (
577 : get_implementation(), PIXMAN_OP_ADD,
578 : src_format, info.src_flags,
579 : mask_format, info.mask_flags,
580 : dest_format, dest_flags,
581 : &implementation, &func);
582 : }
583 :
584 0 : glyph_box.x1 = glyphs[i].x - glyph->origin_x + off_x;
585 0 : glyph_box.y1 = glyphs[i].y - glyph->origin_y + off_y;
586 0 : glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
587 0 : glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
588 :
589 0 : if (box32_intersect (&composite_box, &glyph_box, &dest_box))
590 : {
591 0 : int src_x = composite_box.x1 - glyph_box.x1;
592 0 : int src_y = composite_box.y1 - glyph_box.y1;
593 :
594 0 : if (white_src)
595 0 : info.mask_image = glyph_img;
596 : else
597 0 : info.src_image = glyph_img;
598 :
599 0 : info.mask_x = info.src_x = src_x;
600 0 : info.mask_y = info.src_y = src_y;
601 0 : info.dest_x = composite_box.x1;
602 0 : info.dest_y = composite_box.y1;
603 0 : info.width = composite_box.x2 - composite_box.x1;
604 0 : info.height = composite_box.y2 - composite_box.y1;
605 :
606 0 : func (implementation, &info);
607 :
608 0 : pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
609 : }
610 : }
611 :
612 : out:
613 0 : if (white_img)
614 0 : pixman_image_unref (white_img);
615 0 : }
616 :
617 : /* Conceptually, for each glyph, (white IN glyph) is PIXMAN_OP_ADDed to an
618 : * infinitely big mask image at the position such that the glyph origin point
619 : * is positioned at the (glyphs[i].x, glyphs[i].y) point.
620 : *
621 : * Then (mask_x, mask_y) in the infinite mask and (src_x, src_y) in the source
622 : * image are both aligned with (dest_x, dest_y) in the destination image. Then
623 : * these three images are composited within the
624 : *
625 : * (dest_x, dest_y, dst_x + width, dst_y + height)
626 : *
627 : * rectangle.
628 : *
629 : * TODO:
630 : * - Trim the mask to the destination clip/image?
631 : * - Trim composite region based on sources, when the op ignores 0s.
632 : */
633 : PIXMAN_EXPORT void
634 0 : pixman_composite_glyphs (pixman_op_t op,
635 : pixman_image_t *src,
636 : pixman_image_t *dest,
637 : pixman_format_code_t mask_format,
638 : int32_t src_x,
639 : int32_t src_y,
640 : int32_t mask_x,
641 : int32_t mask_y,
642 : int32_t dest_x,
643 : int32_t dest_y,
644 : int32_t width,
645 : int32_t height,
646 : pixman_glyph_cache_t *cache,
647 : int n_glyphs,
648 : const pixman_glyph_t *glyphs)
649 : {
650 : pixman_image_t *mask;
651 :
652 0 : if (!(mask = pixman_image_create_bits (mask_format, width, height, NULL, -1)))
653 0 : return;
654 :
655 0 : if (PIXMAN_FORMAT_A (mask_format) != 0 &&
656 0 : PIXMAN_FORMAT_RGB (mask_format) != 0)
657 : {
658 0 : pixman_image_set_component_alpha (mask, TRUE);
659 : }
660 :
661 0 : add_glyphs (cache, mask, - mask_x, - mask_y, n_glyphs, glyphs);
662 :
663 0 : pixman_image_composite32 (op, src, mask, dest,
664 : src_x, src_y,
665 : 0, 0,
666 : dest_x, dest_y,
667 : width, height);
668 :
669 0 : pixman_image_unref (mask);
670 : }
|