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.
This commit is contained in:
Owen Taylor 2005-04-08 13:14:17 +00:00
parent 7aa5b71e8c
commit c803908d95
18 changed files with 401 additions and 178 deletions

View file

@ -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):

View file

@ -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

View file

@ -17,18 +17,6 @@ Font Handling
<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### TYPEDEF cairo_font_face_t ##### -->
<para>
</para>
<!-- ##### TYPEDEF cairo_scaled_font_t ##### -->
<para>
</para>
<!-- ##### FUNCTION cairo_font_face_reference ##### -->
<para>
@ -45,6 +33,28 @@ Font Handling
@font_face:
<!-- ##### FUNCTION cairo_font_face_get_user_data ##### -->
<para>
</para>
@font_face:
@key:
@Returns:
<!-- ##### FUNCTION cairo_font_face_set_user_data ##### -->
<para>
</para>
@font_face:
@key:
@user_data:
@destroy:
@Returns:
<!-- ##### FUNCTION cairo_scaled_font_create ##### -->
<para>

View file

@ -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>

View file

@ -17,12 +17,6 @@ cairo_pattern_t
<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### TYPEDEF cairo_pattern_t ##### -->
<para>
</para>
<!-- ##### FUNCTION cairo_pattern_create_for_surface ##### -->
<para>

View file

@ -17,12 +17,6 @@ cairo_surface_t
<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### TYPEDEF cairo_surface_t ##### -->
<para>
</para>
<!-- ##### MACRO cairo_surface_create_for_image ##### -->
<para>

View file

@ -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>

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}
/**

View file

@ -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
*/
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;
}
last_face = tmp_face;
_cairo_unscaled_font_destroy (&font_face->unscaled->base);
font_face->unscaled = NULL;
}
_cairo_unscaled_font_destroy (&font_face->unscaled->base);
free (font_face);
}
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;
}
/**

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
/**

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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);