image: Load resources and files into textures
authorBenjamin Otte <otte@redhat.com>
Wed, 14 Mar 2018 03:45:25 +0000 (04:45 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 16 Mar 2018 05:04:44 +0000 (06:04 +0100)
Instead of loading them into surfaces (which we want to get rid of), we
load into textures.
In fact, we introduce a new paintable subclass called a GtkScaler that
takes care of tracking scaling.

This also ideally gets rid of an extra conversion once renderers learn
to render textures directly.

demos/gtk-demo/main.c
gtk/gtkcellrendererpixbuf.c
gtk/gtkiconhelper.c
gtk/gtkimage.c
gtk/gtkimagedefinition.c
gtk/gtkimagedefinitionprivate.h
gtk/gtkscaler.c [new file with mode: 0644]
gtk/gtkscalerprivate.h [new file with mode: 0644]
gtk/meson.build

index a5e7388888d8929d2f22ba4f10788595e39bcc77..95798c7c2f7a377c4f96305f4cdffbdb5238c6a9 100644 (file)
@@ -555,7 +555,7 @@ add_data_tab (const gchar *demoname)
       resource_name = g_strconcat (resource_dir, "/", resources[i], NULL);
 
       widget = gtk_image_new_from_resource (resource_name);
-      if (gtk_image_get_surface (GTK_IMAGE (widget)) == NULL)
+      if (gtk_image_get_texture (GTK_IMAGE (widget)) == NULL)
         {
           GBytes *bytes;
 
index 1c043a3a462ed7db58cb8912900dc253662fc518..a217634f948829b83550ca76e9ac891801150fbc 100644 (file)
@@ -381,7 +381,7 @@ gtk_cell_renderer_pixbuf_set_property (GObject      *object,
       take_image_definition (cellpixbuf, gtk_image_definition_new_surface (g_value_get_boxed (value)));
       break;
     case PROP_TEXTURE:
-      take_image_definition (cellpixbuf, gtk_image_definition_new_texture (g_value_get_object (value), 1));
+      take_image_definition (cellpixbuf, gtk_image_definition_new_texture (g_value_get_object (value)));
       break;
     case PROP_ICON_SIZE:
       gtk_cell_renderer_pixbuf_set_icon_size (cellpixbuf, g_value_get_enum (value));
index 26c1b2ca4a8ea54f60753b9f58a56e3dd6843dc1..e5acea210c4f6ea1a27b14a6549ad5009194dc22 100644 (file)
@@ -626,7 +626,7 @@ void
 _gtk_icon_helper_set_texture (GtkIconHelper *self,
                              GdkTexture *texture)
 {
-  gtk_icon_helper_take_definition (self, gtk_image_definition_new_texture (texture, 1));
+  gtk_icon_helper_take_definition (self, gtk_image_definition_new_texture (texture));
 }
 
 void
index 3013a93a29c72c8f136eddee7c94ecfe50eb93f4..fbddabd930882a8acd9173a68089d1c60df90c60 100644 (file)
@@ -31,6 +31,7 @@
 #include "gtkicontheme.h"
 #include "gtkintl.h"
 #include "gtkprivate.h"
+#include "gtkscalerprivate.h"
 #include "gtksnapshot.h"
 #include "gtktypebuiltins.h"
 #include "gtkwidgetprivate.h"
@@ -729,7 +730,8 @@ gtk_image_set_from_file   (GtkImage    *image,
   GtkImagePrivate *priv = gtk_image_get_instance_private (image);
   GdkPixbufAnimation *anim;
   gint scale_factor;
-  cairo_surface_t *surface;
+  GdkTexture *texture;
+  GdkPaintable *scaler;
 
   g_return_if_fail (GTK_IS_IMAGE (image));
 
@@ -753,11 +755,13 @@ gtk_image_set_from_file   (GtkImage    *image,
       return;
     }
 
-  surface = gdk_cairo_surface_create_from_pixbuf (gdk_pixbuf_animation_get_static_image (anim),
-                                                  scale_factor, _gtk_widget_get_window (GTK_WIDGET (image)));
-  gtk_image_set_from_surface (image, surface);
-  cairo_surface_destroy (surface);
+  texture = gdk_texture_new_for_pixbuf (gdk_pixbuf_animation_get_static_image (anim));
+  scaler = gtk_scaler_new (GDK_PAINTABLE (texture), scale_factor);
 
+  gtk_image_set_from_paintable (image, scaler);
+
+  g_object_unref (scaler);
+  g_object_unref (texture);
   g_object_unref (anim);
 
   priv->filename = g_strdup (filename);
@@ -809,7 +813,8 @@ gtk_image_set_from_resource (GtkImage    *image,
   GtkImagePrivate *priv = gtk_image_get_instance_private (image);
   GdkPixbufAnimation *animation;
   gint scale_factor = 1;
-  cairo_surface_t *surface;
+  GdkTexture *texture;
+  GdkPaintable *scaler;
 
   g_return_if_fail (GTK_IS_IMAGE (image));
 
@@ -840,10 +845,13 @@ gtk_image_set_from_resource (GtkImage    *image,
       return;
     }
 
-  surface = gdk_cairo_surface_create_from_pixbuf (gdk_pixbuf_animation_get_static_image (animation),
-                                                  scale_factor, _gtk_widget_get_window (GTK_WIDGET (image)));
-  gtk_image_set_from_surface (image, surface);
-  cairo_surface_destroy (surface);
+  texture = gdk_texture_new_for_pixbuf (gdk_pixbuf_animation_get_static_image (animation));
+  scaler = gtk_scaler_new (GDK_PAINTABLE (texture), scale_factor);
+
+  gtk_image_set_from_paintable (image, scaler);
+
+  g_object_unref (scaler);
+  g_object_unref (texture);
 
   priv->resource_path = g_strdup (resource_path);
 
index c3b8a456da56d885a0d601121567ebef8d1d94d3..f663f12365ec032940833794d3aff1eb1b198c98 100644 (file)
@@ -57,7 +57,6 @@ struct _GtkImageDefinitionTexture {
   gint ref_count;
 
   GdkTexture *texture;
-  int scale;
 };
 
 struct _GtkImageDefinitionPaintable {
@@ -151,8 +150,7 @@ gtk_image_definition_new_surface (cairo_surface_t *surface)
 }
 
 GtkImageDefinition *
-gtk_image_definition_new_texture (GdkTexture *texture,
-                                  gint        scale)
+gtk_image_definition_new_texture (GdkTexture *texture)
 {
   GtkImageDefinition *def;
 
@@ -161,7 +159,6 @@ gtk_image_definition_new_texture (GdkTexture *texture,
 
   def = gtk_image_definition_alloc (GTK_IMAGE_TEXTURE);
   def->texture.texture = g_object_ref (texture);
-  def->texture.scale = scale;
 
   return def;
 }
@@ -238,11 +235,10 @@ gtk_image_definition_get_scale (const GtkImageDefinition *def)
     case GTK_IMAGE_EMPTY:
     case GTK_IMAGE_SURFACE:
     case GTK_IMAGE_PAINTABLE:
+    case GTK_IMAGE_TEXTURE:
     case GTK_IMAGE_ICON_NAME:
     case GTK_IMAGE_GICON:
       return 1;
-    case GTK_IMAGE_TEXTURE:
-      return def->texture.scale;
     }
 }
 
index 66ccae8be5ad7aac5bf58f2e88790e9926254348..8cdb26c9e6fdcf119024a462595d6ff1a0cdf462 100644 (file)
@@ -29,8 +29,7 @@ GtkImageDefinition *    gtk_image_definition_new_empty          (void);
 GtkImageDefinition *    gtk_image_definition_new_icon_name      (const char                     *icon_name);
 GtkImageDefinition *    gtk_image_definition_new_gicon          (GIcon                          *gicon);
 GtkImageDefinition *    gtk_image_definition_new_surface        (cairo_surface_t                *surface);
-GtkImageDefinition *    gtk_image_definition_new_texture        (GdkTexture                     *texture,
-                                                                 int                             scale);
+GtkImageDefinition *    gtk_image_definition_new_texture        (GdkTexture                     *texture);
 GtkImageDefinition *    gtk_image_definition_new_paintable      (GdkPaintable                   *paintable);
 
 GtkImageDefinition *    gtk_image_definition_ref                (GtkImageDefinition             *def);
diff --git a/gtk/gtkscaler.c b/gtk/gtkscaler.c
new file mode 100644 (file)
index 0000000..2d9caa7
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2018 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#include "config.h"
+
+#include "gtkscalerprivate.h"
+
+#include "gtksnapshot.h"
+
+struct _GtkScaler
+{
+  GObject parent_instance;
+
+  GdkPaintable *paintable;
+  double scale_factor;
+};
+
+struct _GtkScalerClass
+{
+  GObjectClass parent_class;
+};
+
+static void
+gtk_scaler_paintable_snapshot (GdkPaintable *paintable,
+                               GdkSnapshot  *snapshot,
+                               double        width,
+                               double        height)
+{
+  GtkScaler *self = GTK_SCALER (paintable);
+
+  if (self->scale_factor == 1.0)
+    {
+      gdk_paintable_snapshot (self->paintable, snapshot, width, height);
+    }
+  else
+    {
+      graphene_matrix_t scale_matrix;
+
+      graphene_matrix_init_scale (&scale_matrix, 1.0 / self->scale_factor, 1.0 / self->scale_factor, 1.0);
+      gtk_snapshot_push_transform (snapshot,
+                                   &scale_matrix,
+                                   "GtkScaler<%g>",
+                                   self->scale_factor);
+      gdk_paintable_snapshot (self->paintable,
+                              snapshot,
+                              width * self->scale_factor,
+                              height * self->scale_factor);
+      gtk_snapshot_pop (snapshot);
+    }
+}
+
+static GdkPaintable *
+gtk_scaler_paintable_get_current_image (GdkPaintable *paintable)
+{
+  GtkScaler *self = GTK_SCALER (paintable);
+  GdkPaintable *current_paintable, *current_self;
+
+  current_paintable = gdk_paintable_get_current_image (self->paintable);
+  current_self = gtk_scaler_new (current_paintable, self->scale_factor);
+  g_object_unref (current_paintable);
+
+  return current_self;
+}
+
+static GdkPaintableFlags
+gtk_scaler_paintable_get_flags (GdkPaintable *paintable)
+{
+  GtkScaler *self = GTK_SCALER (paintable);
+
+  return gdk_paintable_get_flags (self->paintable);
+}
+
+static int
+gtk_scaler_paintable_get_intrinsic_width (GdkPaintable *paintable)
+{
+  GtkScaler *self = GTK_SCALER (paintable);
+
+  return gdk_paintable_get_intrinsic_width (self->paintable) / self->scale_factor;
+}
+
+static int
+gtk_scaler_paintable_get_intrinsic_height (GdkPaintable *paintable)
+{
+  GtkScaler *self = GTK_SCALER (paintable);
+
+  return gdk_paintable_get_intrinsic_height (self->paintable) / self->scale_factor;
+}
+
+static double gtk_scaler_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
+{
+  GtkScaler *self = GTK_SCALER (paintable);
+
+  return gdk_paintable_get_intrinsic_aspect_ratio (self->paintable);
+};
+
+static void
+gtk_scaler_paintable_init (GdkPaintableInterface *iface)
+{
+  iface->snapshot = gtk_scaler_paintable_snapshot;
+  iface->get_current_image = gtk_scaler_paintable_get_current_image;
+  iface->get_flags = gtk_scaler_paintable_get_flags;
+  iface->get_intrinsic_width = gtk_scaler_paintable_get_intrinsic_width;
+  iface->get_intrinsic_height = gtk_scaler_paintable_get_intrinsic_height;
+  iface->get_intrinsic_aspect_ratio = gtk_scaler_paintable_get_intrinsic_aspect_ratio;
+}
+
+G_DEFINE_TYPE_EXTENDED (GtkScaler, gtk_scaler, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
+                                               gtk_scaler_paintable_init))
+
+static void
+gtk_scaler_dispose (GObject *object)
+{
+  GtkScaler *self = GTK_SCALER (object);
+
+  if (self->paintable)
+    {
+      g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_contents, self);
+      g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_size, self);
+      g_clear_object (&self->paintable);
+    }
+
+  G_OBJECT_CLASS (gtk_scaler_parent_class)->dispose (object);
+}
+
+static void
+gtk_scaler_class_init (GtkScalerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = gtk_scaler_dispose;
+}
+
+static void
+gtk_scaler_init (GtkScaler *self)
+{
+  self->scale_factor = 1.0;
+}
+
+GdkPaintable *
+gtk_scaler_new (GdkPaintable *paintable,
+                double        scale_factor)
+{
+  GtkScaler *self;
+
+  g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), NULL);
+  g_return_val_if_fail (scale_factor > 0.0, NULL);
+
+  self = g_object_new (GTK_TYPE_SCALER, NULL);
+
+  self->paintable = g_object_ref (paintable);
+  g_signal_connect_swapped (paintable, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
+  g_signal_connect_swapped (paintable, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
+  self->scale_factor = scale_factor;
+
+  return GDK_PAINTABLE (self);
+}
diff --git a/gtk/gtkscalerprivate.h b/gtk/gtkscalerprivate.h
new file mode 100644 (file)
index 0000000..b48bc10
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2018 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#ifndef __GTK_SCALER_H__
+#define __GTK_SCALER_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SCALER (gtk_scaler_get_type ())
+
+G_DECLARE_FINAL_TYPE (GtkScaler, gtk_scaler, GTK, SCALER, GObject)
+
+GdkPaintable *  gtk_scaler_new                  (GdkPaintable   *paintable,
+                                                 double          scale_factor);
+
+G_END_DECLS
+
+#endif /* __GTK_SCALER_H__ */
index 63b374c84825da5a9759866cf4d6d499c5b1e48d..619b709b1b38a498cb6d355482d1da4879574694 100644 (file)
@@ -123,6 +123,7 @@ gtk_private_sources = files([
   'gtkprivate.c',
   'gtkprogresstracker.c',
   'gtkquery.c',
+  'gtkscaler.c',
   'gtksearchengine.c',
   'gtksearchenginemodel.c',
   'gtksearchenginesimple.c',