[aisleriot] Support compressed SVG files



commit 1de6550ead1837c63e8980197c0e3169229bf8d1
Author: Christian Persch <chpe gnome org>
Date:   Tue Apr 26 21:50:06 2011 +0200

    Support compressed SVG files
    
    Make ArSvg inherit RsvgHandle, implement GInitable, and support
    SVGZ files.

 src/lib/Makefile.am              |    1 -
 src/lib/ar-card-theme-kde.c      |   28 +++---
 src/lib/ar-card-theme-preimage.c |    4 +-
 src/lib/ar-card-theme-svg.c      |    1 -
 src/lib/ar-svg-private.h         |   32 ------
 src/lib/ar-svg.c                 |  198 ++++++++++++++++++++++++++++----------
 src/lib/ar-svg.h                 |   35 ++++---
 7 files changed, 184 insertions(+), 115 deletions(-)
---
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index f6529e4..dfdea2e 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -50,7 +50,6 @@ if HAVE_RSVG
 libaisleriot_la_SOURCES += \
 	ar-svg.c \
 	ar-svg.h \
-	ar-svg-private.h \
 	ar-card-theme-preimage.c \
 	$(NULL)
 
diff --git a/src/lib/ar-card-theme-kde.c b/src/lib/ar-card-theme-kde.c
index 7abf22a..38bff97 100644
--- a/src/lib/ar-card-theme-kde.c
+++ b/src/lib/ar-card-theme-kde.c
@@ -29,7 +29,6 @@
 #include "ar-debug.h"
 #include "ar-profile.h"
 #include "ar-svg.h"
-#include "ar-svg-private.h"
 #include "ar-runtime.h"
 #include "ar-string-utils.h"
 
@@ -205,7 +204,7 @@ ar_card_theme_kde_get_card_extents (ArCardThemeKDE *theme,
   surface = cairo_recording_surface_create (CAIRO_CONTENT_ALPHA, NULL);
   cr = cairo_create (surface);
   ar_profilestart ("getting ink extents for node %s", node);
-  rsvg_handle_render_cairo_sub (svg->rsvg_handle, cr, node);
+  rsvg_handle_render_cairo_sub (RSVG_HANDLE (svg), cr, node);
   ar_profileend ("getting ink extents for node %s", node);
   cairo_destroy (cr);
 
@@ -242,6 +241,7 @@ ar_card_theme_kde_load (ArCardTheme *card_theme,
   };
   ArCardThemeKDE *theme = (ArCardThemeKDE *) card_theme;
   ArSvg *svg;
+  RsvgHandle *rsvg_handle;
   char node[32];
   guint i;
   gboolean has_red_joker, has_black_joker, has_joker;
@@ -250,24 +250,25 @@ ar_card_theme_kde_load (ArCardTheme *card_theme,
     return FALSE;
 
   svg = ((ArCardThemePreimage *) theme)->cards_svg;
+  rsvg_handle = RSVG_HANDLE (svg);
 
   /* Check available backs */
   g_assert (theme->n_backs == 0);
 
   ar_card_get_node_by_id_snprintf (node, sizeof (node), AR_CARD_BACK);
-  if (rsvg_handle_has_sub (svg->rsvg_handle, node)) {
+  if (rsvg_handle_has_sub (rsvg_handle, node)) {
     theme->backs[theme->n_backs++] = g_strdup (node);
   }
 
   for (i = 0; i < G_N_ELEMENTS (extra_backs); ++i) {
-    if (rsvg_handle_has_sub (svg->rsvg_handle, extra_backs[i])) {
+    if (rsvg_handle_has_sub (rsvg_handle, extra_backs[i])) {
       theme->backs[theme->n_backs++] = g_strdup (extra_backs[i]);
     }
   }
 
   for (i = 1; i < 10; ++i) {
     g_snprintf (node, sizeof (node), "#back_c%d", i);
-    if (rsvg_handle_has_sub (svg->rsvg_handle, node)) {
+    if (rsvg_handle_has_sub (rsvg_handle, node)) {
       theme->backs[theme->n_backs++] = g_strdup (node);
     }
   }
@@ -281,11 +282,11 @@ ar_card_theme_kde_load (ArCardTheme *card_theme,
 
   /* Look for the jokers */
   ar_card_get_node_by_id_snprintf (node, sizeof (node), AR_CARD_BLACK_JOKER);
-  has_black_joker = rsvg_handle_has_sub (svg->rsvg_handle, node);
+  has_black_joker = rsvg_handle_has_sub (rsvg_handle, node);
   ar_card_get_node_by_id_snprintf (node, sizeof (node), AR_CARD_RED_JOKER);
-  has_red_joker = rsvg_handle_has_sub (svg->rsvg_handle, node);
+  has_red_joker = rsvg_handle_has_sub (rsvg_handle, node);
 
-  has_joker = rsvg_handle_has_sub (svg->rsvg_handle, "#joker");
+  has_joker = rsvg_handle_has_sub (rsvg_handle, "#joker");
 
   theme->has_2_jokers = has_red_joker && has_black_joker;
   theme->has_joker = has_joker;
@@ -323,6 +324,7 @@ ar_card_theme_kde_paint_card (ArCardTheme *card_theme,
   char node[32];
   cairo_rectangle_t *card_extents;
   cairo_matrix_t matrix;
+  cairo_font_options_t *font_options;
 
   if (G_UNLIKELY (card_id == AR_CARD_SLOT)) {
     ar_svg_render_cairo (preimage_card_theme->slot_preimage,
@@ -340,10 +342,10 @@ ar_card_theme_kde_paint_card (ArCardTheme *card_theme,
 
   cairo_save (cr);
 
-  if (svg->font_options) {
-    cairo_set_antialias (cr, cairo_font_options_get_antialias (svg->font_options));
-
-    cairo_set_font_options (cr, svg->font_options);
+  font_options = ar_svg_get_font_options (svg);
+  if (font_options) {
+    cairo_set_antialias (cr, cairo_font_options_get_antialias (font_options));
+    cairo_set_font_options (cr, font_options);
   }
 
   cairo_matrix_init_identity (&matrix);
@@ -354,7 +356,7 @@ ar_card_theme_kde_paint_card (ArCardTheme *card_theme,
 
   cairo_set_matrix (cr, &matrix);
 
-  rsvg_handle_render_cairo_sub (svg->rsvg_handle, cr, node);
+  rsvg_handle_render_cairo_sub (RSVG_HANDLE (svg), cr, node);
 
   cairo_restore (cr);
 }
diff --git a/src/lib/ar-card-theme-preimage.c b/src/lib/ar-card-theme-preimage.c
index 279b77d..8056706 100644
--- a/src/lib/ar-card-theme-preimage.c
+++ b/src/lib/ar-card-theme-preimage.c
@@ -68,7 +68,7 @@ ar_card_theme_preimage_load (ArCardTheme *card_theme,
   /* FIXMEchpe: use uninstalled data dir for rendering the card theme! */
   slot_dir = ar_runtime_get_directory (AR_RUNTIME_PIXMAP_DIRECTORY);
   path = g_build_filename (slot_dir, "slot.svg", NULL);
-  theme->slot_preimage = ar_svg_new_from_file (path, error);
+  theme->slot_preimage = ar_svg_new_from_filename_sync (path, NULL, error);
   g_free (path);
   if (!theme->slot_preimage)
     return FALSE;
@@ -76,7 +76,7 @@ ar_card_theme_preimage_load (ArCardTheme *card_theme,
 
   /* Now the main course */
   path = g_build_filename (theme_info->path, theme_info->filename, NULL);
-  theme->cards_svg = ar_svg_new_from_file (path, error);
+  theme->cards_svg = ar_svg_new_from_filename_sync (path, NULL, error);
   g_free (path);
   if (!theme->cards_svg)
     return FALSE;
diff --git a/src/lib/ar-card-theme-svg.c b/src/lib/ar-card-theme-svg.c
index 5aaebf0..b7ad3f6 100644
--- a/src/lib/ar-card-theme-svg.c
+++ b/src/lib/ar-card-theme-svg.c
@@ -26,7 +26,6 @@
 #include <gtk/gtk.h>
 
 #include "ar-svg.h"
-#include "ar-svg-private.h"
 #include "ar-runtime.h"
 #include "ar-string-utils.h"
 
diff --git a/src/lib/ar-svg.c b/src/lib/ar-svg.c
index 4fff3fc..0a6748b 100644
--- a/src/lib/ar-svg.c
+++ b/src/lib/ar-svg.c
@@ -1,6 +1,6 @@
 /*
    Copyright © 2004 Richard Hoelscher
-   Copyright © 2007 Christian Persch
+   Copyright © 2007, 2011 Christian Persch
    
    This library is free software; you can redistribute it and'or modify
    it under the terms of the GNU Library General Public License as published 
@@ -37,16 +37,29 @@
 #include "ar-profile.h"
 
 #include "ar-svg.h"
-#include "ar-svg-private.h"
+
+struct _ArSvgClass {
+  RsvgHandleClass parent_class;
+};
+
+struct _ArSvg {
+  RsvgHandle parent_instance;
+
+  cairo_font_options_t *font_options;
+  GFile *file;
+
+  gint width;
+  gint height;
+};
 
 enum {
   PROP_0,
-  PROP_FILENAME
+  PROP_FILE
 };
 
 static void ar_svg_initable_iface_init (GInitableIface *iface);
 
-G_DEFINE_TYPE_WITH_CODE (ArSvg, ar_svg, G_TYPE_OBJECT,
+G_DEFINE_TYPE_WITH_CODE (ArSvg, ar_svg, RSVG_TYPE_HANDLE,
                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, ar_svg_initable_iface_init))
 
 static void
@@ -62,21 +75,56 @@ ar_svg_initable_init (GInitable *initable,
                       GError **error)
 {
   ArSvg *svg = AR_SVG (initable);
+  RsvgHandle *handle = RSVG_HANDLE (initable);
+  GFileInfo *info;
+  const char *type;
+  char *gz_type;
+  GInputStream *stream;
   RsvgDimensionData data;
+  gboolean is_gzip;
   gboolean retval = FALSE;
 
-  ar_profilestart ("creating ArSvg from %s", svg->filename);
+//   ar_profilestart ("creating ArSvg from %s", svg->filename);
 
-  svg->rsvg_handle = rsvg_handle_new_from_file (svg->filename, error);
-  if (svg->rsvg_handle == NULL)
+  if (!(info = g_file_query_info (svg->file,
+                                  G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE,
+                                  G_FILE_QUERY_INFO_NONE,
+                                  cancellable,
+                                  error)))
     goto out;
 
-  rsvg_handle_get_dimensions (svg->rsvg_handle, &data);
+  type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
+  gz_type = g_content_type_from_mime_type ("application/x-gzip");
+  is_gzip = (type != NULL && g_content_type_is_a (type, gz_type));
+  g_free (gz_type);
+  g_object_unref (info);
+
+  if (!(stream = G_INPUT_STREAM (g_file_read (svg->file, cancellable, error))))
+    goto out;
 
+  if (is_gzip) {
+    GZlibDecompressor *decompressor;
+    GInputStream *converter_stream;
+
+    decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
+    converter_stream = g_converter_input_stream_new (stream,
+                                                     G_CONVERTER (decompressor));
+    g_object_unref (stream);
+    stream = converter_stream;
+  }
+
+  if (!rsvg_handle_read_stream_sync (handle, stream, cancellable, error)) {
+    g_object_unref (stream);
+    goto out;
+  }
+  g_object_unref (stream);
+
+  rsvg_handle_get_dimensions (handle, &data);
   if (data.width == 0 || data.height == 0) {
-    g_set_error (error,
-                  GDK_PIXBUF_ERROR,
-                  GDK_PIXBUF_ERROR_FAILED, "Image has zero extent");
+    g_set_error_literal (error,
+                         GDK_PIXBUF_ERROR,
+                         GDK_PIXBUF_ERROR_FAILED,
+                         "Image has zero extent");
     goto out;
   }
 
@@ -86,7 +134,8 @@ ar_svg_initable_init (GInitable *initable,
   retval = TRUE;
 
 out:
-  ar_profileend ("creating ArSvg from %s", svg->filename);
+
+//   ar_profileend ("creating ArSvg from %s", svg->filename);
   return retval;
 }
 
@@ -95,9 +144,8 @@ ar_svg_finalize (GObject * object)
 {
   ArSvg *svg = AR_SVG (object);
 
-  if (svg->rsvg_handle != NULL) {
-    g_object_unref (svg->rsvg_handle);
-  }
+  if (svg->file)
+    g_object_unref (svg->file);
   if (svg->font_options) {
     cairo_font_options_destroy (svg->font_options);
   }
@@ -114,8 +162,10 @@ ar_svg_set_property (GObject      *object,
   ArSvg *svg = AR_SVG (object);
 
   switch (property_id) {
-    case PROP_FILENAME:
-      svg->filename = g_value_dup_string (value);
+    case PROP_FILE:
+      svg->file = g_value_dup_object (value);
+      if (svg->file)
+        rsvg_handle_set_base_gfile (RSVG_HANDLE (svg), svg->file);
       break;
 
     default:
@@ -133,9 +183,9 @@ ar_svg_class_init (ArSvgClass * klass)
 
   g_object_class_install_property
     (object_class,
-     PROP_FILENAME,
-     g_param_spec_string ("filename", NULL, NULL,
-                          NULL,
+     PROP_FILE,
+     g_param_spec_object ("file", NULL, NULL,
+                          G_TYPE_FILE,
                           G_PARAM_WRITABLE |
                           G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
@@ -151,13 +201,12 @@ ar_svg_initable_iface_init (GInitableIface *iface)
 
 /**
  * ar_svg_render_cairo:
- * @preimage:
- * @cr:
+ * @svg: a #ArSvg
+ * @cr: a #cairo_t
  * @width: the desired width
  * @height: the desired height
  *
- * Renders from @preimage's image at the specified
- * @width and @height to @cr.
+ * Paints the SVG at the specified @width and @height to @cr.
  **/
 void
 ar_svg_render_cairo (ArSvg *svg,
@@ -181,9 +230,9 @@ ar_svg_render_cairo (ArSvg *svg,
 
 /**
  * ar_svg_render_cairo_sub:
- * @preimage:
- * @cr:
- * @node: a SVG node ID (starting with "#"), or %NULL
+ * @svg: a #ArSvg
+ * @cr: a #cairo_t
+ * @node: (allow-none): a SVG node ID (starting with "#"), or %NULL
  * @width: the width of the clip region
  * @height: the height of the clip region
  * @xoffset: the x offset of the clip region
@@ -191,14 +240,10 @@ ar_svg_render_cairo (ArSvg *svg,
  * @xzoom: the x zoom factor
  * @yzoom: the y zoom factor
  *
- * Creates a #GdkPixbuf with the dimensions @width by @height,
- * and renders the subimage of @preimage specified by @node to it,
- * transformed by @xzoom, @yzoom and offset by @xoffset and @yoffset,
- * clipped to @width and @height.
- * If @node is NULL, the whole image is rendered into tha clip region.
+ * Paints the SVG element @node to @cr, transformed by @xzoom, @yzoom
+ * and offset by @xoffset and @yoffset, clipped to @width and @height.
  *
- * Returns: %TRUE, of %FALSE if there was an error or @preimage
- * isn't a scalable SVG image
+ * If @node is NULL, the whole image is rendered into tha clip region.
  **/
 void
 ar_svg_render_cairo_sub (ArSvg *svg,
@@ -227,37 +272,88 @@ ar_svg_render_cairo_sub (ArSvg *svg,
 
   cairo_set_matrix (cr, &matrix);
 
-  rsvg_handle_render_cairo_sub (svg->rsvg_handle, cr, node);
+  rsvg_handle_render_cairo_sub (RSVG_HANDLE (svg), cr, node);
 }
 
 /**
- * ar_svg_new_from_file:
- * @filename:
- * @error: a location for a #GError
+ * ar_svg_new_from_gfile_sync:
+ * @file: a #GFile
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a location to store a #GError, or %NULL
  *
- * Creates a new #ArSvg from the image in @filename.
+ * Creates a new #ArSvg and synchronously loads its contents from @file.
  *
- * Returns: (allow-none): a new #ArSvg, or %NULL if there was an error
+ * Returns: (allow-none): a new #ArSvg, or %NULL on error with @error
+ *   filled in
  */
 ArSvg *
-ar_svg_new_from_file (const gchar * filename, GError ** error)
+ar_svg_new_from_gfile_sync (GFile *file,
+                            GCancellable *cancellable,
+                            GError ** error)
 {
-  g_return_val_if_fail (filename != NULL, NULL);
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
   return g_initable_new (AR_TYPE_SVG,
-                         NULL,
+                         cancellable,
                          error,
-                         "filename", filename,
+                         "file", file,
                          NULL);
 }
 
 /**
+ * ar_svg_new_from_filename:
+ * @filename: the path to the SVG file
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a location to store a #GError, or %NULL
+ *
+ * Creates a new #ArSvg and synchronously loads its contents from @filename.
+ *
+ * Returns: (allow-none): a new #ArSvg, or %NULL on error with @error
+ *   filled in
+ */
+ArSvg *
+ar_svg_new_from_filename_sync (const char *filename,
+                               GCancellable *cancellable,
+                               GError ** error)
+{
+  GFile *file;
+  ArSvg *svg;
+
+  g_return_val_if_fail (filename != NULL, NULL);
+
+  file = g_file_new_for_path (filename);
+  svg = ar_svg_new_from_gfile_sync (file, cancellable, error);
+  g_object_unref (file);
+
+  return svg;
+}
+
+/**
+ * ar_svg_get_font_options:
+ * @svg: a #ArSvg
+ *
+ * Returns the font options set in @svg.
+ * 
+ * Retursn: (transfer none): a #cairo_font_options_t, or %NULL
+ */
+cairo_font_options_t *
+ar_svg_get_font_options (ArSvg *svg)
+{
+  g_return_val_if_fail (AR_IS_SVG (svg), NULL);
+
+  return svg->font_options;
+}
+
+/**
  * ar_svg_set_font_options:
- * @preimage: a #ArSvg
- * @font_options: the font options
+ * @svg: a #ArSvg
+ * @font_options: (allow-none): a #cairo_font_options_t, or %NULL
  *
- * Turns on antialising of @preimage, if it contains an SVG image.
+ * Sets font options to use when painting to cairo using
+ * ar_svg_render_cairo_sub(). Use %NULL to unset previously set
+ * font options.
  */
 void
 ar_svg_set_font_options (ArSvg *svg,
@@ -278,9 +374,9 @@ ar_svg_set_font_options (ArSvg *svg,
 
 /**
  * ar_svg_get_width:
- * @preimage:
+ * @svg: a #ArSvg
  *
- * Returns: the natural width of the image in @preimage
+ * Returns: the natural width of the image in @svg
  */
 gint
 ar_svg_get_width (ArSvg *svg)
@@ -292,9 +388,9 @@ ar_svg_get_width (ArSvg *svg)
 
 /**
  * ar_svg_get_height:
- * @preimage:
+ * @svg: a #ArSvg
  *
- * Returns: the natural height of the image in @preimage
+ * Returns: the natural height of the image in @svg
  */
 gint
 ar_svg_get_height (ArSvg *svg)
diff --git a/src/lib/ar-svg.h b/src/lib/ar-svg.h
index 562b473..90c1bac 100644
--- a/src/lib/ar-svg.h
+++ b/src/lib/ar-svg.h
@@ -1,5 +1,6 @@
 /*
   Copyright © 2004 Richard Hoelscher
+  Copyright © 2011 Christian Persch
 
   This library is free software; you can redistribute it and'or modify
   it under the terms of the GNU Library General Public License as published
@@ -22,9 +23,9 @@
 #ifndef AR_SVG_H
 #define AR_SVG_H
 
-#include <glib.h>
+#include <gio/gio.h>
 #include <cairo.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <librsvg/rsvg.h>
 
 G_BEGIN_DECLS
 
@@ -35,28 +36,32 @@ G_BEGIN_DECLS
 #define AR_IS_SVG_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), AR_TYPE_SVG))
 #define AR_GET_SVG_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), AR_TYPE_SVG, ArSvgClass))
 
-typedef struct _ArSvg ArSvg;
-
-typedef struct {
-  GObjectClass parent_class;
-} ArSvgClass;
+typedef struct _ArSvg      ArSvg;
+typedef struct _ArSvgClass ArSvgClass;
 
 GType ar_svg_get_type (void);
 
 ArSvg *ar_svg_new (void);
 
-ArSvg *ar_svg_new_from_file (const gchar * filename,
-                                             GError ** error);
+ArSvg *ar_svg_new_from_gfile_sync (GFile *file,
+                                   GCancellable *cancellable,
+                                   GError ** error);
+
+ArSvg *ar_svg_new_from_filename_sync (const gchar * filename,
+                                      GCancellable *cancellable,
+                                      GError ** error);
+
+cairo_font_options_t *ar_svg_get_font_options (ArSvg *svg);
 
-void ar_svg_set_font_options (ArSvg * preimage,
-                                      const cairo_font_options_t *font_options);
+void ar_svg_set_font_options (ArSvg *svg,
+                              const cairo_font_options_t *font_options);
 
-void ar_svg_render_cairo (ArSvg * preimage,
+void ar_svg_render_cairo (ArSvg *svg,
                                   cairo_t *cr,
                                   gint width,
                                   gint height);
 
-void ar_svg_render_cairo_sub (ArSvg * preimage,
+void ar_svg_render_cairo_sub (ArSvg *svg,
                                       cairo_t *cr,
                                       const char *node,
                                       int width,
@@ -66,9 +71,9 @@ void ar_svg_render_cairo_sub (ArSvg * preimage,
                                       double xzoom,
                                       double yzoom);
 
-gint ar_svg_get_width (ArSvg * preimage);
+gint ar_svg_get_width (ArSvg *svg);
 
-gint ar_svg_get_height (ArSvg * preimage);
+gint ar_svg_get_height (ArSvg *svg);
 
 G_END_DECLS
 



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