diff options
author | Behdad Esfahbod <behdad@behdad.org> | 2008-12-26 15:15:15 -0500 |
---|---|---|
committer | Behdad Esfahbod <behdad@behdad.org> | 2008-12-26 15:17:15 -0500 |
commit | e8e6ae1294f11addcbc8a95db471bb48a50b0b1a (patch) | |
tree | 8c54ae509e2e6877073f96475c26bd8469f71983 /src/cairo-font-face-twin.c | |
parent | e133cc14469e8ebb8311bf8db206147f6b07786d (diff) | |
download | cairo-e8e6ae1294f11addcbc8a95db471bb48a50b0b1a.tar.gz |
[twin] Cache pen and other properties on the scaled font
Diffstat (limited to 'src/cairo-font-face-twin.c')
-rw-r--r-- | src/cairo-font-face-twin.c | 170 |
1 files changed, 101 insertions, 69 deletions
diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c index 7c446c9a6..3b9f969c3 100644 --- a/src/cairo-font-face-twin.c +++ b/src/cairo-font-face-twin.c @@ -159,7 +159,7 @@ parse_field (twin_face_properties_t *props, } static void -props_parse (twin_face_properties_t *props, +face_props_parse (twin_face_properties_t *props, const char *s) { const char *start, *end; @@ -180,8 +180,8 @@ props_parse (twin_face_properties_t *props, } static cairo_status_t -twin_set_face_properties_from_toy (cairo_font_face_t *twin_face, - cairo_toy_font_face_t *toy_face) +twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face, + cairo_toy_font_face_t *toy_face) { cairo_status_t status; twin_face_properties_t *props; @@ -197,7 +197,7 @@ twin_set_face_properties_from_toy (cairo_font_face_t *twin_face, props->slant = toy_face->slant; props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ? TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD; - props_parse (props, toy_face->family); + face_props_parse (props, toy_face->family); status = cairo_font_face_set_user_data (twin_face, &twin_properties_key, @@ -218,10 +218,85 @@ FREE_PROPS: */ typedef struct _twin_scaled_properties { - cairo_bool_t snap; - double penx, peny; + twin_face_properties_t *face_props; + + cairo_bool_t snap; /* hint outlines */ + + double weight; /* unhinted pen width */ + double penx, peny; /* hinted pen width */ + + double stretch; /* stretch factor */ } twin_scaled_properties_t; +static void +twin_compute_pen (cairo_t *cr, + double width, + double *penx, double *peny) +{ + double x, y; + double scale, inv; + + x = 1; y = 0; + cairo_user_to_device_distance (cr, &x, &y); + scale = sqrt (x*x + y*y); + inv = 1 / scale; + *penx = round (width * scale) * inv; + if (*penx < inv) + *penx = inv; + + x = 0; y = 1; + cairo_user_to_device_distance (cr, &x, &y); + scale = sqrt (x*x + y*y); + inv = 1 / scale; + *peny = round (width * scale) * inv; + if (*peny < inv) + *peny = inv; +} + +static cairo_status_t +twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font, + cairo_t *cr) +{ + cairo_status_t status; + twin_scaled_properties_t *props; + + props = malloc (sizeof (twin_scaled_properties_t)); + if (unlikely (props == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + + props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &twin_properties_key); + + props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE; + + /* weight */ + props->weight = props->face_props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL); + + /* pen */ + if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT) + twin_compute_pen (cr, props->weight, &props->penx, &props->peny); + else + props->penx = props->peny = props->weight; + + /* stretch */ + props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL); + + + /* Save it */ + status = cairo_scaled_font_set_user_data (scaled_font, + &twin_properties_key, + props, free); + if (unlikely (status)) + goto FREE_PROPS; + + return CAIRO_STATUS_SUCCESS; + +FREE_PROPS: + free (props); + return status; +} + /* * User-font implementation @@ -238,7 +313,7 @@ twin_scaled_font_init (cairo_scaled_font_t *scaled_font, metrics->ascent = F (54); metrics->descent = 1 - metrics->ascent; - return CAIRO_STATUS_SUCCESS; + return twin_scaled_font_compute_properties (scaled_font, cr); } static double @@ -346,39 +421,6 @@ _twin_compute_snap (cairo_t *cr, } } -static void -_twin_compute_pen (cairo_t *cr, - cairo_scaled_font_t *scaled_font, - double width, - double *penx, double *peny) -{ - double x, y; - double scale, inv; - cairo_bool_t hint; - - hint = scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT; - if (!hint) { - *penx = *peny = width; - return; - } - - x = 1; y = 0; - cairo_user_to_device_distance (cr, &x, &y); - scale = sqrt (x*x + y*y); - inv = 1 / scale; - *penx = round (width * scale) * inv; - if (*penx < inv) - *penx = inv; - - x = 0; y = 1; - cairo_user_to_device_distance (cr, &x, &y); - scale = sqrt (x*x + y*y); - inv = 1 / scale; - *peny = round (width * scale) * inv; - if (*peny < inv) - *peny = inv; -} - #define SNAPX(p) _twin_snap (p, info.snap, info.snap_x, info.snapped_x, info.n_snap_x) #define SNAPY(p) _twin_snap (p, info.snap, info.snap_y, info.snapped_y, info.n_snap_y) @@ -389,45 +431,30 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, cairo_text_extents_t *metrics) { double x1, y1, x2, y2, x3, y3; - twin_face_properties_t *props; + twin_scaled_properties_t *props; twin_snap_info_t info; const int8_t *b; const int8_t *g; int8_t w; double gw; - double weight, stretch; - double penx, peny; - - cairo_set_tolerance (cr, 0.01); - cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); - cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); - /* Prepare face */ + props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key); - props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), - &twin_properties_key); - - /* weight */ - weight = props->weight * (4. / 64 / TWIN_WEIGHT_NORMAL); - - /* lock pen matrix */ - _twin_compute_pen (cr, scaled_font, weight, &penx, &peny); + /* Save glyph space, we need it when stroking */ cairo_save (cr); /* left margin + pen width, pen width */ - cairo_translate (cr, penx * 1.5, -peny * .5); + cairo_translate (cr, props->penx * 1.5, -props->peny * .5); - /* stretch */ - stretch = 1 + .1 * ((int) props->stretch - (int) TWIN_STRETCH_NORMAL); - cairo_scale (cr, stretch, 1); + cairo_scale (cr, props->stretch, 1); /* slant */ - if (props->slant != CAIRO_FONT_SLANT_NORMAL) { + if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) { cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0}; cairo_transform (cr, &shear); } - if (props->smallcaps && glyph >= 'a' && glyph <= 'z') { + if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') { glyph += 'A' - 'a'; cairo_scale (cr, 1, 28. / 42); } @@ -439,16 +466,16 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, gw = F(w); /* monospace */ - if (props->monospace) { + if (props->face_props->monospace) { double monow = F(24); - cairo_scale (cr, (monow+penx) / (gw+penx), 1); + cairo_scale (cr, (monow+props->penx) / (gw+props->penx), 1); gw = monow; } _twin_compute_snap (cr, scaled_font, &info, b); /* advance width */ - metrics->x_advance = gw * stretch + penx * 3; /* pen width + margin */ + metrics->x_advance = gw * props->stretch + props->penx * 3; /* pen width + margin */ /* glyph shape */ for (;;) { @@ -485,9 +512,12 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, cairo_close_path (cr); /* fall through */ case 'e': - cairo_restore (cr); - cairo_scale (cr, penx, peny); + cairo_restore (cr); /* restore glyph space */ + cairo_set_tolerance (cr, 0.01); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_width (cr, 1); + cairo_scale (cr, props->penx, props->peny); cairo_stroke (cr); break; case 'X': @@ -534,9 +564,11 @@ _cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t *toy_face, cairo_user_font_face_set_init_func (twin_font_face, twin_scaled_font_init); cairo_user_font_face_set_render_glyph_func (twin_font_face, twin_scaled_font_render_glyph); cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph); - status = twin_set_face_properties_from_toy (twin_font_face, toy_face); - if (status) + status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face); + if (status) { + cairo_font_face_destroy (twin_font_face); return status; + } *font_face = twin_font_face; |