mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-24 18:20:09 +01:00
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:
parent
7aa5b71e8c
commit
c803908d95
18 changed files with 401 additions and 178 deletions
42
ChangeLog
42
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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,6 @@ cairo_pattern_t
|
|||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### TYPEDEF cairo_pattern_t ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
|
||||
<!-- ##### FUNCTION cairo_pattern_create_for_surface ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,6 @@ cairo_surface_t
|
|||
<!-- ##### SECTION Stability_Level ##### -->
|
||||
|
||||
|
||||
<!-- ##### TYPEDEF cairo_surface_t ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
|
||||
<!-- ##### MACRO cairo_surface_create_for_image ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
54
src/cairo.h
54
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue