diff options
-rw-r--r-- | pango/pangofc-font.c | 142 | ||||
-rw-r--r-- | pango/pangofc-fontmap.c | 4 | ||||
-rw-r--r-- | pango/pangofc-shape.c | 333 |
3 files changed, 147 insertions, 332 deletions
diff --git a/pango/pangofc-font.c b/pango/pangofc-font.c index 437c7709..7c4f64e9 100644 --- a/pango/pangofc-font.c +++ b/pango/pangofc-font.c @@ -46,6 +46,7 @@ #include "pango-layout.h" #include "pango-impl-utils.h" +#include <harfbuzz/hb-ot.h> #include <fontconfig/fcfreetype.h> #include FT_TRUETYPE_TABLES_H @@ -1066,40 +1067,135 @@ pango_fc_font_get_features (PangoFont *font, (*num_features)++; } } +} -static hb_font_t * -pango_fc_font_create_hb_font (PangoFont *font) +extern gpointer get_gravity_class (void); + +static PangoGravity +pango_fc_font_key_get_gravity (PangoFcFontKey *key) { - PangoFcFont *fcfont = PANGO_FC_FONT (font); - hb_face_t *hb_face; + FcPattern *pattern; + PangoGravity gravity = PANGO_GRAVITY_SOUTH; + FcChar8 *s; - hb_face = pango_fc_font_map_get_hb_face (PANGO_FC_FONT_MAP (fcfont->fontmap), fcfont); + pattern = pango_fc_font_key_get_pattern (key); + if (FcPatternGetString (pattern, PANGO_FC_GRAVITY, 0, (FcChar8 **)&s) == FcResultMatch) + { + GEnumValue *value = g_enum_get_value_by_nick (get_gravity_class (), (char *)s); + gravity = value->value; + } - return hb_font_create (hb_face); + return gravity; +} + +static double +get_font_size (PangoFcFontKey *key) +{ + FcPattern *pattern; + double size; + double dpi; + + pattern = pango_fc_font_key_get_pattern (key); + if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch) + return size; + + /* Just in case FC_PIXEL_SIZE got unset between pango_fc_make_pattern() + * and here. That would be very weird. + */ + + if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) != FcResultMatch) + dpi = 72; + + if (FcPatternGetDouble (pattern, FC_SIZE, 0, &size) == FcResultMatch) + return size * dpi / 72.; + + /* Whatever */ + return 18.; } static void -pango_fc_font_get_features (PangoFont *font, - hb_feature_t *features, - guint len, - guint *num_features) +parse_variations (const char *variations, + hb_variation_t **hb_variations, + guint *n_variations) +{ + guint n; + hb_variation_t *var; + int i; + const char *p; + + n = 1; + for (i = 0; variations[i]; i++) + { + if (variations[i] == ',') + n++; + } + + var = g_new (hb_variation_t, n); + + p = variations; + n = 0; + while (p && *p) + { + char *end = strchr (p, ','); + if (hb_variation_from_string (p, end ? end - p: -1, &var[n])) + n++; + p = end ? end + 1 : NULL; + } + + *hb_variations = var; + *n_variations = n; +} + +static hb_font_t * +pango_fc_font_create_hb_font (PangoFont *font) { - /* Setup features from fontconfig pattern. */ PangoFcFont *fc_font = PANGO_FC_FONT (font); - if (fc_font->font_pattern) + PangoFcFontKey *key; + hb_face_t *hb_face; + hb_font_t *hb_font; + double x_scale_inv, y_scale_inv; + double x_scale, y_scale; + double size; + PangoGravity gravity; + + x_scale_inv = y_scale_inv = 1.0; + key = _pango_fc_font_get_font_key (fc_font); + if (key) { - char *s; - while (*num_features < len && - FcResultMatch == FcPatternGetString (fc_font->font_pattern, - PANGO_FC_FONT_FEATURES, - *num_features, - (FcChar8 **) &s)) + const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key); + pango_matrix_get_font_scale_factors (matrix, &x_scale_inv, &y_scale_inv); + } + if (PANGO_GRAVITY_IS_IMPROPER (gravity)) + { + x_scale_inv = -x_scale_inv; + y_scale_inv = -y_scale_inv; + } + + x_scale = 1. / x_scale_inv; + y_scale = 1. / y_scale_inv; + + size = get_font_size (key); + gravity = pango_fc_font_key_get_gravity (key); + hb_face = pango_fc_font_map_get_hb_face (PANGO_FC_FONT_MAP (fc_font->fontmap), fc_font); + + hb_font = hb_font_create (hb_face); + hb_font_set_scale (hb_font, + size * PANGO_SCALE * x_scale, + size * PANGO_SCALE * y_scale); + if (key) + { + const char *variations = pango_fc_font_key_get_variations (key); + if (variations) { - gboolean ret = hb_feature_from_string (s, -1, &features[*num_features]); - features[*num_features].start = 0; - features[*num_features].end = (unsigned int) -1; - if (ret) - (*num_features)++; + guint n_variations; + hb_variation_t *hb_variations; + + parse_variations (variations, &hb_variations, &n_variations); + hb_font_set_variations (hb_font, hb_variations, n_variations); + + g_free (hb_variations); } } + + return hb_font; } diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c index 9d968328..cc450d20 100644 --- a/pango/pangofc-fontmap.c +++ b/pango/pangofc-fontmap.c @@ -264,7 +264,9 @@ static FcPattern *pango_fc_patterns_get_font_pattern (PangoFcPatterns *pat static FcPattern *uniquify_pattern (PangoFcFontMap *fcfontmap, FcPattern *pattern); -static gpointer +gpointer get_gravity_class (void); + +gpointer get_gravity_class (void) { static GEnumClass *class = NULL; /* MT-safe */ diff --git a/pango/pangofc-shape.c b/pango/pangofc-shape.c index 9bedd28a..e64b8deb 100644 --- a/pango/pangofc-shape.c +++ b/pango/pangofc-shape.c @@ -70,249 +70,6 @@ release_buffer (hb_buffer_t *buffer, gboolean free_buffer) hb_buffer_destroy (buffer); } -typedef struct _PangoFcHbContext { - FT_Face ft_face; - PangoFcFont *fc_font; - gboolean vertical; - double x_scale, y_scale; /* CTM scales. */ -} PangoFcHbContext; - -static hb_bool_t -pango_fc_hb_font_get_nominal_glyph (hb_font_t *font, void *font_data, - hb_codepoint_t unicode, - hb_codepoint_t *glyph, - void *user_data G_GNUC_UNUSED) -{ - PangoFcHbContext *context = (PangoFcHbContext *) font_data; - PangoFcFont *fc_font = context->fc_font; - - *glyph = pango_fc_font_get_glyph (fc_font, unicode); - if (G_LIKELY (*glyph)) - return TRUE; - - *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); - - /* We draw our own invalid-Unicode shape, so prevent HarfBuzz - * from using REPLACEMENT CHARACTER. */ - if (unicode > 0x10FFFF) - return TRUE; - - return FALSE; -} - -static hb_bool_t -pango_fc_hb_font_get_variation_glyph (hb_font_t *font, - void *font_data, - hb_codepoint_t unicode, - hb_codepoint_t variation_selector, - hb_codepoint_t *glyph, - void *user_data G_GNUC_UNUSED) -{ - PangoFcHbContext *context = (PangoFcHbContext *) font_data; - FT_Face ft_face = context->ft_face; - unsigned int g; - - g = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector); - - if (G_UNLIKELY (!g)) - return FALSE; - - *glyph = g; - return TRUE; -} - -static hb_bool_t -pango_fc_hb_font_get_glyph_contour_point (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, unsigned int point_index, - hb_position_t *x, hb_position_t *y, - void *user_data G_GNUC_UNUSED) -{ - return FALSE; -#if 0 - FT_Face ft_face = (FT_Face) font_data; - int load_flags = FT_LOAD_DEFAULT; - - /* TODO: load_flags, embolden, etc */ - - if (HB_UNLIKELY (FT_Load_Glyph (ft_face, glyph, load_flags))) - return FALSE; - - if (HB_UNLIKELY (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) - return FALSE; - - if (HB_UNLIKELY (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) - return FALSE; - - *x = ft_face->glyph->outline.points[point_index].x; - *y = ft_face->glyph->outline.points[point_index].y; - - return TRUE; -#endif -} - -static hb_position_t -pango_fc_hb_font_get_glyph_advance (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - void *user_data G_GNUC_UNUSED) -{ - PangoFcHbContext *context = (PangoFcHbContext *) font_data; - PangoFcFont *fc_font = context->fc_font; - PangoRectangle logical; - - pango_font_get_glyph_extents ((PangoFont *) fc_font, glyph, NULL, &logical); - - return logical.width; -} - -static hb_bool_t -pango_fc_hb_font_get_glyph_extents (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_glyph_extents_t *extents, - void *user_data G_GNUC_UNUSED) -{ - PangoFcHbContext *context = (PangoFcHbContext *) font_data; - PangoFcFont *fc_font = context->fc_font; - PangoRectangle ink; - - pango_font_get_glyph_extents ((PangoFont *) fc_font, glyph, &ink, NULL); - - if (G_LIKELY (!context->vertical)) { - extents->x_bearing = ink.x; - extents->y_bearing = ink.y; - extents->width = ink.width; - extents->height = ink.height; - } else { - /* XXX */ - extents->x_bearing = ink.x; - extents->y_bearing = ink.y; - extents->width = ink.height; - extents->height = ink.width; - } - - return TRUE; -} - -static hb_bool_t -pango_fc_hb_font_get_glyph_h_origin (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y, - void *user_data G_GNUC_UNUSED) -{ - PangoFcHbContext *context = (PangoFcHbContext *) font_data; - FT_Face ft_face = context->ft_face; - int load_flags = FT_LOAD_DEFAULT; - - if (!context->vertical) return TRUE; - - if (FT_Load_Glyph (ft_face, glyph, load_flags)) - return FALSE; - - /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates - * have a Y growing upward. Hence the extra negations. */ - *x = -PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX); - *y = +PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY)); - - return TRUE; -} - -static hb_bool_t -pango_fc_hb_font_get_glyph_v_origin (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y, - void *user_data G_GNUC_UNUSED) -{ - PangoFcHbContext *context = (PangoFcHbContext *) font_data; - FT_Face ft_face = context->ft_face; - int load_flags = FT_LOAD_DEFAULT; - - /* pangocairo-fc configures font in vertical origin for vertical writing. */ - if (context->vertical) return TRUE; - - if (FT_Load_Glyph (ft_face, glyph, load_flags)) - return FALSE; - - /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates - * have a Y growing upward. Hence the extra negation. */ - *x = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX); - *y = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY)); - - /* XXX */ - - return TRUE; -} - - -static hb_position_t -pango_fc_hb_font_get_h_kerning (hb_font_t *font, void *font_data, - hb_codepoint_t left_glyph, hb_codepoint_t right_glyph, - void *user_data G_GNUC_UNUSED) -{ - PangoFcHbContext *context = (PangoFcHbContext *) font_data; - FT_Face ft_face = context->ft_face; - FT_Vector kerning; - - if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerning)) - return 0; - - return PANGO_UNITS_26_6 (kerning.x * context->x_scale); -} - -static hb_font_funcs_t * -pango_fc_get_hb_font_funcs (void) -{ - static hb_font_funcs_t *funcs; - - if (G_UNLIKELY (!funcs)) { - funcs = hb_font_funcs_create (); - hb_font_funcs_set_nominal_glyph_func (funcs, pango_fc_hb_font_get_nominal_glyph, NULL, NULL); - hb_font_funcs_set_variation_glyph_func (funcs, pango_fc_hb_font_get_variation_glyph, NULL, NULL); - hb_font_funcs_set_glyph_h_advance_func (funcs, pango_fc_hb_font_get_glyph_advance, NULL, NULL); - hb_font_funcs_set_glyph_v_advance_func (funcs, pango_fc_hb_font_get_glyph_advance, NULL, NULL); - hb_font_funcs_set_glyph_h_origin_func (funcs, pango_fc_hb_font_get_glyph_h_origin, NULL, NULL); - hb_font_funcs_set_glyph_v_origin_func (funcs, pango_fc_hb_font_get_glyph_v_origin, NULL, NULL); - hb_font_funcs_set_glyph_h_kerning_func (funcs, pango_fc_hb_font_get_h_kerning, NULL, NULL); - /* Don't need v_kerning. */ - hb_font_funcs_set_glyph_extents_func (funcs, pango_fc_hb_font_get_glyph_extents, NULL, NULL); - hb_font_funcs_set_glyph_contour_point_func (funcs, pango_fc_hb_font_get_glyph_contour_point, NULL, NULL); - /* Don't need glyph_name / glyph_from_name */ - } - - return funcs; -} - -static void -parse_variations (const char *variations, - hb_variation_t **hb_variations, - guint *n_variations) -{ - guint n; - hb_variation_t *var; - int i; - const char *p; - - n = 1; - for (i = 0; variations[i]; i++) - { - if (variations[i] == ',') - n++; - } - - var = g_new (hb_variation_t, n); - - p = variations; - n = 0; - while (p && *p) - { - char *end = strchr (p, ','); - if (hb_variation_from_string (p, end ? end - p: -1, &var[n])) - n++; - p = end ? end + 1 : NULL; - } - - *hb_variations = var; - *n_variations = n; -} - static void apply_extra_attributes (GSList *attrs, hb_feature_t *features, @@ -365,11 +122,7 @@ _pango_fc_shape (PangoFont *font, const char *paragraph_text, unsigned int paragraph_length) { - PangoFcHbContext context; PangoFcFont *fc_font; - PangoFcFontKey *key; - FT_Face ft_face; - hb_face_t *hb_face; hb_font_t *hb_font; hb_buffer_t *hb_buffer; hb_direction_t hb_direction; @@ -381,64 +134,12 @@ _pango_fc_shape (PangoFont *font, unsigned int item_offset = item_text - paragraph_text; hb_feature_t features[32]; unsigned int num_features = 0; - double x_scale_inv, y_scale_inv; PangoGlyphInfo *infos; - const char *variations; g_return_if_fail (font != NULL); g_return_if_fail (analysis != NULL); - fc_font = PANGO_FC_FONT (font); - ft_face = pango_fc_font_lock_face (fc_font); - if (!ft_face) - return; - - /* TODO: Cache hb_font? */ - - x_scale_inv = y_scale_inv = 1.0; - key = _pango_fc_font_get_font_key (fc_font); - if (key) - { - const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key); - pango_matrix_get_font_scale_factors (matrix, &x_scale_inv, &y_scale_inv); - } - if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity)) - { - x_scale_inv = -x_scale_inv; - y_scale_inv = -y_scale_inv; - } - context.x_scale = 1. / x_scale_inv; - context.y_scale = 1. / y_scale_inv; - context.ft_face = ft_face; - context.fc_font = fc_font; - context.vertical = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity); - hb_face = hb_ft_face_create_cached (ft_face); - hb_font = hb_font_create (hb_face); - hb_font_set_funcs (hb_font, - pango_fc_get_hb_font_funcs (), - &context, - NULL); - hb_font_set_scale (hb_font, - +(((gint64) ft_face->size->metrics.x_scale * ft_face->units_per_EM) >> 12) * context.x_scale, - -(((gint64) ft_face->size->metrics.y_scale * ft_face->units_per_EM) >> 12) * context.y_scale); - hb_font_set_ppem (hb_font, - fc_font->is_hinted ? ft_face->size->metrics.x_ppem : 0, - fc_font->is_hinted ? ft_face->size->metrics.y_ppem : 0); - - if (key) - { - variations = pango_fc_font_key_get_variations (key); - if (variations) - { - guint n_variations; - hb_variation_t *hb_variations; - - parse_variations (variations, &hb_variations, &n_variations); - hb_font_set_variations (hb_font, hb_variations, n_variations); - - g_free (hb_variations); - } - } + hb_font = pango_font_get_hb_font (font); hb_buffer = acquire_buffer (&free_buffer); @@ -484,7 +185,7 @@ _pango_fc_shape (PangoFont *font, } hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL); - if (context.vertical) + if (PANGO_GRAVITY_IS_VERTICAL (analysis->gravity)) for (i = 0; i < num_glyphs; i++) { /* 90 degrees rotation counter-clockwise. */ @@ -504,7 +205,26 @@ _pango_fc_shape (PangoFont *font, if (fc_font->is_hinted) { - if (context.x_scale == 1.0 && context.y_scale == 1.0) + double x_scale_inv, y_scale_inv; + double x_scale, y_scale; + PangoFcFontKey *key; + + x_scale_inv = y_scale_inv = 1.0; + key = _pango_fc_font_get_font_key (fc_font); + if (key) + { + const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key); + pango_matrix_get_font_scale_factors (matrix, &x_scale_inv, &y_scale_inv); + } + if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity)) + { + x_scale_inv = -x_scale_inv; + y_scale_inv = -y_scale_inv; + } + x_scale = 1. / x_scale_inv; + y_scale = 1. / y_scale_inv; + + if (x_scale == 1.0 && y_scale == 1.0) { for (i = 0; i < num_glyphs; i++) infos[i].geometry.width = PANGO_UNITS_ROUND (infos[i].geometry.width); @@ -512,7 +232,7 @@ _pango_fc_shape (PangoFont *font, else { #if 0 - if (context.vertical) + if (PANGO_GRAVITY_IS_VERTICAL (analysis->gravity)) { /* XXX */ double tmp = x_scale; @@ -521,8 +241,8 @@ _pango_fc_shape (PangoFont *font, } #endif #define HINT(value, scale_inv, scale) (PANGO_UNITS_ROUND ((int) ((value) * scale)) * scale_inv) -#define HINT_X(value) HINT ((value), context.x_scale, x_scale_inv) -#define HINT_Y(value) HINT ((value), context.y_scale, y_scale_inv) +#define HINT_X(value) HINT ((value), x_scale, x_scale_inv) +#define HINT_Y(value) HINT ((value), y_scale, y_scale_inv) for (i = 0; i < num_glyphs; i++) { infos[i].geometry.width = HINT_X (infos[i].geometry.width); @@ -536,7 +256,4 @@ _pango_fc_shape (PangoFont *font, } release_buffer (hb_buffer, free_buffer); - hb_font_destroy (hb_font); - hb_face_destroy (hb_face); - pango_fc_font_unlock_face (fc_font); } |