mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-31 16:00:14 +01:00
[cairo-scaled-font] Create error objects on demand.
In order to correctly report the error back to the user during the creation of a scaled font, we need to support a nil object per error. Instead of statically allocating all possible errors, lazily allocate the nil object the first time we need to report a particular error. This fixes the misreporting of an INVALID_MATRIX or NULL_POINTER that are common user errors during the construction of a scaled font.
This commit is contained in:
parent
38fcc015a5
commit
fc732c3aaa
7 changed files with 79 additions and 18 deletions
|
|
@ -69,5 +69,7 @@ cairo_debug_reset_static_data (void)
|
|||
|
||||
_cairo_pattern_reset_static_data ();
|
||||
|
||||
_cairo_scaled_font_reset_static_data ();
|
||||
|
||||
CAIRO_MUTEX_FINALIZE ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock);
|
|||
|
||||
CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex);
|
||||
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex);
|
||||
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex);
|
||||
|
||||
#if CAIRO_HAS_FT_FONT
|
||||
CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex);
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ _cairo_scaled_glyph_destroy (void *abstract_glyph)
|
|||
}
|
||||
|
||||
#define ZOMBIE 0
|
||||
const cairo_scaled_font_t _cairo_scaled_font_nil = {
|
||||
static const cairo_scaled_font_t _cairo_scaled_font_nil = {
|
||||
{ ZOMBIE }, /* hash_entry */
|
||||
CAIRO_STATUS_NO_MEMORY, /* status */
|
||||
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
|
||||
|
|
@ -621,17 +621,18 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
|
|||
cairo_scaled_font_t key, *scaled_font = NULL;
|
||||
|
||||
if (font_face->status)
|
||||
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
|
||||
return _cairo_scaled_font_create_in_error (font_face->status);
|
||||
|
||||
if (cairo_font_options_status ((cairo_font_options_t *) options))
|
||||
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
|
||||
status = cairo_font_options_status ((cairo_font_options_t *) options);
|
||||
if (status)
|
||||
return _cairo_scaled_font_create_in_error (status);
|
||||
|
||||
/* Note that degenerate ctm or font_matrix *are* allowed.
|
||||
* We want to support a font size of 0. */
|
||||
|
||||
font_map = _cairo_scaled_font_map_lock ();
|
||||
if (font_map == NULL)
|
||||
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
|
||||
return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
|
||||
_cairo_scaled_font_init_key (&key, font_face,
|
||||
font_matrix, ctm, options);
|
||||
|
|
@ -682,7 +683,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
|
|||
if (status) {
|
||||
_cairo_scaled_font_map_unlock ();
|
||||
status = _cairo_font_face_set_error (font_face, status);
|
||||
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
|
||||
return _cairo_scaled_font_create_in_error (status);
|
||||
}
|
||||
|
||||
status = _cairo_hash_table_insert (font_map->hash_table,
|
||||
|
|
@ -695,13 +696,63 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
|
|||
* hash table. */
|
||||
_cairo_scaled_font_fini (scaled_font);
|
||||
free (scaled_font);
|
||||
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
|
||||
return _cairo_scaled_font_create_in_error (status);
|
||||
}
|
||||
|
||||
return scaled_font;
|
||||
}
|
||||
slim_hidden_def (cairo_scaled_font_create);
|
||||
|
||||
static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
|
||||
|
||||
/* XXX This should disappear in favour of a common pool of error objects. */
|
||||
cairo_scaled_font_t *
|
||||
_cairo_scaled_font_create_in_error (cairo_status_t status)
|
||||
{
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
|
||||
assert (status != CAIRO_STATUS_SUCCESS);
|
||||
|
||||
if (status == CAIRO_STATUS_NO_MEMORY)
|
||||
return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
|
||||
|
||||
CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
|
||||
scaled_font = _cairo_scaled_font_nil_objects[status];
|
||||
if (scaled_font == NULL) {
|
||||
scaled_font = malloc (sizeof (cairo_scaled_font_t));
|
||||
if (scaled_font == NULL) {
|
||||
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
|
||||
}
|
||||
|
||||
*scaled_font = _cairo_scaled_font_nil;
|
||||
scaled_font->status = status;
|
||||
_cairo_scaled_font_nil_objects[status] = scaled_font;
|
||||
}
|
||||
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
|
||||
|
||||
return scaled_font;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_scaled_font_reset_static_data (void)
|
||||
{
|
||||
int status;
|
||||
|
||||
CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
|
||||
for (status = CAIRO_STATUS_SUCCESS;
|
||||
status <= CAIRO_STATUS_LAST_STATUS;
|
||||
status++)
|
||||
{
|
||||
if (_cairo_scaled_font_nil_objects[status] != NULL) {
|
||||
free (_cairo_scaled_font_nil_objects[status]);
|
||||
_cairo_scaled_font_nil_objects[status] = NULL;
|
||||
}
|
||||
}
|
||||
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_scaled_font_reference:
|
||||
* @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
|
||||
|
|
|
|||
10
src/cairo.c
10
src/cairo.c
|
|
@ -63,12 +63,6 @@ static const cairo_t _cairo_nil = {
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
/* This has to be updated whenever #cairo_status_t is extended. That's
|
||||
* a bit of a pain, but it should be easy to always catch as long as
|
||||
* one adds a new test case to test a trigger of the new status value.
|
||||
*/
|
||||
#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_STRIDE
|
||||
|
||||
/**
|
||||
* _cairo_error:
|
||||
* @status: a status value indicating an error, (eg. not
|
||||
|
|
@ -2869,12 +2863,12 @@ cairo_get_scaled_font (cairo_t *cr)
|
|||
cairo_scaled_font_t *scaled_font;
|
||||
|
||||
if (cr->status)
|
||||
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
|
||||
return _cairo_scaled_font_create_in_error (cr->status);
|
||||
|
||||
status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
|
||||
if (status) {
|
||||
_cairo_set_error (cr, status);
|
||||
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
|
||||
return _cairo_scaled_font_create_in_error (status);
|
||||
}
|
||||
|
||||
return scaled_font;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ typedef enum _cairo_status {
|
|||
CAIRO_STATUS_CLIP_NOT_REPRESENTABLE,
|
||||
CAIRO_STATUS_TEMP_FILE_ERROR,
|
||||
CAIRO_STATUS_INVALID_STRIDE
|
||||
/* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairo.c */
|
||||
/* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairoint.h */
|
||||
} cairo_status_t;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -105,6 +105,14 @@ _cairo_win32_tmpfile (void);
|
|||
#undef ARRAY_LENGTH
|
||||
#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
|
||||
|
||||
|
||||
/* This has to be updated whenever #cairo_status_t is extended. That's
|
||||
* a bit of a pain, but it should be easy to always catch as long as
|
||||
* one adds a new test case to test a trigger of the new status value.
|
||||
*/
|
||||
#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_STRIDE
|
||||
|
||||
|
||||
/* Size in bytes of buffer to use off the stack per functions.
|
||||
* Mostly used by text functions. For larger allocations, they'll
|
||||
* malloc(). */
|
||||
|
|
@ -1227,8 +1235,13 @@ cairo_private cairo_status_t
|
|||
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
|
||||
cairo_status_t status);
|
||||
|
||||
cairo_private cairo_scaled_font_t *
|
||||
_cairo_scaled_font_create_in_error (cairo_status_t status);
|
||||
|
||||
cairo_private void
|
||||
_cairo_scaled_font_reset_static_data (void);
|
||||
|
||||
extern const cairo_private cairo_font_face_t _cairo_font_face_nil;
|
||||
extern const cairo_private cairo_scaled_font_t _cairo_scaled_font_nil;
|
||||
|
||||
cairo_private void
|
||||
_cairo_font_face_init (cairo_font_face_t *font_face,
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ main (void)
|
|||
scaled_font = cairo_scaled_font_create (cairo_get_font_face (cr),
|
||||
&identity, &identity,
|
||||
NULL);
|
||||
assert (cairo_scaled_font_status (scaled_font) == CAIRO_STATUS_NO_MEMORY); /* XXX */
|
||||
assert (cairo_scaled_font_status (scaled_font) == CAIRO_STATUS_NULL_POINTER);
|
||||
cairo_scaled_font_get_font_options (scaled_font, NULL);
|
||||
cairo_scaled_font_destroy (scaled_font);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue