From 5f0e8de3e5721d55328b6b06922f7b29b49cc5cb Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Sat, 25 Jun 2005 13:51:22 +0000 Subject: [PATCH] Add mostly useless (other than perhaps 90-degree rotation) code for transforming bitmap glyphs. --- ChangeLog | 8 ++- src/cairo-ft-font.c | 136 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 91cfef6e7..550bc13e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-06-24 Owen Taylor + + * src/cairo-ft-font.c (_transform_glyph_bitmap): Add mostly + useless (other than perhaps 90-degree rotation) code for + transforming bitmap glyphs. + 2005-06-25 Carl Worth From: J. Ali Harlow" @@ -41,7 +47,7 @@ * src/cairo-ft-font.c (_render_glyph_bitmap): Handle rendering bitmap glyphslots as well as outline glyphslots. - + * src/cairo-ft-font.c (_ft_unscaled_font_set_scale): When setting the scale for a non-scalable font, use the nearest available size (FreeType won't set the glyph metrics otherwise.) diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 3aea02d77..7fbac1305 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -86,10 +86,11 @@ typedef struct { int id; /* We temporarily scale the unscaled font as neede */ - int have_scale; + cairo_bool_t have_scale; cairo_matrix_t current_scale; double x_scale; /* Extracted X scale factor */ double y_scale; /* Extracted Y scale factor */ + cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/ int lock; /* count of how many times this font has been locked */ @@ -474,6 +475,11 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); + unscaled->have_shape = (mat.xx != 0x10000 || + mat.yx != 0x00000 || + mat.xy != 0x00000 || + mat.yy != 0x10000); + FT_Set_Transform(unscaled->face, &mat, NULL); if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) { @@ -723,6 +729,125 @@ _render_glyph_bitmap (FT_Face face, return status; } +static cairo_status_t +_transform_glyph_bitmap (cairo_image_glyph_cache_entry_t *val) +{ + ft_font_transform_t sf; + cairo_matrix_t original_to_transformed; + cairo_matrix_t transformed_to_original; + cairo_image_surface_t *old_image; + cairo_surface_t *image; + double x[4], y[4]; + double origin_x, origin_y; + int i; + int x_min, y_min, x_max, y_max; + int width, height; + cairo_status_t status; + cairo_surface_pattern_t pattern; + + /* We want to compute a transform that takes the origin + * (val->size.x, val->size.y) to 0,0, then applies the "shape" + * portion of the font transform + */ + _compute_transform (&sf, &val->key.scale); + + cairo_matrix_init (&original_to_transformed, + sf.shape[0][0], sf.shape[0][1], + sf.shape[1][0], sf.shape[1][1], + 0, 0); + + cairo_matrix_translate (&original_to_transformed, + val->size.x, val->size.y); + + /* Find the bounding box of the original bitmap under that + * transform + */ + x[0] = 0; y[0] = 0; + x[1] = val->size.width; y[1] = 0; + x[2] = val->size.width; y[2] = val->size.height; + x[3] = 0; y[3] = val->size.height; + + for (i = 0; i < 4; i++) + cairo_matrix_transform_point (&original_to_transformed, + &x[i], &y[i]); + + x_min = floor (x[0]); y_min = floor (y[0]); + x_max = ceil (x[0]); y_max = ceil (y[0]); + + for (i = 1; i < 4; i++) { + if (x[i] < x_min) + x_min = floor (x[i]); + if (x[i] > x_max) + x_max = ceil (x[i]); + if (y[i] < y_min) + y_min = floor (y[i]); + if (y[i] > y_max) + y_max = ceil (y[i]); + } + + /* Adjust the transform so that the bounding box starts at 0,0 ... + * this gives our final transform from original bitmap to transformed + * bitmap. + */ + original_to_transformed.x0 -= x_min; + original_to_transformed.y0 -= y_min; + + /* Create the transformed bitmap + */ + width = x_max - x_min; + height = y_max - y_min; + + transformed_to_original = original_to_transformed; + status = cairo_matrix_invert (&transformed_to_original); + if (status) + return status; + + /* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */ + width = (width + 3) & ~3; + image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + if (!image) + return CAIRO_STATUS_NO_MEMORY; + + /* Initialize it to empty + */ + _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_TRANSPARENT, + 0, 0, + width, height); + + /* Draw the original bitmap transformed into the new bitmap + */ + _cairo_pattern_init_for_surface (&pattern, &val->image->base); + cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); + + _cairo_surface_composite (CAIRO_OPERATOR_OVER, + &pattern.base, NULL, image, + 0, 0, 0, 0, 0, 0, + width, + height); + + _cairo_pattern_fini (&pattern.base); + + /* Now update the cache entry for the new bitmap, recomputing + * the origin based on the final transform. + */ + origin_x = - val->size.x; + origin_y = - val->size.y; + cairo_matrix_transform_point (&original_to_transformed, + &origin_x, &origin_y); + + old_image = val->image; + val->image = (cairo_image_surface_t *)image; + cairo_surface_destroy (&old_image->base); + + val->size.width = width; + val->size.height = height; + val->size.x = - floor (origin_x + 0.5); + val->size.y = - floor (origin_y + 0.5); + + return status; +} + static cairo_status_t _cairo_ft_unscaled_font_create_glyph (void *abstract_font, cairo_image_glyph_cache_entry_t *val) @@ -775,7 +900,16 @@ _cairo_ft_unscaled_font_create_glyph (void *abstract_ else status = _render_glyph_bitmap (face, val); + if (unscaled->have_shape && + (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) + status = _transform_glyph_bitmap (val); + FAIL: + if (status && val->image) { + cairo_surface_destroy (&val->image->base); + val->image = NULL; + } + _ft_unscaled_font_unlock_face (unscaled); return status;