GtkImage: Preload icons during css validation
authorAlexander Larsson <alexl@redhat.com>
Wed, 29 Jan 2020 17:10:13 +0000 (18:10 +0100)
committerAlexander Larsson <alexl@redhat.com>
Thu, 30 Jan 2020 09:53:43 +0000 (10:53 +0100)
At the end of GtkImage css validation (during style-updated) when the
css properties (like the icon size) are valid we call _gtk_icon_helper_preload
which does an async icon theme lookup and load. This will happen on a thread
in parallel with the rest of the css machinery, and hopefully by the
time we need the icon it will be ready. If not we will block when we need
it, but during that blocking all the other icons will be loaded.

Testing widget-factory this changes the time of snapshot() from 31 to
25 msec, but on the other hand we also load a few more icons that we
didn't before causing the css validation phase to be about 8 msec slower.
This is because we're preloading all the images in the window, not only
the ones that are visible.

Unfortunately we still load a bunch of icons in snapshot(), from
GtkCssImageIconTheme, and ideally we should try to preload those also.

gtk/gtkiconhelper.c
gtk/gtkiconhelperprivate.h
gtk/gtkimage.c

index b5a49831575c7a0e0d601d8293382dc6d7b7cf78..47b5b675b0ebfa3edea345f9597fc82ca368f86e 100644 (file)
@@ -174,6 +174,54 @@ gtk_icon_helper_load_paintable (GtkIconHelper   *self,
   return paintable;
 }
 
+void
+_gtk_icon_helper_preload (GtkIconHelper *self)
+{
+  GtkIconTheme *icon_theme;
+  GtkIconLookupFlags flags = 0;
+  int size, scale;
+  GtkCssStyle *style;
+  GIcon *gicon = NULL;
+  GIcon *free_gicon = NULL;
+
+  switch (gtk_image_definition_get_storage_type (self->def))
+    {
+    case GTK_IMAGE_ICON_NAME:
+      if (self->use_fallback)
+        free_gicon = g_themed_icon_new_with_default_fallbacks (gtk_image_definition_get_icon_name (self->def));
+      else
+        free_gicon = g_themed_icon_new (gtk_image_definition_get_icon_name (self->def));
+      gicon = free_gicon;
+      break;
+    case GTK_IMAGE_GICON:
+      gicon = gtk_image_definition_get_gicon (self->def) ;
+     break;
+    case GTK_IMAGE_EMPTY:
+    case GTK_IMAGE_PAINTABLE:
+    default:
+      break;
+    }
+
+  if (gicon && G_IS_THEMED_ICON (gicon))
+    {
+      style = gtk_css_node_get_style (self->node);
+      icon_theme = gtk_css_icon_theme_value_get_icon_theme
+        (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_THEME));
+      flags |= get_icon_lookup_flags (self, style,
+                                      gtk_widget_get_direction (self->owner));
+      size = gtk_icon_helper_get_size (self);
+      scale = gtk_widget_get_scale_factor (self->owner);
+
+      gtk_icon_theme_choose_icon_async (icon_theme,
+                                        (const gchar **)g_themed_icon_get_names (G_THEMED_ICON (gicon)),
+                                        size, scale,
+                                        flags, NULL, NULL, NULL);
+    }
+
+  if (free_gicon)
+    g_object_unref (free_gicon);
+}
+
 static void
 gtk_icon_helper_ensure_paintable (GtkIconHelper *self)
 {
index b7656bb849ad83f1ac42a3429104220b595c2b65..9fbed2a92cce8f5e65751187c8dff85884af7e27 100644 (file)
@@ -48,6 +48,7 @@ void _gtk_icon_helper_set_icon_name (GtkIconHelper *self,
                                      const gchar *icon_name);
 void _gtk_icon_helper_set_paintable (GtkIconHelper *self,
                                     GdkPaintable  *paintable);
+void _gtk_icon_helper_preload (GtkIconHelper *self);
 
 gboolean _gtk_icon_helper_set_pixel_size   (GtkIconHelper *self,
                                             gint           pixel_size);
index 8a415750e93605f2ecb507201eb898ff7191a917..ad59d97b14382b7741314815e5a67dfd6f4e0c36 100644 (file)
@@ -1294,6 +1294,8 @@ gtk_image_style_updated (GtkWidget *widget)
 
   GTK_WIDGET_CLASS (gtk_image_parent_class)->style_updated (widget);
 
+  _gtk_icon_helper_preload (priv->icon_helper);
+
   priv->baseline_align = 0.0;
 }