71195bf131b21d404907c4bcec2be492e277d630
diff --git a/shell/Makefile.am b/shell/Makefile.am
index b301374..2b5d58e 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -84,6 +84,8 @@ evince_SOURCES=				\
 	ev-timeline.h			\
 	ev-tooltip.c			\
 	ev-tooltip.h			\
+	ev-transition-animation.c	\
+	ev-transition-animation.h	\
 	main.c				\
 	xdg-user-dir-lookup.c
 
diff --git a/shell/ev-transition-animation.c b/shell/ev-transition-animation.c
new file mode 100644
index 0000000..f0057ec
--- /dev/null
+++ b/shell/ev-transition-animation.c
@@ -0,0 +1,325 @@
+/* ev-transition-animation.c
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <cairo.h>
+#include <gdk/gdk.h>
+#include "ev-transition-animation.h"
+#include "ev-timeline.h"
+
+#define EV_TRANSITION_ANIMATION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimationPriv))
+#define N_BLINDS 6
+
+typedef struct EvTransitionAnimationPriv EvTransitionAnimationPriv;
+
+struct EvTransitionAnimationPriv {
+	EvPixbufCache *pixbuf_cache;
+	EvTransitionEffect *effect;
+
+	gint page_from;
+	gint page_to;
+
+	cairo_surface_t *origin_surface;
+	cairo_surface_t *dest_surface;
+};
+
+enum {
+	PROP_0,
+	PROP_PIXBUF_CACHE,
+	PROP_EFFECT,
+	PROP_PAGE_FROM,
+	PROP_PAGE_TO
+};
+
+
+G_DEFINE_TYPE (EvTransitionAnimation, ev_transition_animation, EV_TYPE_TIMELINE)
+
+
+static void
+ev_transition_animation_init (EvTransitionAnimation *animation)
+{
+}
+
+static void
+ev_transition_animation_set_property (GObject      *object,
+				      guint         prop_id,
+				      const GValue *value,
+				      GParamSpec   *pspec)
+{
+	EvTransitionAnimationPriv *priv;
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_PIXBUF_CACHE:
+		if (priv->pixbuf_cache)
+			g_object_unref (priv->pixbuf_cache);
+
+		priv->pixbuf_cache = g_value_dup_object (value);
+		break;
+	case PROP_EFFECT:
+		if (priv->effect)
+			g_object_unref (priv->effect);
+
+		priv->effect = g_value_dup_object (value);
+		break;
+	case PROP_PAGE_FROM:
+		priv->page_from = g_value_get_int (value);
+		break;
+	case PROP_PAGE_TO:
+		priv->page_to = g_value_get_int (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+ev_transition_animation_get_property (GObject      *object,
+				      guint         prop_id,
+				      GValue       *value,
+				      GParamSpec   *pspec)
+{
+	EvTransitionAnimationPriv *priv;
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_PIXBUF_CACHE:
+		g_value_set_object (value, priv->pixbuf_cache);
+		break;
+	case PROP_EFFECT:
+		g_value_set_object (value, priv->effect);
+		break;
+	case PROP_PAGE_FROM:
+		g_value_set_int (value, priv->page_from);
+		break;
+	case PROP_PAGE_TO:
+		g_value_set_int (value, priv->page_to);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+ev_transition_animation_finalize (GObject *object)
+{
+	EvTransitionAnimationPriv *priv;
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
+
+	if (priv->pixbuf_cache)
+		g_object_unref (priv->pixbuf_cache);
+
+	if (priv->effect)
+		g_object_unref (priv->effect);
+
+	G_OBJECT_CLASS (ev_transition_animation_parent_class)->finalize (object);
+}
+
+static GObject *
+ev_transition_animation_constructor (GType                  type,
+				     guint                  n_construct_properties,
+				     GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	EvTransitionAnimationPriv *priv;
+	EvTransitionEffect *effect;
+	gint duration;
+
+	object = G_OBJECT_CLASS (ev_transition_animation_parent_class)->constructor (type,
+										     n_construct_properties,
+										     construct_params);
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
+	effect = priv->effect;
+
+	g_object_get (effect, "duration", &duration, NULL);
+	ev_timeline_set_duration (EV_TIMELINE (object), duration * 1000);
+
+	return object;
+}
+
+static void
+ev_transition_animation_start (EvTimeline *timeline)
+{
+	EvTransitionAnimationPriv *priv;
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (timeline);
+
+	priv->origin_surface = ev_pixbuf_cache_get_surface (priv->pixbuf_cache, priv->page_from);
+	priv->dest_surface = ev_pixbuf_cache_get_surface (priv->pixbuf_cache, priv->page_to);
+
+	EV_TIMELINE_CLASS (ev_transition_animation_parent_class)->start (timeline);
+}
+
+static void
+ev_transition_animation_class_init (EvTransitionAnimationClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	EvTimelineClass *timeline_class = EV_TIMELINE_CLASS (klass);
+
+	object_class->set_property = ev_transition_animation_set_property;
+	object_class->get_property = ev_transition_animation_get_property;
+	object_class->finalize = ev_transition_animation_finalize;
+	object_class->constructor = ev_transition_animation_constructor;
+
+	timeline_class->start = ev_transition_animation_start;
+
+	g_object_class_install_property (object_class,
+					 PROP_PIXBUF_CACHE,
+					 g_param_spec_object ("pixbuf-cache",
+							      "Pixbuf cache",
+							      "Pixbuf cache to retrieve pages",
+							      EV_TYPE_PIXBUF_CACHE,
+							      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+	g_object_class_install_property (object_class,
+					 PROP_EFFECT,
+					 g_param_spec_object ("effect",
+							      "Effect",
+							      "Transition effect description",
+							      EV_TYPE_TRANSITION_EFFECT,
+							      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+	g_object_class_install_property (object_class,
+					 PROP_PAGE_FROM,
+					 g_param_spec_int ("page-from",
+							   "Page from",
+							   "Page from which the animation will happen",
+							   0, G_MAXINT, 0,
+							   G_PARAM_READWRITE));
+	g_object_class_install_property (object_class,
+					 PROP_PAGE_TO,
+					 g_param_spec_int ("page-to",
+							   "Page to",
+							   "Page to which the animation will happen",
+							   0, G_MAXINT, 0,
+							   G_PARAM_READWRITE));
+
+	g_type_class_add_private (klass, sizeof (EvTransitionAnimationPriv));
+}
+
+static void
+paint_surface (cairo_t         *cr,
+	       cairo_surface_t *surface,
+	       gdouble          x_offset,
+	       gdouble          y_offset,
+	       gdouble          alpha,
+	       GdkRectangle     page_area)
+{
+	gint width, height;
+
+	gdk_cairo_rectangle (cr, &page_area);
+	cairo_clip (cr);
+
+	width = cairo_image_surface_get_width (surface);
+	height = cairo_image_surface_get_height (surface);
+
+	cairo_save (cr);
+
+	if (width != page_area.width || height != page_area.height) {
+		cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
+		cairo_scale (cr,
+			     (gdouble) page_area.width / width,
+			     (gdouble) page_area.height / height);
+	}
+
+	cairo_surface_set_device_offset (surface, x_offset, y_offset);
+	cairo_set_source_surface (cr, surface, 0, 0);
+
+	if (alpha == 0.)
+		cairo_paint (cr);
+	else
+		cairo_paint_with_alpha (cr, alpha);
+
+	cairo_restore (cr);
+}
+
+void
+ev_transition_animation_paint (EvTransitionAnimation *animation,
+			       cairo_t               *cr,
+			       GdkRectangle           page_area)
+{
+	EvTransitionAnimationPriv *priv;
+	EvTransitionEffectType type;
+	gdouble progress;
+
+	g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+	g_object_get (priv->effect, "type", &type, NULL);
+	progress = ev_timeline_get_progress (EV_TIMELINE (animation));
+
+	priv->origin_surface = ev_pixbuf_cache_get_surface (priv->pixbuf_cache, priv->page_from);
+	priv->dest_surface = ev_pixbuf_cache_get_surface (priv->pixbuf_cache, priv->page_to);
+
+	if (!priv->origin_surface || !priv->dest_surface)
+		return;
+
+	switch (type) {
+	case EV_TRANSITION_EFFECT_REPLACE:
+		/* just paint the destination slide */
+		paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+		break;
+	default:
+		g_warning ("Transition animation not implemented");
+	}
+}
+
+EvTransitionAnimation *
+ev_transition_animation_new (EvPixbufCache      *pixbuf_cache,
+			     EvTransitionEffect *effect,
+			     gint                page_from,
+			     gint                page_to)
+{
+	g_return_val_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache), NULL);
+	g_return_val_if_fail (EV_IS_TRANSITION_EFFECT (effect), NULL);
+
+	return g_object_new (EV_TYPE_TRANSITION_ANIMATION,
+			     "pixbuf-cache", pixbuf_cache,
+			     "effect", effect,
+			     "page-from", page_from,
+			     "page-to", page_to,
+			     NULL);
+}
+
+gint
+ev_transition_animation_get_page_from (EvTransitionAnimation *animation)
+{
+	EvTransitionAnimationPriv *priv;
+
+	g_return_val_if_fail (EV_IS_TRANSITION_ANIMATION (animation), 0);
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+
+	return priv->page_from;
+}
+
+gint
+ev_transition_animation_get_page_to (EvTransitionAnimation *animation)
+{
+	EvTransitionAnimationPriv *priv;
+
+	g_return_val_if_fail (EV_IS_TRANSITION_ANIMATION (animation), 0);
+
+	priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+
+	return priv->page_to;
+}
diff --git a/shell/ev-transition-animation.h b/shell/ev-transition-animation.h
new file mode 100644
index 0000000..df0ca6e
--- /dev/null
+++ b/shell/ev-transition-animation.h
@@ -0,0 +1,66 @@
+/* ev-transition-animation.h
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EV_TRANSITION_ANIMATION_H__
+#define __EV_TRANSITION_ANIMATION_H__
+
+#include "ev-timeline.h"
+#include "ev-pixbuf-cache.h"
+#include "ev-transition-effect.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_TRANSITION_ANIMATION                 (ev_transition_animation_get_type ())
+#define EV_TRANSITION_ANIMATION(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimation))
+#define EV_TRANSITION_ANIMATION_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass),  EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimationClass))
+#define EV_IS_TRANSITION_ANIMATION(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_TRANSITION_ANIMATION))
+#define EV_IS_TRANSITION_ANIMATION_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass),  EV_TYPE_TRANSITION_ANIMATION))
+#define EV_TRANSITION_ANIMATION_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj),  EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimationClass))
+
+typedef struct EvTransitionAnimation      EvTransitionAnimation;
+typedef struct EvTransitionAnimationClass EvTransitionAnimationClass;
+
+struct EvTransitionAnimation {
+	EvTimeline parent_instance;
+};
+
+struct EvTransitionAnimationClass {
+	EvTimelineClass parent_class;
+};
+
+
+GType                   ev_transition_animation_get_type           (void) G_GNUC_CONST;
+
+EvTransitionAnimation * ev_transition_animation_new                (EvPixbufCache         *pixbuf_cache,
+								    EvTransitionEffect    *effect,
+								    gint                   page_from,
+								    gint                   page_to);
+
+gint                    ev_transition_animation_get_page_from      (EvTransitionAnimation *animation);
+gint                    ev_transition_animation_get_page_to        (EvTransitionAnimation *animation);
+
+void                    ev_transition_animation_paint              (EvTransitionAnimation *animation,
+								    cairo_t               *cr,
+								    GdkRectangle           page_area);
+
+G_END_DECLS
+
+#endif /* __EV_TRANSITION_ANIMATION_H__ */
