Hi all Please review the attached patch that will eliminate important performance issue with GtkTreeView described in the bug 168654. http://bugzilla.gnome.org/show_bug.cgi?id=168654 Currently pango layout is created two times for every render call, first to calculate the size of the cell, second time to render layout itself. With this patch layout is cached in cell renderer. It only updates pango attributes responsible to rendering flags while others attributes are not modified. Also it eliminates issue with recalculation of layout width when ellipsize attribute is set.
diff -upr gtk+.old/gtk/gtkcellrenderertext.c gtk+/gtk/gtkcellrenderertext.c --- gtk+.old/gtk/gtkcellrenderertext.c 2006-10-24 15:11:29.000000000 +0400 +++ gtk+/gtk/gtkcellrenderertext.c 2006-10-24 15:34:28.000000000 +0400 @@ -128,6 +128,7 @@ static guint text_cell_renderer_signals typedef struct _GtkCellRendererTextPrivate GtkCellRendererTextPrivate; struct _GtkCellRendererTextPrivate { + PangoLayout *layout; guint single_paragraph : 1; guint language_set : 1; guint markup_set : 1; @@ -170,6 +171,7 @@ gtk_cell_renderer_text_init (GtkCellRend priv->wrap_width = -1; priv->align = PANGO_ALIGN_LEFT; priv->align_set = FALSE; + priv->layout = NULL; } static void @@ -589,6 +591,9 @@ gtk_cell_renderer_text_finalize (GObject if (priv->language) g_object_unref (priv->language); + if (priv->layout) + g_object_unref (priv->layout); + (* G_OBJECT_CLASS (gtk_cell_renderer_text_parent_class)->finalize) (object); } @@ -1314,6 +1319,12 @@ gtk_cell_renderer_text_set_property (GOb G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } + + if (priv->layout != NULL) + { + g_object_unref (priv->layout); + priv->layout = NULL; + } } /** @@ -1347,9 +1358,7 @@ add_attr (PangoAttrList *attr_list, static PangoLayout* get_layout (GtkCellRendererText *celltext, - GtkWidget *widget, - gboolean will_render, - GtkCellRendererState flags) + GtkWidget *widget) { PangoAttrList *attr_list; PangoLayout *layout; @@ -1367,67 +1376,34 @@ get_layout (GtkCellRendererText *celltex pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph); - if (will_render) - { - /* Add options that affect appearance but not size */ - - /* note that background doesn't go here, since it affects - * background_area not the PangoLayout area - */ - - if (celltext->foreground_set - && (flags & GTK_CELL_RENDERER_SELECTED) == 0) - { - PangoColor color; - - color = celltext->foreground; - - add_attr (attr_list, - pango_attr_foreground_new (color.red, color.green, color.blue)); - } - - if (celltext->strikethrough_set) - add_attr (attr_list, - pango_attr_strikethrough_new (celltext->strikethrough)); - } + if (celltext->strikethrough_set) + add_attr (attr_list, + pango_attr_strikethrough_new (celltext->strikethrough)); add_attr (attr_list, pango_attr_font_desc_new (celltext->font)); if (celltext->scale_set && celltext->font_scale != 1.0) add_attr (attr_list, pango_attr_scale_new (celltext->font_scale)); + + if (priv->language_set) + add_attr (attr_list, pango_attr_language_new (priv->language)); if (celltext->underline_set) uline = celltext->underline_style; else uline = PANGO_UNDERLINE_NONE; - - if (priv->language_set) - add_attr (attr_list, pango_attr_language_new (priv->language)); - if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT) - { - switch (uline) - { - case PANGO_UNDERLINE_NONE: - uline = PANGO_UNDERLINE_SINGLE; - break; - - case PANGO_UNDERLINE_SINGLE: - uline = PANGO_UNDERLINE_DOUBLE; - break; - - default: - break; - } - } - if (uline != PANGO_UNDERLINE_NONE) add_attr (attr_list, pango_attr_underline_new (celltext->underline_style)); if (celltext->rise_set) add_attr (attr_list, pango_attr_rise_new (celltext->rise)); + pango_layout_set_attributes (layout, attr_list); + + pango_attr_list_unref (attr_list); + if (priv->ellipsize_set) pango_layout_set_ellipsize (layout, priv->ellipsize); else @@ -1437,12 +1413,6 @@ get_layout (GtkCellRendererText *celltex { pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE); pango_layout_set_wrap (layout, priv->wrap_mode); - - if (pango_layout_get_line_count (layout) == 1) - { - pango_layout_set_width (layout, -1); - pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); - } } else { @@ -1464,10 +1434,6 @@ get_layout (GtkCellRendererText *celltex pango_layout_set_alignment (layout, align); } - pango_layout_set_attributes (layout, attr_list); - - pango_attr_list_unref (attr_list); - return layout; } @@ -1475,7 +1441,6 @@ static void get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, - PangoLayout *layout, gint *x_offset, gint *y_offset, gint *width, @@ -1526,12 +1491,10 @@ get_size (GtkCellRenderer *cell, return; } - if (layout) - g_object_ref (layout); - else - layout = get_layout (celltext, widget, FALSE, 0); + if (priv->layout == NULL) + priv->layout = get_layout (celltext, widget); - pango_layout_get_pixel_extents (layout, NULL, &rect); + pango_layout_get_pixel_extents (priv->layout, NULL, &rect); if (height) *height = cell->ypad * 2 + rect.height; @@ -1539,13 +1502,13 @@ get_size (GtkCellRenderer *cell, /* The minimum size for ellipsized labels is ~ 3 chars */ if (width) { - if (priv->ellipsize || priv->width_chars > 0) + if (priv->ellipsize_set || priv->width_chars > 0) { PangoContext *context; PangoFontMetrics *metrics; gint char_width; - context = pango_layout_get_context (layout); + context = pango_layout_get_context (priv->layout); metrics = pango_context_get_metrics (context, widget->style->font_desc, pango_context_get_language (context)); char_width = pango_font_metrics_get_approximate_char_width (metrics); @@ -1577,8 +1540,6 @@ get_size (GtkCellRenderer *cell, *y_offset = MAX (*y_offset, 0); } } - - g_object_unref (layout); } @@ -1591,11 +1552,73 @@ gtk_cell_renderer_text_get_size (GtkCell gint *width, gint *height) { - get_size (cell, widget, cell_area, NULL, + get_size (cell, widget, cell_area, x_offset, y_offset, width, height); } static void +cell_layout_set_flags (GtkCellRenderer *cell, + GtkCellRendererState flags) +{ + GtkCellRendererText *celltext = (GtkCellRendererText *) cell; + PangoAttrList *attr_list; + GtkCellRendererTextPrivate *priv; + PangoUnderline uline; + + priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell); + g_return_if_fail (priv->layout != NULL); + + if (flags == 0) + return; + + attr_list = pango_layout_get_attributes (priv->layout); + if (attr_list == NULL) + attr_list = pango_attr_list_new (); + else + pango_attr_list_ref (attr_list); + + if (celltext->foreground_set + && (flags & GTK_CELL_RENDERER_SELECTED) == 0) + { + PangoColor color; + + color = celltext->foreground; + + add_attr (attr_list, + pango_attr_foreground_new (color.red, color.green, color.blue)); + } + + if (celltext->underline_set) + uline = celltext->underline_style; + else + uline = PANGO_UNDERLINE_NONE; + + if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT) + { + switch (uline) + { + case PANGO_UNDERLINE_NONE: + uline = PANGO_UNDERLINE_SINGLE; + break; + + case PANGO_UNDERLINE_SINGLE: + uline = PANGO_UNDERLINE_DOUBLE; + break; + + default: + break; + } + add_attr (attr_list, pango_attr_underline_new (celltext->underline_style)); + } + + pango_layout_set_attributes (priv->layout, attr_list); + + pango_attr_list_unref (attr_list); + + return; +} + +static void gtk_cell_renderer_text_render (GtkCellRenderer *cell, GdkDrawable *window, GtkWidget *widget, @@ -1606,7 +1629,6 @@ gtk_cell_renderer_text_render (GtkCellRe { GtkCellRendererText *celltext = (GtkCellRendererText *) cell; - PangoLayout *layout; GtkStateType state; gint x_offset; gint y_offset; @@ -1614,8 +1636,16 @@ gtk_cell_renderer_text_render (GtkCellRe priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell); - layout = get_layout (celltext, widget, TRUE, flags); - get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL); + if (priv->layout == NULL); + priv->layout = get_layout (celltext, widget); + + if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) + pango_layout_set_width (priv->layout, + (cell_area->width - x_offset - 2 * cell->xpad) * PANGO_SCALE); + + cell_layout_set_flags (cell, flags); + + get_size (cell, widget, cell_area, &x_offset, &y_offset, NULL, NULL); if (!cell->sensitive) { @@ -1662,12 +1692,6 @@ gtk_cell_renderer_text_render (GtkCellRe cairo_destroy (cr); } - if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) - pango_layout_set_width (layout, - (cell_area->width - x_offset - 2 * cell->xpad) * PANGO_SCALE); - else if (priv->wrap_width == -1) - pango_layout_set_width (layout, -1); - gtk_paint_layout (widget->style, window, state, @@ -1677,9 +1701,7 @@ gtk_cell_renderer_text_render (GtkCellRe "cellrenderertext", cell_area->x + x_offset + cell->xpad, cell_area->y + y_offset + cell->ypad, - layout); - - g_object_unref (layout); + priv->layout); } static void
Attachment:
signature.asc
Description: =?koi8-r?Q?=FC=D4=C1?= =?koi8-r?Q?_=DE=C1=D3=D4=D8?= =?koi8-r?Q?_=D3=CF=CF=C2=DD=C5=CE=C9=D1?= =?koi8-r?Q?_=D0=CF=C4=D0=C9=D3=C1=CE=C1?= =?koi8-r?Q?_=C3=C9=C6=D2=CF=D7=CF=CA?= =?koi8-r?Q?_=D0=CF=C4=D0=C9=D3=D8=C0?=