[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