diff options
author | David Reveman <davidr@novell.com> | 2004-05-24 02:28:05 +0000 |
---|---|---|
committer | David Reveman <davidr@novell.com> | 2004-05-24 02:28:05 +0000 |
commit | cdad6472111848e5167f3d71c7b4e7c3e9b2ebb6 (patch) | |
tree | 75d87bc8254e70df3d879a5dd82596cbf3309193 /src | |
parent | 23026d5ab65201793ac19b459e3e7e05a090e435 (diff) |
Added glyph caching
Diffstat (limited to 'src')
-rw-r--r-- | src/cairo-font.c | 221 | ||||
-rw-r--r-- | src/cairo-ft-font.c | 248 | ||||
-rw-r--r-- | src/cairo-gstate.c | 41 | ||||
-rw-r--r-- | src/cairo-image-surface.c | 1 | ||||
-rw-r--r-- | src/cairo-ps-surface.c | 1 | ||||
-rw-r--r-- | src/cairo-surface.c | 28 | ||||
-rw-r--r-- | src/cairo-xcb-surface.c | 3 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 3 | ||||
-rw-r--r-- | src/cairo_font.c | 221 | ||||
-rw-r--r-- | src/cairo_ft_font.c | 248 | ||||
-rw-r--r-- | src/cairo_gl_surface.c | 18 | ||||
-rw-r--r-- | src/cairo_gstate.c | 41 | ||||
-rw-r--r-- | src/cairo_image_surface.c | 1 | ||||
-rw-r--r-- | src/cairo_png_surface.c | 1 | ||||
-rw-r--r-- | src/cairo_ps_surface.c | 1 | ||||
-rw-r--r-- | src/cairo_surface.c | 28 | ||||
-rw-r--r-- | src/cairo_xcb_surface.c | 3 | ||||
-rw-r--r-- | src/cairo_xlib_surface.c | 3 | ||||
-rw-r--r-- | src/cairoint.h | 84 |
19 files changed, 973 insertions, 222 deletions
diff --git a/src/cairo-font.c b/src/cairo-font.c index 157ebedb..20ecc532 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -27,6 +27,12 @@ #include "cairoint.h" +static cairo_glyph_cache_t * +_cairo_glyph_cache_create (void); + +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 +56,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 +81,10 @@ _cairo_font_copy (cairo_font_t *font) newfont->refcount = 1; cairo_matrix_copy(&newfont->matrix, &font->matrix); newfont->backend = font->backend; + + newfont->glyph_cache = font->glyph_cache; + _cairo_glyph_cache_reference (font->glyph_cache); + return newfont; } @@ -105,18 +118,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 +159,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 +195,181 @@ _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) + 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 +384,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 +403,3 @@ cairo_font_current_transform (cairo_font_t *font, { cairo_matrix_copy (matrix, &(font->matrix)); } - - diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index c1c8d6ea..5b0a7f64 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -29,6 +29,7 @@ #include <ft2build.h> #include FT_FREETYPE_H #include FT_OUTLINE_H +#include FT_IMAGE_H typedef struct { cairo_font_t base; @@ -464,23 +465,99 @@ _cairo_ft_font_text_extents (void *abstract_font, } static cairo_status_t +_cairo_ft_font_glyph_bbox (void *abstract_font, + cairo_surface_t *surface, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) +{ + cairo_ft_font_t *font = abstract_font; + cairo_surface_t *mask = NULL; + cairo_glyph_size_t size; + + cairo_fixed_t x1, y1, x2, y2; + int i; + + bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16; + bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16; + + if (font == NULL + || surface == NULL + || glyphs == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < num_glyphs; i++) + { + mask = _cairo_font_lookup_glyph (&font->base, surface, + &glyphs[i], &size); + if (mask == NULL) + continue; + + x1 = _cairo_fixed_from_double (glyphs[i].x + size.x); + y1 = _cairo_fixed_from_double (glyphs[i].y - size.y); + x2 = x1 + _cairo_fixed_from_double (size.width); + y2 = y1 + _cairo_fixed_from_double (size.height); + + if (x1 < bbox->p1.x) + bbox->p1.x = x1; + + if (y1 < bbox->p1.y) + bbox->p1.y = y1; + + if (x2 > bbox->p2.x) + bbox->p2.x = x2; + + if (y2 > bbox->p2.y) + bbox->p2.y = y2; + + if (mask) + cairo_surface_destroy (mask); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ft_font_text_bbox (void *abstract_font, + cairo_surface_t *surface, + double x0, + double y0, + const unsigned char *utf8, + cairo_box_t *bbox) +{ + cairo_ft_font_t *font = abstract_font; + cairo_glyph_t *glyphs; + size_t num_glyphs; + + if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) + { + cairo_status_t res; + res = _cairo_ft_font_glyph_bbox (font, surface, + glyphs, num_glyphs, bbox); + free (glyphs); + return res; + } + else + return CAIRO_STATUS_NO_MEMORY; +} + +static cairo_status_t _cairo_ft_font_show_glyphs (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, - cairo_surface_t *surface, + cairo_surface_t *surface, + int source_x, + int source_y, const cairo_glyph_t *glyphs, int num_glyphs) { cairo_ft_font_t *font = abstract_font; cairo_status_t status; - int i; - cairo_ft_font_t *ft = NULL; - FT_GlyphSlot glyphslot; cairo_surface_t *mask = NULL; - cairo_point_double_t origin; + cairo_glyph_size_t size; double x, y; - int width, height, stride; + int i; if (font == NULL || source == NULL @@ -488,84 +565,27 @@ _cairo_ft_font_show_glyphs (void *abstract_font, || glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; - ft = (cairo_ft_font_t *)font; - glyphslot = ft->face->glyph; - _install_font_matrix (&font->base.matrix, ft->face); - for (i = 0; i < num_glyphs; i++) { - unsigned char *bitmap; - - FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT); - FT_Render_Glyph (glyphslot, ft_render_mode_normal); - - width = glyphslot->bitmap.width; - height = glyphslot->bitmap.rows; - stride = glyphslot->bitmap.pitch; - bitmap = glyphslot->bitmap.buffer; + mask = _cairo_font_lookup_glyph (&font->base, surface, + &glyphs[i], &size); + if (mask == NULL) + continue; x = glyphs[i].x; y = glyphs[i].y; - if (i == 0) { - origin.x = x; - origin.y = y; - } - - /* X gets upset with zero-sized images (such as whitespace) */ - if (width * height == 0) - continue; - - /* - * XXX - * reformat to match libic alignment requirements. - * This should be done before rendering the glyph, - * but that requires using FT_Outline_Get_Bitmap - * function - */ - if (stride & 3) - { - int nstride = (stride + 3) & ~3; - unsigned char *g, *b; - int h; - - bitmap = malloc (nstride * height); - if (!bitmap) - return CAIRO_STATUS_NO_MEMORY; - g = glyphslot->bitmap.buffer; - b = bitmap; - h = height; - while (h--) - { - memcpy (b, g, width); - b += nstride; - g += stride; - } - stride = nstride; - } - mask = cairo_surface_create_for_image (bitmap, - CAIRO_FORMAT_A8, - width, height, stride); - if (mask == NULL) - { - if (bitmap != glyphslot->bitmap.buffer) - free (bitmap); - return CAIRO_STATUS_NO_MEMORY; - } - - status = - _cairo_surface_composite (operator, source, mask, surface, - -origin.x + x + glyphslot->bitmap_left, - -origin.y + y - glyphslot->bitmap_top, - 0, 0, - x + glyphslot->bitmap_left, - y - glyphslot->bitmap_top, - (double) width, (double) height); + status = _cairo_surface_composite (operator, source, mask, surface, + source_x + x + size.x, + source_y + y - size.y, + 0, 0, + x + size.x, + y - size.y, + (double) size.width, + (double) size.height); cairo_surface_destroy (mask); - if (bitmap != glyphslot->bitmap.buffer) - free (bitmap); - + if (status) return status; } @@ -577,19 +597,22 @@ _cairo_ft_font_show_text (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, + int source_x, + int source_y, double x0, double y0, const unsigned char *utf8) { cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; - int num_glyphs; + size_t num_glyphs; if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) { cairo_status_t res; res = _cairo_ft_font_show_glyphs (font, operator, source, surface, + source_x, source_y, glyphs, num_glyphs); free (glyphs); return res; @@ -768,6 +791,74 @@ cairo_ft_font_create_for_ft_face (FT_Face face) return (cairo_font_t *) f; } +static cairo_surface_t * +_cairo_ft_font_create_glyph (void *abstract_font, + const cairo_glyph_t *glyph, + cairo_glyph_size_t *return_size) +{ + cairo_ft_font_t *font = abstract_font; + cairo_image_surface_t *image; + FT_GlyphSlot glyphslot; + unsigned int width, height, stride; + FT_Outline *outline; + FT_BBox cbox; + FT_Bitmap bitmap; + + glyphslot = font->face->glyph; + _install_font_matrix (&font->base.matrix, font->face); + + FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT); + + outline = &glyphslot->outline; + + FT_Outline_Get_CBox (outline, &cbox); + + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = (cbox.xMax + 63) & -64; + cbox.yMax = (cbox.yMax + 63) & -64; + + width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); + height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); + stride = (width + 3) & -4; + + bitmap.pixel_mode = ft_pixel_mode_grays; + bitmap.num_grays = 256; + bitmap.width = width; + bitmap.rows = height; + bitmap.pitch = stride; + + if (width * height == 0) + return NULL; + + bitmap.buffer = malloc (stride * height); + if (bitmap.buffer == NULL) + return NULL; + + memset (bitmap.buffer, 0x0, stride * height); + + FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); + FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap); + + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data ((char *) bitmap.buffer, + CAIRO_FORMAT_A8, + width, height, stride); + if (image == NULL) { + free (bitmap.buffer); + return NULL; + } + + _cairo_image_surface_assume_ownership_of_data (image); + + return_size->width = (unsigned short) width; + return_size->height = (unsigned short) height; + return_size->x = (short) (cbox.xMin >> 6); + return_size->y = (short) (cbox.yMax >> 6); + + return &image->base; +} + const struct cairo_font_backend cairo_ft_font_backend = { _cairo_ft_font_create, _cairo_ft_font_copy, @@ -775,8 +866,11 @@ const struct cairo_font_backend cairo_ft_font_backend = { _cairo_ft_font_font_extents, _cairo_ft_font_text_extents, _cairo_ft_font_glyph_extents, + _cairo_ft_font_text_bbox, + _cairo_ft_font_glyph_bbox, _cairo_ft_font_show_text, _cairo_ft_font_show_glyphs, _cairo_ft_font_text_path, _cairo_ft_font_glyph_path, + _cairo_ft_font_create_glyph }; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 7599d44c..741b3370 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -2089,8 +2089,7 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, double x, y; cairo_matrix_t saved_font_matrix; cairo_pattern_t pattern; - cairo_text_extents_t text_extents; - cairo_box_t extents; + cairo_box_t bbox; status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { @@ -2107,17 +2106,15 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_gstate_text_extents (gstate, utf8, &text_extents); + status = _cairo_font_text_bbox (gstate->font, gstate->surface, + x, y, utf8, &bbox); if (status) return status; - extents.p1.x = _cairo_fixed_from_double (x); - extents.p1.y = _cairo_fixed_from_double (y); - extents.p2.x = _cairo_fixed_from_double (x + text_extents.width); - extents.p2.y = _cairo_fixed_from_double (y + text_extents.height); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); if (status) return status; + if (gstate->clip.surface) { cairo_surface_t *intermediate; @@ -2133,7 +2130,9 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, status = _cairo_font_show_text (gstate->font, CAIRO_OPERATOR_ADD, pattern.source, - intermediate, + intermediate, + gstate->clip.x - pattern.source_offset.x, + gstate->clip.y - pattern.source_offset.y, x - gstate->clip.x, y - gstate->clip.y, utf8); @@ -2172,7 +2171,10 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, { status = _cairo_font_show_text (gstate->font, gstate->operator, pattern.source, - gstate->surface, x, y, utf8); + gstate->surface, + -pattern.source_offset.x, + -pattern.source_offset.y, + x, y, utf8); } cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); @@ -2192,8 +2194,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, int i; cairo_glyph_t *transformed_glyphs = NULL; cairo_pattern_t pattern; - cairo_text_extents_t text_extents; - cairo_box_t extents; + cairo_box_t bbox; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2211,18 +2212,12 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs, - &text_extents); + status = _cairo_font_glyph_bbox (gstate->font, gstate->surface, + transformed_glyphs, num_glyphs, &bbox); if (status) return status; - extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x); - extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y); - extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x + - text_extents.width); - extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y + - text_extents.height); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); if (status) return status; @@ -2249,6 +2244,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, status = _cairo_font_show_glyphs (gstate->font, CAIRO_OPERATOR_ADD, pattern.source, intermediate, + gstate->clip.x - pattern.source_offset.x, + gstate->clip.y - pattern.source_offset.y, transformed_glyphs, num_glyphs); if (status) @@ -2287,6 +2284,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, status = _cairo_font_show_glyphs (gstate->font, gstate->operator, pattern.source, gstate->surface, + -pattern.source_offset.x, + -pattern.source_offset.y, transformed_glyphs, num_glyphs); } diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 2b52e5b2..76a3dbaa 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -179,6 +179,7 @@ cairo_image_surface_create_for_data (char *data, static cairo_surface_t * _cairo_image_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 98d34e44..b7d911ac 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -139,6 +139,7 @@ cairo_ps_surface_create (FILE *file, static cairo_surface_t * _cairo_ps_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 75c7fdd3..c18c1193 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -54,6 +54,26 @@ cairo_surface_create_for_image (char *data, slim_hidden_def(cairo_surface_create_for_image); cairo_surface_t * +_cairo_surface_create_similar_scratch (cairo_surface_t *other, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_surface_t *surface; + + if (other == NULL) + return NULL; + + surface = other->backend->create_similar (other, format, drawable, + width, height); + if (surface == NULL) + surface = cairo_image_surface_create (format, width, height); + + return surface; +} + +cairo_surface_t * cairo_surface_create_similar (cairo_surface_t *other, cairo_format_t format, int width, @@ -79,12 +99,10 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_color_t *color) { cairo_status_t status; - cairo_surface_t *surface = NULL; - - surface = other->backend->create_similar (other, format, width, height); - if (surface == NULL) - surface = cairo_image_surface_create (format, width, height); + cairo_surface_t *surface; + surface = _cairo_surface_create_similar_scratch (other, format, 1, + width, height); status = _cairo_surface_fill_rectangle (surface, CAIRO_OPERATOR_SRC, color, 0, 0, width, height); diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index ea1f72e1..61218f3c 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -231,6 +231,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format) static cairo_surface_t * _cairo_xcb_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { @@ -508,7 +509,7 @@ _cairo_xcb_surface_clone_similar (cairo_surface_t *src, src_image = _cairo_surface_get_image (src); clone = (cairo_xcb_surface_t *) - _cairo_xcb_surface_create_similar (template, format, + _cairo_xcb_surface_create_similar (template, format, 0, src_image->width, src_image->height); if (clone == NULL) diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index b54284aa..4f442594 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -111,6 +111,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format) static cairo_surface_t * _cairo_xlib_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { @@ -382,7 +383,7 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src, src_image = _cairo_surface_get_image (src); clone = (cairo_xlib_surface_t *) - _cairo_xlib_surface_create_similar (template, format, + _cairo_xlib_surface_create_similar (template, format, 0, src_image->width, src_image->height); if (clone == NULL) diff --git a/src/cairo_font.c b/src/cairo_font.c index 157ebedb..20ecc532 100644 --- a/src/cairo_font.c +++ b/src/cairo_font.c @@ -27,6 +27,12 @@ #include "cairoint.h" +static cairo_glyph_cache_t * +_cairo_glyph_cache_create (void); + +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 +56,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 +81,10 @@ _cairo_font_copy (cairo_font_t *font) newfont->refcount = 1; cairo_matrix_copy(&newfont->matrix, &font->matrix); newfont->backend = font->backend; + + newfont->glyph_cache = font->glyph_cache; + _cairo_glyph_cache_reference (font->glyph_cache); + return newfont; } @@ -105,18 +118,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 +159,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 +195,181 @@ _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) + 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 +384,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 +403,3 @@ cairo_font_current_transform (cairo_font_t *font, { cairo_matrix_copy (matrix, &(font->matrix)); } - - diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c index c1c8d6ea..5b0a7f64 100644 --- a/src/cairo_ft_font.c +++ b/src/cairo_ft_font.c @@ -29,6 +29,7 @@ #include <ft2build.h> #include FT_FREETYPE_H #include FT_OUTLINE_H +#include FT_IMAGE_H typedef struct { cairo_font_t base; @@ -464,23 +465,99 @@ _cairo_ft_font_text_extents (void *abstract_font, } static cairo_status_t +_cairo_ft_font_glyph_bbox (void *abstract_font, + cairo_surface_t *surface, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) +{ + cairo_ft_font_t *font = abstract_font; + cairo_surface_t *mask = NULL; + cairo_glyph_size_t size; + + cairo_fixed_t x1, y1, x2, y2; + int i; + + bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16; + bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16; + + if (font == NULL + || surface == NULL + || glyphs == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < num_glyphs; i++) + { + mask = _cairo_font_lookup_glyph (&font->base, surface, + &glyphs[i], &size); + if (mask == NULL) + continue; + + x1 = _cairo_fixed_from_double (glyphs[i].x + size.x); + y1 = _cairo_fixed_from_double (glyphs[i].y - size.y); + x2 = x1 + _cairo_fixed_from_double (size.width); + y2 = y1 + _cairo_fixed_from_double (size.height); + + if (x1 < bbox->p1.x) + bbox->p1.x = x1; + + if (y1 < bbox->p1.y) + bbox->p1.y = y1; + + if (x2 > bbox->p2.x) + bbox->p2.x = x2; + + if (y2 > bbox->p2.y) + bbox->p2.y = y2; + + if (mask) + cairo_surface_destroy (mask); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ft_font_text_bbox (void *abstract_font, + cairo_surface_t *surface, + double x0, + double y0, + const unsigned char *utf8, + cairo_box_t *bbox) +{ + cairo_ft_font_t *font = abstract_font; + cairo_glyph_t *glyphs; + size_t num_glyphs; + + if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) + { + cairo_status_t res; + res = _cairo_ft_font_glyph_bbox (font, surface, + glyphs, num_glyphs, bbox); + free (glyphs); + return res; + } + else + return CAIRO_STATUS_NO_MEMORY; +} + +static cairo_status_t _cairo_ft_font_show_glyphs (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, - cairo_surface_t *surface, + cairo_surface_t *surface, + int source_x, + int source_y, const cairo_glyph_t *glyphs, int num_glyphs) { cairo_ft_font_t *font = abstract_font; cairo_status_t status; - int i; - cairo_ft_font_t *ft = NULL; - FT_GlyphSlot glyphslot; cairo_surface_t *mask = NULL; - cairo_point_double_t origin; + cairo_glyph_size_t size; double x, y; - int width, height, stride; + int i; if (font == NULL || source == NULL @@ -488,84 +565,27 @@ _cairo_ft_font_show_glyphs (void *abstract_font, || glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; - ft = (cairo_ft_font_t *)font; - glyphslot = ft->face->glyph; - _install_font_matrix (&font->base.matrix, ft->face); - for (i = 0; i < num_glyphs; i++) { - unsigned char *bitmap; - - FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT); - FT_Render_Glyph (glyphslot, ft_render_mode_normal); - - width = glyphslot->bitmap.width; - height = glyphslot->bitmap.rows; - stride = glyphslot->bitmap.pitch; - bitmap = glyphslot->bitmap.buffer; + mask = _cairo_font_lookup_glyph (&font->base, surface, + &glyphs[i], &size); + if (mask == NULL) + continue; x = glyphs[i].x; y = glyphs[i].y; - if (i == 0) { - origin.x = x; - origin.y = y; - } - - /* X gets upset with zero-sized images (such as whitespace) */ - if (width * height == 0) - continue; - - /* - * XXX - * reformat to match libic alignment requirements. - * This should be done before rendering the glyph, - * but that requires using FT_Outline_Get_Bitmap - * function - */ - if (stride & 3) - { - int nstride = (stride + 3) & ~3; - unsigned char *g, *b; - int h; - - bitmap = malloc (nstride * height); - if (!bitmap) - return CAIRO_STATUS_NO_MEMORY; - g = glyphslot->bitmap.buffer; - b = bitmap; - h = height; - while (h--) - { - memcpy (b, g, width); - b += nstride; - g += stride; - } - stride = nstride; - } - mask = cairo_surface_create_for_image (bitmap, - CAIRO_FORMAT_A8, - width, height, stride); - if (mask == NULL) - { - if (bitmap != glyphslot->bitmap.buffer) - free (bitmap); - return CAIRO_STATUS_NO_MEMORY; - } - - status = - _cairo_surface_composite (operator, source, mask, surface, - -origin.x + x + glyphslot->bitmap_left, - -origin.y + y - glyphslot->bitmap_top, - 0, 0, - x + glyphslot->bitmap_left, - y - glyphslot->bitmap_top, - (double) width, (double) height); + status = _cairo_surface_composite (operator, source, mask, surface, + source_x + x + size.x, + source_y + y - size.y, + 0, 0, + x + size.x, + y - size.y, + (double) size.width, + (double) size.height); cairo_surface_destroy (mask); - if (bitmap != glyphslot->bitmap.buffer) - free (bitmap); - + if (status) return status; } @@ -577,19 +597,22 @@ _cairo_ft_font_show_text (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, + int source_x, + int source_y, double x0, double y0, const unsigned char *utf8) { cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; - int num_glyphs; + size_t num_glyphs; if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) { cairo_status_t res; res = _cairo_ft_font_show_glyphs (font, operator, source, surface, + source_x, source_y, glyphs, num_glyphs); free (glyphs); return res; @@ -768,6 +791,74 @@ cairo_ft_font_create_for_ft_face (FT_Face face) return (cairo_font_t *) f; } +static cairo_surface_t * +_cairo_ft_font_create_glyph (void *abstract_font, + const cairo_glyph_t *glyph, + cairo_glyph_size_t *return_size) +{ + cairo_ft_font_t *font = abstract_font; + cairo_image_surface_t *image; + FT_GlyphSlot glyphslot; + unsigned int width, height, stride; + FT_Outline *outline; + FT_BBox cbox; + FT_Bitmap bitmap; + + glyphslot = font->face->glyph; + _install_font_matrix (&font->base.matrix, font->face); + + FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT); + + outline = &glyphslot->outline; + + FT_Outline_Get_CBox (outline, &cbox); + + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = (cbox.xMax + 63) & -64; + cbox.yMax = (cbox.yMax + 63) & -64; + + width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); + height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); + stride = (width + 3) & -4; + + bitmap.pixel_mode = ft_pixel_mode_grays; + bitmap.num_grays = 256; + bitmap.width = width; + bitmap.rows = height; + bitmap.pitch = stride; + + if (width * height == 0) + return NULL; + + bitmap.buffer = malloc (stride * height); + if (bitmap.buffer == NULL) + return NULL; + + memset (bitmap.buffer, 0x0, stride * height); + + FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); + FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap); + + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data ((char *) bitmap.buffer, + CAIRO_FORMAT_A8, + width, height, stride); + if (image == NULL) { + free (bitmap.buffer); + return NULL; + } + + _cairo_image_surface_assume_ownership_of_data (image); + + return_size->width = (unsigned short) width; + return_size->height = (unsigned short) height; + return_size->x = (short) (cbox.xMin >> 6); + return_size->y = (short) (cbox.yMax >> 6); + + return &image->base; +} + const struct cairo_font_backend cairo_ft_font_backend = { _cairo_ft_font_create, _cairo_ft_font_copy, @@ -775,8 +866,11 @@ const struct cairo_font_backend cairo_ft_font_backend = { _cairo_ft_font_font_extents, _cairo_ft_font_text_extents, _cairo_ft_font_glyph_extents, + _cairo_ft_font_text_bbox, + _cairo_ft_font_glyph_bbox, _cairo_ft_font_show_text, _cairo_ft_font_show_glyphs, _cairo_ft_font_text_path, _cairo_ft_font_glyph_path, + _cairo_ft_font_create_glyph }; diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c index 3a60302b..6480f110 100644 --- a/src/cairo_gl_surface.c +++ b/src/cairo_gl_surface.c @@ -321,15 +321,27 @@ _glitz_format (cairo_format_t format) static cairo_surface_t * _cairo_gl_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { cairo_gl_surface_t *src = abstract_src; glitz_surface_t *surface; cairo_surface_t *crsurface; + glitz_format_t *glitz_format; + unsigned long option_mask; + + option_mask = GLITZ_FORMAT_OPTION_OFFSCREEN_MASK; + if (!drawable) + option_mask |= GLITZ_FORMAT_OPTION_READONLY_MASK; + + glitz_format = + glitz_surface_find_similar_standard_format (src->surface, option_mask, + _glitz_format (format)); + if (glitz_format == NULL) + return NULL; - surface = glitz_surface_create_similar (src->surface, - _glitz_format (format), + surface = glitz_surface_create_similar (src->surface, glitz_format, width, height); if (surface == NULL) return NULL; @@ -352,7 +364,7 @@ _cairo_gl_surface_clone_similar (cairo_surface_t *src, src_image = _cairo_surface_get_image (src); clone = (cairo_gl_surface_t *) - _cairo_gl_surface_create_similar (template, format, + _cairo_gl_surface_create_similar (template, format, 0, src_image->width, src_image->height); if (clone == NULL) diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index 7599d44c..741b3370 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -2089,8 +2089,7 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, double x, y; cairo_matrix_t saved_font_matrix; cairo_pattern_t pattern; - cairo_text_extents_t text_extents; - cairo_box_t extents; + cairo_box_t bbox; status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { @@ -2107,17 +2106,15 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_gstate_text_extents (gstate, utf8, &text_extents); + status = _cairo_font_text_bbox (gstate->font, gstate->surface, + x, y, utf8, &bbox); if (status) return status; - extents.p1.x = _cairo_fixed_from_double (x); - extents.p1.y = _cairo_fixed_from_double (y); - extents.p2.x = _cairo_fixed_from_double (x + text_extents.width); - extents.p2.y = _cairo_fixed_from_double (y + text_extents.height); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); if (status) return status; + if (gstate->clip.surface) { cairo_surface_t *intermediate; @@ -2133,7 +2130,9 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, status = _cairo_font_show_text (gstate->font, CAIRO_OPERATOR_ADD, pattern.source, - intermediate, + intermediate, + gstate->clip.x - pattern.source_offset.x, + gstate->clip.y - pattern.source_offset.y, x - gstate->clip.x, y - gstate->clip.y, utf8); @@ -2172,7 +2171,10 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, { status = _cairo_font_show_text (gstate->font, gstate->operator, pattern.source, - gstate->surface, x, y, utf8); + gstate->surface, + -pattern.source_offset.x, + -pattern.source_offset.y, + x, y, utf8); } cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); @@ -2192,8 +2194,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, int i; cairo_glyph_t *transformed_glyphs = NULL; cairo_pattern_t pattern; - cairo_text_extents_t text_extents; - cairo_box_t extents; + cairo_box_t bbox; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2211,18 +2212,12 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs, - &text_extents); + status = _cairo_font_glyph_bbox (gstate->font, gstate->surface, + transformed_glyphs, num_glyphs, &bbox); if (status) return status; - extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x); - extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y); - extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x + - text_extents.width); - extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y + - text_extents.height); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); if (status) return status; @@ -2249,6 +2244,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, status = _cairo_font_show_glyphs (gstate->font, CAIRO_OPERATOR_ADD, pattern.source, intermediate, + gstate->clip.x - pattern.source_offset.x, + gstate->clip.y - pattern.source_offset.y, transformed_glyphs, num_glyphs); if (status) @@ -2287,6 +2284,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, status = _cairo_font_show_glyphs (gstate->font, gstate->operator, pattern.source, gstate->surface, + -pattern.source_offset.x, + -pattern.source_offset.y, transformed_glyphs, num_glyphs); } diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c index 2b52e5b2..76a3dbaa 100644 --- a/src/cairo_image_surface.c +++ b/src/cairo_image_surface.c @@ -179,6 +179,7 @@ cairo_image_surface_create_for_data (char *data, static cairo_surface_t * _cairo_image_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c index b012514b..ae7938ee 100644 --- a/src/cairo_png_surface.c +++ b/src/cairo_png_surface.c @@ -82,6 +82,7 @@ cairo_png_surface_create (FILE *file, static cairo_surface_t * _cairo_png_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c index 98d34e44..b7d911ac 100644 --- a/src/cairo_ps_surface.c +++ b/src/cairo_ps_surface.c @@ -139,6 +139,7 @@ cairo_ps_surface_create (FILE *file, static cairo_surface_t * _cairo_ps_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { diff --git a/src/cairo_surface.c b/src/cairo_surface.c index 75c7fdd3..c18c1193 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -54,6 +54,26 @@ cairo_surface_create_for_image (char *data, slim_hidden_def(cairo_surface_create_for_image); cairo_surface_t * +_cairo_surface_create_similar_scratch (cairo_surface_t *other, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_surface_t *surface; + + if (other == NULL) + return NULL; + + surface = other->backend->create_similar (other, format, drawable, + width, height); + if (surface == NULL) + surface = cairo_image_surface_create (format, width, height); + + return surface; +} + +cairo_surface_t * cairo_surface_create_similar (cairo_surface_t *other, cairo_format_t format, int width, @@ -79,12 +99,10 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_color_t *color) { cairo_status_t status; - cairo_surface_t *surface = NULL; - - surface = other->backend->create_similar (other, format, width, height); - if (surface == NULL) - surface = cairo_image_surface_create (format, width, height); + cairo_surface_t *surface; + surface = _cairo_surface_create_similar_scratch (other, format, 1, + width, height); status = _cairo_surface_fill_rectangle (surface, CAIRO_OPERATOR_SRC, color, 0, 0, width, height); diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c index ea1f72e1..61218f3c 100644 --- a/src/cairo_xcb_surface.c +++ b/src/cairo_xcb_surface.c @@ -231,6 +231,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format) static cairo_surface_t * _cairo_xcb_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { @@ -508,7 +509,7 @@ _cairo_xcb_surface_clone_similar (cairo_surface_t *src, src_image = _cairo_surface_get_image (src); clone = (cairo_xcb_surface_t *) - _cairo_xcb_surface_create_similar (template, format, + _cairo_xcb_surface_create_similar (template, format, 0, src_image->width, src_image->height); if (clone == NULL) diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index b54284aa..4f442594 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -111,6 +111,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format) static cairo_surface_t * _cairo_xlib_surface_create_similar (void *abstract_src, cairo_format_t format, + int drawable, int width, int height) { @@ -382,7 +383,7 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src, src_image = _cairo_surface_get_image (src); clone = (cairo_xlib_surface_t *) - _cairo_xlib_surface_create_similar (template, format, + _cairo_xlib_surface_create_similar (template, format, 0, src_image->width, src_image->height); if (clone == NULL) diff --git a/src/cairoint.h b/src/cairoint.h index 8ace018e..25688945 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -157,7 +157,7 @@ typedef struct cairo_trapezoid { typedef struct cairo_rectangle_int { short x, y; unsigned short width, height; -} cairo_rectangle_t; +} cairo_rectangle_t, cairo_glyph_size_t; /* Sure wish C had a real enum type so that this would be distinct from cairo_status_t. Oh well, without that, I'll use this bogus 1000 @@ -274,11 +274,26 @@ typedef struct cairo_font_backend { cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents); + + cairo_status_t (*text_bbox) (void *font, + cairo_surface_t *surface, + double x, + double y, + const unsigned char *utf8, + cairo_box_t *bbox); + + cairo_status_t (*glyph_bbox) (void *font, + cairo_surface_t *surface, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox); cairo_status_t (*show_text) (void *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); @@ -287,6 +302,8 @@ typedef struct cairo_font_backend { cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, + int source_x, + int source_y, const cairo_glyph_t *glyphs, int num_glyphs); @@ -300,6 +317,9 @@ typedef struct cairo_font_backend { cairo_glyph_t *glyphs, int num_glyphs, cairo_path_t *path); + cairo_surface_t *(*create_glyph) (void *font, + const cairo_glyph_t *glyph, + cairo_glyph_size_t *return_size); } cairo_font_backend_t; /* concrete font backends */ @@ -311,6 +331,7 @@ typedef struct cairo_surface_backend { cairo_surface_t * (*create_similar) (void *surface, cairo_format_t format, + int drawable, int width, int height); @@ -527,9 +548,38 @@ typedef struct cairo_traps { /* XXX: Platform-specific. Other platforms may want a different default */ #define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend +#define CAIRO_FONT_CACHE_SIZE_DEFAULT 256 + +typedef struct { + unsigned long index; + double matrix[2][2]; + + unsigned int time; + + cairo_surface_t *surface; + cairo_glyph_size_t size; +} cairo_glyph_surface_t; + +typedef struct cairo_glyph_surface_node { + struct cairo_glyph_surface_node *next; + struct cairo_glyph_surface_node *prev; + + cairo_glyph_surface_t s; +} cairo_glyph_surface_node_t; + +typedef struct { + cairo_glyph_surface_node_t *first; + cairo_glyph_surface_node_t *last; + unsigned int n_nodes; + + unsigned int ref_count; + unsigned int cache_size; +} cairo_glyph_cache_t; + struct cairo_font { int refcount; cairo_matrix_t matrix; + cairo_glyph_cache_t *glyph_cache; const struct cairo_font_backend *backend; }; @@ -977,10 +1027,27 @@ _cairo_font_glyph_extents (cairo_font_t *font, cairo_text_extents_t *extents); extern cairo_status_t __internal_linkage +_cairo_font_text_bbox (cairo_font_t *font, + cairo_surface_t *surface, + double x, + double y, + const unsigned char *utf8, + cairo_box_t *bbox); + +extern cairo_status_t __internal_linkage +_cairo_font_glyph_bbox (cairo_font_t *font, + cairo_surface_t *surface, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox); + +extern cairo_status_t __internal_linkage _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); @@ -991,6 +1058,8 @@ _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); @@ -1008,6 +1077,12 @@ _cairo_font_glyph_path (cairo_font_t *font, int num_glyphs, cairo_path_t *path); +extern cairo_surface_t *__internal_linkage +_cairo_font_lookup_glyph (cairo_font_t *font, + cairo_surface_t *surface, + const cairo_glyph_t *glyph, + cairo_glyph_size_t *return_size); + /* cairo_hull.c */ extern cairo_status_t _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices); @@ -1087,6 +1162,13 @@ _cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_t /* cairo_surface.c */ extern cairo_surface_t * __internal_linkage +_cairo_surface_create_similar_scratch (cairo_surface_t *other, + cairo_format_t format, + int drawable, + int width, + int height); + +extern cairo_surface_t * __internal_linkage _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_format_t format, int width, |