[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:
Chris Wilson 2008-02-11 16:17:34 +00:00
parent 38fcc015a5
commit fc732c3aaa
7 changed files with 79 additions and 18 deletions

View file

@ -69,5 +69,7 @@ cairo_debug_reset_static_data (void)
_cairo_pattern_reset_static_data ();
_cairo_scaled_font_reset_static_data ();
CAIRO_MUTEX_FINALIZE ();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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