From fc732c3aaa53d8abcea46ad28da696ad08d09b63 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 11 Feb 2008 16:17:34 +0000 Subject: [PATCH] [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. --- src/cairo-debug.c | 2 ++ src/cairo-mutex-list-private.h | 1 + src/cairo-scaled-font.c | 65 ++++++++++++++++++++++++++++++---- src/cairo.c | 10 ++---- src/cairo.h | 2 +- src/cairoint.h | 15 +++++++- test/font-options.c | 2 +- 7 files changed, 79 insertions(+), 18 deletions(-) diff --git a/src/cairo-debug.c b/src/cairo-debug.c index c4b7edfe3..da2052745 100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c @@ -69,5 +69,7 @@ cairo_debug_reset_static_data (void) _cairo_pattern_reset_static_data (); + _cairo_scaled_font_reset_static_data (); + CAIRO_MUTEX_FINALIZE (); } diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h index 89fe77010..1fe5bd5ae 100644 --- a/src/cairo-mutex-list-private.h +++ b/src/cairo-mutex-list-private.h @@ -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); diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 8d79648f4..3d9e32a55 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -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 diff --git a/src/cairo.c b/src/cairo.c index ebb660393..7f5e1ecca 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -63,12 +63,6 @@ static const cairo_t _cairo_nil = { #include -/* 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; diff --git a/src/cairo.h b/src/cairo.h index 0c244ba30..5988f3aaa 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -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; /** diff --git a/src/cairoint.h b/src/cairoint.h index 0ca08f40a..8f8685f34 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -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, diff --git a/test/font-options.c b/test/font-options.c index 50c1fb812..b0e111ef6 100644 --- a/test/font-options.c +++ b/test/font-options.c @@ -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);