[sushi/wip/cosimoc/no-clutter: 31/67] image: port to use a custom GtkWidget



commit 8187b1fba0649bd5df88b57a747d67fe03ff9b91
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Mon Apr 3 12:39:51 2017 -0700

    image: port to use a custom GtkWidget
    
    The Image class will draw an image at the right scale, while preserving
    the aspect ratio.

 src/js/viewers/image.js |  106 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 98 insertions(+), 8 deletions(-)
---
diff --git a/src/js/viewers/image.js b/src/js/viewers/image.js
index dea3dc5..4902d3a 100644
--- a/src/js/viewers/image.js
+++ b/src/js/viewers/image.js
@@ -23,10 +23,11 @@
  *
  */
 
+const Gdk = imports.gi.Gdk;
 const GdkPixbuf = imports.gi.GdkPixbuf;
-const GtkClutter = imports.gi.GtkClutter;
-const Gtk = imports.gi.Gtk;
 const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
+const Gtk = imports.gi.Gtk;
 
 const Gettext = imports.gettext.domain('sushi');
 const _ = Gettext.gettext;
@@ -36,6 +37,94 @@ const Mainloop = imports.mainloop;
 const MimeHandler = imports.ui.mimeHandler;
 const Utils = imports.ui.utils;
 
+const Image = new Lang.Class({
+    Name: 'Image',
+    Extends: Gtk.DrawingArea,
+    Properties: {
+        'pix': GObject.ParamSpec.object('pix', '', '',
+                                        GObject.ParamFlags.READWRITE,
+                                        GdkPixbuf.Pixbuf)
+    },
+
+    _init: function() {
+        this._pix = null;
+        this._scaledSurface = null;
+
+        this.parent();
+    },
+
+    _ensureScaledPix: function() {
+        let scaleFactor = this.get_scale_factor();
+        let width = this.get_allocated_width() * scaleFactor;
+        let height = this.get_allocated_height() * scaleFactor;
+
+        // Downscale original to fit, if necessary
+        let origWidth = this._pix.get_width();
+        let origHeight = this._pix.get_height();
+
+        let scaleX = origWidth / width;
+        let scaleY = origHeight / height;
+        let scale = Math.max(scaleX, scaleY);
+
+        let newWidth;
+        let newHeight;
+
+        if (scale < 1) {
+            newWidth = Math.min(width, origWidth * scaleFactor);
+            newHeight = Math.min(height, origHeight * scaleFactor);
+        } else {
+            newWidth = Math.floor(origWidth / scale);
+            newHeight = Math.floor(origHeight / scale);
+        }
+
+        let scaledWidth = this._scaledSurface ? this._scaledSurface.getWidth() : 0;
+        let scaledHeight = this._scaledSurface ? this._scaledSurface.getHeight() : 0;
+
+        if (newWidth != scaledWidth || newHeight != scaledHeight) {
+            let scaledPixbuf = this._pix.scale_simple(newWidth, newHeight,
+                                                      GdkPixbuf.InterpType.BILINEAR);
+            this._scaledSurface = Gdk.cairo_surface_create_from_pixbuf(scaledPixbuf,
+                                                                       scaleFactor,
+                                                                       this.get_window());
+        }
+    },
+
+    vfunc_get_preferred_width: function() {
+        return [1, this._pix ? this.pix.get_width() : 1];
+    },
+
+    vfunc_get_preferred_height: function() {
+        return [1, this._pix ? this.pix.get_height() : 1];
+    },
+
+    vfunc_size_allocate: function(allocation) {
+        this.parent(allocation);
+        this._ensureScaledPix();
+    },
+
+    vfunc_draw: function(context) {
+        let width = this.get_allocated_width();
+        let height = this.get_allocated_height();
+
+        let scaleFactor = this.get_scale_factor();
+        let offsetX = (width - this._scaledSurface.getWidth() / scaleFactor) / 2;
+        let offsetY = (height - this._scaledSurface.getHeight() / scaleFactor) / 2;
+
+        context.setSourceSurface(this._scaledSurface, offsetX, offsetY);
+        context.paint();
+        return false;
+    },
+
+    set pix(p) {
+        this._pix = p;
+        this.queue_resize();
+    },
+
+    get pix() {
+        return this._pix;
+    }
+});
+
 const ImageRenderer = new Lang.Class({
     Name: 'ImageRenderer',
 
@@ -58,6 +147,8 @@ const ImageRenderer = new Lang.Class({
     },
 
     _createImageTexture : function(file) {
+        this._texture = new Image();
+
         file.read_async
         (GLib.PRIORITY_DEFAULT, null,
          Lang.bind(this,
@@ -78,9 +169,7 @@ const ImageRenderer = new Lang.Class({
 
              this._iter = anim.get_iter(null);
              let pix = this._iter.get_pixbuf().apply_embedded_orientation();
-
-             this._texture = new GtkClutter.Texture({ keep_aspect_ratio: true });
-             this._texture.set_from_pixbuf(pix);
+             this._texture.pix = pix;
 
              if (!anim.is_static_image())
                  this._startTimeout();
@@ -99,9 +188,10 @@ const ImageRenderer = new Lang.Class({
          }));
     },
 
-    getSizeForAllocation : function(allocation, fullScreen) {
-        let baseSize = this._texture.get_base_size();
-        return Utils.getScaledSize(baseSize, allocation, fullScreen);
+    getSizeForAllocation : function(allocation) {
+        let width = this._texture.pix.get_width();
+        let height = this._texture.pix.get_height();
+        return Utils.getScaledSize([width, height], allocation, false);
     },
 
     _startTimeout : function() {


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