[gtk+] GtkIconHelper: Short circuit _gtk_icon_helper_get_size in some cases



commit 928822f1a5f2e5302c9bc5cfe98f5960e97d61de
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Aug 12 12:34:12 2014 +0200

    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

 gtk/gtkiconhelper.c |  123 ++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 93 insertions(+), 30 deletions(-)
---
diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c
index 0ee9957..2fc97d1 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)


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