diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-09-29 19:04:02 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-09-29 19:04:02 -0400 |
commit | 1e37d5f6dba7b723c4b9ef2739d08bfa886e51b1 (patch) | |
tree | 599868ac91d26051bd63ab49f04dc4840a8c17a3 | |
parent | 3b9991f6dca9877cd4110184cd050adefa6ddb70 (diff) |
glyphs
-rw-r--r-- | src/cairo-pixman-surface.c | 151 |
1 files changed, 142 insertions, 9 deletions
diff --git a/src/cairo-pixman-surface.c b/src/cairo-pixman-surface.c index 82d90a89..60f3d62b 100644 --- a/src/cairo-pixman-surface.c +++ b/src/cairo-pixman-surface.c @@ -668,7 +668,7 @@ static cairo_int_status_t create_clip_image (const cairo_clip_t *clip, pixman_image_t **clip_image) { cairo_int_status_t status; - pixman_trapezoid_t *traps; + pixman_trapezoid_t *ptraps = NULL; pixman_image_t *white_img = NULL; cairo_clip_path_t *clip_path; int i; @@ -689,7 +689,7 @@ create_clip_image (const cairo_clip_t *clip, pixman_image_t **clip_image) } /* First add the boxes */ - if (!(traps = malloc (clip->num_boxes * sizeof (pixman_trapezoid_t)))) + if (!(ptraps = malloc (clip->num_boxes * sizeof (pixman_trapezoid_t)))) { status = CAIRO_INT_STATUS_NO_MEMORY; goto out; @@ -698,7 +698,7 @@ create_clip_image (const cairo_clip_t *clip, pixman_image_t **clip_image) for (i = 0; i < clip->num_boxes; ++i) { cairo_box_t *box = &(clip->boxes[i]); - pixman_trapezoid_t *trap = &(traps[i]); + pixman_trapezoid_t *trap = &(ptraps[i]); trap->top = _cairo_fixed_to_16_16 (box->p1.y); trap->bottom = _cairo_fixed_to_16_16 (box->p2.y); @@ -714,11 +714,10 @@ create_clip_image (const cairo_clip_t *clip, pixman_image_t **clip_image) trap->right.p2.y = _cairo_fixed_to_16_16 (box->p2.y); } - pixman_add_trapezoids (*clip_image, 0, 0, clip->num_boxes, traps); + pixman_add_trapezoids (*clip_image, 0, 0, clip->num_boxes, ptraps); /* Then intersect with all the paths */ - if (!(white_img = pixman_image_create_solid_fill ( - (pixman_color_t *)&white))) + if (!(white_img = pixman_image_create_solid_fill (&white))) { status = CAIRO_INT_STATUS_NO_MEMORY; goto out; @@ -771,8 +770,7 @@ out: if (white_img) pixman_image_unref (white_img); - if (traps) - free (traps); + free (ptraps); return status; } @@ -1078,6 +1076,7 @@ clip_and_composite_traps (cairo_pixman_surface_t *psurface, format = PIXMAN_a4; break; + default: case CAIRO_ANTIALIAS_GRAY: case CAIRO_ANTIALIAS_DEFAULT: case CAIRO_ANTIALIAS_SUBPIXEL: @@ -1170,16 +1169,150 @@ cairo_pixman_surface_fill (void *abstract_surface, return status; } +static pixman_glyph_cache_t *global_glyph_cache; + +static inline pixman_glyph_cache_t * +get_glyph_cache (void) +{ + if (!global_glyph_cache) + global_glyph_cache = pixman_glyph_cache_create (); + + return global_glyph_cache; +} + +/* FIXME: make sure this gets called when glyphs are finalized */ +void +_cairo_pixman_surface_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); + + if (global_glyph_cache) { + pixman_glyph_cache_remove ( + global_glyph_cache, scaled_font, + (void *)_cairo_scaled_glyph_index (scaled_glyph)); + } + + CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); +} + static cairo_int_status_t cairo_pixman_surface_glyphs (void *abstract_surface, - cairo_operator_t op, + cairo_operator_t operator, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { + cairo_pixman_surface_t *psurface = abstract_surface; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + pixman_glyph_cache_t *glyph_cache; + pixman_glyph_t pglyphs_stack[CAIRO_STACK_ARRAY_LENGTH (pixman_glyph_t)]; + pixman_glyph_t *pglyphs = pglyphs_stack; + pixman_format_code_t mask_format; + pixman_image_t *white_image = NULL; + pixman_image_t *mask_image = NULL; + int width, height; + pixman_glyph_t *pg; + int i; + + width = pixman_image_get_width (psurface->pimage); + height = pixman_image_get_height (psurface->pimage); + + if (!(white_image = pixman_image_create_solid_fill (&white))) + return CAIRO_INT_STATUS_NO_MEMORY; + + CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); + + glyph_cache = get_glyph_cache(); + if (unlikely (glyph_cache == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto out_unlock; + } + pixman_glyph_cache_freeze (glyph_cache); + + if (num_glyphs > ARRAY_LENGTH (pglyphs_stack)) { + pglyphs = _cairo_malloc_ab (num_glyphs, sizeof (pixman_glyph_t)); + if (unlikely (pglyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto out_thaw; + } + } + + pg = pglyphs; + for (i = 0; i < num_glyphs; i++) + { + unsigned long index = glyphs[i].index; + const void *glyph; + + glyph = pixman_glyph_cache_lookup (glyph_cache, scaled_font, (void *)index); + if (!glyph) + { + cairo_scaled_glyph_t *scaled_glyph; + cairo_image_surface_t *glyph_surface; + + /* This call can actually end up recursing, so we have to + * drop the mutex around it. + */ + CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); + status = _cairo_scaled_glyph_lookup (scaled_font, index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); + + if (unlikely (status)) + goto out_thaw; + + glyph_surface = scaled_glyph->surface; + glyph = pixman_glyph_cache_insert (glyph_cache, scaled_font, (void *)index, + glyph_surface->base.device_transform.x0, + glyph_surface->base.device_transform.y0, + glyph_surface->pixman_image); + if (unlikely (!glyph)) + { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto out_thaw; + } + } + + pg->x = _cairo_lround (glyphs[i].x); + pg->y = _cairo_lround (glyphs[i].y); + pg->glyph = glyph; + pg++; + } + + mask_format = pixman_glyph_get_mask_format (glyph_cache, pg - pglyphs, pglyphs); + + mask_image = pixman_image_create_bits (mask_format, width, height, NULL, -1); + if (!mask_image) + { + status = CAIRO_INT_STATUS_NO_MEMORY; + goto out_thaw; + } + + pixman_composite_glyphs (PIXMAN_OP_ADD, + white_image, mask_image, + mask_format, + 0, 0, 0, 0, 0, 0, width, height, + glyph_cache, pg - pglyphs, pglyphs); + + status = clip_and_composite (psurface, operator, source, mask_image, clip); +out_thaw: + if (mask_image) + pixman_image_unref (mask_image); + + pixman_image_unref (white_image); + + pixman_glyph_cache_thaw (glyph_cache); + + if (pglyphs != pglyphs_stack) + free (pglyphs); + +out_unlock: + CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); + return status; } const cairo_surface_backend_t cairo_pixman_surface_backend = |