[gtk+/wip/window-scales: 75/84] GtkIconHelper: render to cairo pattern rather than pixbuf for drawing



commit 599870cb9550277dfae8235f574cdba39a3ba3ab
Author: Alexander Larsson <alexl redhat com>
Date:   Mon Jun 24 14:13:43 2013 +0200

    GtkIconHelper: render to cairo pattern rather than pixbuf for drawing
    
    We render the source into a cairo_patter_t into a pixbuf so that
    we can render it directly, rather than having to convert it every
    time we render. We also specify the target window when creating
    the cairo surface so that rendering can be faster.

 gtk/gtkiconhelper.c |  192 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 186 insertions(+), 6 deletions(-)
---
diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c
index 2223da6..f5d853e 100644
--- a/gtk/gtkiconhelper.c
+++ b/gtk/gtkiconhelper.c
@@ -43,6 +43,9 @@ struct _GtkIconHelperPrivate {
 
   GdkPixbuf *rendered_pixbuf;
   GtkStateFlags last_rendered_state;
+
+  cairo_pattern_t *rendered_pattern;
+  GtkStateFlags last_pattern_state;
 };
 
 void
@@ -374,6 +377,184 @@ _gtk_icon_helper_ensure_pixbuf (GtkIconHelper *self,
   return pixbuf;
 }
 
+static gboolean
+check_invalidate_pattern (GtkIconHelper *self,
+                         GtkStyleContext *context)
+{
+  GtkStateFlags state;
+
+  state = gtk_style_context_get_state (context);
+
+  if ((self->priv->rendered_pattern != NULL) &&
+      (self->priv->last_pattern_state == state))
+    return FALSE;
+
+  self->priv->last_pattern_state = state;
+
+  if (self->priv->rendered_pattern)
+    cairo_pattern_destroy (self->priv->rendered_pattern);
+  self->priv->rendered_pattern = NULL;
+
+  return TRUE;
+}
+
+static void
+ensure_pattern_at_size (GtkIconHelper   *self,
+                       GtkStyleContext *context)
+{
+  gint width, height;
+  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface;
+
+  if (!check_invalidate_pattern (self, context))
+    return;
+
+  if (self->priv->rendered_pattern)
+    return;
+
+  if (self->priv->force_scale_pixbuf &&
+      (self->priv->pixel_size != -1 ||
+       self->priv->icon_size != GTK_ICON_SIZE_INVALID))
+    {
+      ensure_icon_size (self, context, &width, &height);
+
+      if (width < gdk_pixbuf_get_width (self->priv->orig_pixbuf) ||
+          height < gdk_pixbuf_get_height (self->priv->orig_pixbuf))
+       {
+         pixbuf = gdk_pixbuf_scale_simple (self->priv->orig_pixbuf,
+                                           width, height,
+                                           GDK_INTERP_BILINEAR);
+       }
+      else
+       pixbuf = g_object_ref (self->priv->orig_pixbuf);
+    }
+  else
+    pixbuf = g_object_ref (self->priv->orig_pixbuf);
+
+  surface = gdk_cairo_pixbuf_to_surface (pixbuf, self->priv->window);
+  g_object_unref (pixbuf);
+  self->priv->rendered_pattern = cairo_pattern_create_for_surface (surface);
+  cairo_surface_destroy (surface);
+
+}
+
+static void
+ensure_pattern_for_icon_set (GtkIconHelper *self,
+                            GtkStyleContext *context,
+                            GtkIconSet *icon_set)
+{
+  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface;
+
+  if (!check_invalidate_pattern (self, context))
+    return;
+
+  pixbuf = 
+    gtk_icon_set_render_icon_pixbuf (icon_set, context, self->priv->icon_size);
+
+  surface = gdk_cairo_pixbuf_to_surface (pixbuf, self->priv->window);
+  g_object_unref (pixbuf);
+  self->priv->rendered_pattern = cairo_pattern_create_for_surface (surface);
+  cairo_surface_destroy (surface);
+}
+
+static void
+ensure_pattern_for_icon_name_or_gicon (GtkIconHelper *self,
+                                      GtkStyleContext *context)
+{
+  GtkIconTheme *icon_theme;
+  gint width, height;
+  GtkIconInfo *info;
+  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface;
+  GtkIconLookupFlags flags;
+
+  if (!check_invalidate_pattern (self, context))
+    return;
+
+  icon_theme = gtk_icon_theme_get_default ();
+  flags = get_icon_lookup_flags (self);
+
+  ensure_icon_size (self, context, &width, &height);
+
+  if (self->priv->storage_type == GTK_IMAGE_ICON_NAME &&
+      self->priv->icon_name != NULL)
+    {
+      info = gtk_icon_theme_lookup_icon (icon_theme,
+                                         self->priv->icon_name,
+                                         MIN (width, height), flags);
+    }
+  else if (self->priv->storage_type == GTK_IMAGE_GICON &&
+           self->priv->gicon != NULL)
+    {
+      info = gtk_icon_theme_lookup_by_gicon (icon_theme,
+                                             self->priv->gicon,
+                                             MIN (width, height), flags);
+    }
+  else
+    {
+      g_assert_not_reached ();
+      return;
+    }
+
+  pixbuf = ensure_stated_icon_from_info (self, context, info);
+  if (pixbuf)
+    {
+      surface = gdk_cairo_pixbuf_to_surface (pixbuf, self->priv->window);
+      g_object_unref (pixbuf);
+      self->priv->rendered_pattern = cairo_pattern_create_for_surface (surface);
+      cairo_surface_destroy (surface);
+    }
+
+  if (info)
+    g_object_unref (info);
+}
+
+cairo_pattern_t *
+_gtk_icon_helper_ensure_pattern (GtkIconHelper *self,
+                                GtkStyleContext *context)
+{
+  cairo_pattern_t *pattern = NULL;
+  GtkIconSet *icon_set;
+
+  switch (self->priv->storage_type)
+    {
+    case GTK_IMAGE_PIXBUF:
+      ensure_pattern_at_size (self, context);
+      break;
+
+    case GTK_IMAGE_STOCK:
+      icon_set = gtk_style_context_lookup_icon_set (context, self->priv->stock_id);
+      if (icon_set != NULL)
+       ensure_pattern_for_icon_set (self, context, icon_set);
+      else
+       pattern = NULL;
+      break;
+
+    case GTK_IMAGE_ICON_SET:
+      icon_set = self->priv->icon_set;
+      ensure_pattern_for_icon_set (self, context, icon_set);
+      break;
+
+    case GTK_IMAGE_ICON_NAME:
+    case GTK_IMAGE_GICON:
+      ensure_pattern_for_icon_name_or_gicon (self, context);
+      break;
+
+    case GTK_IMAGE_ANIMATION:
+    case GTK_IMAGE_EMPTY:
+    default:
+      pattern = NULL;
+      break;
+    }
+
+  if (pattern == NULL &&
+      self->priv->rendered_pattern != NULL)
+    pattern = cairo_pattern_reference (self->priv->rendered_pattern);
+
+  return pattern;
+}
+
 void
 _gtk_icon_helper_get_size (GtkIconHelper *self,
                            GtkStyleContext *context,
@@ -603,14 +784,13 @@ _gtk_icon_helper_draw (GtkIconHelper *self,
                        gdouble x,
                        gdouble y)
 {
-  GdkPixbuf *pixbuf;
+  cairo_pattern_t *pattern;
 
-  pixbuf = _gtk_icon_helper_ensure_pixbuf (self, context);
-
-  if (pixbuf != NULL)
+  pattern = _gtk_icon_helper_ensure_pattern (self, context);
+  if (pattern != NULL)
     {
-      gtk_render_icon (context, cr, pixbuf, x, y);
-      g_object_unref (pixbuf);
+      gtk_render_icon_pattern (context, cr, pattern, x, y);
+      cairo_pattern_destroy (pattern);
     }
 }
 


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