diff options
author | Owen Taylor <otaylor@redhat.com> | 2005-04-08 13:14:17 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@redhat.com> | 2005-04-08 13:14:17 +0000 |
commit | c803908d95d0022463d138f0caee949b14d0cadb (patch) | |
tree | 7e93e35f8e335c977b466f1a998a3cb03d80c3a0 | |
parent | 7aa5b71e8cc42bdcc935ad0990a0ac434dd0aa0e (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-- | ChangeLog | 42 | ||||
-rw-r--r-- | doc/public/cairo-sections.txt | 2 | ||||
-rw-r--r-- | doc/public/tmpl/cairo-font.sgml | 18 | ||||
-rw-r--r-- | doc/public/tmpl/cairo-matrix.sgml | 12 | ||||
-rw-r--r-- | doc/public/tmpl/cairo-pattern.sgml | 6 | ||||
-rw-r--r-- | doc/public/tmpl/cairo-surface.sgml | 6 | ||||
-rw-r--r-- | doc/public/tmpl/cairo.sgml | 13 | ||||
-rw-r--r-- | src/cairo-array.c | 139 | ||||
-rw-r--r-- | src/cairo-atsui-font.c | 2 | ||||
-rw-r--r-- | src/cairo-font.c | 67 | ||||
-rw-r--r-- | src/cairo-ft-font.c | 97 | ||||
-rw-r--r-- | src/cairo-gstate.c | 1 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 2 | ||||
-rw-r--r-- | src/cairo-surface.c | 71 | ||||
-rw-r--r-- | src/cairo-win32-font.c | 3 | ||||
-rw-r--r-- | src/cairo.h | 54 | ||||
-rw-r--r-- | src/cairoint.h | 24 | ||||
-rw-r--r-- | test/user-data.c | 4 |
18 files changed, 393 insertions, 170 deletions
@@ -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); |