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.c479
1 files changed, 217 insertions, 262 deletions
diff --git a/src/cairo_font.c b/src/cairo_font.c
index f5fc0e981..529c1c7c3 100644
--- a/src/cairo_font.c
+++ b/src/cairo_font.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -31,293 +32,129 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
+ * Graydon Hoare <graydon@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.h"
-/* First we implement a global font cache for named fonts. */
-
-typedef struct {
- cairo_cache_entry_base_t base;
- const char *family;
- cairo_font_slant_t slant;
- cairo_font_weight_t weight;
-} cairo_font_cache_key_t;
-
-typedef struct {
- cairo_font_cache_key_t key;
- cairo_unscaled_font_t *unscaled;
-} cairo_font_cache_entry_t;
-
-static unsigned long
-_font_cache_hash (void *cache, void *key)
-{
- unsigned long hash;
- cairo_font_cache_key_t *in;
- in = (cairo_font_cache_key_t *) key;
-
- /* 1607 and 1451 are just a couple random primes. */
- hash = _cairo_hash_string (in->family);
- hash += ((unsigned long) in->slant) * 1607;
- hash += ((unsigned long) in->weight) * 1451;
- return hash;
-}
-
-
-static int
-_font_cache_keys_equal (void *cache,
- void *k1,
- void *k2)
-{
- cairo_font_cache_key_t *a, *b;
- a = (cairo_font_cache_key_t *) k1;
- b = (cairo_font_cache_key_t *) k2;
-
- return (strcmp (a->family, b->family) == 0)
- && (a->weight == b->weight)
- && (a->slant == b->slant);
-}
-
-
-static cairo_status_t
-_font_cache_create_entry (void *cache,
- void *key,
- void **return_value)
-{
- const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
- cairo_font_cache_key_t *k;
- cairo_font_cache_entry_t *entry;
- k = (cairo_font_cache_key_t *) key;
-
- /* XXX: The current freetype backend may return NULL, (for example
- * if no fonts are installed), but I would like to guarantee that
- * the toy API always returns at least *some* font, so I would
- * like to build in some sort fo font here, (even a really lame,
- * ugly one if necessary). */
-
- entry = malloc (sizeof (cairo_font_cache_entry_t));
- if (entry == NULL)
- goto FAIL;
-
- entry->key.slant = k->slant;
- entry->key.weight = k->weight;
- entry->key.family = strdup(k->family);
- if (entry->key.family == NULL)
- goto FREE_ENTRY;
-
- entry->unscaled = backend->create (k->family, k->slant, k->weight);
- if (entry->unscaled == NULL)
- goto FREE_FAMILY;
-
- /* Not sure how to measure backend font mem; use a simple count for now.*/
- entry->key.base.memory = 1;
- *return_value = entry;
- return CAIRO_STATUS_SUCCESS;
-
- FREE_FAMILY:
- free ((void *) entry->key.family);
-
- FREE_ENTRY:
- free (entry);
-
- FAIL:
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static void
-_font_cache_destroy_entry (void *cache,
- void *entry)
-{
- cairo_font_cache_entry_t *e;
-
- e = (cairo_font_cache_entry_t *) entry;
- _cairo_unscaled_font_destroy (e->unscaled);
- free ((void *) e->key.family);
- free (e);
-}
-
-static void
-_font_cache_destroy_cache (void *cache)
-{
- free (cache);
-}
-
-static const cairo_cache_backend_t cairo_font_cache_backend = {
- _font_cache_hash,
- _font_cache_keys_equal,
- _font_cache_create_entry,
- _font_cache_destroy_entry,
- _font_cache_destroy_cache
-};
-
-static void
-_lock_global_font_cache (void)
-{
- /* FIXME: implement locking. */
-}
-
-static void
-_unlock_global_font_cache (void)
-{
- /* FIXME: implement locking. */
-}
-
-static cairo_cache_t *
-_global_font_cache = NULL;
-
-static cairo_cache_t *
-_get_global_font_cache (void)
-{
- if (_global_font_cache == NULL) {
- _global_font_cache = malloc (sizeof (cairo_cache_t));
-
- if (_global_font_cache == NULL)
- goto FAIL;
-
- if (_cairo_cache_init (_global_font_cache,
- &cairo_font_cache_backend,
- CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT))
- goto FAIL;
- }
-
- return _global_font_cache;
-
- FAIL:
- if (_global_font_cache)
- free (_global_font_cache);
- _global_font_cache = NULL;
- return NULL;
-}
-
-
/* Now the internal "unscaled + scale" font API */
-cairo_unscaled_font_t *
-_cairo_unscaled_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+cairo_private cairo_status_t
+_cairo_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *sc,
+ cairo_font_t **font)
{
- cairo_cache_t * cache;
- cairo_font_cache_key_t key;
- cairo_font_cache_entry_t *font;
- cairo_status_t status;
-
- _lock_global_font_cache ();
- cache = _get_global_font_cache ();
- if (cache == NULL) {
- _unlock_global_font_cache ();
- return NULL;
- }
-
- key.family = family;
- key.slant = slant;
- key.weight = weight;
-
- status = _cairo_cache_lookup (cache, &key, (void **) &font);
- if (status) {
- _unlock_global_font_cache ();
- return NULL;
- }
+ const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
- _cairo_unscaled_font_reference (font->unscaled);
- _unlock_global_font_cache ();
- return font->unscaled;
+ return backend->create (family, slant, weight, sc, font);
}
void
-_cairo_font_init (cairo_font_t *scaled,
- cairo_font_scale_t *scale,
- cairo_unscaled_font_t *unscaled)
+_cairo_font_init (cairo_font_t *font,
+ cairo_font_scale_t *scale,
+ const cairo_font_backend_t *backend)
{
- scaled->scale = *scale;
- scaled->unscaled = unscaled;
- scaled->refcount = 1;
+ font->scale = *scale;
+ font->refcount = 1;
+ font->backend = backend;
}
-cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const cairo_font_backend_t *backend)
+void
+_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
+ const cairo_font_backend_t *backend)
{
font->refcount = 1;
font->backend = backend;
- return CAIRO_STATUS_SUCCESS;
}
-
cairo_status_t
-_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+_cairo_font_text_to_glyphs (cairo_font_t *font,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs);
+ return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs);
}
cairo_status_t
-_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_font_glyph_extents (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents);
+ return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
}
cairo_status_t
-_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
- return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox);
+ return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox);
}
cairo_status_t
-_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_operator_t operator,
- cairo_surface_t *source,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_font_show_glyphs (cairo_font_t *font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_status_t status;
if (surface->backend->show_glyphs != NULL) {
- status = surface->backend->show_glyphs (font, scale, operator, source,
- surface, source_x, source_y,
+ status = surface->backend->show_glyphs (font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
glyphs, num_glyphs);
if (status == CAIRO_STATUS_SUCCESS)
return status;
}
/* Surface display routine either does not exist or failed. */
- return font->backend->show_glyphs (font, scale, operator, source,
- surface, source_x, source_y,
+ return font->backend->show_glyphs (font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
glyphs, num_glyphs);
}
cairo_status_t
-_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+_cairo_font_glyph_path (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
+{
+ return font->backend->glyph_path (font, glyphs, num_glyphs, path);
+}
+
+void
+_cairo_font_get_glyph_cache_key (cairo_font_t *font,
+ cairo_glyph_cache_key_t *key)
{
- return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path);
+ font->backend->get_glyph_cache_key (font, key);
}
cairo_status_t
-_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_font_extents_t *extents)
+_cairo_font_font_extents (cairo_font_t *font,
+ cairo_font_extents_t *extents)
{
- return font->backend->font_extents(font, scale, extents);
+ return font->backend->font_extents (font, extents);
}
void
@@ -332,8 +169,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
if (--(font->refcount) > 0)
return;
- if (font->backend)
- font->backend->destroy (font);
+ font->backend->destroy_unscaled_font (font);
}
@@ -352,37 +188,154 @@ cairo_font_destroy (cairo_font_t *font)
if (--(font->refcount) > 0)
return;
- if (font->unscaled)
- _cairo_unscaled_font_destroy (font->unscaled);
-
- free (font);
+ font->backend->destroy_font (font);
}
-void
-cairo_font_set_transform (cairo_font_t *font,
- cairo_matrix_t *matrix)
+/**
+ * cairo_font_extents:
+ * @font: a #cairo_font_t
+ * @font_matrix: the font transformation for which this font was
+ * created. (See cairo_transform_font()). This is needed
+ * properly convert the metrics from the font into user space.
+ * @extents: a #cairo_font_extents_t which to store the retrieved extents.
+ *
+ * Gets the metrics for a #cairo_font_t.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
+ * error such as %CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_status_t
+cairo_font_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_font_extents_t *extents)
{
- double dummy;
- cairo_matrix_get_affine (matrix,
- &font->scale.matrix[0][0],
- &font->scale.matrix[0][1],
- &font->scale.matrix[1][0],
- &font->scale.matrix[1][1],
- &dummy, &dummy);
+ cairo_int_status_t status;
+ double font_scale_x, font_scale_y;
+
+ status = _cairo_font_font_extents (font, extents);
+
+ if (!CAIRO_OK (status))
+ return status;
+
+ _cairo_matrix_compute_scale_factors (font_matrix,
+ &font_scale_x, &font_scale_y,
+ /* XXX */ 1);
+
+ /*
+ * The font responded in unscaled units, scale by the font
+ * matrix scale factors to get to user space
+ */
+
+ extents->ascent *= font_scale_y;
+ extents->descent *= font_scale_y;
+ extents->height *= font_scale_y;
+ extents->max_x_advance *= font_scale_x;
+ extents->max_y_advance *= font_scale_y;
+
+ return status;
}
+/**
+ * cairo_font_glyph_extents:
+ * @font: a #cairo_font_t
+ * @font_matrix: the font transformation for which this font was
+ * created. (See cairo_transform_font()). This is needed
+ * properly convert the metrics from the font into user space.
+ * @glyphs: an array of glyph IDs with X and Y offsets.
+ * @num_glyphs: the number of glyphs in the @glyphs array
+ * @extents: a #cairo_text_extents_t which to store the retrieved extents.
+ *
+ * cairo_font_glyph_extents() gets the overall metrics for a string of
+ * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0.
+ **/
void
-cairo_font_current_transform (cairo_font_t *font,
- cairo_matrix_t *matrix)
+cairo_font_glyph_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- cairo_matrix_set_affine (matrix,
- font->scale.matrix[0][0],
- font->scale.matrix[0][1],
- font->scale.matrix[1][0],
- font->scale.matrix[1][1],
- 0, 0);
-}
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_glyph_t origin_glyph;
+ cairo_text_extents_t origin_extents;
+ int i;
+ double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
+ double x_pos = 0.0, y_pos = 0.0;
+ int set = 0;
+
+ if (!num_glyphs)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return;
+ }
+ for (i = 0; i < num_glyphs; i++)
+ {
+ double x, y;
+ double wm, hm;
+
+ origin_glyph = glyphs[i];
+ origin_glyph.x = 0.0;
+ origin_glyph.y = 0.0;
+ status = _cairo_font_glyph_extents (font,
+ &origin_glyph, 1,
+ &origin_extents);
+
+ /*
+ * Transform font space metrics into user space metrics
+ * by running the corners through the font matrix and
+ * expanding the bounding box as necessary
+ */
+ x = origin_extents.x_bearing;
+ y = origin_extents.y_bearing;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+
+ for (hm = 0.0; hm <= 1.0; hm += 1.0)
+ for (wm = 0.0; wm <= 1.0; wm += 1.0)
+ {
+ x = origin_extents.x_bearing + origin_extents.width * wm;
+ y = origin_extents.y_bearing + origin_extents.height * hm;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+ x += glyphs[i].x;
+ y += glyphs[i].y;
+ if (!set)
+ {
+ min_x = max_x = x;
+ min_y = max_y = y;
+ set = 1;
+ }
+ else
+ {
+ if (x < min_x) min_x = x;
+ if (x > max_x) max_x = x;
+ if (y < min_y) min_y = y;
+ if (y > max_y) max_y = y;
+ }
+ }
+
+ x = origin_extents.x_advance;
+ y = origin_extents.y_advance;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+ x_pos = glyphs[i].x + x;
+ y_pos = glyphs[i].y + y;
+ }
+
+ extents->x_bearing = min_x - glyphs[0].x;
+ extents->y_bearing = min_y - glyphs[0].y;
+ extents->width = max_x - min_x;
+ extents->height = max_y - min_y;
+ extents->x_advance = x_pos - glyphs[0].x;
+ extents->y_advance = y_pos - glyphs[0].y;
+}
/* Now we implement functions to access a default global image & metrics
* cache.
@@ -398,7 +351,8 @@ _cairo_glyph_cache_hash (void *cache, void *key)
^ ((unsigned long) in->scale.matrix[0][0])
^ ((unsigned long) in->scale.matrix[0][1])
^ ((unsigned long) in->scale.matrix[1][0])
- ^ ((unsigned long) in->scale.matrix[1][1])
+ ^ ((unsigned long) in->scale.matrix[1][1])
+ ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
^ in->index;
}
@@ -412,6 +366,7 @@ _cairo_glyph_cache_keys_equal (void *cache,
b = (cairo_glyph_cache_key_t *) k2;
return (a->index == b->index)
&& (a->unscaled == b->unscaled)
+ && (a->flags == b->flags)
&& (a->scale.matrix[0][0] == b->scale.matrix[0][0])
&& (a->scale.matrix[0][1] == b->scale.matrix[0][1])
&& (a->scale.matrix[1][0] == b->scale.matrix[1][0])