diff options
author | Alexander Larsson <alexl@redhat.com> | 2014-08-12 12:34:12 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2014-08-12 15:47:42 +0200 |
commit | 928822f1a5f2e5302c9bc5cfe98f5960e97d61de (patch) | |
tree | a27541402e246819ec1c9ead7f8d0c33c1887687 /gtk/gtkiconhelper.c | |
parent | 8ff47570af18c42800c629e6c0ec6e98f2302f18 (diff) | |
download | gtk+-928822f1a5f2e5302c9bc5cfe98f5960e97d61de.tar.gz |
GtkIconHelper: Short circuit _gtk_icon_helper_get_size in some cases
_gtk_icon_helper_get_size() is often used during size request and may
not necessary mean that the icon will be displayed immediately. In
many common cases we know the size without having to ensure a surface.
In many cases this means we can avoid loading an icon until needed, and
in the case of stateless IconHelpers such as GtkCellRendererPixbuf this
is very important as otherwise it will constantly be reloading icons
if the displayed set is larger than the in-memory icon cache.
https://bugzilla.gnome.org/show_bug.cgi?id=734651
Diffstat (limited to 'gtk/gtkiconhelper.c')
-rw-r--r-- | gtk/gtkiconhelper.c | 123 |
1 files changed, 93 insertions, 30 deletions
diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c index 0ee99570ba..2fc97d106c 100644 --- a/gtk/gtkiconhelper.c +++ b/gtk/gtkiconhelper.c @@ -542,21 +542,19 @@ ensure_surface_from_surface (GtkIconHelper *self, &self->priv->rendered_surface_height); } -static void -ensure_surface_from_pixbuf (GtkIconHelper *self, - GtkStyleContext *context) +static gboolean +get_pixbuf_size (GtkIconHelper *self, + GtkStyleContext *context, + gint *width_out, + gint *height_out, + gint *scale_out) { + gboolean scale_pixmap; gint width, height; - GdkPixbuf *pixbuf, *stated; int scale; - if (!check_invalidate_surface (self, context)) - return; - - if (self->priv->rendered_surface) - return; - scale = get_scale_factor (self, context); + scale_pixmap = FALSE; if (self->priv->force_scale_pixbuf && (self->priv->pixel_size != -1 || @@ -571,28 +569,56 @@ ensure_surface_from_pixbuf (GtkIconHelper *self, width = MIN (width * scale, gdk_pixbuf_get_width (self->priv->orig_pixbuf) * scale / self->priv->orig_pixbuf_scale); height = MIN (height * scale, gdk_pixbuf_get_height (self->priv->orig_pixbuf) * scale / self->priv->orig_pixbuf_scale); - pixbuf = gdk_pixbuf_scale_simple (self->priv->orig_pixbuf, - width, height, - GDK_INTERP_BILINEAR); + scale_pixmap = TRUE; } else { - pixbuf = g_object_ref (self->priv->orig_pixbuf); + width = gdk_pixbuf_get_width (self->priv->orig_pixbuf); + height = gdk_pixbuf_get_height (self->priv->orig_pixbuf); scale = self->priv->orig_pixbuf_scale; } } else { - pixbuf = g_object_ref (self->priv->orig_pixbuf); + width = gdk_pixbuf_get_width (self->priv->orig_pixbuf); + height = gdk_pixbuf_get_height (self->priv->orig_pixbuf); scale = self->priv->orig_pixbuf_scale; } + *width_out = width; + *height_out = height; + *scale_out = scale; + + return scale_pixmap; +} + +static void +ensure_surface_from_pixbuf (GtkIconHelper *self, + GtkStyleContext *context) +{ + gint width, height; + GdkPixbuf *pixbuf, *stated; + int scale; + + if (!check_invalidate_surface (self, context)) + return; + + if (self->priv->rendered_surface) + return; + + if (get_pixbuf_size (self, context, &width, &height, &scale)) + pixbuf = gdk_pixbuf_scale_simple (self->priv->orig_pixbuf, + width, height, + GDK_INTERP_BILINEAR); + else + pixbuf = g_object_ref (self->priv->orig_pixbuf); + stated = ensure_stated_pixbuf_from_pixbuf (self, context, pixbuf); g_object_unref (pixbuf); pixbuf = stated; - self->priv->rendered_surface_width = (gdk_pixbuf_get_width (pixbuf) + scale - 1) / scale; - self->priv->rendered_surface_height = (gdk_pixbuf_get_height (pixbuf) + scale - 1) / scale; + self->priv->rendered_surface_width = (width + scale - 1) / scale; + self->priv->rendered_surface_height = (height + scale - 1) / scale; self->priv->rendered_surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, self->priv->window); g_object_unref (pixbuf); @@ -774,25 +800,62 @@ _gtk_icon_helper_get_size (GtkIconHelper *self, gint *height_out) { cairo_surface_t *surface; - gint width, height; + gint width, height, scale; width = height = 0; - surface = _gtk_icon_helper_ensure_surface (self, context); - if (surface != NULL) - { - width = self->priv->rendered_surface_width; - height = self->priv->rendered_surface_height; - cairo_surface_destroy (surface); - } - else if (self->priv->storage_type == GTK_IMAGE_ANIMATION) + /* Certain kinds of images are easy to calculate the size for, these + we do immediately to avoid having to potentially load the image + data for something that may not yet be visible */ + switch (self->priv->storage_type) { - width = gdk_pixbuf_animation_get_width (self->priv->animation); - height = gdk_pixbuf_animation_get_height (self->priv->animation); + case GTK_IMAGE_SURFACE: + get_surface_size (self, context, self->priv->orig_surface, + &width, + &height); + break; + + case GTK_IMAGE_PIXBUF: + get_pixbuf_size (self, context, &width, &height, &scale); + width = (width + scale - 1) / scale; + height = (height + scale - 1) / scale; + break; + + case GTK_IMAGE_ICON_NAME: + case GTK_IMAGE_GICON: + if (self->priv->pixel_size != -1 || self->priv->force_scale_pixbuf) + ensure_icon_size (self, context, &width, &height); + + break; + + case GTK_IMAGE_STOCK: + case GTK_IMAGE_ICON_SET: + case GTK_IMAGE_ANIMATION: + case GTK_IMAGE_EMPTY: + default: + break; } - else if (self->priv->icon_size != -1) + + /* Otherwise we load the surface to guarantee we get a size */ + if (width == 0) { - ensure_icon_size (self, context, &width, &height); + surface = _gtk_icon_helper_ensure_surface (self, context); + + if (surface != NULL) + { + width = self->priv->rendered_surface_width; + height = self->priv->rendered_surface_height; + cairo_surface_destroy (surface); + } + else if (self->priv->storage_type == GTK_IMAGE_ANIMATION) + { + width = gdk_pixbuf_animation_get_width (self->priv->animation); + height = gdk_pixbuf_animation_get_height (self->priv->animation); + } + else if (self->priv->icon_size != -1) + { + ensure_icon_size (self, context, &width, &height); + } } if (width_out) |