summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2005-04-08 13:14:17 +0000
committerOwen Taylor <otaylor@redhat.com>2005-04-08 13:14:17 +0000
commitc803908d95d0022463d138f0caee949b14d0cadb (patch)
tree7e93e35f8e335c977b466f1a998a3cb03d80c3a0
parent7aa5b71e8cc42bdcc935ad0990a0ac434dd0aa0e (diff)
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. 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. 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. Update the docs to describe how to figure out when the FT_Face can be freed. Fix refcount leaks when creating fonts. Remove excess call to _cairo_unscaled_font_reference(). Remove stray initialization of font matrix to the identity. 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. Don't append an element when user_data is NULL.
-rw-r--r--ChangeLog42
-rw-r--r--doc/public/cairo-sections.txt2
-rw-r--r--doc/public/tmpl/cairo-font.sgml18
-rw-r--r--doc/public/tmpl/cairo-matrix.sgml12
-rw-r--r--doc/public/tmpl/cairo-pattern.sgml6
-rw-r--r--doc/public/tmpl/cairo-surface.sgml6
-rw-r--r--doc/public/tmpl/cairo.sgml13
-rw-r--r--src/cairo-array.c139
-rw-r--r--src/cairo-atsui-font.c2
-rw-r--r--src/cairo-font.c67
-rw-r--r--src/cairo-ft-font.c97
-rw-r--r--src/cairo-gstate.c1
-rw-r--r--src/cairo-pdf-surface.c2
-rw-r--r--src/cairo-surface.c71
-rw-r--r--src/cairo-win32-font.c3
-rw-r--r--src/cairo.h54
-rw-r--r--src/cairoint.h24
-rw-r--r--test/user-data.c4
18 files changed, 393 insertions, 170 deletions
diff --git a/ChangeLog b/ChangeLog
index 96740beb..e805df7e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2005-04-08 Owen Taylor <otaylor@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.
+
2005-04-08 Dave Beckett <Dave.Beckett@bristol.ac.uk>
* src/cairo-glitz-surface.c (_cairo_glitz_surface_set_matrix):
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 94ba4f8a..1b2e5461 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -142,6 +142,8 @@ cairo_font_face_t
cairo_scaled_font_t
cairo_font_face_reference
cairo_font_face_destroy
+cairo_font_face_get_user_data
+cairo_font_face_set_user_data
cairo_scaled_font_create
cairo_scaled_font_reference
cairo_scaled_font_destroy
diff --git a/doc/public/tmpl/cairo-font.sgml b/doc/public/tmpl/cairo-font.sgml
index cdf0ed28..a04a1e9c 100644
--- a/doc/public/tmpl/cairo-font.sgml
+++ b/doc/public/tmpl/cairo-font.sgml
@@ -17,32 +17,42 @@ Font Handling
<!-- ##### SECTION Stability_Level ##### -->
-<!-- ##### TYPEDEF cairo_font_face_t ##### -->
+<!-- ##### FUNCTION cairo_font_face_reference ##### -->
<para>
</para>
+@font_face:
+
-<!-- ##### TYPEDEF cairo_scaled_font_t ##### -->
+<!-- ##### FUNCTION cairo_font_face_destroy ##### -->
<para>
</para>
+@font_face:
+
-<!-- ##### FUNCTION cairo_font_face_reference ##### -->
+<!-- ##### FUNCTION cairo_font_face_get_user_data ##### -->
<para>
</para>
@font_face:
+@key:
+@Returns:
-<!-- ##### FUNCTION cairo_font_face_destroy ##### -->
+<!-- ##### FUNCTION cairo_font_face_set_user_data ##### -->
<para>
</para>
@font_face:
+@key:
+@user_data:
+@destroy:
+@Returns:
<!-- ##### FUNCTION cairo_scaled_font_create ##### -->
diff --git a/doc/public/tmpl/cairo-matrix.sgml b/doc/public/tmpl/cairo-matrix.sgml
index 686d89ad..e1d2f8cc 100644
--- a/doc/public/tmpl/cairo-matrix.sgml
+++ b/doc/public/tmpl/cairo-matrix.sgml
@@ -41,18 +41,6 @@ cairo_matrix_t
<!-- ##### SECTION Stability_Level ##### -->
-<!-- ##### STRUCT cairo_matrix_t ##### -->
-<para>
-
-</para>
-
-@xx:
-@yx:
-@xy:
-@yy:
-@x0:
-@y0:
-
<!-- ##### FUNCTION cairo_matrix_create ##### -->
<para>
diff --git a/doc/public/tmpl/cairo-pattern.sgml b/doc/public/tmpl/cairo-pattern.sgml
index 4687bd6c..747dba28 100644
--- a/doc/public/tmpl/cairo-pattern.sgml
+++ b/doc/public/tmpl/cairo-pattern.sgml
@@ -17,12 +17,6 @@ cairo_pattern_t
<!-- ##### SECTION Stability_Level ##### -->
-<!-- ##### TYPEDEF cairo_pattern_t ##### -->
-<para>
-
-</para>
-
-
<!-- ##### FUNCTION cairo_pattern_create_for_surface ##### -->
<para>
diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml
index b6b7217c..456347e9 100644
--- a/doc/public/tmpl/cairo-surface.sgml
+++ b/doc/public/tmpl/cairo-surface.sgml
@@ -17,12 +17,6 @@ cairo_surface_t
<!-- ##### SECTION Stability_Level ##### -->
-<!-- ##### TYPEDEF cairo_surface_t ##### -->
-<para>
-
-</para>
-
-
<!-- ##### MACRO cairo_surface_create_for_image ##### -->
<para>
diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml
index 6fb842ae..a725a1b4 100644
--- a/doc/public/tmpl/cairo.sgml
+++ b/doc/public/tmpl/cairo.sgml
@@ -27,12 +27,6 @@ Drawing contexts.
<!-- ##### SECTION Stability_Level ##### -->
-<!-- ##### TYPEDEF cairo_t ##### -->
-<para>
-
-</para>
-
-
<!-- ##### FUNCTION cairo_create ##### -->
<para>
@@ -997,13 +991,6 @@ End:
@data:
-<!-- ##### STRUCT cairo_user_data_key_t ##### -->
-<para>
-
-</para>
-
-@unused:
-
<!-- ##### USER_FUNCTION cairo_write_func_t ##### -->
<para>
diff --git a/src/cairo-array.c b/src/cairo-array.c
index 2b1cf9d6..a37ea9af 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -132,3 +132,142 @@ _cairo_array_num_elements (cairo_array_t *array)
{
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;
+}
+
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index 0813ff82..bddd761e 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -214,8 +214,6 @@ _cairo_atsui_font_destroy_font(void *abstract_font)
ATSUDisposeStyle(font->style);
if (font->unscaled_style)
ATSUDisposeStyle(font->unscaled_style);
-
- free(font);
}
diff --git a/src/cairo-font.c b/src/cairo-font.c
index d1743b13..4f7779d6 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -47,6 +47,8 @@ _cairo_font_face_init (cairo_font_face_t *font_face,
{
font_face->refcount = 1;
font_face->backend = backend;
+
+ _cairo_user_data_array_init (&font_face->user_data);
}
/**
@@ -73,11 +75,70 @@ cairo_font_face_reference (cairo_font_face_t *font_face)
**/
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 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
return;
unscaled_font->backend->destroy (unscaled_font);
+
+ free (unscaled_font);
}
@@ -852,6 +915,8 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
}
scaled_font->backend->destroy (scaled_font);
+
+ free (scaled_font);
}
/**
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 80c70e94..0ae98902 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -482,7 +482,13 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font)
{
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_ft_unscaled_font_destroy (void *abstract_font)
_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 @@ _cairo_ft_scaled_font_destroy (void *abstract_font)
return;
_cairo_unscaled_font_destroy (&scaled_font->unscaled->base);
-
- free (scaled_font);
}
static void
@@ -1332,20 +1331,47 @@ _ft_font_face_destroy (void *abstract_face)
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_font_face_t *
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 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face,
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;
}
/**
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 014294ae..34dc1cd2 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -2359,7 +2359,6 @@ _cairo_gstate_set_font_face (cairo_gstate_t *gstate,
cairo_font_face_reference (gstate->font_face);
}
- cairo_matrix_init_identity (&gstate->font_matrix);
_cairo_gstate_unset_font (gstate);
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index c612ca01..7b016ad2 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -324,8 +324,6 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
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;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index fead5f4e..4e5215df 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -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 @@ _cairo_surface_init (cairo_surface_t *surface,
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 @@ cairo_surface_reference (cairo_surface_t *surface)
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_destroy (cairo_surface_t *surface)
cairo_surface_finish (surface);
- _destroy_user_data (surface);
+ _cairo_user_data_array_destroy (&surface->user_data);
free (surface);
}
@@ -216,17 +193,8 @@ void *
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 @@ cairo_surface_set_user_data (cairo_surface_t *surface,
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);
}
/**
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index cbe245bf..4ea0abbc 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -470,8 +470,6 @@ _cairo_win32_scaled_font_destroy (void *abstract_font)
if (scaled_font->unscaled_hfont)
DeleteObject (scaled_font->unscaled_hfont);
-
- free (scaled_font);
}
static void
@@ -1130,7 +1128,6 @@ struct _cairo_win32_font_face {
static void
_cairo_win32_font_face_destroy (void *abstract_face)
{
- free (abstract_face);
}
static cairo_status_t
diff --git a/src/cairo.h b/src/cairo.h
index ea854cc4..1cced055 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -102,6 +102,28 @@ typedef struct _cairo_matrix {
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 @@ cairo_font_face_reference (cairo_font_face_t *font_face);
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 @@ cairo_status (cairo_t *cr);
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_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter);
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);
diff --git a/src/cairoint.h b/src/cairoint.h
index 8da9c8cd..b5c3d0f5 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -279,6 +279,24 @@ _cairo_array_copy_element (cairo_array_t *array, int index, void *dst);
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_scaled_font {
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_scaled_font_backend {
};
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 @@ struct _cairo_surface {
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;
diff --git a/test/user-data.c b/test/user-data.c
index 88a706af..d17b933b 100644
--- a/test/user-data.c
+++ b/test/user-data.c
@@ -60,6 +60,10 @@ main (void)
assert (data1 == 1);
assert (data2 == 0);
+ assert (cairo_surface_set_user_data (surface, &key2, NULL, NULL)
+ == CAIRO_STATUS_SUCCESS);
+ assert (data2 == 2);
+
data1 = 0;
assert (cairo_surface_set_user_data (surface, &key1, &data1, NULL)
== CAIRO_STATUS_SUCCESS);