summaryrefslogtreecommitdiff
path: root/src/cairo-font.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-font.c')
-rw-r--r--src/cairo-font.c218
1 files changed, 183 insertions, 35 deletions
diff --git a/src/cairo-font.c b/src/cairo-font.c
index a74cac453..9645f3df2 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -39,13 +39,26 @@
#include "cairoint.h"
+/* Forward declare so we can use it as an arbitrary backend for
+ * _cairo_font_face_nil.
+ */
+static const cairo_font_face_backend_t _cairo_simple_font_face_backend;
+
/* cairo_font_face_t */
+const cairo_font_face_t _cairo_font_face_nil = {
+ CAIRO_STATUS_NO_MEMORY, /* status */
+ -1, /* ref_count */
+ { 0, 0, 0, NULL }, /* user_data */
+ &_cairo_simple_font_face_backend
+};
+
void
_cairo_font_face_init (cairo_font_face_t *font_face,
const cairo_font_face_backend_t *backend)
{
- font_face->refcount = 1;
+ font_face->status = CAIRO_STATUS_SUCCESS;
+ font_face->ref_count = 1;
font_face->backend = backend;
_cairo_user_data_array_init (&font_face->user_data);
@@ -66,7 +79,10 @@ cairo_font_face_reference (cairo_font_face_t *font_face)
if (font_face == NULL)
return;
- font_face->refcount++;
+ if (font_face->ref_count == (unsigned int)-1)
+ return;
+
+ font_face->ref_count++;
}
/**
@@ -83,7 +99,10 @@ cairo_font_face_destroy (cairo_font_face_t *font_face)
if (font_face == NULL)
return;
- if (--(font_face->refcount) > 0)
+ if (font_face->ref_count == (unsigned int)-1)
+ return;
+
+ if (--(font_face->ref_count) > 0)
return;
font_face->backend->destroy (font_face);
@@ -92,7 +111,7 @@ cairo_font_face_destroy (cairo_font_face_t *font_face)
* 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)
+ if (font_face->ref_count > 0)
return;
_cairo_user_data_array_fini (&font_face->user_data);
@@ -101,6 +120,22 @@ cairo_font_face_destroy (cairo_font_face_t *font_face)
}
/**
+ * cairo_font_face_status:
+ * @surface: a #cairo_font_face_t
+ *
+ * Checks whether an error has previously occurred for this
+ * font face
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or another error such as
+ * %CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_status_t
+cairo_font_face_status (cairo_font_face_t *font_face)
+{
+ return font_face->status;
+}
+
+/**
* 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
@@ -142,6 +177,9 @@ cairo_font_face_set_user_data (cairo_font_face_t *font_face,
void *user_data,
cairo_destroy_func_t destroy)
{
+ if (font_face->ref_count == -1)
+ return CAIRO_STATUS_NO_MEMORY;
+
return _cairo_user_data_array_set_data (&font_face->user_data,
key, user_data, destroy);
}
@@ -159,8 +197,6 @@ struct _cairo_simple_font_face {
cairo_font_weight_t weight;
};
-static const cairo_font_face_backend_t _cairo_simple_font_face_backend;
-
/* We maintain a global cache from family/weight/slant => cairo_font_face_t
* for cairo_simple_font_t. The primary purpose of this cache is to provide
* unique cairo_font_face_t values so that our cache from
@@ -355,17 +391,18 @@ _cairo_simple_font_face_destroy (void *abstract_face)
}
static cairo_status_t
-_cairo_simple_font_face_create_font (void *abstract_face,
- const cairo_matrix_t *font_matrix,
- const cairo_matrix_t *ctm,
- cairo_scaled_font_t **scaled_font)
+_cairo_simple_font_face_create_font (void *abstract_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ const cairo_font_options_t *options,
+ cairo_scaled_font_t **scaled_font)
{
const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
cairo_simple_font_face_t *simple_face = abstract_face;
return backend->create (simple_face->family, simple_face->slant, simple_face->weight,
- font_matrix, ctm, scaled_font);
+ font_matrix, ctm, options, scaled_font);
}
static const cairo_font_face_backend_t _cairo_simple_font_face_backend = {
@@ -405,21 +442,75 @@ _cairo_simple_font_face_create (const char *family,
cache = _get_global_simple_cache ();
if (cache == NULL) {
_unlock_global_simple_cache ();
- return NULL;
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_font_face_t *)&_cairo_font_face_nil;
}
status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
if (status == CAIRO_STATUS_SUCCESS && !created_entry)
cairo_font_face_reference (&entry->font_face->base);
_unlock_global_simple_cache ();
- if (status)
- return NULL;
+ if (status) {
+ _cairo_error (status);
+ return (cairo_font_face_t *)&_cairo_font_face_nil;
+ }
return &entry->font_face->base;
}
/* cairo_scaled_font_t */
+static const cairo_scaled_font_t _cairo_scaled_font_nil = {
+ CAIRO_STATUS_NO_MEMORY, /* status */
+ -1, /* ref_count */
+ { 1., 0., 0., 1., 0, 0}, /* font_matrix */
+ { 1., 0., 0., 1., 0, 0}, /* ctm */
+ { 1., 0., 0., 1., 0, 0}, /* scale */
+ NULL, /* font_face */
+ CAIRO_SCALED_FONT_BACKEND_DEFAULT,
+};
+
+/**
+ * _cairo_scaled_font_set_error:
+ * @scaled_font: a scaled_font
+ * @status: a status value indicating an error, (eg. not
+ * CAIRO_STATUS_SUCCESS)
+ *
+ * Sets scaled_font->status to @status and calls _cairo_error;
+ *
+ * All assignments of an error status to scaled_font->status should happen
+ * through _cairo_scaled_font_set_error() or else _cairo_error() should be
+ * called immediately after the assignment.
+ *
+ * The purpose of this function is to allow the user to set a
+ * breakpoint in _cairo_error() to generate a stack trace for when the
+ * user causes cairo to detect an error.
+ **/
+void
+_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
+ cairo_status_t status)
+{
+ scaled_font->status = status;
+
+ _cairo_error (status);
+}
+
+/**
+ * cairo_scaled_font_status:
+ * @surface: a #cairo_scaled_font_t
+ *
+ * Checks whether an error has previously occurred for this
+ * scaled_font.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or another error such as
+ * %CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_status_t
+cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
+{
+ return scaled_font->status;
+}
+
/* Here we keep a cache from cairo_font_face_t/matrix/ctm => cairo_scaled_font_t.
*
* The implementation is messy because we want
@@ -444,6 +535,7 @@ typedef struct {
cairo_font_face_t *font_face;
const cairo_matrix_t *font_matrix;
const cairo_matrix_t *ctm;
+ cairo_font_options_t options;
} cairo_font_cache_key_t;
typedef struct {
@@ -554,7 +646,9 @@ _cairo_font_cache_hash (void *cache, void *key)
sizeof(double) * 4,
hash);
- return hash ^ (unsigned long)k->font_face;
+ return (hash ^
+ (unsigned long)k->font_face ^
+ cairo_font_options_hash (&k->options));
}
static int
@@ -573,7 +667,8 @@ _cairo_font_cache_keys_equal (void *cache,
sizeof(double) * 4) == 0 &&
memcmp ((unsigned char *)(&a->ctm->xx),
(unsigned char *)(&b->ctm->xx),
- sizeof(double) * 4) == 0);
+ sizeof(double) * 4) == 0 &&
+ cairo_font_options_equal (&a->options, &b->options));
}
/* The cache lookup failed in the outer cache, so we pull
@@ -614,6 +709,7 @@ _cairo_outer_font_cache_create_entry (void *cache,
entry->key.font_face = entry->scaled_font->font_face;
entry->key.font_matrix = &entry->scaled_font->font_matrix;
entry->key.ctm = &entry->scaled_font->ctm;
+ entry->key.options = ((cairo_font_cache_key_t *) key)->options;
*return_entry = entry;
@@ -650,6 +746,7 @@ _cairo_inner_font_cache_create_entry (void *cache,
status = k->font_face->backend->create_font (k->font_face,
k->font_matrix,
k->ctm,
+ &k->options,
&entry->scaled_font);
if (status) {
free (entry);
@@ -663,6 +760,7 @@ _cairo_inner_font_cache_create_entry (void *cache,
entry->key.font_face = k->font_face;
entry->key.font_matrix = &entry->scaled_font->font_matrix;
entry->key.ctm = &entry->scaled_font->ctm;
+ entry->key.options = k->options;
*return_entry = entry;
@@ -712,6 +810,8 @@ static const cairo_cache_backend_t _cairo_inner_font_cache_backend = {
* cairo_set_font_matrix().
* @ctm: user to device transformation matrix with which the font will
* be used.
+ * @options: options to use when getting metrics for the font and
+ * rendering with it.
*
* Creates a #cairo_scaled_font_t object from a font face and matrices that
* describe the size of the font and the environment in which it will
@@ -721,24 +821,30 @@ static const cairo_cache_backend_t _cairo_inner_font_cache_backend = {
* cairo_scaled_font_destroy()
**/
cairo_scaled_font_t *
-cairo_scaled_font_create (cairo_font_face_t *font_face,
- const cairo_matrix_t *font_matrix,
- const cairo_matrix_t *ctm)
+cairo_scaled_font_create (cairo_font_face_t *font_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ const cairo_font_options_t *options)
{
cairo_font_cache_entry_t *entry;
cairo_font_cache_key_t key;
cairo_cache_t *cache;
cairo_status_t status;
+ if (font_face->status)
+ return (cairo_scaled_font_t*) &_cairo_scaled_font_nil;
+
key.font_face = font_face;
key.font_matrix = font_matrix;
key.ctm = ctm;
+ key.options = *options;
_lock_global_font_cache ();
cache = _get_outer_font_cache ();
if (cache == NULL) {
_unlock_global_font_cache ();
- return NULL;
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_scaled_font_t*) &_cairo_scaled_font_nil;
}
status = _cairo_cache_lookup (cache, &key, (void **) &entry, NULL);
@@ -746,8 +852,10 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
cairo_scaled_font_reference (entry->scaled_font);
_unlock_global_font_cache ();
- if (status)
- return NULL;
+ if (status) {
+ _cairo_error (status);
+ return (cairo_scaled_font_t*) &_cairo_scaled_font_nil;
+ }
return entry->scaled_font;
}
@@ -758,11 +866,13 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
const cairo_matrix_t *ctm,
const cairo_scaled_font_backend_t *backend)
{
+ scaled_font->status = CAIRO_STATUS_SUCCESS;
+
scaled_font->font_matrix = *font_matrix;
scaled_font->ctm = *ctm;
cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, &scaled_font->ctm);
- scaled_font->refcount = 1;
+ scaled_font->ref_count = 1;
scaled_font->backend = backend;
}
@@ -772,6 +882,9 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
cairo_glyph_t **glyphs,
int *num_glyphs)
{
+ if (scaled_font->status)
+ return scaled_font->status;
+
return scaled_font->backend->text_to_glyphs (scaled_font, utf8, glyphs, num_glyphs);
}
@@ -781,6 +894,9 @@ _cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
int num_glyphs,
cairo_text_extents_t *extents)
{
+ if (scaled_font->status)
+ return scaled_font->status;
+
return scaled_font->backend->glyph_extents (scaled_font, glyphs, num_glyphs, extents);
}
@@ -791,6 +907,9 @@ _cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font,
int num_glyphs,
cairo_box_t *bbox)
{
+ if (scaled_font->status)
+ return scaled_font->status;
+
return scaled_font->backend->glyph_bbox (scaled_font, glyphs, num_glyphs, bbox);
}
@@ -810,6 +929,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
{
cairo_status_t status;
+ if (scaled_font->status)
+ return scaled_font->status;
+
status = _cairo_surface_show_glyphs (scaled_font, operator, pattern,
surface,
source_x, source_y,
@@ -834,20 +956,31 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
int num_glyphs,
cairo_path_fixed_t *path)
{
+ if (scaled_font->status)
+ return scaled_font->status;
+
return scaled_font->backend->glyph_path (scaled_font, glyphs, num_glyphs, path);
}
-void
+cairo_status_t
_cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font,
cairo_glyph_cache_key_t *key)
{
+ if (scaled_font->status)
+ return scaled_font->status;
+
scaled_font->backend->get_glyph_cache_key (scaled_font, key);
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents)
{
+ if (scaled_font->status)
+ return scaled_font->status;
+
return scaled_font->backend->font_extents (scaled_font, extents);
}
@@ -855,7 +988,7 @@ void
_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font,
const cairo_unscaled_font_backend_t *backend)
{
- unscaled_font->refcount = 1;
+ unscaled_font->ref_count = 1;
unscaled_font->backend = backend;
}
@@ -865,7 +998,7 @@ _cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
if (unscaled_font == NULL)
return;
- unscaled_font->refcount++;
+ unscaled_font->ref_count++;
}
void
@@ -874,7 +1007,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
if (unscaled_font == NULL)
return;
- if (--(unscaled_font->refcount) > 0)
+ if (--(unscaled_font->ref_count) > 0)
return;
unscaled_font->backend->destroy (unscaled_font);
@@ -901,7 +1034,10 @@ cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
if (scaled_font == NULL)
return;
- scaled_font->refcount++;
+ if (scaled_font->ref_count == (unsigned int)-1)
+ return;
+
+ scaled_font->ref_count++;
}
/**
@@ -921,7 +1057,10 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
if (scaled_font == NULL)
return;
- if (--(scaled_font->refcount) > 0)
+ if (scaled_font->ref_count == (unsigned int)-1)
+ return;
+
+ if (--(scaled_font->ref_count) > 0)
return;
if (scaled_font->font_face) {
@@ -954,17 +1093,23 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
* Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
* error such as %CAIRO_STATUS_NO_MEMORY.
**/
-cairo_status_t
+void
cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents)
{
cairo_int_status_t status;
double font_scale_x, font_scale_y;
+
+ if (scaled_font->status) {
+ _cairo_scaled_font_set_error (scaled_font, scaled_font->status);
+ return;
+ }
status = _cairo_scaled_font_font_extents (scaled_font, extents);
-
- if (status)
- return status;
+ if (status) {
+ _cairo_scaled_font_set_error (scaled_font, status);
+ return;
+ }
_cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
@@ -980,8 +1125,6 @@ cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
extents->height *= font_scale_y;
extents->max_x_advance *= font_scale_x;
extents->max_y_advance *= font_scale_y;
-
- return status;
}
/**
@@ -1008,6 +1151,11 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
double x_pos = 0.0, y_pos = 0.0;
int set = 0;
+ if (scaled_font->status) {
+ _cairo_scaled_font_set_error (scaled_font, scaled_font->status);
+ return;
+ }
+
if (!num_glyphs)
{
extents->x_bearing = 0.0;