Patch for [Bug 168654] GtkCellRendererText re-creates PangoLayouts



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?=



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]