[gtk+/wip/matthiasc/font-variations: 1/2] Some initial support for font variations
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/matthiasc/font-variations: 1/2] Some initial support for font variations
- Date: Sat, 16 Sep 2017 18:52:17 +0000 (UTC)
commit efc405a22bde1e0830c6ed48d3f88aa0bc645e98
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Sep 15 22:38:08 2017 -0400
Some initial support for font variations
Make the font chooser show sliders for axes of
variable fonts.
gtk/gtkfontchooserwidget.c | 225 ++++++++++++++++++++++++++++++++++++++++
gtk/ui/gtkfontchooserwidget.ui | 22 +++-
2 files changed, 242 insertions(+), 5 deletions(-)
---
diff --git a/gtk/gtkfontchooserwidget.c b/gtk/gtkfontchooserwidget.c
index d8a8f3a..268740c 100644
--- a/gtk/gtkfontchooserwidget.c
+++ b/gtk/gtkfontchooserwidget.c
@@ -51,6 +51,13 @@
#include "gtksettings.h"
#include "gtkdialog.h"
+#include <pango/pangofc-font.h>
+#include <hb.h>
+#include <hb-ot.h>
+#include <hb-ft.h>
+#include <freetype/ftmm.h>
+#include <freetype/ftsnames.h>
+
/**
* SECTION:gtkfontchooserwidget
* @Short_description: A widget for selecting fonts
@@ -98,6 +105,8 @@ struct _GtkFontChooserWidgetPrivate
GtkWidget *size_spin;
GtkWidget *size_slider;
+ GtkWidget *font_grid;
+
PangoFontMap *font_map;
PangoFontDescription *font_desc;
@@ -108,6 +117,9 @@ struct _GtkFontChooserWidgetPrivate
GDestroyNotify filter_data_destroy;
guint last_fontconfig_timestamp;
+
+ GHashTable *axes;
+ gboolean updating_variations;
};
/* Keep in line with GtkTreeStore defined in gtkfontchooserwidget.ui */
@@ -170,6 +182,43 @@ static void gtk_font_chooser_widget_cell_data_func (GtkTreeViewColum
GtkTreeIter *iter,
gpointer user_data);
+typedef struct {
+ guint32 tag;
+ GtkAdjustment *adjustment;
+ GtkWidget *label;
+ GtkWidget *scale;
+ GtkWidget *spin;
+ GtkWidget *fontchooser;
+} Axis;
+
+static guint
+axis_hash (gconstpointer v)
+{
+ const Axis *a = v;
+
+ return a->tag;
+}
+
+static gboolean
+axis_equal (gconstpointer v1, gconstpointer v2)
+{
+ const Axis *a1 = v1;
+ const Axis *a2 = v2;
+
+ return a1->tag == a2->tag;
+}
+
+static void
+axis_free (gpointer v)
+{
+ Axis *a = v;
+
+ gtk_widget_destroy (a->label);
+ gtk_widget_destroy (a->scale);
+ gtk_widget_destroy (a->spin);
+ g_free (a);
+}
+
static void gtk_font_chooser_widget_iface_init (GtkFontChooserIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkFontChooserWidget, gtk_font_chooser_widget, GTK_TYPE_WIDGET,
@@ -659,6 +708,7 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GtkFontChooserWidget, size_spin);
gtk_widget_class_bind_template_child_private (widget_class, GtkFontChooserWidget, size_slider);
gtk_widget_class_bind_template_child_private (widget_class, GtkFontChooserWidget, grid);
+ gtk_widget_class_bind_template_child_private (widget_class, GtkFontChooserWidget, font_grid);
gtk_widget_class_bind_template_callback (widget_class, text_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, stop_search_cb);
@@ -687,6 +737,8 @@ gtk_font_chooser_widget_init (GtkFontChooserWidget *fontchooser)
gtk_widget_init_template (GTK_WIDGET (fontchooser));
+ priv->axes = g_hash_table_new_full (axis_hash, axis_equal, NULL, axis_free);
+
/* Default preview string */
priv->preview_text = g_strdup (pango_language_get_sample_string (NULL));
priv->show_preview_entry = TRUE;
@@ -1035,6 +1087,8 @@ gtk_font_chooser_widget_finalize (GObject *object)
g_clear_object (&priv->font_map);
+ g_hash_table_unref (priv->axes);
+
G_OBJECT_CLASS (gtk_font_chooser_widget_parent_class)->finalize (object);
}
@@ -1235,6 +1289,175 @@ gtk_font_chooser_widget_ensure_selection (GtkFontChooserWidget *fontchooser)
}
}
+
+#define FixedToFloat(f) (((float)(f))/65536.0)
+
+static void
+add_font_variations (GtkFontChooserWidget *fontchooser,
+ GString *s)
+{
+ GHashTableIter iter;
+ Axis *axis;
+ char *sep = "";
+ char buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+ g_hash_table_iter_init (&iter, fontchooser->priv->axes);
+ while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
+ {
+ char tag[5];
+ double value;
+
+ tag[0] = (axis->tag >> 24) & 0xff;
+ tag[1] = (axis->tag >> 16) & 0xff;
+ tag[2] = (axis->tag >> 8) & 0xff;
+ tag[3] = (axis->tag >> 0) & 0xff;
+ tag[4] = '\0';
+ value = gtk_adjustment_get_value (axis->adjustment);
+ g_string_append_printf (s, "%s%s=%s", sep, tag, g_ascii_dtostr (buf, sizeof(buf), value));
+ sep = ",";
+ }
+}
+
+static void
+adjustment_changed (GtkAdjustment *adjustment,
+ Axis *axis)
+{
+ GtkFontChooserWidget *fontchooser = GTK_FONT_CHOOSER_WIDGET (axis->fontchooser);
+ GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
+ PangoFontDescription *font_desc;
+ GString *s;
+
+ priv->updating_variations = TRUE;
+
+ s = g_string_new ("");
+ add_font_variations (fontchooser, s);
+
+ font_desc = pango_font_description_new ();
+ pango_font_description_set_variations (font_desc, s->str);
+ pango_font_description_set_variations (font_desc, s->str);
+ gtk_font_chooser_widget_take_font_desc (fontchooser, font_desc);
+
+ g_string_free (s, TRUE);
+
+ priv->updating_variations = FALSE;
+}
+
+static gboolean
+should_show_axis (FT_Var_Axis *ax)
+{
+ /* FIXME use FT_Get_Var_Axis_Flags */
+ if (ax->tag == FT_MAKE_TAG ('o', 'p', 's', 'z'))
+ return FALSE;
+
+ return TRUE;
+}
+
+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") },
+};
+
+static void
+add_axis (GtkFontChooserWidget *fontchooser,
+ FT_Var_Axis *ax,
+ FT_Fixed value,
+ int i)
+{
+ GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
+ Axis *axis;
+ const char *name;
+
+ axis = g_new (Axis, 1);
+ axis->tag = ax->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)
+ {
+ name = _(axis_names[i].name);
+ break;
+ }
+ }
+ axis->label = gtk_label_new (name);
+ gtk_widget_set_halign (axis->label, GTK_ALIGN_START);
+ gtk_widget_set_valign (axis->label, GTK_ALIGN_BASELINE);
+ gtk_grid_attach (GTK_GRID (priv->font_grid), axis->label, 0, 4 + i, 1, 1);
+ axis->adjustment = gtk_adjustment_new ((double)FixedToFloat(value),
+ (double)FixedToFloat(ax->minimum),
+ (double)FixedToFloat(ax->maximum),
+ 1.0, 10.0, 0.0);
+ axis->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, axis->adjustment);
+ gtk_scale_add_mark (GTK_SCALE (axis->scale), (double)FixedToFloat(ax->def), 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);
+ gtk_scale_set_draw_value (GTK_SCALE (axis->scale), FALSE);
+ gtk_grid_attach (GTK_GRID (priv->font_grid), axis->scale, 1, 4 + i, 1, 1);
+ axis->spin = gtk_spin_button_new (axis->adjustment, 0, 0);
+ g_signal_connect (axis->spin, "output", G_CALLBACK (output_cb), fontchooser);
+ gtk_widget_set_valign (axis->spin, GTK_ALIGN_BASELINE);
+ gtk_grid_attach (GTK_GRID (priv->font_grid), axis->spin, 2, 4 + i, 1, 1);
+
+ g_hash_table_add (priv->axes, axis);
+
+ adjustment_changed (axis->adjustment, axis);
+ g_signal_connect (axis->adjustment, "value-changed", G_CALLBACK (adjustment_changed), axis);
+}
+
+static void
+gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchooser)
+{
+ GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
+ PangoFont *pango_font;
+ FT_Face ft_face;
+ FT_MM_Var *ft_mm_var;
+ FT_Error ret;
+
+ if (priv->updating_variations)
+ return;
+
+ g_hash_table_remove_all (priv->axes);
+
+ 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));
+ ret = FT_Get_MM_Var (ft_face, &ft_mm_var);
+ if (ret == 0)
+ {
+ int i;
+ int pos;
+ FT_Fixed *coords;
+
+ coords = g_new (FT_Fixed, ft_mm_var->num_axis);
+ ret = FT_Get_Var_Design_Coordinates (ft_face, ft_mm_var->num_axis, coords);
+ if (ret == 0)
+ {
+ pos = 0;
+ for (i = 0; i < ft_mm_var->num_axis; i++)
+ {
+ if (should_show_axis (&ft_mm_var->axis[i]))
+ {
+ add_axis (fontchooser, &ft_mm_var->axis[i], coords[i], pos);
+ pos++;
+ }
+ }
+ }
+ g_free (coords);
+ free (ft_mm_var);
+ }
+
+ pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
+ g_object_unref (pango_font);
+}
+
static void
gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
const PangoFontDescription *font_desc,
@@ -1280,6 +1503,8 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser
}
gtk_font_chooser_widget_update_preview_attributes (fontchooser);
+ if (iter)
+ gtk_font_chooser_widget_update_font_variations (fontchooser);
g_object_notify (G_OBJECT (fontchooser), "font");
g_object_notify (G_OBJECT (fontchooser), "font-desc");
diff --git a/gtk/ui/gtkfontchooserwidget.ui b/gtk/ui/gtkfontchooserwidget.ui
index 7bf0fc9..abf0d87 100644
--- a/gtk/ui/gtkfontchooserwidget.ui
+++ b/gtk/ui/gtkfontchooserwidget.ui
@@ -61,7 +61,7 @@
<object class="GtkStack" id="list_stack">
<property name="visible">1</property>
<child>
- <object class="GtkGrid">
+ <object class="GtkGrid" id="font_grid">
<property name="visible">1</property>
<property name="row-spacing">6</property>
<property name="column-spacing">6</property>
@@ -108,7 +108,7 @@
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
- <property name="width">2</property>
+ <property name="width">3</property>
</packing>
</child>
<child>
@@ -121,7 +121,19 @@
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
- <property name="width">2</property>
+ <property name="width">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">1</property>
+ <property name="label" translatable="yes">Size</property>
+ <property name="xalign">0</property>
+ <property name="valign">baseline</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
</packing>
</child>
<child>
@@ -135,7 +147,7 @@
<signal name="scroll-event" handler="resize_by_scroll_cb" swapped="no"/>
</object>
<packing>
- <property name="left-attach">0</property>
+ <property name="left-attach">1</property>
<property name="top-attach">3</property>
</packing>
</child>
@@ -147,7 +159,7 @@
<signal name="output" handler="output_cb"/>
</object>
<packing>
- <property name="left-attach">1</property>
+ <property name="left-attach">2</property>
<property name="top-attach">3</property>
</packing>
</child>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]