Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/libview/ev-transition-animation.c
diff options
context:
space:
mode:
authorCarlos Garcia Campos <carlosgc@gnome.org>2009-01-18 11:53:54 (GMT)
committer Carlos Garcia Campos <carlosgc@src.gnome.org>2009-01-18 11:53:54 (GMT)
commit68d0fc3c59185065d9694ba3f8cb2665b984eb9f (patch)
tree1c3495114d26e1b9d201c557c351d5cf3996f925 /libview/ev-transition-animation.c
parent51e1ae36121928f84940b8e8dcb317f87157933b (diff)
Move EvView specific code to a libeviview library so that it can be
2009-01-18 Carlos Garcia Campos <carlosgc@gnome.org> * configure.ac: * Makefile.am: * libdocument/Makefile.am: * libview/Makefile.am: * libview/ev-job-scheduler.[ch]: * libview/ev-jobs.[ch]: * libview/ev-page-cache.[ch]: * libview/ev-pixbuf-cache.[ch]: * libview/ev-timeline.[ch]: * libview/ev-transition-animation.[ch]: * libview/ev-view-accessible.[ch]: * libview/ev-view-marshal.list: * libview/ev-view.[ch]: * shell/Makefile.am: Move EvView specific code to a libeviview library so that it can be embbeded in other applications. Based on patches by Tomeu Vizoso. Fixes bug #567751. svn path=/trunk/; revision=3348
Diffstat (limited to 'libview/ev-transition-animation.c')
-rw-r--r--libview/ev-transition-animation.c682
1 files changed, 682 insertions, 0 deletions
diff --git a/libview/ev-transition-animation.c b/libview/ev-transition-animation.c
new file mode 100644
index 0000000..148b4c7
--- /dev/null
+++ b/libview/ev-transition-animation.c
@@ -0,0 +1,682 @@
+/* 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 {
+ EvTransitionEffect *effect;
+ cairo_surface_t *origin_surface;
+ cairo_surface_t *dest_surface;
+};
+
+enum {
+ PROP_0,
+ PROP_EFFECT,
+ PROP_ORIGIN_SURFACE,
+ PROP_DEST_SURFACE
+};
+
+
+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_EFFECT:
+ if (priv->effect)
+ g_object_unref (priv->effect);
+
+ priv->effect = g_value_dup_object (value);
+ break;
+ case PROP_ORIGIN_SURFACE:
+ ev_transition_animation_set_origin_surface (EV_TRANSITION_ANIMATION (object),
+ g_value_get_pointer (value));
+ break;
+ case PROP_DEST_SURFACE:
+ ev_transition_animation_set_dest_surface (EV_TRANSITION_ANIMATION (object),
+ g_value_get_pointer (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_EFFECT:
+ g_value_set_object (value, priv->effect);
+ break;
+ case PROP_ORIGIN_SURFACE:
+ g_value_set_pointer (value, priv->origin_surface);
+ break;
+ case PROP_DEST_SURFACE:
+ g_value_set_pointer (value, priv->dest_surface);
+ 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->effect)
+ g_object_unref (priv->effect);
+
+ if (priv->origin_surface)
+ cairo_surface_destroy (priv->origin_surface);
+
+ if (priv->dest_surface)
+ cairo_surface_destroy (priv->dest_surface);
+
+ 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_class_init (EvTransitionAnimationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_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;
+
+ 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_ORIGIN_SURFACE,
+ g_param_spec_pointer ("origin-surface",
+ "Origin surface",
+ "Cairo surface from which the animation will happen",
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_DEST_SURFACE,
+ g_param_spec_pointer ("dest-surface",
+ "Destination surface",
+ "Cairo surface to which the animation will happen",
+ 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);
+}
+
+/* animations */
+static void
+ev_transition_animation_split (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+ EvTransitionEffectAlignment alignment;
+ EvTransitionEffectDirection direction;
+ gint width, height;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+ width = page_area.width;
+ height = page_area.height;
+
+ g_object_get (effect,
+ "alignment", &alignment,
+ "direction", &direction,
+ NULL);
+
+ if (direction == EV_TRANSITION_DIRECTION_INWARD) {
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+
+ if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) {
+ cairo_rectangle (cr,
+ 0,
+ height * progress / 2,
+ width,
+ height * (1 - progress));
+ } else {
+ cairo_rectangle (cr,
+ width * progress / 2,
+ 0,
+ width * (1 - progress),
+ height);
+ }
+
+ cairo_clip (cr);
+
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+ } else {
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+
+ if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) {
+ cairo_rectangle (cr,
+ 0,
+ (height / 2) - (height * progress / 2),
+ width,
+ height * progress);
+ } else {
+ cairo_rectangle (cr,
+ (width / 2) - (width * progress / 2),
+ 0,
+ width * progress,
+ height);
+ }
+
+ cairo_clip (cr);
+
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+ }
+}
+
+static void
+ev_transition_animation_blinds (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+ EvTransitionEffectAlignment alignment;
+ gint width, height, i;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+ width = page_area.width;
+ height = page_area.height;
+
+ g_object_get (effect,
+ "alignment", &alignment,
+ NULL);
+
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+
+ for (i = 0; i < N_BLINDS; i++) {
+ cairo_save (cr);
+
+ if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) {
+ cairo_rectangle (cr,
+ 0,
+ height / N_BLINDS * i,
+ width,
+ height / N_BLINDS * progress);
+ } else {
+ cairo_rectangle (cr,
+ width / N_BLINDS * i,
+ 0,
+ width / N_BLINDS * progress,
+ height);
+ }
+
+ cairo_clip (cr);
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+ cairo_restore (cr);
+ }
+}
+
+static void
+ev_transition_animation_box (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+ EvTransitionEffectDirection direction;
+ gint width, height;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+ width = page_area.width;
+ height = page_area.height;
+
+ g_object_get (effect,
+ "direction", &direction,
+ NULL);
+
+ if (direction == EV_TRANSITION_DIRECTION_INWARD) {
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+
+ cairo_rectangle (cr,
+ width * progress / 2,
+ height * progress / 2,
+ width * (1 - progress),
+ height * (1 - progress));
+ cairo_clip (cr);
+
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+ } else {
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+
+ cairo_rectangle (cr,
+ (width / 2) - (width * progress / 2),
+ (height / 2) - (height * progress / 2),
+ width * progress,
+ height * progress);
+ cairo_clip (cr);
+
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+ }
+}
+
+static void
+ev_transition_animation_wipe (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+ gint width, height;
+ gint angle;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+ width = page_area.width;
+ height = page_area.height;
+
+ g_object_get (effect,
+ "angle", &angle,
+ NULL);
+
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+
+ if (angle == 0) {
+ /* left to right */
+ cairo_rectangle (cr,
+ 0, 0,
+ width * progress,
+ height);
+ } else if (angle <= 90) {
+ /* bottom to top */
+ cairo_rectangle (cr,
+ 0,
+ height * (1 - progress),
+ width,
+ height * progress);
+ } else if (angle <= 180) {
+ /* right to left */
+ cairo_rectangle (cr,
+ width * (1 - progress),
+ 0,
+ width * progress,
+ height);
+ } else if (angle <= 270) {
+ /* top to bottom */
+ cairo_rectangle (cr,
+ 0, 0,
+ width,
+ height * progress);
+ }
+
+ cairo_clip (cr);
+
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+}
+
+static void
+ev_transition_animation_dissolve (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+ paint_surface (cr, priv->origin_surface, 0, 0, 1 - progress, page_area);
+}
+
+static void
+ev_transition_animation_push (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+ gint width, height;
+ gint angle;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+ width = page_area.width;
+ height = page_area.height;
+
+ g_object_get (effect,
+ "angle", &angle,
+ NULL);
+
+ if (angle == 0) {
+ /* left to right */
+ paint_surface (cr, priv->origin_surface, - (width * progress), 0, 0, page_area);
+ paint_surface (cr, priv->dest_surface, width * (1 - progress), 0, 0, page_area);
+ } else {
+ /* top to bottom */
+ paint_surface (cr, priv->origin_surface, 0, - (height * progress), 0, page_area);
+ paint_surface (cr, priv->dest_surface, 0, height * (1 - progress), 0, page_area);
+ }
+}
+
+static void
+ev_transition_animation_cover (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+ gint width, height;
+ gint angle;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+ width = page_area.width;
+ height = page_area.height;
+
+ g_object_get (effect,
+ "angle", &angle,
+ NULL);
+
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+
+ if (angle == 0) {
+ /* left to right */
+ paint_surface (cr, priv->dest_surface, width * (1 - progress), 0, 0, page_area);
+ } else {
+ /* top to bottom */
+ paint_surface (cr, priv->dest_surface, 0, height * (1 - progress), 0, page_area);
+ }
+}
+
+static void
+ev_transition_animation_uncover (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+ gint width, height;
+ gint angle;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+ width = page_area.width;
+ height = page_area.height;
+
+ g_object_get (effect,
+ "angle", &angle,
+ NULL);
+
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+
+ if (angle == 0) {
+ /* left to right */
+ paint_surface (cr, priv->origin_surface, - (width * progress), 0, 0, page_area);
+ } else {
+ /* top to bottom */
+ paint_surface (cr, priv->origin_surface, 0, - (height * progress), 0, page_area);
+ }
+}
+
+static void
+ev_transition_animation_fade (cairo_t *cr,
+ EvTransitionAnimation *animation,
+ EvTransitionEffect *effect,
+ gdouble progress,
+ GdkRectangle page_area)
+{
+ EvTransitionAnimationPriv *priv;
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+ paint_surface (cr, priv->dest_surface, 0, 0, progress, page_area);
+}
+
+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));
+
+ if (!priv->dest_surface) {
+ /* animation is still not ready, paint the origin surface */
+ paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
+ 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;
+ case EV_TRANSITION_EFFECT_SPLIT:
+ ev_transition_animation_split (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_BLINDS:
+ ev_transition_animation_blinds (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_BOX:
+ ev_transition_animation_box (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_WIPE:
+ ev_transition_animation_wipe (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_DISSOLVE:
+ ev_transition_animation_dissolve (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_PUSH:
+ ev_transition_animation_push (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_COVER:
+ ev_transition_animation_cover (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_UNCOVER:
+ ev_transition_animation_uncover (cr, animation, priv->effect, progress, page_area);
+ break;
+ case EV_TRANSITION_EFFECT_FADE:
+ ev_transition_animation_fade (cr, animation, priv->effect, progress, page_area);
+ break;
+ default: {
+ GEnumValue *enum_value;
+
+ enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_TRANSITION_EFFECT_TYPE), type);
+
+ g_warning ("Unimplemented transition animation: '%s', "
+ "please post a bug report in Evince bugzilla "
+ "(http://bugzilla.gnome.org) with a testcase.",
+ enum_value->value_nick);
+
+ /* just paint the destination slide */
+ paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
+ }
+ }
+}
+
+EvTransitionAnimation *
+ev_transition_animation_new (EvTransitionEffect *effect)
+{
+ g_return_val_if_fail (EV_IS_TRANSITION_EFFECT (effect), NULL);
+
+ return g_object_new (EV_TYPE_TRANSITION_ANIMATION,
+ "effect", effect,
+ NULL);
+}
+
+void
+ev_transition_animation_set_origin_surface (EvTransitionAnimation *animation,
+ cairo_surface_t *origin_surface)
+{
+ EvTransitionAnimationPriv *priv;
+ cairo_surface_t *surface;
+
+ g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+
+ surface = cairo_surface_reference (origin_surface);
+
+ if (priv->origin_surface)
+ cairo_surface_destroy (priv->origin_surface);
+
+ priv->origin_surface = surface;
+ g_object_notify (G_OBJECT (animation), "origin-surface");
+
+ if (priv->origin_surface && priv->dest_surface)
+ ev_timeline_start (EV_TIMELINE (animation));
+}
+
+void
+ev_transition_animation_set_dest_surface (EvTransitionAnimation *animation,
+ cairo_surface_t *dest_surface)
+{
+ EvTransitionAnimationPriv *priv;
+ cairo_surface_t *surface;
+
+ g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+
+ surface = cairo_surface_reference (dest_surface);
+
+ if (priv->dest_surface)
+ cairo_surface_destroy (priv->dest_surface);
+
+ priv->dest_surface = surface;
+ g_object_notify (G_OBJECT (animation), "dest-surface");
+
+ if (priv->origin_surface && priv->dest_surface)
+ ev_timeline_start (EV_TIMELINE (animation));
+}
+
+gboolean
+ev_transition_animation_ready (EvTransitionAnimation *animation)
+{
+ EvTransitionAnimationPriv *priv;
+
+ g_return_val_if_fail (EV_IS_TRANSITION_ANIMATION (animation), FALSE);
+
+ priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
+
+ return (priv->origin_surface && priv->dest_surface);
+}