fontchooserwidget: Refactor code so we actually optimize

Previously, we would pango_font_describe() every time the code ran and
we wouldn't ever hit the optimized quick exit.

The code now is a lot more complex because the
compute-actual-value-when-required-the-first-time approach is not
supported out of the box in GtkTreeModel (or GValue).
This commit is contained in:
Benjamin Otte 2015-07-22 15:04:34 +02:00
parent 3fc5d09890
commit 31191d5566
2 changed files with 106 additions and 60 deletions

View File

@ -145,9 +145,9 @@ static void gtk_font_chooser_widget_set_font (GtkFontChooserWidget *
const gchar *fontname);
static PangoFontDescription *gtk_font_chooser_widget_get_font_desc (GtkFontChooserWidget *fontchooser);
static void gtk_font_chooser_widget_merge_font_desc(GtkFontChooserWidget *fontchooser,
PangoFontDescription *font_desc,
GtkTreeIter *iter);
static void gtk_font_chooser_widget_merge_font_desc(GtkFontChooserWidget *fontchooser,
const PangoFontDescription *font_desc,
GtkTreeIter *iter);
static void gtk_font_chooser_widget_take_font_desc (GtkFontChooserWidget *fontchooser,
PangoFontDescription *font_desc);
@ -179,6 +179,63 @@ G_DEFINE_TYPE_WITH_CODE (GtkFontChooserWidget, gtk_font_chooser_widget, GTK_TYPE
G_IMPLEMENT_INTERFACE (GTK_TYPE_FONT_CHOOSER,
gtk_font_chooser_widget_iface_init))
typedef struct _GtkDelayedFontDescription GtkDelayedFontDescription;
struct _GtkDelayedFontDescription {
PangoFontFace *face;
PangoFontDescription *desc;
guint ref_count;
};
static GtkDelayedFontDescription *
gtk_delayed_font_description_new (PangoFontFace *face)
{
GtkDelayedFontDescription *result;
result = g_slice_new0 (GtkDelayedFontDescription);
result->face = g_object_ref (face);
result->desc = NULL;
result->ref_count = 1;
return result;
}
static GtkDelayedFontDescription *
gtk_delayed_font_description_ref (GtkDelayedFontDescription *desc)
{
desc->ref_count++;
return desc;
}
static void
gtk_delayed_font_description_unref (GtkDelayedFontDescription *desc)
{
desc->ref_count--;
if (desc->ref_count > 0)
return;
g_object_unref (desc->face);
if (desc->desc)
pango_font_description_free (desc->desc);
g_slice_free (GtkDelayedFontDescription, desc);
}
static const PangoFontDescription *
gtk_delayed_font_description_get (GtkDelayedFontDescription *desc)
{
if (desc->desc == NULL)
desc->desc = pango_font_face_describe (desc->face);
return desc->desc;
}
#define GTK_TYPE_DELAYED_FONT_DESCRIPTION (gtk_delayed_font_description_get_type ())
G_DEFINE_BOXED_TYPE (GtkDelayedFontDescription, gtk_delayed_font_description,
gtk_delayed_font_description_ref,
gtk_delayed_font_description_unref)
static void
gtk_font_chooser_widget_set_property (GObject *object,
guint prop_id,
@ -379,39 +436,13 @@ row_activated_cb (GtkTreeView *view,
g_free (fontname);
}
static PangoFontDescription *
tree_model_get_font_description (GtkTreeModel *model,
GtkTreeIter *iter)
{
PangoFontDescription *desc, *face_desc;
PangoFontFace *face;
gtk_tree_model_get (model, iter,
FONT_DESC_COLUMN, &desc,
-1);
if (pango_font_description_get_set_fields (desc) != 0)
return desc;
gtk_tree_model_get (model, iter,
FACE_COLUMN, &face,
-1);
face_desc = pango_font_face_describe (face);
g_object_unref (face);
pango_font_description_merge (desc, face_desc, TRUE);
pango_font_description_free (face_desc);
return desc;
}
static void
cursor_changed_cb (GtkTreeView *treeview,
gpointer user_data)
{
GtkFontChooserWidget *fontchooser = user_data;
GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
PangoFontDescription *desc;
GtkDelayedFontDescription *desc;
GtkTreeIter filter_iter, iter;
GtkTreePath *path = NULL;
@ -431,9 +462,15 @@ cursor_changed_cb (GtkTreeView *treeview,
gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (priv->filter_model),
&iter,
&filter_iter);
desc = tree_model_get_font_description (priv->model, &iter);
gtk_tree_model_get (priv->filter_model, &iter,
FONT_DESC_COLUMN, &desc,
-1);
gtk_font_chooser_widget_merge_font_desc (fontchooser, desc, &iter);
gtk_font_chooser_widget_merge_font_desc (fontchooser,
gtk_delayed_font_description_get (desc),
&iter);
gtk_delayed_font_description_unref (desc);
}
static gboolean
@ -515,6 +552,8 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
g_type_ensure (GTK_TYPE_DELAYED_FONT_DESCRIPTION);
widget_class->screen_changed = gtk_font_chooser_widget_screen_changed;
widget_class->style_updated = gtk_font_chooser_widget_style_updated;
@ -676,23 +715,23 @@ gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser,
for (j = 0; j < n_faces; j++)
{
PangoFontDescription *empty_font_desc;
GtkDelayedFontDescription *desc;
const gchar *face_name;
face_name = pango_font_face_get_face_name (faces[j]);
family_and_face = g_strconcat (fam_name, " ", face_name, NULL);
empty_font_desc = pango_font_description_new ();
desc = gtk_delayed_font_description_new (faces[j]);
gtk_list_store_insert_with_values (list_store, &iter, -1,
FAMILY_COLUMN, families[i],
FACE_COLUMN, faces[j],
FONT_DESC_COLUMN, empty_font_desc,
FONT_DESC_COLUMN, desc,
PREVIEW_TITLE_COLUMN, family_and_face,
-1);
g_free (family_and_face);
pango_font_description_free (empty_font_desc);
gtk_delayed_font_description_unref (desc);
}
g_free (faces);
@ -830,22 +869,21 @@ gtk_font_chooser_widget_cell_data_func (GtkTreeViewColumn *column,
gpointer user_data)
{
GtkFontChooserWidget *fontchooser = user_data;
PangoFontDescription *font_desc;
GtkDelayedFontDescription *desc;
PangoAttrList *attrs;
char *preview_title, *text;
gsize first_line_len;
font_desc = tree_model_get_font_description (tree_model, iter);
gtk_tree_model_get (tree_model, iter,
PREVIEW_TITLE_COLUMN, &preview_title,
FONT_DESC_COLUMN, &desc,
-1);
text = g_strconcat (preview_title, "\n", fontchooser->priv->preview_text, NULL);
first_line_len = strlen (preview_title) + 1;
attrs = gtk_font_chooser_widget_get_preview_attributes (fontchooser,
font_desc,
gtk_delayed_font_description_get (desc),
first_line_len);
g_object_set (cell,
@ -853,7 +891,7 @@ gtk_font_chooser_widget_cell_data_func (GtkTreeViewColumn *column,
"text", text,
NULL);
pango_font_description_free (font_desc);
gtk_delayed_font_description_unref (desc);
pango_attr_list_unref (attrs);
g_free (text);
g_free (preview_title);
@ -928,26 +966,37 @@ gtk_font_chooser_widget_find_font (GtkFontChooserWidget *fontchooser,
valid;
valid = gtk_tree_model_iter_next (priv->model, iter))
{
PangoFontDescription *desc;
GtkDelayedFontDescription *desc;
PangoFontDescription *merged;
PangoFontFamily *family;
gtk_tree_model_get (priv->model, iter,
FAMILY_COLUMN, &family,
FONT_DESC_COLUMN, &desc,
-1);
if (!my_pango_font_family_equal (pango_font_description_get_family (font_desc),
pango_font_family_get_name (family)))
continue;
{
gtk_delayed_font_description_unref (desc);
g_object_unref (family);
continue;
}
desc = tree_model_get_font_description (priv->model, iter);
merged = pango_font_description_copy_static (gtk_delayed_font_description_get (desc));
pango_font_description_merge_static (desc, font_desc, FALSE);
if (pango_font_description_equal (desc, font_desc)) {
pango_font_description_free (desc);
break;
}
pango_font_description_merge_static (merged, font_desc, FALSE);
if (pango_font_description_equal (merged, font_desc))
{
gtk_delayed_font_description_unref (desc);
pango_font_description_free (merged);
g_object_unref (family);
break;
}
pango_font_description_free (desc);
gtk_delayed_font_description_unref (desc);
pango_font_description_free (merged);
g_object_unref (family);
}
return valid;
@ -1092,9 +1141,9 @@ gtk_font_chooser_widget_ensure_selection (GtkFontChooserWidget *fontchooser)
}
static void
gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
PangoFontDescription *font_desc,
GtkTreeIter *iter)
gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
const PangoFontDescription *font_desc,
GtkTreeIter *iter)
{
GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
PangoFontMask mask;
@ -1107,10 +1156,7 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
/* sucky test, because we can't restrict the comparison to
* only the parts that actually do get merged */
if (pango_font_description_equal (font_desc, priv->font_desc))
{
pango_font_description_free (font_desc);
return;
}
return;
pango_font_description_merge (priv->font_desc, font_desc, TRUE);
@ -1140,8 +1186,6 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser,
gtk_font_chooser_widget_update_preview_attributes (fontchooser);
pango_font_description_free (font_desc); /* adopted */
g_object_notify (G_OBJECT (fontchooser), "font");
g_object_notify (G_OBJECT (fontchooser), "font-desc");
}
@ -1171,6 +1215,8 @@ gtk_font_chooser_widget_take_font_desc (GtkFontChooserWidget *fontchooser,
{
gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc, &priv->font_iter);
}
pango_font_description_free (font_desc);
}
static const gchar*

View File

@ -8,7 +8,7 @@
<!-- column-name face -->
<column type="PangoFontFace"/>
<!-- column-name description -->
<column type="PangoFontDescription"/>
<column type="GtkDelayedFontDescription"/>
<!-- column-name preview-title -->
<column type="gchararray"/>
</columns>