[gtk+/optimize-height-for-width: 3/4] Cache heights-for-range-of-widths instead of height for every width.



commit d9183a133eda663bb36e54d22f573c7dff5688d6
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sun Mar 6 15:13:56 2011 +0900

    Cache heights-for-range-of-widths instead of height for every width.
    
    This patch optimizes window resizes by assuming that if a widget
    has the same height at a width of 50 as with a width of 150, the
    height for width 100 will also be the same.
    
    The patch also further optimizes the cache allocator, now there
    are 2 pointer arrays of up to a maximum of 5 requests, the arrays
    will only be allocated if a request is ever made in that orientation
    and the array will be sparse until each request is made (i.e. if a
    label can only wrap to 3 lines, there will only be 3 out of a
    possible 5 SizeRequest structures allocated to cache it).

 gtk/gtksizerequest.c   |  411 ++++++++++++++++++++++++++++--------------------
 gtk/gtkwidget.c        |    3 +-
 gtk/gtkwidgetprivate.h |   42 +++---
 3 files changed, 264 insertions(+), 192 deletions(-)
---
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c
index b27fd05..95cf2fa 100644
--- a/gtk/gtksizerequest.c
+++ b/gtk/gtksizerequest.c
@@ -31,126 +31,235 @@
 #include "gtksizegroup-private.h"
 #include "gtkwidgetprivate.h"
 
-/* looks for a cached size request for this for_size. If not
- * found, returns the oldest entry so it can be overwritten
- *
- * Note that this caching code was originally derived from
- * the Clutter toolkit.
- */
 
+#ifndef G_DISABLE_CHECKS
+static GQuark recursion_check_quark = 0;
+#endif /* G_DISABLE_CHECKS */
+
+static void
+push_recursion_check (GtkWidget       *widget,
+                      GtkSizeGroupMode orientation,
+                      gint             for_size)
+{
+#ifndef G_DISABLE_CHECKS
+  const char *previous_method;
+  const char *method;
+
+  if (recursion_check_quark == 0)
+    recursion_check_quark = g_quark_from_static_string ("gtk-size-request-in-progress");
+
+  previous_method = g_object_get_qdata (G_OBJECT (widget), recursion_check_quark);
+
+  if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
+    {
+      method = for_size < 0 ? "get_width" : "get_width_for_height";
+    }
+  else
+    {
+      method = for_size < 0 ? "get_height" : "get_height_for_width";
+    }
+
+  if (previous_method != NULL)
+    {
+      g_warning ("%s %p: widget tried to gtk_widget_%s inside "
+                 " GtkWidget     ::%s implementation. "
+                 "Should just invoke GTK_WIDGET_GET_CLASS(widget)->%s "
+                 "directly rather than using gtk_widget_%s",
+                 G_OBJECT_TYPE_NAME (widget), widget,
+                 method, previous_method,
+                 method, method);
+    }
+
+  g_object_set_qdata (G_OBJECT (widget), recursion_check_quark, (char*) method);
+#endif /* G_DISABLE_CHECKS */
+}
+
+static void
+pop_recursion_check (GtkWidget       *widget,
+                     GtkSizeGroupMode orientation)
+{
+#ifndef G_DISABLE_CHECKS
+  g_object_set_qdata (G_OBJECT (widget), recursion_check_quark, NULL);
+#endif
+}
+
+
+static void
+clear_cache (SizeRequestCache   *cache,
+	     GtkSizeGroupMode    orientation)
+{
+  SizeRequest **sizes;
+  gint          i;
+
+  if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
+    {
+      sizes = cache->widths;
+
+      cache->widths            = NULL;
+      cache->cached_widths     = 0;
+      cache->last_cached_width = 0;
+      cache->cached_base_width = FALSE;
+    }
+  else
+    {
+      sizes = cache->heights;
+
+      cache->heights            = NULL;
+      cache->cached_heights     = 0;
+      cache->last_cached_height = 0; 
+      cache->cached_base_height = FALSE;
+   }
+
+  if (sizes)
+    {
+      for (i = 0; sizes[i] != NULL; i++)
+	g_slice_free (SizeRequest, sizes[i]);
+      
+      g_slice_free1 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes);
+    }
+}
+
+void
+_gtk_widget_free_cached_sizes (GtkWidget *widget)
+{
+  SizeRequestCache   *cache;
+
+  cache = _gtk_widget_peek_request_cache (widget);
+
+  clear_cache (cache, GTK_SIZE_GROUP_HORIZONTAL);
+  clear_cache (cache, GTK_SIZE_GROUP_VERTICAL);
+}
 
 /* This function checks if 'request_needed' flag is present
  * and resets the cache state if a request is needed for
  * a given orientation.
  */
 static SizeRequestCache *
-init_cache (GtkWidget        *widget,
-	    GtkSizeGroupMode  orientation)
+init_cache (GtkWidget        *widget)
 {
-  GtkSizeRequestMode  mode;
-  SizeRequestCache   *cache;
+  SizeRequestCache *cache;
 
   cache = _gtk_widget_peek_request_cache (widget);
 
-  if (orientation == GTK_SIZE_GROUP_HORIZONTAL &&
-      _gtk_widget_get_width_request_needed (widget))
-    {
-      mode = gtk_widget_get_request_mode (widget);
+  if (_gtk_widget_get_width_request_needed (widget))
+    clear_cache (cache, GTK_SIZE_GROUP_HORIZONTAL);
+  else if (_gtk_widget_get_height_request_needed (widget))
+    clear_cache (cache, GTK_SIZE_GROUP_VERTICAL);
+
+  return cache;
+}
+
+/* looks for a cached size request for this for_size. If not
+ * found, returns the oldest entry so it can be overwritten
+ *
+ * Note that this caching code was originally derived from
+ * the Clutter toolkit but has evolved for other GTK+ requirements.
+ */
+static gboolean
+get_cached_size (GtkWidget         *widget,
+		 GtkSizeGroupMode   orientation,
+		 gint               for_size,
+		 CachedSize       **result)
+{
+  SizeRequestCache  *cache;
+  SizeRequest      **cached_sizes;
+  guint              i, n_sizes;
+
+  cache = init_cache (widget);
 
-      if (mode == GTK_SIZE_REQUEST_CONSTANT_SIZE)
+  if (for_size < 0)
+    {
+      if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
 	{
-	  if (cache->sizes)
-	    {
-	      g_slice_free (ContextualSizes, cache->sizes);
-	      cache->sizes = NULL;
-	    }
+	  *result = &cache->cached_width;
+	  return cache->cached_base_width;
 	}
       else
 	{
-	  if (!cache->sizes)
-	    cache->sizes = g_slice_new0 (ContextualSizes);
-
-          memset (cache->sizes->widths, 0x0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest));
-          cache->sizes->cached_widths     = 0;
-          cache->sizes->last_cached_width = 0;
+	  *result = &cache->cached_height;
+	  return cache->cached_base_height;
 	}
+    }
 
-      cache->cached_width.minimum_size = -1;
-      cache->cached_width.natural_size = -1;
+  if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
+    {
+      cached_sizes = cache->widths;
+      n_sizes      = cache->cached_widths;
     }
-  else if (orientation == GTK_SIZE_GROUP_VERTICAL &&
-	   _gtk_widget_get_height_request_needed (widget))
+  else
     {
-      mode = gtk_widget_get_request_mode (widget);
+      cached_sizes = cache->heights;
+      n_sizes      = cache->cached_heights;
+    }
 
-      if (mode == GTK_SIZE_REQUEST_CONSTANT_SIZE)
-	{
-	  if (cache->sizes)
-	    {
-	      g_slice_free (ContextualSizes, cache->sizes);
-	      cache->sizes = NULL;
-	    }
-	}
-      else
+  /* Search for an already cached size */
+  for (i = 0; i < n_sizes; i++)
+    {
+      if (cached_sizes[i]->lower_for_size <= for_size &&
+	  cached_sizes[i]->upper_for_size >= for_size)
 	{
-	  if (!cache->sizes)
-	    cache->sizes = g_slice_new0 (ContextualSizes);
-
-          memset (cache->sizes->heights, 0x0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest));
-          cache->sizes->cached_heights     = 0;
-          cache->sizes->last_cached_height = 0;
+	  *result = &cached_sizes[i]->cached_size;
+	  return TRUE;
 	}
-
-      cache->cached_height.minimum_size = -1;
-      cache->cached_height.natural_size = -1;
     }
 
-  return cache;
+  return FALSE;
 }
 
-static gboolean
-get_cached_size (GtkWidget         *widget,
-		 GtkSizeGroupMode   orientation,
-		 gint               for_size,
-		 CachedSize       **result)
+static void
+commit_cached_size (GtkWidget         *widget,
+		    GtkSizeGroupMode   orientation,
+		    gint               for_size,
+		    gint               minimum_size,
+		    gint               natural_size)
 {
-  SizeRequestCache *cache;
-  SizeRequest      *cached_sizes;
-  guint             i, n_sizes;
+  SizeRequestCache  *cache;
+  SizeRequest      **cached_sizes;
+  guint              i, n_sizes;
 
-  cache = init_cache (widget, orientation);
+  cache = _gtk_widget_peek_request_cache (widget);
 
+  /* First handle caching of the base requests */
   if (for_size < 0)
     {
       if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
-	*result = &cache->cached_width;
-      else
-	*result = &cache->cached_height;
-
-      if ((*result)->minimum_size < 0)
-	return FALSE;
+	{
+	  cache->cached_width.minimum_size = minimum_size;
+	  cache->cached_width.natural_size = natural_size;
+	  cache->cached_base_width = TRUE;
+	}
       else
-	return TRUE;
+	{
+	  cache->cached_height.minimum_size = minimum_size;
+	  cache->cached_height.natural_size = natural_size;
+	  cache->cached_base_height = TRUE;
+	}
+      return;
     }
 
+  /* Check if the minimum_size and natural_size is already
+   * in the cache and if this result can be used to extend
+   * that cache entry 
+   */
   if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
     {
-      cached_sizes = cache->sizes->widths;
-      n_sizes = cache->sizes->cached_widths;
+      cached_sizes = cache->widths;
+      n_sizes = cache->cached_widths;
     }
   else
     {
-      cached_sizes = cache->sizes->heights;
-      n_sizes = cache->sizes->cached_widths;
+      cached_sizes = cache->heights;
+      n_sizes = cache->cached_heights;
     }
 
-  /* Search for an already cached size */
   for (i = 0; i < n_sizes; i++)
     {
-      if (cached_sizes[i].for_size == for_size)
+      if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
+	  cached_sizes[i]->cached_size.natural_size == natural_size)
 	{
-	  *result = &cached_sizes[i].cached_size;
-	  return TRUE;
+	  cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
+	  cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
+	  return;
 	}
     }
 
@@ -159,90 +268,52 @@ get_cached_size (GtkWidget         *widget,
    * and increment the last_cached_width/height right away */
   if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
     {
-      if (cache->sizes->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES)
+      if (cache->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES)
 	{
-	  cache->sizes->cached_widths++;
-	  cache->sizes->last_cached_width = cache->sizes->cached_widths - 1;
+	  cache->cached_widths++;
+	  cache->last_cached_width = cache->cached_widths - 1;
 	}
       else
 	{
-	  if (++cache->sizes->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES)
-	    cache->sizes->last_cached_width = 0;
+	  if (++cache->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES)
+	    cache->last_cached_width = 0;
 	}
 
-      cache->sizes->widths[cache->sizes->last_cached_width].for_size = for_size;
-      *result = &cache->sizes->widths[cache->sizes->last_cached_width].cached_size;
+      if (!cache->widths)
+	cache->widths = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
+
+      if (!cache->widths[cache->last_cached_width])
+	cache->widths[cache->last_cached_width] = g_slice_new (SizeRequest);
+
+      cache->widths[cache->last_cached_width]->lower_for_size = for_size;
+      cache->widths[cache->last_cached_width]->upper_for_size = for_size;
+      cache->widths[cache->last_cached_width]->cached_size.minimum_size = minimum_size;
+      cache->widths[cache->last_cached_width]->cached_size.natural_size = natural_size;
     }
   else /* GTK_SIZE_GROUP_VERTICAL */
     {
-      if (cache->sizes->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES)
+      if (cache->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES)
 	{
-	  cache->sizes->cached_heights++;
-	  cache->sizes->last_cached_height = cache->sizes->cached_heights - 1;
+	  cache->cached_heights++;
+	  cache->last_cached_height = cache->cached_heights - 1;
 	}
       else
 	{
-	  if (++cache->sizes->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES)
-	    cache->sizes->last_cached_height = 0;
+	  if (++cache->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES)
+	    cache->last_cached_height = 0;
 	}
 
-      cache->sizes->heights[cache->sizes->last_cached_height].for_size = for_size;
-      *result = &cache->sizes->heights[cache->sizes->last_cached_height].cached_size;
-    }
-
-  return FALSE;
-}
-
+      if (!cache->heights)
+	cache->heights = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
 
-#ifndef G_DISABLE_CHECKS
-static GQuark recursion_check_quark = 0;
-#endif /* G_DISABLE_CHECKS */
+      if (!cache->heights[cache->last_cached_height])
+	cache->heights[cache->last_cached_height] = g_slice_new (SizeRequest);
 
-static void
-push_recursion_check (GtkWidget       *widget,
-                      GtkSizeGroupMode orientation,
-                      gint             for_size)
-{
-#ifndef G_DISABLE_CHECKS
-  const char *previous_method;
-  const char *method;
-
-  if (recursion_check_quark == 0)
-    recursion_check_quark = g_quark_from_static_string ("gtk-size-request-in-progress");
-
-  previous_method = g_object_get_qdata (G_OBJECT (widget), recursion_check_quark);
-
-  if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
-    {
-      method = for_size < 0 ? "get_width" : "get_width_for_height";
-    }
-  else
-    {
-      method = for_size < 0 ? "get_height" : "get_height_for_width";
-    }
-
-  if (previous_method != NULL)
-    {
-      g_warning ("%s %p: widget tried to gtk_widget_%s inside "
-                 " GtkWidget     ::%s implementation. "
-                 "Should just invoke GTK_WIDGET_GET_CLASS(widget)->%s "
-                 "directly rather than using gtk_widget_%s",
-                 G_OBJECT_TYPE_NAME (widget), widget,
-                 method, previous_method,
-                 method, method);
+      cache->heights[cache->last_cached_height]->lower_for_size = for_size;
+      cache->heights[cache->last_cached_height]->upper_for_size = for_size;
+      cache->heights[cache->last_cached_height]->cached_size.minimum_size = minimum_size;
+      cache->heights[cache->last_cached_height]->cached_size.natural_size = natural_size;
     }
-
-  g_object_set_qdata (G_OBJECT (widget), recursion_check_quark, (char*) method);
-#endif /* G_DISABLE_CHECKS */
-}
-
-static void
-pop_recursion_check (GtkWidget       *widget,
-                     GtkSizeGroupMode orientation)
-{
-#ifndef G_DISABLE_CHECKS
-  g_object_set_qdata (G_OBJECT (widget), recursion_check_quark, NULL);
-#endif
 }
 
 /* This is the main function that checks for a cached size and
@@ -259,14 +330,14 @@ compute_size_for_orientation (GtkWidget         *widget,
 {
   CachedSize       *cached_size;
   gboolean          found_in_cache = FALSE;
-  gint              adjusted_min, adjusted_natural;
+  gint              min_size = 0;
+  gint              nat_size = 0;
 
   found_in_cache = get_cached_size (widget, orientation, for_size, &cached_size);
 
   if (!found_in_cache)
     {
-      gint min_size = 0;
-      gint nat_size = 0;
+      gint adjusted_min, adjusted_natural, adjusted_for_size = for_size;
 
       if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
         {
@@ -292,11 +363,11 @@ compute_size_for_orientation (GtkWidget         *widget,
                                                                      &minimum_height,
 								     &natural_height,
                                                                      &ignored_position,
-                                                                     &for_size);
+                                                                     &adjusted_for_size);
 
 	      push_recursion_check (widget, orientation, for_size);
               GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, 
-									     MAX (for_size, minimum_height),
+									     MAX (adjusted_for_size, minimum_height),
 									     &min_size, &nat_size);
 	      pop_recursion_check (widget, orientation);
             }
@@ -311,9 +382,9 @@ compute_size_for_orientation (GtkWidget         *widget,
             }
           else
             {
-              int ignored_position = 0;
-              int minimum_width;
-              int natural_width;
+              gint ignored_position = 0;
+              gint minimum_width;
+              gint natural_width;
 
 	      /* Pull the base natural width from the cache as it's needed to adjust
 	       * the proposed 'for_size' */
@@ -325,11 +396,11 @@ compute_size_for_orientation (GtkWidget         *widget,
 								     &minimum_width,
                                                                      &natural_width,
                                                                      &ignored_position,
-                                                                     &for_size);
+                                                                     &adjusted_for_size);
 
 	      push_recursion_check (widget, orientation, for_size);
               GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, 
-									     MAX (for_size, minimum_width),
+									     MAX (adjusted_for_size, minimum_width),
 									     &min_size, &nat_size);
 	      pop_recursion_check (widget, orientation);
             }
@@ -341,16 +412,13 @@ compute_size_for_orientation (GtkWidget         *widget,
                      G_OBJECT_TYPE_NAME (widget), widget, min_size, nat_size);
         }
 
-      cached_size->minimum_size = min_size;
-      cached_size->natural_size = nat_size;
-
       if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
           _gtk_widget_set_width_request_needed (widget, FALSE);
       else
           _gtk_widget_set_height_request_needed (widget, FALSE);
 
-      adjusted_min = cached_size->minimum_size;
-      adjusted_natural = cached_size->natural_size;
+      adjusted_min     = min_size;
+      adjusted_natural = nat_size;
       GTK_WIDGET_GET_CLASS (widget)->adjust_size_request (widget,
                                                           orientation == GTK_SIZE_GROUP_HORIZONTAL ?
                                                           GTK_ORIENTATION_HORIZONTAL :
@@ -358,14 +426,14 @@ compute_size_for_orientation (GtkWidget         *widget,
                                                           &adjusted_min,
                                                           &adjusted_natural);
 
-      if (adjusted_min < cached_size->minimum_size ||
-          adjusted_natural < cached_size->natural_size)
+      if (adjusted_min < min_size ||
+          adjusted_natural < nat_size)
         {
           g_warning ("%s %p adjusted size %s min %d natural %d must not decrease below min %d natural %d",
                      G_OBJECT_TYPE_NAME (widget), widget,
                      orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal",
                      adjusted_min, adjusted_natural,
-                     cached_size->minimum_size, cached_size->natural_size);
+                     min_size, nat_size);
           /* don't use the adjustment */
         }
       else if (adjusted_min > adjusted_natural)
@@ -374,14 +442,14 @@ compute_size_for_orientation (GtkWidget         *widget,
                      G_OBJECT_TYPE_NAME (widget), widget,
                      orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal",
                      adjusted_min, adjusted_natural,
-                     cached_size->minimum_size, cached_size->natural_size);
+                     min_size, nat_size);
           /* don't use the adjustment */
         }
       else
         {
           /* adjustment looks good */
-          cached_size->minimum_size = adjusted_min;
-          cached_size->natural_size = adjusted_natural;
+          min_size = adjusted_min;
+          nat_size = adjusted_natural;
         }
 
       /* Update size-groups with our request and update our cached requests
@@ -389,26 +457,31 @@ compute_size_for_orientation (GtkWidget         *widget,
        */
       _gtk_size_group_bump_requisition (widget,
 					orientation,
-					&cached_size->minimum_size,
-					&cached_size->natural_size);
+					&min_size,
+					&nat_size);
+
+      commit_cached_size (widget, orientation, for_size, min_size, nat_size);
+    }
+  else
+    {
+      min_size = cached_size->minimum_size;
+      nat_size = cached_size->natural_size;
     }
 
   if (minimum_size)
-    *minimum_size = cached_size->minimum_size;
+    *minimum_size = min_size;
 
   if (natural_size)
-    *natural_size = cached_size->natural_size;
+    *natural_size = nat_size;
 
-  g_assert (cached_size->minimum_size <= cached_size->natural_size);
+  g_assert (min_size <= nat_size);
 
   GTK_NOTE (SIZE_REQUEST,
             g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d (hit cache: %s)\n",
                      widget, G_OBJECT_TYPE_NAME (widget),
                      orientation == GTK_SIZE_GROUP_HORIZONTAL ?
                      "width for height" : "height for width" ,
-                     for_size,
-                     cached_size->minimum_size,
-                     cached_size->natural_size,
+                     for_size, min_size, nat_size,
                      found_in_cache ? "yes" : "no"));
 
 }
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 1162d68..ab96a15 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -10670,8 +10670,7 @@ gtk_widget_finalize (GObject *object)
   if (priv->context)
     g_object_unref (priv->context);
 
-  if (priv->requests.sizes)
-    g_slice_free (ContextualSizes, priv->requests.sizes);
+  _gtk_widget_free_cached_sizes (widget);
 
   if (g_object_is_floating (object))
     g_warning ("A floating object was finalized. This means that someone\n"
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index 9dfec65..7d298c6 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -29,12 +29,13 @@
 
 G_BEGIN_DECLS
 
-/* With GtkWidget, a widget may be requested
- * its width for 2 or maximum 3 heights in one resize
- * (Note this define is limited by the bitfield sizes
- * defined on the SizeRequestCache structure).
+/* Cache as many ranges of height-for-width
+ * (or width-for-height) as can be rational
+ * for a said widget to have, if a label can
+ * only wrap to 3 lines, only 3 caches will
+ * ever be allocated for it.
  */
-#define GTK_SIZE_REQUEST_CACHED_SIZES   (2)
+#define GTK_SIZE_REQUEST_CACHED_SIZES   (5)
 
 typedef struct {
   gint minimum_size;
@@ -43,26 +44,24 @@ typedef struct {
 
 typedef struct
 {
-  /* the size this request is for */
-  gint       for_size;
+  gint       lower_for_size; /* The minimum for_size with the same result */
+  gint       upper_for_size; /* The maximum for_size with the same result */
   CachedSize cached_size;
 } SizeRequest;
 
 typedef struct {
-  SizeRequest widths[GTK_SIZE_REQUEST_CACHED_SIZES];
-  SizeRequest heights[GTK_SIZE_REQUEST_CACHED_SIZES];
-
-  guint       cached_widths      : 2;
-  guint       cached_heights     : 2;
-  guint       last_cached_width  : 2;
-  guint       last_cached_height : 2;
-} ContextualSizes;
-
-typedef struct {
-  ContextualSizes *sizes;
-
-  CachedSize cached_width;
-  CachedSize cached_height;
+  SizeRequest **widths;
+  SizeRequest **heights;
+
+  CachedSize  cached_width;
+  CachedSize  cached_height;
+
+  guint       cached_widths      : 3;
+  guint       cached_heights     : 3;
+  guint       last_cached_width  : 3;
+  guint       last_cached_height : 3;
+  guint       cached_base_width  : 1;
+  guint       cached_base_height : 1;
 } SizeRequestCache;
 
 void         _gtk_widget_set_visible_flag   (GtkWidget *widget,
@@ -114,6 +113,7 @@ gboolean _gtk_widget_get_translation_to_window (GtkWidget      *widget,
                                                 GdkWindow      *window,
                                                 int            *x,
                                                 int            *y);
+void     _gtk_widget_free_cached_sizes (GtkWidget *widget);
 
 G_END_DECLS
 



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