From 827bd968202158b26bf0643b9e26228cc8d7a2f9 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 22 Nov 2018 09:45:40 -0500 Subject: [PATCH] font chooser: port to new harfbuzz apis Use pango_font_get_hb_font() and some new harfbuzz apis to avoid freetype. --- gtk/gtkfontchooserwidget.c | 287 +++++++++++++++++++++---------------- 1 file changed, 163 insertions(+), 124 deletions(-) diff --git a/gtk/gtkfontchooserwidget.c b/gtk/gtkfontchooserwidget.c index b858d92c29..834a6d1cb2 100644 --- a/gtk/gtkfontchooserwidget.c +++ b/gtk/gtkfontchooserwidget.c @@ -53,13 +53,10 @@ #include "gtkcombobox.h" #include "gtkgesturemultipress.h" -#if defined(HAVE_HARFBUZZ) && defined(HAVE_PANGOFT) -#include +#ifdef HAVE_HARFBUZZ #include #include #include -#include -#include #include "language-names.h" #include "script-names.h" #endif @@ -862,7 +859,7 @@ gtk_font_chooser_widget_init (GtkFontChooserWidget *fontchooser) /* Load data and set initial style-dependent parameters */ gtk_font_chooser_widget_load_fonts (fontchooser, TRUE); -#if defined(HAVE_HARFBUZZ) && defined(HAVE_PANGOFT) +#ifdef HAVE_HARFBUZZ gtk_font_chooser_widget_populate_features (fontchooser); #endif gtk_font_chooser_widget_set_cell_size (fontchooser); @@ -1442,7 +1439,7 @@ gtk_font_chooser_widget_ensure_selection (GtkFontChooserWidget *fontchooser) } } -#if defined(HAVE_HARFBUZZ) && defined(HAVE_PANGOFT) +#ifdef HAVE_HARFBUZZ /* OpenType variations */ @@ -1501,69 +1498,139 @@ adjustment_changed (GtkAdjustment *adjustment, } static gboolean -should_show_axis (FT_Var_Axis *ax) +should_show_axis (hb_ot_var_axis_info_t *hb_axis) { - /* FIXME use FT_Get_Var_Axis_Flags */ - if (ax->tag == FT_MAKE_TAG ('o', 'p', 's', 'z')) + if (hb_axis->tag == HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE) + return FALSE; + + if ((hb_axis->flags & HB_OT_VAR_AXIS_FLAG_HIDDEN) != 0) return FALSE; return TRUE; } +#if 0 static gboolean -is_named_instance (FT_Face face) +is_named_instance (hb_font_t *hb_font) { - return (face->face_index >> 16) > 0; + hb_face_t *hb_face; + unsigned int n_axes; + unsigned int n_instances; + unsigned int len; + int *coords; + const int *coords1; + float *design_coords; + int *norm_coords; + unsigned int instance; + int i; + + hb_face = hb_font_get_face (hb_font); + n_axes = hb_ot_var_get_axis_count (hb_face); + n_instances = hb_ot_var_get_named_instance_count (hb_face); + if (n_instances == 0) + return FALSE; + + coords1 = hb_font_get_var_coords_normalized (hb_font, &len); + coords = g_new0 (int, n_axes); + for (i = 0; i < len; i++) + coords[i] = coords1[i]; + + design_coords = g_new (float, n_axes); + norm_coords = g_new (int, n_axes); + for (instance = 0; instance < n_instances; instance++) + { + len = n_axes; + hb_ot_var_named_instance_get_design_coords (hb_face, instance, &len, design_coords); + hb_ot_var_normalize_coords (hb_face, len, design_coords, norm_coords); + for (i = 0; i < n_axes; i++) + { + if (norm_coords[i] != coords[i]) + break; + } + if (i == n_axes) + { + g_free (coords); + return TRUE; + } + } + + g_free (coords); + return FALSE; } +#endif static struct { guint32 tag; const char *name; } axis_names[] = { - { FT_MAKE_TAG ('w', 'd', 't', 'h'), N_("Width") }, - { FT_MAKE_TAG ('w', 'g', 'h', 't'), N_("Weight") }, - { FT_MAKE_TAG ('i', 't', 'a', 'l'), N_("Italic") }, - { FT_MAKE_TAG ('s', 'l', 'n', 't'), N_("Slant") }, - { FT_MAKE_TAG ('o', 'p', 's', 'z'), N_("Optical Size") }, + { HB_OT_TAG_VAR_AXIS_WIDTH, N_("Width") }, + { HB_OT_TAG_VAR_AXIS_WEIGHT, N_("Weight") }, + { HB_OT_TAG_VAR_AXIS_ITALIC, N_("Italic") }, + { HB_OT_TAG_VAR_AXIS_SLANT, N_("Slant") }, }; +/* FIXME: this is missing harfbuzz api that needs to deal with AVAR */ +static double +get_value (hb_ot_var_axis_info_t *hb_axis, int value) +{ + double val; + + val = value * 1.0 / (1 << 14); + if (value < 0) + return hb_axis->default_value + (hb_axis->default_value - hb_axis->min_value) * val; + else + return hb_axis->default_value + (hb_axis->max_value - hb_axis->default_value) * val; +} + static gboolean -add_axis (GtkFontChooserWidget *fontchooser, - FT_Face face, - FT_Var_Axis *ax, - FT_Fixed value, - int row) +add_axis (GtkFontChooserWidget *fontchooser, + hb_font_t *hb_font, + hb_ot_var_axis_info_t *hb_axis, + int value, + int row) { GtkFontChooserWidgetPrivate *priv = fontchooser->priv; Axis *axis; - const char *name; + const char *name = NULL; + char text[64]; + unsigned int len = 64; int i; + double val; axis = g_new (Axis, 1); - axis->tag = ax->tag; + axis->tag = hb_axis->tag; axis->fontchooser = GTK_WIDGET (fontchooser); - name = ax->name; for (i = 0; i < G_N_ELEMENTS (axis_names); i++) { - if (axis_names[i].tag == ax->tag) + if (axis_names[i].tag == hb_axis->tag) { name = _(axis_names[i].name); break; } } + + if (name == NULL) + { + hb_face_t *hb_face = hb_font_get_face (hb_font); + hb_language_t language = hb_language_from_string ("en", -1); + hb_ot_name_get_utf8 (hb_face, hb_axis->name_id, language, &len, text); + name = text; + } + axis->label = gtk_label_new (name); gtk_widget_show (axis->label); gtk_widget_set_halign (axis->label, GTK_ALIGN_START); gtk_widget_set_valign (axis->label, GTK_ALIGN_BASELINE); gtk_grid_attach (GTK_GRID (priv->axis_grid), axis->label, 0, row, 1, 1); - axis->adjustment = gtk_adjustment_new ((double)FixedToFloat(value), - (double)FixedToFloat(ax->minimum), - (double)FixedToFloat(ax->maximum), + val = get_value (hb_axis, value); + axis->adjustment = gtk_adjustment_new (val, + (double)hb_axis->min_value, + (double)hb_axis->max_value, 1.0, 10.0, 0.0); axis->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, axis->adjustment); gtk_widget_show (axis->scale); - gtk_scale_add_mark (GTK_SCALE (axis->scale), (double)FixedToFloat(ax->def), GTK_POS_TOP, NULL); + gtk_scale_add_mark (GTK_SCALE (axis->scale), (double)hb_axis->default_value, GTK_POS_TOP, NULL); gtk_widget_set_valign (axis->scale, GTK_ALIGN_BASELINE); gtk_widget_set_hexpand (axis->scale, TRUE); gtk_widget_set_size_request (axis->scale, 100, -1); @@ -1579,7 +1646,8 @@ add_axis (GtkFontChooserWidget *fontchooser, adjustment_changed (axis->adjustment, axis); g_signal_connect (axis->adjustment, "value-changed", G_CALLBACK (adjustment_changed), axis); - if (is_named_instance (face) || !should_show_axis (ax)) + + if (/* is_named_instance (hb_font) || */ !should_show_axis (hb_axis)) { gtk_widget_hide (axis->label); gtk_widget_hide (axis->scale); @@ -1596,10 +1664,15 @@ gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchoose { GtkFontChooserWidgetPrivate *priv = fontchooser->priv; PangoFont *pango_font; - FT_Face ft_face; - FT_MM_Var *ft_mm_var; - FT_Error ret; + hb_font_t *hb_font; + hb_face_t *hb_face; + unsigned int n_axes; + hb_ot_var_axis_info_t *axes; + const int *coords; + unsigned int len; + int i; gboolean has_axis = FALSE; + PangoFontFace *face; if (priv->updating_variations) return FALSE; @@ -1612,39 +1685,21 @@ gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchoose pango_font = pango_context_load_font (gtk_widget_get_pango_context (GTK_WIDGET (fontchooser)), priv->font_desc); - ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)); + face = gtk_font_chooser_widget_get_face (GTK_FONT_CHOOSER (fontchooser)); + if (pango_font_face_is_synthesized (face)) + return FALSE; - ret = FT_Get_MM_Var (ft_face, &ft_mm_var); - if (ret == 0) + hb_font = pango_font_get_hb_font (pango_font); + hb_face = hb_font_get_face (hb_font); + n_axes = hb_ot_var_get_axis_count (hb_face); + axes = g_new (hb_ot_var_axis_info_t, n_axes); + hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, axes); + coords = hb_font_get_var_coords_normalized (hb_font, &len); + for (i = 0; i < n_axes; i++) { - int i; - FT_Fixed *coords; - - coords = g_new (FT_Fixed, ft_mm_var->num_axis); - for (i = 0; i < ft_mm_var->num_axis; i++) - coords[i] = ft_mm_var->axis[i].def; - - if (ft_face->face_index > 0) - { - int instance_id = ft_face->face_index >> 16; - if (instance_id && instance_id <= ft_mm_var->num_namedstyles) - { - FT_Var_Named_Style *instance = &ft_mm_var->namedstyle[instance_id - 1]; - memcpy (coords, instance->coords, ft_mm_var->num_axis * sizeof (*coords)); - } - } - - for (i = 0; i < ft_mm_var->num_axis; i++) - { - if (add_axis (fontchooser, ft_face, &ft_mm_var->axis[i], coords[i], i + 4)) - has_axis = TRUE; - } - - g_free (coords); - free (ft_mm_var); + if (add_axis (fontchooser, hb_font, &axes[i], i < len ? coords[i] : 0, i + 4)) + has_axis = TRUE; } - - pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font)); g_object_unref (pango_font); return has_axis; @@ -1787,7 +1842,7 @@ find_affected_text (hb_tag_t feature_tag, chars = g_string_new (""); hb_ot_layout_table_find_script (hb_face, HB_OT_TAG_GSUB, script_tag, &script_index); - hb_ot_layout_script_find_language (hb_face, HB_OT_TAG_GSUB, script_index, lang_tag, &lang_index); + hb_ot_layout_script_select_language (hb_face, HB_OT_TAG_GSUB, script_index, 1, &lang_tag, &lang_index); if (hb_ot_layout_language_find_feature (hb_face, HB_OT_TAG_GSUB, script_index, lang_index, feature_tag, &feature_index)) { unsigned int lookup_indexes[32]; @@ -2123,8 +2178,8 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser) { GtkFontChooserWidgetPrivate *priv = fontchooser->priv; PangoFont *pango_font; - FT_Face ft_face; hb_font_t *hb_font; + hb_face_t *hb_face; hb_tag_t script_tag; hb_tag_t lang_tag; guint script_index = 0; @@ -2132,6 +2187,10 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser) int i, j; GList *l; gboolean has_feature = FALSE; + hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS }; + hb_tag_t features[80]; + unsigned int count; + unsigned int n_features; for (l = priv->feature_items; l; l = l->next) { @@ -2145,67 +2204,47 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser) pango_font = pango_context_load_font (gtk_widget_get_pango_context (GTK_WIDGET (fontchooser)), priv->font_desc); - ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)), - hb_font = hb_ft_font_create (ft_face, NULL); + hb_font = pango_font_get_hb_font (pango_font); + hb_face = hb_font_get_face (hb_font); - if (hb_font) + find_language_and_script (fontchooser, hb_face, &lang_tag, &script_tag); + + n_features = 0; + for (i = 0; i < 2; i++) { - hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS }; - hb_face_t *hb_face; - hb_tag_t features[80]; - unsigned int count; - unsigned int n_features; - - hb_face = hb_font_get_face (hb_font); - - find_language_and_script (fontchooser, hb_face, &lang_tag, &script_tag); - - n_features = 0; - for (i = 0; i < 2; i++) - { - hb_ot_layout_table_find_script (hb_face, table[i], script_tag, &script_index); - hb_ot_layout_script_find_language (hb_face, table[i], script_index, lang_tag, &lang_index); - count = G_N_ELEMENTS (features); - hb_ot_layout_language_get_feature_tags (hb_face, - table[i], - script_index, - lang_index, - n_features, - &count, - features); - n_features += count; - } - - for (j = 0; j < n_features; j++) - { - for (l = priv->feature_items; l; l = l->next) - { - FeatureItem *item = l->data; - if (item->tag != features[j]) - continue; - - has_feature = TRUE; - gtk_widget_show (item->top); - gtk_widget_show (gtk_widget_get_parent (item->top)); - - update_feature_example (item, hb_face, script_tag, lang_tag, priv->font_desc); - - if (GTK_IS_RADIO_BUTTON (item->feat)) - { - GtkWidget *def = GTK_WIDGET (g_object_get_data (G_OBJECT (item->feat), "default")); - gtk_widget_show (gtk_widget_get_parent (def)); - } - else if (GTK_IS_CHECK_BUTTON (item->feat)) - { - set_inconsistent (GTK_CHECK_BUTTON (item->feat), TRUE); - } - } - } - - hb_face_destroy (hb_face); + hb_ot_layout_table_find_script (hb_face, table[i], script_tag, &script_index); + hb_ot_layout_script_select_language (hb_face, table[i], script_index, 1, &lang_tag, &lang_index); + count = G_N_ELEMENTS (features); + hb_ot_layout_language_get_feature_tags (hb_face, table[i], script_index, lang_index, n_features, &count, features); + n_features += count; + } + + for (j = 0; j < n_features; j++) + { + for (l = priv->feature_items; l; l = l->next) + { + FeatureItem *item = l->data; + if (item->tag != features[j]) + continue; + + has_feature = TRUE; + gtk_widget_show (item->top); + gtk_widget_show (gtk_widget_get_parent (item->top)); + + update_feature_example (item, hb_face, script_tag, lang_tag, priv->font_desc); + + if (GTK_IS_RADIO_BUTTON (item->feat)) + { + GtkWidget *def = GTK_WIDGET (g_object_get_data (G_OBJECT (item->feat), "default")); + gtk_widget_show (gtk_widget_get_parent (def)); + } + else if (GTK_IS_CHECK_BUTTON (item->feat)) + { + set_inconsistent (GTK_CHECK_BUTTON (item->feat), TRUE); + } + } } - pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font)); g_object_unref (pango_font); return has_feature; @@ -2258,7 +2297,7 @@ update_font_features (GtkFontChooserWidget *fontchooser) gtk_font_chooser_widget_update_preview_attributes (fontchooser); } -#endif +#endif /* HAVE_HARFBUZ */ static void gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser, @@ -2305,7 +2344,7 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser gtk_font_chooser_widget_update_marks (fontchooser); -#if defined(HAVE_HARFBUZZ) && defined(HAVE_PANGOFT) +#ifdef HAVE_HARFBUZZ if (gtk_font_chooser_widget_update_font_features (fontchooser)) has_tweak = TRUE; if (gtk_font_chooser_widget_update_font_variations (fontchooser))