[aisleriot] all: Add QtSvg based renderer for KDE card themes



commit 9942ed02d7f8978afb7a686614f80c3f164e25ba
Author: Christian Persch <chpe gnome org>
Date:   Wed Dec 10 20:14:31 2014 +0100

    all: Add QtSvg based renderer for KDE card themes
    
    The old one using librsvg is quite slow and doesn't work for most
    of the KDE card themes. Add a new renderer for KDE card themes using
    QtSvg.
    
    Also add an alternative QtSvg based renderer for our native
    card themes. However, most of our card themes don't render correctly
    with it. Apparently QtSvg requires that for xlink:href="#foo" refs, it
    has seen the id="foo" on an element *previously*, instead of it existing
    anywhere in the document.

 configure.ac                         |   49 +++-
 src/Makefile.am                      |    1 +
 src/lib/Makefile.am                  |   21 ++-
 src/lib/ar-card-surface-cache.c      |   21 +-
 src/lib/ar-card-theme-kde.c          |  560 ----------------------------------
 src/lib/ar-card-theme-kde.cpp        |  176 +++++++++++
 src/lib/ar-card-theme-native.cpp     |  148 +++++++++
 src/lib/ar-card-theme-private.h      |   47 +++-
 src/lib/ar-card-theme-qsvg-private.h |   46 +++
 src/lib/ar-card-theme-qsvg.cpp       |  367 ++++++++++++++++++++++
 src/lib/ar-card-theme-svg.c          |    8 +-
 src/lib/ar-card-theme.c              |   27 +-
 src/lib/ar-card-theme.h              |    2 +-
 src/lib/ar-card-themes.c             |   29 ++-
 src/lib/ar-svg.c                     |   15 +-
 src/lib/ar-svg.h                     |    4 +-
 16 files changed, 915 insertions(+), 606 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 7526b05..48d05ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,7 @@ PKGS=
 
 AC_PROG_CC
 AC_PROG_CPP
+AC_PROG_CXX
 AC_PROG_LN_S
 AC_PROG_MKDIR_P
 AC_PROG_SED
@@ -125,15 +126,17 @@ AC_ARG_WITH([card-theme-formats],
 
 case "$with_card_theme_formats" in
   default) with_card_theme_formats="svg,pysol" ;;
-  all) with_card_theme_formats="svg,kde,fixed,sliced,pysol" ;;
+  all) with_card_theme_formats="svg,kde,fixed,native,pysol" ;;
 esac
 
 enable_card_theme_format_svg=no
 enable_card_theme_format_kde=no
 enable_card_theme_format_fixed=no
-enable_card_theme_format_sliced=no
+enable_card_theme_format_native=no
 enable_card_theme_format_pysol=no
+need_svg=no
 need_rsvg=no
+need_qtsvg=no
 
 IFS="${IFS=    }"; gg_saved_ifs="$IFS"; IFS=","
 for format in $with_card_theme_formats; do
@@ -141,7 +144,7 @@ for format in $with_card_theme_formats; do
     svg) enable_card_theme_format_svg=yes ;;
     kde) enable_card_theme_format_kde=yes ;;
     fixed) enable_card_theme_format_fixed=yes ;;
-    sliced) enable_card_theme_format_svg=yes ;;
+    native) enable_card_theme_format_native=yes ;;
     pysol) enable_card_theme_format_pysol=yes ;;
     *) IFS="$gg_saved_ifs" AC_MSG_ERROR([unknown card theme format $format requested]) ;;
   esac
@@ -152,17 +155,21 @@ AC_MSG_RESULT([$with_card_theme_formats])
 
 if test "$enable_card_theme_format_svg" = "yes"; then
   AC_DEFINE([ENABLE_CARD_THEME_FORMAT_SVG],[1],[Define to enable SVG card theme format support])
+  need_svg=yes
   need_rsvg=yes
 fi
 if test "$enable_card_theme_format_kde" = "yes"; then
   AC_DEFINE([ENABLE_CARD_THEME_FORMAT_KDE],[1],[Define to enable KDE card theme format support])
-  need_rsvg=yes
+  need_svg=yes
+  need_qtsvg=yes
 fi
 if test "$enable_card_theme_format_fixed" = "yes"; then
   AC_DEFINE([ENABLE_CARD_THEME_FORMAT_FIXED],[1],[Define to enable prerendered card theme format support])
 fi
-if test "$enable_card_theme_format_sliced" = "yes"; then
-  AC_DEFINE([ENABLE_CARD_THEME_FORMAT_SLICED],[1],[Define to enable pre-2.19 card theme format support])
+if test "$enable_card_theme_format_native" = "yes"; then
+  AC_DEFINE([ENABLE_CARD_THEME_FORMAT_NATIVE],[1],[Define to enable native SVG rendering with QtSvg])
+  need_svg=yes
+  need_qtsvg=yes
 fi
 if test "$enable_card_theme_format_pysol" = "yes"; then
   AC_DEFINE([ENABLE_CARD_THEME_FORMAT_PYSOL],[1],[Define to enable PySol card theme format support])
@@ -171,7 +178,7 @@ fi
 AM_CONDITIONAL([ENABLE_CARD_THEME_FORMAT_SVG],[test "$enable_card_theme_format_svg" = "yes"])
 AM_CONDITIONAL([ENABLE_CARD_THEME_FORMAT_KDE],[test "$enable_card_theme_format_kde" = "yes"])
 AM_CONDITIONAL([ENABLE_CARD_THEME_FORMAT_FIXED],[test "$enable_card_theme_format_fixed" = "yes"])
-AM_CONDITIONAL([ENABLE_CARD_THEME_FORMAT_SLICED],[test "$enable_card_theme_format_sliced" = "yes"])
+AM_CONDITIONAL([ENABLE_CARD_THEME_FORMAT_NATIVE],[test "$enable_card_theme_format_native" = "yes"])
 AM_CONDITIONAL([ENABLE_CARD_THEME_FORMAT_PYSOL],[test "$enable_card_theme_format_pysol" = "yes"])
 
 # Card theme paths
@@ -227,7 +234,7 @@ AC_ARG_WITH([default-card-theme-format],
 AC_MSG_RESULT([$with_default_card_theme_format])
 
 case "$with_default_card_theme_format" in
-  svg|kde|fixed|sliced|pysol) ;;
+  svg|kde|fixed|native|pysol) ;;
   *) AC_MSG_ERROR([card theme format $with_default_card_theme_format unknown])
 esac
 
@@ -306,10 +313,10 @@ fi
 
 have_rsvg=no
 if test "$need_rsvg" = "yes"; then
-  have_rsvg=yes
-
   CAIRO_REQUIRED=1.10.0
 
+  PKG_CHECK_EXISTS([librsvg-2.0 >= $RSVG_REQUIRED],[have_rsvg=yes],[have_rsvg=no])
+
   PKGS="$PKGS librsvg-2.0 >= $RSVG_REQUIRED cairo >= $CAIRO_REQUIRED"
 
   AC_DEFINE([HAVE_RSVG],[1],[Refine if librsvg is available])
@@ -317,6 +324,26 @@ fi
 
 AM_CONDITIONAL([HAVE_RSVG],[test "$have_rsvg" = "yes"])
 
+# Check for QtSvg
+
+have_qtsvg=no
+if test "$need_qtsvg" = "yes"; then
+  QT_SVG_REQUIRED=4.4.0
+
+  PKG_CHECK_EXISTS([QtSvg >= $QT_SVG_REQUIRED],[have_qtsvg=yes],[have_qtsvg=no])
+
+  PKGS="$PKGS QtSvg >= $QT_SVG_REQUIRED"
+  EXTRA_CXX_LIBS="$EXTRA_CXX_LIBS -lstdc++"
+
+  AC_DEFINE([HAVE_QTSVG],[1],[Refine if QtSvg is available])
+fi
+
+AM_CONDITIONAL([HAVE_QTSVG],[test "$have_qtsvg" = "yes"])
+
+if test "$need_svg" = "yes" -a "$have_rsvg" = "no" -a "$have_qtsvg" = "no"; then
+   AC_MSG_ERROR([One of librsvg or QtSvg are required])
+fi
+
 # *****************
 # Extra build tools
 # *****************
@@ -556,6 +583,7 @@ AC_SUBST([AM_CPPFLAGS])
 AC_SUBST([AM_CFLAGS])
 AC_SUBST([AM_CXXFLAGS])
 AC_SUBST([AM_LDFLAGS])
+AC_SUBST([EXTRA_CXX_LIBS])
 
 ##############################################
 ##############################################
@@ -587,6 +615,7 @@ Configuration:
     Platform:              ${with_platform}
     Help method:           ${with_help_method} ${with_help_file_format}
     Using RSVG:            ${have_rsvg}
+    Using QtSvg:           ${have_qtsvg}
     Card theme formats:    ${with_card_theme_formats}
     Default theme format:  ${with_default_card_theme_format}
     Default theme:         ${with_default_card_theme}
diff --git a/src/Makefile.am b/src/Makefile.am
index f88bd03..d6f29df 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -53,6 +53,7 @@ sol_CFLAGS = \
        $(AM_CFLAGS)
 
 sol_LDFLAGS = \
+       $(EXTRA_CXX_LIBS) \
        $(AM_LDFLAGS)
 
 sol_LDADD = \
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index e6e797f..263eafb 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -53,11 +53,23 @@ if ENABLE_CARD_THEME_FORMAT_SVG
 libaisleriot_la_SOURCES += ar-card-theme-svg.c
 endif
 
+endif # HAVE_RSVG
+
+if HAVE_QTSVG
+
+libaisleriot_la_SOURCES += \
+       ar-card-theme-qsvg.cpp \
+       ar-card-theme-qsvg-private.h \
+       $(NULL)
+
 if ENABLE_CARD_THEME_FORMAT_KDE
-libaisleriot_la_SOURCES += ar-card-theme-kde.c
+libaisleriot_la_SOURCES += ar-card-theme-kde.cpp
+endif
+if ENABLE_CARD_THEME_FORMAT_NATIVE
+libaisleriot_la_SOURCES += ar-card-theme-native.cpp
 endif
 
-endif # HAVE_RSVG
+endif # HAVE_QTSVG
 
 if ENABLE_CARD_THEME_FORMAT_PYSOL
 libaisleriot_la_SOURCES += ar-card-theme-pysol.c
@@ -84,6 +96,10 @@ libaisleriot_la_CFLAGS = \
        $(AISLERIOT_CFLAGS) \
        $(AM_CFLAGS)
 
+libaisleriot_la_CXXFLAGS = \
+       $(AISLERIOT_CFLAGS) \
+       $(AM_CXXFLAGS)
+
 libaisleriot_la_LIBADD = \
        $(AISLERIOT_LIBS)
 
@@ -121,6 +137,7 @@ ar_cards_renderer_CFLAGS = \
        $(AM_CFLAGS)
 
 ar_cards_renderer_LDFLAGS = \
+       $(EXTRA_CXX_LIBS) \
        $(AM_LDFLAGS)
 
 ar_cards_renderer_LDADD = \
diff --git a/src/lib/ar-card-surface-cache.c b/src/lib/ar-card-surface-cache.c
index bfd2d84..34fc01d 100644
--- a/src/lib/ar-card-surface-cache.c
+++ b/src/lib/ar-card-surface-cache.c
@@ -23,6 +23,7 @@
 
 #include "ar-card-surface-cache.h"
 #include "ar-card-private.h"
+#include "ar-card-theme-private.h"
 
 struct _ArCardSurfaceCachePrivate
 {
@@ -323,7 +324,6 @@ ar_card_surface_cache_get_card_surface_by_id (ArCardSurfaceCache *cache,
 
   if (surface == NULL) {
     CardSize card_size;
-    cairo_t *cr;
 
     LOG_CACHE_MISS (cache);
 
@@ -337,9 +337,22 @@ ar_card_surface_cache_get_card_surface_by_id (ArCardSurfaceCache *cache,
                                             card_size.width, card_size.height);
     }
 
-    cr = cairo_create (surface);
-    ar_card_theme_paint_card (priv->theme, cr, card_id);
-    cairo_destroy (cr);
+    if (!_ar_card_theme_requires_image_surface (priv->theme)) {
+      ar_card_theme_paint_card (priv->theme, surface, card_id);
+    } else {
+      cairo_surface_t *aux_surface;
+      cairo_t *cr;
+
+      /* Use an auxiliary image surface and paint to the similar surface afterwards */
+      aux_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                                card_size.width, card_size.height);
+      ar_card_theme_paint_card (priv->theme, aux_surface, card_id);
+      cr = cairo_create (surface);
+      cairo_set_source_surface (cr, aux_surface, 0, 0);
+      cairo_paint (cr);
+      cairo_destroy (cr);
+      cairo_surface_destroy (aux_surface);
+    }
 
     if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
       cairo_surface_destroy (surface);
diff --git a/src/lib/ar-card-theme-kde.cpp b/src/lib/ar-card-theme-kde.cpp
new file mode 100644
index 0000000..d4ab302
--- /dev/null
+++ b/src/lib/ar-card-theme-kde.cpp
@@ -0,0 +1,176 @@
+/*
+  Copyright © 2004 Callum McKenzie
+  Copyright © 2007, 2008, 2010, 2014 Christian Persch
+
+  This programme is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This programme 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 General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this programme.  If not, see <http://www.gnu.org/licenses/>. */
+
+/* Authors:   Callum McKenzie <callum physics otago ac nz> */
+
+#include <config.h>
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "ar-debug.h"
+#include "ar-profile.h"
+#include "ar-runtime.h"
+#include "ar-string-utils.h"
+
+#include "ar-card-theme.h"
+#include "ar-card-theme-private.h"
+#include "ar-card-theme-qsvg-private.h"
+
+struct _ArCardThemeKDEClass {
+  ArCardThemeQSvgClass parent_class;
+};
+
+struct _ArCardThemeKDE {
+  ArCardThemeQSvg parent_instance;
+};
+
+#define KDE_CARDS_GROUP           "KDE Cards"
+#define KDE_CARDS_NAME_KEY        "Name"
+#define KDE_CARDS_SVG_KEY         "SVG"
+
+#define KDE_BACKDECK_FILENAME     "index.desktop"
+#define KDE_BACKDECK_GROUP        "KDE Backdeck"
+#define KDE_BACKDECK_BACK_KEY     "Back"
+#define KDE_BACKDECK_NAME_KEY     "Name" /* localised */
+#define KDE_BACKDECK_PYSOL_KEY    "PySol"
+#define KDE_BACKDECK_SVG_KEY      "SVG"
+
+static gboolean
+get_is_blacklisted (const char *filename)
+{
+  static const char *blacklist[] = {
+#if defined(HAVE_RSVG) && defined(ENABLE_CARD_THEME_FORMAT_SVG)
+    /* We have these as native themes, and ours even render faster */
+    "svg-dondorf",
+    "svg-gm-paris", /* Bellot */
+    "svg-nicu-ornamental",
+#endif /* !HAVE_RSVG || !ENABLE_CARD_THEME_FORMAT_SVG */
+
+    /* These are just plaing ugly */
+    "svg-konqi-modern",
+    "svg-standard",
+    "svg-xskat-french",
+  };
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (blacklist); ++i)
+    if (strcmp (filename, blacklist[i]) == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
+/* Class implementation */
+
+extern "C" {
+G_DEFINE_TYPE (ArCardThemeKDE, ar_card_theme_kde, AR_TYPE_CARD_THEME_QSVG);
+}
+
+static void
+ar_card_theme_kde_init (ArCardThemeKDE *theme)
+{
+}
+
+static ArCardThemeInfo *
+ar_card_theme_kde_class_get_theme_info (ArCardThemeClass *klass,
+                                        const char *path,
+                                        const char *filename)
+{
+  ArCardThemeInfo *info = NULL;
+  char *base_path = NULL, *key_file_path = NULL;
+  GKeyFile *key_file = NULL;
+  char *svg_filename = NULL, *name = NULL, *display_name, *pref_name;
+
+  if (get_is_blacklisted (filename)) {
+    ar_debug_print (AR_DEBUG_CARD_THEME,
+                        "KDE card theme %s is blacklisted\n", filename);
+    return NULL;
+  }
+
+  base_path = g_build_filename (path, filename, NULL);
+  if (!g_file_test (path, G_FILE_TEST_IS_DIR))
+    goto out;
+
+  key_file_path = g_build_filename (base_path, KDE_BACKDECK_FILENAME, NULL);
+  key_file = g_key_file_new ();
+  if (!g_key_file_load_from_file (key_file, key_file_path, GKeyFileFlags(0), NULL))
+    goto out;
+
+  if (!g_key_file_has_group (key_file, KDE_BACKDECK_GROUP))
+    goto out;
+
+  name = g_key_file_get_locale_string (key_file, KDE_BACKDECK_GROUP, KDE_BACKDECK_NAME_KEY, NULL, NULL);
+  svg_filename = g_key_file_get_string (key_file, KDE_BACKDECK_GROUP, KDE_BACKDECK_SVG_KEY, NULL);
+  if (!name || !name[0] || !svg_filename || !svg_filename[0])
+    goto out;
+
+  display_name = g_strdup_printf ("%s (KDE)", name);
+  pref_name = g_strdup_printf ("kde:%s", filename);
+  info = _ar_card_theme_info_new (G_OBJECT_CLASS_TYPE (klass),
+                                  base_path,
+                                  svg_filename,
+                                  display_name /* adopts */,
+                                  pref_name /* adopts */,
+                                  TRUE /* scalable */,
+                                  NULL, NULL);
+
+out:
+  g_free (base_path);
+  g_free (key_file_path);
+  g_free (name);
+  g_free (svg_filename);
+  if (key_file) {
+    g_key_file_free (key_file);
+  }
+
+  return info;
+}
+
+static gboolean
+ar_card_theme_kde_class_foreach_theme_dir (ArCardThemeClass *klass,
+                                           ArCardThemeForeachFunc callback,
+                                           gpointer data)
+{
+  if (!_ar_card_theme_class_foreach_env (klass, "AR_CARD_THEME_PATH_KDE", callback, data))
+    return FALSE;
+
+  return callback (klass, KDE_CARD_THEME_PATH, data);
+}
+
+static void
+ar_card_theme_kde_class_init (ArCardThemeKDEClass * klass)
+{
+  ArCardThemeClass *theme_class = AR_CARD_THEME_CLASS (klass);
+
+  theme_class->get_theme_info = ar_card_theme_kde_class_get_theme_info;
+  theme_class->foreach_theme_dir = ar_card_theme_kde_class_foreach_theme_dir;
+}
+
+/* private API */
+
+/**
+ * ar_card_theme_kde_new:
+ *
+ * Returns: a new #ArCardThemeKDE
+ */
+ArCardTheme*
+ar_card_theme_kde_new (void)
+{
+  return (ArCardTheme *) g_object_new (AR_TYPE_CARD_THEME_KDE, NULL);
+}
diff --git a/src/lib/ar-card-theme-native.cpp b/src/lib/ar-card-theme-native.cpp
new file mode 100644
index 0000000..e0e8d4c
--- /dev/null
+++ b/src/lib/ar-card-theme-native.cpp
@@ -0,0 +1,148 @@
+/*
+  Copyright © 2004 Callum McKenzie
+  Copyright © 2007, 2008, 2010, 2014 Christian Persch
+
+  This programme is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This programme 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 General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this programme.  If not, see <http://www.gnu.org/licenses/>. */
+
+/* Authors:   Callum McKenzie <callum physics otago ac nz> */
+
+#include <config.h>
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "ar-debug.h"
+#include "ar-profile.h"
+#include "ar-runtime.h"
+#include "ar-string-utils.h"
+
+#include "ar-card-theme.h"
+#include "ar-card-theme-private.h"
+#include "ar-card-theme-qsvg-private.h"
+
+struct _ArCardThemeNativeClass {
+  ArCardThemeQSvgClass parent_class;
+};
+
+struct _ArCardThemeNative {
+  ArCardThemeQSvg parent_instance;
+};
+
+/* QtSvg can't render these correctly */
+static gboolean
+get_is_blacklisted (const char *filename)
+{
+  static const char *blacklist[] = {
+    "anglo.svgz",
+    "anglo_bitmap.svgz",
+    "gnomangelo.svgz",
+    "gnomangelo_bitmap.svgz",
+    "ornamental.svgz",
+    "swiss-xvii.svgz", /* trivial to fix */
+    "tango.svgz"
+  };
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (blacklist); ++i)
+    if (strcmp (filename, blacklist[i]) == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
+
+/* Class implementation */
+
+extern "C" {
+G_DEFINE_TYPE (ArCardThemeNative, ar_card_theme_native, AR_TYPE_CARD_THEME_QSVG);
+}
+
+static void
+ar_card_theme_native_init (ArCardThemeNative *theme)
+{
+}
+
+static ArCardThemeInfo *
+ar_card_theme_native_class_get_theme_info (ArCardThemeClass *klass,
+                                           const char *path,
+                                           const char *filename)
+{
+  ArCardThemeInfo *info;
+  char *display_name, *real_display_name;
+
+  if (!g_str_has_suffix (filename, ".svgz"))
+    return NULL;
+
+  if (get_is_blacklisted (filename))
+    return NULL;
+
+  display_name = ar_filename_to_display_name (filename);
+  real_display_name = g_strdup_printf ("%s (QtSvg)", display_name);
+  g_free (display_name);
+
+  info = _ar_card_theme_info_new (G_OBJECT_CLASS_TYPE (klass),
+                                  path,
+                                  filename,
+                                  real_display_name /* adopts */,
+                                  g_strdup_printf("native:%s", filename) /* pref name */,
+                                  TRUE /* scalable */,
+                                  NULL, NULL);
+
+  return info;
+}
+
+static gboolean
+ar_card_theme_native_class_foreach_theme_dir (ArCardThemeClass *klass,
+                                              ArCardThemeForeachFunc callback,
+                                              gpointer data)
+{
+  if (!_ar_card_theme_class_foreach_env (klass, "AR_CARD_THEME_PATH_SVG", callback, data))
+    return FALSE;
+  if (!_ar_card_theme_class_foreach_env (klass, "AR_CARD_THEME_PATH_NATIVE", callback, data))
+    return FALSE;
+
+  if (!callback (klass, ar_runtime_get_directory (AR_RUNTIME_SCALABLE_CARDS_DIRECTORY), data))
+    return FALSE;
+
+  /* If we're installed in a non-system prefix, also load the card themes
+   * from the system prefix.
+   */
+  if (!ar_runtime_is_system_prefix ())
+    return callback (klass, "/usr/share/aisleriot/cards", data);
+
+  return TRUE;
+}
+
+static void
+ar_card_theme_native_class_init (ArCardThemeNativeClass * klass)
+{
+  ArCardThemeClass *theme_class = AR_CARD_THEME_CLASS (klass);
+
+  theme_class->get_theme_info = ar_card_theme_native_class_get_theme_info;
+  theme_class->foreach_theme_dir = ar_card_theme_native_class_foreach_theme_dir;
+}
+
+/* private API */
+
+/**
+ * ar_card_theme_native_new:
+ *
+ * Returns: a new #ArCardThemeNative
+ */
+ArCardTheme*
+ar_card_theme_native_new (void)
+{
+  return (ArCardTheme *) g_object_new (AR_TYPE_CARD_THEME_NATIVE, NULL);
+}
diff --git a/src/lib/ar-card-theme-private.h b/src/lib/ar-card-theme-private.h
index ecc110a..ebaaf39 100644
--- a/src/lib/ar-card-theme-private.h
+++ b/src/lib/ar-card-theme-private.h
@@ -16,6 +16,8 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+G_BEGIN_DECLS
+
 #include "ar-card.h"
 
 #ifdef HAVE_RSVG
@@ -85,7 +87,7 @@ struct _ArCardThemeClass {
                                      int card_id);
 
   void        (* paint_card)        (ArCardTheme *theme,
-                                     cairo_t *cr,
+                                     cairo_surface_t *surface,
                                      int card_id);
   void        (* set_font_options)  (ArCardTheme *theme,
                                      const cairo_font_options_t *font_options);
@@ -97,6 +99,7 @@ struct _ArCardTheme {
   ArCardThemeClass *klass;
 
   ArCardThemeInfo *theme_info;
+  gboolean requires_image_surface;
 };
 
 void _ar_card_theme_class_get_theme_infos (ArCardThemeClass *klass,
@@ -115,6 +118,8 @@ gboolean _ar_card_theme_class_foreach_env (ArCardThemeClass *klass,
 
 void _ar_card_theme_emit_changed (ArCardTheme *theme);
 
+gboolean _ar_card_theme_requires_image_surface (ArCardTheme *theme);
+
 #ifdef HAVE_RSVG
 
 /* ArCardThemePreimage (abstract) */
@@ -178,6 +183,42 @@ ArCardTheme* ar_card_theme_svg_new (void);
 
 #endif /* ENABLE_CARD_THEME_FORMAT_SVG */
 
+/* */
+
+#endif /* HAVE_RSVG */
+
+#if 1 //def HAVE_QTSVG
+
+/* ArCardThemeQSvg (abstract) */
+
+#define AR_TYPE_CARD_THEME_QSVG            (ar_card_theme_qsvg_get_type ())
+#define AR_CARD_THEME_QSVG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), AR_TYPE_CARD_THEME_QSVG, 
ArCardThemeQSvg))
+#define AR_CARD_THEME_QSVG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), AR_TYPE_CARD_THEME_QSVG, 
ArCardThemeQSvgClass))
+#define AR_IS_CARD_THEME_QSVG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AR_TYPE_CARD_THEME_QSVG))
+#define AR_IS_CARD_THEME_QSVG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AR_TYPE_CARD_THEME_QSVG))
+#define AR_CARD_THEME_QSVG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), AR_TYPE_CARD_THEME_QSVG, 
ArCardThemeQSvgClass))
+
+typedef struct _ArCardThemeQSvgClass ArCardThemeQSvgClass;
+typedef struct _ArCardThemeQSvg      ArCardThemeQSvg;
+
+GType ar_card_theme_qsvg_get_type (void);
+
+/* ArCardThemeNative */
+
+#define AR_TYPE_CARD_THEME_NATIVE            (ar_card_theme_native_get_type ())
+#define AR_CARD_THEME_NATIVE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), AR_TYPE_CARD_THEME_NATIVE, 
ArCardThemeNative))
+#define AR_CARD_THEME_NATIVE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), AR_TYPE_CARD_THEME_NATIVE, 
ArCardThemeNativeClass))
+#define AR_IS_CARD_THEME_NATIVE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AR_TYPE_CARD_THEME_NATIVE))
+#define AR_IS_CARD_THEME_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AR_TYPE_CARD_THEME_NATIVE))
+#define AR_CARD_THEME_NATIVE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), AR_TYPE_CARD_THEME_NATIVE, 
ArCardThemeNativeClass))
+
+typedef struct _ArCardThemeNativeClass ArCardThemeNativeClass;
+typedef struct _ArCardThemeNative      ArCardThemeNative;
+
+GType ar_card_theme_native_get_type (void);
+
+ArCardTheme* ar_card_theme_native_new (void);
+
 /* ArCardThemeKDE */
 
 #ifdef ENABLE_CARD_THEME_FORMAT_KDE
@@ -200,7 +241,7 @@ ArCardTheme* ar_card_theme_kde_new (void);
 
 /* */
 
-#endif /* HAVE_RSVG */
+#endif /* HAVE_QTSVG */
 
 /* ArCardThemeFixed */
 
@@ -240,3 +281,5 @@ GType ar_card_theme_pysol_get_type (void);
 ArCardTheme* ar_card_theme_pysol_new (void);
 
 #endif /* ENABLE_CARD_THEME_FORMAT_PYSOL */
+
+G_END_DECLS
diff --git a/src/lib/ar-card-theme-qsvg-private.h b/src/lib/ar-card-theme-qsvg-private.h
new file mode 100644
index 0000000..6767caf
--- /dev/null
+++ b/src/lib/ar-card-theme-qsvg-private.h
@@ -0,0 +1,46 @@
+/*
+  Copyright © 2004 Callum McKenzie
+  Copyright © 2007, 2008, 2010, 2014 Christian Persch
+
+  This programme is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This programme 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 General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this programme.  If not, see <http://www.gnu.org/licenses/>. */
+
+/* Authors:   Callum McKenzie <callum physics otago ac nz> */
+
+#include <QApplication>
+#include <QtSvg/QtSvg>
+
+#define MAX_N_BACKS (10)
+
+struct _ArCardThemeQSvgClass {
+  ArCardThemeClass parent_class;
+
+  QApplication *app;
+};
+
+struct _ArCardThemeQSvg {
+  ArCardTheme parent_instance;
+
+  QSvgRenderer *renderer;
+  QSvgRenderer *slot_renderer;
+
+  QRectF back_rect;
+  QSize card_size;
+
+  char *backs[MAX_N_BACKS];
+  guint n_backs : 4; /* enough bits for MAX_N_BACKS */
+  guint back_index : 4; /* same */
+  guint has_2_jokers : 1;
+  guint has_joker : 1;
+  guint legacy : 1;
+};
diff --git a/src/lib/ar-card-theme-qsvg.cpp b/src/lib/ar-card-theme-qsvg.cpp
new file mode 100644
index 0000000..e36cdc7
--- /dev/null
+++ b/src/lib/ar-card-theme-qsvg.cpp
@@ -0,0 +1,367 @@
+/*
+  Copyright © 2004 Callum McKenzie
+  Copyright © 2007, 2008, 2010, 2014 Christian Persch
+
+  This programme is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This programme 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 General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this programme.  If not, see <http://www.gnu.org/licenses/>. */
+
+/* Authors:   Callum McKenzie <callum physics otago ac nz> */
+
+#include <config.h>
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "ar-debug.h"
+#include "ar-profile.h"
+#include "ar-runtime.h"
+#include "ar-string-utils.h"
+
+#include "ar-card-theme.h"
+#include "ar-card-theme-private.h"
+#include "ar-card-theme-qsvg-private.h"
+
+enum {
+  PROP_0,
+  PROP_BACK_INDEX,
+  PROP_N_BACKS,
+};
+
+/* Class implementation */
+
+extern "C" {
+G_DEFINE_TYPE (ArCardThemeQSvg, ar_card_theme_qsvg, AR_TYPE_CARD_THEME);
+}
+
+static gboolean
+ar_card_theme_qsvg_load (ArCardTheme *card_theme,
+                        GError **error)
+{
+  static const char extra_backs[][12] = {
+    "#blue_back",
+    "#red_back",
+    "#green_back"
+  };
+  ArCardThemeQSvg *theme = (ArCardThemeQSvg *) card_theme;
+  char node[32];
+  guint i;
+  gboolean has_red_joker, has_black_joker, has_joker;
+  ArCardThemeInfo *theme_info = card_theme->theme_info;
+  char *path;
+
+  /* Now the main course */
+  path = g_build_filename (theme_info->path, theme_info->filename, NULL);
+
+  theme->renderer = new QSvgRenderer (QString::fromUtf8 (path));
+  if (!theme->renderer->isValid()) {
+    g_set_error (error, AR_CARD_THEME_ERROR, AR_CARD_THEME_ERROR_GENERIC,
+                 "Failed to load \"%s\"", path);
+    g_free (path);
+    return FALSE;
+  }
+
+  g_free (path);
+
+  GError *err = NULL; 
+  GBytes *bytes = g_resources_lookup_data("/org/gnome/aisleriot/art/slot.svg", GResourceLookupFlags(0), 
&err);
+  g_assert_no_error (err);
+
+  theme->slot_renderer = new QSvgRenderer(QByteArray::fromRawData((const char*)g_bytes_get_data(bytes, 
NULL), g_bytes_get_size(bytes)));
+  g_bytes_unref(bytes);
+  if (!theme->slot_renderer->isValid()) {
+    g_set_error_literal (error, AR_CARD_THEME_ERROR, AR_CARD_THEME_ERROR_GENERIC,
+                         "Failed to load slot.svg");
+    return FALSE;
+  }
+  
+  /* Check available backs */
+  g_assert (theme->n_backs == 0);
+
+  ar_card_get_node_by_id_snprintf (node, sizeof (node), AR_CARD_BACK);
+  if (theme->renderer->elementExists(QString (node+1))) {
+    theme->backs[theme->n_backs++] = g_strdup (node+1);
+  }
+
+  for (i = 0; i < G_N_ELEMENTS (extra_backs); ++i) {
+    if (theme->renderer->elementExists(QString(extra_backs[i]+1))) {
+      theme->backs[theme->n_backs++] = g_strdup (extra_backs[i]+1);
+    }
+  }
+
+  for (i = 1; i < 10; ++i) {
+    g_snprintf (node, sizeof (node), "#back_c%d", i);
+    if (theme->renderer->elementExists(QString(node+1))) {
+      theme->backs[theme->n_backs++] = g_strdup (node+1);
+    }
+  }
+
+  /* No backs at all? Fail! */
+  if (theme->n_backs == 0) {
+    g_set_error (error, AR_CARD_THEME_ERROR, AR_CARD_THEME_ERROR_MISSING_ELEMENT,
+                 "Missing element for card back");
+    return FALSE;
+  }
+
+  /* Look for the jokers */
+  ar_card_get_node_by_id_snprintf (node, sizeof (node), AR_CARD_BLACK_JOKER);
+  has_black_joker = theme->renderer->elementExists(QString(node+1));
+  ar_card_get_node_by_id_snprintf (node, sizeof (node), AR_CARD_RED_JOKER);
+  has_red_joker = theme->renderer->elementExists(QString(node+1));
+
+  has_joker = theme->renderer->elementExists(QString("joker"));
+
+  theme->has_2_jokers = has_red_joker && has_black_joker;
+  theme->has_joker = has_joker;
+
+  ar_card_get_legacy_node_by_suit_and_rank_snprintf (node, sizeof (node), AR_CARDS_CLUBS, AR_CARD_ACE);
+  theme->legacy = theme->renderer->elementExists(QString(node+1));
+
+  /* Get the card_extents of the card back, which we use to compute the theme's aspect ratio */
+  QRectF rect = theme->renderer->boundsOnElement(QString(theme->backs[theme->back_index]));
+  if (rect.isNull()) {
+    g_set_error (error, AR_CARD_THEME_ERROR, AR_CARD_THEME_ERROR_GENERIC,
+                 "Failed to get the theme's aspect ratio");
+    return FALSE;
+  }
+
+  theme->back_rect = rect;
+  return TRUE;
+}
+
+static gboolean
+ar_card_theme_qsvg_set_card_size (ArCardTheme *card_theme,
+                                 int width,
+                                 int height,
+                                 double proportion)
+{
+  ArCardThemeQSvg *theme = (ArCardThemeQSvg *) card_theme;
+  double aspect_ratio, twidth, theight;
+  QSize size(width, height);
+
+  if (theme->card_size == size)
+    return FALSE;
+
+  /* Now calculate the card size: find the maximum size that fits
+   * into the given area, preserving the card's aspect ratio.
+   */
+  aspect_ratio = ar_card_theme_get_aspect (card_theme);
+
+  twidth = proportion * width;
+  theight = proportion * height;
+  if (twidth / theight < aspect_ratio) {
+    theight = twidth / aspect_ratio;
+  } else {
+    twidth = theight * aspect_ratio;
+  }
+  
+  QSize tsize(twidth, theight);
+  if (theme->card_size == tsize)
+    return FALSE;
+
+  theme->card_size = tsize;
+
+  _ar_card_theme_emit_changed (card_theme);
+  return TRUE;
+}
+
+static void
+ar_card_theme_qsvg_get_card_size (ArCardTheme *card_theme,
+                                  CardSize *size)
+{
+  ArCardThemeQSvg *theme = (ArCardThemeQSvg *) card_theme;
+
+  size->width = theme->card_size.width();
+  size->height = theme->card_size.height();
+}
+
+static qreal
+ar_card_theme_qsvg_get_card_aspect (ArCardTheme* card_theme)
+{
+  ArCardThemeQSvg *theme = (ArCardThemeQSvg *) card_theme;
+  const QRectF &rect = theme->back_rect;
+
+  return rect.isNull() ? 1. : rect.width() / rect.height ();
+}
+
+static void
+ar_card_theme_qsvg_paint_card (ArCardTheme *card_theme,
+                               cairo_surface_t *surface,
+                               int card_id)
+{
+  ArCardThemeQSvg *theme = (ArCardThemeQSvg *) card_theme;
+  char node[32];
+
+  g_assert_cmpint (cairo_surface_get_type (surface), ==, CAIRO_SURFACE_TYPE_IMAGE);
+  g_assert_cmpint (cairo_image_surface_get_format (surface), ==, CAIRO_FORMAT_ARGB32);
+
+  /* cairo_surface_flush(surface); */
+
+  if (theme->legacy)
+    ar_card_get_legacy_node_by_id_snprintf (node, sizeof (node), card_id);
+  else
+    ar_card_get_node_by_id_snprintf (node, sizeof (node), card_id);
+
+  if (card_id != AR_CARD_SLOT &&
+      !theme->renderer->elementExists(QString(node+1))) {
+    return;
+  }
+
+  QImage img(cairo_image_surface_get_data(surface),
+             cairo_image_surface_get_width(surface),
+             cairo_image_surface_get_height(surface),
+             QImage::Format_ARGB32_Premultiplied);
+  g_assert_cmpuint(img.bytesPerLine(), ==, cairo_image_surface_get_stride(surface));
+
+  /* img.fill(Qt::transparent); */
+  QPainter painter(&img);
+
+  if (card_id != AR_CARD_SLOT)
+    theme->renderer->render(&painter, QString(node+1));
+  else
+    theme->slot_renderer->render(&painter);
+
+  cairo_surface_mark_dirty(surface);
+}
+
+static void
+ar_card_theme_qsvg_init (ArCardThemeQSvg *theme)
+{
+  ArCardTheme *card_theme = (ArCardTheme *) theme;
+  ArCardThemeQSvgClass *klass = AR_CARD_THEME_QSVG_GET_CLASS(theme);
+  static char *argv[] = { (char*)"aisleriot", NULL };
+  static int argc = 1;
+
+  /* guiEnabled = true doesn't work, seems to drag in gtk+2.0 somehow. That
+   * also means we have to use image surfaces.
+   */
+  if (!klass->app)
+    klass->app = new QApplication(argc, argv, false);
+
+  card_theme->requires_image_surface = TRUE;
+
+  theme->back_rect = QRectF();
+  theme->card_size = QSize();
+  theme->n_backs = 0;
+  theme->back_index = 0;
+}
+
+static void
+ar_card_theme_qsvg_finalize (GObject * object)
+{
+  ArCardThemeQSvg *theme = AR_CARD_THEME_QSVG (object);
+  guint i;
+
+  for (i = 0; i < theme->n_backs; ++i)
+    g_free (theme->backs[i]);
+
+  if (theme->renderer)
+    delete theme->renderer;
+  if (theme->slot_renderer)
+    delete theme->slot_renderer;
+
+  G_OBJECT_CLASS (ar_card_theme_qsvg_parent_class)->finalize (object);
+}
+
+static void
+ar_card_theme_qsvg_get_property (GObject    *object,
+                                guint       property_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  ArCardThemeQSvg *theme = AR_CARD_THEME_QSVG (object);
+
+  switch (property_id) {
+    case PROP_BACK_INDEX:
+      g_value_set_int (value, theme->back_index);
+      //      theme->card_extents[AR_CARD_BACK].width = theme->card_extents[AR_CARD_BACK].height = 0;
+      break;
+
+    case PROP_N_BACKS:
+      g_value_set_int (value, theme->n_backs);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+ar_card_theme_qsvg_set_property (GObject      *object,
+                                guint         property_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  ArCardThemeQSvg *theme = AR_CARD_THEME_QSVG (object);
+
+  switch (property_id) {
+    case PROP_BACK_INDEX:
+      theme->back_index = g_value_get_int (value);
+      theme->back_index = CLAMP (theme->back_index, 0, theme->n_backs);
+
+      /* FIXMEchpe don't invalidate the whole thing, just the BACK card */
+      _ar_card_theme_emit_changed (AR_CARD_THEME (theme));
+      break;
+
+    case PROP_N_BACKS:
+      /* not writable */
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+ar_card_theme_qsvg_class_init (ArCardThemeQSvgClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ArCardThemeClass *theme_class = AR_CARD_THEME_CLASS (klass);
+
+  gobject_class->finalize = ar_card_theme_qsvg_finalize;
+  gobject_class->get_property = ar_card_theme_qsvg_get_property;
+  gobject_class->set_property = ar_card_theme_qsvg_set_property;
+
+  theme_class->load = ar_card_theme_qsvg_load;
+  theme_class->set_card_size = ar_card_theme_qsvg_set_card_size;
+  theme_class->get_card_size = ar_card_theme_qsvg_get_card_size;
+  theme_class->get_card_aspect = ar_card_theme_qsvg_get_card_aspect;
+  theme_class->paint_card = ar_card_theme_qsvg_paint_card;
+
+  g_object_class_install_property
+    (gobject_class,
+     PROP_BACK_INDEX,
+     g_param_spec_int ("back-index", NULL, NULL,
+                       0, 15, 0,
+                       GParamFlags(G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_STRINGS)));
+
+  g_object_class_install_property
+    (gobject_class,
+     PROP_N_BACKS,
+     g_param_spec_int ("n-backs", NULL, NULL,
+                       1, 16, 1,
+                       GParamFlags(G_PARAM_READABLE |
+                                   G_PARAM_STATIC_STRINGS)));
+}
+
+/* private API */
+
+/**
+ * ar_card_theme_qsvg_new:
+ *
+ * Returns: a new #ArCardThemeQSvg
+ */
+ArCardTheme*
+ar_card_theme_qsvg_new (void)
+{
+  return (ArCardTheme *) g_object_new (AR_TYPE_CARD_THEME_QSVG, NULL);
+}
diff --git a/src/lib/ar-card-theme-svg.c b/src/lib/ar-card-theme-svg.c
index b7ad3f6..41f7fb6 100644
--- a/src/lib/ar-card-theme-svg.c
+++ b/src/lib/ar-card-theme-svg.c
@@ -51,7 +51,7 @@ G_DEFINE_TYPE (ArCardThemeSVG, ar_card_theme_svg, AR_TYPE_CARD_THEME_PREIMAGE);
 
 static void
 ar_card_theme_svg_paint_card (ArCardTheme *card_theme,
-                              cairo_t *cr,
+                              cairo_surface_t *surface,
                               int card_id)
 {
   ArCardThemePreimage *preimage_card_theme = (ArCardThemePreimage *) card_theme;
@@ -65,7 +65,7 @@ ar_card_theme_svg_paint_card (ArCardTheme *card_theme,
 
   if (G_UNLIKELY (card_id == AR_CARD_SLOT)) {
     ar_svg_render_cairo (preimage_card_theme->slot_preimage,
-                                 cr,
+                                 surface,
                                  preimage_card_theme->card_size.width,
                                  preimage_card_theme->card_size.height);
     return;
@@ -89,7 +89,7 @@ ar_card_theme_svg_paint_card (ArCardTheme *card_theme,
   ar_card_get_node_by_suit_and_rank_snprintf (node, sizeof (node), suit, rank);
 
   ar_svg_render_cairo_sub (svg,
-                                   cr,
+                                   surface,
                                    node,
                                    preimage_card_theme->card_size.width,
                                    preimage_card_theme->card_size.height,
@@ -139,7 +139,7 @@ ar_card_theme_svg_class_foreach_theme_dir (ArCardThemeClass *klass,
    * from the system prefix.
    */
   if (!ar_runtime_is_system_prefix ())
-    return callback (klass, "/usr/share/gnome-games-common/cards", data);
+    return callback (klass, "/usr/share/aisleriot/cards", data);
 
   return TRUE;
 }
diff --git a/src/lib/ar-card-theme.c b/src/lib/ar-card-theme.c
index d512596..8b80f41 100644
--- a/src/lib/ar-card-theme.c
+++ b/src/lib/ar-card-theme.c
@@ -51,6 +51,7 @@ G_DEFINE_ABSTRACT_TYPE (ArCardTheme, ar_card_theme, G_TYPE_OBJECT);
 static void
 ar_card_theme_init (ArCardTheme * theme)
 {
+  theme->requires_image_surface = FALSE;
 }
 
 static GObject *
@@ -151,17 +152,18 @@ cairo_pixels_to_pixbuf (guint8 *pixels,
 /* Two-way adapters cairo <-> pixbuf, so theme classes only need to implement one of them. */
 
 static void ar_card_theme_class_real_paint_card (ArCardTheme *theme,
-                                                 cairo_t *cr,
+                                                 cairo_surface_t *surface,
                                                  int cardid);
 static GdkPixbuf * ar_card_theme_class_real_get_card_pixbuf (ArCardTheme *card_theme,
                                                              int card_id);
 
 static void
 ar_card_theme_class_real_paint_card (ArCardTheme *theme,
-                                     cairo_t *cr,
+                                     cairo_surface_t *surface,
                                      int cardid)
 {
   GdkPixbuf *pixbuf;
+  cairo_t *cr;
 
   g_assert (AR_CARD_THEME_GET_CLASS (theme)->get_card_pixbuf != ar_card_theme_class_real_get_card_pixbuf);
 
@@ -169,11 +171,11 @@ ar_card_theme_class_real_paint_card (ArCardTheme *theme,
   if (pixbuf == NULL)
     return;
 
-  cairo_save (cr);
+  cr = cairo_create (surface);
   gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
   cairo_paint (cr);
-  cairo_restore (cr);
 
+  cairo_destroy (cr);
   g_object_unref (pixbuf);
 }
 
@@ -184,7 +186,6 @@ ar_card_theme_class_real_get_card_pixbuf (ArCardTheme *card_theme,
   int rowstride;
   guint8 *data;
   cairo_surface_t *surface;
-  cairo_t *cr;
   CardSize card_size;
 
   g_assert (AR_CARD_THEME_GET_CLASS (card_theme)->paint_card != ar_card_theme_class_real_paint_card);
@@ -201,9 +202,7 @@ ar_card_theme_class_real_get_card_pixbuf (ArCardTheme *card_theme,
                                                  CAIRO_FORMAT_ARGB32,
                                                  card_size.width, card_size.height,
                                                  rowstride);
-  cr = cairo_create (surface);
-  ar_card_theme_paint_card (card_theme, cr, card_id);
-  cairo_destroy (cr);
+  ar_card_theme_paint_card (card_theme, surface, card_id);
 
   cairo_surface_destroy (surface);
   cairo_pixels_to_pixbuf (data, rowstride, card_size.height);
@@ -268,6 +267,12 @@ _ar_card_theme_emit_changed (ArCardTheme *theme)
   g_signal_emit (theme, signals[CHANGED], 0);
 }
 
+gboolean
+_ar_card_theme_requires_image_surface (ArCardTheme *theme)
+{
+  return theme->requires_image_surface;
+}
+
 ArCardThemeInfo *
 _ar_card_theme_class_get_theme_info (ArCardThemeClass *klass,
                                         const char *dir,
@@ -438,21 +443,21 @@ ar_card_theme_get_card_pixbuf (ArCardTheme *theme,
 /**
  * ar_card_theme_paint_card:
  * @theme:
- * @cr:
+ * @surface:
  * @card_id:
  *
  * Paints the card to @cr.
 */
 void
 ar_card_theme_paint_card (ArCardTheme *theme,
-                          cairo_t *cr,
+                          cairo_surface_t *surface,
                           int cardid)
 {
   g_return_if_fail ((cardid >= 0) && (cardid < AR_CARDS_TOTAL));
 
   ar_profilestart ("loading card %d from theme %s", cardid, theme->theme_info->display_name);
 
-  theme->klass->paint_card (theme, cr, cardid);
+  theme->klass->paint_card (theme, surface, cardid);
 
   ar_profileend ("loading card %d from theme %s", cardid, theme->theme_info->display_name);
 }
diff --git a/src/lib/ar-card-theme.h b/src/lib/ar-card-theme.h
index 6eca07d..47c7725 100644
--- a/src/lib/ar-card-theme.h
+++ b/src/lib/ar-card-theme.h
@@ -95,7 +95,7 @@ GdkPixbuf *ar_card_theme_get_card_pixbuf (ArCardTheme * theme,
                                           int cardid);
 
 void ar_card_theme_paint_card (ArCardTheme *theme,
-                                cairo_t *cr,
+                                cairo_surface_t *surface,
                                 int cardid);
 
 G_END_DECLS
diff --git a/src/lib/ar-card-themes.c b/src/lib/ar-card-themes.c
index 5baacab..db51a19 100644
--- a/src/lib/ar-card-themes.c
+++ b/src/lib/ar-card-themes.c
@@ -70,17 +70,26 @@ theme_type_from_string (const char *type_str,
                         gssize type_str_len)
 {
   const struct {
-    const char name[6];
+    const char name[8];
     GType type;
   } type_strings[] = {
+#ifdef HAVE_QTSVG
+#if defined(ENABLE_CARD_THEME_NATIVE) && !defined(ENABLE_CARD_THEME_FORMAT_SVG)
+    { "svg", AR_TYPE_CARD_THEME_NATIVE },
+#endif /* HAVE_QTSVG */
+#else
 #ifdef HAVE_RSVG
 #ifdef ENABLE_CARD_THEME_FORMAT_SVG
     { "svg", AR_TYPE_CARD_THEME_SVG },
 #endif
+#endif /* HAVE_RSVG */
+#endif /* HAVE_QTSVG */
+#ifdef HAVE_QTSVG
+    { "native", AR_TYPE_CARD_THEME_NATIVE },
 #ifdef ENABLE_CARD_THEME_FORMAT_KDE
     { "kde", AR_TYPE_CARD_THEME_KDE },
 #endif
-#endif /* HAVE_RSVG */
+#endif /* HAVE_QTSVG */
 #ifdef ENABLE_CARD_THEME_FORMAT_PYSOL
     { "pysol", AR_TYPE_CARD_THEME_PYSOL },
 #endif
@@ -202,19 +211,29 @@ ar_card_themes_foreach_theme_dir (GType type,
 
 static gboolean
 ar_card_themes_foreach_theme_type_and_dir (ArCardThemes *theme_manager,
-                                              ArCardThemeForeachFunc callback,
-                                              gpointer data)
+                                           ArCardThemeForeachFunc callback,
+                                           gpointer data)
 {
   const GType types[] = {
   /* List of supported theme types, in order of decreasing precedence */
+#ifdef HAVE_QTSVG
+#ifdef ENABLE_CARD_THEME_NATIVE
+    AR_TYPE_CARD_THEME_NATIVE,
+#endif
+#endif /* HAVE_QTSVG */
 #ifdef HAVE_RSVG
 #ifdef ENABLE_CARD_THEME_FORMAT_SVG
   AR_TYPE_CARD_THEME_SVG,
 #endif
+#endif /* HAVE_RSVG */
+#ifdef HAVE_QTSVG
 #ifdef ENABLE_CARD_THEME_FORMAT_KDE
   AR_TYPE_CARD_THEME_KDE,
 #endif
-#endif /* HAVE_RSVG */
+#if !defined(ENABLE_CARD_THEME_SVG) && !defined(ENABLE_CARD_THEME_NATIVE)
+    AR_TYPE_CARD_THEME_NATIVE,
+#endif
+#endif /* HAVE_QTSVG */
 #ifdef ENABLE_CARD_THEME_FORMAT_PYSOL
   AR_TYPE_CARD_THEME_PYSOL,
 #endif
diff --git a/src/lib/ar-svg.c b/src/lib/ar-svg.c
index aa7fcba..adaa7b3 100644
--- a/src/lib/ar-svg.c
+++ b/src/lib/ar-svg.c
@@ -200,7 +200,7 @@ ar_svg_initable_iface_init (GInitableIface *iface)
 /**
  * ar_svg_render_cairo:
  * @svg: a #ArSvg
- * @cr: a #cairo_t
+ * @surface: a #cairo_surface_t
  * @width: the desired width
  * @height: the desired height
  *
@@ -208,14 +208,14 @@ ar_svg_initable_iface_init (GInitableIface *iface)
  **/
 void
 ar_svg_render_cairo (ArSvg *svg,
-                             cairo_t *cr,
+                     cairo_surface_t *surface,
                              gint width,
                              gint height)
 {
   g_return_if_fail (width > 0 && height > 0);
 
     ar_svg_render_cairo_sub (svg,
-                                     cr,
+                                     surface,
                                      NULL,
                                      width,
                                      height,
@@ -229,7 +229,7 @@ ar_svg_render_cairo (ArSvg *svg,
 /**
  * ar_svg_render_cairo_sub:
  * @svg: a #ArSvg
- * @cr: a #cairo_t
+ * @surface: a #cairo_surface_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
@@ -245,7 +245,7 @@ ar_svg_render_cairo (ArSvg *svg,
  **/
 void
 ar_svg_render_cairo_sub (ArSvg *svg,
-                                 cairo_t *cr,
+                         cairo_surface_t *surface,
                                  const char *node,
                                  int width,
                                  int height,
@@ -254,10 +254,13 @@ ar_svg_render_cairo_sub (ArSvg *svg,
                                  double xzoom,
                                  double yzoom)
 {
+  cairo_t *cr;
   cairo_matrix_t matrix;
 
   g_return_if_fail (AR_IS_SVG (svg));
 
+  cr = cairo_create (surface);
+
   if (svg->font_options) {
     cairo_set_antialias (cr, cairo_font_options_get_antialias (svg->font_options));
 
@@ -271,6 +274,8 @@ ar_svg_render_cairo_sub (ArSvg *svg,
   cairo_set_matrix (cr, &matrix);
 
   rsvg_handle_render_cairo_sub (RSVG_HANDLE (svg), cr, node);
+
+  cairo_destroy (cr);
 }
 
 /**
diff --git a/src/lib/ar-svg.h b/src/lib/ar-svg.h
index 1453a1e..c7bda30 100644
--- a/src/lib/ar-svg.h
+++ b/src/lib/ar-svg.h
@@ -61,12 +61,12 @@ void ar_svg_set_font_options (ArSvg *svg,
                               const cairo_font_options_t *font_options);
 
 void ar_svg_render_cairo (ArSvg *svg,
-                                  cairo_t *cr,
+                          cairo_surface_t *surface,
                                   gint width,
                                   gint height);
 
 void ar_svg_render_cairo_sub (ArSvg *svg,
-                                      cairo_t *cr,
+                              cairo_surface_t *surface,
                                       const char *node,
                                       int width,
                                       int height,



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