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.c229
1 files changed, 225 insertions, 4 deletions
diff --git a/src/cairo-font.c b/src/cairo-font.c
index 157ebedbe..3044e8877 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -27,6 +27,15 @@
#include "cairoint.h"
+static cairo_glyph_cache_t *
+_cairo_glyph_cache_create (void);
+
+static void
+_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache);
+
+static void
+_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache);
+
cairo_font_t *
_cairo_font_create (const char *family,
cairo_font_slant_t slant,
@@ -50,6 +59,9 @@ _cairo_font_init (cairo_font_t *font,
cairo_matrix_set_identity (&font->matrix);
font->refcount = 1;
font->backend = backend;
+ font->glyph_cache = _cairo_glyph_cache_create ();
+ if (font->glyph_cache == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
}
@@ -72,6 +84,13 @@ _cairo_font_copy (cairo_font_t *font)
newfont->refcount = 1;
cairo_matrix_copy(&newfont->matrix, &font->matrix);
newfont->backend = font->backend;
+
+ if (newfont->glyph_cache)
+ _cairo_glyph_cache_destroy (newfont->glyph_cache);
+
+ newfont->glyph_cache = font->glyph_cache;
+ _cairo_glyph_cache_reference (font->glyph_cache);
+
return newfont;
}
@@ -105,18 +124,40 @@ _cairo_font_glyph_extents (cairo_font_t *font,
return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
}
+cairo_status_t
+_cairo_font_text_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_box_t *bbox)
+{
+ return font->backend->text_bbox (font, surface, x, y, utf8, bbox);
+}
+
+cairo_status_t
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox);
+}
cairo_status_t
_cairo_font_show_text (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
double x,
double y,
const unsigned char *utf8)
{
return font->backend->show_text(font, operator, source,
- surface, x, y, utf8);
+ surface, source_x, source_y, x, y, utf8);
}
cairo_status_t
@@ -124,11 +165,14 @@ _cairo_font_show_glyphs (cairo_font_t *font,
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)
{
return font->backend->show_glyphs(font, operator, source,
- surface, glyphs, num_glyphs);
+ surface, source_x, source_y,
+ glyphs, num_glyphs);
}
cairo_status_t
@@ -157,6 +201,183 @@ _cairo_font_font_extents (cairo_font_t *font,
return font->backend->font_extents(font, extents);
}
+static void
+_cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache->last) {
+ cairo_glyph_surface_node_t *remove = glyph_cache->last;
+
+ cairo_surface_destroy (remove->s.surface);
+ glyph_cache->last = remove->prev;
+ if (glyph_cache->last)
+ glyph_cache->last->next = NULL;
+
+ free (remove);
+ glyph_cache->n_nodes--;
+ }
+}
+
+static cairo_glyph_cache_t *
+_cairo_glyph_cache_create (void)
+{
+ cairo_glyph_cache_t *glyph_cache;
+
+ glyph_cache = malloc (sizeof (cairo_glyph_cache_t));
+ if (glyph_cache == NULL)
+ return NULL;
+
+ glyph_cache->n_nodes = 0;
+ glyph_cache->first = NULL;
+ glyph_cache->last = NULL;
+ glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT;
+ glyph_cache->ref_count = 1;
+
+ return glyph_cache;
+}
+
+static void
+_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache == NULL)
+ return;
+
+ glyph_cache->ref_count++;
+}
+
+static void
+_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache == NULL)
+ return;
+
+ glyph_cache->ref_count--;
+ if (glyph_cache->ref_count)
+ return;
+
+ while (glyph_cache->last)
+ _cairo_glyph_cache_pop_last (glyph_cache);
+
+ free (glyph_cache);
+}
+
+static void
+_cairo_glyph_surface_init (cairo_font_t *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_surface_t *glyph_surface)
+{
+ cairo_surface_t *image;
+
+ glyph_surface->surface = NULL;
+ glyph_surface->index = glyph->index;
+ glyph_surface->matrix[0][0] = font->matrix.m[0][0];
+ glyph_surface->matrix[0][1] = font->matrix.m[0][1];
+ glyph_surface->matrix[1][0] = font->matrix.m[1][0];
+ glyph_surface->matrix[1][1] = font->matrix.m[1][1];
+
+ image = font->backend->create_glyph (font, glyph, &glyph_surface->size);
+ if (image == NULL)
+ return;
+
+ if (surface->backend != image->backend) {
+ cairo_status_t status;
+
+ glyph_surface->surface =
+ _cairo_surface_create_similar_scratch (surface,
+ CAIRO_FORMAT_A8, 0,
+ glyph_surface->size.width,
+ glyph_surface->size.height);
+ if (glyph_surface->surface == NULL) {
+ glyph_surface->surface = image;
+ return;
+ }
+
+ status = _cairo_surface_set_image (glyph_surface->surface,
+ (cairo_image_surface_t *) image);
+ if (status) {
+ cairo_surface_destroy (glyph_surface->surface);
+ glyph_surface->surface = NULL;
+ }
+ cairo_surface_destroy (image);
+ } else
+ glyph_surface->surface = image;
+}
+
+cairo_surface_t *
+_cairo_font_lookup_glyph (cairo_font_t *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size)
+{
+ cairo_glyph_surface_t glyph_surface;
+ cairo_glyph_cache_t *cache = font->glyph_cache;
+ cairo_glyph_surface_node_t *node;
+
+ for (node = cache->first; node != NULL; node = node->next) {
+ cairo_glyph_surface_t *s = &node->s;
+
+ if ((s->surface == NULL || s->surface->backend == surface->backend) &&
+ s->index == glyph->index &&
+ s->matrix[0][0] == font->matrix.m[0][0] &&
+ s->matrix[0][1] == font->matrix.m[0][1] &&
+ s->matrix[1][0] == font->matrix.m[1][0] &&
+ s->matrix[1][1] == font->matrix.m[1][1]) {
+
+ /* move node first in cache */
+ if (node->prev) {
+ if (node->next == NULL) {
+ cache->last = node->prev;
+ node->prev->next = NULL;
+ } else {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ }
+
+ node->prev = NULL;
+ node->next = cache->first;
+ cache->first = node;
+ if (node->next)
+ node->next->prev = node;
+ else
+ cache->last = node;
+ }
+
+ cairo_surface_reference (s->surface);
+ *return_size = s->size;
+
+ return s->surface;
+ }
+ }
+
+ _cairo_glyph_surface_init (font, surface, glyph, &glyph_surface);
+
+ *return_size = glyph_surface.size;
+
+ if (cache->cache_size > 0) {
+ if (cache->n_nodes == cache->cache_size)
+ _cairo_glyph_cache_pop_last (cache);
+
+ node = malloc (sizeof (cairo_glyph_surface_node_t));
+ if (node) {
+ cairo_surface_reference (glyph_surface.surface);
+
+ /* insert node first in cache */
+ node->s = glyph_surface;
+ node->prev = NULL;
+ node->next = cache->first;
+ cache->first = node;
+ if (node->next)
+ node->next->prev = node;
+ else
+ cache->last = node;
+
+ cache->n_nodes++;
+ }
+ }
+
+ return glyph_surface.surface;
+}
+
/* public font interface follows */
void
@@ -171,6 +392,8 @@ cairo_font_destroy (cairo_font_t *font)
if (--(font->refcount) > 0)
return;
+ _cairo_glyph_cache_destroy (font->glyph_cache);
+
if (font->backend->destroy)
font->backend->destroy (font);
}
@@ -188,5 +411,3 @@ cairo_font_current_transform (cairo_font_t *font,
{
cairo_matrix_copy (matrix, &(font->matrix));
}
-
-