[gnome-games] aisleriot: Make kde card theme support work
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games] aisleriot: Make kde card theme support work
- Date: Tue, 14 Sep 2010 15:57:06 +0000 (UTC)
commit 5e734eb83cf660689613587c2fb6d640d130c91a
Author: Christian Persch <chpe gnome org>
Date: Tue Sep 14 15:24:42 2010 +0200
aisleriot: Make kde card theme support work
Use a recording surface and get its ink extents to know the card
positions and sizes, instead of using the (broken, and slow)
svg_handle_get_dimensions_sub() and rsvg_handle_get_position_sub()
functions.
Blacklist themes known not to work. That leaves us with just one
working theme for now, unfortunately.
aisleriot/lib/ar-card-theme-kde.c | 235 +++++++++++++++++++++----------------
aisleriot/lib/ar-card-theme.h | 3 +-
2 files changed, 135 insertions(+), 103 deletions(-)
---
diff --git a/aisleriot/lib/ar-card-theme-kde.c b/aisleriot/lib/ar-card-theme-kde.c
index 30a4283..0fc3515 100644
--- a/aisleriot/lib/ar-card-theme-kde.c
+++ b/aisleriot/lib/ar-card-theme-kde.c
@@ -1,6 +1,6 @@
/*
Copyright © 2004 Callum McKenzie
- Copyright © 2007, 2008 Christian Persch
+ Copyright © 2007, 2008, 2010 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
@@ -21,9 +21,11 @@
#include <string.h>
#include <glib.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
+#include <librsvg/rsvg.h>
+#include <librsvg/rsvg-cairo.h>
+
#include <libgames-support/games-debug.h>
#include <libgames-support/games-profile.h>
#include <libgames-support/games-preimage.h>
@@ -43,7 +45,7 @@ struct _ArCardThemeKDEClass {
struct _ArCardThemeKDE {
ArCardThemePreimage parent_instance;
- cairo_rectangle_t *bboxes;
+ cairo_rectangle_t *card_extents;
char *backs[MAX_N_BACKS];
guint n_backs : 4; /* enough bits for MAX_N_BACKS */
@@ -52,15 +54,6 @@ struct _ArCardThemeKDE {
guint has_joker : 1;
};
-#include <librsvg/librsvg-features.h>
-
-/* We need librsvg >= 2.22.4 here */
-#if defined(LIBRSVG_CHECK_VERSION)
-#if LIBRSVG_CHECK_VERSION(2, 26, 0)
-#define HAVE_NEW_RSVG
-#endif
-#endif
-
enum {
PROP_0,
PROP_BACK_INDEX,
@@ -83,13 +76,27 @@ enum {
static gboolean
get_is_blacklisted (const char *filename)
{
- /* Let's blacklist these themes, since they exist in g-g-extra-data too,
- * and our variants render faster.
- */
static const char *blacklist[] = {
+ /* These exist in g-g-extra-data too, and ours render faster */
"svg-dondorf",
"svg-nicu-ornamental",
- "svg-gm-paris"
+ "svg-gm-paris",
+ /* These are defective, they have no back card */
+ "svg-ancient-egyptians",
+ "svg-future",
+ "svg-jolly-royal",
+ "svg-konqi-modern",
+ "svg-oxygen",
+ "svg-penguins",
+ "svg-standard",
+ "svg-xskat-french",
+ /* These are broken in some other way */
+ "svg-tigullio-international",
+ "svg-xskat-german",
+ /* These just crash librsvg / cairo */
+ "svg-oxygen-white",
+ /* This is a combinded theme containing card backs */
+ "decks"
};
guint i;
@@ -100,74 +107,57 @@ get_is_blacklisted (const char *filename)
return FALSE;
}
-#ifdef HAVE_NEW_RSVG
-
static cairo_rectangle_t *
-ar_card_theme_kde_get_card_bbox (ArCardThemeKDE *theme,
+ar_card_theme_kde_get_card_extents (ArCardThemeKDE *theme,
int card_id,
const char *node)
{
- cairo_rectangle_t *bbox;
GamesPreimage *preimage;
- RsvgDimensionData dim;
- RsvgPositionData pos;
- gboolean retval;
+ cairo_rectangle_t *card_extents;
+ cairo_rectangle_t rect;
+ cairo_surface_t *surface;
+ cairo_t *cr;
- bbox = &theme->bboxes[card_id];
+ card_extents = &theme->card_extents[card_id];
/* Is it initalised yet? */
- if (bbox->width != G_MAXFLOAT)
- return bbox;
+ if (card_extents->width != 0. && card_extents->height != 0.)
+ return card_extents;
preimage = ((ArCardThemePreimage *) theme)->cards_preimage;
- _games_profile_start ("rsvg_handle_get_dimensions_sub node %s", node);
- retval = rsvg_handle_get_dimensions_sub (preimage->rsvg_handle, &dim, node);
- _games_profile_end ("rsvg_handle_get_dimensions_sub node %s", node);
+ surface = cairo_recording_surface_create (CAIRO_CONTENT_ALPHA, NULL);
+ cr = cairo_create (surface);
+ _games_profile_start ("getting ink extents for node %s", node);
+ rsvg_handle_render_cairo_sub (preimage->rsvg_handle, cr, node);
+ _games_profile_end ("getting ink extents for node %s", node);
+ cairo_destroy (cr);
- if (!retval) {
- _games_debug_print (GAMES_DEBUG_CARD_THEME,
- "Failed to get dim for '%s'\n", node);
- return NULL;
- }
+ cairo_recording_surface_ink_extents (surface, &rect.x, &rect.y, &rect.width, &rect.height);
+ cairo_surface_destroy (surface);
- _games_profile_start ("rsvg_handle_get_position_sub node %s", node);
- retval = rsvg_handle_get_position_sub (preimage->rsvg_handle, &pos, node);
- _games_profile_end ("rsvg_handle_get_position_sub node %s", node);
+ _games_debug_print (GAMES_DEBUG_CARD_THEME,
+ "card %s %.3f x%.3f at (%.3f | %.3f)\n",
+ node,
+ card_extents->width, card_extents->height,
+ card_extents->x, card_extents->y);
- if (!retval) {
- _games_debug_print (GAMES_DEBUG_CARD_THEME,
- "Failed to get pos for '%s'\n", node);
- return NULL;
- }
+ *card_extents = rect;
/* Sanity check; necessary? */
- if (dim.width <= 0 || dim.height <= 0)
+ if (rect.width == 0. || rect.height == 0.)
return NULL;
- bbox->width = dim.width;
- bbox->height = dim.height;
- bbox->x = pos.x;
- bbox->y = pos.y;
-
- _games_debug_print (GAMES_DEBUG_CARD_THEME,
- "card %s position %.3f:%.3f dimension %.3f:%.3f\n",
- node,
- bbox->x, bbox->y, bbox->width, bbox->height);
-
- return bbox;
+ return card_extents;
}
-#endif /* HAVE_NEW_RSVG */
-
/* Class implementation */
G_DEFINE_TYPE (ArCardThemeKDE, ar_card_theme_kde, AR_TYPE_CARD_THEME_PREIMAGE);
static gboolean
ar_card_theme_kde_load (ArCardTheme *card_theme,
- GError **error)
+ GError **error)
{
-#ifdef HAVE_NEW_RSVG
static const char extra_backs[][11] = {
"#blue_back",
"#red_back",
@@ -206,8 +196,11 @@ ar_card_theme_kde_load (ArCardTheme *card_theme,
}
/* No backs at all? Fail! */
- if (theme->n_backs == 0)
+ 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);
@@ -219,37 +212,33 @@ ar_card_theme_kde_load (ArCardTheme *card_theme,
theme->has_2_jokers = has_red_joker && has_black_joker;
theme->has_joker = has_joker;
-
- /* Get the bbox of the card back, which we use to compute the theme's aspect ratio */
- if (!ar_card_theme_kde_get_card_bbox (theme, AR_CARD_BACK, theme->backs[theme->back_index])) {
+
+ /* Get the card_extents of the card back, which we use to compute the theme's aspect ratio */
+ if (!ar_card_theme_kde_get_card_extents (theme, AR_CARD_BACK, theme->backs[theme->back_index])) {
g_set_error (error, AR_CARD_THEME_ERROR, AR_CARD_THEME_ERROR_GENERIC,
"Failed to get the theme's aspect ratio");
return FALSE;
}
return TRUE;
-#else
- return FALSE;
-#endif /* HAVE_NEW_RSVG */
}
static double
ar_card_theme_kde_get_card_aspect (ArCardTheme* card_theme)
{
ArCardThemeKDE *theme = (ArCardThemeKDE *) card_theme;
- cairo_rectangle_t *bbox;
+ cairo_rectangle_t *card_extents;
- bbox = &theme->bboxes[AR_CARD_BACK];
- g_assert (bbox->width != G_MAXFLOAT); /* initialised */
+ card_extents = &theme->card_extents[AR_CARD_BACK];
+ g_assert (card_extents->width != 0 && card_extents->height != 0); /* initialised */
- return bbox->width / bbox->height;
+ return card_extents->width / card_extents->height;
}
static GdkPixbuf *
ar_card_theme_kde_get_card_pixbuf (ArCardTheme *card_theme,
- int card_id)
+ int card_id)
{
-#ifdef HAVE_NEW_RSVG
ArCardThemePreimage *preimage_card_theme = (ArCardThemePreimage *) card_theme;
ArCardThemeKDE *theme = (ArCardThemeKDE *) card_theme;
GamesPreimage *preimage = preimage_card_theme->cards_preimage;
@@ -258,7 +247,7 @@ ar_card_theme_kde_get_card_pixbuf (ArCardTheme *card_theme,
double width, height;
double zoomx, zoomy;
char node[32];
- cairo_rectangle_t *bbox;
+ cairo_rectangle_t *card_extents;
if (G_UNLIKELY (card_id == AR_CARD_SLOT)) {
subpixbuf = games_preimage_render (preimage_card_theme->slot_preimage,
@@ -270,8 +259,8 @@ ar_card_theme_kde_get_card_pixbuf (ArCardTheme *card_theme,
ar_card_get_node_by_id_snprintf (node, sizeof (node), card_id);
- bbox = ar_card_theme_kde_get_card_bbox (theme, card_id, node);
- if (!bbox)
+ card_extents = ar_card_theme_kde_get_card_extents (theme, card_id, node);
+ if (!card_extents)
return NULL;
card_width = ((double) games_preimage_get_width (preimage)) / N_COLS;
@@ -283,23 +272,67 @@ ar_card_theme_kde_get_card_pixbuf (ArCardTheme *card_theme,
zoomx = width / card_width;
zoomy = height / card_height;
-// zoomx = width / bbox->width;
-// zoomy = height / bbox->height;
+// zoomx = width / card_extents->width;
+// zoomy = height / card_extents->height;
subpixbuf = games_preimage_render_sub (preimage,
node,
preimage_card_theme->card_size.width,
preimage_card_theme->card_size.height,
- -bbox->x, -bbox->y,
+ -card_extents->x, -card_extents->y,
zoomx, zoomy);
_games_debug_print (GAMES_DEBUG_CARD_THEME,
"Returning %p\n", subpixbuf);
return subpixbuf;
-#else
- return NULL;
-#endif /* HAVE_NEW_RSVG */
+}
+
+static void
+ar_card_theme_kde_paint_card (ArCardTheme *card_theme,
+ cairo_t *cr,
+ int card_id)
+{
+ ArCardThemePreimage *preimage_card_theme = (ArCardThemePreimage *) card_theme;
+ ArCardThemeKDE *theme = (ArCardThemeKDE *) card_theme;
+ GamesPreimage *preimage = preimage_card_theme->cards_preimage;
+ char node[32];
+ cairo_rectangle_t *card_extents;
+ cairo_matrix_t matrix;
+
+ if (G_UNLIKELY (card_id == AR_CARD_SLOT)) {
+ games_preimage_render_cairo (preimage_card_theme->slot_preimage,
+ cr,
+ preimage_card_theme->card_size.width,
+ preimage_card_theme->card_size.height);
+ return;
+ }
+
+ ar_card_get_node_by_id_snprintf (node, sizeof (node), card_id);
+
+ card_extents = ar_card_theme_kde_get_card_extents (theme, card_id, node);
+ if (!card_extents)
+ return;
+
+ cairo_save (cr);
+
+ if (preimage->font_options) {
+ cairo_set_antialias (cr, cairo_font_options_get_antialias (preimage->font_options));
+
+ cairo_set_font_options (cr, preimage->font_options);
+ }
+
+ cairo_matrix_init_identity (&matrix);
+ cairo_matrix_scale (&matrix,
+ preimage_card_theme->card_size.width / card_extents->width,
+ preimage_card_theme->card_size.height / card_extents->height);
+ cairo_matrix_translate (&matrix, -card_extents->x, -card_extents->y);
+
+ cairo_set_matrix (cr, &matrix);
+
+ rsvg_handle_render_cairo_sub (preimage->rsvg_handle, cr, node);
+
+ cairo_restore (cr);
}
static void
@@ -307,9 +340,9 @@ ar_card_theme_kde_init (ArCardThemeKDE *theme)
{
int i;
- theme->bboxes = g_new0 (cairo_rectangle_t, AR_CARDS_TOTAL);
+ theme->card_extents = g_new0 (cairo_rectangle_t, AR_CARDS_TOTAL);
for (i = 0; i < AR_CARDS_TOTAL; ++i)
- theme->bboxes[i].width = G_MAXFLOAT; /* uninitialised */
+ theme->card_extents[i].width = theme->card_extents[i].height = 0.;
theme->n_backs = 0;
theme->back_index = 0;
@@ -321,7 +354,7 @@ ar_card_theme_kde_finalize (GObject * object)
ArCardThemeKDE *theme = AR_CARD_THEME_KDE (object);
guint i;
- g_free (theme->bboxes);
+ g_free (theme->card_extents);
for (i = 0; i < theme->n_backs; ++i)
g_free (theme->backs[i]);
@@ -331,10 +364,9 @@ ar_card_theme_kde_finalize (GObject * object)
static ArCardThemeInfo *
ar_card_theme_kde_class_get_theme_info (ArCardThemeClass *klass,
- const char *path,
- const char *filename)
+ const char *path,
+ const char *filename)
{
-#ifdef HAVE_NEW_RSVG
ArCardThemeInfo *info = NULL;
char *base_path = NULL, *key_file_path = NULL;
GKeyFile *key_file = NULL;
@@ -354,7 +386,7 @@ ar_card_theme_kde_class_get_theme_info (ArCardThemeClass *klass,
key_file = g_key_file_new ();
if (!g_key_file_load_from_file (key_file, key_file_path, 0, NULL))
goto out;
-
+
if (!g_key_file_has_group (key_file, KDE_BACKDECK_GROUP))
goto out;
@@ -366,12 +398,12 @@ ar_card_theme_kde_class_get_theme_info (ArCardThemeClass *klass,
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);
+ base_path,
+ svg_filename,
+ display_name /* adopts */,
+ pref_name /* adopts */,
+ TRUE /* scalable */,
+ NULL, NULL);
out:
g_free (base_path);
@@ -383,9 +415,6 @@ out:
}
return info;
-#else
- return NULL;
-#endif /* HAVE_NEW_RSVG */
}
static gboolean
@@ -401,15 +430,16 @@ ar_card_theme_kde_class_foreach_theme_dir (ArCardThemeClass *klass,
static void
ar_card_theme_kde_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
ArCardThemeKDE *theme = AR_CARD_THEME_KDE (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:
@@ -423,9 +453,9 @@ ar_card_theme_kde_get_property (GObject *object,
static void
ar_card_theme_kde_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
ArCardThemeKDE *theme = AR_CARD_THEME_KDE (object);
@@ -462,6 +492,7 @@ ar_card_theme_kde_class_init (ArCardThemeKDEClass * klass)
theme_class->load = ar_card_theme_kde_load;
theme_class->get_card_aspect = ar_card_theme_kde_get_card_aspect;
theme_class->get_card_pixbuf = ar_card_theme_kde_get_card_pixbuf;
+ theme_class->paint_card = ar_card_theme_kde_paint_card;
preimage_theme_class->needs_scalable_cards = TRUE;
diff --git a/aisleriot/lib/ar-card-theme.h b/aisleriot/lib/ar-card-theme.h
index 21156f5..0f6fb93 100644
--- a/aisleriot/lib/ar-card-theme.h
+++ b/aisleriot/lib/ar-card-theme.h
@@ -31,7 +31,8 @@ G_BEGIN_DECLS
typedef enum {
AR_CARD_THEME_ERROR_GENERIC = 0,
- AR_CARD_THEME_ERROR_NOT_SCALABLE = 1
+ AR_CARD_THEME_ERROR_NOT_SCALABLE = 1,
+ AR_CARD_THEME_ERROR_MISSING_ELEMENT = 2
} ArCardThemeError;
/* ArCardThemeInfo (boxed) */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]