Reduce memory consumption of the size request cache.

This patch makes contextual height-for-width request caching
optional (the contextual cache is not allocated for widgets that
report GTK_SIZE_REQUEST_CONSTANT_SIZE).
This commit is contained in:
Tristan Van Berkom 2011-03-05 19:29:10 +09:00
parent 887142f1f5
commit 82ae7b77ca
3 changed files with 132 additions and 59 deletions

View File

@ -34,27 +34,114 @@
/* looks for a cached size request for this for_size. If not /* looks for a cached size request for this for_size. If not
* found, returns the oldest entry so it can be overwritten * found, returns the oldest entry so it can be overwritten
* *
* Note that this caching code was directly derived from * Note that this caching code was originally derived from
* the Clutter toolkit. * the Clutter toolkit.
*/ */
/* 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)
{
GtkSizeRequestMode mode;
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 (mode == GTK_SIZE_REQUEST_CONSTANT_SIZE)
{
if (cache->sizes)
{
g_slice_free (ContextualSizes, cache->sizes);
cache->sizes = NULL;
}
}
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;
}
cache->cached_width.minimum_size = -1;
cache->cached_width.natural_size = -1;
}
else if (orientation == GTK_SIZE_GROUP_VERTICAL &&
_gtk_widget_get_height_request_needed (widget))
{
mode = gtk_widget_get_request_mode (widget);
if (mode == GTK_SIZE_REQUEST_CONSTANT_SIZE)
{
if (cache->sizes)
{
g_slice_free (ContextualSizes, cache->sizes);
cache->sizes = NULL;
}
}
else
{
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;
}
cache->cached_height.minimum_size = -1;
cache->cached_height.natural_size = -1;
}
return cache;
}
static gboolean static gboolean
get_cached_size (SizeRequestCache *cache, get_cached_size (GtkWidget *widget,
GtkSizeGroupMode orientation, GtkSizeGroupMode orientation,
gint for_size, gint for_size,
SizeRequest **result) CachedSize **result)
{ {
guint i, n_sizes; SizeRequestCache *cache;
SizeRequest *cached_sizes; SizeRequest *cached_sizes;
guint i, n_sizes;
cache = init_cache (widget, orientation);
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;
else
return TRUE;
}
if (orientation == GTK_SIZE_GROUP_HORIZONTAL) if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{ {
cached_sizes = cache->widths; cached_sizes = cache->sizes->widths;
n_sizes = cache->cached_widths; n_sizes = cache->sizes->cached_widths;
} }
else else
{ {
cached_sizes = cache->heights; cached_sizes = cache->sizes->heights;
n_sizes = cache->cached_widths; n_sizes = cache->sizes->cached_widths;
} }
/* Search for an already cached size */ /* Search for an already cached size */
@ -62,7 +149,7 @@ get_cached_size (SizeRequestCache *cache,
{ {
if (cached_sizes[i].for_size == for_size) if (cached_sizes[i].for_size == for_size)
{ {
*result = &cached_sizes[i]; *result = &cached_sizes[i].cached_size;
return TRUE; return TRUE;
} }
} }
@ -72,33 +159,35 @@ get_cached_size (SizeRequestCache *cache,
* and increment the last_cached_width/height right away */ * and increment the last_cached_width/height right away */
if (orientation == GTK_SIZE_GROUP_HORIZONTAL) if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{ {
if (cache->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES) if (cache->sizes->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES)
{ {
cache->cached_widths++; cache->sizes->cached_widths++;
cache->last_cached_width = cache->cached_widths - 1; cache->sizes->last_cached_width = cache->sizes->cached_widths - 1;
} }
else else
{ {
if (++cache->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES) if (++cache->sizes->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES)
cache->last_cached_width = 0; cache->sizes->last_cached_width = 0;
} }
*result = &cache->widths[cache->last_cached_width]; cache->sizes->widths[cache->sizes->last_cached_width].for_size = for_size;
*result = &cache->sizes->widths[cache->sizes->last_cached_width].cached_size;
} }
else /* GTK_SIZE_GROUP_VERTICAL */ else /* GTK_SIZE_GROUP_VERTICAL */
{ {
if (cache->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES) if (cache->sizes->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES)
{ {
cache->cached_heights++; cache->sizes->cached_heights++;
cache->last_cached_height = cache->cached_heights - 1; cache->sizes->last_cached_height = cache->sizes->cached_heights - 1;
} }
else else
{ {
if (++cache->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES) if (++cache->sizes->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES)
cache->last_cached_height = 0; cache->sizes->last_cached_height = 0;
} }
*result = &cache->heights[cache->last_cached_height]; 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; return FALSE;
@ -168,39 +257,11 @@ compute_size_for_orientation (GtkWidget *widget,
gint *minimum_size, gint *minimum_size,
gint *natural_size) gint *natural_size)
{ {
SizeRequestCache *cache; CachedSize *cached_size;
SizeRequest *cached_size;
gboolean found_in_cache = FALSE; gboolean found_in_cache = FALSE;
int adjusted_min, adjusted_natural; gint adjusted_min, adjusted_natural;
cache = _gtk_widget_peek_request_cache (widget); found_in_cache = get_cached_size (widget, orientation, for_size, &cached_size);
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
cached_size = &cache->widths[0];
if (!_gtk_widget_get_width_request_needed (widget))
found_in_cache = get_cached_size (cache, orientation, for_size, &cached_size);
else
{
memset (cache->widths, 0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest));
cache->cached_widths = 1;
cache->last_cached_width = 0;
}
}
else
{
cached_size = &cache->heights[0];
if (!_gtk_widget_get_height_request_needed (widget))
found_in_cache = get_cached_size (cache, orientation, for_size, &cached_size);
else
{
memset (cache->heights, 0, GTK_SIZE_REQUEST_CACHED_SIZES * sizeof (SizeRequest));
cache->cached_heights = 1;
cache->last_cached_height = 0;
}
}
if (!found_in_cache) if (!found_in_cache)
{ {
@ -282,7 +343,6 @@ compute_size_for_orientation (GtkWidget *widget,
cached_size->minimum_size = min_size; cached_size->minimum_size = min_size;
cached_size->natural_size = nat_size; cached_size->natural_size = nat_size;
cached_size->for_size = for_size;
if (orientation == GTK_SIZE_GROUP_HORIZONTAL) if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
_gtk_widget_set_width_request_needed (widget, FALSE); _gtk_widget_set_width_request_needed (widget, FALSE);

View File

@ -10669,6 +10669,9 @@ gtk_widget_finalize (GObject *object)
if (priv->context) if (priv->context)
g_object_unref (priv->context); g_object_unref (priv->context);
if (priv->requests.sizes)
g_slice_free (ContextualSizes, priv->requests.sizes);
if (g_object_is_floating (object)) if (g_object_is_floating (object))
g_warning ("A floating object was finalized. This means that someone\n" g_warning ("A floating object was finalized. This means that someone\n"
"called g_object_unref() on an object that had only a floating\n" "called g_object_unref() on an object that had only a floating\n"

View File

@ -34,15 +34,18 @@ G_BEGIN_DECLS
* (Note this define is limited by the bitfield sizes * (Note this define is limited by the bitfield sizes
* defined on the SizeRequestCache structure). * defined on the SizeRequestCache structure).
*/ */
#define GTK_SIZE_REQUEST_CACHED_SIZES (3) #define GTK_SIZE_REQUEST_CACHED_SIZES (2)
typedef struct {
gint minimum_size;
gint natural_size;
} CachedSize;
typedef struct typedef struct
{ {
/* the size this request is for */ /* the size this request is for */
gint for_size; gint for_size;
CachedSize cached_size;
gint minimum_size;
gint natural_size;
} SizeRequest; } SizeRequest;
typedef struct { typedef struct {
@ -53,6 +56,13 @@ typedef struct {
guint cached_heights : 2; guint cached_heights : 2;
guint last_cached_width : 2; guint last_cached_width : 2;
guint last_cached_height : 2; guint last_cached_height : 2;
} ContextualSizes;
typedef struct {
ContextualSizes *sizes;
CachedSize cached_width;
CachedSize cached_height;
} SizeRequestCache; } SizeRequestCache;
void _gtk_widget_set_visible_flag (GtkWidget *widget, void _gtk_widget_set_visible_flag (GtkWidget *widget,