[cairo-commit] cairo/src cairo-array.c, 1.2, 1.3 cairo-atsui-font.c, 1.7, 1.8 cairo-font.c, 1.42, 1.43 cairo-ft-font.c, 1.54, 1.55 cairo-gstate.c, 1.107, 1.108 cairo-pdf-surface.c, 1.27, 1.28 cairo-surface.c, 1.54, 1.55 cairo-win32-font.c, 1.15, 1.16 cairo.h, 1.95, 1.96 cairoint.h, 1.123, 1.124

Owen Taylor commit at pdx.freedesktop.org
Fri Apr 8 13:14:19 PDT 2005


Committed by: otaylor

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv9556/src

Modified Files:
	cairo-array.c cairo-atsui-font.c cairo-font.c cairo-ft-font.c 
	cairo-gstate.c cairo-pdf-surface.c cairo-surface.c 
	cairo-win32-font.c cairo.h cairoint.h 
Log Message:
2005-04-08  Owen Taylor  <otaylor at redhat.com>

	* src/cairo.h src/cairo-font.c src/cairoint.h
	doc/public/cairo-sections.txt:
	Add cairo_font_face_set/get_user_data().

	* src/cairo-array.c src/cairoint.h src/cairo-surface.c:
	Refactor user data code from cairo-surface.c into 
	cairo_user_data_array_t.

	* src/cairo-font.c (cairo_font_face_destroy,
	(cairo_scaled_font_destroy, _cairo_unscaled_font_destroy):
	Switch these types to be like cairo_surface_t where the
	generic code frees the wrapper object.

	* src/cairo-atsui-font.c src/cairo-ft-font.c
	src/cairo-win32-font.c: Fix up for the above changes.

	* src/cairo-ft-font.c (_cairo_ft_unscaled_font_destroy,
	_ft_font_face_destroy): Implement a complicated mutual-referencing
	scheme to make sure that a face from cairo_ft_font_face_create_for_ft_face()
	is freed only when the FT_Face is no longer needed.

	* src/cairo-ft-font.c (cairo_ft_font_face_create_for_ft_face): 
	Update the docs to describe how to figure out when the FT_Face
	can be freed.

	* src/cairo-ft-font.c: Fix refcount leaks when creating fonts.

	* src/cairo-pdf-surface.c (cairo_pdf_ft_font_create): Remove
	excess call to _cairo_unscaled_font_reference().

	* src/cairo-gstate.c (_cairo_gstate_set_font_face): Remove
	stray initialization of font matrix to the identity.

	* src/cairo-array.c (_cairo_user_data_array_set_data) test/user-data.c:
	Fix a bug when setting/unsetting a key with a free key slot before it,
	add that to the test case.

	* src/cairo-array.c (_cairo_user_data_array_set_data): 
	Don't append an element when user_data is NULL.

Index: cairo-array.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-array.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- cairo-array.c	17 Jan 2005 17:40:01 -0000	1.2
+++ cairo-array.c	8 Apr 2005 20:14:17 -0000	1.3
@@ -132,3 +132,142 @@
 {
     return array->num_elements;
 }
+
+/* cairo_user_data_array_t */
+
+typedef struct {
+    const cairo_user_data_key_t *key;
+    void *user_data;
+    cairo_destroy_func_t destroy;
+} cairo_user_data_slot_t;
+
+/**
+ * _cairo_user_data_array_init:
+ * @array: a #cairo_user_data_array_t
+ * 
+ * Initializes a #cairo_user_data_array_t structure for future
+ * use. After initialization, the array has no keys. Call
+ * _cairo_user_data_array_destroy() to free any allocated memory
+ * when done using the array.
+ **/
+void
+_cairo_user_data_array_init (cairo_user_data_array_t *array)
+{
+    _cairo_array_init (array, sizeof (cairo_user_data_slot_t));
+}
+
+/**
+ * _cairo_user_data_array_destroy:
+ * @array: a #cairo_user_data_array_t
+ * 
+ * Destroys all current keys in the user data array and deallocates
+ * any memory allocated for the array itself.
+ **/
+void
+_cairo_user_data_array_destroy (cairo_user_data_array_t *array)
+{
+    int i, num_slots;
+    cairo_user_data_slot_t *slots;
+
+    num_slots = array->num_elements;
+    slots = (cairo_user_data_slot_t *) array->elements;
+    for (i = 0; i < num_slots; i++) {
+	if (slots[i].user_data != NULL && slots[i].destroy != NULL)
+	    slots[i].destroy (slots[i].user_data);
+    }
+
+    _cairo_array_fini (array);
+}
+
+/**
+ * _cairo_user_data_array_get_data:
+ * @array: a #cairo_user_data_array_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ * 
+ * Returns user data previously attached using the specified
+ * key.  If no user data has been attached with the given key this
+ * function returns %NULL.
+ * 
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+_cairo_user_data_array_get_data (cairo_user_data_array_t     *array,
+				 const cairo_user_data_key_t *key)
+{
+    int i, num_slots;
+    cairo_user_data_slot_t *slots;
+
+    num_slots = array->num_elements;
+    slots = (cairo_user_data_slot_t *) array->elements;
+    for (i = 0; i < num_slots; i++) {
+	if (slots[i].key == key)
+	    return slots[i].user_data;
+    }
+
+    return NULL;
+}
+
+/**
+ * _cairo_user_data_array_set_data:
+ * @array: a #cairo_user_data_array_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * user data array is destroyed or when new user data is attached using the
+ * same key.
+ * 
+ * Attaches user data to a user data array.  To remove user data,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
+cairo_status_t
+_cairo_user_data_array_set_data (cairo_user_data_array_t     *array,
+				 const cairo_user_data_key_t *key,
+				 void			     *user_data,
+				 cairo_destroy_func_t	      destroy)
+{
+    int i, num_slots;
+    cairo_user_data_slot_t *slots, *s;
+
+    s = NULL;
+    num_slots = array->num_elements;
+    slots = (cairo_user_data_slot_t *) array->elements;
+    for (i = 0; i < num_slots; i++) {
+	if (slots[i].key == key) {
+	    if (slots[i].user_data != NULL && slots[i].destroy != NULL)
+		slots[i].destroy (slots[i].user_data);
+	    s = &slots[i];
+	    break;
+	}
+	if (user_data && slots[i].user_data == NULL) {
+	    s = &slots[i];	/* Have to keep searching for an exact match */
+	}
+    }
+
+    if (user_data == NULL) {
+	if (s != NULL) {
+	    s->key = NULL;
+	    s->user_data = NULL;
+	    s->destroy = NULL;
+	}
+
+	return CAIRO_STATUS_SUCCESS;
+	
+    } else {
+	if (s == NULL)
+	    s = _cairo_array_append (array, NULL, 1);
+	if (s == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	s->key = key;
+	s->user_data = user_data;
+	s->destroy = destroy;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+

Index: cairo-atsui-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-atsui-font.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- cairo-atsui-font.c	7 Apr 2005 17:01:49 -0000	1.7
+++ cairo-atsui-font.c	8 Apr 2005 20:14:17 -0000	1.8
@@ -214,8 +214,6 @@
         ATSUDisposeStyle(font->style);
     if (font->unscaled_style)
         ATSUDisposeStyle(font->unscaled_style);
-
-    free(font);
 }
 
 

Index: cairo-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-font.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -d -r1.42 -r1.43
--- cairo-font.c	7 Apr 2005 20:29:32 -0000	1.42
+++ cairo-font.c	8 Apr 2005 20:14:17 -0000	1.43
@@ -47,6 +47,8 @@
 {
     font_face->refcount = 1;
     font_face->backend = backend;
+
+    _cairo_user_data_array_init (&font_face->user_data);
 }
 
 /**
@@ -73,11 +75,70 @@
  **/
 void
 cairo_font_face_destroy (cairo_font_face_t *font_face)
-{    
+{
+    cairo_user_data_array_t user_data_copy;
+  
     if (--(font_face->refcount) > 0)
 	return;
 
     font_face->backend->destroy (font_face);
+
+    /* We allow resurrection to deal with some memory management for the
+     * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
+     * need to effectively mutually reference each other
+     */
+    if (font_face->refcount > 0)
+	return;
+
+    _cairo_user_data_array_destroy (&font_face->user_data);
+
+    free (font_face);
+}
+
+/**
+ * cairo_font_face_get_user_data:
+ * @font_face: a #cairo_font_face_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ * 
+ * Return user data previously attached to @font_face using the specified
+ * key.  If no user data has been attached with the given key this
+ * function returns %NULL.
+ * 
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+cairo_font_face_get_user_data (cairo_font_face_t	   *font_face,
+			       const cairo_user_data_key_t *key)
+{
+    return _cairo_user_data_array_get_data (&font_face->user_data,
+					    key);
+}
+
+/**
+ * cairo_font_face_set_user_data:
+ * @font_face: a #cairo_font_face_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach to the font face
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * font face is destroyed or when new user data is attached using the
+ * same key.
+ * 
+ * Attach user data to @font_face.  To remove user data from a font face,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
+cairo_status_t
+cairo_font_face_set_user_data (cairo_font_face_t	   *font_face,
+			       const cairo_user_data_key_t *key,
+			       void			   *user_data,
+			       cairo_destroy_func_t	    destroy)
+{
+    return _cairo_user_data_array_set_data (&font_face->user_data,
+					    key, user_data, destroy);
 }
 
 /* cairo_simple_font_face_t - simple family/slant/weight font faces used for
@@ -799,6 +860,8 @@
 	return;
 
     unscaled_font->backend->destroy (unscaled_font);
+
+    free (unscaled_font);
 }
 
 
@@ -852,6 +915,8 @@
     }
 
     scaled_font->backend->destroy (scaled_font);
+
+    free (scaled_font);
 }
 
 /**

Index: cairo-ft-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ft-font.c,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -d -r1.54 -r1.55
--- cairo-ft-font.c	7 Apr 2005 18:04:00 -0000	1.54
+++ cairo-ft-font.c	8 Apr 2005 20:14:17 -0000	1.55
@@ -482,7 +482,13 @@
 {
     ft_unscaled_font_t *unscaled  = abstract_font;
 
-    if (!unscaled->from_face) {
+    if (unscaled->from_face) {
+	/* See comments in _ft_font_face_destroy about the "zombie" state
+	 * for a _ft_font_face.
+	 */
+	if (unscaled->faces && !unscaled->faces->unscaled)
+	    cairo_font_face_destroy (&unscaled->faces->base);
+    } else {
 	cairo_cache_t *cache;
 	cairo_ft_cache_key_t key;
 	
@@ -496,18 +502,13 @@
 	_cairo_cache_remove (cache, &key);
 	
 	_unlock_global_ft_cache ();
+	
+	if (unscaled->filename)
+	    free (unscaled->filename);
+	
+	if (unscaled->face)
+	    FT_Done_Face (unscaled->face);
     }
-    
-    if (unscaled == NULL)
-        return;
-
-    if (!unscaled->from_face && unscaled->face)
-	FT_Done_Face (unscaled->face);
-
-    if (unscaled->filename)
-	free (unscaled->filename);
-  
-    free (unscaled);
 }
 
 static cairo_status_t 
@@ -830,8 +831,6 @@
         return;
   
     _cairo_unscaled_font_destroy (&scaled_font->unscaled->base);
-
-    free (scaled_font);
 }
 
 static void
@@ -1332,20 +1331,47 @@
     ft_font_face_t *tmp_face = NULL;
     ft_font_face_t *last_face = NULL;
 
-    /* Remove face from linked list */
-    for (tmp_face = font_face->unscaled->faces; tmp_face; tmp_face = tmp_face->next_face) {
-	if (tmp_face == font_face) {
-	    if (last_face)
-		last_face->next_face = tmp_face->next_face;
-	    else
-		font_face->unscaled->faces = tmp_face->next_face;
-	}
+    /* When destroying the face created by cairo_ft_font_face_create_for_ft_face,
+     * we have a special "zombie" state for the face when the unscaled font
+     * is still alive but there are no public references to the font face.
+     *
+     * We go from:
+     *
+     *   font_face ------> unscaled
+     *        <-....weak....../
+     *
+     * To:
+     *
+     *    font_face <------- unscaled
+     */
 
-	last_face = tmp_face;
+    if (font_face->unscaled &&
+	font_face->unscaled->from_face &&
+	font_face->unscaled->base.refcount > 1) {
+	cairo_font_face_reference (&font_face->base);
+	
+	_cairo_unscaled_font_destroy (&font_face->unscaled->base);
+	font_face->unscaled = NULL;
+	
+	return;
     }
+    
+    if (font_face->unscaled) {
+	/* Remove face from linked list */
+	for (tmp_face = font_face->unscaled->faces; tmp_face; tmp_face = tmp_face->next_face) {
+	    if (tmp_face == font_face) {
+		if (last_face)
+		    last_face->next_face = tmp_face->next_face;
+		else
+		    font_face->unscaled->faces = tmp_face->next_face;
+	    }
+	    
+	    last_face = tmp_face;
+	}
 
-    _cairo_unscaled_font_destroy (&font_face->unscaled->base);
-    free (font_face);
+	_cairo_unscaled_font_destroy (&font_face->unscaled->base);
+	font_face->unscaled = NULL;
+    }
 }
 
 static cairo_status_t
@@ -1426,21 +1452,26 @@
 cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
 {
     ft_unscaled_font_t *unscaled;
+    cairo_font_face_t *font_face;
 
     unscaled = _ft_unscaled_font_get_for_pattern (pattern);
     if (unscaled == NULL)
 	return NULL;
 
-    return _ft_font_face_create (unscaled, _get_load_flags (pattern));
+    font_face = _ft_font_face_create (unscaled, _get_load_flags (pattern));
+    _cairo_unscaled_font_destroy (&unscaled->base);
+
+    return font_face;
 }
 
 /**
  * cairo_ft_font_create_for_ft_face:
  * @face: A FreeType face object, already opened. This must
- *   be kept around until the font object's refcount drops to
- *   zero and it is freed. The font object can be kept alive by
- *   internal caching, so it's safest to keep the face object
- *   around forever.
+ *   be kept around until the face's refcount drops to
+ *   zero and it is freed. Since the face may be referenced
+ *   internally to Cairo, the best way to determine when it
+ *   is safe to free the face is to pass a
+ *   #cairo_destroy_func_t to cairo_font_face_set_user_data()
  * @load_flags: The flags to pass to FT_Load_Glyph when loading
  *   glyphs from the font. These flags control aspects of
  *   rendering such as hinting and antialiasing. See the FreeType
@@ -1460,12 +1491,16 @@
 				       int             load_flags)
 {
     ft_unscaled_font_t *unscaled;
+    cairo_font_face_t *font_face;
 
     unscaled = _ft_unscaled_font_create_from_face (face);
     if (unscaled == NULL)
 	return NULL;
 
-    return _ft_font_face_create (unscaled, load_flags);
+    font_face = _ft_font_face_create (unscaled, load_flags);
+    _cairo_unscaled_font_destroy (&unscaled->base);
+
+    return font_face;
 }
 
 /**

Index: cairo-gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-gstate.c,v
retrieving revision 1.107
retrieving revision 1.108
diff -u -d -r1.107 -r1.108
--- cairo-gstate.c	8 Apr 2005 17:03:17 -0000	1.107
+++ cairo-gstate.c	8 Apr 2005 20:14:17 -0000	1.108
@@ -2359,7 +2359,6 @@
 	    cairo_font_face_reference (gstate->font_face);
     }
 
-    cairo_matrix_init_identity (&gstate->font_matrix);
     _cairo_gstate_unset_font (gstate);
     
     return CAIRO_STATUS_SUCCESS;

Index: cairo-pdf-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pdf-surface.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- cairo-pdf-surface.c	7 Apr 2005 21:25:00 -0000	1.27
+++ cairo-pdf-surface.c	8 Apr 2005 20:14:17 -0000	1.28
@@ -324,8 +324,6 @@
     if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
 	goto fail1;
 
-    font->base.unscaled_font = unscaled_font;
-    _cairo_unscaled_font_reference (unscaled_font);
     font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
     if (font->glyphs == NULL)
 	goto fail2;

Index: cairo-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-surface.c,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -d -r1.54 -r1.55
--- cairo-surface.c	7 Apr 2005 21:25:00 -0000	1.54
+++ cairo-surface.c	8 Apr 2005 20:14:17 -0000	1.55
@@ -38,12 +38,6 @@
 
 #include "cairoint.h"
 
-typedef struct {
-    const cairo_user_data_key_t *key;
-    void *user_data;
-    cairo_destroy_func_t destroy;
-} cairo_user_data_slot_t;
-
 void
 _cairo_surface_init (cairo_surface_t			*surface,
 		     const cairo_surface_backend_t	*backend)
@@ -53,8 +47,7 @@
     surface->ref_count = 1;
     surface->finished = FALSE;
 
-    _cairo_array_init (&surface->user_data_slots,
-		       sizeof (cairo_user_data_slot_t));
+    _cairo_user_data_array_init (&surface->user_data);
 
     cairo_matrix_init_identity (&surface->matrix);
     surface->filter = CAIRO_FILTER_NEAREST;
@@ -132,22 +125,6 @@
     surface->ref_count++;
 }
 
-static void
-_destroy_user_data (cairo_surface_t *surface)
-{
-    int i, num_slots;
-    cairo_user_data_slot_t *slots;
-
-    num_slots = surface->user_data_slots.num_elements;
-    slots = (cairo_user_data_slot_t *) surface->user_data_slots.elements;
-    for (i = 0; i < num_slots; i++) {
-	if (slots[i].user_data != NULL && slots[i].destroy != NULL)
-	    slots[i].destroy (slots[i].user_data);
-    }
-
-    _cairo_array_fini (&surface->user_data_slots);
-}
-
 void
 cairo_surface_destroy (cairo_surface_t *surface)
 {
@@ -160,7 +137,7 @@
 
     cairo_surface_finish (surface);
 
-    _destroy_user_data (surface);
+    _cairo_user_data_array_destroy (&surface->user_data);
 
     free (surface);
 }
@@ -216,17 +193,8 @@
 cairo_surface_get_user_data (cairo_surface_t		 *surface,
 			     const cairo_user_data_key_t *key)
 {
-    int i, num_slots;
-    cairo_user_data_slot_t *slots;
-
-    num_slots = surface->user_data_slots.num_elements;
-    slots = (cairo_user_data_slot_t *) surface->user_data_slots.elements;
-    for (i = 0; i < num_slots; i++) {
-	if (slots[i].key == key)
-	    return slots[i].user_data;
-    }
-
-    return NULL;
+    return _cairo_user_data_array_get_data (&surface->user_data,
+					    key);
 }
 
 /**
@@ -251,35 +219,8 @@
 			     void			 *user_data,
 			     cairo_destroy_func_t	 destroy)
 {
-    int i, num_slots;
-    cairo_user_data_slot_t *slots, *s;
-
-    s = NULL;
-    num_slots = surface->user_data_slots.num_elements;
-    slots = (cairo_user_data_slot_t *) surface->user_data_slots.elements;
-    for (i = 0; i < num_slots; i++) {
-	if (slots[i].key == key) {
-	    if (slots[i].user_data != NULL && slots[i].destroy != NULL)
-		slots[i].destroy (slots[i].user_data);
-	    s = &slots[i];
-	    break;
-	}
-	if (slots[i].user_data == NULL) {
-	    s = &slots[i];
-	    break;
-	}
-    }
-
-    if (s == NULL)
-	s = _cairo_array_append (&surface->user_data_slots, NULL, 1);
-    if (s == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
-
-    s->key = key;
-    s->user_data = user_data;
-    s->destroy = destroy;
-
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_user_data_array_set_data (&surface->user_data,
+					    key, user_data, destroy);
 }
 
 /**

Index: cairo-win32-font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-win32-font.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- cairo-win32-font.c	7 Apr 2005 19:56:43 -0000	1.15
+++ cairo-win32-font.c	8 Apr 2005 20:14:17 -0000	1.16
@@ -470,8 +470,6 @@
 
     if (scaled_font->unscaled_hfont)
 	DeleteObject (scaled_font->unscaled_hfont);
-
-    free (scaled_font);
 }
 
 static void
@@ -1130,7 +1128,6 @@
 static void
 _cairo_win32_font_face_destroy (void *abstract_face)
 {
-    free (abstract_face);
 }
 
 static cairo_status_t

Index: cairo.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.h,v
retrieving revision 1.95
retrieving revision 1.96
diff -u -d -r1.95 -r1.96
--- cairo.h	8 Apr 2005 17:03:17 -0000	1.95
+++ cairo.h	8 Apr 2005 20:14:17 -0000	1.96
@@ -102,6 +102,28 @@
 
 typedef struct _cairo_pattern cairo_pattern_t;
 
+/**
+ * cairo_destroy_func_t
+ *
+ * #cairo_destroy_func_t the type of function which is called when a
+ * data element is destroyed. It is passed the pointer to the data
+ * element and should free any memory and resources allocated for it.
+ */
+typedef void (*cairo_destroy_func_t) (void *data);
+
+/**
+ * cairo_user_data_key_t
+ *
+ * #cairo_user_data_key_t is used for attaching user data to cairo
+ * data structures.  The actual contents of the struct is never used,
+ * and there is no need to initialize the object; only the unique
+ * address of a #cairo_data_key_t object is used.  Typically, you
+ * would just use the address of a static #cairo_data_key_t object.
+ */
+typedef struct _cairo_user_data_key {
+    int unused;
+} cairo_user_data_key_t;
+
 typedef enum cairo_status {
     CAIRO_STATUS_SUCCESS = 0,
     CAIRO_STATUS_NO_MEMORY,
@@ -622,6 +644,15 @@
 void
 cairo_font_face_destroy (cairo_font_face_t *font_face);
 
+void *
+cairo_font_face_get_user_data (cairo_font_face_t	   *font_face,
+			       const cairo_user_data_key_t *key);
+
+cairo_status_t
+cairo_font_face_set_user_data (cairo_font_face_t	   *font_face,
+			       const cairo_user_data_key_t *key,
+			       void			   *user_data,
+			       cairo_destroy_func_t	    destroy);
 
 /* Portable interface to general font features. */
 
@@ -850,15 +881,6 @@
 const char *
 cairo_status_string (cairo_t *cr);
 
-/**
- * cairo_destroy_func_t
- *
- * #cairo_destroy_func_t the type of function which is called when a
- * data element is destroyed. It is passed the pointer to the data
- * element and should free any memory and resources allocated for it.
- */
-typedef void (*cairo_destroy_func_t) (void *data);
-
 /* Surface manipulation */
 
 /* XXX: I want to remove this function, (replace with
@@ -908,20 +930,6 @@
 cairo_filter_t 
 cairo_surface_get_filter (cairo_surface_t *surface);
 
-
-/**
- * cairo_user_data_key_t
- *
- * #cairo_user_data_key_t is used for attaching user data to cairo
- * data structures.  The actual contents of the struct is never used,
- * and there is no need to initialize the object; only the unique
- * address of a #cairo_data_key_t object is used.  Typically, you
- * would just use the address of a static #cairo_data_key_t object.
- */
-typedef struct _cairo_user_data_key {
-    int unused;
-} cairo_user_data_key_t;
-
 void *
 cairo_surface_get_user_data (cairo_surface_t		 *surface,
 			     const cairo_user_data_key_t *key);

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.123
retrieving revision 1.124
diff -u -d -r1.123 -r1.124
--- cairoint.h	8 Apr 2005 17:03:17 -0000	1.123
+++ cairoint.h	8 Apr 2005 20:14:17 -0000	1.124
@@ -279,6 +279,24 @@
 cairo_private int
 _cairo_array_num_elements (cairo_array_t *array);
 
+typedef cairo_array_t cairo_user_data_array_t;
+
+cairo_private void
+_cairo_user_data_array_init (cairo_user_data_array_t *array);
+
+cairo_private void
+_cairo_user_data_array_destroy (cairo_user_data_array_t *array);
+
+cairo_private void *
+_cairo_user_data_array_get_data (cairo_user_data_array_t     *array,
+				 const cairo_user_data_key_t *key);
+
+cairo_private cairo_status_t
+_cairo_user_data_array_set_data (cairo_user_data_array_t     *array,
+				 const cairo_user_data_key_t *key,
+				 void			     *user_data,
+				 cairo_destroy_func_t	      destroy);
+
 /* cairo_cache.c structures and functions */ 
 
 typedef struct _cairo_cache_backend {
@@ -407,6 +425,7 @@
 
 struct _cairo_font_face {
     int refcount;
+    cairo_user_data_array_t user_data;
     const cairo_font_face_backend_t *backend;
 };
 
@@ -512,6 +531,9 @@
 };
 
 struct _cairo_font_face_backend {
+    /* The destroy() function is allowed to resurrect the font face
+     * by re-referencing. This is needed for the FreeType backend.
+     */
     void           (*destroy)     (void                 *font_face);
     cairo_status_t (*create_font) (void                 *font_face,
 				   cairo_matrix_t       *font_matrix,
@@ -656,7 +678,7 @@
 
     unsigned int ref_count;
     cairo_bool_t finished;
-    cairo_array_t user_data_slots;
+    cairo_user_data_array_t user_data;
 
     cairo_matrix_t matrix;
     cairo_filter_t filter;




More information about the cairo-commit mailing list