summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-09-29 19:04:02 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-09-29 19:04:02 -0400
commit1e37d5f6dba7b723c4b9ef2739d08bfa886e51b1 (patch)
tree599868ac91d26051bd63ab49f04dc4840a8c17a3
parent3b9991f6dca9877cd4110184cd050adefa6ddb70 (diff)
glyphs
-rw-r--r--src/cairo-pixman-surface.c151
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 =