[gtk/label-cache-extents] label: Cache extents
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/label-cache-extents] label: Cache extents
- Date: Thu, 12 Nov 2020 02:31:01 +0000 (UTC)
commit e7b76f7308357e8269d1dfc91483d3addd375bcc
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Nov 11 19:29:59 2020 -0500
label: Cache extents
When a label has width-chars or max-width-chars set, we end
up calling pango_layout_set_width() on the layout once or
twice, just for measuring. This causes pango to redo all
its work. We can avoid this by caching a few sizes.
gtk/gtklabel.c | 103 +++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 70 insertions(+), 33 deletions(-)
---
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 3d82096bfb..18d36a0d32 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -288,6 +288,12 @@ struct _GtkLabel
int width_chars;
int max_width_chars;
int lines;
+
+ struct {
+ int width;
+ int height;
+ int baseline;
+ } cached_extents[3];
};
struct _GtkLabelClass
@@ -472,6 +478,7 @@ static void gtk_label_ensure_select_info (GtkLabel *self);
static void gtk_label_clear_select_info (GtkLabel *self);
static void gtk_label_update_cursor (GtkLabel *self);
static void gtk_label_clear_layout (GtkLabel *self);
+static void gtk_label_clear_cached_extents (GtkLabel *self);
static void gtk_label_ensure_layout (GtkLabel *self);
static void gtk_label_select_region_index (GtkLabel *self,
int anchor_index,
@@ -2580,6 +2587,8 @@ gtk_label_set_width_chars (GtkLabel *self,
if (self->width_chars != n_chars)
{
self->width_chars = n_chars;
+
+ gtk_label_clear_cached_extents (self);
g_object_notify_by_pspec (G_OBJECT (self), label_props[PROP_WIDTH_CHARS]);
gtk_widget_queue_resize (GTK_WIDGET (self));
}
@@ -2619,6 +2628,8 @@ gtk_label_set_max_width_chars (GtkLabel *self,
{
self->max_width_chars = n_chars;
+ gtk_label_clear_cached_extents (self);
+
g_object_notify_by_pspec (G_OBJECT (self), label_props[PROP_MAX_WIDTH_CHARS]);
gtk_widget_queue_resize (GTK_WIDGET (self));
}
@@ -2765,13 +2776,27 @@ gtk_label_finalize (GObject *object)
G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
}
+static void
+gtk_label_clear_cached_extents (GtkLabel *self)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ self->cached_extents[i].width = 0;
+ self->cached_extents[i].height = 0;
+ self->cached_extents[i].baseline = 0;
+ }
+}
+
static void
gtk_label_clear_layout (GtkLabel *self)
{
g_clear_object (&self->layout);
+ gtk_label_clear_cached_extents (self);
}
-/**
+/*
* gtk_label_get_measuring_layout:
* @self: the label
* @existing_layout: %NULL or an existing layout already in use.
@@ -3003,14 +3028,13 @@ get_height_for_width (GtkLabel *self,
}
static int
-get_char_pixels (GtkWidget *self,
- PangoLayout *layout)
+get_char_pixels (GtkWidget *self)
{
PangoContext *context;
PangoFontMetrics *metrics;
int char_width, digit_width;
- context = pango_layout_get_context (layout);
+ context = gtk_widget_get_pango_context (self);
metrics = pango_context_get_metrics (context,
pango_context_get_font_description (context),
pango_context_get_language (context));
@@ -3018,7 +3042,33 @@ get_char_pixels (GtkWidget *self,
digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
pango_font_metrics_unref (metrics);
- return MAX (char_width, digit_width);;
+ return MAX (char_width, digit_width);
+}
+
+static void
+get_cached_extents (GtkLabel *self,
+ PangoLayout **layout,
+ int idx,
+ int for_width,
+ int min_width,
+ PangoRectangle *extents,
+ int *baseline)
+{
+ if (self->cached_extents[idx].width == 0)
+ {
+ *layout = gtk_label_get_measuring_layout (self, *layout, for_width);
+
+ pango_layout_get_extents (*layout, NULL, extents);
+
+ self->cached_extents[idx].width = MAX (extents->width, min_width);
+ self->cached_extents[idx].height = extents->height;
+ self->cached_extents[idx].baseline = pango_layout_get_baseline (*layout) / PANGO_SCALE;
+ }
+
+ extents->x = extents->y = 0;
+ extents->width = self->cached_extents[idx].width;
+ extents->height = self->cached_extents[idx].height;
+ *baseline = self->cached_extents[idx].baseline;
}
static void
@@ -3028,7 +3078,7 @@ gtk_label_get_preferred_layout_size (GtkLabel *self,
int *smallest_baseline,
int *widest_baseline)
{
- PangoLayout *layout;
+ PangoLayout *layout = NULL;
int char_pixels;
/* "width-chars" Hard-coded minimum width:
@@ -3047,43 +3097,30 @@ gtk_label_get_preferred_layout_size (GtkLabel *self,
* width will default to the wrap guess that gtk_label_ensure_layout() does.
*/
- /* Start off with the pixel extents of an as-wide-as-possible layout */
- layout = gtk_label_get_measuring_layout (self, NULL, -1);
-
if (self->width_chars > -1 || self->max_width_chars > -1)
- char_pixels = get_char_pixels (GTK_WIDGET (self), layout);
+ char_pixels = get_char_pixels (GTK_WIDGET (self));
else
char_pixels = 0;
- pango_layout_get_extents (layout, NULL, widest);
- widest->width = MAX (widest->width, char_pixels * self->width_chars);
- widest->x = widest->y = 0;
- *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
+ /* Start off with the pixel extents of an as-wide-as-possible layout */
+ get_cached_extents (self, &layout, 0,
+ -1, char_pixels * self->width_chars,
+ widest, widest_baseline);
if (self->ellipsize || self->wrap)
{
/* a layout with width 0 will be as small as humanly possible */
- layout = gtk_label_get_measuring_layout (self,
- layout,
- self->width_chars > -1 ? char_pixels * self->width_chars
- : 0);
-
- pango_layout_get_extents (layout, NULL, smallest);
- smallest->width = MAX (smallest->width, char_pixels * self->width_chars);
- smallest->x = smallest->y = 0;
-
- *smallest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
+ get_cached_extents (self, &layout, 1,
+ self->width_chars > -1 ? char_pixels * self->width_chars : 0,
+ char_pixels * self->width_chars,
+ smallest, smallest_baseline);
if (self->max_width_chars > -1 && widest->width > char_pixels * self->max_width_chars)
{
- layout = gtk_label_get_measuring_layout (self,
- layout,
- MAX (smallest->width, char_pixels *
self->max_width_chars));
- pango_layout_get_extents (layout, NULL, widest);
- widest->width = MAX (widest->width, char_pixels * self->width_chars);
- widest->x = widest->y = 0;
-
- *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
+ get_cached_extents (self, &layout, 2,
+ MAX (smallest->width, char_pixels * self->max_width_chars),
+ char_pixels * self->width_chars,
+ widest, widest_baseline);
}
if (widest->width < smallest->width)
@@ -3098,7 +3135,7 @@ gtk_label_get_preferred_layout_size (GtkLabel *self,
*smallest_baseline = *widest_baseline;
}
- g_object_unref (layout);
+ g_clear_object (&layout);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]