1
/* ev-transition-animation.c
2
* this file is part of evince, a gnome document viewer
4
* Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Library General Public
8
* License as published by the Free Software Foundation; either
9
* version 2 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Library General Public License for more details.
16
* You should have received a copy of the GNU Library General Public
17
* License along with this library; if not, write to the
18
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
* Boston, MA 02111-1307, USA.
24
#include "ev-transition-animation.h"
25
#include "ev-timeline.h"
27
#define EV_TRANSITION_ANIMATION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimationPriv))
30
typedef struct EvTransitionAnimationPriv EvTransitionAnimationPriv;
32
struct EvTransitionAnimationPriv {
33
EvTransitionEffect *effect;
34
cairo_surface_t *origin_surface;
35
cairo_surface_t *dest_surface;
46
G_DEFINE_TYPE (EvTransitionAnimation, ev_transition_animation, EV_TYPE_TIMELINE)
50
ev_transition_animation_init (EvTransitionAnimation *animation)
55
ev_transition_animation_set_property (GObject *object,
60
EvTransitionAnimationPriv *priv;
62
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
67
g_object_unref (priv->effect);
69
priv->effect = g_value_dup_object (value);
71
case PROP_ORIGIN_SURFACE:
72
ev_transition_animation_set_origin_surface (EV_TRANSITION_ANIMATION (object),
73
g_value_get_pointer (value));
75
case PROP_DEST_SURFACE:
76
ev_transition_animation_set_dest_surface (EV_TRANSITION_ANIMATION (object),
77
g_value_get_pointer (value));
80
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
85
ev_transition_animation_get_property (GObject *object,
90
EvTransitionAnimationPriv *priv;
92
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
96
g_value_set_object (value, priv->effect);
98
case PROP_ORIGIN_SURFACE:
99
g_value_set_pointer (value, priv->origin_surface);
101
case PROP_DEST_SURFACE:
102
g_value_set_pointer (value, priv->dest_surface);
105
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
110
ev_transition_animation_finalize (GObject *object)
112
EvTransitionAnimationPriv *priv;
114
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
117
g_object_unref (priv->effect);
119
if (priv->origin_surface)
120
cairo_surface_destroy (priv->origin_surface);
122
if (priv->dest_surface)
123
cairo_surface_destroy (priv->dest_surface);
125
G_OBJECT_CLASS (ev_transition_animation_parent_class)->finalize (object);
129
ev_transition_animation_constructor (GType type,
130
guint n_construct_properties,
131
GObjectConstructParam *construct_params)
134
EvTransitionAnimationPriv *priv;
135
EvTransitionEffect *effect;
138
object = G_OBJECT_CLASS (ev_transition_animation_parent_class)->constructor (type,
139
n_construct_properties,
142
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (object);
143
effect = priv->effect;
145
g_object_get (effect, "duration", &duration, NULL);
146
ev_timeline_set_duration (EV_TIMELINE (object), duration * 1000);
152
ev_transition_animation_class_init (EvTransitionAnimationClass *klass)
154
GObjectClass *object_class = G_OBJECT_CLASS (klass);
156
object_class->set_property = ev_transition_animation_set_property;
157
object_class->get_property = ev_transition_animation_get_property;
158
object_class->finalize = ev_transition_animation_finalize;
159
object_class->constructor = ev_transition_animation_constructor;
161
g_object_class_install_property (object_class,
163
g_param_spec_object ("effect",
165
"Transition effect description",
166
EV_TYPE_TRANSITION_EFFECT,
167
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
168
g_object_class_install_property (object_class,
170
g_param_spec_pointer ("origin-surface",
172
"Cairo surface from which the animation will happen",
174
g_object_class_install_property (object_class,
176
g_param_spec_pointer ("dest-surface",
177
"Destination surface",
178
"Cairo surface to which the animation will happen",
181
g_type_class_add_private (klass, sizeof (EvTransitionAnimationPriv));
185
paint_surface (cairo_t *cr,
186
cairo_surface_t *surface,
190
GdkRectangle page_area)
194
gdk_cairo_rectangle (cr, &page_area);
197
width = cairo_image_surface_get_width (surface);
198
height = cairo_image_surface_get_height (surface);
202
if (width != page_area.width || height != page_area.height) {
203
cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
205
(gdouble) page_area.width / width,
206
(gdouble) page_area.height / height);
209
cairo_surface_set_device_offset (surface, x_offset, y_offset);
210
cairo_set_source_surface (cr, surface, 0, 0);
215
cairo_paint_with_alpha (cr, alpha);
222
ev_transition_animation_split (cairo_t *cr,
223
EvTransitionAnimation *animation,
224
EvTransitionEffect *effect,
226
GdkRectangle page_area)
228
EvTransitionAnimationPriv *priv;
229
EvTransitionEffectAlignment alignment;
230
EvTransitionEffectDirection direction;
233
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
234
width = page_area.width;
235
height = page_area.height;
237
g_object_get (effect,
238
"alignment", &alignment,
239
"direction", &direction,
242
if (direction == EV_TRANSITION_DIRECTION_INWARD) {
243
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
245
if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) {
248
height * progress / 2,
250
height * (1 - progress));
253
width * progress / 2,
255
width * (1 - progress),
261
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
263
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
265
if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) {
268
(height / 2) - (height * progress / 2),
273
(width / 2) - (width * progress / 2),
281
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
286
ev_transition_animation_blinds (cairo_t *cr,
287
EvTransitionAnimation *animation,
288
EvTransitionEffect *effect,
290
GdkRectangle page_area)
292
EvTransitionAnimationPriv *priv;
293
EvTransitionEffectAlignment alignment;
294
gint width, height, i;
296
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
297
width = page_area.width;
298
height = page_area.height;
300
g_object_get (effect,
301
"alignment", &alignment,
304
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
306
for (i = 0; i < N_BLINDS; i++) {
309
if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) {
312
height / N_BLINDS * i,
314
height / N_BLINDS * progress);
317
width / N_BLINDS * i,
319
width / N_BLINDS * progress,
324
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
330
ev_transition_animation_box (cairo_t *cr,
331
EvTransitionAnimation *animation,
332
EvTransitionEffect *effect,
334
GdkRectangle page_area)
336
EvTransitionAnimationPriv *priv;
337
EvTransitionEffectDirection direction;
340
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
341
width = page_area.width;
342
height = page_area.height;
344
g_object_get (effect,
345
"direction", &direction,
348
if (direction == EV_TRANSITION_DIRECTION_INWARD) {
349
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
352
width * progress / 2,
353
height * progress / 2,
354
width * (1 - progress),
355
height * (1 - progress));
358
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
360
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
363
(width / 2) - (width * progress / 2),
364
(height / 2) - (height * progress / 2),
369
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
374
ev_transition_animation_wipe (cairo_t *cr,
375
EvTransitionAnimation *animation,
376
EvTransitionEffect *effect,
378
GdkRectangle page_area)
380
EvTransitionAnimationPriv *priv;
384
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
385
width = page_area.width;
386
height = page_area.height;
388
g_object_get (effect,
392
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
400
} else if (angle <= 90) {
404
height * (1 - progress),
407
} else if (angle <= 180) {
410
width * (1 - progress),
414
} else if (angle <= 270) {
424
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
428
ev_transition_animation_dissolve (cairo_t *cr,
429
EvTransitionAnimation *animation,
430
EvTransitionEffect *effect,
432
GdkRectangle page_area)
434
EvTransitionAnimationPriv *priv;
436
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
438
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
439
paint_surface (cr, priv->origin_surface, 0, 0, 1 - progress, page_area);
443
ev_transition_animation_push (cairo_t *cr,
444
EvTransitionAnimation *animation,
445
EvTransitionEffect *effect,
447
GdkRectangle page_area)
449
EvTransitionAnimationPriv *priv;
453
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
454
width = page_area.width;
455
height = page_area.height;
457
g_object_get (effect,
463
paint_surface (cr, priv->origin_surface, - (width * progress), 0, 0, page_area);
464
paint_surface (cr, priv->dest_surface, width * (1 - progress), 0, 0, page_area);
467
paint_surface (cr, priv->origin_surface, 0, - (height * progress), 0, page_area);
468
paint_surface (cr, priv->dest_surface, 0, height * (1 - progress), 0, page_area);
473
ev_transition_animation_cover (cairo_t *cr,
474
EvTransitionAnimation *animation,
475
EvTransitionEffect *effect,
477
GdkRectangle page_area)
479
EvTransitionAnimationPriv *priv;
483
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
484
width = page_area.width;
485
height = page_area.height;
487
g_object_get (effect,
491
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
495
paint_surface (cr, priv->dest_surface, width * (1 - progress), 0, 0, page_area);
498
paint_surface (cr, priv->dest_surface, 0, height * (1 - progress), 0, page_area);
503
ev_transition_animation_uncover (cairo_t *cr,
504
EvTransitionAnimation *animation,
505
EvTransitionEffect *effect,
507
GdkRectangle page_area)
509
EvTransitionAnimationPriv *priv;
513
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
514
width = page_area.width;
515
height = page_area.height;
517
g_object_get (effect,
521
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
525
paint_surface (cr, priv->origin_surface, - (width * progress), 0, 0, page_area);
528
paint_surface (cr, priv->origin_surface, 0, - (height * progress), 0, page_area);
533
ev_transition_animation_fade (cairo_t *cr,
534
EvTransitionAnimation *animation,
535
EvTransitionEffect *effect,
537
GdkRectangle page_area)
539
EvTransitionAnimationPriv *priv;
541
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
543
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
544
paint_surface (cr, priv->dest_surface, 0, 0, progress, page_area);
548
ev_transition_animation_paint (EvTransitionAnimation *animation,
550
GdkRectangle page_area)
552
EvTransitionAnimationPriv *priv;
553
EvTransitionEffectType type;
556
g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
558
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
559
g_object_get (priv->effect, "type", &type, NULL);
560
progress = ev_timeline_get_progress (EV_TIMELINE (animation));
562
if (!priv->dest_surface) {
563
/* animation is still not ready, paint the origin surface */
564
paint_surface (cr, priv->origin_surface, 0, 0, 0, page_area);
569
case EV_TRANSITION_EFFECT_REPLACE:
570
/* just paint the destination slide */
571
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
573
case EV_TRANSITION_EFFECT_SPLIT:
574
ev_transition_animation_split (cr, animation, priv->effect, progress, page_area);
576
case EV_TRANSITION_EFFECT_BLINDS:
577
ev_transition_animation_blinds (cr, animation, priv->effect, progress, page_area);
579
case EV_TRANSITION_EFFECT_BOX:
580
ev_transition_animation_box (cr, animation, priv->effect, progress, page_area);
582
case EV_TRANSITION_EFFECT_WIPE:
583
ev_transition_animation_wipe (cr, animation, priv->effect, progress, page_area);
585
case EV_TRANSITION_EFFECT_DISSOLVE:
586
ev_transition_animation_dissolve (cr, animation, priv->effect, progress, page_area);
588
case EV_TRANSITION_EFFECT_PUSH:
589
ev_transition_animation_push (cr, animation, priv->effect, progress, page_area);
591
case EV_TRANSITION_EFFECT_COVER:
592
ev_transition_animation_cover (cr, animation, priv->effect, progress, page_area);
594
case EV_TRANSITION_EFFECT_UNCOVER:
595
ev_transition_animation_uncover (cr, animation, priv->effect, progress, page_area);
597
case EV_TRANSITION_EFFECT_FADE:
598
ev_transition_animation_fade (cr, animation, priv->effect, progress, page_area);
601
GEnumValue *enum_value;
603
enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_TRANSITION_EFFECT_TYPE), type);
605
g_warning ("Unimplemented transition animation: '%s', "
606
"please post a bug report in Evince bugzilla "
607
"(http://bugzilla.gnome.org) with a testcase.",
608
enum_value->value_nick);
610
/* just paint the destination slide */
611
paint_surface (cr, priv->dest_surface, 0, 0, 0, page_area);
616
EvTransitionAnimation *
617
ev_transition_animation_new (EvTransitionEffect *effect)
619
g_return_val_if_fail (EV_IS_TRANSITION_EFFECT (effect), NULL);
621
return g_object_new (EV_TYPE_TRANSITION_ANIMATION,
627
ev_transition_animation_set_origin_surface (EvTransitionAnimation *animation,
628
cairo_surface_t *origin_surface)
630
EvTransitionAnimationPriv *priv;
631
cairo_surface_t *surface;
633
g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
635
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
637
surface = cairo_surface_reference (origin_surface);
639
if (priv->origin_surface)
640
cairo_surface_destroy (priv->origin_surface);
642
priv->origin_surface = surface;
643
g_object_notify (G_OBJECT (animation), "origin-surface");
645
if (priv->origin_surface && priv->dest_surface)
646
ev_timeline_start (EV_TIMELINE (animation));
650
ev_transition_animation_set_dest_surface (EvTransitionAnimation *animation,
651
cairo_surface_t *dest_surface)
653
EvTransitionAnimationPriv *priv;
654
cairo_surface_t *surface;
656
g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation));
658
priv = EV_TRANSITION_ANIMATION_GET_PRIVATE (animation);
660
surface = cairo_surface_reference (dest_surface);
662
if (priv->dest_surface)
663
cairo_surface_destroy (priv->dest_surface);
665
priv->dest_surface = surface;
666
g_object_notify (G_OBJECT (animation), "dest-surface");
668
if (priv->origin_surface && priv->dest_surface)
669
ev_timeline_start (EV_TIMELINE (animation));