summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Reveman <davidr@novell.com>2004-05-24 02:28:05 +0000
committerDavid Reveman <davidr@novell.com>2004-05-24 02:28:05 +0000
commitcdad6472111848e5167f3d71c7b4e7c3e9b2ebb6 (patch)
tree75d87bc8254e70df3d879a5dd82596cbf3309193 /src
parent23026d5ab65201793ac19b459e3e7e05a090e435 (diff)
Added glyph caching
Diffstat (limited to 'src')
-rw-r--r--src/cairo-font.c221
-rw-r--r--src/cairo-ft-font.c248
-rw-r--r--src/cairo-gstate.c41
-rw-r--r--src/cairo-image-surface.c1
-rw-r--r--src/cairo-ps-surface.c1
-rw-r--r--src/cairo-surface.c28
-rw-r--r--src/cairo-xcb-surface.c3
-rw-r--r--src/cairo-xlib-surface.c3
-rw-r--r--src/cairo_font.c221
-rw-r--r--src/cairo_ft_font.c248
-rw-r--r--src/cairo_gl_surface.c18
-rw-r--r--src/cairo_gstate.c41
-rw-r--r--src/cairo_image_surface.c1
-rw-r--r--src/cairo_png_surface.c1
-rw-r--r--src/cairo_ps_surface.c1
-rw-r--r--src/cairo_surface.c28
-rw-r--r--src/cairo_xcb_surface.c3
-rw-r--r--src/cairo_xlib_surface.c3
-rw-r--r--src/cairoint.h84
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,