[cairo-commit] cairo/src cairo-glitz-surface.c,1.33,1.34
David Reveman
commit at pdx.freedesktop.org
Wed May 4 05:46:02 PDT 2005
Committed by: davidr
Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv13872/src
Modified Files:
cairo-glitz-surface.c
Log Message:
Add glyph caching to glitz backend
Index: cairo-glitz-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-glitz-surface.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- cairo-glitz-surface.c 19 Apr 2005 23:29:05 -0000 1.33
+++ cairo-glitz-surface.c 4 May 2005 12:46:00 -0000 1.34
@@ -1213,6 +1213,860 @@
return CAIRO_STATUS_SUCCESS;
}
+#define CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
+
+#define CAIRO_GLITZ_AREA_AVAILABLE 0
+#define CAIRO_GLITZ_AREA_DIVIDED 1
+#define CAIRO_GLITZ_AREA_OCCUPIED 2
+
+typedef struct _cairo_glitz_root_area cairo_glitz_root_area_t;
+
+typedef struct _cairo_glitz_area {
+ int state;
+ int level;
+ int x, y;
+ int width, height;
+ struct _cairo_glitz_area *area[4];
+ cairo_glitz_root_area_t *root;
+ void *closure;
+} cairo_glitz_area_t;
+
+typedef struct _cairo_glitz_area_funcs {
+ cairo_status_t (*move_in) (cairo_glitz_area_t *area,
+ void *closure);
+
+ void (*move_out) (cairo_glitz_area_t *area,
+ void *closure);
+
+ int (*compare_score) (cairo_glitz_area_t *area,
+ void *closure1,
+ void *closure2);
+} cairo_glitz_area_funcs_t;
+
+struct _cairo_glitz_root_area {
+ int max_level;
+ int width, height;
+ cairo_glitz_area_t *area;
+ const cairo_glitz_area_funcs_t *funcs;
+};
+
+static cairo_status_t
+_cairo_glitz_area_move_in (cairo_glitz_area_t *area,
+ void *closure)
+{
+ area->closure = closure;
+ area->state = CAIRO_GLITZ_AREA_OCCUPIED;
+
+ return (*area->root->funcs->move_in) (area, area->closure);
+}
+
+static void
+_cairo_glitz_area_move_out (cairo_glitz_area_t *area)
+{
+ (*area->root->funcs->move_out) (area, area->closure);
+
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+}
+
+static cairo_glitz_area_t *
+_cairo_glitz_area_create (cairo_glitz_root_area_t *root,
+ int level,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ cairo_glitz_area_t *area;
+ int n = 4;
+
+ area = malloc (sizeof (cairo_glitz_area_t));
+ if (!area)
+ return NULL;
+
+ area->level = level;
+ area->x = x;
+ area->y = y;
+ area->width = width;
+ area->height = height;
+ area->root = root;
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+
+ while (n--)
+ area->area[n] = NULL;
+
+ return area;
+}
+
+static void
+_cairo_glitz_area_destroy (cairo_glitz_area_t *area)
+{
+ if (!area)
+ return;
+
+ if (area->state == CAIRO_GLITZ_AREA_OCCUPIED)
+ {
+ _cairo_glitz_area_move_out (area);
+ }
+ else
+ {
+ int n = 4;
+
+ while (n--)
+ _cairo_glitz_area_destroy (area->area[n]);
+ }
+
+ free (area);
+}
+
+static cairo_glitz_area_t *
+_cairo_glitz_area_get_top_scored_sub_area (cairo_glitz_area_t *area)
+{
+ if (!area)
+ return NULL;
+
+ switch (area->state) {
+ case CAIRO_GLITZ_AREA_OCCUPIED:
+ return area;
+ case CAIRO_GLITZ_AREA_AVAILABLE:
+ break;
+ case CAIRO_GLITZ_AREA_DIVIDED: {
+ cairo_glitz_area_t *tmp, *top = NULL;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ tmp = _cairo_glitz_area_get_top_scored_sub_area (area->area[i]);
+ if (tmp && top)
+ {
+ if ((*area->root->funcs->compare_score) (tmp,
+ tmp->closure,
+ top->closure) > 0)
+ top = tmp;
+ }
+ else if (tmp)
+ {
+ top = tmp;
+ }
+ }
+ return top;
+ }
+ }
+
+ return NULL;
+}
+
+static cairo_int_status_t
+_cairo_glitz_area_find (cairo_glitz_area_t *area,
+ int width,
+ int height,
+ cairo_bool_t kick_out,
+ void *closure)
+{
+ if (area->width < width || area->height < height)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ switch (area->state) {
+ case CAIRO_GLITZ_AREA_OCCUPIED:
+ if (kick_out)
+ {
+ if ((*area->root->funcs->compare_score) (area,
+ area->closure,
+ closure) >= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_glitz_area_move_out (area);
+ } else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* fall-through */
+ case CAIRO_GLITZ_AREA_AVAILABLE: {
+ if (area->level == area->root->max_level ||
+ (area->width == width && area->height == height))
+ {
+ return _cairo_glitz_area_move_in (area, closure);
+ }
+ else
+ {
+ int dx[4], dy[4], w[4], h[4], i;
+
+ dx[0] = dx[2] = dy[0] = dy[1] = 0;
+
+ w[0] = w[2] = dx[1] = dx[3] = width;
+ h[0] = h[1] = dy[2] = dy[3] = height;
+
+ w[1] = w[3] = area->width - width;
+ h[2] = h[3] = area->height - height;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (w[i])
+ area->area[i] =
+ _cairo_glitz_area_create (area->root,
+ area->level + 1,
+ area->x + dx[i],
+ area->y + dy[i],
+ w[i], h[i]);
+ }
+
+ for (; i < 4; i++)
+ {
+ if (w[i] && h[i])
+ area->area[i] =
+ _cairo_glitz_area_create (area->root,
+ area->level + 1,
+ area->x + dx[i],
+ area->y + dy[i],
+ w[i], h[i]);
+ }
+
+ area->state = CAIRO_GLITZ_AREA_DIVIDED;
+
+ if (CAIRO_OK (_cairo_glitz_area_find (area->area[0],
+ width, height,
+ kick_out, closure)))
+ return CAIRO_STATUS_SUCCESS;
+ }
+ } break;
+ case CAIRO_GLITZ_AREA_DIVIDED: {
+ cairo_glitz_area_t *to_area;
+ int i, rejected = FALSE;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (area->area[i])
+ {
+ if (area->area[i]->width >= width &&
+ area->area[i]->height >= height)
+ {
+ if (CAIRO_OK (_cairo_glitz_area_find (area->area[i],
+ width, height,
+ kick_out, closure)))
+ return CAIRO_STATUS_SUCCESS;
+
+ rejected = TRUE;
+ }
+ }
+ }
+
+ if (rejected)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ to_area = _cairo_glitz_area_get_top_scored_sub_area (area);
+ if (to_area)
+ {
+ if (kick_out)
+ {
+ if ((*area->root->funcs->compare_score) (to_area,
+ to_area->closure,
+ closure) >= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ } else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ _cairo_glitz_area_destroy (area->area[i]);
+ area->area[i] = NULL;
+ }
+
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+ if (CAIRO_OK (_cairo_glitz_area_find (area, width, height,
+ TRUE, closure)))
+ return CAIRO_STATUS_SUCCESS;
+
+ } break;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_glitz_root_area_init (cairo_glitz_root_area_t *root,
+ int max_level,
+ int width,
+ int height,
+ const cairo_glitz_area_funcs_t *funcs)
+{
+ root->max_level = max_level;
+ root->funcs = funcs;
+
+ root->area = _cairo_glitz_area_create (root, 0, 0, 0, width, height);
+ if (!root->area)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_root_area_fini (cairo_glitz_root_area_t *root)
+{
+ _cairo_glitz_area_destroy (root->area);
+}
+
+#define GLYPH_CACHE_TEXTURE_SIZE 512
+#define GLYPH_CACHE_MAX_LEVEL 64
+#define GLYPH_CACHE_MAX_HEIGHT 72
+#define GLYPH_CACHE_MAX_WIDTH 72
+
+#define WRITE_VEC2(ptr, _x, _y) \
+ *(ptr)++ = (_x); \
+ *(ptr)++ = (_y)
+
+#define WRITE_BOX(ptr, _vx1, _vy1, _vx2, _vy2, p1, p2) \
+ WRITE_VEC2 (ptr, _vx1, _vy1); \
+ WRITE_VEC2 (ptr, (p1)->x, (p2)->y); \
+ WRITE_VEC2 (ptr, _vx2, _vy1); \
+ WRITE_VEC2 (ptr, (p2)->x, (p2)->y); \
+ WRITE_VEC2 (ptr, _vx2, _vy2); \
+ WRITE_VEC2 (ptr, (p2)->x, (p1)->y); \
+ WRITE_VEC2 (ptr, _vx1, _vy2); \
+ WRITE_VEC2 (ptr, (p1)->x, (p1)->y)
+
+typedef struct _cairo_glitz_glyph_cache {
+ cairo_cache_t base;
+ cairo_glitz_root_area_t root;
+ glitz_surface_t *surface;
+} cairo_glitz_glyph_cache_t;
+
+typedef struct {
+ cairo_glyph_cache_key_t key;
+ int refcount;
+ cairo_glyph_size_t size;
+ cairo_glitz_area_t *area;
+ cairo_bool_t locked;
+ cairo_point_double_t p1, p2;
+} cairo_glitz_glyph_cache_entry_t;
+
+static cairo_status_t
+_cairo_glitz_glyph_move_in (cairo_glitz_area_t *area,
+ void *closure)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure;
+
+ entry->area = area;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_glyph_move_out (cairo_glitz_area_t *area,
+ void *closure)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure;
+
+ entry->area = NULL;
+}
+
+static int
+_cairo_glitz_glyph_compare (cairo_glitz_area_t *area,
+ void *closure1,
+ void *closure2)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure1;
+
+ if (entry->locked)
+ return 1;
+
+ return -1;
+}
+
+static const cairo_glitz_area_funcs_t _cairo_glitz_area_funcs = {
+ _cairo_glitz_glyph_move_in,
+ _cairo_glitz_glyph_move_out,
+ _cairo_glitz_glyph_compare
+};
+
+static cairo_status_t
+_cairo_glitz_glyph_cache_entry_create (void *abstract_cache,
+ void *abstract_key,
+ void **return_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry;
+ cairo_glyph_cache_key_t *key = abstract_key;
+
+ entry = malloc (sizeof (cairo_glitz_glyph_cache_entry_t));
+ if (!entry)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ entry->refcount = 1;
+ entry->key = *key;
+ entry->area = NULL;
+ entry->locked = FALSE;
+
+ _cairo_unscaled_font_reference (entry->key.unscaled);
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_glyph_cache_entry_destroy (void *abstract_cache,
+ void *abstract_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
+
+ entry->refcount--;
+ if (entry->refcount)
+ return;
+
+ if (entry->area)
+ _cairo_glitz_area_move_out (entry->area);
+
+ _cairo_unscaled_font_destroy (entry->key.unscaled);
+
+ free (entry);
+}
+
+static void
+_cairo_glitz_glyph_cache_entry_reference (void *abstract_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
+
+ entry->refcount++;
+}
+
+static void
+_cairo_glitz_glyph_cache_destroy (void *abstract_cache)
+{
+ cairo_glitz_glyph_cache_t *cache = abstract_cache;
+
+ _cairo_glitz_root_area_fini (&cache->root);
+
+ glitz_surface_destroy (cache->surface);
+}
+
+static const cairo_cache_backend_t _cairo_glitz_glyph_cache_backend = {
+ _cairo_glyph_cache_hash,
+ _cairo_glyph_cache_keys_equal,
+ _cairo_glitz_glyph_cache_entry_create,
+ _cairo_glitz_glyph_cache_entry_destroy,
+ _cairo_glitz_glyph_cache_destroy
+};
+
+static cairo_glitz_glyph_cache_t *_cairo_glitz_glyph_caches = NULL;
+
+static cairo_glitz_glyph_cache_t *
+_cairo_glitz_get_glyph_cache (cairo_glitz_surface_t *surface)
+{
+ cairo_glitz_glyph_cache_t *cache;
+ glitz_drawable_t *drawable;
+ glitz_format_t *format;
+
+ /*
+ * FIXME: caches should be thread specific, display specific and screen
+ * specific.
+ */
+
+ if (_cairo_glitz_glyph_caches)
+ return _cairo_glitz_glyph_caches;
+
+ drawable = glitz_surface_get_drawable (surface->surface);
+
+ format = glitz_find_standard_format (drawable, GLITZ_STANDARD_A8);
+ if (!format)
+ return NULL;
+
+ cache = malloc (sizeof (cairo_glitz_glyph_cache_t));
+ if (!cache)
+ return NULL;
+
+ cache->surface =
+ glitz_surface_create (drawable, format,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ 0, NULL);
+ if (!cache->surface)
+ {
+ free (cache);
+ return NULL;
+ }
+
+ if (_cairo_glitz_root_area_init (&cache->root,
+ GLYPH_CACHE_MAX_LEVEL,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ &_cairo_glitz_area_funcs))
+ {
+ glitz_surface_destroy (cache->surface);
+ free (cache);
+ return NULL;
+ }
+
+ if (_cairo_cache_init (&cache->base,
+ &_cairo_glitz_glyph_cache_backend,
+ CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT))
+ {
+ _cairo_glitz_root_area_fini (&cache->root);
+ glitz_surface_destroy (cache->surface);
+ free (cache);
+ return NULL;
+ }
+
+ _cairo_glitz_glyph_caches = cache;
+
+ return cache;
+}
+
+#define FIXED_TO_FLOAT(f) (((glitz_float_t) (f)) / 65536)
+
+static cairo_status_t
+_cairo_glitz_cache_glyph (cairo_glitz_glyph_cache_t *cache,
+ cairo_glitz_glyph_cache_entry_t *entry,
+ cairo_image_glyph_cache_entry_t *image_entry)
+{
+ glitz_point_fixed_t p1, p2;
+ glitz_pixel_format_t pf;
+ glitz_buffer_t *buffer;
+ pixman_format_t *format;
+ int am, rm, gm, bm;
+
+ entry->size = image_entry->size;
+
+ if (entry->size.width > GLYPH_CACHE_MAX_WIDTH ||
+ entry->size.height > GLYPH_CACHE_MAX_HEIGHT)
+ return CAIRO_STATUS_SUCCESS;
+
+ format = pixman_image_get_format (image_entry->image->pixman_image);
+ if (!format)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (_cairo_glitz_area_find (cache->root.area,
+ entry->size.width,
+ entry->size.height,
+ FALSE, entry))
+ {
+ if (_cairo_glitz_area_find (cache->root.area,
+ entry->size.width,
+ entry->size.height,
+ TRUE, entry))
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ buffer = glitz_buffer_create_for_data (image_entry->image->data);
+ if (!buffer)
+ {
+ _cairo_glitz_area_move_out (entry->area);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
+
+ pf.masks.alpha_mask = am;
+ pf.masks.red_mask = rm;
+ pf.masks.green_mask = gm;
+ pf.masks.blue_mask = bm;
+
+ pf.bytes_per_line = image_entry->image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
+ pf.xoffset = 0;
+ pf.skip_lines = 0;
+
+ glitz_set_pixels (cache->surface,
+ entry->area->x,
+ entry->area->y,
+ entry->size.width,
+ entry->size.height,
+ &pf, buffer);
+
+ glitz_buffer_destroy (buffer);
+
+ p1.x = entry->area->x << 16;
+ p1.y = entry->area->y << 16;
+ p2.x = (entry->area->x + entry->size.width) << 16;
+ p2.y = (entry->area->y + entry->size.height) << 16;
+
+ glitz_surface_translate_point (cache->surface, &p1, &p1);
+ glitz_surface_translate_point (cache->surface, &p2, &p2);
+
+ entry->p1.x = FIXED_TO_FLOAT (p1.x);
+ entry->p1.y = FIXED_TO_FLOAT (p1.y);
+ entry->p2.x = FIXED_TO_FLOAT (p2.x);
+ entry->p2.y = FIXED_TO_FLOAT (p2.y);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#define N_STACK_BUF 256
+
+static cairo_status_t
+_cairo_glitz_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_surface,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_glitz_surface_attributes_t attributes;
+ cairo_glitz_surface_t *dst = abstract_surface;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_glyph_cache_t *cache;
+ cairo_glitz_glyph_cache_entry_t *stack_entries[N_STACK_BUF];
+ cairo_glitz_glyph_cache_entry_t **entries;
+ cairo_glyph_cache_key_t key;
+ glitz_float_t stack_vertices[N_STACK_BUF * 16];
+ glitz_float_t *vertices;
+ glitz_buffer_t *buffer;
+ cairo_int_status_t status;
+ int i, cached_glyphs = 0;
+ glitz_float_t x1, y1, x2, y2;
+ static glitz_vertex_format_t format = {
+ GLITZ_PRIMITIVE_QUADS,
+ GLITZ_DATA_TYPE_FLOAT,
+ sizeof (glitz_float_t) * 4,
+ GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK,
+ { 0 },
+ {
+ GLITZ_DATA_TYPE_FLOAT,
+ GLITZ_COORDINATE_SIZE_XY,
+ sizeof (glitz_float_t) * 2,
+ }
+ };
+
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
+ if (status)
+ return status;
+
+ _cairo_glitz_surface_set_attributes (src, &attributes);
+
+ if (num_glyphs > N_STACK_BUF)
+ {
+ char *data;
+
+ data = malloc (num_glyphs * sizeof (void *) +
+ num_glyphs * sizeof (glitz_float_t) * 16);
+ if (!data)
+ goto FAIL1;
+
+ entries = (cairo_glitz_glyph_cache_entry_t **) data;
+ vertices = (glitz_float_t *) (data + num_glyphs * sizeof (void *));
+ }
+ else
+ {
+ entries = stack_entries;
+ vertices = stack_vertices;
+ }
+
+ buffer = glitz_buffer_create_for_data (vertices);
+ if (!buffer)
+ goto FAIL2;
+
+ cache = _cairo_glitz_get_glyph_cache (dst);
+ if (!cache)
+ {
+ num_glyphs = 0;
+ goto UNLOCK;
+ }
+
+ _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ key.index = glyphs[i].index;
+
+ status = _cairo_cache_lookup (&cache->base,
+ &key,
+ (void **) &entries[i],
+ NULL);
+ if (status)
+ {
+ num_glyphs = i;
+ goto UNLOCK;
+ }
+
+ _cairo_glitz_glyph_cache_entry_reference (entries[i]);
+
+ if (entries[i]->area)
+ {
+ x1 = floor (glyphs[i].x + 0.5) + entries[i]->size.x;
+ y1 = floor (glyphs[i].y + 0.5) + entries[i]->size.y;
+ x2 = x1 + entries[i]->size.width;
+ y2 = y1 + entries[i]->size.height;
+
+ WRITE_BOX (vertices, x1, y1, x2, y2,
+ &entries[i]->p1, &entries[i]->p2);
+
+ entries[i]->locked = TRUE;
+ cached_glyphs++;
+ }
+ }
+
+ if (cached_glyphs != num_glyphs)
+ {
+ cairo_cache_t *image_cache;
+ cairo_image_glyph_cache_entry_t *image_entry;
+ cairo_surface_t *image;
+ cairo_glitz_surface_t *clone;
+
+ _cairo_lock_global_image_glyph_cache ();
+
+ image_cache = _cairo_get_global_image_glyph_cache ();
+ if (!image_cache)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto UNLOCK;
+ }
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ if (!entries[i]->area)
+ {
+ key.index = glyphs[i].index;
+
+ status = _cairo_cache_lookup (image_cache,
+ &key,
+ (void **) &image_entry,
+ NULL);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+
+ status = _cairo_glitz_cache_glyph (cache,
+ entries[i],
+ image_entry);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+ }
+
+ x1 = floor (glyphs[i].x + 0.5);
+ y1 = floor (glyphs[i].y + 0.5);
+
+ if (entries[i]->area)
+ {
+ x1 += entries[i]->size.x;
+ y1 += entries[i]->size.y;
+ x2 = x1 + entries[i]->size.width;
+ y2 = y1 + entries[i]->size.height;
+
+ WRITE_BOX (vertices, x1, y1, x2, y2,
+ &entries[i]->p1, &entries[i]->p2);
+
+ entries[i]->locked = TRUE;
+ cached_glyphs++;
+ }
+ else
+ {
+ x1 += image_entry->size.x;
+ y1 += image_entry->size.y;
+
+ image = &image_entry->image->base;
+ status =
+ _cairo_glitz_surface_clone_similar (abstract_surface,
+ image,
+ (cairo_surface_t **)
+ &clone);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+
+ glitz_composite (op,
+ src->surface,
+ clone->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset + x1,
+ src_y + attributes.base.y_offset + y1,
+ 0, 0,
+ x1, y1,
+ image_entry->size.width,
+ image_entry->size.height);
+
+ cairo_surface_destroy (&clone->base);
+
+ if (glitz_surface_get_status (dst->surface) ==
+ GLITZ_STATUS_NOT_SUPPORTED)
+ {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+ }
+ }
+
+ _cairo_unlock_global_image_glyph_cache ();
+ }
+
+ if (cached_glyphs)
+ {
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_VERTEX,
+ (glitz_geometry_format_t *) &format,
+ buffer);
+
+ glitz_set_array (dst->surface, 0, 4, cached_glyphs * 4, 0, 0);
+
+ glitz_composite (op,
+ src->surface,
+ cache->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset,
+ src_y + attributes.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_NONE,
+ NULL, NULL);
+ }
+
+UNLOCK:
+ if (cached_glyphs)
+ {
+ for (i = 0; i < num_glyphs; i++)
+ entries[i]->locked = FALSE;
+ }
+
+ for (i = 0; i < num_glyphs; i++)
+ _cairo_glitz_glyph_cache_entry_destroy (cache, entries[i]);
+
+ glitz_buffer_destroy (buffer);
+
+ FAIL2:
+ if (num_glyphs > N_STACK_BUF)
+ free (entries);
+
+ FAIL1:
+ if (attributes.n_params)
+ free (attributes.params);
+
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+
+ if (status)
+ return status;
+
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_finish,
@@ -1228,7 +2082,7 @@
NULL, /* show_page */
_cairo_glitz_surface_set_clip_region,
_cairo_glitz_surface_get_extents,
- NULL /* show_glyphs */
+ _cairo_glitz_surface_show_glyphs
};
cairo_surface_t *
More information about the cairo-commit
mailing list