[Swfdec-commits] 20 commits - configure.ac swfdec-gtk/swfdec_gtk_widget.c swfdec/Makefile.am swfdec/swfdec_actor.c swfdec/swfdec_cache.c swfdec/swfdec_cached.c swfdec/swfdec_cached.h swfdec/swfdec_cached_image.c swfdec/swfdec_cached_image.h swfdec/swfdec_cache.h swfdec/swfdec_gradient_pattern.c swfdec/swfdec.h swfdec/swfdec_image.c swfdec/swfdec_image_decoder.c swfdec/swfdec_image.h swfdec/swfdec_movie.c swfdec/swfdec_pattern.c swfdec/swfdec_pattern.h swfdec/swfdec_player.c swfdec/swfdec_player.h swfdec/swfdec_player_internal.h swfdec/swfdec_renderer.c swfdec/swfdec_renderer.h swfdec/swfdec_renderer_internal.h swfdec/swfdec_sound.c swfdec/swfdec_sound.h swfdec/swfdec_stroke.c swfdec/swfdec_swf_decoder.c swfdec/swfdec_text_field_movie.c swfdec/swfdec_text_field_movie.h swfdec/swfdec_types.h tools/dump.c tools/swfdec-extract.c

Benjamin Otte company at kemper.freedesktop.org
Tue Apr 8 11:01:40 PDT 2008


 configure.ac                      |    2 
 swfdec-gtk/swfdec_gtk_widget.c    |   56 ++++-
 swfdec/Makefile.am                |    4 
 swfdec/swfdec.h                   |    1 
 swfdec/swfdec_actor.c             |   14 +
 swfdec/swfdec_cache.c             |  245 ++++++++++++++----------
 swfdec/swfdec_cache.h             |   61 +++---
 swfdec/swfdec_cached.c            |  124 ++++++------
 swfdec/swfdec_cached.h            |   26 +-
 swfdec/swfdec_cached_image.c      |   98 +++++++++
 swfdec/swfdec_cached_image.h      |   67 ++++++
 swfdec/swfdec_gradient_pattern.c  |    3 
 swfdec/swfdec_image.c             |  281 +++++++++++++++++----------
 swfdec/swfdec_image.h             |   15 -
 swfdec/swfdec_image_decoder.c     |    2 
 swfdec/swfdec_movie.c             |    4 
 swfdec/swfdec_pattern.c           |   20 +
 swfdec/swfdec_pattern.h           |    2 
 swfdec/swfdec_player.c            |  100 +++++++++
 swfdec/swfdec_player.h            |   23 +-
 swfdec/swfdec_player_internal.h   |    2 
 swfdec/swfdec_renderer.c          |  386 ++++++++++++++++++++++++++++++++++++++
 swfdec/swfdec_renderer.h          |   70 ++++++
 swfdec/swfdec_renderer_internal.h |   55 +++++
 swfdec/swfdec_sound.c             |   20 -
 swfdec/swfdec_sound.h             |    6 
 swfdec/swfdec_stroke.c            |    4 
 swfdec/swfdec_swf_decoder.c       |    3 
 swfdec/swfdec_text_field_movie.c  |   68 +++---
 swfdec/swfdec_text_field_movie.h  |    6 
 swfdec/swfdec_types.h             |    2 
 tools/dump.c                      |    2 
 tools/swfdec-extract.c            |    2 
 33 files changed, 1362 insertions(+), 412 deletions(-)

New commits:
commit 07c175aa23267639cd4093a2be120eaa9ecdb047
Merge: df9b708... bc28022...
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 19:49:23 2008 +0200

    Merge branch 'cache'

commit df9b7083c6a9665a5f8f4f7df5c41ad860d29f43
Merge: d46085e... f07cf46...
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 19:47:29 2008 +0200

    Merge branch 'master' of ssh://company@git.freedesktop.org/git/swfdec/swfdec

commit bc2802229f625b0e34c1471b16e7139ac407c2ad
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 19:46:47 2008 +0200

    update tools to API changes

diff --git a/tools/dump.c b/tools/dump.c
index 1b8d701..c6c1da3 100644
--- a/tools/dump.c
+++ b/tools/dump.c
@@ -316,7 +316,7 @@ get_image_type_name (SwfdecImageType type)
 static void
 dump_image (SwfdecImage *image)
 {
-  cairo_surface_destroy (swfdec_image_create_surface (image));
+  cairo_surface_destroy (swfdec_image_create_surface (image, NULL));
   g_print ("  %s %u x %u\n", get_image_type_name (image->type),
       image->width, image->height);
 }
diff --git a/tools/swfdec-extract.c b/tools/swfdec-extract.c
index 1e57034..ebcba2c 100644
--- a/tools/swfdec-extract.c
+++ b/tools/swfdec-extract.c
@@ -228,7 +228,7 @@ export_graphic (SwfdecGraphic *graphic, const char *filename)
 static gboolean
 export_image (SwfdecImage *image, const char *filename)
 {
-  cairo_surface_t *surface = swfdec_image_create_surface (image);
+  cairo_surface_t *surface = swfdec_image_create_surface (image, NULL);
 
   if (surface == NULL)
     return FALSE;
commit 2542db0bdcd2dba742fca023c9af48b29329d139
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 19:46:32 2008 +0200

    implement transformed surfaces without crashing

diff --git a/swfdec/swfdec_image.c b/swfdec/swfdec_image.c
index 005d23d..ccf43d1 100644
--- a/swfdec/swfdec_image.c
+++ b/swfdec/swfdec_image.c
@@ -705,8 +705,10 @@ swfdec_image_create_surface_transformed (SwfdecImage *image, SwfdecRenderer *ren
   source = swfdec_image_lookup_surface (image, renderer, &mask);
   if (source == NULL) {
     source = swfdec_image_create_surface (image, NULL);
+    if (source == NULL)
+      return NULL;
     if (renderer) {
-      cached = swfdec_cached_image_new (surface, image->width * image->height * 4);
+      cached = swfdec_cached_image_new (source, image->width * image->height * 4);
       swfdec_cached_image_set_color_transform (cached, &mask);
       swfdec_renderer_add_cache (renderer, image, SWFDEC_CACHED (cached));
       g_object_unref (cached);
commit 5a27f9bfb76eb05b7e4d787e7e2324da118a1b51
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 19:24:55 2008 +0200

    we require glib 2.16 now

diff --git a/configure.ac b/configure.ac
index a5bb805..4da21cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -92,7 +92,7 @@ AC_ARG_WITH(pkg-config-path,
 dnl Check for essential libraries first:
 dnl ====================================
 
-GLIB_VER=2.12
+GLIB_VER=2.16
 PKG_CHECK_MODULES(GLIB, glib-2.0 >= $GLIB_VER gobject-2.0 >= $GLIB_VER gthread-2.0 >= $GLIB_VER,
 		HAVE_GLIB=yes, HAVE_GLIB=no)
 if test "$HAVE_GLIB" = "no"; then
commit fb42d401651aa07bc2755ae814f9f6b64ee92a3f
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 15:19:21 2008 +0200

    use a proper SwfdecRenderer here

diff --git a/swfdec-gtk/swfdec_gtk_widget.c b/swfdec-gtk/swfdec_gtk_widget.c
index 7b96da6..5830681 100644
--- a/swfdec-gtk/swfdec_gtk_widget.c
+++ b/swfdec-gtk/swfdec_gtk_widget.c
@@ -33,6 +33,7 @@ struct _SwfdecGtkWidgetPrivate
   gboolean		renderer_set;	/* TRUE if a special renderer has been set */
   cairo_surface_type_t	renderer_type;	/* the renderer that was set */
   gboolean		interactive;	/* TRUE if this widget propagates keyboard and mouse events */
+  SwfdecRenderer *	renderer;	/* renderer in use */
 };
 
 enum {
@@ -316,6 +317,8 @@ swfdec_gtk_widget_dispose (GObject *object)
 
   swfdec_gtk_widget_set_player (widget, NULL);
 
+  g_assert (widget->priv->renderer == NULL);
+
   G_OBJECT_CLASS (swfdec_gtk_widget_parent_class)->dispose (object);
 }
 
@@ -407,6 +410,32 @@ swfdec_gtk_widget_update_cursor (SwfdecGtkWidget *widget)
 }
 
 static void
+swfdec_gtk_widget_update_renderer (SwfdecGtkWidget *widget)
+{
+  SwfdecGtkWidgetPrivate *priv = widget->priv;
+  gboolean needs_renderer;
+
+  needs_renderer = GTK_WIDGET_REALIZED (widget) &&
+    priv->player != NULL;
+
+  if (priv->renderer != NULL) {
+    swfdec_player_set_renderer (priv->player, NULL);
+    g_object_unref (priv->renderer);
+    priv->renderer = NULL;
+  }
+  if (needs_renderer) {
+    cairo_t *cr = gdk_cairo_create (GTK_WIDGET (widget)->window);
+
+    if (priv->renderer_set)
+      g_printerr ("FIXME: create the right renderer\n");
+    priv->renderer = swfdec_renderer_new_for_player (
+	cairo_get_target (cr), priv->player);
+    swfdec_player_set_renderer (priv->player, priv->renderer);
+    cairo_destroy (cr);
+  }
+}
+
+static void
 swfdec_gtk_widget_realize (GtkWidget *widget)
 {
   GdkWindowAttr attributes;
@@ -442,6 +471,15 @@ swfdec_gtk_widget_realize (GtkWidget *widget)
   if (SWFDEC_GTK_WIDGET (widget)->priv->player) {
     swfdec_gtk_widget_update_cursor (SWFDEC_GTK_WIDGET (widget));
   }
+  swfdec_gtk_widget_update_renderer (SWFDEC_GTK_WIDGET (widget));
+}
+
+static void
+swfdec_gtk_widget_unrealize (GtkWidget *widget)
+{
+  GTK_WIDGET_CLASS (swfdec_gtk_widget_parent_class)->unrealize (widget);
+
+  swfdec_gtk_widget_update_renderer (SWFDEC_GTK_WIDGET (widget));
 }
 
 static void
@@ -469,6 +507,7 @@ swfdec_gtk_widget_class_init (SwfdecGtkWidgetClass * g_class)
 	  0, G_MAXUINT, CAIRO_SURFACE_TYPE_IMAGE, G_PARAM_READWRITE));
 
   widget_class->realize = swfdec_gtk_widget_realize;
+  widget_class->unrealize = swfdec_gtk_widget_unrealize;
   widget_class->size_request = swfdec_gtk_widget_size_request;
   widget_class->size_allocate = swfdec_gtk_widget_size_allocate;
   widget_class->expose_event = swfdec_gtk_widget_expose;
@@ -561,6 +600,7 @@ swfdec_gtk_widget_set_player (SwfdecGtkWidget *widget, SwfdecPlayer *player)
   priv->player = player;
   gtk_widget_queue_resize (GTK_WIDGET (widget));
   g_object_notify (G_OBJECT (widget), "player");
+  swfdec_gtk_widget_update_renderer (widget);
 }
 
 /**
@@ -655,6 +695,7 @@ swfdec_gtk_widget_set_renderer (SwfdecGtkWidget *widget, cairo_surface_type_t re
     g_object_notify (G_OBJECT (widget), "renderer-set");
   }
   g_object_notify (G_OBJECT (widget), "renderer");
+  swfdec_gtk_widget_update_renderer (widget);
 }
 
 /**
@@ -673,6 +714,7 @@ swfdec_gtk_widget_unset_renderer (SwfdecGtkWidget *widget)
     return;
   widget->priv->renderer_set = FALSE;
   g_object_notify (G_OBJECT (widget), "renderer-set");
+  swfdec_gtk_widget_update_renderer (widget);
 }
 
 /**
commit fc0a5d065b069030821981138125eb16f95b910e
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 15:02:37 2008 +0200

    rename renderer member to renderer_type

diff --git a/swfdec-gtk/swfdec_gtk_widget.c b/swfdec-gtk/swfdec_gtk_widget.c
index f0c47b6..7b96da6 100644
--- a/swfdec-gtk/swfdec_gtk_widget.c
+++ b/swfdec-gtk/swfdec_gtk_widget.c
@@ -31,7 +31,7 @@ struct _SwfdecGtkWidgetPrivate
   SwfdecPlayer *	player;		/* the video we play */
 
   gboolean		renderer_set;	/* TRUE if a special renderer has been set */
-  cairo_surface_type_t	renderer;	/* the renderer that was set */
+  cairo_surface_type_t	renderer_type;	/* the renderer that was set */
   gboolean		interactive;	/* TRUE if this widget propagates keyboard and mouse events */
 };
 
@@ -231,7 +231,7 @@ swfdec_gtk_widget_expose (GtkWidget *gtkwidget, GdkEventExpose *event)
     return FALSE;
 
   if (!priv->renderer_set ||
-      (surface = swfdec_gtk_widget_create_renderer (priv->renderer, 
+      (surface = swfdec_gtk_widget_create_renderer (priv->renderer_type, 
 	      event->area.width, event->area.height)) == NULL) {
     cr = gdk_cairo_create (gtkwidget->window);
   } else {
@@ -272,7 +272,7 @@ swfdec_gtk_widget_get_property (GObject *object, guint param_id, GValue *value,
       g_value_set_boolean (value, priv->renderer_set);
       break;
     case PROP_RENDERER:
-      g_value_set_uint (value, priv->renderer);
+      g_value_set_uint (value, priv->renderer_type);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -299,7 +299,7 @@ swfdec_gtk_widget_set_property (GObject *object, guint param_id, const GValue *v
       gtk_widget_queue_draw (GTK_WIDGET (widget));
       break;
     case PROP_RENDERER:
-      priv->renderer = g_value_get_uint (value);
+      priv->renderer_type = g_value_get_uint (value);
       if (priv->renderer_set)
 	gtk_widget_queue_draw (GTK_WIDGET (widget));
       break;
@@ -493,7 +493,7 @@ swfdec_gtk_widget_init (SwfdecGtkWidget * widget)
   priv = widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (widget, SWFDEC_TYPE_GTK_WIDGET, SwfdecGtkWidgetPrivate);
 
   priv->interactive = TRUE;
-  priv->renderer = CAIRO_SURFACE_TYPE_IMAGE;
+  priv->renderer_type = CAIRO_SURFACE_TYPE_IMAGE;
 
   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
 }
@@ -649,7 +649,7 @@ swfdec_gtk_widget_set_renderer (SwfdecGtkWidget *widget, cairo_surface_type_t re
 {
   g_return_if_fail (SWFDEC_IS_GTK_WIDGET (widget));
 
-  widget->priv->renderer = renderer;
+  widget->priv->renderer_type = renderer;
   if (widget->priv->renderer_set == FALSE) {
     widget->priv->renderer_set = TRUE;
     g_object_notify (G_OBJECT (widget), "renderer-set");
@@ -690,7 +690,7 @@ swfdec_gtk_widget_get_renderer (SwfdecGtkWidget *widget)
 {
   g_return_val_if_fail (SWFDEC_IS_GTK_WIDGET (widget), CAIRO_SURFACE_TYPE_IMAGE);
 
-  return widget->priv->renderer;
+  return widget->priv->renderer_type;
 }
 
 /**
commit 07959353bac5b375cbcf9f06eaeee4a395e5eeff
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 14:59:33 2008 +0200

    make SwfdecPatternClass.get_pattern require a renderer argument

diff --git a/swfdec/swfdec_gradient_pattern.c b/swfdec/swfdec_gradient_pattern.c
index 2f63634..da4661a 100644
--- a/swfdec/swfdec_gradient_pattern.c
+++ b/swfdec/swfdec_gradient_pattern.c
@@ -54,7 +54,8 @@ swfdec_gradient_pattern_morph (SwfdecDraw *dest, SwfdecDraw *source, guint ratio
 }
 
 static cairo_pattern_t *
-swfdec_gradient_pattern_get_pattern (SwfdecPattern *pat, const SwfdecColorTransform *trans)
+swfdec_gradient_pattern_get_pattern (SwfdecPattern *pat, SwfdecRenderer *renderer,
+    const SwfdecColorTransform *trans)
 {
   guint i, ratio;
   cairo_pattern_t *pattern;
diff --git a/swfdec/swfdec_pattern.c b/swfdec/swfdec_pattern.c
index 70a3292..b642293 100644
--- a/swfdec/swfdec_pattern.c
+++ b/swfdec/swfdec_pattern.c
@@ -31,6 +31,7 @@
 #include "swfdec_gradient_pattern.h"
 #include "swfdec_image.h"
 #include "swfdec_path.h"
+#include "swfdec_renderer_internal.h"
 #include "swfdec_stroke.h"
 
 /*** PATTERN ***/
@@ -48,7 +49,8 @@ swfdec_pattern_paint (SwfdecDraw *draw, cairo_t *cr, const SwfdecColorTransform
 {
   cairo_pattern_t *pattern;
 
-  pattern = swfdec_pattern_get_pattern (SWFDEC_PATTERN (draw), trans);
+  pattern = swfdec_pattern_get_pattern (SWFDEC_PATTERN (draw), swfdec_renderer_get (cr),
+      trans);
   if (pattern == NULL)
     return;
   cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
@@ -143,7 +145,8 @@ swfdec_color_pattern_morph (SwfdecDraw *dest, SwfdecDraw *source, guint ratio)
 }
 
 static cairo_pattern_t *
-swfdec_color_pattern_get_pattern (SwfdecPattern *pat, const SwfdecColorTransform *trans)
+swfdec_color_pattern_get_pattern (SwfdecPattern *pat, SwfdecRenderer *renderer,
+    const SwfdecColorTransform *trans)
 {
   SwfdecColor color = SWFDEC_COLOR_PATTERN (pat)->start_color;
 
@@ -209,10 +212,10 @@ swfdec_image_pattern_morph (SwfdecDraw *dest, SwfdecDraw *source, guint ratio)
 }
 
 static cairo_pattern_t *
-swfdec_image_pattern_get_pattern (SwfdecPattern *pat, const SwfdecColorTransform *trans)
+swfdec_image_pattern_get_pattern (SwfdecPattern *pat, SwfdecRenderer *renderer,
+    const SwfdecColorTransform *trans)
 {
   SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pat);
-  SwfdecRenderer *renderer = NULL;
   cairo_pattern_t *pattern;
   cairo_surface_t *surface;
   
@@ -546,15 +549,17 @@ swfdec_pattern_to_string (SwfdecPattern *pattern)
 }
 
 cairo_pattern_t *
-swfdec_pattern_get_pattern (SwfdecPattern *pattern, const SwfdecColorTransform *trans)
+swfdec_pattern_get_pattern (SwfdecPattern *pattern, SwfdecRenderer *renderer,
+    const SwfdecColorTransform *trans)
 {
   SwfdecPatternClass *klass;
 
   g_return_val_if_fail (SWFDEC_IS_PATTERN (pattern), NULL);
+  g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer), NULL);
   g_return_val_if_fail (trans != NULL, NULL);
 
   klass = SWFDEC_PATTERN_GET_CLASS (pattern);
   g_assert (klass->get_pattern);
-  return klass->get_pattern (pattern, trans);
+  return klass->get_pattern (pattern, renderer, trans);
 }
 
diff --git a/swfdec/swfdec_pattern.h b/swfdec/swfdec_pattern.h
index 811389d..16021a8 100644
--- a/swfdec/swfdec_pattern.h
+++ b/swfdec/swfdec_pattern.h
@@ -52,6 +52,7 @@ struct _SwfdecPatternClass
 
   /* create a cairo pattern for the given values */
   cairo_pattern_t *	(* get_pattern)		(SwfdecPattern *		pattern,
+						 SwfdecRenderer *		renderer,
 						 const SwfdecColorTransform *	trans);
 };
 
@@ -66,6 +67,7 @@ SwfdecDraw *	swfdec_pattern_parse_morph    	(SwfdecBits *			bits,
 						 SwfdecSwfDecoder *		dec);
 
 cairo_pattern_t *swfdec_pattern_get_pattern	(SwfdecPattern *		pattern, 
+						 SwfdecRenderer *		renderer,
 						 const SwfdecColorTransform *	trans);
 
 /* debug */
diff --git a/swfdec/swfdec_stroke.c b/swfdec/swfdec_stroke.c
index f043727..0e966eb 100644
--- a/swfdec/swfdec_stroke.c
+++ b/swfdec/swfdec_stroke.c
@@ -29,6 +29,7 @@
 #include "swfdec_debug.h"
 #include "swfdec_decoder.h"
 #include "swfdec_path.h"
+#include "swfdec_renderer_internal.h"
 
 #define MAX_ALIGN 10
 
@@ -113,7 +114,8 @@ swfdec_stroke_paint (SwfdecDraw *draw, cairo_t *cr, const SwfdecColorTransform *
     cairo_append_path (cr, &draw->path);
 
   if (stroke->pattern) {
-    cairo_pattern_t *pattern = swfdec_pattern_get_pattern (stroke->pattern, trans);
+    cairo_pattern_t *pattern = swfdec_pattern_get_pattern (stroke->pattern, 
+	swfdec_renderer_get (cr), trans);
     cairo_set_source (cr, pattern);
     cairo_pattern_destroy (pattern);
   } else {
commit 4291a54b08aaa31b7ece0d911f4794ddf810255b
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 14:58:26 2008 +0200

    add API to render with a given renderer
    
    and actually attach the renderer to the cairo_t when rendering.
    
    It might be useful to use the SwfdecRenderer directly instead of handing the cr
    around.

diff --git a/swfdec/swfdec_player.c b/swfdec/swfdec_player.c
index 3924b2f..29ca9f8 100644
--- a/swfdec/swfdec_player.c
+++ b/swfdec/swfdec_player.c
@@ -2846,12 +2846,38 @@ swfdec_player_render_focusrect (SwfdecPlayer *player, cairo_t *cr, SwfdecRect *i
  * @width: width of area to render or 0 for full width
  * @height: height of area to render or 0 for full height
  *
- * Renders the given area of the current frame to @cr.
+ * Renders the given area of the current frame to @cr using the player's
+ * renderer.
  **/
 void
 swfdec_player_render (SwfdecPlayer *player, cairo_t *cr, 
     double x, double y, double width, double height)
 {
+  g_return_if_fail (SWFDEC_IS_PLAYER (player));
+  g_return_if_fail (cr != NULL);
+  g_return_if_fail (width >= 0.0);
+  g_return_if_fail (height >= 0.0);
+
+  swfdec_player_render_with_renderer (player, cr, player->priv->renderer,
+      x, y, width, height);
+}
+
+/**
+ * swfdec_player_render:
+ * @player: a #SwfdecPlayer
+ * @cr: #cairo_t to render to
+ * @renderer: Renderer to use for rendering
+ * @x: x coordinate of top left position to render
+ * @y: y coordinate of top left position to render
+ * @width: width of area to render or 0 for full width
+ * @height: height of area to render or 0 for full height
+ *
+ * Renders the given area of the current frame to @cr.
+ **/
+void
+swfdec_player_render_with_renderer (SwfdecPlayer *player, cairo_t *cr, 
+    SwfdecRenderer *renderer, double x, double y, double width, double height)
+{
   static const SwfdecColorTransform trans = { FALSE, 256, 0, 256, 0, 256, 0, 256, 0 };
   SwfdecPlayerPrivate *priv;
   GList *walk;
@@ -2859,6 +2885,7 @@ swfdec_player_render (SwfdecPlayer *player, cairo_t *cr,
 
   g_return_if_fail (SWFDEC_IS_PLAYER (player));
   g_return_if_fail (cr != NULL);
+  g_return_if_fail (SWFDEC_IS_RENDERER (renderer));
   g_return_if_fail (width >= 0.0);
   g_return_if_fail (height >= 0.0);
 
@@ -2871,6 +2898,8 @@ swfdec_player_render (SwfdecPlayer *player, cairo_t *cr,
     width = priv->stage_width;
   if (height == 0.0)
     height = priv->stage_height;
+
+  swfdec_renderer_attach (renderer, cr);
   /* clip the area */
   cairo_save (cr);
   cairo_rectangle (cr, x, y, width, height);
diff --git a/swfdec/swfdec_player.h b/swfdec/swfdec_player.h
index a0a9e94..49cfe39 100644
--- a/swfdec/swfdec_player.h
+++ b/swfdec/swfdec_player.h
@@ -153,12 +153,19 @@ SwfdecRenderer *swfdec_player_get_renderer	(SwfdecPlayer *		player);
 void		swfdec_player_set_renderer	(SwfdecPlayer *		player,
 						 SwfdecRenderer *	renderer);
 					 
-void		swfdec_player_render		(SwfdecPlayer *	player,
-						 cairo_t *	cr,
-						 double		x,
-						 double		y,
-						 double		width,
-						 double		height);
+void		swfdec_player_render		(SwfdecPlayer *		player,
+						 cairo_t *		cr,
+						 double			x,
+						 double			y,
+						 double			width,
+						 double			height);
+void		swfdec_player_render_with_renderer (SwfdecPlayer *	player,
+						 cairo_t *		cr,
+						 SwfdecRenderer *	renderer,
+						 double			x,
+						 double			y,
+						 double			width,
+						 double			height);
 gulong		swfdec_player_advance		(SwfdecPlayer *	player,
 						 gulong		msecs);
 gboolean	swfdec_player_mouse_move	(SwfdecPlayer *	player, 
commit 75c3b01ca0c265192ac122efeeb2cf72fef70b6e
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 14:58:08 2008 +0200

    actually create the hash table we use

diff --git a/swfdec/swfdec_renderer.c b/swfdec/swfdec_renderer.c
index ad62d70..dc88721 100644
--- a/swfdec/swfdec_renderer.c
+++ b/swfdec/swfdec_renderer.c
@@ -192,8 +192,12 @@ swfdec_renderer_class_init (SwfdecRendererClass *klass)
 static void
 swfdec_renderer_init (SwfdecRenderer *renderer)
 {
-  renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer, SWFDEC_TYPE_RENDERER, SwfdecRendererPrivate);
-  renderer->priv->cache = swfdec_cache_new (8 * 1024 * 1024);
+  SwfdecRendererPrivate *priv;
+
+  renderer->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer, SWFDEC_TYPE_RENDERER, SwfdecRendererPrivate);
+  
+  priv->cache = swfdec_cache_new (8 * 1024 * 1024);
+  priv->cache_lookup = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 /*** INTERNAL API ***/
commit 4d275c48cfacd4d3f8cf8cfcfde32faa9a3b9caf
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 13:54:11 2008 +0200

    rewrite image handling to use the new caching mechanism in SwfdecRenderer

diff --git a/swfdec/swfdec_cached_image.c b/swfdec/swfdec_cached_image.c
index 2cc6c76..2640b5f 100644
--- a/swfdec/swfdec_cached_image.c
+++ b/swfdec/swfdec_cached_image.c
@@ -54,33 +54,7 @@ swfdec_cached_image_init (SwfdecCachedImage *cached)
 }
 
 SwfdecCachedImage *
-swfdec_cached_image_new (guint8 *image_data, cairo_format_t format,
-    guint width, guint height, guint rowstride)
-{
-  SwfdecCachedImage *image;
-  static const cairo_user_data_key_t key;
-  gulong size;
-
-  g_return_val_if_fail (image_data != NULL, NULL);
-  g_return_val_if_fail (width > 0, NULL);
-  g_return_val_if_fail (height > 0, NULL);
-  g_return_val_if_fail (rowstride > 0, NULL);
-
-  /* FIXME: sizeof (cairo_surface_t) */
-  size = sizeof (SwfdecCachedImage) + height * rowstride;
-  image = g_object_new (SWFDEC_TYPE_CACHED_IMAGE, "size", size, NULL);
-  image->surface = cairo_image_surface_create_for_data (image_data, format,
-      width, height, rowstride);
-  if (cairo_surface_set_user_data (image->surface, &key, image_data, g_free) != CAIRO_STATUS_SUCCESS) {
-    /* guess we should abort here due to OOM? */
-    g_warning ("failed to register data free function");
-  }
-
-  return image;
-}
-
-SwfdecCachedImage *
-swfdec_cached_image_new_for_surface (cairo_surface_t *surface, gsize size)
+swfdec_cached_image_new (cairo_surface_t *surface, gsize size)
 {
   SwfdecCachedImage *image;
 
@@ -102,3 +76,23 @@ swfdec_cached_image_get_surface (SwfdecCachedImage *image)
   return cairo_surface_reference (image->surface);
 }
 
+void
+swfdec_cached_image_get_color_transform (SwfdecCachedImage *image,
+    SwfdecColorTransform *trans)
+{
+  g_return_if_fail (SWFDEC_IS_CACHED_IMAGE (image));
+  g_return_if_fail (trans != NULL);
+
+  *trans = image->trans;
+}
+
+void
+swfdec_cached_image_set_color_transform (SwfdecCachedImage *image,
+    const SwfdecColorTransform *trans)
+{
+  g_return_if_fail (SWFDEC_IS_CACHED_IMAGE (image));
+  g_return_if_fail (trans != NULL);
+
+  image->trans = *trans;
+}
+
diff --git a/swfdec/swfdec_cached_image.h b/swfdec/swfdec_cached_image.h
index d370a06..89a08b1 100644
--- a/swfdec/swfdec_cached_image.h
+++ b/swfdec/swfdec_cached_image.h
@@ -51,18 +51,17 @@ struct _SwfdecCachedImageClass
 
 GType			swfdec_cached_image_get_type	(void);
 
-SwfdecCachedImage *	swfdec_cached_image_new		(guint8 *		image_data,
-							 cairo_format_t		format,
-							 guint			width,
-							 guint			height,
-							 guint			rowstride);
-SwfdecCachedImage *	swfdec_cached_image_new_for_surface
-							(cairo_surface_t *	surface,
+SwfdecCachedImage *	swfdec_cached_image_new		(cairo_surface_t *	surface,
 							 gsize			size);
 
 
 cairo_surface_t *	swfdec_cached_image_get_surface	(SwfdecCachedImage *	image);
-
+void			swfdec_cached_image_get_color_transform
+							(SwfdecCachedImage *	image,
+							 SwfdecColorTransform *	trans);
+void			swfdec_cached_image_set_color_transform
+							(SwfdecCachedImage *	image,
+							 const SwfdecColorTransform *trans);
 
 G_END_DECLS
 #endif
diff --git a/swfdec/swfdec_image.c b/swfdec/swfdec_image.c
index 1be91b8..005d23d 100644
--- a/swfdec/swfdec_image.c
+++ b/swfdec/swfdec_image.c
@@ -31,10 +31,9 @@
 #include "swfdec_image.h"
 #include "swfdec_cached_image.h"
 #include "swfdec_debug.h"
+#include "swfdec_renderer_internal.h"
 #include "swfdec_swf_decoder.h"
 
-static const cairo_user_data_key_t key;
-
 static void merge_alpha (SwfdecImage * image, unsigned char *image_data,
     unsigned char *alpha);
 static void swfdec_image_colormap_decode (SwfdecImage * image,
@@ -151,8 +150,25 @@ swfdec_jpeg_decode_argb (unsigned char *data1, int length1,
   return ret;
 }
 
-static SwfdecCachedImage * 
-swfdec_image_jpeg_load (SwfdecImage *image)
+static cairo_surface_t *
+swfdec_image_create_surface_for_data (SwfdecRenderer *renderer, guint8 *data,
+    cairo_format_t format, guint width, guint height, guint rowstride)
+{
+  cairo_surface_t *surface;
+
+  if (renderer) {
+    surface = swfdec_renderer_create_for_data (renderer, data, format, width, height, rowstride);
+  } else {
+    static const cairo_user_data_key_t key;
+    surface = cairo_image_surface_create_for_data (data,
+	format, width, height, rowstride);
+    cairo_surface_set_user_data (surface, &key, data, g_free);
+  }
+  return surface;
+}
+
+static cairo_surface_t * 
+swfdec_image_jpeg_load (SwfdecImage *image, SwfdecRenderer *renderer)
 {
   gboolean ret;
   guint8 *data;
@@ -175,8 +191,8 @@ swfdec_image_jpeg_load (SwfdecImage *image)
   SWFDEC_LOG ("  width = %d", image->width);
   SWFDEC_LOG ("  height = %d", image->height);
 
-  return swfdec_cached_image_new (data, CAIRO_FORMAT_RGB24, image->width, 
-      image->height, 4 * image->width);
+  return swfdec_image_create_surface_for_data (renderer, data, 
+      CAIRO_FORMAT_RGB24, image->width, image->height, 4 * image->width);
 }
 
 int
@@ -199,8 +215,8 @@ tag_func_define_bits_jpeg_2 (SwfdecSwfDecoder * s, guint tag)
   return SWFDEC_STATUS_OK;
 }
 
-static SwfdecCachedImage *
-swfdec_image_jpeg2_load (SwfdecImage *image)
+static cairo_surface_t *
+swfdec_image_jpeg2_load (SwfdecImage *image, SwfdecRenderer *renderer)
 {
   gboolean ret;
   guint8 *data;
@@ -214,8 +230,8 @@ swfdec_image_jpeg2_load (SwfdecImage *image)
   SWFDEC_LOG ("  width = %d", image->width);
   SWFDEC_LOG ("  height = %d", image->height);
 
-  return swfdec_cached_image_new (data, CAIRO_FORMAT_RGB24, image->width, 
-      image->height, 4 * image->width);
+  return swfdec_image_create_surface_for_data (renderer, data, 
+      CAIRO_FORMAT_RGB24, image->width, image->height, 4 * image->width);
 }
 
 int
@@ -238,8 +254,8 @@ tag_func_define_bits_jpeg_3 (SwfdecSwfDecoder * s, guint tag)
   return SWFDEC_STATUS_OK;
 }
 
-static SwfdecCachedImage *
-swfdec_image_jpeg3_load (SwfdecImage *image)
+static cairo_surface_t *
+swfdec_image_jpeg3_load (SwfdecImage *image, SwfdecRenderer *renderer)
 {
   SwfdecBits bits;
   SwfdecBuffer *buffer;
@@ -273,8 +289,8 @@ swfdec_image_jpeg3_load (SwfdecImage *image)
   SWFDEC_LOG ("  width = %d", image->width);
   SWFDEC_LOG ("  height = %d", image->height);
 
-  return swfdec_cached_image_new (data, CAIRO_FORMAT_RGB24, image->width, 
-      image->height, 4 * image->width);
+  return swfdec_image_create_surface_for_data (renderer, data, 
+      CAIRO_FORMAT_RGB24, image->width, image->height, 4 * image->width);
 }
 
 static void
@@ -294,8 +310,8 @@ merge_alpha (SwfdecImage * image, unsigned char *image_data,
   }
 }
 
-static SwfdecCachedImage *
-swfdec_image_lossless_load (SwfdecImage *image)
+static cairo_surface_t *
+swfdec_image_lossless_load (SwfdecImage *image, SwfdecRenderer *renderer)
 {
   int format;
   guint color_table_size;
@@ -450,7 +466,7 @@ swfdec_image_lossless_load (SwfdecImage *image)
   }
 
 out:
-  return swfdec_cached_image_new (data,
+  return swfdec_image_create_surface_for_data (renderer, data,
       have_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, 
       image->width, image->height, image->width * 4);
 }
@@ -546,72 +562,126 @@ swfdec_image_png_read (void *bitsp, unsigned char *data, unsigned int length)
   return CAIRO_STATUS_SUCCESS;
 }
 
-static SwfdecCachedImage *
-swfdec_image_png_load (SwfdecImage *image)
+static cairo_surface_t *
+swfdec_image_png_load (SwfdecImage *image, SwfdecRenderer *renderer)
 {
   SwfdecBits bits;
   cairo_surface_t *surface;
-  SwfdecCachedImage *cached;
 
   swfdec_bits_init (&bits, image->raw_data);
   surface = cairo_image_surface_create_from_png_stream (
       swfdec_image_png_read, &bits);
+  if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
+    cairo_surface_destroy (surface);
+    return NULL;
+  }
+
   image->width = cairo_image_surface_get_width (surface);
   image->height = cairo_image_surface_get_height (surface);
-  cached = swfdec_cached_image_new_for_surface (surface,
-      image->height * cairo_image_surface_get_stride (surface));
-  cairo_surface_destroy (surface);
-  return cached;
+  if (renderer)
+    surface = swfdec_renderer_create_similar (renderer, surface);
+  return surface;
+}
+
+static gboolean
+swfdec_image_find_by_transform (SwfdecCached *cached, gpointer data)
+{
+  const SwfdecColorTransform *trans = data;
+  SwfdecColorTransform ctrans;
+
+  swfdec_cached_image_get_color_transform (SWFDEC_CACHED_IMAGE (cached),
+      &ctrans);
+  if (trans->mask != ctrans.mask)
+    return FALSE;
+  if (trans->mask)
+    return TRUE;
+  return (trans->ra == ctrans.ra && 
+      trans->rb == ctrans.rb && 
+      trans->ga == ctrans.ga && 
+      trans->gb == ctrans.gb && 
+      trans->ba == ctrans.ba && 
+      trans->bb == ctrans.bb && 
+      trans->aa == ctrans.aa && 
+      trans->ab == ctrans.ab);
+}
+
+static cairo_surface_t *
+swfdec_image_lookup_surface (SwfdecImage *image, SwfdecRenderer *renderer,
+    const SwfdecColorTransform *trans)
+{
+  if (renderer) {
+    SwfdecCached *cached = swfdec_renderer_get_cache (renderer, image, 
+	swfdec_image_find_by_transform, (gpointer) trans);
+    if (cached) {
+      swfdec_cached_use (cached);
+      return swfdec_cached_image_get_surface (SWFDEC_CACHED_IMAGE (cached));
+    }
+  }
+  return NULL;
 }
 
 cairo_surface_t *
-swfdec_image_create_surface (SwfdecImage *image)
+swfdec_image_create_surface (SwfdecImage *image, SwfdecRenderer *renderer)
 {
+  SwfdecColorTransform trans;
   SwfdecCachedImage *cached;
   cairo_surface_t *surface;
 
+  g_return_val_if_fail (SWFDEC_IS_IMAGE (image), NULL);
+  g_return_val_if_fail (renderer == NULL || SWFDEC_IS_RENDERER (renderer), NULL);
+
   if (image->raw_data == NULL)
     return NULL;
 
-  if (TRUE) {
-    switch (image->type) {
-      case SWFDEC_IMAGE_TYPE_JPEG:
-	cached = swfdec_image_jpeg_load (image);
-	break;
-      case SWFDEC_IMAGE_TYPE_JPEG2:
-	cached = swfdec_image_jpeg2_load (image);
-	break;
-      case SWFDEC_IMAGE_TYPE_JPEG3:
-	cached = swfdec_image_jpeg3_load (image);
-	break;
-      case SWFDEC_IMAGE_TYPE_LOSSLESS:
-	cached = swfdec_image_lossless_load (image);
-	break;
-      case SWFDEC_IMAGE_TYPE_LOSSLESS2:
-	cached = swfdec_image_lossless_load (image);
-	break;
-      case SWFDEC_IMAGE_TYPE_PNG:
-	cached = swfdec_image_png_load (image);
-	break;
-      case SWFDEC_IMAGE_TYPE_UNKNOWN:
-      default:
-	g_assert_not_reached ();
-	break;
-    }
-    if (cached == NULL) {
-      SWFDEC_WARNING ("failed to decode image");
-      return NULL;
-    }
+  swfdec_color_transform_init_identity (&trans);
+  surface = swfdec_image_lookup_surface (image, renderer, &trans);
+  if (surface)
+    return surface;
+
+  switch (image->type) {
+    case SWFDEC_IMAGE_TYPE_JPEG:
+      surface = swfdec_image_jpeg_load (image, renderer);
+      break;
+    case SWFDEC_IMAGE_TYPE_JPEG2:
+      surface = swfdec_image_jpeg2_load (image, renderer);
+      break;
+    case SWFDEC_IMAGE_TYPE_JPEG3:
+      surface = swfdec_image_jpeg3_load (image, renderer);
+      break;
+    case SWFDEC_IMAGE_TYPE_LOSSLESS:
+      surface = swfdec_image_lossless_load (image, renderer);
+      break;
+    case SWFDEC_IMAGE_TYPE_LOSSLESS2:
+      surface = swfdec_image_lossless_load (image, renderer);
+      break;
+    case SWFDEC_IMAGE_TYPE_PNG:
+      surface = swfdec_image_png_load (image, renderer);
+      break;
+    case SWFDEC_IMAGE_TYPE_UNKNOWN:
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+  if (surface == NULL) {
+    SWFDEC_WARNING ("failed to decode image");
+    return NULL;
+  }
+  if (renderer) {
+    /* FIXME: The size is just an educated guess */
+    cached = swfdec_cached_image_new (surface, image->width * image->height * 4);
+    swfdec_renderer_add_cache (renderer, image, SWFDEC_CACHED (cached));
+    g_object_unref (cached);
   }
 
-  surface = swfdec_cached_image_get_surface (cached);
-  g_object_unref (cached);
   return surface;
 }
 
 cairo_surface_t *
-swfdec_image_create_surface_transformed (SwfdecImage *image, const SwfdecColorTransform *trans)
+swfdec_image_create_surface_transformed (SwfdecImage *image, SwfdecRenderer *renderer,
+    const SwfdecColorTransform *trans)
 {
+  SwfdecColorTransform mask;
+  SwfdecCachedImage *cached;
   cairo_surface_t *surface, *source;
   guint32 *tdata;
   const guint32 *sdata;
@@ -619,13 +689,30 @@ swfdec_image_create_surface_transformed (SwfdecImage *image, const SwfdecColorTr
   gboolean has_alpha = FALSE;
 
   g_return_val_if_fail (SWFDEC_IS_IMAGE (image), NULL);
+  g_return_val_if_fail (renderer == NULL || SWFDEC_IS_RENDERER (renderer), NULL);
   g_return_val_if_fail (trans != NULL, NULL);
 
+  surface = swfdec_image_lookup_surface (image, renderer, trans);
+  if (surface)
+    return surface;
   /* obvious optimization */
   if (swfdec_color_transform_is_identity (trans))
-    return swfdec_image_create_surface (image);
+    return swfdec_image_create_surface (image, renderer);
+
+  /* need to create an image surface here, so we can modify it. Will upload later */
+  /* NB: we use the mask property here to inidicate an image surface */
+  swfdec_color_transform_init_mask (&mask);
+  source = swfdec_image_lookup_surface (image, renderer, &mask);
+  if (source == NULL) {
+    source = swfdec_image_create_surface (image, NULL);
+    if (renderer) {
+      cached = swfdec_cached_image_new (surface, image->width * image->height * 4);
+      swfdec_cached_image_set_color_transform (cached, &mask);
+      swfdec_renderer_add_cache (renderer, image, SWFDEC_CACHED (cached));
+      g_object_unref (cached);
+    }
+  }
 
-  source = swfdec_image_create_surface (image);
   tdata = g_try_malloc (image->width * image->height * 4);
   if (!tdata) {
     SWFDEC_ERROR ("failed to allocate memory for transformed image");
@@ -642,10 +729,16 @@ swfdec_image_create_surface_transformed (SwfdecImage *image, const SwfdecColorTr
     has_alpha |= SWFDEC_COLOR_A (tdata[i]) != 0xFF;
   }
   cairo_surface_destroy (source);
-  surface = cairo_image_surface_create_for_data ((unsigned char *) tdata,
+  surface = swfdec_image_create_surface_for_data (renderer, (guchar *) tdata,
       has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, 
       image->width, image->height, image->width * 4);
-  cairo_surface_set_user_data (surface, &key, tdata, g_free);
+  if (renderer) {
+    /* FIXME: The size is just an educated guess */
+    cached = swfdec_cached_image_new (surface, image->width * image->height * 4);
+    swfdec_cached_image_set_color_transform (cached, trans);
+    swfdec_renderer_add_cache (renderer, image, SWFDEC_CACHED (cached));
+    g_object_unref (cached);
+  }
   return surface;
 }
 
diff --git a/swfdec/swfdec_image.h b/swfdec/swfdec_image.h
index 3e2d53d..b127e5d 100644
--- a/swfdec/swfdec_image.h
+++ b/swfdec/swfdec_image.h
@@ -67,9 +67,11 @@ GType			swfdec_image_get_type		(void);
 
 SwfdecImageType		swfdec_image_detect		(const guint8 *		data);
 SwfdecImage *		swfdec_image_new		(SwfdecBuffer *		buffer);
-cairo_surface_t *	swfdec_image_create_surface	(SwfdecImage *		image);
+cairo_surface_t *	swfdec_image_create_surface	(SwfdecImage *		image,
+							 SwfdecRenderer *	renderer);
 cairo_surface_t *	swfdec_image_create_surface_transformed 
 							(SwfdecImage *		image,
+							 SwfdecRenderer *	renderer,
 							 const SwfdecColorTransform *trans);
 
 int swfdec_image_jpegtables (SwfdecSwfDecoder * s, guint tag);
diff --git a/swfdec/swfdec_image_decoder.c b/swfdec/swfdec_image_decoder.c
index 7a50d16..30ef283 100644
--- a/swfdec/swfdec_image_decoder.c
+++ b/swfdec/swfdec_image_decoder.c
@@ -65,7 +65,7 @@ swfdec_image_get_size (SwfdecImage *image, guint *w, guint *h)
 {
   cairo_surface_t *surface;
 
-  surface = swfdec_image_create_surface (image);
+  surface = swfdec_image_create_surface (image, NULL);
   if (surface == NULL)
     return FALSE;
 
diff --git a/swfdec/swfdec_movie.c b/swfdec/swfdec_movie.c
index 57704dc..27e6486 100644
--- a/swfdec/swfdec_movie.c
+++ b/swfdec/swfdec_movie.c
@@ -40,6 +40,7 @@
 #include "swfdec_player_internal.h"
 #include "swfdec_sprite.h"
 #include "swfdec_sprite_movie.h"
+#include "swfdec_renderer_internal.h"
 #include "swfdec_resource.h"
 #include "swfdec_system.h"
 #include "swfdec_text_field_movie.h"
@@ -1163,8 +1164,9 @@ swfdec_movie_do_render (SwfdecMovie *movie, cairo_t *cr,
 
   /* if the movie loaded an image, draw it here now */
   if (movie->image) {
+    SwfdecRenderer *renderer = swfdec_renderer_get (cr);
     cairo_surface_t *surface = swfdec_image_create_surface_transformed (movie->image,
-	ctrans);
+	renderer, ctrans);
     if (surface) {
       static const cairo_matrix_t matrix = { 1.0 / SWFDEC_TWIPS_SCALE_FACTOR, 0, 0, 1.0 / SWFDEC_TWIPS_SCALE_FACTOR, 0, 0 };
       cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
diff --git a/swfdec/swfdec_pattern.c b/swfdec/swfdec_pattern.c
index d641556..70a3292 100644
--- a/swfdec/swfdec_pattern.c
+++ b/swfdec/swfdec_pattern.c
@@ -212,10 +212,11 @@ static cairo_pattern_t *
 swfdec_image_pattern_get_pattern (SwfdecPattern *pat, const SwfdecColorTransform *trans)
 {
   SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pat);
+  SwfdecRenderer *renderer = NULL;
   cairo_pattern_t *pattern;
   cairo_surface_t *surface;
   
-  surface = swfdec_image_create_surface_transformed (image->image, trans);
+  surface = swfdec_image_create_surface_transformed (image->image, renderer, trans);
   if (surface == NULL)
     return NULL;
   pattern = cairo_pattern_create_for_surface (surface);
@@ -524,7 +525,7 @@ swfdec_pattern_to_string (SwfdecPattern *pattern)
   if (SWFDEC_IS_IMAGE_PATTERN (pattern)) {
     SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pattern);
     if (image->image->width == 0)
-      cairo_surface_destroy (swfdec_image_create_surface (image->image));
+      cairo_surface_destroy (swfdec_image_create_surface (image->image, NULL));
     return g_strdup_printf ("%ux%u image %u (%s, %s)", image->image->width,
 	image->image->height, SWFDEC_CHARACTER (image->image)->id,
 	image->extend == CAIRO_EXTEND_REPEAT ? "repeat" : "no repeat",
commit 235d21d8c19db6157eb71835d35f0856bbffb756
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 12:53:09 2008 +0200

    add create_similar and create_for_data functions

diff --git a/swfdec/swfdec_renderer.c b/swfdec/swfdec_renderer.c
index 00cf5a5..ad62d70 100644
--- a/swfdec/swfdec_renderer.c
+++ b/swfdec/swfdec_renderer.c
@@ -132,6 +132,43 @@ swfdec_renderer_set_property (GObject *object, guint param_id, const GValue *val
   }
 }
 
+static cairo_surface_t *
+swfdec_renderer_do_create_similar (SwfdecRenderer *renderer, cairo_surface_t *surface)
+{
+  SwfdecRendererPrivate *priv;
+  cairo_surface_t *result;
+  cairo_t *cr;
+
+  priv = renderer->priv;
+  if (cairo_surface_get_type (priv->surface) == CAIRO_SURFACE_TYPE_IMAGE)
+    return surface;
+
+  result = cairo_surface_create_similar (priv->surface,
+      cairo_surface_get_content (surface),
+      cairo_image_surface_get_width (surface),
+      cairo_image_surface_get_height (surface));
+  cr = cairo_create (result);
+
+  cairo_set_source_surface (cr, surface, 0, 0);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface);
+  return result;
+}
+
+static cairo_surface_t *
+swfdec_renderer_do_create_for_data (SwfdecRenderer *renderer, guint8 *data,
+    cairo_format_t format, guint width, guint height, guint rowstride)
+{
+  static const cairo_user_data_key_t key;
+  cairo_surface_t *surface;
+
+  surface = cairo_image_surface_create_for_data (data, format, width, height, rowstride);
+  cairo_surface_set_user_data (surface, &key, data, g_free);
+  return swfdec_renderer_create_similar (renderer, surface);
+}
+
 static void
 swfdec_renderer_class_init (SwfdecRendererClass *klass)
 {
@@ -147,6 +184,9 @@ swfdec_renderer_class_init (SwfdecRendererClass *klass)
   g_object_class_install_property (object_class, PROP_SURFACE,
       g_param_spec_pointer ("surface", "surface", "cairo surface in use by this renderer",
 	  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  klass->create_similar = swfdec_renderer_do_create_similar;
+  klass->create_for_data = swfdec_renderer_do_create_for_data;
 }
 
 static void
@@ -247,6 +287,48 @@ swfdec_renderer_get (cairo_t *cr)
   return cairo_get_user_data (cr, &cr_key);
 }
 
+/**
+ * swfdec_renderer_create_similar:
+ * @renderer: a renderer
+ * @surface: an image surface; this function takes ownership of the passed-in image.
+ *
+ * Creates a surface with the same contents and size as the given image 
+ * @surface, but optimized for use in @renderer. You should use this function 
+ * before caching a surface.
+ *
+ * Returns: A surface with the same contents as @surface. You own a reference to the 
+ *          returned surface.
+ **/
+cairo_surface_t *
+swfdec_renderer_create_similar (SwfdecRenderer *renderer, cairo_surface_t *surface)
+{
+  SwfdecRendererClass *klass;
+
+  g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer), NULL);
+  g_return_val_if_fail (surface != NULL, NULL);
+  g_return_val_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL);
+
+  klass = SWFDEC_RENDERER_GET_CLASS (renderer);
+  return klass->create_similar (renderer, surface);
+}
+
+/* FIXME: get data parameter const */
+cairo_surface_t *
+swfdec_renderer_create_for_data (SwfdecRenderer *renderer, guint8 *data,
+    cairo_format_t format, guint width, guint height, guint rowstride)
+{
+  SwfdecRendererClass *klass;
+
+  g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer), NULL);
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+  g_return_val_if_fail (rowstride > 0, NULL);
+
+  klass = SWFDEC_RENDERER_GET_CLASS (renderer);
+  return klass->create_for_data (renderer, data, format, width, height, rowstride);
+}
+
 /*** PUBLIC API ***/
 
 /**
diff --git a/swfdec/swfdec_renderer.h b/swfdec/swfdec_renderer.h
index 5d3ce71..1b1ffe0 100644
--- a/swfdec/swfdec_renderer.h
+++ b/swfdec/swfdec_renderer.h
@@ -46,6 +46,15 @@ struct _SwfdecRenderer {
 struct _SwfdecRendererClass
 {
   GObjectClass		object_class;
+
+  cairo_surface_t *	(* create_similar)		(SwfdecRenderer *	renderer,
+							 cairo_surface_t *	surface);
+  cairo_surface_t *	(* create_for_data)		(SwfdecRenderer *	renderer,
+							 guint8 *		data,
+							 cairo_format_t		format,
+							 guint			width,
+							 guint			height,
+							 guint			rowstride);
 };
 
 GType			swfdec_renderer_get_type	(void);
diff --git a/swfdec/swfdec_renderer_internal.h b/swfdec/swfdec_renderer_internal.h
index 1f23333..b8a3dd9 100644
--- a/swfdec/swfdec_renderer_internal.h
+++ b/swfdec/swfdec_renderer_internal.h
@@ -41,6 +41,15 @@ SwfdecCached *		swfdec_renderer_get_cache	(SwfdecRenderer *	renderer,
 							 SwfdecRendererSearchFunc func,
 							 gpointer		data);
 
+cairo_surface_t *	swfdec_renderer_create_similar	(SwfdecRenderer *	renderer,
+							 cairo_surface_t *	surface);
+cairo_surface_t *	swfdec_renderer_create_for_data	(SwfdecRenderer *	renderer,
+							 guint8 *		data,
+							 cairo_format_t		format,
+							 guint			width,
+							 guint			height,
+							 guint			rowstride);
+
 
 G_END_DECLS
 #endif
commit 89dee153a1cc4b8410e786e31b6d13a124e5f13b
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 11:12:09 2008 +0200

    use the current renderer for computing layouts

diff --git a/swfdec/swfdec_text_field_movie.c b/swfdec/swfdec_text_field_movie.c
index 8c4cbc2..7bf23d5 100644
--- a/swfdec/swfdec_text_field_movie.c
+++ b/swfdec/swfdec_text_field_movie.c
@@ -552,8 +552,12 @@ swfdec_text_field_movie_get_layouts (SwfdecTextFieldMovie *text, int *num,
 
   g_assert (SWFDEC_IS_TEXT_FIELD_MOVIE (text));
 
-  if (cr == NULL)
-    cr = text->cr;
+  if (cr == NULL) {
+    cr = cairo_create (swfdec_renderer_get_surface (
+	  SWFDEC_PLAYER (SWFDEC_AS_OBJECT (text)->context)->priv->renderer));
+  } else {
+    cairo_reference (cr);
+  }
 
   if (paragraphs == NULL) {
     paragraphs_free = swfdec_text_field_movie_get_paragraphs (text, NULL);
@@ -766,6 +770,7 @@ swfdec_text_field_movie_get_layouts (SwfdecTextFieldMovie *text, int *num,
 
   if (num != NULL)
     *num = layouts->len;
+  cairo_destroy (cr);
 
   return (SwfdecLayout *) (void *) g_array_free (layouts, FALSE);
 }
@@ -1246,11 +1251,6 @@ swfdec_text_field_movie_dispose (GObject *object)
   g_string_free (text->input, TRUE);
   text->input = NULL;
 
-  cairo_destroy (text->cr);
-  text->cr = NULL;
-  cairo_surface_destroy (text->surface);
-  text->surface = NULL;
-
   G_OBJECT_CLASS (swfdec_text_field_movie_parent_class)->dispose (object);
 }
 
@@ -1729,9 +1729,6 @@ swfdec_text_field_movie_class_init (SwfdecTextFieldMovieClass * g_class)
 static void
 swfdec_text_field_movie_init (SwfdecTextFieldMovie *text)
 {
-  text->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-  text->cr = cairo_create (text->surface);
-
   text->input = g_string_new ("");
   text->scroll = 1;
   text->mouse_wheel_enabled = TRUE;
diff --git a/swfdec/swfdec_text_field_movie.h b/swfdec/swfdec_text_field_movie.h
index 5d8eebd..7bd978b 100644
--- a/swfdec/swfdec_text_field_movie.h
+++ b/swfdec/swfdec_text_field_movie.h
@@ -135,11 +135,6 @@ struct _SwfdecTextFieldMovie {
   gsize			cursor_start;		/* index of cursor (aka insertion point) in ->input */
   gsize			cursor_end;		/* end of cursor, either equal to cursor_start or if text selected smaller or bigger */
   guint			character_pressed;
-
-  // FIXME: Temporary using image surface, until there is a way to get cairo_t
-  // outside the rendering functions
-  cairo_surface_t *	surface;
-  cairo_t *		cr;
 };
 
 struct _SwfdecTextFieldMovieClass {
commit 40d8e8517dc61888fac3bec6cb1ff19b43c91e43
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 11:11:57 2008 +0200

    include swfdec_renderer.h

diff --git a/swfdec/swfdec.h b/swfdec/swfdec.h
index 1e769b3..2dec954 100644
--- a/swfdec/swfdec.h
+++ b/swfdec/swfdec.h
@@ -40,6 +40,7 @@
 #include <swfdec/swfdec_player.h>
 #include <swfdec/swfdec_player_scripting.h>
 #include <swfdec/swfdec_rectangle.h>
+#include <swfdec/swfdec_renderer.h>
 #include <swfdec/swfdec_socket.h>
 #include <swfdec/swfdec_stream.h>
 #include <swfdec/swfdec_system.h>
commit 68f6e7ec4285eec6b9265dd020e18bd05380ef34
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 11:01:22 2008 +0200

    add long-awaited SwfdecRenderer object

diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index f158c66..b218079 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -117,6 +117,7 @@ libswfdec_source_files = \
 	swfdec_policy_file.c \
 	swfdec_rect.c \
 	swfdec_rectangle.c \
+	swfdec_renderer.c \
 	swfdec_resource.c \
 	swfdec_ringbuffer.c \
 	swfdec_sandbox.c \
@@ -195,6 +196,7 @@ public_headers = \
 	swfdec_player.h \
 	swfdec_player_scripting.h \
 	swfdec_rectangle.h \
+	swfdec_renderer.h \
 	swfdec_script.h \
 	swfdec_socket.h \
 	swfdec_stream.h \
diff --git a/swfdec/swfdec_player.c b/swfdec/swfdec_player.c
index 0ba1ac2..3924b2f 100644
--- a/swfdec/swfdec_player.c
+++ b/swfdec/swfdec_player.c
@@ -44,6 +44,7 @@
 #include "swfdec_loader_internal.h"
 #include "swfdec_marshal.h"
 #include "swfdec_movie.h"
+#include "swfdec_renderer_internal.h"
 #include "swfdec_resource.h"
 #include "swfdec_script_internal.h"
 #include "swfdec_sprite_movie.h"
@@ -664,7 +665,8 @@ enum {
   PROP_URL,
   PROP_VARIABLES,
   PROP_START_TIME,
-  PROP_FOCUS
+  PROP_FOCUS,
+  PROP_RENDERER
 };
 
 G_DEFINE_TYPE (SwfdecPlayer, swfdec_player, SWFDEC_TYPE_AS_CONTEXT)
@@ -787,6 +789,9 @@ swfdec_player_get_property (GObject *object, guint param_id, GValue *value,
     case PROP_FOCUS:
       g_value_set_boolean (value, priv->has_focus);
       break;
+    case PROP_RENDERER:
+      g_value_set_object (value, priv->renderer);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
       break;
@@ -931,6 +936,9 @@ swfdec_player_set_property (GObject *object, guint param_id, const GValue *value
     case PROP_FOCUS:
       swfdec_player_set_focus (player, g_value_get_boolean (value));
       break;
+    case PROP_RENDERER:
+      swfdec_player_set_renderer (player, g_value_get_object (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
       break;
@@ -2010,6 +2018,9 @@ swfdec_player_class_init (SwfdecPlayerClass *klass)
   g_object_class_install_property (object_class, PROP_FOCUS,
       g_param_spec_boolean ("focus", "focus", "TRUE if the player has keyboard focus",
 	  TRUE, G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_RENDERER,
+      g_param_spec_object ("renderer", "renderer", "the renderer used by this player",
+	  SWFDEC_TYPE_RENDERER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
   /**
    * SwfdecPlayer::invalidate:
@@ -3395,6 +3406,52 @@ swfdec_player_set_focus	(SwfdecPlayer *player, gboolean	focus)
 }
 
 /**
+ * swfdec_player_get_renderer:
+ * @player: a player
+ *
+ * Gets the current renderer in use. See swfdec_player_set_renderer() for 
+ * details.
+ *
+ * Returns: the current #SwfdecRenderer in use.
+ **/
+SwfdecRenderer *
+swfdec_player_get_renderer (SwfdecPlayer *player)
+{
+  g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+
+  return player->priv->renderer;
+}
+
+/**
+ * swfdec_player_set_renderer:
+ * @player: a player
+ * @renderer: the renderer to use
+ *
+ * Sets the renderer to be used by the @player. Setting the correct renderer is 
+ * mostly relevant for TextField flash objects with native fonts, as the 
+ * renderer provides those. It can also be very relevant for performance 
+ * reasons. See the #SwfdecRenderer documentation for details.
+ **/
+void
+swfdec_player_set_renderer (SwfdecPlayer *player, SwfdecRenderer *renderer)
+{
+  SwfdecPlayerPrivate *priv;
+
+  g_return_if_fail (SWFDEC_IS_PLAYER (player));
+
+  priv = player->priv;
+  if (renderer) {
+    g_object_ref (renderer);
+  } else {
+    renderer = swfdec_renderer_new_default (player);
+  }
+  if (priv->renderer)
+    g_object_unref (renderer);
+  priv->renderer = renderer;
+  g_object_notify (G_OBJECT (player), "renderer");
+}
+
+/**
  * swfdec_player_get_base_url:
  * @player: a #SwfdecPlayer
  *
diff --git a/swfdec/swfdec_player.h b/swfdec/swfdec_player.h
index 21f6670..a0a9e94 100644
--- a/swfdec/swfdec_player.h
+++ b/swfdec/swfdec_player.h
@@ -59,6 +59,7 @@ GType swfdec_time_val_get_type  (void);
 
 /* forward declarations */
 typedef struct _SwfdecPlayerScripting SwfdecPlayerScripting;
+typedef struct _SwfdecRenderer SwfdecRenderer;
 
 typedef struct _SwfdecPlayer SwfdecPlayer;
 typedef struct _SwfdecPlayerPrivate SwfdecPlayerPrivate;
@@ -148,6 +149,9 @@ void		swfdec_player_set_scripting	(SwfdecPlayer *		player,
 gboolean	swfdec_player_get_focus		(SwfdecPlayer *		player);
 void		swfdec_player_set_focus		(SwfdecPlayer *		player,
 						 gboolean		focus);
+SwfdecRenderer *swfdec_player_get_renderer	(SwfdecPlayer *		player);
+void		swfdec_player_set_renderer	(SwfdecPlayer *		player,
+						 SwfdecRenderer *	renderer);
 					 
 void		swfdec_player_render		(SwfdecPlayer *	player,
 						 cairo_t *	cr,
diff --git a/swfdec/swfdec_player_internal.h b/swfdec/swfdec_player_internal.h
index 7d03034..7b9dd54 100644
--- a/swfdec/swfdec_player_internal.h
+++ b/swfdec/swfdec_player_internal.h
@@ -77,6 +77,7 @@ struct _SwfdecPlayerPrivate
   char *		variables;		/* variables to set on the player */
   SwfdecURL *		url;			/* url or NULL if not set yet */
   SwfdecURL *		base_url;	      	/* base url or NULL if not set yet */
+  SwfdecRenderer *	renderer;		/* the renderer to use */
   SwfdecPlayerScripting *scripting;		/* scripting object */
   GHashTable *		scripting_callbacks;	/* GC string => SwfdecAsFunction mapping of script callbacks */
   GType			loader_type;		/* type to use for creating sockets */
diff --git a/swfdec/swfdec_renderer.c b/swfdec/swfdec_renderer.c
new file mode 100644
index 0000000..00cf5a5
--- /dev/null
+++ b/swfdec/swfdec_renderer.c
@@ -0,0 +1,300 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_renderer.h"
+#include "swfdec_renderer_internal.h"
+#include "swfdec_cache.h"
+#include "swfdec_player_internal.h"
+
+struct _SwfdecRendererPrivate {
+  cairo_surface_t *	surface;	/* the surface we assume we render to */
+  SwfdecCache *		cache;		/* the cache we use for cached items */
+  GHashTable *		cache_lookup;	/* gpointer => GList mapping */
+};
+
+/*** GTK-DOC ***/
+
+/**
+ * SECTION:SwfdecRenderer
+ * @title: SwfdecRenderer
+ * @short_description: provide accelerated rendering and caching abilities
+ *
+ * The #SwfdecRenderer object is used internally to improve rendering done by
+ * Swfdec.
+ *
+ * The first thing #SwfdecRenderer does is provide a way to cache data relevant
+ * to rendering.
+ *
+ * The second thing it does is provide access to the surface that is used for 
+ * rendering, even when not in the process of rendering. This is relevant for
+ * font backends, as different surfaces provide different native fonts. See
+ * swfdec_player_set_default_backend() for details about this.
+ *
+ * The third thing it does is provide a list of virtual functions for critical
+ * operations that you can optimize using subclasses to provide faster 
+ * implementations. Note that a working default implementation is provided, so
+ * you only need to override the functions you care about. 
+ * See #SwfdecRendererClass for details about these functions.
+ */
+
+
+/*** OBJECT ***/
+
+G_DEFINE_TYPE (SwfdecRenderer, swfdec_renderer, G_TYPE_OBJECT)
+
+enum {
+  PROP_0,
+  PROP_SURFACE
+};
+
+static void
+swfdec_renderer_dispose (GObject *object)
+{
+  SwfdecRendererPrivate *priv = SWFDEC_RENDERER (object)->priv;
+
+  if (priv->surface) {
+    cairo_surface_destroy (priv->surface);
+    priv->surface = NULL;
+  }
+  if (priv->cache_lookup) {
+    GHashTableIter iter;
+    GList *walk;
+    gpointer list;
+    g_hash_table_iter_init (&iter, priv->cache_lookup);
+    while (g_hash_table_iter_next (&iter, NULL, &list)) {
+      for (walk = list; walk; walk = walk->next) {
+	g_object_remove_weak_pointer (walk->data, &walk->data);
+      }
+      g_list_free (list);
+    }
+    g_hash_table_destroy (priv->cache_lookup);
+    priv->cache_lookup = NULL;
+  }
+  if (priv->cache) {
+    g_object_unref (priv->cache);
+    priv->cache = NULL;
+  }
+
+  G_OBJECT_CLASS (swfdec_renderer_parent_class)->dispose (object);
+}
+
+static void
+swfdec_renderer_get_property (GObject *object, guint param_id, GValue *value,
+    GParamSpec *pspec)
+{
+  SwfdecRendererPrivate *priv = SWFDEC_RENDERER (object)->priv;
+
+  switch (param_id) {
+    case PROP_SURFACE:
+      g_value_set_pointer (value, priv->surface);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+  }
+}
+
+static void
+swfdec_renderer_set_property (GObject *object, guint param_id, const GValue *value,
+    GParamSpec *pspec)
+{
+  SwfdecRendererPrivate *priv = SWFDEC_RENDERER (object)->priv;
+
+  switch (param_id) {
+    case PROP_SURFACE:
+      priv->surface = g_value_get_pointer (value);
+      g_assert (priv->surface != NULL);
+      cairo_surface_reference (priv->surface);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+  }
+}
+
+static void
+swfdec_renderer_class_init (SwfdecRendererClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (SwfdecRendererPrivate));
+
+  object_class->dispose = swfdec_renderer_dispose;
+  object_class->get_property = swfdec_renderer_get_property;
+  object_class->set_property = swfdec_renderer_set_property;
+
+  /* FIXME: should be g_param_spec_size(), but no such thing exists */
+  g_object_class_install_property (object_class, PROP_SURFACE,
+      g_param_spec_pointer ("surface", "surface", "cairo surface in use by this renderer",
+	  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+swfdec_renderer_init (SwfdecRenderer *renderer)
+{
+  renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer, SWFDEC_TYPE_RENDERER, SwfdecRendererPrivate);
+  renderer->priv->cache = swfdec_cache_new (8 * 1024 * 1024);
+}
+
+/*** INTERNAL API ***/
+
+void
+swfdec_renderer_add_cache (SwfdecRenderer *renderer, gpointer key, SwfdecCached *cached)
+{
+  SwfdecRendererPrivate *priv;
+  GList *list;
+
+  g_return_if_fail (SWFDEC_IS_RENDERER (renderer));
+  g_return_if_fail (key != NULL);
+  g_return_if_fail (SWFDEC_IS_CACHED (cached));
+
+  priv = renderer->priv;
+  list = g_hash_table_lookup (priv->cache_lookup, key);
+  list = g_list_prepend (list, cached);
+  /* NB: empty list entries mean object was deleted */
+  g_object_add_weak_pointer (G_OBJECT (cached), &list->data);
+  g_hash_table_insert (priv->cache_lookup, key, list);
+  swfdec_cache_add (priv->cache, cached);
+}
+
+SwfdecCached *
+swfdec_renderer_get_cache (SwfdecRenderer *renderer, gpointer key, 
+    SwfdecRendererSearchFunc func, gpointer data)
+{
+  SwfdecRendererPrivate *priv;
+  GList *list, *org, *walk;
+  SwfdecCached *result = NULL;
+
+  g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer), NULL);
+  g_return_val_if_fail (key != NULL, NULL);
+
+  priv = renderer->priv;
+  org = g_hash_table_lookup (priv->cache_lookup, key);
+  list = org;
+  walk = list;
+  while (walk) {
+    /* NB: empty list entries mean object was deleted */
+    if (walk->data == NULL) {
+      GList *next = walk->next;
+      list = g_list_delete_link (list, walk);
+      walk = next;
+      continue;
+    }
+    if (!func || func (walk->data, data)) {
+      result = walk->data;
+      break;
+    }
+    walk = walk->next;
+  }
+  if (org != list)
+    g_hash_table_insert (priv->cache_lookup, key, list);
+  return result;
+}
+
+SwfdecRenderer *
+swfdec_renderer_new_default (SwfdecPlayer *player)
+{
+  cairo_surface_t *surface;
+  SwfdecRenderer *renderer;
+
+  g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
+  renderer = swfdec_renderer_new_for_player (surface, player);
+  cairo_surface_destroy (surface);
+  return renderer;
+}
+
+static const cairo_user_data_key_t cr_key;
+
+void
+swfdec_renderer_attach (SwfdecRenderer *renderer, cairo_t *cr)
+{
+  g_return_if_fail (SWFDEC_IS_RENDERER (renderer));
+  g_return_if_fail (cr != NULL);
+
+  g_object_ref (renderer);
+  if (cairo_set_user_data (cr, &cr_key, renderer, g_object_unref) != CAIRO_STATUS_SUCCESS) {
+    g_warning ("could not attach user data");
+  }
+}
+
+SwfdecRenderer *
+swfdec_renderer_get (cairo_t *cr)
+{
+  g_return_val_if_fail (cr != NULL, NULL);
+
+  return cairo_get_user_data (cr, &cr_key);
+}
+
+/*** PUBLIC API ***/
+
+/**
+ * swfdec_renderer_new:
+ * @surface: a cairo surface
+ *
+ * Creates a new renderer to be used with the given @surface.
+ *
+ * Returns: a new renderer
+ **/
+SwfdecRenderer *
+swfdec_renderer_new (cairo_surface_t *surface)
+{
+  g_return_val_if_fail (surface != NULL, NULL);
+
+  return g_object_new (SWFDEC_TYPE_RENDERER, "surface", surface, NULL);
+}
+
+SwfdecRenderer *
+swfdec_renderer_new_for_player (cairo_surface_t *surface, SwfdecPlayer *player)
+{
+  SwfdecRendererPrivate *priv;
+  SwfdecRenderer *renderer;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+  g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+
+  renderer = swfdec_renderer_new (surface);
+  priv = renderer->priv;
+  g_object_unref (priv->cache);
+  priv->cache = g_object_ref (player->priv->cache);
+
+  return renderer;
+}
+
+/**
+ * swfdec_renderer_get_surface:
+ * @renderer: a renderer
+ *
+ * Gets the surface that was used when creating this surface.
+ *
+ * Returns: the surface used by this renderer
+ **/
+cairo_surface_t *
+swfdec_renderer_get_surface (SwfdecRenderer *renderer)
+{
+  g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer), NULL);
+
+  return renderer->priv->surface;
+}
+
diff --git a/swfdec/swfdec_renderer.h b/swfdec/swfdec_renderer.h
new file mode 100644
index 0000000..5d3ce71
--- /dev/null
+++ b/swfdec/swfdec_renderer.h
@@ -0,0 +1,61 @@
+/* Swfdec
+ * Copyright (c) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SWFDEC_RENDERER_H_
+#define _SWFDEC_RENDERER_H_
+
+#include <cairo.h>
+#include <swfdec/swfdec_player.h>
+
+G_BEGIN_DECLS
+
+//typedef struct _SwfdecRenderer SwfdecRenderer;
+typedef struct _SwfdecRendererPrivate SwfdecRendererPrivate;
+typedef struct _SwfdecRendererClass SwfdecRendererClass;
+
+#define SWFDEC_TYPE_RENDERER                    (swfdec_renderer_get_type())
+#define SWFDEC_IS_RENDERER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_RENDERER))
+#define SWFDEC_IS_RENDERER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_RENDERER))
+#define SWFDEC_RENDERER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_RENDERER, SwfdecRenderer))
+#define SWFDEC_RENDERER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_RENDERER, SwfdecRendererClass))
+#define SWFDEC_RENDERER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_RENDERER, SwfdecRendererClass))
+
+
+struct _SwfdecRenderer {
+  GObject		object;
+
+  SwfdecRendererPrivate *priv;
+};
+
+struct _SwfdecRendererClass
+{
+  GObjectClass		object_class;
+};
+
+GType			swfdec_renderer_get_type	(void);
+
+SwfdecRenderer *	swfdec_renderer_new		(cairo_surface_t *	surface);
+SwfdecRenderer *	swfdec_renderer_new_for_player	(cairo_surface_t *	surface,
+							 SwfdecPlayer *		player);
+
+cairo_surface_t *	swfdec_renderer_get_surface	(SwfdecRenderer *	renderer);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_renderer_internal.h b/swfdec/swfdec_renderer_internal.h
new file mode 100644
index 0000000..1f23333
--- /dev/null
+++ b/swfdec/swfdec_renderer_internal.h
@@ -0,0 +1,46 @@
+/* Swfdec
+ * Copyright (c) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SWFDEC_RENDERER_INTERNAL_H_
+#define _SWFDEC_RENDERER_INTERNAL_H_
+
+#include <swfdec/swfdec_renderer.h>
+#include <swfdec/swfdec_cached.h>
+
+G_BEGIN_DECLS
+
+
+typedef gboolean SwfdecRendererSearchFunc (SwfdecCached *cached, gpointer data);
+
+SwfdecRenderer *	swfdec_renderer_new_default	(SwfdecPlayer *		player);
+
+void			swfdec_renderer_attach		(SwfdecRenderer *	renderer,
+							 cairo_t *		cr);
+SwfdecRenderer *	swfdec_renderer_get		(cairo_t *		cr);
+void			swfdec_renderer_add_cache	(SwfdecRenderer *	renderer,
+							 gpointer		key,
+							 SwfdecCached *		value);
+SwfdecCached *		swfdec_renderer_get_cache	(SwfdecRenderer *	renderer,
+							 gpointer		key,
+							 SwfdecRendererSearchFunc func,
+							 gpointer		data);
+
+
+G_END_DECLS
+#endif
commit 9861871f7b09a893d63f85d2619047a5acc06294
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Apr 8 10:54:50 2008 +0200

    terminate vararg list with NULL
    
    Why didn't gcc warn me?!

diff --git a/swfdec/swfdec_cache.c b/swfdec/swfdec_cache.c
index 465a945..1528fac 100644
--- a/swfdec/swfdec_cache.c
+++ b/swfdec/swfdec_cache.c
@@ -122,7 +122,7 @@ swfdec_cache_init (SwfdecCache *cache)
 SwfdecCache *
 swfdec_cache_new (gsize max_size)
 {
-  return g_object_new (SWFDEC_TYPE_CACHE, "max-cache-size", max_size);
+  return g_object_new (SWFDEC_TYPE_CACHE, "max-cache-size", max_size, NULL);
 }
 
 gsize
commit 787f705e69e82cc2cdd6aa417fdc054d914c8e59
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Apr 7 21:57:01 2008 +0200

    remove useless headers

diff --git a/swfdec/swfdec_cache.h b/swfdec/swfdec_cache.h
index 4b87701..84d9a3a 100644
--- a/swfdec/swfdec_cache.h
+++ b/swfdec/swfdec_cache.h
@@ -20,8 +20,6 @@
 #ifndef _SWFDEC_CACHE_H_
 #define _SWFDEC_CACHE_H_
 
-#include <cairo.h>
-#include <swfdec/swfdec_cache.h>
 #include <swfdec/swfdec_cached.h>
 
 G_BEGIN_DECLS
commit 4ce79386fbbeb5557cd17981806f8ed67926cf6a
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Apr 7 21:52:07 2008 +0200

    rewrite cache handling
    
    we now create objects to be cached and don't use a member of some base objects
    for caching. The nice side effect is that we can now cache n elements per object
    and not just one.

diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 016c2a9..f158c66 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -53,6 +53,7 @@ libswfdec_source_files = \
 	swfdec_button_movie_as.c \
 	swfdec_cache.c \
 	swfdec_cached.c \
+	swfdec_cached_image.c \
 	swfdec_camera.c \
 	swfdec_character.c \
 	swfdec_codec_adpcm.c \
@@ -230,6 +231,7 @@ noinst_HEADERS = \
 	swfdec_button_movie.h \
 	swfdec_cache.h \
 	swfdec_cached.h \
+	swfdec_cached_image.h \
 	swfdec_character.h \
 	swfdec_codec_audio.h \
 	swfdec_codec_video.h \
diff --git a/swfdec/swfdec_cache.c b/swfdec/swfdec_cache.c
index 48104e6..465a945 100644
--- a/swfdec/swfdec_cache.c
+++ b/swfdec/swfdec_cache.c
@@ -1,6 +1,6 @@
 /* Swfdec
  * Copyright (C) 2005 David Schleef <ds at schleef.org>
- *		 2007 Benjamin Otte <otte at gnome.org>
+ *		 2007-2008 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,140 +25,183 @@
 #include "swfdec_cache.h"
 #include "swfdec_debug.h"
 
-SwfdecCache *
-swfdec_cache_new (gulong max_size)
-{
-  SwfdecCache *cache;
-  
-  g_return_val_if_fail (max_size > 0, NULL);
 
-  cache = g_new0 (SwfdecCache, 1);
-  cache->refcount = 1;
-  cache->queue = g_queue_new ();
-  cache->max_size = max_size;
+G_DEFINE_TYPE (SwfdecCache, swfdec_cache, G_TYPE_OBJECT)
+
+enum {
+  PROP_0,
+  PROP_CACHE_SIZE,
+  PROP_MAX_CACHE_SIZE,
+};
 
-  return cache;
+/* NB: assumes that the cached was already removed from cache->list */
+static void
+swfdec_cache_remove (SwfdecCache *cache, SwfdecCached *cached)
+{
+  cache->size -= swfdec_cached_get_size (cached);
+  g_signal_handlers_disconnect_matched (cached, 
+      G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, cache);
+  g_object_unref (cached);
 }
 
-void
-swfdec_cache_ref (SwfdecCache *cache)
+static void
+swfdec_cache_dispose (GObject *object)
 {
-  g_return_if_fail (cache != NULL);
+  SwfdecCache *cache = SWFDEC_CACHE (object);
+  SwfdecCached *cached;
+
+  if (cache->queue) {
+    while ((cached = g_queue_pop_tail (cache->queue)))
+      swfdec_cache_remove (cache, cached);
+    g_queue_free (cache->queue);
+  }
+  g_assert (cache->size == 0);
 
-  cache->refcount++;
+  G_OBJECT_CLASS (swfdec_cache_parent_class)->dispose (object);
 }
 
-void
-swfdec_cache_unref (SwfdecCache *cache)
+static void
+swfdec_cache_get_property (GObject *object, guint param_id, GValue *value,
+    GParamSpec *pspec)
 {
-  g_return_if_fail (cache != NULL);
-  g_return_if_fail (cache->refcount > 0);
+  SwfdecCache *cache = SWFDEC_CACHE (object);
+
+  switch (param_id) {
+    case PROP_CACHE_SIZE:
+      g_value_set_ulong (value, cache->size);
+      break;
+    case PROP_MAX_CACHE_SIZE:
+      g_value_set_ulong (value, cache->max_size);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+  }
+}
 
-  cache->refcount--;
-  if (cache->refcount > 0)
-    return;
+static void
+swfdec_cache_set_property (GObject *object, guint param_id, const GValue *value,
+    GParamSpec *pspec)
+{
+  SwfdecCache *cache = SWFDEC_CACHE (object);
+
+  switch (param_id) {
+    case PROP_MAX_CACHE_SIZE:
+      swfdec_cache_set_max_cache_size (cache, g_value_get_ulong (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+  }
+}
 
-  g_queue_free (cache->queue);
-  g_free (cache);
+static void
+swfdec_cache_class_init (SwfdecCacheClass * g_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (g_class);
+
+  object_class->dispose = swfdec_cache_dispose;
+  object_class->get_property = swfdec_cache_get_property;
+  object_class->set_property = swfdec_cache_set_property;
+
+  /* FIXME: should be g_param_spec_size(), but no such thing exists */
+  g_object_class_install_property (object_class, PROP_CACHE_SIZE,
+      g_param_spec_ulong ("cache-size", "cache-size", "current size of cache",
+	  0, G_MAXULONG, 0, G_PARAM_READABLE));
+  g_object_class_install_property (object_class, PROP_MAX_CACHE_SIZE,
+      g_param_spec_ulong ("max-cache-size", "max-cache-size", "maximum allowed size of cache",
+	  0, G_MAXULONG, 1024 * 1024, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 }
 
-gulong
-swfdec_cache_get_usage (SwfdecCache *cache)
+static void
+swfdec_cache_init (SwfdecCache *cache)
 {
-  g_return_val_if_fail (cache != NULL, 0);
+  cache->queue = g_queue_new ();
+}
 
-  return cache->usage;
+SwfdecCache *
+swfdec_cache_new (gsize max_size)
+{
+  return g_object_new (SWFDEC_TYPE_CACHE, "max-cache-size", max_size);
 }
 
-void
-swfdec_cache_shrink (SwfdecCache *cache, gulong max_usage)
+gsize
+swfdec_cache_get_cache_size (SwfdecCache *cache)
 {
-  g_return_if_fail (cache != NULL);
-
-  while (cache->usage > max_usage) {
-    SwfdecCacheHandle *handle = g_queue_pop_tail (cache->queue);
-    g_assert (handle);
-    cache->usage -= handle->size;
-    SWFDEC_LOG ("%p removing %p (%lu => %lu)", cache, handle, 
-	cache->usage + handle->size, cache->usage);
-    handle->unload (handle);
-  }
+  g_return_val_if_fail (SWFDEC_IS_CACHE (cache), 0);
+
+  return cache->size;
 }
 
-gulong
-swfdec_cache_get_size (SwfdecCache *cache)
+gsize
+swfdec_cache_get_max_cache_size (SwfdecCache *cache)
 {
-  g_return_val_if_fail (cache != NULL, 0);
+  g_return_val_if_fail (SWFDEC_IS_CACHE (cache), 0);
 
   return cache->max_size;
 }
 
 void
-swfdec_cache_set_size (SwfdecCache *cache, gulong max_usage)
+swfdec_cache_set_max_cache_size (SwfdecCache *cache, gsize max_size)
 {
-  g_return_if_fail (cache != NULL);
+  g_return_if_fail (SWFDEC_IS_CACHE (cache));
 
-  swfdec_cache_shrink (cache, max_usage);
-  cache->max_size = max_usage;
+  cache->max_size = max_size;
+  swfdec_cache_shrink (cache, max_size);
+  g_object_notify (G_OBJECT (cache), "max-cache-size");
 }
 
-/**
- * swfdec_cache_add_handle:
- * @cache: a #SwfdecCache
- * @handle: a handle to add
- *
- * Adds @handle to @cache. If not enough space is available in the cache,
- * the cache will unload existing handles first. If handle is already part
- * of cache, its usage information will be updated. This will make it less
- * likely that it gets unloaded.
- **/
 void
-swfdec_cache_add_handle (SwfdecCache *cache, const SwfdecCacheHandle *handle)
+swfdec_cache_shrink (SwfdecCache *cache, gsize size)
 {
-  GList *list;
-
-  g_return_if_fail (cache != NULL);
-  g_return_if_fail (handle != NULL);
-  g_return_if_fail (handle->size > 0);
-  g_return_if_fail (handle->unload != NULL);
-
-  list = g_queue_find (cache->queue, handle);
-  if (list) {
-    /* bring to front of queue */
-    g_queue_unlink (cache->queue, list);
-    g_queue_push_head_link (cache->queue, list);
-  } else {
-    swfdec_cache_shrink (cache, cache->max_size - handle->size);
-    g_queue_push_head (cache->queue, (gpointer) handle);
-    cache->usage += handle->size;
-    SWFDEC_LOG ("%p adding %p (%lu => %lu)", cache, handle, 
-	cache->usage - handle->size, cache->usage);
-  }
+  SwfdecCached *cached;
+
+  g_return_if_fail (SWFDEC_IS_CACHE (cache));
+
+  if (size >= cache->size)
+    return;
+
+  do {
+    cached = g_queue_pop_tail (cache->queue);
+    g_assert (cached);
+    swfdec_cache_remove (cache, cached);
+  } while (size < cache->size);
+  g_object_notify (G_OBJECT (cache), "cache-size");
+}
+
+static void
+swfdec_cache_use_cached (SwfdecCached *cached, SwfdecCache *cache)
+{
+  /* move cached item to the front of the queue */
+  g_queue_remove (cache->queue, cached);
+  g_queue_push_head (cache->queue, cached);
+}
+
+static void
+swfdec_cache_unuse_cached (SwfdecCached *cached, SwfdecCache *cache)
+{
+  /* move cached item to the front of the queue */
+  g_queue_remove (cache->queue, cached);
+  swfdec_cache_remove (cache, cached);
 }
 
-/**
- * swfdec_cache_remove_handle:
- * @cache: a #SwfdecCache
- * @handle: the handle to remove
- *
- * Removes the given @handle from the @cache, if it was part of it. If the 
- * handle wasn't part of the cache, nothing happens.
- **/
 void
-swfdec_cache_remove_handle (SwfdecCache *cache, const SwfdecCacheHandle *handle)
+swfdec_cache_add (SwfdecCache *cache, SwfdecCached *cached)
 {
-  GList *list;
-
-  g_return_if_fail (cache != NULL);
-  g_return_if_fail (handle != NULL);
-  g_return_if_fail (handle->size > 0);
-  g_return_if_fail (handle->unload != NULL);
-
-  list = g_queue_find (cache->queue, handle);
-  if (list) {
-    g_queue_delete_link (cache->queue, list);
-    cache->usage -= handle->size;
-    SWFDEC_LOG ("%p removing %p (%lu => %lu)", cache, handle, 
-	cache->usage + handle->size, cache->usage);
-  }
+  gsize needed_size;
+
+  g_return_if_fail (SWFDEC_IS_CACHE (cache));
+  g_return_if_fail (SWFDEC_IS_CACHED (cached));
+
+  needed_size = swfdec_cached_get_size (cached);
+  if (needed_size > cache->max_size)
+    return;
+
+  g_object_ref (cached);
+  swfdec_cache_shrink (cache, cache->max_size - needed_size);
+  cache->size += needed_size;
+  g_signal_connect (cached, "use", G_CALLBACK (swfdec_cache_use_cached), cache);
+  g_signal_connect (cached, "unuse", G_CALLBACK (swfdec_cache_unuse_cached), cache);
+  g_queue_push_head (cache->queue, cached);
 }
+
diff --git a/swfdec/swfdec_cache.h b/swfdec/swfdec_cache.h
index 89b589d..4b87701 100644
--- a/swfdec/swfdec_cache.h
+++ b/swfdec/swfdec_cache.h
@@ -1,6 +1,5 @@
 /* Swfdec
- * Copyright (C) 2005 David Schleef <ds at schleef.org>
- *		 2007 Benjamin Otte <otte at gnome.org>
+ * Copyright (c) 2008 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,43 +20,53 @@
 #ifndef _SWFDEC_CACHE_H_
 #define _SWFDEC_CACHE_H_
 
-#include <swfdec/swfdec_types.h>
+#include <cairo.h>
+#include <swfdec/swfdec_cache.h>
+#include <swfdec/swfdec_cached.h>
 
 G_BEGIN_DECLS
 
-//typedef struct _SwfdecCache SwfdecCache;
-//typedef struct _SwfdecCacheHandle SwfdecCacheHandle;
+typedef struct _SwfdecCache SwfdecCache;
+typedef struct _SwfdecCacheClass SwfdecCacheClass;
+
+#define SWFDEC_TYPE_CACHE                    (swfdec_cache_get_type())
+#define SWFDEC_IS_CACHE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_CACHE))
+#define SWFDEC_IS_CACHE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_CACHE))
+#define SWFDEC_CACHE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_CACHE, SwfdecCache))
+#define SWFDEC_CACHE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_CACHE, SwfdecCacheClass))
+#define SWFDEC_CACHE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_CACHE, SwfdecCacheClass))
+
 
 struct _SwfdecCache {
-  guint		refcount;		/* reference count */
-  gulong	max_size;		/* max size of cache */
-  gulong	usage;			/* current size of cache */
+  GObject		object;
 
-  GQueue *	queue;			/* queue of loaded SwfdecCacheHandle, sorted by most recently used */
-};
+  gsize			max_size;	/* maximum amount of data allowed in cache, before starting to purge */
+  gsize			size;		/* current amount of data in cache */
 
-struct _SwfdecCacheHandle {
-  gulong	size;	          	/* size of this item */
+  GQueue *		queue;		/* queue of SwfdecCached, most recently used first */
+};
 
-  GDestroyNotify	unload;		/* function called when unloading this handle */
+struct _SwfdecCacheClass
+{
+  GObjectClass		object_class;
 };
 
-SwfdecCache *	swfdec_cache_new		(gulong			max_size);
-void		swfdec_cache_ref		(SwfdecCache *		cache);
-void		swfdec_cache_unref		(SwfdecCache *		cache);
+GType			swfdec_cache_get_type		(void);
 
-gulong		swfdec_cache_get_size		(SwfdecCache *		cache);
-void		swfdec_cache_set_size		(SwfdecCache *		cache,
-						 gulong			max_usage);
-gulong		swfdec_cache_get_usage	  	(SwfdecCache *		cache);
-void		swfdec_cache_shrink		(SwfdecCache *		cache,
-						 gulong			max_usage);
-void		swfdec_cache_add_handle		(SwfdecCache *	  	cache,
-						 const SwfdecCacheHandle *handle);
-void		swfdec_cache_remove_handle    	(SwfdecCache *	  	cache,
-						 const SwfdecCacheHandle *handle);
+SwfdecCache *		swfdec_cache_new		(gsize		max_size);
 
+gsize			swfdec_cache_get_cache_size   	(SwfdecCache *	cache);
+gsize			swfdec_cache_get_max_cache_size	(SwfdecCache *	cache);
+void			swfdec_cache_set_max_cache_size	(SwfdecCache *	cache,
+							 gsize		max_size);
 
-G_END_DECLS
+void			swfdec_cache_shrink             (SwfdecCache *	cache,
+							 gsize		size);
 
+void			swfdec_cache_add		(SwfdecCache *	cache,
+							 SwfdecCached *	cached);
+
+
+
+G_END_DECLS
 #endif
diff --git a/swfdec/swfdec_cached.c b/swfdec/swfdec_cached.c
index 4279d1e..173868e 100644
--- a/swfdec/swfdec_cached.c
+++ b/swfdec/swfdec_cached.c
@@ -1,5 +1,5 @@
 /* Swfdec
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,99 +25,101 @@
 #include "swfdec_debug.h"
 
 
-G_DEFINE_ABSTRACT_TYPE (SwfdecCached, swfdec_cached, SWFDEC_TYPE_CHARACTER)
+G_DEFINE_ABSTRACT_TYPE (SwfdecCached, swfdec_cached, G_TYPE_OBJECT)
 
-static void
-swfdec_cached_dispose (GObject *object)
-{
-  SwfdecCached * cached = SWFDEC_CACHED (object);
+enum {
+  PROP_0,
+  PROP_SIZE
+};
 
-  swfdec_cached_unload (cached);
-  swfdec_cached_set_cache (cached, NULL);
+enum {
+  USE,
+  UNUSE,
+  LAST_SIGNAL
+};
 
-  G_OBJECT_CLASS (swfdec_cached_parent_class)->dispose (object);
-}
+guint signals[LAST_SIGNAL] = { 0, };
 
 static void
-swfdec_cached_class_init (SwfdecCachedClass * g_class)
+swfdec_cached_get_property (GObject *object, guint param_id, GValue *value,
+    GParamSpec *pspec)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (g_class);
-
-  object_class->dispose = swfdec_cached_dispose;
+  SwfdecCached *cached = SWFDEC_CACHED (object);
+
+  switch (param_id) {
+    case PROP_SIZE:
+      g_value_set_ulong (value, cached->size);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+  }
 }
 
 static void
-swfdec_cached_init (SwfdecCached * cached)
+swfdec_cached_set_property (GObject *object, guint param_id, const GValue *value,
+    GParamSpec *pspec)
 {
+  SwfdecCached *cached = SWFDEC_CACHED (object);
+
+  switch (param_id) {
+    case PROP_SIZE:
+      cached->size = g_value_get_ulong (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+  }
 }
 
-void
-swfdec_cached_set_cache (SwfdecCached *cached, SwfdecCache *cache)
+static void
+swfdec_cached_class_init (SwfdecCachedClass * g_class)
 {
-  g_return_if_fail (SWFDEC_IS_CACHED (cached));
+  GObjectClass *object_class = G_OBJECT_CLASS (g_class);
 
-  if (cached->cache) {
-    if (cached->handle.unload)
-      swfdec_cache_remove_handle (cached->cache, &cached->handle);
-    swfdec_cache_unref (cached->cache);
-  }
-  cached->cache = cache;
-  if (cache) {
-    swfdec_cache_ref (cache);
-    if (cached->handle.unload)
-      swfdec_cache_add_handle (cached->cache, &cached->handle);
-  }
+  object_class->get_property = swfdec_cached_get_property;
+  object_class->set_property = swfdec_cached_set_property;
+
+  /* FIXME: should be g_param_spec_size(), but no such thing exists */
+  g_object_class_install_property (object_class, PROP_SIZE,
+      g_param_spec_ulong ("size", "size", "size of this object in bytes",
+	  0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  signals[USE] = g_signal_new ("use", G_TYPE_FROM_CLASS (g_class),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0);
+  signals[UNUSE] = g_signal_new ("unuse", G_TYPE_FROM_CLASS (g_class),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0);
 }
 
 static void
-swfdec_cached_unload_func (gpointer data)
+swfdec_cached_init (SwfdecCached * cached)
 {
-  SwfdecCached *cached = SWFDEC_CACHED ((void *) ((guint8 *) data - G_STRUCT_OFFSET (SwfdecCached, handle)));
-
-  cached->handle.unload = NULL;
-  swfdec_cached_unload (cached);
+  cached->size = sizeof (SwfdecCached);
 }
 
 void
-swfdec_cached_load (SwfdecCached *cached, guint size)
+swfdec_cached_use (SwfdecCached *cached)
 {
   g_return_if_fail (SWFDEC_IS_CACHED (cached));
-  g_return_if_fail (cached->handle.unload == NULL);
-  g_return_if_fail (size > 0);
 
-  cached->handle.unload = swfdec_cached_unload_func;
-  cached->handle.size = size;
-  if (cached->cache)
-    swfdec_cache_add_handle (cached->cache, &cached->handle);
+  g_signal_emit (cached, signals[USE], 0);
 }
 
 void
-swfdec_cached_use (SwfdecCached *cached)
+swfdec_cached_unuse (SwfdecCached *cached)
 {
   g_return_if_fail (SWFDEC_IS_CACHED (cached));
-  g_return_if_fail (cached->handle.unload != NULL);
 
-  if (cached->cache)
-    swfdec_cache_add_handle (cached->cache, &cached->handle);
+  g_signal_emit (cached, signals[UNUSE], 0);
 }
 
-void
-swfdec_cached_unload (SwfdecCached *cached)
+gsize
+swfdec_cached_get_size (SwfdecCached *cached)
 {
-  g_return_if_fail (SWFDEC_IS_CACHED (cached));
+  g_return_val_if_fail (SWFDEC_IS_CACHED (cached), 0);
 
-  if (cached->handle.unload) {
-    if (cached->cache)
-      swfdec_cache_remove_handle (cached->cache, &cached->handle);
-    cached->handle.unload = NULL;
-  }
-  if (cached->handle.size) {
-    SwfdecCachedClass *klass;
-
-    klass = SWFDEC_CACHED_GET_CLASS (cached);
-    cached->handle.size = 0;
-    g_return_if_fail (klass->unload != NULL);
-    klass->unload (cached);
-  }
+  return cached->size;
 }
 
diff --git a/swfdec/swfdec_cached.h b/swfdec/swfdec_cached.h
index 52365f4..5eb37b9 100644
--- a/swfdec/swfdec_cached.h
+++ b/swfdec/swfdec_cached.h
@@ -1,5 +1,5 @@
 /* Swfdec
- * Copyright (c) 2007 Benjamin Otte <otte at gnome.org>
+ * Copyright (c) 2008 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,7 @@
 #ifndef _SWFDEC_CACHED_H_
 #define _SWFDEC_CACHED_H_
 
-#include <cairo.h>
-#include <swfdec/swfdec_cache.h>
-#include <swfdec/swfdec_character.h>
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
@@ -38,27 +36,27 @@ typedef struct _SwfdecCachedClass SwfdecCachedClass;
 
 
 struct _SwfdecCached {
-  SwfdecCharacter	character;
+  GObject		object;
 
-  SwfdecCache *		cache;		/* cache to use for cached */
-  SwfdecCacheHandle	handle;		/* handle to unload surface */
+  gsize			size;
 };
 
 struct _SwfdecCachedClass
 {
-  SwfdecCharacterClass	character_class;
+  GObjectClass		object_class;
 
-  void			(* unload)			(SwfdecCached *	cached);
+  /* signals */
+  void			(* use)				(SwfdecCached *	cached);
+  void			(* unuse)			(SwfdecCached *	cached);
 };
 
 GType			swfdec_cached_get_type		(void);
 
-void			swfdec_cached_load		(SwfdecCached *	cached,
-							 guint		size);
+gsize			swfdec_cached_get_size		(SwfdecCached *	cached);
+
+/* for subclasses */
 void			swfdec_cached_use		(SwfdecCached *	cached);
-void			swfdec_cached_unload		(SwfdecCached *	cached);
-void			swfdec_cached_set_cache		(SwfdecCached *	cached,
-							 SwfdecCache *	cache);
+void			swfdec_cached_unuse		(SwfdecCached *	cached);
 
 
 G_END_DECLS
diff --git a/swfdec/swfdec_cached_image.c b/swfdec/swfdec_cached_image.c
new file mode 100644
index 0000000..2cc6c76
--- /dev/null
+++ b/swfdec/swfdec_cached_image.c
@@ -0,0 +1,104 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_cached_image.h"
+#include "swfdec_debug.h"
+
+G_DEFINE_TYPE (SwfdecCachedImage, swfdec_cached_image, SWFDEC_TYPE_CACHED)
+
+static void
+swfdec_cached_image_dispose (GObject *object)
+{
+  SwfdecCachedImage *image = SWFDEC_CACHED_IMAGE (object);
+
+  if (image->surface) {
+    cairo_surface_destroy (image->surface);
+    image->surface = NULL;
+  }
+
+  G_OBJECT_CLASS (swfdec_cached_image_parent_class)->dispose (object);
+}
+
+static void
+swfdec_cached_image_class_init (SwfdecCachedImageClass * g_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (g_class);
+
+  object_class->dispose = swfdec_cached_image_dispose;
+}
+
+static void
+swfdec_cached_image_init (SwfdecCachedImage *cached)
+{
+  swfdec_color_transform_init_identity (&cached->trans);
+}
+
+SwfdecCachedImage *
+swfdec_cached_image_new (guint8 *image_data, cairo_format_t format,
+    guint width, guint height, guint rowstride)
+{
+  SwfdecCachedImage *image;
+  static const cairo_user_data_key_t key;
+  gulong size;
+
+  g_return_val_if_fail (image_data != NULL, NULL);
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+  g_return_val_if_fail (rowstride > 0, NULL);
+
+  /* FIXME: sizeof (cairo_surface_t) */
+  size = sizeof (SwfdecCachedImage) + height * rowstride;
+  image = g_object_new (SWFDEC_TYPE_CACHED_IMAGE, "size", size, NULL);
+  image->surface = cairo_image_surface_create_for_data (image_data, format,
+      width, height, rowstride);
+  if (cairo_surface_set_user_data (image->surface, &key, image_data, g_free) != CAIRO_STATUS_SUCCESS) {
+    /* guess we should abort here due to OOM? */
+    g_warning ("failed to register data free function");
+  }
+
+  return image;
+}
+
+SwfdecCachedImage *
+swfdec_cached_image_new_for_surface (cairo_surface_t *surface, gsize size)
+{
+  SwfdecCachedImage *image;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+  g_return_val_if_fail (size > 0, NULL);
+
+  size += sizeof (SwfdecCachedImage);
+  image = g_object_new (SWFDEC_TYPE_CACHED_IMAGE, "size", size, NULL);
+  image->surface = cairo_surface_reference (surface);
+
+  return image;
+}
+
+cairo_surface_t *
+swfdec_cached_image_get_surface (SwfdecCachedImage *image)
+{
+  g_return_val_if_fail (SWFDEC_IS_CACHED_IMAGE (image), NULL);
+
+  return cairo_surface_reference (image->surface);
+}
+
diff --git a/swfdec/swfdec_cached_image.h b/swfdec/swfdec_cached_image.h
new file mode 100644
index 0000000..d370a06
--- /dev/null
+++ b/swfdec/swfdec_cached_image.h
@@ -0,0 +1,68 @@
+/* Swfdec
+ * Copyright (c) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SWFDEC_CACHED_IMAGE_H_
+#define _SWFDEC_CACHED_IMAGE_H_
+
+#include <cairo.h>
+#include <swfdec/swfdec_cached.h>
+#include <swfdec/swfdec_color.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SwfdecCachedImage SwfdecCachedImage;
+typedef struct _SwfdecCachedImageClass SwfdecCachedImageClass;
+
+#define SWFDEC_TYPE_CACHED_IMAGE                    (swfdec_cached_image_get_type())
+#define SWFDEC_IS_CACHED_IMAGE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_CACHED_IMAGE))
+#define SWFDEC_IS_CACHED_IMAGE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_CACHED_IMAGE))
+#define SWFDEC_CACHED_IMAGE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_CACHED_IMAGE, SwfdecCachedImage))
+#define SWFDEC_CACHED_IMAGE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_CACHED_IMAGE, SwfdecCachedImageClass))
+#define SWFDEC_CACHED_IMAGE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_CACHED_IMAGE, SwfdecCachedImageClass))
+
+
+struct _SwfdecCachedImage {
+  SwfdecCached		cached;
+
+  cairo_surface_t *	surface;	/* the surface */
+  SwfdecColorTransform	trans;		/* the transform that has been applied to this surface */
+};
+
+struct _SwfdecCachedImageClass
+{
+  SwfdecCachedClass	cached_class;
+};
+
+GType			swfdec_cached_image_get_type	(void);
+
+SwfdecCachedImage *	swfdec_cached_image_new		(guint8 *		image_data,
+							 cairo_format_t		format,
+							 guint			width,
+							 guint			height,
+							 guint			rowstride);
+SwfdecCachedImage *	swfdec_cached_image_new_for_surface
+							(cairo_surface_t *	surface,
+							 gsize			size);
+
+
+cairo_surface_t *	swfdec_cached_image_get_surface	(SwfdecCachedImage *	image);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_image.c b/swfdec/swfdec_image.c
index b4bff6c..1be91b8 100644
--- a/swfdec/swfdec_image.c
+++ b/swfdec/swfdec_image.c
@@ -1,7 +1,7 @@
 /* Swfdec
  * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
  *		 2005-2006 Eric Anholt <eric at anholt.net>
- *		 2006-2007 Benjamin Otte <otte at gnome.org>
+ *		 2006-2008 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,7 +29,7 @@
 
 #include "jpeg.h"
 #include "swfdec_image.h"
-#include "swfdec_cache.h"
+#include "swfdec_cached_image.h"
 #include "swfdec_debug.h"
 #include "swfdec_swf_decoder.h"
 
@@ -41,18 +41,7 @@ static void swfdec_image_colormap_decode (SwfdecImage * image,
     unsigned char *dest,
     unsigned char *src, unsigned char *colormap, int colormap_len);
 
-G_DEFINE_TYPE (SwfdecImage, swfdec_image, SWFDEC_TYPE_CACHED)
-
-static void
-swfdec_image_unload (SwfdecCached *cached)
-{
-  SwfdecImage *image = SWFDEC_IMAGE (cached);
-
-  if (image->surface) {
-    cairo_surface_destroy (image->surface);
-    image->surface = NULL;
-  }
-}
+G_DEFINE_TYPE (SwfdecImage, swfdec_image, SWFDEC_TYPE_CHARACTER)
 
 static void
 swfdec_image_dispose (GObject *object)
@@ -69,19 +58,14 @@ swfdec_image_dispose (GObject *object)
   }
 
   G_OBJECT_CLASS (swfdec_image_parent_class)->dispose (object);
-
-  g_assert (image->surface == NULL);
 }
 
 static void
 swfdec_image_class_init (SwfdecImageClass * g_class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (g_class);
-  SwfdecCachedClass *cached_class = SWFDEC_CACHED_CLASS (g_class);
 
   object_class->dispose = swfdec_image_dispose;
-
-  cached_class->unload = swfdec_image_unload;
 }
 
 static void
@@ -167,7 +151,7 @@ swfdec_jpeg_decode_argb (unsigned char *data1, int length1,
   return ret;
 }
 
-static void
+static SwfdecCachedImage * 
 swfdec_image_jpeg_load (SwfdecImage *image)
 {
   gboolean ret;
@@ -186,15 +170,13 @@ swfdec_image_jpeg_load (SwfdecImage *image)
   }
 
   if (!ret)
-    return;
-
-  swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height);
-  image->surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24,
-      image->width, image->height, image->width * 4);
-  cairo_surface_set_user_data (image->surface, &key, data, g_free);
+    return NULL;
 
   SWFDEC_LOG ("  width = %d", image->width);
   SWFDEC_LOG ("  height = %d", image->height);
+
+  return swfdec_cached_image_new (data, CAIRO_FORMAT_RGB24, image->width, 
+      image->height, 4 * image->width);
 }
 
 int
@@ -217,7 +199,7 @@ tag_func_define_bits_jpeg_2 (SwfdecSwfDecoder * s, guint tag)
   return SWFDEC_STATUS_OK;
 }
 
-static void
+static SwfdecCachedImage *
 swfdec_image_jpeg2_load (SwfdecImage *image)
 {
   gboolean ret;
@@ -227,15 +209,13 @@ swfdec_image_jpeg2_load (SwfdecImage *image)
       NULL, 0,
       (void *)&data, &image->width, &image->height);
   if (!ret)
-    return;
-
-  swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height);
-  image->surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24,
-      image->width, image->height, image->width * 4);
-  cairo_surface_set_user_data (image->surface, &key, data, g_free);
+    return NULL;
 
   SWFDEC_LOG ("  width = %d", image->width);
   SWFDEC_LOG ("  height = %d", image->height);
+
+  return swfdec_cached_image_new (data, CAIRO_FORMAT_RGB24, image->width, 
+      image->height, 4 * image->width);
 }
 
 int
@@ -258,7 +238,7 @@ tag_func_define_bits_jpeg_3 (SwfdecSwfDecoder * s, guint tag)
   return SWFDEC_STATUS_OK;
 }
 
-static void
+static SwfdecCachedImage *
 swfdec_image_jpeg3_load (SwfdecImage *image)
 {
   SwfdecBits bits;
@@ -272,7 +252,7 @@ swfdec_image_jpeg3_load (SwfdecImage *image)
   jpeg_length = swfdec_bits_get_u32 (&bits);
   buffer = swfdec_bits_get_buffer (&bits, jpeg_length);
   if (buffer == NULL)
-    return;
+    return NULL;
 
   ret = swfdec_jpeg_decode_argb (buffer->data, buffer->length,
       NULL, 0,
@@ -280,9 +260,7 @@ swfdec_image_jpeg3_load (SwfdecImage *image)
   swfdec_buffer_unref (buffer);
 
   if (!ret)
-    return;
-
-  swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height);
+    return NULL;
 
   buffer = swfdec_bits_decompress (&bits, -1, image->width * image->height);
   if (buffer) {
@@ -295,9 +273,8 @@ swfdec_image_jpeg3_load (SwfdecImage *image)
   SWFDEC_LOG ("  width = %d", image->width);
   SWFDEC_LOG ("  height = %d", image->height);
 
-  image->surface = cairo_image_surface_create_for_data (data,
-      CAIRO_FORMAT_ARGB32, image->width, image->height, image->width * 4);
-  cairo_surface_set_user_data (image->surface, &key, data, g_free);
+  return swfdec_cached_image_new (data, CAIRO_FORMAT_RGB24, image->width, 
+      image->height, 4 * image->width);
 }
 
 static void
@@ -317,7 +294,7 @@ merge_alpha (SwfdecImage * image, unsigned char *image_data,
   }
 }
 
-static void
+static SwfdecCachedImage *
 swfdec_image_lossless_load (SwfdecImage *image)
 {
   int format;
@@ -347,8 +324,7 @@ swfdec_image_lossless_load (SwfdecImage *image)
   SWFDEC_LOG ("color_table_size = %d", color_table_size);
 
   if (image->width == 0 || image->height == 0)
-    return;
-  swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height);
+    return NULL;
 
   if (format == 3) {
     SwfdecBuffer *buffer;
@@ -467,22 +443,16 @@ swfdec_image_lossless_load (SwfdecImage *image)
 	p++;
       }
     }
-    image->surface = cairo_image_surface_create_for_data (data, 
-	have_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, 
-	image->width, image->height, image->width * 4);
-    cairo_surface_set_user_data (image->surface, &key, buffer, 
-	(cairo_destroy_func_t) swfdec_buffer_unref);
-    return;
+    data = g_memdup (buffer->data, buffer->length);
   } else {
     SWFDEC_ERROR ("unknown lossless image format %u", format);
-    return;
+    return NULL;
   }
 
 out:
-  image->surface = cairo_image_surface_create_for_data (data, 
+  return swfdec_cached_image_new (data,
       have_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, 
       image->width, image->height, image->width * 4);
-  cairo_surface_set_user_data (image->surface, &key, data, g_free);
 }
 
 int
@@ -576,59 +546,67 @@ swfdec_image_png_read (void *bitsp, unsigned char *data, unsigned int length)
   return CAIRO_STATUS_SUCCESS;
 }
 
-static void
+static SwfdecCachedImage *
 swfdec_image_png_load (SwfdecImage *image)
 {
   SwfdecBits bits;
+  cairo_surface_t *surface;
+  SwfdecCachedImage *cached;
 
   swfdec_bits_init (&bits, image->raw_data);
-  image->surface = cairo_image_surface_create_from_png_stream (
+  surface = cairo_image_surface_create_from_png_stream (
       swfdec_image_png_read, &bits);
-  image->width = cairo_image_surface_get_width (image->surface);
-  image->height = cairo_image_surface_get_height (image->surface);
-  swfdec_cached_load (SWFDEC_CACHED (image), image->height *
-      cairo_image_surface_get_stride (image->surface));
+  image->width = cairo_image_surface_get_width (surface);
+  image->height = cairo_image_surface_get_height (surface);
+  cached = swfdec_cached_image_new_for_surface (surface,
+      image->height * cairo_image_surface_get_stride (surface));
+  cairo_surface_destroy (surface);
+  return cached;
 }
 
 cairo_surface_t *
 swfdec_image_create_surface (SwfdecImage *image)
 {
+  SwfdecCachedImage *cached;
+  cairo_surface_t *surface;
+
   if (image->raw_data == NULL)
     return NULL;
 
-  if (image->surface == NULL) {
+  if (TRUE) {
     switch (image->type) {
       case SWFDEC_IMAGE_TYPE_JPEG:
-	swfdec_image_jpeg_load (image);
+	cached = swfdec_image_jpeg_load (image);
 	break;
       case SWFDEC_IMAGE_TYPE_JPEG2:
-	swfdec_image_jpeg2_load (image);
+	cached = swfdec_image_jpeg2_load (image);
 	break;
       case SWFDEC_IMAGE_TYPE_JPEG3:
-	swfdec_image_jpeg3_load (image);
+	cached = swfdec_image_jpeg3_load (image);
 	break;
       case SWFDEC_IMAGE_TYPE_LOSSLESS:
-	swfdec_image_lossless_load (image);
+	cached = swfdec_image_lossless_load (image);
 	break;
       case SWFDEC_IMAGE_TYPE_LOSSLESS2:
-	swfdec_image_lossless_load (image);
+	cached = swfdec_image_lossless_load (image);
 	break;
       case SWFDEC_IMAGE_TYPE_PNG:
-	swfdec_image_png_load (image);
+	cached = swfdec_image_png_load (image);
 	break;
       case SWFDEC_IMAGE_TYPE_UNKNOWN:
       default:
 	g_assert_not_reached ();
 	break;
     }
-    if (image->surface == NULL) {
+    if (cached == NULL) {
       SWFDEC_WARNING ("failed to decode image");
       return NULL;
     }
-  } else {
-    swfdec_cached_use (SWFDEC_CACHED (image));
   }
-  return cairo_surface_reference (image->surface);
+
+  surface = swfdec_cached_image_get_surface (cached);
+  g_object_unref (cached);
+  return surface;
 }
 
 cairo_surface_t *
diff --git a/swfdec/swfdec_image.h b/swfdec/swfdec_image.h
index 8e41db9..3e2d53d 100644
--- a/swfdec/swfdec_image.h
+++ b/swfdec/swfdec_image.h
@@ -1,7 +1,7 @@
 /* Swfdec
  * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
  *		 2005-2006 Eric Anholt <eric at anholt.net>
- *		 2006-2007 Benjamin Otte <otte at gnome.org>
+ *		 2006-2008 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,10 +23,11 @@
 #define _SWFDEC_IMAGE_H_
 
 #include <cairo.h>
-#include <swfdec/swfdec_cached.h>
+#include <swfdec/swfdec_character.h>
 #include <swfdec/swfdec_decoder.h>
 
 G_BEGIN_DECLS
+
 //typedef struct _SwfdecImage SwfdecImage;
 typedef struct _SwfdecImageClass SwfdecImageClass;
 
@@ -48,11 +49,10 @@ typedef enum {
 } SwfdecImageType;
 
 struct _SwfdecImage {
-  SwfdecCached		cached;
+  SwfdecCharacter	character;
 
   int			width;		/* width of image or 0 if not known yet */
   int			height;		/* height of image or 0 if not known yet */
-  cairo_surface_t *	surface;	/* surface when cache loaded or NULL */
 
   SwfdecImageType	type;
   SwfdecBuffer *	jpegtables;
@@ -60,8 +60,7 @@ struct _SwfdecImage {
 };
 
 struct _SwfdecImageClass {
-  SwfdecCachedClass	cached_class;
-
+  SwfdecCharacterClass	character_class;
 };
 
 GType			swfdec_image_get_type		(void);
diff --git a/swfdec/swfdec_player.c b/swfdec/swfdec_player.c
index 83a43bd..0ba1ac2 100644
--- a/swfdec/swfdec_player.c
+++ b/swfdec/swfdec_player.c
@@ -728,7 +728,7 @@ swfdec_player_get_property (GObject *object, guint param_id, GValue *value,
       g_value_set_uint (value, swfdec_player_get_background_color (player));
       break;
     case PROP_CACHE_SIZE:
-      g_value_set_ulong (value, swfdec_cache_get_size (priv->cache));
+      g_value_set_ulong (value, swfdec_cache_get_max_cache_size (priv->cache));
       break;
     case PROP_INITIALIZED:
       g_value_set_boolean (value, swfdec_player_is_initialized (player));
@@ -875,7 +875,7 @@ swfdec_player_set_property (GObject *object, guint param_id, const GValue *value
       swfdec_player_set_background_color (player, g_value_get_uint (value));
       break;
     case PROP_CACHE_SIZE:
-      swfdec_cache_set_size (priv->cache, g_value_get_ulong (value));
+      swfdec_cache_set_max_cache_size (priv->cache, g_value_get_ulong (value));
       break;
     case PROP_WIDTH:
       swfdec_player_set_size (player, g_value_get_int (value), priv->stage_height);
@@ -1010,7 +1010,7 @@ swfdec_player_dispose (GObject *object)
   g_assert (priv->timeouts == NULL);
   g_list_free (priv->intervals);
   priv->intervals = NULL;
-  swfdec_cache_unref (priv->cache);
+  g_object_unref (priv->cache);
   if (priv->system) {
     g_object_unref (priv->system);
     priv->system = NULL;
@@ -2188,7 +2188,7 @@ swfdec_player_init (SwfdecPlayer *player)
     priv->actions[i] = swfdec_ring_buffer_new_for_type (SwfdecPlayerAction, 16);
   }
   priv->external_actions = swfdec_ring_buffer_new_for_type (SwfdecPlayerExternalAction, 8);
-  priv->cache = swfdec_cache_new (50 * 1024 * 1024); /* 100 MB */
+  priv->cache = swfdec_cache_new (16 * 1024 * 1024);
   priv->bgcolor = SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF);
   priv->socket_type = SWFDEC_TYPE_SOCKET;
 
diff --git a/swfdec/swfdec_player_internal.h b/swfdec/swfdec_player_internal.h
index 340c658..7d03034 100644
--- a/swfdec/swfdec_player_internal.h
+++ b/swfdec/swfdec_player_internal.h
@@ -23,6 +23,7 @@
 #include <swfdec/swfdec_player.h>
 #include <swfdec/swfdec_audio.h>
 #include <swfdec/swfdec_audio_internal.h>
+#include <swfdec/swfdec_cache.h>
 #include <swfdec/swfdec_event.h>
 #include <swfdec/swfdec_function_list.h>
 #include <swfdec/swfdec_loader.h>
diff --git a/swfdec/swfdec_sound.c b/swfdec/swfdec_sound.c
index a788b14..76e21fc 100644
--- a/swfdec/swfdec_sound.c
+++ b/swfdec/swfdec_sound.c
@@ -33,24 +33,15 @@
 #include "swfdec_sprite.h"
 #include "swfdec_swf_decoder.h"
 
-G_DEFINE_TYPE (SwfdecSound, swfdec_sound, SWFDEC_TYPE_CACHED)
-
-static void
-swfdec_sound_unload (SwfdecCached *cached)
-{
-  SwfdecSound * sound = SWFDEC_SOUND (cached);
-
-  if (sound->decoded) {
-    swfdec_buffer_unref (sound->decoded);
-    sound->decoded = NULL;
-  }
-}
+G_DEFINE_TYPE (SwfdecSound, swfdec_sound, SWFDEC_TYPE_CHARACTER)
 
 static void
 swfdec_sound_dispose (GObject *object)
 {
   SwfdecSound * sound = SWFDEC_SOUND (object);
 
+  if (sound->decoded)
+    swfdec_buffer_unref (sound->decoded);
   if (sound->encoded)
     swfdec_buffer_unref (sound->encoded);
 
@@ -61,11 +52,8 @@ static void
 swfdec_sound_class_init (SwfdecSoundClass * g_class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (g_class);
-  SwfdecCachedClass *cached_class = SWFDEC_CACHED_CLASS (g_class);
 
   object_class->dispose = swfdec_sound_dispose;
-
-  cached_class->unload = swfdec_sound_unload;
 }
 
 static void
@@ -177,7 +165,6 @@ swfdec_sound_get_decoded (SwfdecSound *sound, SwfdecAudioFormat *format)
   g_return_val_if_fail (format != NULL, NULL);
 
   if (sound->decoded) {
-    swfdec_cached_use (SWFDEC_CACHED (sound));
     *format = sound->decoded_format;
     return sound->decoded;
   }
@@ -201,7 +188,6 @@ swfdec_sound_get_decoded (SwfdecSound *sound, SwfdecAudioFormat *format)
     SWFDEC_ERROR ("decoding didn't produce any data, bailing");
     return NULL;
   }
-  swfdec_cached_load (SWFDEC_CACHED (sound), depth);
   tmp = swfdec_buffer_queue_pull (queue, depth);
   swfdec_buffer_queue_unref (queue);
 
diff --git a/swfdec/swfdec_sound.h b/swfdec/swfdec_sound.h
index cea0a58..4d63b6e 100644
--- a/swfdec/swfdec_sound.h
+++ b/swfdec/swfdec_sound.h
@@ -22,7 +22,7 @@
 #ifndef _SWFDEC_SOUND_H_
 #define _SWFDEC_SOUND_H_
 
-#include <swfdec/swfdec_cached.h>
+#include <swfdec/swfdec_character.h>
 #include <swfdec/swfdec_codec_audio.h>
 #include <swfdec/swfdec_swf_decoder.h>
 #include <swfdec/swfdec_types.h>
@@ -61,7 +61,7 @@ struct _SwfdecSoundChunk
 
 struct _SwfdecSound
 {
-  SwfdecCached		cached;
+  SwfdecCharacter	character;
 
   guint			codec;			/* codec in use */
   SwfdecAudioFormat	format;	        	/* channel/rate/width information for codec */
@@ -75,7 +75,7 @@ struct _SwfdecSound
 
 struct _SwfdecSoundClass
 {
-  SwfdecCachedClass	cached_class;
+  SwfdecCharacterClass	character_class;
 };
 
 GType swfdec_sound_get_type (void);
diff --git a/swfdec/swfdec_swf_decoder.c b/swfdec/swfdec_swf_decoder.c
index 733faa7..da750e1 100644
--- a/swfdec/swfdec_swf_decoder.c
+++ b/swfdec/swfdec_swf_decoder.c
@@ -459,9 +459,6 @@ swfdec_swf_decoder_create_character (SwfdecSwfDecoder * s, guint id, GType type)
   result = g_object_new (type, NULL);
   result->id = id;
   g_hash_table_insert (s->characters, GUINT_TO_POINTER (id), result);
-  if (SWFDEC_IS_CACHED (result)) {
-    swfdec_cached_set_cache (SWFDEC_CACHED (result), SWFDEC_DECODER (s)->player->priv->cache);
-  }
 
   return result;
 }
diff --git a/swfdec/swfdec_types.h b/swfdec/swfdec_types.h
index eafb4f3..1beb94b 100644
--- a/swfdec/swfdec_types.h
+++ b/swfdec/swfdec_types.h
@@ -33,8 +33,6 @@ typedef int SwfdecFixed;
 
 typedef struct _SwfdecActor SwfdecActor;
 typedef struct _SwfdecButton SwfdecButton;
-typedef struct _SwfdecCache SwfdecCache;
-typedef struct _SwfdecCacheHandle SwfdecCacheHandle;
 typedef struct _SwfdecCharacter SwfdecCharacter;
 typedef struct _SwfdecColorTransform SwfdecColorTransform;
 typedef struct _SwfdecDecoder SwfdecDecoder;
commit 4db428f0a4adf930fbadd01e4e56917a7f7e0341
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Apr 6 21:37:36 2008 +0200

    fix maximum value to be ulong

diff --git a/swfdec/swfdec_player.c b/swfdec/swfdec_player.c
index 56145d0..83a43bd 100644
--- a/swfdec/swfdec_player.c
+++ b/swfdec/swfdec_player.c
@@ -1964,7 +1964,7 @@ swfdec_player_class_init (SwfdecPlayerClass *klass)
 	  -1, G_MAXLONG, -1, G_PARAM_READABLE));
   g_object_class_install_property (object_class, PROP_CACHE_SIZE,
       g_param_spec_ulong ("cache-size", "cache size", "maximum cache size in bytes",
-	  0, G_MAXUINT, 50 * 1024 * 1024, G_PARAM_READWRITE));
+	  0, G_MAXULONG, 50 * 1024 * 1024, G_PARAM_READWRITE));
   g_object_class_install_property (object_class, PROP_BACKGROUND_COLOR,
       g_param_spec_uint ("background-color", "background color", "ARGB color used to draw the background",
 	  0, G_MAXUINT, SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF), G_PARAM_READWRITE));
commit d46085ebf1a0c873f73394456361eedde6794fe8
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Apr 6 15:59:25 2008 +0200

    emit onChanged after changes
    
    the method is completely bogus, but makes some flash files work.

diff --git a/swfdec/swfdec_actor.c b/swfdec/swfdec_actor.c
index 7f853c5..f6b3e53 100644
--- a/swfdec/swfdec_actor.c
+++ b/swfdec/swfdec_actor.c
@@ -219,6 +219,16 @@ swfdec_actor_execute (SwfdecActor *actor, SwfdecEventType condition)
   } else if (condition == SWFDEC_EVENT_ENTER) {
     if (SWFDEC_MOVIE (actor)->state >= SWFDEC_MOVIE_STATE_REMOVED)
       return;
+  } else if (condition == SWFDEC_EVENT_SCROLL || condition == SWFDEC_EVENT_CHANGED) {
+    SwfdecAsValue argv[2];
+
+    SWFDEC_AS_VALUE_SET_STRING (&argv[0], SWFDEC_AS_STR_onScroller);
+    SWFDEC_AS_VALUE_SET_OBJECT (&argv[1], SWFDEC_AS_OBJECT (actor));
+    swfdec_sandbox_use (SWFDEC_MOVIE (actor)->resource->sandbox);
+    swfdec_as_object_call (SWFDEC_AS_OBJECT (actor),
+	SWFDEC_AS_STR_broadcastMessage, 2, argv, NULL);
+    swfdec_sandbox_unuse (SWFDEC_MOVIE (actor)->resource->sandbox);
+    return;
   }
 
   swfdec_sandbox_use (SWFDEC_MOVIE (actor)->resource->sandbox);
@@ -284,11 +294,9 @@ swfdec_actor_queue_script (SwfdecActor *actor, SwfdecEventType condition)
     case SWFDEC_EVENT_DRAG_OVER:
     case SWFDEC_EVENT_DRAG_OUT:
     case SWFDEC_EVENT_KEY_PRESS:
-      importance = SWFDEC_PLAYER_ACTION_QUEUE_NORMAL;
-      break;
     case SWFDEC_EVENT_CHANGED:
     case SWFDEC_EVENT_SCROLL:
-      importance = SWFDEC_PLAYER_ACTION_QUEUE_PRIORITY;
+      importance = SWFDEC_PLAYER_ACTION_QUEUE_NORMAL;
       break;
     default:
       g_return_if_reached ();
diff --git a/swfdec/swfdec_text_field_movie.c b/swfdec/swfdec_text_field_movie.c
index d348eae..8c4cbc2 100644
--- a/swfdec/swfdec_text_field_movie.c
+++ b/swfdec/swfdec_text_field_movie.c
@@ -1364,18 +1364,12 @@ swfdec_text_field_movie_iterate (SwfdecActor *actor)
 {
   SwfdecTextFieldMovie *text = SWFDEC_TEXT_FIELD_MOVIE (actor);
 
+  while (text->changed) {
+    swfdec_actor_queue_script (actor, SWFDEC_EVENT_CHANGED);
+    text->changed--;
+  }
   if (text->scroll_changed) {
-    SwfdecAsValue argv[2];
-
-    SWFDEC_FIXME ("I'm pretty sure this is swfdec_player_add_action()'d");
-    SWFDEC_AS_VALUE_SET_STRING (&argv[0], SWFDEC_AS_STR_onScroller);
-    SWFDEC_AS_VALUE_SET_OBJECT (&argv[1], SWFDEC_AS_OBJECT (text));
-    swfdec_sandbox_use (SWFDEC_MOVIE (actor)->resource->sandbox);
-    swfdec_as_object_call (SWFDEC_AS_OBJECT (text),
-	SWFDEC_AS_STR_broadcastMessage, 2, argv, NULL);
-    swfdec_sandbox_unuse (SWFDEC_MOVIE (actor)->resource->sandbox);
-
-    /* FIXME: unset this before or after emitting the event? */
+    swfdec_actor_queue_script (actor, SWFDEC_EVENT_SCROLL);
     text->scroll_changed = FALSE;
   }
 }
@@ -1619,6 +1613,12 @@ swfdec_text_field_movie_focus_out (SwfdecActor *actor)
 }
 
 static void
+swfdec_text_field_movie_changed (SwfdecTextFieldMovie *text)
+{
+  text->changed++;
+}
+
+static void
 swfdec_text_field_movie_key_press (SwfdecActor *actor, guint keycode, guint character)
 {
   SwfdecTextFieldMovie *text = SWFDEC_TEXT_FIELD_MOVIE (actor);
@@ -1654,17 +1654,23 @@ swfdec_text_field_movie_key_press (SwfdecActor *actor, guint keycode, guint char
       if (swfdec_text_field_movie_has_cursor (text)) {
 	start = BACKWARD (text, start);
       }
-      swfdec_sandbox_use (SWFDEC_MOVIE (text)->resource->sandbox);
-      swfdec_text_field_movie_replace_text (text, start, end, "");
-      swfdec_sandbox_unuse (SWFDEC_MOVIE (text)->resource->sandbox);
+      if (start != end) {
+	swfdec_sandbox_use (SWFDEC_MOVIE (text)->resource->sandbox);
+	swfdec_text_field_movie_replace_text (text, start, end, "");
+	swfdec_sandbox_unuse (SWFDEC_MOVIE (text)->resource->sandbox);
+	swfdec_text_field_movie_changed (text);
+      }
       return;
     case SWFDEC_KEY_DELETE:
       if (swfdec_text_field_movie_has_cursor (text)) {
 	end = FORWARD (text, end);
       }
-      swfdec_sandbox_use (SWFDEC_MOVIE (text)->resource->sandbox);
-      swfdec_text_field_movie_replace_text (text, start, end, "");
-      swfdec_sandbox_unuse (SWFDEC_MOVIE (text)->resource->sandbox);
+      if (start != end) {
+	swfdec_sandbox_use (SWFDEC_MOVIE (text)->resource->sandbox);
+	swfdec_text_field_movie_replace_text (text, start, end, "");
+	swfdec_sandbox_unuse (SWFDEC_MOVIE (text)->resource->sandbox);
+	swfdec_text_field_movie_changed (text);
+      }
       return;
     default:
       break;
@@ -1673,10 +1679,13 @@ swfdec_text_field_movie_key_press (SwfdecActor *actor, guint keycode, guint char
   if (character == 0)
     return;
   len = g_unichar_to_utf8 (character, insert);
-  insert[len] = 0;
-  swfdec_sandbox_use (SWFDEC_MOVIE (text)->resource->sandbox);
-  swfdec_text_field_movie_replace_text (text, start, end, insert);
-  swfdec_sandbox_unuse (SWFDEC_MOVIE (text)->resource->sandbox);
+  if (len) {
+    insert[len] = 0;
+    swfdec_sandbox_use (SWFDEC_MOVIE (text)->resource->sandbox);
+    swfdec_text_field_movie_replace_text (text, start, end, insert);
+    swfdec_sandbox_unuse (SWFDEC_MOVIE (text)->resource->sandbox);
+    swfdec_text_field_movie_changed (text);
+  }
 }
 
 static void
diff --git a/swfdec/swfdec_text_field_movie.h b/swfdec/swfdec_text_field_movie.h
index ea8ddd9..5d8eebd 100644
--- a/swfdec/swfdec_text_field_movie.h
+++ b/swfdec/swfdec_text_field_movie.h
@@ -118,6 +118,7 @@ struct _SwfdecTextFieldMovie {
   const char *		style_sheet_input; /* saved input, so it can be used to apply stylesheet again */
 
   gboolean		scroll_changed; /* if any of the scroll attributes have changed and we haven't fired the event yet */
+  guint			changed;	/* number of onChanged events we have to emit */
   int			scroll;
   int			scroll_max;
   int			scroll_bottom;


More information about the Swfdec-commits mailing list