summaryrefslogtreecommitdiff
path: root/src/cairo_ft_font.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo_ft_font.c')
-rw-r--r--src/cairo_ft_font.c248
1 files changed, 171 insertions, 77 deletions
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
index c1c8d6ea0..5b0a7f641 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
};