[librsvg] Rework rsvg-view



commit 2c2917c3c19fbc51503ef19300e09a0da457b1fe
Author: Christian Persch <chpe gnome org>
Date:   Sat Dec 17 00:20:11 2011 +0100

    Rework rsvg-view
    
    Drop gtk2, use cairo surfaces instead of pixbuf, use GIO, load
    the SVG just once instead of every time we zoom or print, and
    remove some unused or unnecessary options.

 Makefile.am    |   26 --
 librsvg.def    |    1 -
 test-display.c |  706 ++++++++++++++++++++++----------------------------------
 3 files changed, 281 insertions(+), 452 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 5aca4aa..e53d569 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,9 +11,6 @@ endif
 lib_LTLIBRARIES = librsvg- RSVG_API_MAJOR_VERSION@.la
 
 bin_PROGRAMS = rsvg-convert
-if HAVE_GTK_2
-bin_PROGRAMS += rsvg-view
-endif
 if HAVE_GTK_3
 bin_PROGRAMS += rsvg-view-3
 endif
@@ -130,29 +127,6 @@ rsvg_convert_LDADD = \
 	$(GTHREAD_LIBS)		\
 	$(LIBM)
 
-rsvg_view_SOURCES = \
-	test-display.c
-
-rsvg_view_CPPFLAGS = \
-	-I$(top_srcdir) 			\
-	-I$(top_builddir) 			\
-	-DLIBRSVG_DATADIR="\"$(datadir)\""	\
-	$(AM_CPPFLAGS)
-
-rsvg_view_CFLAGS =\
-	$(GTK2_CFLAGS)		\
-	$(LIBRSVG_CFLAGS) 	\
-	$(AM_CFLAGS)
-
-rsvg_view_LDFLAGS =
-
-rsvg_view_LDADD = \
-	$(top_builddir)/librsvg- RSVG_API_MAJOR_VERSION@.la \
-	$(GTK2_LIBS)		\
-	$(LIBRSVG_LIBS)		\
-	$(GTHREAD_LIBS)		\
-	$(LIBM)
-
 rsvg_view_3_SOURCES = \
 	test-display.c
 
diff --git a/librsvg.def b/librsvg.def
index 37b30b3..79373ee 100644
--- a/librsvg.def
+++ b/librsvg.def
@@ -35,7 +35,6 @@ rsvg_handle_render_cairo
 rsvg_handle_render_cairo_sub
 rsvg_handle_get_type
 _rsvg_size_callback
-_rsvg_acquire_xlink_href_resource
 _rsvg_register_types
 rsvg_defs_lookup
 rsvg_pixbuf_from_data_with_size_data
diff --git a/test-display.c b/test-display.c
index 0231ac0..a71ad0f 100644
--- a/test-display.c
+++ b/test-display.c
@@ -30,147 +30,188 @@
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 
-#if GTK_CHECK_VERSION(2,90,7)
-#define GDK_KEY(symbol) GDK_KEY_##symbol
-#else
-#include <gdk/gdkkeysyms.h>
-#define GDK_KEY(symbol) GDK_##symbol
+#if 0 // defined (G_OS_UNIX)
+#include <gio/gunixinputstream.h>
 #endif
 
 #define DEFAULT_WIDTH  640
 #define DEFAULT_HEIGHT 480
 
-static char *
-_rsvg_basename (const char *file)
-{
-    if (file && *file)
-        return g_path_get_basename (file);
+/* RsvgImage */
 
-    return NULL;
-}
+#define RSVG_TYPE_IMAGE (rsvg_image_get_type ())
+#define RSVG_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RSVG_TYPE_IMAGE, RsvgImage))
 
-typedef struct _ViewerCbInfo ViewerCbInfo;
-struct _ViewerCbInfo {
-    GtkWidget *window;
-    GtkWidget *popup_menu;
-    GtkWidget *image;           /* the image widget */
+typedef struct _RsvgImage       RsvgImage;
+typedef struct _RsvgImageClass  RsvgImageClass;
 
-    GdkPixbuf *pixbuf;
-    GByteArray *svg_bytes;
-    GtkAccelGroup *accel_group;
-    char *base_uri;
-    char *id;
-    gdouble x_zoom;
-    gdouble y_zoom;
+struct _RsvgImage {
+    GtkWidget parent_instance;
+
+    cairo_surface_t *surface; /* a cairo image surface */
 };
 
-static gboolean
-get_image_size_from_data (ViewerCbInfo *info,
-                          gint *width,
-                          gint *height,
-                          GError **error)
+struct _RsvgImageClass {
+    GtkWidgetClass parent_class;
+};
+
+static GType rsvg_image_get_type (void);
+
+static void
+rsvg_image_take_surface (RsvgImage *image,
+                         cairo_surface_t *surface)
 {
-    RsvgHandle *handle;
-    RsvgDimensionData dimensions;
+    if (image->surface == surface)
+      return;
+    if (image->surface)
+      cairo_surface_destroy (image->surface);
+    image->surface = surface; /* adopted */
 
-    handle = rsvg_handle_new ();
+    gtk_widget_queue_resize (GTK_WIDGET (image));
+}
 
-    if (!handle) {
-        g_set_error (error, rsvg_error_quark (), 0, _("Error creating SVG reader"));
-        return FALSE;
-    }
+G_DEFINE_TYPE (RsvgImage, rsvg_image, GTK_TYPE_WIDGET);
 
-    rsvg_handle_set_base_uri (handle, info->base_uri);
+static void
+rsvg_image_init (RsvgImage *image)
+{
+  gtk_widget_set_has_window (GTK_WIDGET (image), FALSE);
+}
 
-    if (!rsvg_handle_write (handle, info->svg_bytes->data, info->svg_bytes->len, error)) {
-        g_object_unref (handle);
-        return FALSE;
-    }
+static void
+rsvg_image_finalize (GObject *object)
+{
+  RsvgImage *image = RSVG_IMAGE (object);
 
-    if (!rsvg_handle_close (handle, error)) {
-        g_object_unref (handle);
-        return FALSE;
-    }
+  rsvg_image_take_surface (image, NULL);
+}
+
+static void
+rsvg_image_get_preferred_width (GtkWidget *widget,
+                                gint      *minimum,
+                                gint      *natural)
+{
+  RsvgImage *image = RSVG_IMAGE (widget);
 
-    (void) rsvg_handle_get_dimensions_sub (handle, &dimensions, info->id);
-    g_object_unref (handle);
+  *minimum = *natural = image->surface ? cairo_image_surface_get_width (image->surface) : 1;
+}
 
-    if (width)
-        *width = dimensions.width;
-    if (height)
-        *height = dimensions.height;
+static void
+rsvg_image_get_preferred_height (GtkWidget *widget,
+                                 gint      *minimum,
+                                 gint      *natural)
+{
+  RsvgImage *image = RSVG_IMAGE (widget);
 
-    return TRUE;
+  *minimum = *natural = image->surface ? cairo_image_surface_get_height (image->surface) : 1;
 }
 
 static gboolean
-calculate_zoom_ratio (ViewerCbInfo *info,
-                      struct RsvgSizeCallbackData *size_data,
-                      GError **error)
+rsvg_image_draw (GtkWidget *widget,
+                 cairo_t *cr)
 {
-    GdkScreen *screen;
-    gint image_width, image_height;
-    gint screen_width, screen_height;
-    gdouble x_zoom = 1.0, y_zoom = 1.0, zoom;
+  RsvgImage *image = RSVG_IMAGE (widget);
+
+  if (image->surface == NULL)
+      return FALSE;
 
-    if (!get_image_size_from_data (info, &image_width, &image_height, error))
-        return FALSE;
+  cairo_save (cr);
+  cairo_set_source_surface (cr, image->surface, 0, 0);
+  cairo_paint (cr);
+  cairo_restore (cr);
 
-    screen = gdk_screen_get_default ();
-    screen_width = gdk_screen_get_width (screen);
-    screen_height = gdk_screen_get_height (screen);
+  return FALSE;
+}
 
-    if (image_width > screen_width)
-        x_zoom = (gdouble) screen_width / image_width * 0.8;
+static void
+rsvg_image_class_init (RsvgImageClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-    if (image_height > screen_height)
-        y_zoom = (gdouble) screen_height / image_height * 0.8;
+  gobject_class->finalize = rsvg_image_finalize;
+  widget_class->get_preferred_width = rsvg_image_get_preferred_width;
+  widget_class->get_preferred_height = rsvg_image_get_preferred_height;
+  widget_class->draw = rsvg_image_draw;
+}
 
-    zoom = MAX (x_zoom, y_zoom);
+static RsvgImage *
+rsvg_image_new_take_surface (cairo_surface_t *surface)
+{
+  RsvgImage *image;
 
-    info->x_zoom = zoom;
-    info->y_zoom = zoom;
-    size_data->x_zoom = zoom;
-    size_data->y_zoom = zoom;
+  image = g_object_new (RSVG_TYPE_IMAGE, NULL);
+  rsvg_image_take_surface (image, surface);
 
-    return TRUE;
+  return image;
 }
 
-static GdkPixbuf *
-pixbuf_from_data_with_size_data (const guchar * buff,
-                                 size_t len,
-                                 struct RsvgSizeCallbackData *data,
-                                 const char *base_uri,
-                                 const char *id,
-                                 GError ** error)
+static cairo_surface_t *
+rsvg_image_get_surface (RsvgImage *image)
 {
-    RsvgHandle *handle;
-    GdkPixbuf *retval;
+  return image->surface;
+}
 
-    handle = rsvg_handle_new ();
+/* Main */
 
-    if (!handle) {
-        g_set_error (error, rsvg_error_quark (), 0, _("Error creating SVG reader"));
-        return NULL;
-    }
+static char *
+_rsvg_basename (const char *file)
+{
+    if (file && *file)
+        return g_path_get_basename (file);
+
+    return NULL;
+}
 
-    rsvg_handle_set_size_callback (handle, _rsvg_size_callback, data, NULL);
-    rsvg_handle_set_base_uri (handle, base_uri);
+typedef struct _ViewerCbInfo ViewerCbInfo;
+struct _ViewerCbInfo {
+    GtkWidget *window;
+    GtkWidget *popup_menu;
+    RsvgImage *image;
+    RsvgHandle *handle;
+    GtkAccelGroup *accel_group;
+    char *base_uri;
+    char *id;
+    RsvgDimensionData dimensions;
+    gdouble x_zoom;
+    gdouble y_zoom;
+};
 
-    if (!rsvg_handle_write (handle, buff, len, error)) {
-        g_object_unref (handle);
+static cairo_surface_t *
+render_to_surface (ViewerCbInfo *info)
+{
+    RsvgDimensionData dimensions;
+    int width, height;
+    cairo_matrix_t matrix;
+    GdkPixbuf *output = NULL;
+    guint8 *pixels;
+    cairo_surface_t *surface;
+    cairo_t *cr;
+    int rowstride, minimum;
+
+    width = ceil ((double) info->dimensions.width * info->x_zoom);
+    height = ceil ((double) info->dimensions.height * info->y_zoom);
+
+    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+    if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
+        cairo_surface_destroy (surface);
         return NULL;
     }
 
-    if (!rsvg_handle_close (handle, error)) {
-        g_object_unref (handle);
+    cr = cairo_create (surface);
+
+    cairo_matrix_init_scale (&matrix, info->x_zoom, info->y_zoom);
+    cairo_transform (cr, &matrix);
+
+    if (!rsvg_handle_render_cairo_sub (info->handle, cr, info->id)) {
+        cairo_destroy (cr);
+        cairo_surface_destroy (surface);
         return NULL;
     }
 
-    retval = rsvg_handle_get_pixbuf_sub (handle, id);
-    g_object_unref (handle);
+    cairo_destroy (cr);
 
-    return retval;
+    return surface;
 }
 
 static void
@@ -207,79 +248,26 @@ set_window_title (ViewerCbInfo * info)
 static void
 zoom_image (ViewerCbInfo * info, gdouble factor)
 {
-    struct RsvgSizeCallbackData size_data;
-    GdkPixbuf *save_pixbuf = info->pixbuf;
-
     info->x_zoom *= factor;
     info->y_zoom *= factor;
 
-    size_data.type = RSVG_SIZE_WH;
-    size_data.width = gdk_pixbuf_get_width (info->pixbuf) * factor;
-    size_data.height = gdk_pixbuf_get_height (info->pixbuf) * factor;
-    size_data.keep_aspect_ratio = FALSE;
-
-    info->pixbuf =
-        pixbuf_from_data_with_size_data (info->svg_bytes->data, info->svg_bytes->len,
-                                         &size_data, info->base_uri, info->id, NULL);
-    gtk_image_set_from_pixbuf (GTK_IMAGE (info->image), info->pixbuf);
+    rsvg_image_take_surface (info->image, render_to_surface (info));
 
     set_window_title (info);
-
-    if (save_pixbuf)
-        g_object_unref (save_pixbuf);
 }
 
 static void
 zoom_in (GObject * ignored, ViewerCbInfo * info)
 {
-    if (!info->pixbuf)
-        return;
-    zoom_image (info, 1.25);
+    zoom_image (info, sqrt (G_SQRT2));
 }
 
 static void
 zoom_out (GObject * ignored, ViewerCbInfo * info)
 {
-    if (!info->pixbuf)
-        return;
-    zoom_image (info, 1. / 1.25);
-}
-
-static void
-rsvg_window_set_default_icon (GtkWindow * window, GdkPixbuf * src)
-{
-    GList *list;
-    GdkPixbuf *icon;
-    gint width, height;
-
-    width = gdk_pixbuf_get_width (src);
-    height = gdk_pixbuf_get_height (src);
-
-    if (width > 128 || height > 128) {
-        /* sending images greater than 128x128 has this nasty tendency to 
-           cause broken pipe errors X11 Servers */
-        if (width > height) {
-            width = 0.5 + width * 128. / height;
-            height = 128;
-        } else {
-            height = 0.5 + height * 128. / width;
-            width = 128;
-        }
-
-        icon = gdk_pixbuf_scale_simple (src, width, height, GDK_INTERP_BILINEAR);
-    } else {
-        icon = g_object_ref (src);
-    }
-
-    list = g_list_prepend (NULL, icon);
-    gtk_window_set_icon_list (window, list);
-    g_list_free (list);
-
-    g_object_unref (icon);
+    zoom_image (info, 1. / sqrt (G_SQRT2));
 }
 
-#if GTK_CHECK_VERSION(2,10,0)
-
 static void
 begin_print (GtkPrintOperation *operation,
 			 GtkPrintContext   *context,
@@ -295,48 +283,40 @@ draw_page (GtkPrintOperation *operation,
 		   gpointer           user_data)
 {
     ViewerCbInfo *info = (ViewerCbInfo *) user_data;
+    cairo_t *cr;
+    gdouble page_width, page_height, page_aspect;
+    gdouble width, height, aspect;
+    cairo_matrix_t matrix;
+
+    cr = gtk_print_context_get_cairo_context (context);
+    page_width = gtk_print_context_get_width (context);
+    page_height = gtk_print_context_get_height (context);
+    page_aspect = page_width / page_height;
+
+    // FIXMEchpe
+    rsvg_handle_set_dpi_x_y (info->handle, 
+                             gtk_print_context_get_dpi_x(context), 
+                             gtk_print_context_get_dpi_y(context));
+
+    width = info->dimensions.width;
+    height = info->dimensions.height;
+    aspect = width / height;
+
+    if (aspect <= page_aspect) {
+        width = page_height * aspect;
+        height = page_height;
+    } else {
+        width = page_width;
+        height = page_width / aspect;
+    }
 
-	cairo_t *cr;
-	gdouble page_width, page_height;
-  
-	cr = gtk_print_context_get_cairo_context (context);
-	page_width = gtk_print_context_get_width (context);
-	page_height = gtk_print_context_get_height (context);
-
-	{
-        RsvgHandle *handle;
-        RsvgDimensionData svg_dimensions;
-        struct RsvgSizeCallbackData size_data;
-
-        /* should not fail */
-        handle = rsvg_handle_new_from_data(info->svg_bytes->data, info->svg_bytes->len, NULL);
-        rsvg_handle_set_base_uri (handle, info->base_uri);
-        rsvg_handle_set_dpi_x_y (handle, gtk_print_context_get_dpi_x(context), 
-                                 gtk_print_context_get_dpi_y(context));
-        rsvg_handle_get_dimensions(handle, &svg_dimensions);
-
-        if (svg_dimensions.width > page_width || svg_dimensions.height > page_height) {
-            /* scale down the image to the page's size, while preserving the aspect ratio */
-
-            if ((double) svg_dimensions.height * (double) page_width > (double) svg_dimensions.width * (double) page_height) {
-                svg_dimensions.width = 0.5 + (double) svg_dimensions.width *(double) page_height / (double) svg_dimensions.height;
-                svg_dimensions.height = page_height;
-            } else {
-                svg_dimensions.height = 0.5 + (double) svg_dimensions.height *(double) page_width / (double) svg_dimensions.width;
-                svg_dimensions.width = page_width;
-            }
-        }
-
-        size_data.type = RSVG_SIZE_WH;
-        size_data.width = svg_dimensions.width;
-        size_data.height = svg_dimensions.height;
-        size_data.keep_aspect_ratio = FALSE;
-        rsvg_handle_set_size_callback (handle, _rsvg_size_callback, &size_data, NULL);
-
-        rsvg_handle_render_cairo(handle, cr);
-
-        g_object_unref (handle);
-	}
+    cairo_save (cr);
+    cairo_matrix_init_scale (&matrix, 
+                             width / info->dimensions.width,
+                             height / info->dimensions.height);
+    cairo_transform (cr, &matrix);
+    rsvg_handle_render_cairo (info->handle, cr);
+    cairo_restore (cr);
 }
 
 static void
@@ -356,8 +336,6 @@ print_pixbuf (GObject * ignored, gpointer user_data)
   g_object_unref (print);
 }
 
-#endif                          /* HAVE_GNOME_PRINT */
-
 static char *
 save_file (const char *title, const char *suggested_filename, GtkWidget * parent, int *success)
 {
@@ -391,6 +369,7 @@ save_pixbuf (GObject * ignored, gpointer user_data)
     ViewerCbInfo *info = (ViewerCbInfo *) user_data;
     char *filename, *base_name, *filename_suggestion;
     int success = 0;
+    cairo_surface_t *surface;
 
     base_name = _rsvg_basename (info->base_uri);
     if (base_name)
@@ -403,92 +382,18 @@ save_pixbuf (GObject * ignored, gpointer user_data)
     g_free (filename_suggestion);
 
     if (filename) {
-        GError *err = NULL;
-
-        if (!gdk_pixbuf_save (info->pixbuf, filename, "png", &err, NULL)) {
-            if (err) {
+        surface = rsvg_image_get_surface (info->image);
+        if (cairo_surface_write_to_png (surface, filename) != CAIRO_STATUS_SUCCESS) {
                 GtkWidget *errmsg;
 
                 errmsg = gtk_message_dialog_new (GTK_WINDOW (info->window),
                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                  GTK_MESSAGE_WARNING,
-                                                 GTK_BUTTONS_CLOSE, "%s", err->message);
+                                                 GTK_BUTTONS_CLOSE, "Failed to save");
 
                 gtk_dialog_run (GTK_DIALOG (errmsg));
 
-                g_error_free (err);
                 gtk_widget_destroy (errmsg);
-            }
-        }
-
-        g_free (filename);
-    } else if (success) {
-        GtkWidget *errmsg;
-
-        errmsg = gtk_message_dialog_new (GTK_WINDOW (info->window),
-                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                                         GTK_MESSAGE_WARNING,
-                                         GTK_BUTTONS_CLOSE, _("No filename given"));
-        gtk_window_set_transient_for (GTK_WINDOW (errmsg), GTK_WINDOW (info->window));
-
-        gtk_dialog_run (GTK_DIALOG (errmsg));
-        gtk_widget_destroy (errmsg);
-    }
-}
-
-static void
-save_svg (GObject * ignored, gpointer user_data)
-{
-    ViewerCbInfo *info = (ViewerCbInfo *) user_data;
-    char *filename, *base_name;
-    int success = 0;
-
-    base_name = _rsvg_basename (info->base_uri);
-    filename = save_file (_("Save SVG"), base_name, info->window, &success);
-    g_free (base_name);
-
-    if (filename) {
-        FILE *fp;
-
-        /* todo: make this support gnome vfs */
-        fp = fopen (filename, "wb");
-        if (!fp) {
-            GtkWidget *errmsg;
-
-            errmsg = gtk_message_dialog_new (GTK_WINDOW (info->window),
-                                             GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                                             GTK_MESSAGE_WARNING,
-                                             GTK_BUTTONS_CLOSE, _("Couldn't save %s"), filename);
-            gtk_window_set_transient_for (GTK_WINDOW (errmsg), GTK_WINDOW (info->window));
-
-            gtk_dialog_run (GTK_DIALOG (errmsg));
-            gtk_widget_destroy (errmsg);
-        } else {
-            size_t written = 0, remaining = info->svg_bytes->len;
-            const unsigned char *buffer = info->svg_bytes->data;
-
-            while (remaining > 0) {
-                written = fwrite (buffer + (info->svg_bytes->len - remaining), 1, remaining, fp);
-                if ((written < remaining) && ferror (fp) != 0) {
-                    GtkWidget *errmsg;
-
-                    errmsg = gtk_message_dialog_new (GTK_WINDOW (info->window),
-                                                     GTK_DIALOG_MODAL |
-                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                     GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE,
-                                                     _("Couldn't save %s"), filename);
-                    gtk_window_set_transient_for (GTK_WINDOW (errmsg), GTK_WINDOW (info->window));
-
-                    gtk_dialog_run (GTK_DIALOG (errmsg));
-                    gtk_widget_destroy (errmsg);
-
-                    break;
-                }
-
-                remaining -= written;
-            }
-
-            fclose (fp);
         }
 
         g_free (filename);
@@ -536,17 +441,10 @@ create_popup_menu (ViewerCbInfo * info)
         g_signal_connect (menu_item, "activate", G_CALLBACK (copy_svg_location), info);
         gtk_widget_show (menu_item);
         gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
-        gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY(C),
+        gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY_C,
                                     GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
     }
 
-    menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE, NULL);
-    g_signal_connect (menu_item, "activate", G_CALLBACK (save_svg), info);
-    gtk_widget_show (menu_item);
-    gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
-    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY(S), GDK_CONTROL_MASK,
-                                GTK_ACCEL_VISIBLE);
-
     menu_item = gtk_image_menu_item_new_with_label (_("Save as PNG"));
     stock = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_MENU);
     gtk_widget_show (stock);
@@ -554,30 +452,28 @@ create_popup_menu (ViewerCbInfo * info)
     g_signal_connect (menu_item, "activate", G_CALLBACK (save_pixbuf), info);
     gtk_widget_show (menu_item);
     gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
-    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY(S),
+    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY_S,
                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
 
-#if GTK_CHECK_VERSION(2,10,0)
     menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_PRINT, NULL);
     g_signal_connect (menu_item, "activate", G_CALLBACK (print_pixbuf), info);
     gtk_widget_show (menu_item);
     gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
-    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY(P), GDK_CONTROL_MASK,
+    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY_P, GDK_CONTROL_MASK,
                                 GTK_ACCEL_VISIBLE);
-#endif
 
     menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_ZOOM_IN, NULL);
     g_signal_connect (menu_item, "activate", G_CALLBACK (zoom_in), info);
     gtk_widget_show (menu_item);
     gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
-    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY(plus),
+    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY_plus,
                                 GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
     menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_ZOOM_OUT, NULL);
     g_signal_connect (menu_item, "activate", G_CALLBACK (zoom_out), info);
     gtk_widget_show (menu_item);
     gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
-    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY(minus),
+    gtk_widget_add_accelerator (menu_item, "activate", info->accel_group, GDK_KEY_minus,
                                 GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
     info->popup_menu = popup_menu;
@@ -605,10 +501,17 @@ quit_cb (GtkWidget * win, gpointer unused)
 }
 
 static void
-populate_window (GtkWidget * win, ViewerCbInfo * info, int xid, gint win_width, gint win_height)
+populate_window (GtkWidget * win, 
+                 ViewerCbInfo * info, 
+                 cairo_surface_t *surface /* adopted */,
+                 gint win_width, 
+                 gint win_height)
 {
     GtkWidget *vbox;
     GtkWidget *scroll;
+    GtkWidget *toolbar;
+    GtkToolItem *toolitem;
+    GtkRequisition requisition;
     gint img_width, img_height;
 
 #if GTK_CHECK_VERSION (3, 2, 0)
@@ -618,56 +521,44 @@ populate_window (GtkWidget * win, ViewerCbInfo * info, int xid, gint win_width,
 #endif
     gtk_container_add (GTK_CONTAINER (win), vbox);
 
-    /* create a new image */
-    info->image = gtk_image_new_from_pixbuf (info->pixbuf);
-
     /* pack the window with the image */
-    img_width = gdk_pixbuf_get_width (info->pixbuf);
-    img_height = gdk_pixbuf_get_height (info->pixbuf);
+    img_width = cairo_image_surface_get_width (surface);
+    img_height = cairo_image_surface_get_height (surface);
 
-    if (xid <= 0) {
-		GtkWidget *toolbar;
-		GtkToolItem *toolitem;
-		GtkRequisition requisition;
-
-        toolbar = gtk_toolbar_new ();
-        gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
+    /* create a new image */
+    info->image = rsvg_image_new_take_surface (surface);
 
-        toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_ZOOM_IN);
-        gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, 0);
-        g_signal_connect (toolitem, "clicked", G_CALLBACK (zoom_in), info);
+    toolbar = gtk_toolbar_new ();
+    gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
 
-        toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_ZOOM_OUT);
-        gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, 1);
-        g_signal_connect (toolitem, "clicked", G_CALLBACK (zoom_out), info);
+    toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_ZOOM_IN);
+    gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, 0);
+    g_signal_connect (toolitem, "clicked", G_CALLBACK (zoom_in), info);
 
-		gtk_widget_size_request(toolbar, &requisition);
+    toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_ZOOM_OUT);
+    gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, 1);
+    g_signal_connect (toolitem, "clicked", G_CALLBACK (zoom_out), info);
 
-		/* HACK: adjust for frame width & height + packing borders */
-		img_height += requisition.height + 30;
-		win_height += requisition.height + 30;
-		img_width  += 20;
-		win_width  += 20;
-    }
+    gtk_widget_size_request(toolbar, &requisition);
 
-    if ((xid > 0 && (img_width > win_width || img_height > win_height))
-        || (xid <= 0)) {
-        gtk_window_set_default_size (GTK_WINDOW (win), MIN (img_width, win_width),
-                                     MIN (img_height, win_height));
+    /* HACK: adjust for frame width & height + packing borders */
+    img_height += requisition.height + 30;
+    win_height += requisition.height + 30;
+    img_width  += 20;
+    win_width  += 20;
 
-        scroll = gtk_scrolled_window_new (NULL, NULL);
-        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
-                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-        gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll), info->image);
-        gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
-    } else {
-        gtk_box_pack_start (GTK_BOX (vbox), info->image, TRUE, TRUE, 0);
-        gtk_window_set_default_size (GTK_WINDOW (win), img_width, img_height);
-    }
+    scroll = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll), 
+                                           GTK_WIDGET (info->image));
+    gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
 }
 
 static void
-view_pixbuf (ViewerCbInfo * info, int xid, const char *color)
+view_surface (ViewerCbInfo * info, 
+              cairo_surface_t *surface /* adopted */,
+              const char *color)
 {
     GtkWidget *win;
     GdkColor bg_color;
@@ -680,9 +571,7 @@ view_pixbuf (ViewerCbInfo * info, int xid, const char *color)
     win_width = DEFAULT_WIDTH;
     win_height = DEFAULT_HEIGHT;
 
-    populate_window (win, info, xid, win_width, win_height);
-
-    rsvg_window_set_default_icon (GTK_WINDOW (win), info->pixbuf);
+    populate_window (win, info, surface, win_width, win_height);
 
     /* exit when 'X' is clicked */
     g_signal_connect (win, "destroy", G_CALLBACK (quit_cb), NULL);
@@ -690,17 +579,9 @@ view_pixbuf (ViewerCbInfo * info, int xid, const char *color)
 
     if (color && strcmp (color, "none") != 0) {
         if (gdk_color_parse (color, &bg_color)) {
-            GtkWidget *parent_widget = gtk_widget_get_parent (info->image);
+            GtkWidget *parent_widget = gtk_widget_get_parent (GTK_WIDGET (info->image));
 
-#if GTK_CHECK_VERSION (2, 90, 8)
             gtk_widget_modify_bg (parent_widget, GTK_STATE_NORMAL, &bg_color);
-#else
-            if (gdk_colormap_alloc_color
-                (gtk_widget_get_colormap (parent_widget), &bg_color, FALSE, TRUE))
-                gtk_widget_modify_bg (parent_widget, GTK_STATE_NORMAL, &bg_color);
-            else
-                g_warning (_("Couldn't allocate color '%s'"), color);
-#endif
         } else
             g_warning (_("Couldn't parse color '%s'"), color);
     }
@@ -732,10 +613,12 @@ main (int argc, char **argv)
     int bVersion = 0;
     char *bg_color = NULL;
     char *base_uri = NULL;
-    int bKeepAspect = 0;
+    gboolean keep_aspect_ratio = FALSE;
     char *id = NULL;
+    GInputStream *input;
+    GFile *file, *base_file;
+    cairo_surface_t *surface;
 
-    int xid = -1;
     int from_stdin = 0;
     ViewerCbInfo info;
 
@@ -763,7 +646,7 @@ main (int argc, char **argv)
          N_("<string>")},
         {"id", 0, 0, G_OPTION_ARG_STRING, &id, N_("Only show one node (default: all)"),
          N_("<string>")},
-        {"keep-aspect", 'k', 0, G_OPTION_ARG_NONE, &bKeepAspect,
+        {"keep-aspect", 'k', 0, G_OPTION_ARG_NONE, &keep_aspect_ratio,
          N_("Preserve the image's aspect ratio"), NULL},
         {"version", 'v', 0, G_OPTION_ARG_NONE, &bVersion, N_("Show version information"), NULL},
         {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("[FILE...]")},
@@ -775,8 +658,6 @@ main (int argc, char **argv)
 
     g_type_init ();
 
-    info.pixbuf = NULL;
-    info.svg_bytes = NULL;
     info.window = NULL;
     info.popup_menu = NULL;
 
@@ -795,10 +676,10 @@ main (int argc, char **argv)
         return 0;
     }
 
-    if (args) {
-        while (args[n_args] != NULL)
-            n_args++;
-    }
+    if (args)
+        n_args = g_strv_length (args);
+    else
+        n_args = 0;
 
     if ((!from_stdin) && (n_args != 1)) {
         g_print (_("No files specified, and not using --stdin\n"));
@@ -807,94 +688,70 @@ main (int argc, char **argv)
 
     rsvg_set_default_dpi_x_y (dpi_x, dpi_y);
 
-    /* if both are unspecified, assume user wants to zoom the pixbuf in at least 1 dimension */
-    if (width == -1 && height == -1) {
-        size_data.type = RSVG_SIZE_ZOOM;
-        size_data.x_zoom = x_zoom;
-        size_data.y_zoom = y_zoom;
-    }
-    /* if both are unspecified, assume user wants to resize pixbuf in at least 1 dimension */
-    else if (x_zoom == 1.0 && y_zoom == 1.0) {
-        size_data.type = RSVG_SIZE_WH;
-        size_data.width = width;
-        size_data.height = height;
-    }
-    /* assume the user wants to zoom the pixbuf, but cap the maximum size */
-    else {
-        size_data.type = RSVG_SIZE_ZOOM_MAX;
-        size_data.x_zoom = x_zoom;
-        size_data.y_zoom = y_zoom;
-        size_data.width = width;
-        size_data.height = height;
-    }
-
-    size_data.keep_aspect_ratio = bKeepAspect;
-
-    if (!from_stdin) {
-        if (base_uri == NULL)
-            base_uri = (char *) args[0];
-
-        info.svg_bytes = _rsvg_acquire_xlink_href_resource (args[0], base_uri, NULL);
+    if (from_stdin) {
+#if 0 // defined (G_OS_UNIX)
+        input = g_unix_input_stream_new (STDIN_FILENO, FALSE);
+#else
+        input = NULL;
+        g_set_error_literal (&err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                             "Reading from stdin not supported");
+#endif
+        base_file = NULL;
     } else {
-        info.svg_bytes = g_byte_array_new ();
+        file = g_file_new_for_commandline_arg (args[0]);
+        input = (GInputStream *) g_file_read (file, NULL, &err);
 
-        for (;;) {
-            unsigned char buf[1024 * 8];
-            size_t nread = fread (buf, 1, sizeof (buf), stdin);
+        if (base_uri)
+            base_file = g_file_new_for_uri (base_uri);
+        else
+            base_file = g_object_ref (file);
 
-            if (nread > 0)
-                g_byte_array_append (info.svg_bytes, buf, nread);
-
-            if (nread < sizeof (buf)) {
-                if (ferror (stdin)) {
-                    g_print (_("Error reading\n"));
-                    g_byte_array_free (info.svg_bytes, TRUE);
-                    fclose (stdin);
-
-                    return 1;
-                } else if (feof (stdin))
-                    break;
-            }
-        }
-
-        fclose (stdin);
+        g_object_unref (file);
     }
 
-    if (!info.svg_bytes || !info.svg_bytes->len) {
-        g_print (_("Couldn't open %s\n"), args[0]);
+    g_strfreev (args);
+
+    if (input == NULL) {
+        g_printerr ("Failed to read input: %s\n", err->message);
+        g_error_free (err);
         return 1;
     }
 
-    info.base_uri = base_uri;
+    info.base_uri = base_file ? g_file_get_uri (base_file) : g_strdup ("");
     info.id = id;
     info.x_zoom = x_zoom;
     info.y_zoom = y_zoom;
 
-    if (size_data.type == RSVG_SIZE_ZOOM &&
-        x_zoom == 1.0 && y_zoom == 1.0) {
-        if (!calculate_zoom_ratio (&info, &size_data, &err)) {
-            if (err) {
-                g_print (": %s\n", err->message);
-                g_error_free (err);
-            }
-            return 1;
-        }
+    info.handle = rsvg_handle_new_from_stream_sync (input, 
+                                                    base_file, 
+                                                    RSVG_HANDLE_FLAGS_NONE,
+                                                    NULL /* cancellable */,
+                                                    &err);
+    g_object_unref (base_file);
+
+    if (info.handle == NULL) {
+        g_printerr ("Failed to load SVG: %s\n", err->message);
+        g_error_free (err);
+        g_object_unref (info.handle);
+        return 1;
     }
 
-    info.pixbuf = 
-        pixbuf_from_data_with_size_data (info.svg_bytes->data, info.svg_bytes->len, &size_data,
-                                         base_uri, id, &err);
+    rsvg_handle_get_dimensions (info.handle, &info.dimensions);
 
-    if (!info.pixbuf) {
-        g_print (_("Error displaying image"));
-
-        if (err) {
-            g_print (": %s", err->message);
-            g_error_free (err);
-        }
-
-        g_print ("\n");
+    if (width != -1) {
+        info.x_zoom = (double) width / info.dimensions.width;
+    } else {
+        info.x_zoom = x_zoom;
+    }
+    if (height != -1) {
+        info.y_zoom = (double) height / info.dimensions.height;
+    } else {
+        info.y_zoom = y_zoom;
+    }
 
+    surface = render_to_surface (&info);
+    if (surface == NULL) {
+        g_printerr (_("Error displaying image"));
         goto done;
     }
 
@@ -902,16 +759,15 @@ main (int argc, char **argv)
 
     info.accel_group = gtk_accel_group_new ();
 
-    view_pixbuf (&info, xid, bg_color);
+    view_surface (&info, surface, bg_color);
 
     /* run the gtk+ main loop */
     gtk_main ();
 
-    g_object_unref (info.pixbuf);
-
   done:
-    g_byte_array_free (info.svg_bytes, TRUE);
-    g_strfreev (args);
+
+    g_free (info.base_uri);
+    g_object_unref (info.handle);
 
     rsvg_cleanup ();
 



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