diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index d48cec7..693ccf0 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -123,6 +123,7 @@ struct _cairo_ft_font_face { cairo_font_face_t base; cairo_ft_unscaled_font_t *unscaled; cairo_ft_options_t ft_options; + cairo_font_options_t font_options; cairo_ft_font_face_t *next; }; @@ -1217,6 +1218,7 @@ typedef struct _cairo_ft_scaled_font { cairo_scaled_font_t base; cairo_ft_unscaled_font_t *unscaled; cairo_ft_options_t ft_options; + cairo_font_options_t font_options; } cairo_ft_scaled_font_t; const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend; @@ -1224,21 +1226,50 @@ const cairo_scaled_font_backend_t cairo_ /* The load flags passed to FT_Load_Glyph control aspects like hinting and * antialiasing. Here we compute them from the fields of a FcPattern. */ -static cairo_ft_options_t -_get_pattern_ft_options (FcPattern *pattern) +static void +_get_pattern_ft_options (FcPattern *pattern, + cairo_ft_options_t *ft_options, + cairo_font_options_t *font_options) { - FcBool antialias, vertical_layout, hinting, autohint, bitmap; + FcBool antialias, vertical_layout, hinting, autohint, bitmap, embolden; FcBool transform; FcMatrix *font_matrix; - cairo_ft_options_t ft_options; int rgba; #ifdef FC_HINT_STYLE int hintstyle; -#endif - int target_flags = 0; +#endif + int load_target = FT_LOAD_TARGET_NORMAL; - ft_options.load_flags = 0; - ft_options.extra_flags = 0; + ft_options->load_flags = FT_LOAD_DEFAULT; + ft_options->extra_flags = 0; + + _cairo_font_options_init_default (font_options); + + /* force autohinting if requested */ + if (FcPatternGetBool (pattern, + FC_AUTOHINT, 0, &autohint) != FcResultMatch) + autohint = FcFalse; + + if (autohint) + ft_options->load_flags |= FT_LOAD_FORCE_AUTOHINT; + + if (FcPatternGetBool (pattern, + FC_VERTICAL_LAYOUT, 0, &vertical_layout) != FcResultMatch) + vertical_layout = FcFalse; + + if (vertical_layout) + ft_options->load_flags |= FT_LOAD_VERTICAL_LAYOUT; + +#ifndef FC_EMBOLDEN +#define FC_EMBOLDEN "embolden" +#endif + + if (FcPatternGetBool (pattern, + FC_EMBOLDEN, 0, &embolden) != FcResultMatch) + embolden = FcFalse; + + if (embolden) + ft_options->extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN; #ifndef FC_EMBEDDED_BITMAP #define FC_EMBEDDED_BITMAP "embeddedbitmap" @@ -1262,42 +1293,23 @@ #endif antialias = FcTrue; if ((!bitmap && antialias) || transform) - ft_options.load_flags |= FT_LOAD_NO_BITMAP; - else if (!antialias) - ft_options.load_flags |= FT_LOAD_MONOCHROME; + ft_options->load_flags |= FT_LOAD_NO_BITMAP; + else if (!antialias) { + /* + * for monochrome rendering, we force hinting and rendering, + * ignoring the pattern values for hint style. + */ + ft_options->load_flags = FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO; + font_options->antialias = CAIRO_ANTIALIAS_NONE; + + return; + } /* disable hinting if requested */ if (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting) != FcResultMatch) hinting = FcTrue; -#ifdef FC_HINT_STYLE - if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) - hintstyle = FC_HINT_FULL; - - if (!hinting || hintstyle == FC_HINT_NONE) - ft_options.load_flags |= FT_LOAD_NO_HINTING; - - if (antialias) { - switch (hintstyle) { - case FC_HINT_SLIGHT: - case FC_HINT_MEDIUM: - target_flags = FT_LOAD_TARGET_LIGHT; - break; - default: - target_flags = FT_LOAD_TARGET_NORMAL; - break; - } - } else { -#ifdef FT_LOAD_TARGET_MONO - target_flags = FT_LOAD_TARGET_MONO; -#endif - } -#else /* !FC_HINT_STYLE */ - if (!hinting) - target_flags = FT_LOAD_NO_HINTING; -#endif /* FC_FHINT_STYLE */ - if (FcPatternGetInteger (pattern, FC_RGBA, 0, &rgba) != FcResultMatch) rgba = FC_RGBA_UNKNOWN; @@ -1308,71 +1320,86 @@ #endif /* FC_FHINT_STYLE */ default: break; case FC_RGBA_RGB: + font_options->subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + load_target = FT_LOAD_TARGET_LCD; + break; case FC_RGBA_BGR: - target_flags = FT_LOAD_TARGET_LCD; + font_options->subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + load_target = FT_LOAD_TARGET_LCD; break; case FC_RGBA_VRGB: + font_options->subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + load_target = FT_LOAD_TARGET_LCD_V; + break; case FC_RGBA_VBGR: - target_flags = FT_LOAD_TARGET_LCD_V; + font_options->subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + load_target = FT_LOAD_TARGET_LCD_V; break; } - ft_options.load_flags |= target_flags; - - /* force autohinting if requested */ - if (FcPatternGetBool (pattern, - FC_AUTOHINT, 0, &autohint) != FcResultMatch) - autohint = FcFalse; - - if (autohint) - ft_options.load_flags |= FT_LOAD_FORCE_AUTOHINT; - - if (FcPatternGetBool (pattern, - FC_VERTICAL_LAYOUT, 0, &vertical_layout) != FcResultMatch) - vertical_layout = FcFalse; - - if (vertical_layout) - ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT; - -#ifdef FC_EMBOLDEN - { - FcBool embolden; +#ifdef FC_HINT_STYLE + if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) + hintstyle = FC_HINT_FULL; - if (FcPatternGetBool (pattern, - FC_EMBOLDEN, 0, &embolden) != FcResultMatch) - embolden = FcFalse; - - if (embolden) - ft_options.extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN; + if (!hinting || hintstyle == FC_HINT_NONE) { + ft_options->load_flags |= FT_LOAD_NO_HINTING; + font_options->hint_style = CAIRO_HINT_STYLE_NONE; } -#endif - return ft_options; + if (antialias) { + switch (hintstyle) { + case FC_HINT_SLIGHT: + load_target = FT_LOAD_TARGET_LIGHT; + font_options->hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + default: + load_target = FT_LOAD_TARGET_NORMAL; + font_options->hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + if (rgba == FC_RGBA_RGB || rgba == FC_RGBA_BGR) + load_target = FT_LOAD_TARGET_LCD; + else if (rgba == FC_RGBA_VRGB || rgba == FC_RGBA_VBGR) + load_target = FT_LOAD_TARGET_LCD_V; + font_options->hint_style = CAIRO_HINT_STYLE_FULL; + break; + } + } +#else /* !FC_HINT_STYLE */ + if (!hinting) { + ft_options->load_flags |= FT_LOAD_NO_HINTING; + font_options->hint_style = CAIRO_HINT_STYLE_NONE; + } +#endif /* FC_FHINT_STYLE */ + + ft_options->load_flags |= load_target; } static int _get_options_load_flags (const cairo_font_options_t *options) { - int load_flags = 0; + int load_flags = FT_LOAD_DEFAULT; + int load_target = FT_LOAD_TARGET_NORMAL; + int render_flags = FT_RENDER_MODE_NORMAL; /* disable antialiasing if requested */ switch (options->antialias) { case CAIRO_ANTIALIAS_NONE: -#ifdef FT_LOAD_TARGET_MONO - load_flags |= FT_LOAD_TARGET_MONO; -#endif - load_flags |= FT_LOAD_MONOCHROME; + load_flags |= FT_LOAD_MONOCHROME; + load_target = FT_LOAD_TARGET_MONO; + render_flags = FT_RENDER_MODE_MONO; break; case CAIRO_ANTIALIAS_SUBPIXEL: switch (options->subpixel_order) { case CAIRO_SUBPIXEL_ORDER_DEFAULT: case CAIRO_SUBPIXEL_ORDER_RGB: case CAIRO_SUBPIXEL_ORDER_BGR: - load_flags |= FT_LOAD_TARGET_LCD; + render_flags |= FT_LOAD_TARGET_LCD; break; case CAIRO_SUBPIXEL_ORDER_VRGB: case CAIRO_SUBPIXEL_ORDER_VBGR: - load_flags |= FT_LOAD_TARGET_LCD_V; + render_flags |= FT_LOAD_TARGET_LCD_V; break; } /* fall through ... */ @@ -1389,15 +1416,20 @@ #endif break; case CAIRO_HINT_STYLE_SLIGHT: case CAIRO_HINT_STYLE_MEDIUM: - load_flags |= FT_LOAD_TARGET_LIGHT; + /* slight/medium hinting - except for monochrome rendering */ + if (render_flags != FT_RENDER_MODE_MONO) + load_target |= FT_LOAD_TARGET_LIGHT; break; case CAIRO_HINT_STYLE_FULL: default: - load_flags |= FT_LOAD_TARGET_NORMAL; + if (render_flags == FT_RENDER_MODE_LCD) + load_target = FT_LOAD_TARGET_LCD; + else if (render_flags == FT_RENDER_MODE_LCD_V) + load_target = FT_LOAD_TARGET_LCD_V; break; } - return load_flags; + return load_flags | load_target; } static cairo_scaled_font_t * @@ -1406,6 +1438,7 @@ _cairo_ft_scaled_font_create (cairo_ft_u const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, const cairo_font_options_t *options, + const cairo_font_options_t *ft_font_options, cairo_ft_options_t ft_options) { cairo_ft_scaled_font_t *scaled_font = NULL; @@ -1430,6 +1463,9 @@ _cairo_ft_scaled_font_create (cairo_ft_u ft_options.extra_flags |= CAIRO_FT_OPTIONS_HINT_METRICS; scaled_font->ft_options = ft_options; + scaled_font->font_options = *options; + cairo_font_options_merge (&scaled_font->font_options, + ft_font_options); _cairo_scaled_font_init (&scaled_font->base, font_face, @@ -1502,6 +1538,7 @@ _cairo_ft_scaled_font_create_toy (cairo_ cairo_matrix_t scale; cairo_ft_font_transform_t sf; cairo_ft_options_t ft_options; + cairo_font_options_t ft_font_options; unsigned char *family = (unsigned char*) toy_face->family; pattern = FcPatternCreate (); @@ -1557,12 +1594,13 @@ _cairo_ft_scaled_font_create_toy (cairo_ if (!unscaled) goto FREE_RESOLVED; - ft_options = _get_pattern_ft_options (resolved); - + _get_pattern_ft_options (resolved, &ft_options, &ft_font_options); + new_font = _cairo_ft_scaled_font_create (unscaled, &toy_face->base, font_matrix, ctm, - font_options, ft_options); + font_options, + &ft_font_options, ft_options); _cairo_unscaled_font_destroy (&unscaled->base); @@ -1832,10 +1870,10 @@ #endif cairo_image_surface_t *surface; cairo_status_t status; if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) - status = _render_glyph_outline (face, &scaled_font->base.options, + status = _render_glyph_outline (face, &scaled_font->font_options, &surface); else - status = _render_glyph_bitmap (face, &scaled_font->base.options, + status = _render_glyph_bitmap (face, &scaled_font->font_options, &surface); if (status) { cairo_ft_scaled_font_unlock_face (abstract_font); @@ -1865,7 +1903,7 @@ #endif } } if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) - status = _decompose_glyph_outline (face, &scaled_font->base.options, + status = _decompose_glyph_outline (face, &scaled_font->font_options, &path); else status = CAIRO_STATUS_NO_MEMORY; @@ -2015,7 +2053,8 @@ _cairo_ft_font_face_scaled_font_create ( *scaled_font = _cairo_ft_scaled_font_create (font_face->unscaled, &font_face->base, font_matrix, ctm, - options, ft_options); + options, &font_face->font_options, + ft_options); if (*scaled_font) return CAIRO_STATUS_SUCCESS; else @@ -2030,7 +2069,8 @@ static const cairo_font_face_backend_t _ static cairo_font_face_t * _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, - cairo_ft_options_t ft_options) + cairo_ft_options_t *ft_options, + cairo_font_options_t *font_options) { cairo_ft_font_face_t *font_face; @@ -2039,8 +2079,8 @@ _cairo_ft_font_face_create (cairo_ft_uns font_face; font_face = font_face->next) { - if (font_face->ft_options.load_flags == ft_options.load_flags && - font_face->ft_options.extra_flags == ft_options.extra_flags) + if (font_face->ft_options.load_flags == ft_options->load_flags && + font_face->ft_options.extra_flags == ft_options->extra_flags) return cairo_font_face_reference (&font_face->base); } @@ -2052,7 +2092,8 @@ _cairo_ft_font_face_create (cairo_ft_uns font_face->unscaled = unscaled; _cairo_unscaled_font_reference (&unscaled->base); - font_face->ft_options = ft_options; + font_face->ft_options = *ft_options; + font_face->font_options = *font_options; font_face->next = unscaled->faces; unscaled->faces = font_face; @@ -2182,6 +2223,8 @@ cairo_ft_font_face_create_for_pattern (F { cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; + cairo_ft_options_t ft_options; + cairo_font_options_t font_options; unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern); if (unscaled == NULL) { @@ -2189,8 +2232,8 @@ cairo_ft_font_face_create_for_pattern (F return (cairo_font_face_t *)&_cairo_font_face_nil; } - font_face = _cairo_ft_font_face_create (unscaled, - _get_pattern_ft_options (pattern)); + _get_pattern_ft_options (pattern, &ft_options, &font_options); + font_face = _cairo_ft_font_face_create (unscaled, &ft_options, &font_options); _cairo_unscaled_font_destroy (&unscaled->base); if (font_face) @@ -2234,6 +2277,7 @@ cairo_ft_font_face_create_for_ft_face (F cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; cairo_ft_options_t ft_options; + cairo_font_options_t font_options; unscaled = _cairo_ft_unscaled_font_create_from_face (face); if (unscaled == NULL) { @@ -2243,8 +2287,10 @@ cairo_ft_font_face_create_for_ft_face (F ft_options.load_flags = load_flags; ft_options.extra_flags = 0; - - font_face = _cairo_ft_font_face_create (unscaled, ft_options); + + _cairo_font_options_init_default (&font_options); + + font_face = _cairo_ft_font_face_create (unscaled, &ft_options, &font_options); _cairo_unscaled_font_destroy (&unscaled->base); if (font_face) {