summaryrefslogtreecommitdiff
path: root/slideshow/source/engine
diff options
context:
space:
mode:
Diffstat (limited to 'slideshow/source/engine')
-rw-r--r--slideshow/source/engine/OGLTrans/exports.dxp2
-rw-r--r--slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.h94
-rw-r--r--slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.m231
-rw-r--r--slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.hxx497
-rw-r--r--slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.mm1326
-rw-r--r--slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionerImpl.mm1132
-rw-r--r--slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.h39
-rw-r--r--slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.m195
-rw-r--r--slideshow/source/engine/OGLTrans/mac/makefile.mk87
-rw-r--r--slideshow/source/engine/OGLTrans/ogltrans.component34
-rw-r--r--slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.cxx142
-rw-r--r--slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.hxx71
-rw-r--r--slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.cxx1312
-rw-r--r--slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.hxx497
-rw-r--r--slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionerImpl.cxx1484
-rw-r--r--slideshow/source/engine/OGLTrans/unx/makefile.mk73
-rw-r--r--slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.cxx142
-rw-r--r--slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.hxx71
-rw-r--r--slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.cxx1315
-rw-r--r--slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.hxx507
-rw-r--r--slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionerImpl.cxx1455
-rw-r--r--slideshow/source/engine/OGLTrans/win/makefile.mk80
-rw-r--r--slideshow/source/engine/activities/accumulation.hxx95
-rw-r--r--slideshow/source/engine/activities/activitiesfactory.cxx988
-rw-r--r--slideshow/source/engine/activities/activitybase.cxx249
-rw-r--r--slideshow/source/engine/activities/activitybase.hxx154
-rw-r--r--slideshow/source/engine/activities/activityparameters.hxx145
-rw-r--r--slideshow/source/engine/activities/continuousactivitybase.cxx57
-rw-r--r--slideshow/source/engine/activities/continuousactivitybase.hxx76
-rw-r--r--slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx79
-rw-r--r--slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx86
-rw-r--r--slideshow/source/engine/activities/discreteactivitybase.cxx209
-rw-r--r--slideshow/source/engine/activities/discreteactivitybase.hxx90
-rw-r--r--slideshow/source/engine/activities/interpolation.hxx194
-rw-r--r--slideshow/source/engine/activities/makefile.mk53
-rw-r--r--slideshow/source/engine/activities/simplecontinuousactivitybase.cxx261
-rw-r--r--slideshow/source/engine/activities/simplecontinuousactivitybase.hxx90
-rw-r--r--slideshow/source/engine/activitiesqueue.cxx212
-rw-r--r--slideshow/source/engine/animatedsprite.cxx228
-rw-r--r--slideshow/source/engine/animationfactory.cxx1396
-rw-r--r--slideshow/source/engine/animationnodes/animationaudionode.cxx183
-rw-r--r--slideshow/source/engine/animationnodes/animationaudionode.hxx80
-rw-r--r--slideshow/source/engine/animationnodes/animationbasenode.cxx492
-rw-r--r--slideshow/source/engine/animationnodes/animationbasenode.hxx113
-rw-r--r--slideshow/source/engine/animationnodes/animationcolornode.cxx139
-rw-r--r--slideshow/source/engine/animationnodes/animationcolornode.hxx65
-rw-r--r--slideshow/source/engine/animationnodes/animationcommandnode.cxx137
-rw-r--r--slideshow/source/engine/animationnodes/animationcommandnode.hxx72
-rw-r--r--slideshow/source/engine/animationnodes/animationnodefactory.cxx621
-rw-r--r--slideshow/source/engine/animationnodes/animationpathmotionnode.cxx69
-rw-r--r--slideshow/source/engine/animationnodes/animationpathmotionnode.hxx68
-rw-r--r--slideshow/source/engine/animationnodes/animationsetnode.cxx215
-rw-r--r--slideshow/source/engine/animationnodes/animationsetnode.hxx60
-rw-r--r--slideshow/source/engine/animationnodes/animationtransformnode.cxx117
-rw-r--r--slideshow/source/engine/animationnodes/animationtransformnode.hxx69
-rw-r--r--slideshow/source/engine/animationnodes/animationtransitionfilternode.cxx62
-rw-r--r--slideshow/source/engine/animationnodes/animationtransitionfilternode.hxx70
-rw-r--r--slideshow/source/engine/animationnodes/basecontainernode.cxx177
-rw-r--r--slideshow/source/engine/animationnodes/basecontainernode.hxx107
-rw-r--r--slideshow/source/engine/animationnodes/basenode.cxx771
-rw-r--r--slideshow/source/engine/animationnodes/basenode.hxx231
-rw-r--r--slideshow/source/engine/animationnodes/generateevent.cxx248
-rw-r--r--slideshow/source/engine/animationnodes/generateevent.hxx64
-rw-r--r--slideshow/source/engine/animationnodes/makefile.mk61
-rw-r--r--slideshow/source/engine/animationnodes/nodetools.cxx131
-rw-r--r--slideshow/source/engine/animationnodes/nodetools.hxx91
-rw-r--r--slideshow/source/engine/animationnodes/paralleltimecontainer.cxx71
-rw-r--r--slideshow/source/engine/animationnodes/paralleltimecontainer.hxx65
-rw-r--r--slideshow/source/engine/animationnodes/propertyanimationnode.cxx117
-rw-r--r--slideshow/source/engine/animationnodes/propertyanimationnode.hxx60
-rw-r--r--slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx164
-rw-r--r--slideshow/source/engine/animationnodes/sequentialtimecontainer.hxx77
-rw-r--r--slideshow/source/engine/animationnodes/setactivity.hxx158
-rw-r--r--slideshow/source/engine/arith-grammar.txt61
-rw-r--r--slideshow/source/engine/attributemap.cxx105
-rw-r--r--slideshow/source/engine/color.cxx390
-rw-r--r--slideshow/source/engine/debug.cxx327
-rw-r--r--slideshow/source/engine/delayevent.cxx71
-rw-r--r--slideshow/source/engine/effectrewinder.cxx436
-rw-r--r--slideshow/source/engine/effectrewinder.hxx185
-rw-r--r--slideshow/source/engine/eventmultiplexer.cxx1280
-rw-r--r--slideshow/source/engine/eventqueue.cxx337
-rw-r--r--slideshow/source/engine/expressionnodefactory.cxx282
-rw-r--r--slideshow/source/engine/makefile.mk98
-rw-r--r--slideshow/source/engine/rehearsetimingsactivity.cxx585
-rw-r--r--slideshow/source/engine/rehearsetimingsactivity.hxx150
-rw-r--r--slideshow/source/engine/screenupdater.cxx271
-rw-r--r--slideshow/source/engine/shapeattributelayer.cxx859
-rw-r--r--slideshow/source/engine/shapes/appletshape.cxx333
-rw-r--r--slideshow/source/engine/shapes/appletshape.hxx63
-rw-r--r--slideshow/source/engine/shapes/backgroundshape.cxx339
-rw-r--r--slideshow/source/engine/shapes/backgroundshape.hxx65
-rw-r--r--slideshow/source/engine/shapes/drawinglayeranimation.cxx983
-rw-r--r--slideshow/source/engine/shapes/drawinglayeranimation.hxx50
-rw-r--r--slideshow/source/engine/shapes/drawshape.cxx1481
-rw-r--r--slideshow/source/engine/shapes/drawshape.hxx385
-rw-r--r--slideshow/source/engine/shapes/drawshapesubsetting.cxx867
-rw-r--r--slideshow/source/engine/shapes/drawshapesubsetting.hxx291
-rw-r--r--slideshow/source/engine/shapes/externalshapebase.cxx249
-rw-r--r--slideshow/source/engine/shapes/externalshapebase.hxx148
-rw-r--r--slideshow/source/engine/shapes/gdimtftools.cxx551
-rw-r--r--slideshow/source/engine/shapes/gdimtftools.hxx158
-rw-r--r--slideshow/source/engine/shapes/intrinsicanimationactivity.cxx293
-rw-r--r--slideshow/source/engine/shapes/intrinsicanimationactivity.hxx79
-rw-r--r--slideshow/source/engine/shapes/makefile.mk60
-rw-r--r--slideshow/source/engine/shapes/mediashape.cxx300
-rw-r--r--slideshow/source/engine/shapes/mediashape.hxx58
-rw-r--r--slideshow/source/engine/shapes/shapeimporter.cxx672
-rw-r--r--slideshow/source/engine/shapes/viewappletshape.cxx303
-rw-r--r--slideshow/source/engine/shapes/viewappletshape.hxx172
-rw-r--r--slideshow/source/engine/shapes/viewbackgroundshape.cxx214
-rw-r--r--slideshow/source/engine/shapes/viewbackgroundshape.hxx107
-rw-r--r--slideshow/source/engine/shapes/viewmediashape.cxx551
-rw-r--r--slideshow/source/engine/shapes/viewmediashape.hxx177
-rw-r--r--slideshow/source/engine/shapes/viewshape.cxx901
-rw-r--r--slideshow/source/engine/shapes/viewshape.hxx343
-rw-r--r--slideshow/source/engine/shapesubset.cxx144
-rw-r--r--slideshow/source/engine/slide/layer.cxx367
-rw-r--r--slideshow/source/engine/slide/layer.hxx319
-rw-r--r--slideshow/source/engine/slide/layermanager.cxx923
-rw-r--r--slideshow/source/engine/slide/layermanager.hxx388
-rw-r--r--slideshow/source/engine/slide/makefile.mk51
-rw-r--r--slideshow/source/engine/slide/shapemanagerimpl.cxx466
-rw-r--r--slideshow/source/engine/slide/shapemanagerimpl.hxx212
-rw-r--r--slideshow/source/engine/slide/slideanimations.cxx134
-rw-r--r--slideshow/source/engine/slide/slideanimations.hxx128
-rw-r--r--slideshow/source/engine/slide/slideimpl.cxx1284
-rw-r--r--slideshow/source/engine/slide/userpaintoverlay.cxx562
-rw-r--r--slideshow/source/engine/slide/userpaintoverlay.hxx97
-rw-r--r--slideshow/source/engine/slidebitmap.cxx134
-rw-r--r--slideshow/source/engine/slideshowcontext.cxx79
-rw-r--r--slideshow/source/engine/slideshowimpl.cxx2465
-rw-r--r--slideshow/source/engine/slideview.cxx1194
-rw-r--r--slideshow/source/engine/smilfunctionparser.cxx640
-rw-r--r--slideshow/source/engine/soundplayer.cxx186
-rw-r--r--slideshow/source/engine/sp_debug.cxx300
-rw-r--r--slideshow/source/engine/tools.cxx839
-rw-r--r--slideshow/source/engine/transitions/barndoorwipe.cxx68
-rw-r--r--slideshow/source/engine/transitions/barndoorwipe.hxx58
-rw-r--r--slideshow/source/engine/transitions/barwipepolypolygon.cxx59
-rw-r--r--slideshow/source/engine/transitions/barwipepolypolygon.hxx58
-rw-r--r--slideshow/source/engine/transitions/boxwipe.cxx60
-rw-r--r--slideshow/source/engine/transitions/boxwipe.hxx57
-rw-r--r--slideshow/source/engine/transitions/checkerboardwipe.cxx68
-rw-r--r--slideshow/source/engine/transitions/checkerboardwipe.hxx60
-rw-r--r--slideshow/source/engine/transitions/clippingfunctor.cxx239
-rw-r--r--slideshow/source/engine/transitions/clippingfunctor.hxx98
-rw-r--r--slideshow/source/engine/transitions/clockwipe.cxx77
-rw-r--r--slideshow/source/engine/transitions/clockwipe.hxx53
-rw-r--r--slideshow/source/engine/transitions/combtransition.cxx199
-rw-r--r--slideshow/source/engine/transitions/combtransition.hxx75
-rw-r--r--slideshow/source/engine/transitions/doublediamondwipe.cxx69
-rw-r--r--slideshow/source/engine/transitions/doublediamondwipe.hxx56
-rw-r--r--slideshow/source/engine/transitions/ellipsewipe.cxx55
-rw-r--r--slideshow/source/engine/transitions/ellipsewipe.hxx51
-rw-r--r--slideshow/source/engine/transitions/fanwipe.cxx74
-rw-r--r--slideshow/source/engine/transitions/fanwipe.hxx54
-rw-r--r--slideshow/source/engine/transitions/figurewipe.cxx132
-rw-r--r--slideshow/source/engine/transitions/figurewipe.hxx58
-rw-r--r--slideshow/source/engine/transitions/fourboxwipe.cxx88
-rw-r--r--slideshow/source/engine/transitions/fourboxwipe.hxx58
-rw-r--r--slideshow/source/engine/transitions/iriswipe.cxx55
-rw-r--r--slideshow/source/engine/transitions/iriswipe.hxx55
-rw-r--r--slideshow/source/engine/transitions/makefile.mk73
-rw-r--r--slideshow/source/engine/transitions/parametricpolypolygon.hxx101
-rw-r--r--slideshow/source/engine/transitions/parametricpolypolygonfactory.cxx315
-rw-r--r--slideshow/source/engine/transitions/parametricpolypolygonfactory.hxx57
-rw-r--r--slideshow/source/engine/transitions/pinwheelwipe.cxx62
-rw-r--r--slideshow/source/engine/transitions/pinwheelwipe.hxx54
-rw-r--r--slideshow/source/engine/transitions/randomwipe.cxx97
-rw-r--r--slideshow/source/engine/transitions/randomwipe.hxx61
-rw-r--r--slideshow/source/engine/transitions/shapetransitionfactory.cxx409
-rw-r--r--slideshow/source/engine/transitions/slidechangebase.cxx538
-rw-r--r--slideshow/source/engine/transitions/slidechangebase.hxx211
-rw-r--r--slideshow/source/engine/transitions/slidetransitionfactory.cxx1168
-rw-r--r--slideshow/source/engine/transitions/snakewipe.cxx247
-rw-r--r--slideshow/source/engine/transitions/snakewipe.hxx79
-rw-r--r--slideshow/source/engine/transitions/spiralwipe.cxx134
-rw-r--r--slideshow/source/engine/transitions/spiralwipe.hxx71
-rw-r--r--slideshow/source/engine/transitions/sweepwipe.cxx87
-rw-r--r--slideshow/source/engine/transitions/sweepwipe.hxx56
-rw-r--r--slideshow/source/engine/transitions/transitionfactorytab.cxx2149
-rw-r--r--slideshow/source/engine/transitions/transitiontools.cxx72
-rw-r--r--slideshow/source/engine/transitions/transitiontools.hxx58
-rw-r--r--slideshow/source/engine/transitions/veewipe.cxx56
-rw-r--r--slideshow/source/engine/transitions/veewipe.hxx54
-rw-r--r--slideshow/source/engine/transitions/waterfallwipe.cxx80
-rw-r--r--slideshow/source/engine/transitions/waterfallwipe.hxx55
-rw-r--r--slideshow/source/engine/transitions/zigzagwipe.cxx85
-rw-r--r--slideshow/source/engine/transitions/zigzagwipe.hxx63
-rw-r--r--slideshow/source/engine/unoviewcontainer.cxx152
-rw-r--r--slideshow/source/engine/usereventqueue.cxx1009
-rw-r--r--slideshow/source/engine/waitsymbol.cxx211
-rw-r--r--slideshow/source/engine/waitsymbol.hxx111
-rw-r--r--slideshow/source/engine/wakeupevent.cxx102
195 files changed, 57326 insertions, 0 deletions
diff --git a/slideshow/source/engine/OGLTrans/exports.dxp b/slideshow/source/engine/OGLTrans/exports.dxp
new file mode 100644
index 000000000000..f0e1c69934bc
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/exports.dxp
@@ -0,0 +1,2 @@
+component_getImplementationEnvironment
+component_getFactory
diff --git a/slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.h b/slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.h
new file mode 100644
index 000000000000..358630beb583
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_OGLTRANS_SHADERS_HXX_
+#define INCLUDED_OGLTRANS_SHADERS_HXX_
+
+/* FIXME : Really needed ? */
+#define GL_GLEXT_PROTOTYPES 1
+
+/* Required Includes */
+#import <Cocoa/Cocoa.h>
+#import <OpenGL/gl.h>
+#import <OpenGL/glext.h>
+#import <OpenGL/glu.h>
+#import <OpenGL/OpenGL.h>
+#import <GLUT/glut.h>
+
+/* Parameter */
+typedef struct _Parameter {
+ float current [4];
+ float min [4];
+ float max [4];
+ float delta [4];
+
+} Parameter;
+
+/* Macros */
+#define PARAMETER_CURRENT(p) (p.current)
+#define PARAMETER_ANIMATE(p) ({ int i; for (i = 0; i < 4; i ++) { \
+ p.current[i] += p.delta[i]; \
+ if ((p.current[i] < p.min[i]) || (p.current[i] > p.max[i])) \
+ p.delta[i] = -p.delta[i]; } } )
+
+/* OGLShaders base class */
+@interface OGLShaders : NSObject
+{
+ BOOL initialised;
+ GLhandleARB vertex_shader;
+ GLhandleARB fragment_shader;
+ GLhandleARB program_object;
+ GLUquadric *quadric;
+ BOOL gpuProcessingInit;
+ BOOL gpuProcessing;
+}
+- (id) init;
+- (void) initLazy;
+- (void) dealloc;
+- (NSString *) name;
+- (NSString *) descriptionFilename;
+- (unsigned int) loadVertexShader: (NSString *) vertexString fragmentShader: (NSString *) fragmentString;
+
+ /* if!initialized -> initLazy */
+- (void) renderFrame;
+
+/* Check whether software rasterization or software vertex processing will be used */
+- (BOOL) reflect;
+
+@end
+
+
+// Utility Functions
+
+int NextHighestPowerOf2(int n);
+void CopyFramebufferToTexture(GLuint texture);
+NSBitmapImageRep *LoadImage(NSString *path, int shouldFlipVertical);
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.m b/slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.m
new file mode 100644
index 000000000000..360e8cf5e903
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/OGLTrans_Shaders.m
@@ -0,0 +1,231 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#import "OGLTrans_Shaders.h"
+
+
+@implementation OGLShaders
+
+- (id) init
+{
+ [super init];
+ gpuProcessingInit = NO;
+ return self;
+}
+
+- (void) initLazy
+{
+ /* Subclass should put initialisation code that can be performaned
+ lazily (on first frame render) here */
+ initialised = TRUE;
+
+ /* Create a GLU quadric, used for rendering certain geometry */
+ quadric = gluNewQuadric();
+ gluQuadricDrawStyle(quadric, GLU_FILL);
+ gluQuadricNormals(quadric, GL_SMOOTH);
+ gluQuadricTexture(quadric, GL_TRUE);
+
+}
+
+- (void) dealloc
+{
+ /* Free the GLU quadric */
+ if (quadric)
+ gluDeleteQuadric(quadric);
+
+ [super dealloc];
+}
+
+- (NSString *) name
+{
+ return @"Unnamed OGLShaders";
+}
+
+- (NSString *) descriptionFilename
+{
+ return NULL;
+}
+
+- (unsigned int) loadVertexShader: (NSString *) vertexString fragmentShader: (NSString *) fragmentString
+{
+ const GLcharARB *vertex_string;
+ const GLcharARB *fragment_string;
+ GLint vertex_compiled;
+ GLint fragment_compiled;
+ GLint linked;
+
+ /* Delete any existing program object */
+ if (program_object) {
+ glDeleteObjectARB(program_object);
+ program_object = NULL;
+ }
+
+ /* Load and compile both shaders */
+ if (vertexString) {
+ vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+ vertex_string = (GLcharARB *) [vertexString cString];
+ glShaderSourceARB(vertex_shader, 1, &vertex_string, NULL);
+ glCompileShaderARB(vertex_shader);
+ glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &vertex_compiled);
+ /* TODO - Get info log */
+ } else {
+ vertex_shader = NULL;
+ vertex_compiled = 1;
+ }
+
+ if (fragmentString) {
+ fragment_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ fragment_string = [fragmentString cString];
+ glShaderSourceARB(fragment_shader, 1, &fragment_string, NULL);
+ glCompileShaderARB(fragment_shader);
+ glGetObjectParameterivARB(fragment_shader, GL_OBJECT_COMPILE_STATUS_ARB, &fragment_compiled);
+ /* TODO - Get info log */
+ } else {
+ fragment_shader = NULL;
+ fragment_compiled = 1;
+ }
+
+ /* Ensure both shaders compiled */
+ if (!vertex_compiled || !fragment_compiled) {
+ if (vertex_shader) {
+ glDeleteObjectARB(vertex_shader);
+ vertex_shader = NULL;
+ }
+ if (fragment_shader) {
+ glDeleteObjectARB(fragment_shader);
+ fragment_shader = NULL;
+ }
+ return 1;
+ }
+
+ /* Create a program object and link both shaders */
+ program_object = glCreateProgramObjectARB();
+ if (vertex_shader != NULL)
+ {
+ glAttachObjectARB(program_object, vertex_shader);
+ glDeleteObjectARB(vertex_shader); /* Release */
+ }
+ if (fragment_shader != NULL)
+ {
+ glAttachObjectARB(program_object, fragment_shader);
+ glDeleteObjectARB(fragment_shader); /* Release */
+ }
+ glLinkProgramARB(program_object);
+ glGetObjectParameterivARB(program_object, GL_OBJECT_LINK_STATUS_ARB, &linked);
+ /* TODO - Get info log */
+
+ if (!linked) {
+ glDeleteObjectARB(program_object);
+ program_object = NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+- (void) renderFrame
+{
+ if (!initialised)
+ [self initLazy];
+}
+
+- (BOOL) reflect
+{
+ if(!gpuProcessingInit)
+ {
+ /* Check if this will fall back to software rasterization or
+ software vertex processing and don't reflect if it is. */
+
+ GLint fragmentGPUProcessing, vertexGPUProcessing;
+ gpuProcessingInit = YES;
+
+ glPushAttrib(GL_VIEWPORT_BIT);
+ glViewport(0,0,0,0);
+ glPushMatrix();
+ [self renderFrame];
+ glPopMatrix();
+ CGLGetParameter(CGLGetCurrentContext(), kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
+ CGLGetParameter(CGLGetCurrentContext(), kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
+ gpuProcessing = (fragmentGPUProcessing && vertexGPUProcessing) ? YES : NO;
+ glPopAttrib();
+ }
+
+ return gpuProcessing;
+}
+
+@end
+
+
+// Utility Functions
+
+int NextHighestPowerOf2(int n)
+{
+ n--;
+ n |= n >> 1;
+ n |= n >> 2;
+ n |= n >> 4;
+ n |= n >> 8;
+ n |= n >> 16;
+ n++;
+ return n;
+}
+
+void CopyFramebufferToTexture(GLuint texture)
+{
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewport[0], viewport[1], NextHighestPowerOf2(viewport[2]), NextHighestPowerOf2(viewport[3]), 0);
+}
+
+NSBitmapImageRep *LoadImage(NSString *path, int shouldFlipVertical)
+{
+ NSBitmapImageRep *bitmapimagerep;
+ NSImage *image;
+ image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease];
+ bitmapimagerep = [[NSBitmapImageRep alloc] initWithData:[image TIFFRepresentation]];
+
+ if (shouldFlipVertical)
+ {
+ int bytesPerRow, lowRow, highRow;
+ unsigned char *pixelData, *swapRow;
+
+ bytesPerRow = [bitmapimagerep bytesPerRow];
+ pixelData = [bitmapimagerep bitmapData];
+
+ swapRow = (unsigned char *)malloc(bytesPerRow);
+ for (lowRow = 0, highRow = [bitmapimagerep pixelsHigh]-1; lowRow < highRow; lowRow++, highRow--)
+ {
+ memcpy(swapRow, &pixelData[lowRow*bytesPerRow], bytesPerRow);
+ memcpy(&pixelData[lowRow*bytesPerRow], &pixelData[highRow*bytesPerRow], bytesPerRow);
+ memcpy(&pixelData[highRow*bytesPerRow], swapRow, bytesPerRow);
+ }
+ free(swapRow);
+ }
+
+ return bitmapimagerep;
+}
diff --git a/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.hxx b/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.hxx
new file mode 100644
index 000000000000..7e64b34961de
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.hxx
@@ -0,0 +1,497 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
+#define INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
+
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+
+#include <OpenGL/gl.h>
+#include <vector>
+
+using namespace std;
+
+class Primitive;
+class Operation;
+class SceneObject;
+
+
+/** OpenGL 3D Transition class. It implicitly is constructed from XOGLTransition
+
+ This class is capable of making itself into many difference transitions. It holds Primitives and Operations on those primitives.
+*/
+class OGLTransitionImpl
+{
+public:
+ OGLTransitionImpl() :
+ mbUseMipMapLeaving( true ),
+ mbUseMipMapEntering( true ),
+ mnRequiredGLVersion( 1.0 ),
+ maLeavingSlidePrimitives(),
+ maEnteringSlidePrimitives(),
+ maSceneObjects(),
+ mbReflectSlides( false ),
+ mVertexObject( 0 ),
+ mFragmentObject( 0 ),
+ mProgramObject( 0 ),
+ maHelperTexture( 0 ),
+ mmPrepare( NULL ),
+ mmPrepareTransition( NULL ),
+ mmClearTransition( NULL ),
+ mmDisplaySlides( NULL )
+ {}
+
+ ~OGLTransitionImpl();
+
+ void prepare( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight );
+ void finish();
+
+ void makeOutsideCubeFaceToLeft();
+ void makeInsideCubeFaceToLeft();
+ void makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m );
+ void makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles );
+ void makeHelix( ::sal_uInt16 nRows );
+ void makeFallLeaving();
+ void makeTurnAround();
+ void makeTurnDown();
+ void makeIris();
+ void makeRochade();
+ void makeVenetianBlinds( bool vertical, int parts );
+ void makeStatic();
+ void makeDissolve();
+ void makeNewsflash();
+
+ /** 2D replacements
+ */
+ void makeDiamond();
+ void makeFadeSmoothly();
+ void makeFadeThroughBlack();
+
+ /** Whether to use mipmaping for slides textures
+ */
+ bool mbUseMipMapLeaving;
+ bool mbUseMipMapEntering;
+
+ /** which GL version does the transition require
+ */
+ float mnRequiredGLVersion;
+
+private:
+ /** clears all the primitives and operations
+ */
+ void clear();
+
+ /** All the primitives that use the leaving slide texture
+ */
+ vector<Primitive> maLeavingSlidePrimitives;
+
+ /** All the primitives that use the leaving slide texture
+ */
+ vector<Primitive> maEnteringSlidePrimitives;
+
+ /** All the surrounding scene objects
+ */
+ vector<SceneObject*> maSceneObjects;
+
+ /** All the operations that should be applied to both leaving and entering slide primitives. These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
+ */
+ vector<Operation*> OverallOperations;
+
+ /** Whether to reflect slides, the reflection happens on flat surface beneath the slides.
+ ** Now it only works with slides which keep their rectangular shape together.
+ */
+ bool mbReflectSlides;
+
+ /** GLSL objects, shaders and program
+ */
+ GLuint mVertexObject, mFragmentObject, mProgramObject;
+
+ /** various data */
+ GLuint maHelperTexture;
+
+ /** When this method is not NULL, it is called in display method to prepare the slides, scene, etc.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmPrepare)( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight );
+
+ /** When this method is not NULL, it is called after glx context is ready to let the transition prepare GL related things, like GLSL program.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmPrepareTransition)( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+
+ /** When this method is not NULL, it is called when the transition needs to clear after itself, like delete own textures etc.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmClearTransition)();
+
+ /** When this method is not NULL, it is called in display method to display the slides.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmDisplaySlides)( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+
+ void displaySlides( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlide( double nTime, ::sal_Int32 glSlideTex, std::vector<Primitive>& primitives, double SlideWidthScale, double SlideHeightScale );
+ void displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ void applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale );
+
+ /** various transitions helper methods
+ */
+ void prepareDiamond( double nTime, double SlideWidth, double SlideHeight,double DispWidth, double DispHeight );
+ void displaySlidesFadeSmoothly( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesFadeThroughBlack( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesRochade( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesShaders( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void prepareStatic( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void prepareDissolve( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void preparePermShader();
+};
+
+class SceneObject
+{
+public:
+ SceneObject();
+
+ virtual void prepare() {};
+ virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ virtual void finish() {};
+
+ void pushPrimitive (const Primitive &p);
+
+protected:
+ /** All the surrounding scene primitives
+ */
+ vector<Primitive> maPrimitives;
+};
+
+class Iris : public SceneObject
+{
+public:
+ Iris ();
+
+ virtual void prepare();
+ virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ virtual void finish();
+
+private:
+
+ GLuint maTexture;
+};
+
+/** This class is a list of Triangles that will share Operations, and could possibly share
+*/
+class Primitive
+{
+public:
+ Primitive() {}
+ // making copy constructor explicit makes the class un-suitable for use with stl containers
+ Primitive(const Primitive& rvalue);
+ ~Primitive();
+
+ void applyOperations(double nTime, double SlideWidthScale, double SlideHeightScale);
+ void display(double nTime, double SlideWidthScale, double SlideHeightScale);
+ const Primitive& operator=(const Primitive& rvalue);
+
+ /** PushBack a vertex,normal, and tex coord. Each SlideLocation is where on the slide is mapped to this location ( from (0,0) to (1,1) ). This will make sure the correct aspect ratio is used, and helps to make slides begin and end at the correct position. (0,0) is the top left of the slide, and (1,1) is the bottom right.
+
+ @param SlideLocation0
+ Location of first Vertex on slide
+
+ @param SlideLocation1
+ Location of second Vertex on slide
+
+ @param SlideLocation2
+ Location of third Vertex on slide
+
+ */
+ void pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2);
+
+ /** clear all the vertices, normals, tex coordinates, and normals
+ */
+ void clearTriangles();
+
+ /** guards against directly changing the vertices
+
+ @return
+ the list of vertices
+ */
+ const vector<basegfx::B3DVector>& getVertices() const {return Vertices;}
+
+ /** guards against directly changing the vertices
+ */
+ const vector<basegfx::B3DVector>& getNormals() const {return Normals;}
+
+ /** guards against directly changing the vertices
+
+ @return
+ the list of Texture Coordinates
+
+ */
+ const vector<basegfx::B2DVector>& getTexCoords() const {return TexCoords;}
+
+ /** list of Operations to be performed on this primitive.These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
+
+ @return
+ the list of Operations
+
+ */
+ vector<Operation*> Operations;
+
+private:
+ /** list of vertices
+ */
+ vector<basegfx::B3DVector> Vertices;
+
+ /** list of Normals
+ */
+ vector<basegfx::B3DVector> Normals;
+
+ /** list of Texture Coordinates
+ */
+ vector<basegfx::B2DVector> TexCoords;
+};
+
+/** This class is to be derived to make any operation (tranform) you may need in order to construct your transitions
+*/
+class Operation
+{
+public:
+ Operation(){}
+ virtual ~Operation(){}
+
+ /** Should this operation be interpolated . If TRUE, the transform will smoothly move from making no difference from t = 0.0 to nT0 to being completely transformed from t = nT1 to 1. If FALSE, the transform will be inneffectual from t = 0 to nT0, and completely transformed from t = nT0 to 1.
+ */
+ bool bInterpolate;
+
+ /** time to begin the transformation
+ */
+ double nT0;
+
+ /** time to finish the transformation
+ */
+ double nT1;
+public:
+ /** this is the function that is called to give the Operation to OpenGL.
+
+ @param t
+ time from t = 0 to t = 1
+
+ @param SlideWidthScale
+ width of slide divided by width of window
+
+ @param SlideHeightScale
+ height of slide divided by height of window
+
+ */
+ virtual void interpolate(double t,double SlideWidthScale,double SlideHeightScale) = 0;
+
+ /** return a copy of this operation
+ */
+ virtual Operation* clone() = 0;
+};
+
+/** this class is a generic CounterClockWise(CCW) rotation with an axis angle
+*/
+class SRotate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ virtual SRotate* clone();
+
+ /** Constructor
+
+ @param Axis
+ axis to rotate about
+
+ @param Origin
+ position that rotation axis runs through
+
+ @param Angle
+ angle in radians of CCW rotation
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~SRotate(){}
+private:
+ /** axis to rotate CCW about
+ */
+ basegfx::B3DVector axis;
+
+ /** position that rotation axis runs through
+ */
+ basegfx::B3DVector origin;
+
+ /** angle in radians of CCW rotation
+ */
+ double angle;
+};
+
+/** scaling transformation
+*/
+class SScale: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ SScale* clone();
+
+ /** Constructor
+
+ @param Scale
+ amount to scale by
+
+ @param Origin
+ position that rotation axis runs through
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SScale(const basegfx::B3DVector& Scale, const basegfx::B3DVector& Origin,bool bInter, double T0, double T1);
+ ~SScale(){}
+private:
+ basegfx::B3DVector scale;
+ basegfx::B3DVector origin;
+};
+
+/** translation transformation
+*/
+class STranslate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ STranslate* clone();
+
+ /** Constructor
+
+ @param Vector
+ vector to translate
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ STranslate(const basegfx::B3DVector& Vector,bool bInter, double T0, double T1);
+ ~STranslate(){}
+private:
+ /** vector to translate by
+ */
+ basegfx::B3DVector vector;
+};
+
+/** translation transformation
+*/
+class SEllipseTranslate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ SEllipseTranslate* clone();
+
+ /** Constructor
+
+ @param Vector
+ vector to translate
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1);
+ ~SEllipseTranslate(){}
+private:
+ /** width and length of the ellipse
+ */
+ double width, height;
+
+ /** start and end position on the ellipse <0,1>
+ */
+ double startPosition;
+ double endPosition;
+};
+
+/** Same as SRotate, except the depth is scaled by the width of the slide divided by the width of the window.
+*/
+class RotateAndScaleDepthByWidth: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ RotateAndScaleDepthByWidth* clone();
+
+ RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~RotateAndScaleDepthByWidth(){}
+private:
+ basegfx::B3DVector axis;
+ basegfx::B3DVector origin;
+ double angle;
+};
+
+/** Same as SRotate, except the depth is scaled by the width of the slide divided by the height of the window.
+*/
+class RotateAndScaleDepthByHeight: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ RotateAndScaleDepthByHeight* clone();
+
+ RotateAndScaleDepthByHeight(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~RotateAndScaleDepthByHeight(){}
+private:
+ basegfx::B3DVector axis;
+ basegfx::B3DVector origin;
+ double angle;
+};
+
+#endif // INCLUDED_SLIDESHOW_TRANSITION_HXX_
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.mm b/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.mm
new file mode 100644
index 000000000000..f006e96c2d41
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionImpl.mm
@@ -0,0 +1,1326 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "OGLTrans_TransitionImpl.hxx"
+#include "OGLTrans_Shaders.h"
+#ifdef QUARTZ
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#endif
+#include <math.h>
+
+void OGLTransitionImpl::clear()
+{
+ for(unsigned int i( 0 ); i < OverallOperations.size(); ++i)
+ delete OverallOperations[i];
+ OverallOperations.clear();
+ maLeavingSlidePrimitives.clear();
+ maEnteringSlidePrimitives.clear();
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i)
+ delete maSceneObjects[i];
+ maSceneObjects.clear();
+
+ mbReflectSlides = false;
+
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ glDeleteProgram( mProgramObject );
+ mProgramObject = 0;
+ }
+
+ if( mVertexObject ) {
+ glDeleteShader( mVertexObject );
+ mVertexObject = 0;
+ }
+
+ if( mFragmentObject ) {
+ glDeleteShader( mFragmentObject );
+ mFragmentObject = 0;
+ }
+#endif
+
+ if( maHelperTexture ) {
+ glDeleteTextures( 1, &maHelperTexture );
+ maHelperTexture = 0;
+ }
+
+ if( mmClearTransition )
+ (this->*mmClearTransition)();
+}
+
+OGLTransitionImpl::~OGLTransitionImpl()
+{
+ clear();
+}
+
+void OGLTransitionImpl::prepare( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex )
+{
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
+ maSceneObjects[i]->prepare();
+ }
+
+ if( mmPrepareTransition )
+ (this->*mmPrepareTransition)( glLeavingSlideTex, glEnteringSlideTex );
+}
+
+void OGLTransitionImpl::finish()
+{
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
+ maSceneObjects[i]->finish();
+ }
+}
+
+static void blendSlide( double depth )
+{
+ double showHeight = -1 + depth*2;
+ GLfloat reflectionColor[] = {0, 0, 0, 0.25};
+
+ glDisable( GL_DEPTH_TEST );
+ glBegin( GL_QUADS );
+ glColor4fv( reflectionColor );
+ glVertex3f( -1, -1, 0 );
+ glColor4f( 0, 0, 0, 1 );
+ glVertex3f(-1, showHeight, 0 );
+ glVertex3f( 1, showHeight, 0 );
+ glColor4fv( reflectionColor );
+ glVertex3f( 1, -1, 0 );
+ glEnd();
+
+ glBegin( GL_QUADS );
+ glColor4f( 0, 0, 0, 1 );
+ glVertex3f( -1, showHeight, 0 );
+ glVertex3f( -1, 1, 0 );
+ glVertex3f( 1, 1, 0 );
+ glVertex3f( 1, showHeight, 0 );
+ glEnd();
+ glEnable( GL_DEPTH_TEST );
+}
+
+static void slideShadow( double nTime, Primitive& primitive, double sw, double sh )
+{
+ double reflectionDepth = 0.3;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_LIGHTING);
+
+ glPushMatrix();
+ primitive.applyOperations( nTime, sw, sh );
+ blendSlide( reflectionDepth );
+ glPopMatrix();
+
+ glDisable(GL_BLEND);
+ glEnable(GL_LIGHTING);
+}
+
+void OGLTransitionImpl::display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ double SlideWidthScale, SlideHeightScale;
+
+ SlideWidthScale = SlideWidth/DispWidth;
+ SlideHeightScale = SlideHeight/DispHeight;
+
+ if( mmPrepare ) {
+ clear();
+ (this->*mmPrepare)( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
+ }
+
+ glPushMatrix();
+ displaySlides( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
+ displayScene( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
+ glPopMatrix();
+}
+
+void OGLTransitionImpl::applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale )
+{
+ for(unsigned int i(0); i < OverallOperations.size(); ++i)
+ OverallOperations[i]->interpolate(nTime,SlideWidthScale,SlideHeightScale);
+}
+
+void OGLTransitionImpl::displaySlide( double nTime, ::sal_Int32 glSlideTex, std::vector<Primitive>& primitives,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ //TODO change to foreach
+ glBindTexture(GL_TEXTURE_2D, glSlideTex);
+
+ // display slide reflection
+ // note that depth test is turned off while blending the shadow
+ // so the slides has to be rendered in right order, see rochade as example
+ if( mbReflectSlides ) {
+ double surfaceLevel = -0.04;
+
+ /* reflected slides */
+ glPushMatrix();
+
+ glScaled( 1, -1, 1 );
+ glTranslated( 0, 2 - surfaceLevel, 0 );
+
+ glCullFace(GL_FRONT);
+ for(unsigned int i(0); i < primitives.size(); ++i)
+ primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
+ glCullFace(GL_BACK);
+
+ slideShadow( nTime, primitives[0], SlideWidthScale, SlideHeightScale );
+
+ glPopMatrix();
+ }
+
+ for(unsigned int i(0); i < primitives.size(); ++i)
+ primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
+}
+
+void OGLTransitionImpl::displaySlides( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ if( mmDisplaySlides )
+ (this->*mmDisplaySlides)( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
+ else {
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glEnable(GL_TEXTURE_2D);
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+}
+
+void OGLTransitionImpl::displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ glEnable(GL_TEXTURE_2D);
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i)
+ maSceneObjects[i]->display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
+}
+
+void Primitive::display(double nTime, double WidthScale, double HeightScale)
+{
+ glPushMatrix();
+
+ applyOperations( nTime, WidthScale, HeightScale );
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if(!Normals.empty())
+ {
+ glNormalPointer( GL_DOUBLE , 0 , &Normals[0] );
+ glEnableClientState( GL_NORMAL_ARRAY );
+ }
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glTexCoordPointer( 2, GL_DOUBLE, 0, &TexCoords[0] );
+ glVertexPointer( 3, GL_DOUBLE, 0, &Vertices[0] );
+ glDrawArrays( GL_TRIANGLES, 0, Vertices.size() );
+ glPopMatrix();
+}
+
+void Primitive::applyOperations(double nTime, double WidthScale, double HeightScale)
+{
+ for(unsigned int i(0); i < Operations.size(); ++i)
+ Operations[i]->interpolate( nTime ,WidthScale,HeightScale);
+ glScaled(WidthScale,HeightScale,1);
+}
+
+Primitive::~Primitive()
+{
+ for(unsigned int i( 0 ); i < Operations.size(); ++i)
+ delete Operations[i];
+}
+
+
+void SceneObject::display(double nTime, double /* SlideWidth */, double /* SlideHeight */, double DispWidth, double DispHeight )
+{
+ for(unsigned int i(0); i < maPrimitives.size(); ++i) {
+ // fixme: allow various model spaces, now we make it so that
+ // it is regular -1,-1 to 1,1, where the whole display fits in
+ glPushMatrix();
+ if (DispHeight > DispWidth)
+ glScaled(DispHeight/DispWidth, 1, 1);
+ else
+ glScaled(1, DispWidth/DispHeight, 1);
+ maPrimitives[i].display(nTime, 1, 1);
+ glPopMatrix();
+ }
+}
+
+void SceneObject::pushPrimitive(const Primitive &p)
+{
+ maPrimitives.push_back(p);
+}
+
+SceneObject::SceneObject()
+ : maPrimitives()
+{
+}
+
+Iris::Iris()
+ : SceneObject ()
+{
+}
+
+void Iris::display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ glBindTexture(GL_TEXTURE_2D, maTexture);
+ SceneObject::display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
+}
+
+void Iris::prepare()
+{
+ static GLubyte img[3] = { 80, 80, 80 };
+
+ glGenTextures(1, &maTexture);
+ glBindTexture(GL_TEXTURE_2D, maTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+}
+
+void Iris::finish()
+{
+ glDeleteTextures(1, &maTexture);
+}
+
+void OGLTransitionImpl::makeOutsideCubeFaceToLeft()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),90,false,0.0,1.0));
+
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),-90,true,0.0,1.0));
+}
+
+void OGLTransitionImpl::makeInsideCubeFaceToLeft()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),-90,false,0.0,1.0));
+
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),90,true,0.0,1.0));
+}
+
+void OGLTransitionImpl::makeFallLeaving()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(1,0,0),basegfx::B3DVector(0,-1,0), 90,true,0.0,1.0));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::makeTurnAround()
+{
+ clear();
+ Primitive Slide;
+
+ mbReflectSlides = true;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0),-180,false,0.0,1.0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, -1.5),true, 0, 0.5));
+ OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1.5), true, 0.5, 1));
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0),basegfx::B3DVector(0, 0, 0), -180, true, 0.0, 1.0));
+}
+
+void OGLTransitionImpl::makeTurnDown()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 0.0001), false, -1.0, 0.0));
+ Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), -90, true, 0.0, 1.0));
+ Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), 90, false, -1.0, 0.0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ mbUseMipMapLeaving = false;
+}
+
+void OGLTransitionImpl::makeIris()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, 0.000001), false, -1, 0));
+ Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, -0.000002), false, 0.5, 1));
+ maLeavingSlidePrimitives.push_back (Slide);
+
+
+ Primitive irisPart, part;
+ int i, nSteps = 24, nParts = 7;
+ double lt = 0, t = 1.0/nSteps, cx, cy, lcx, lcy, lx = 1, ly = 0, x, y, cxo, cyo, lcxo, lcyo, of=2.2, f=1.42;
+
+ for (i=1; i<=nSteps; i++) {
+ x = cos ((3*2*M_PI*t)/nParts);
+ y = -sin ((3*2*M_PI*t)/nParts);
+ cx = (f*x + 1)/2;
+ cy = (f*y + 1)/2;
+ lcx = (f*lx + 1)/2;
+ lcy = (f*ly + 1)/2;
+ cxo = (of*x + 1)/2;
+ cyo = (of*y + 1)/2;
+ lcxo = (of*lx + 1)/2;
+ lcyo = (of*ly + 1)/2;
+ irisPart.pushTriangle (basegfx::B2DVector (lcx, lcy),
+ basegfx::B2DVector (lcxo, lcyo),
+ basegfx::B2DVector (cx, cy));
+ irisPart.pushTriangle (basegfx::B2DVector (cx, cy),
+ basegfx::B2DVector (lcxo, lcyo),
+ basegfx::B2DVector (cxo, cyo));
+ lx = x;
+ ly = y;
+ lt = t;
+ t += 1.0/nSteps;
+ }
+
+ Iris* pIris = new Iris();
+ double angle = 87;
+
+ for (i = 0; i < nParts; i++) {
+ irisPart.Operations.clear ();
+ double rx, ry;
+
+ rx = cos ((2*M_PI*i)/nParts);
+ ry = sin ((2*M_PI*i)/nParts);
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0), angle, true, 0.0, 0.5));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0), -angle, true, 0.5, 1));
+ if (i > 0) {
+ irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(rx, ry, 0), false, -1, 0));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(0, 0, 0), i*360.0/nParts, false, -1, 0));
+ irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(-1, 0, 0), false, -1, 0));
+ }
+ irisPart.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1), false, -2, 0.0));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(1, .5, 0), basegfx::B3DVector(1, 0, 0), -30, false, -1, 0));
+ pIris->pushPrimitive (irisPart);
+ }
+
+ maSceneObjects.push_back (pIris);
+
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::displaySlidesRochade( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glEnable(GL_TEXTURE_2D);
+
+ if( nTime > .5) {
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ } else {
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+}
+
+void OGLTransitionImpl::makeRochade()
+{
+ clear();
+ Primitive Slide;
+
+ mbReflectSlides = true;
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesRochade;
+
+ double w, h;
+
+ w = 2.2;
+ h = 10;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.25, -0.25, true, 0, 1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.clear();
+ Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.75, 0.25, true, 0, 1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, -h), false, -1, 0));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), 45, false, -1, 0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ // OverallOperations.push_back(new SEllipseTranslate(0.5, 2, 0, 1, true, 0, 1));
+// push_back(new STranslate(basegfx::B3DVector(0, 0, -2), true, 0, 0.5));
+// OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, 2), true, 0.5, 1));
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B2DVector clamp(const basegfx::B2DVector& v)
+{
+ return basegfx::B2DVector(min(max(v.getX(),-1.0),1.0),
+ min(max(v.getY(),-1.0),1.0));
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B3DVector clamp(const basegfx::B3DVector& v)
+{
+ return basegfx::B3DVector(min(max(v.getX(),-1.0),1.0),
+ min(max(v.getY(),-1.0),1.0),
+ min(max(v.getZ(),-1.0),1.0));
+}
+
+inline double randFromNeg1to1()
+{
+ return ( ( static_cast<double>( rand() ) / static_cast<double>( RAND_MAX ) ) * 2.0 ) - 1.0;
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B3DVector randNormVectorInXYPlane()
+{
+ basegfx::B3DVector toReturn(randFromNeg1to1(),randFromNeg1to1(),0.0);
+ return toReturn/toReturn.getLength();
+}
+
+void OGLTransitionImpl::makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles )
+{
+ clear();
+ double dAngle(2*3.1415926/static_cast<double>( nPointsOnCircles ));
+ if(nCircles < 2 || nPointsOnCircles < 4)
+ {
+ makeNByMTileFlip(1,1);
+ return;
+ }
+ double Radius(1.0/static_cast<double>( nCircles ));
+ double dRadius(Radius);
+ double LastRadius(0.0);
+ double NextRadius(2*Radius);
+
+ /// now we know there is at least two circles
+ /// the first will always be a full circle
+ /// the last will always be the outer shell of the slide with a circle hole
+
+ //add the full circle
+ vector<basegfx::B2DVector> unScaledTexCoords;
+ double TempAngle(0.0);
+ for(unsigned int Point(0); Point < nPointsOnCircles; ++Point)
+ {
+ unScaledTexCoords.push_back( basegfx::B2DVector( cos(TempAngle - 3.1415926/2.0) , sin(TempAngle- 3.1415926/2.0) ) );
+
+ TempAngle += dAngle;
+ }
+
+ {
+ //double angle(0.0);
+ Primitive EnteringSlide;
+ Primitive LeavingSlide;
+ for(int Point(0); Point + 1 < nPointsOnCircles; ++Point)
+ {
+ EnteringSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
+ LeavingSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5, 0.5) );
+ }
+ EnteringSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius * unScaledTexCoords[ 0 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ nPointsOnCircles - 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
+ LeavingSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+ LastRadius = Radius;
+ Radius = NextRadius;
+ NextRadius += dRadius;
+ }
+
+ for(int i(1); i < nCircles - 1; ++i)
+ {
+ Primitive LeavingSlide;
+ Primitive EnteringSlide;
+ for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
+ {
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ }
+
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+
+ LastRadius = Radius;
+ Radius = NextRadius;
+ NextRadius += dRadius;
+ }
+ {
+ Radius = sqrt(2.0);
+ Primitive LeavingSlide;
+ Primitive EnteringSlide;
+ for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
+ {
+
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
+ }
+
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+ }
+}
+
+void OGLTransitionImpl::makeHelix( ::sal_uInt16 nRows )
+{
+ clear();
+ double invN(1.0/static_cast<double>(nRows));
+ double iDn = 0.0;
+ double iPDn = invN;
+ for(unsigned int i(0); i < nRows; ++i)
+ {
+ Primitive Tile;
+
+ Tile.pushTriangle(basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
+
+ Tile.pushTriangle(basegfx::B2DVector( 1.0 , iPDn ) , basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 ,
+ true,min(max(static_cast<double>(i - nRows/2.0)*invN/2.0,0.0),1.0),
+ min(max(static_cast<double>(i + nRows/2.0)*invN/2.0,0.0),1.0) ) );
+
+ maLeavingSlidePrimitives.push_back(Tile);
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180 , false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(Tile);
+
+ iDn += invN;
+ iPDn += invN;
+ }
+}
+
+void OGLTransitionImpl::makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m )
+{
+ clear();
+ double invN(1.0/static_cast<double>(n));
+ double invM(1.0/static_cast<double>(m));
+ double iDn = 0.0;
+ double iPDn = invN;
+ for(unsigned int i(0); i < n; ++i)
+ {
+ double jDm = 0.0;
+ double jPDm = invM;
+ for(unsigned int j(0); j < m; ++j)
+ {
+ Primitive Tile;
+
+ Tile.pushTriangle(basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));
+
+ Tile.pushTriangle(basegfx::B2DVector( iPDn , jPDm ) , basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));//bottom left corner of tile
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 , true, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
+ maLeavingSlidePrimitives.push_back(Tile);
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180, false, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
+
+ maEnteringSlidePrimitives.push_back(Tile);
+
+ jDm += invM;
+ jPDm += invM;
+ }
+ iDn += invN;
+ iPDn += invN;
+ }
+}
+
+SRotate::SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+SScale::SScale(const basegfx::B3DVector& Scale,const basegfx::B3DVector& Origin, bool bInter, double T0, double T1):scale(Scale),origin(Origin)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+RotateAndScaleDepthByWidth::RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+RotateAndScaleDepthByHeight::RotateAndScaleDepthByHeight(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+
+STranslate::STranslate(const basegfx::B3DVector& Vector, bool bInter, double T0, double T1):vector(Vector)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+inline double intervalInter(double t, double T0, double T1)
+{
+ return ( t - T0 ) / ( T1 - T0 );
+}
+
+void STranslate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*t*vector.getX(),SlideHeightScale*t*vector.getY(),t*vector.getZ());
+}
+
+void SRotate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
+ glScaled(SlideWidthScale,SlideHeightScale,1);
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glScaled(1/SlideWidthScale,1/SlideHeightScale,1);
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
+}
+
+void SScale::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
+ glScaled((1-t) + t*scale.getX(),(1-t) + t*scale.getY(),(1-t) + t*scale.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
+}
+
+void RotateAndScaleDepthByWidth::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideWidthScale*origin.getZ());
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideWidthScale*origin.getZ());
+}
+
+void RotateAndScaleDepthByHeight::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideHeightScale*origin.getZ());
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideHeightScale*origin.getZ());
+}
+
+SEllipseTranslate::SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+ width = dWidth;
+ height = dHeight;
+ startPosition = dStartPosition;
+ endPosition = dEndPosition;
+}
+
+void SEllipseTranslate::interpolate(double t,double /* SlideWidthScale */,double /* SlideHeightScale */)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+
+ double a1, a2, x, y;
+ a1 = startPosition*2*M_PI;
+ a2 = (startPosition + t*(endPosition - startPosition))*2*M_PI;
+ x = width*(cos (a2) - cos (a1))/2;
+ y = height*(sin (a2) - sin (a1))/2;
+
+ glTranslated(x, 0, y);
+}
+
+STranslate* STranslate::clone()
+{
+ return new STranslate(*this);
+}
+SRotate* SRotate::clone()
+{
+ return new SRotate(*this);
+}
+
+SScale* SScale::clone()
+{
+ return new SScale(*this);
+}
+
+SEllipseTranslate* SEllipseTranslate::clone()
+{
+ return new SEllipseTranslate(*this);
+}
+
+RotateAndScaleDepthByWidth* RotateAndScaleDepthByWidth::clone()
+{
+ return new RotateAndScaleDepthByWidth(*this);
+}
+
+RotateAndScaleDepthByHeight* RotateAndScaleDepthByHeight::clone()
+{
+ return new RotateAndScaleDepthByHeight(*this);
+}
+
+const Primitive& Primitive::operator=(const Primitive& rvalue)
+{
+ for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
+ Operations.push_back(rvalue.Operations[i]->clone());
+ for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
+ Vertices.push_back(rvalue.Vertices[i]);
+ for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
+ TexCoords.push_back(rvalue.TexCoords[i]);
+ for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
+ Normals.push_back(rvalue.Normals[i]);
+ return *this;
+}
+
+Primitive::Primitive(const Primitive& rvalue)
+{
+ for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
+ Operations.push_back(rvalue.Operations[i]->clone());
+ for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
+ Vertices.push_back(rvalue.Vertices[i]);
+ for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
+ TexCoords.push_back(rvalue.TexCoords[i]);
+ for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
+ Normals.push_back(rvalue.Normals[i]);
+}
+
+void Primitive::pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2)
+{
+ vector<basegfx::B3DVector> Verts;
+ vector<basegfx::B2DVector> Texs;
+ Verts.reserve(3);
+ Texs.reserve(3);
+
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
+
+ //figure out if they're facing the correct way, and make them face the correct way.
+ basegfx::B3DVector Normal( basegfx::cross( Verts[0] - Verts[1] , Verts[1] - Verts[2] ) );
+ if(Normal.getZ() >= 0.0)//if the normal is facing us
+ {
+ Texs.push_back(SlideLocation0);
+ Texs.push_back(SlideLocation1);
+ Texs.push_back(SlideLocation2);
+ }
+ else // if the normal is facing away from us, make it face us
+ {
+ Texs.push_back(SlideLocation0);
+ Texs.push_back(SlideLocation2);
+ Texs.push_back(SlideLocation1);
+ Verts.clear();
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
+ }
+
+ Vertices.push_back(Verts[0]);
+ Vertices.push_back(Verts[1]);
+ Vertices.push_back(Verts[2]);
+
+ TexCoords.push_back(Texs[0]);
+ TexCoords.push_back(Texs[1]);
+ TexCoords.push_back(Texs[2]);
+
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+}
+
+void OGLTransitionImpl::makeDiamond()
+{
+ mmPrepare = &OGLTransitionImpl::prepareDiamond;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::prepareDiamond( double nTime, double /* SlideWidth */, double /* SlideHeight */, double /* DispWidth */, double /* DispHeight */ )
+{
+ Primitive Slide1, Slide2;
+
+ Slide1.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide1.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maEnteringSlidePrimitives.push_back (Slide1);
+
+
+ if( nTime >= 0.5 ) {
+ double m = 1 - nTime;
+
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (m,0), basegfx::B2DVector (0,m));
+ Slide2.pushTriangle (basegfx::B2DVector (nTime,0), basegfx::B2DVector (1,0), basegfx::B2DVector (1,m));
+ Slide2.pushTriangle (basegfx::B2DVector (1,nTime), basegfx::B2DVector (1,1), basegfx::B2DVector (nTime,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,nTime), basegfx::B2DVector (m,1), basegfx::B2DVector (0,1));
+ } else {
+ double l = 0.5 - nTime;
+ double h = 0.5 + nTime;
+
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0.5,l));
+ Slide2.pushTriangle (basegfx::B2DVector (0.5,l), basegfx::B2DVector (1,0), basegfx::B2DVector (h,0.5));
+ Slide2.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (1,1), basegfx::B2DVector (h,0.5));
+ Slide2.pushTriangle (basegfx::B2DVector (h,0.5), basegfx::B2DVector (1,1), basegfx::B2DVector (0.5,h));
+ Slide2.pushTriangle (basegfx::B2DVector (0.5,h), basegfx::B2DVector (1,1), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (l,0.5), basegfx::B2DVector (0.5,h), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (l,0.5), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (0.5,l), basegfx::B2DVector (l,0.5));
+ }
+ Slide2.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, 0.00000001), false, -1, 0));
+ maLeavingSlidePrimitives.push_back (Slide2);
+}
+
+void OGLTransitionImpl::makeVenetianBlinds( bool vertical, int parts )
+{
+ static double t30 = tan( M_PI/6.0 );
+ double n, ln = 0;
+ double p = 1.0/parts;
+
+ for( int i=0; i<parts; i++ ) {
+ Primitive Slide;
+ n = (i + 1)/(double)parts;
+ if( vertical ) {
+ Slide.pushTriangle (basegfx::B2DVector (ln,0), basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1));
+ Slide.pushTriangle (basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1), basegfx::B2DVector (n,1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, -t30*p), -120, true, 0.0, 1.0));
+ } else {
+ Slide.pushTriangle (basegfx::B2DVector (0,ln), basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n));
+ Slide.pushTriangle (basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n), basegfx::B2DVector (1,n));
+ Slide.Operations.push_back(new RotateAndScaleDepthByHeight(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, -t30*p), -120, true, 0.0, 1.0));
+ }
+ maLeavingSlidePrimitives.push_back (Slide);
+
+ if( vertical ) {
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(2*n - 1, 0, 0), -60, false, -1, 0));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, 0), 180, false, -1, 0));
+ } else {
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - 2*n, 0), -60, false, -1, 0));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, 0), 180, false, -1, 0));
+ }
+ maEnteringSlidePrimitives.push_back (Slide);
+ ln = n;
+ }
+}
+
+void OGLTransitionImpl::displaySlidesFadeSmoothly( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_DEPTH_TEST);
+
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4f( 1, 1, 1, nTime );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ glDisable(GL_BLEND);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_LIGHTING);
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+void OGLTransitionImpl::makeFadeSmoothly()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeSmoothly;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::displaySlidesFadeThroughBlack( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_DEPTH_TEST);
+
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ if( nTime < 0.5 ) {
+ glColor4f( 1, 1, 1, 1 - nTime*2 );
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ } else {
+ glColor4f( 1, 1, 1, (nTime - 0.5)*2 );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+ glDisable(GL_BLEND);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_LIGHTING);
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+void OGLTransitionImpl::makeFadeThroughBlack()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeThroughBlack;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+static const char* basicVertexShader = "\n\
+varying vec2 v_texturePosition;\n\
+\n\
+void main( void )\n\
+{\n\
+ gl_Position = ftransform();\n\
+ v_texturePosition = gl_MultiTexCoord0.xy;\n\
+}\n\
+";
+
+static const char* staticFragmentShader = "\n\
+uniform sampler2D leavingSlideTexture;\n\
+uniform sampler2D enteringSlideTexture;\n\
+uniform sampler2D permTexture;\n\
+uniform float time;\n\
+varying vec2 v_texturePosition;\n\
+\n\
+float snoise(vec2 P) {\n\
+\n\
+ return texture2D(permTexture, P).r;\n\
+}\n\
+\n\
+\n\
+#define PART 0.5\n\
+#define START 0.4\n\
+#define END 0.9\n\
+\n\
+void main() {\n\
+ float sn = snoise(10.0*v_texturePosition+time*0.07);\n\
+ if( time < PART ) {\n\
+ float sn1 = snoise(vec2(time*15.0, 20.0*v_texturePosition.y));\n\
+ float sn2 = snoise(v_texturePosition);\n\
+ if (sn1 > 1.0 - time*time && sn2 < 2.0*time+0.1)\n\
+ gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
+ else if (time > START )\n\
+ gl_FragColor = ((time-START)/(PART - START))*vec4(sn, sn, sn, 1.0) + (1.0 - (time - START)/(PART - START))*texture2D(leavingSlideTexture, v_texturePosition);\n\
+ else\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+ } else if ( time < PART ) {\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+ } else if ( time > END ) {\n\
+ gl_FragColor = ((1.0 - time)/(1.0 - END))*vec4(sn, sn, sn, 1.0) + ((time - END)/(1.0 - END))*texture2D(enteringSlideTexture, v_texturePosition);\n\
+ } else \n\
+ gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
+}\n\
+";
+
+static const char* dissolveFragmentShader = "\n\
+uniform sampler2D leavingSlideTexture;\n\
+uniform sampler2D enteringSlideTexture;\n\
+uniform sampler2D permTexture;\n\
+uniform float time;\n\
+varying vec2 v_texturePosition;\n\
+\n\
+float snoise(vec2 P) {\n\
+\n\
+ return texture2D(permTexture, P).r;\n\
+}\n\
+\n\
+void main() {\n\
+ float sn = snoise(10.0*v_texturePosition);\n\
+ if( sn < time)\n\
+ gl_FragColor = texture2D(enteringSlideTexture, v_texturePosition);\n\
+ else\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+}\n\
+";
+
+int permutation256 [256]= {
+215, 100, 200, 204, 233, 50, 85, 196,
+ 71, 141, 122, 160, 93, 131, 243, 234,
+162, 183, 36, 155, 4, 62, 35, 205,
+ 40, 102, 33, 27, 255, 55, 214, 156,
+ 75, 163, 134, 126, 249, 74, 197, 228,
+ 72, 90, 206, 235, 17, 22, 49, 169,
+227, 89, 16, 5, 117, 60, 248, 230,
+217, 68, 138, 96, 194, 170, 136, 10,
+112, 238, 184, 189, 176, 42, 225, 212,
+ 84, 58, 175, 244, 150, 168, 219, 236,
+101, 208, 123, 37, 164, 110, 158, 201,
+ 78, 114, 57, 48, 70, 142, 106, 43,
+232, 26, 32, 252, 239, 98, 191, 94,
+ 59, 149, 39, 187, 203, 190, 19, 13,
+133, 45, 61, 247, 23, 34, 20, 52,
+118, 209, 146, 193, 222, 18, 1, 152,
+ 46, 41, 91, 148, 115, 25, 135, 77,
+254, 147, 224, 161, 9, 213, 223, 250,
+231, 251, 127, 166, 63, 179, 81, 130,
+139, 28, 120, 151, 241, 86, 111, 0,
+ 88, 153, 172, 182, 159, 105, 178, 47,
+ 51, 167, 65, 66, 92, 73, 198, 211,
+245, 195, 31, 220, 140, 76, 221, 186,
+154, 185, 56, 83, 38, 165, 109, 67,
+124, 226, 132, 53, 229, 29, 12, 181,
+121, 24, 207, 199, 177, 113, 30, 80,
+ 3, 97, 188, 79, 216, 173, 8, 145,
+ 87, 128, 180, 237, 240, 137, 125, 104,
+ 15, 242, 119, 246, 103, 143, 95, 144,
+ 2, 44, 69, 157, 192, 174, 14, 54,
+218, 82, 64, 210, 11, 6, 129, 21,
+116, 171, 99, 202, 7, 107, 253, 108
+};
+
+void initPermTexture(GLuint *texID)
+{
+ glGenTextures(1, texID);
+ glBindTexture(GL_TEXTURE_2D, *texID);
+
+ static bool initialized = false;
+ static unsigned char permutation2D[256*256*4];
+ if( !initialized ) {
+ int x, y;
+
+ for( y=0; y < 256; y++ )
+ for( x=0; x < 256; x++ )
+ permutation2D[x*4 + y*1024] = permutation256[(y + permutation256[x]) & 0xff];
+
+ initialized = true;
+ }
+
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, permutation2D );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+}
+
+void OGLTransitionImpl::preparePermShader()
+{
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ glUseProgram( mProgramObject );
+
+ GLint location = glGetUniformLocation( mProgramObject, "leavingSlideTexture" );
+ if( location != -1 ) {
+ glUniform1i( location, 0 ); // texture unit 0
+ }
+
+ glActiveTexture(GL_TEXTURE1);
+ if( !maHelperTexture )
+ initPermTexture( &maHelperTexture );
+ glActiveTexture(GL_TEXTURE0);
+
+ location = glGetUniformLocation( mProgramObject, "permTexture" );
+ if( location != -1 ) {
+ glUniform1i( location, 1 ); // texture unit 1
+ }
+
+ location = glGetUniformLocation( mProgramObject, "enteringSlideTexture" );
+ if( location != -1 ) {
+ glUniform1i( location, 2 ); // texture unit 2
+ }
+ }
+#endif
+}
+
+void OGLTransitionImpl::prepareStatic( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
+{
+ //mProgramObject = LinkProgram( basicVertexShader, staticFragmentShader );
+ NSString * _basicVertexShader = (NSString *) basicVertexShader;
+ NSString * _staticFragmentShader = (NSString *) staticFragmentShader;
+ OGLShaders * anOGLShader = NULL;
+ mProgramObject = [anOGLShader loadVertexShader: _basicVertexShader fragmentShader: _staticFragmentShader];
+
+ preparePermShader();
+}
+
+void OGLTransitionImpl::displaySlidesShaders( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ GLint location = glGetUniformLocation( mProgramObject, "time" );
+ if( location != -1 ) {
+ glUniform1f( location, nTime );
+ }
+ }
+
+ glActiveTexture( GL_TEXTURE2 );
+ glBindTexture( GL_TEXTURE_2D, glEnteringSlideTex );
+ glActiveTexture( GL_TEXTURE0 );
+#endif
+
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+}
+
+void OGLTransitionImpl::makeStatic()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
+ mmPrepareTransition = &OGLTransitionImpl::prepareStatic;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+
+ mnRequiredGLVersion = 2.0;
+}
+
+void OGLTransitionImpl::prepareDissolve( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
+{
+ NSString * _basicVertexShader = (NSString *) basicVertexShader;
+ NSString * _dissolveFragmentShader = (NSString *) dissolveFragmentShader;
+// mProgramObject = loadVertexShader( _basicVertexShader, _dissolveFragmentShader );
+ OGLShaders * anOGLShader = NULL;
+ mProgramObject = [anOGLShader loadVertexShader: _basicVertexShader fragmentShader: _dissolveFragmentShader];
+
+ preparePermShader();
+}
+
+void OGLTransitionImpl::makeDissolve()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
+ mmPrepareTransition = &OGLTransitionImpl::prepareDissolve;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+
+ mnRequiredGLVersion = 2.0;
+}
+
+void OGLTransitionImpl::makeNewsflash()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),3000,true,0,0.5));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),true,0,0.5));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-10000, 0, 0),false, 0.5, 2));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.clear();
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),-3000,true,0.5,1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-100, 0, 0),false, -1, 1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(100, 0, 0),false, 0.5, 1));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),false,-1,1));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(100,100,100),basegfx::B3DVector(0,0,0),true,0.5,1));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0.2,0.2,0),1080,true,0,1));
+}
+
diff --git a/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionerImpl.mm b/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionerImpl.mm
new file mode 100644
index 000000000000..9200f4c94f7c
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/OGLTrans_TransitionerImpl.mm
@@ -0,0 +1,1132 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define GLX_GLXEXT_PROTOTYPES 1
+#include "OGLTrans_TransitionImpl.hxx"
+
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/presentation/XTransitionFactory.hpp>
+#include <com/sun/star/presentation/XTransition.hpp>
+#include <com/sun/star/presentation/XSlideShowView.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/geometry/IntegerSize2D.hpp>
+
+#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/factory.hxx>
+#include <rtl/ref.hxx>
+
+#include <comphelper/servicedecl.hxx>
+
+#include <canvas/canvastools.hxx>
+#include <tools/gen.hxx>
+#include <vcl/window.hxx>
+#include <vcl/syschild.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <boost/noncopyable.hpp>
+
+#include <premac.h>
+#include <Foundation/Foundation.h>
+#include <Cocoa/Cocoa.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#include <OpenGL/glext.h>
+#include "aquaOpenGLView.h"
+#include <postmac.h>
+
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+
+#ifdef DEBUG
+#include <boost/date_time/posix_time/posix_time.hpp>
+using namespace ::boost::posix_time;
+
+static ptime t1;
+static ptime t2;
+
+#define DBG(x) x
+#else
+#define DBG(x)
+#endif
+
+using namespace ::com::sun::star;
+using ::com::sun::star::beans::XFastPropertySet;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+
+namespace
+{
+
+typedef cppu::WeakComponentImplHelper1<presentation::XTransition> OGLTransitionerImplBase;
+
+namespace
+{
+ struct OGLFormat
+ {
+ GLint nInternalFormat;
+ GLenum eFormat;
+ GLenum eType;
+ };
+
+ /* channel ordering: (0:rgba, 1:bgra, 2:argb, 3:abgr)
+ */
+ int calcComponentOrderIndex(const uno::Sequence<sal_Int8>& rTags)
+ {
+ using namespace rendering::ColorComponentTag;
+
+ static const sal_Int8 aOrderTable[] =
+ {
+ RGB_RED, RGB_GREEN, RGB_BLUE, ALPHA,
+ RGB_BLUE, RGB_GREEN, RGB_RED, ALPHA,
+ ALPHA, RGB_RED, RGB_GREEN, RGB_BLUE,
+ ALPHA, RGB_BLUE, RGB_GREEN, RGB_RED,
+ };
+
+ const sal_Int32 nNumComps(rTags.getLength());
+ const sal_Int8* pLine=aOrderTable;
+ for(int i=0; i<4; ++i)
+ {
+ int j=0;
+ while( j<4 && j<nNumComps && pLine[j] == rTags[j] )
+ ++j;
+
+ // all of the line passed, this is a match!
+ if( j==nNumComps )
+ return i;
+
+ pLine+=4;
+ }
+
+ return -1;
+ }
+}
+
+/** This is the Transitioner class for OpenGL 3D transitions in
+ * slideshow. This class is implicitly
+ * constructed from XTransitionFactory.
+*/
+class OGLTransitionerImpl : private cppu::BaseMutex, private boost::noncopyable, public OGLTransitionerImplBase
+{
+public:
+ explicit OGLTransitionerImpl(OGLTransitionImpl* pOGLTransition);
+ bool initWindowFromSlideShowView( const uno::Reference< presentation::XSlideShowView >& xView );
+ void setSlides( const Reference< rendering::XBitmap >& xLeavingSlide , const uno::Reference< rendering::XBitmap >& xEnteringSlide );
+ static bool initialize( const Reference< presentation::XSlideShowView >& xView );
+
+ // XTransition
+ virtual void SAL_CALL update( double nTime )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL viewChanged( const Reference< presentation::XSlideShowView >& rView,
+ const Reference< rendering::XBitmap >& rLeavingBitmap,
+ const Reference< rendering::XBitmap >& rEnteringBitmap )
+ throw (uno::RuntimeException);
+
+protected:
+ void disposeContextAndWindow();
+ void disposeTextures();
+
+ // WeakComponentImplHelperBase
+ virtual void SAL_CALL disposing();
+
+ bool isDisposed() const
+ {
+ return (rBHelper.bDisposed || rBHelper.bInDispose);
+ }
+
+// bool createWindow( Window* pPWindow );
+ void createTexture(GLuint* texID,
+ bool useMipmap,
+ uno::Sequence<sal_Int8>& data,
+ const OGLFormat* pFormat );
+ void prepareEnvironment ();
+ const OGLFormat* chooseFormats();
+
+private:
+ /** After the window has been created, and the slides have been set, we'll initialize the slides with OpenGL.
+ */
+ void GLInitSlides();
+
+
+ /// Holds the information of our new child window
+ struct GLWindow
+ {
+ AquaOpenGLView* pAquaOpenGLView; // Custom Cocoa NSOpenGLView
+ NSOpenGLContext* pOpenGLContext; // our OpenGLContext
+ NSRect aInitFrame;
+ NSView* apView;
+ NSScreen* screen;
+ unsigned int bpp;
+ unsigned int Width;
+ unsigned int Height;
+ const char* GLXExtensions;
+ const GLubyte* GLExtensions;
+
+ bool HasGLXExtension( const char* name ) { return gluCheckExtension( (const GLubyte*) name, (const GLubyte*) GLXExtensions ); }
+ bool HasGLExtension( const char* name ) { return gluCheckExtension( (const GLubyte*) name, GLExtensions ); }
+ } GLWin;
+
+ /** OpenGL handle to the leaving slide's texture
+ */
+#if defined(MAC_OS_X_VERSION_10_5) || defined(MAC_OS_X_VERSION_10_6)
+ GLuint GLleavingSlide;
+#else /* build target 10.4 */
+ unsigned long int GLleavingSlide;
+#endif
+
+ /** OpenGL handle to the entering slide's texture
+ */
+#if defined(MAC_OS_X_VERSION_10_5) || defined(MAC_OS_X_VERSION_10_6)
+ GLuint GLenteringSlide;
+#else /* build target 10.4 */
+ unsigned long int GLenteringSlide;
+#endif
+
+ /** pointer to our window which we MIGHT create.
+ */
+ class SystemChildWindow* pWindow;
+
+ Reference< presentation::XSlideShowView > mxView;
+ Reference< rendering::XIntegerBitmap > mxLeavingBitmap;
+ Reference< rendering::XIntegerBitmap > mxEnteringBitmap;
+
+ /** raw bytes of the entering bitmap
+ */
+ uno::Sequence<sal_Int8> EnteringBytes;
+
+ /** raw bytes of the leaving bitmap
+ */
+ uno::Sequence<sal_Int8> LeavingBytes;
+ bool mbRestoreSync;
+ bool mbUseLeavingPixmap;
+ bool mbUseEnteringPixmap;
+ bool mbFreeLeavingPixmap;
+ bool mbFreeEnteringPixmap;
+// unx::Pixmap maLeavingPixmap;
+// unx::Pixmap maEnteringPixmap;
+
+ /** the form the raw bytes are in for the bitmaps
+ */
+ rendering::IntegerBitmapLayout SlideBitmapLayout;
+
+ /** the size of the slides
+ */
+ geometry::IntegerSize2D SlideSize;
+
+ /** Our Transition to be used.
+ */
+ OGLTransitionImpl* pTransition;
+
+public:
+ /** whether we are running on ATI fglrx with bug related to textures
+ */
+ static bool cbBrokenTexturesATI;
+
+ /** GL version
+ */
+ static float cnGLVersion;
+
+ /** Whether Mesa is the OpenGL vendor
+ */
+
+ static bool cbMesa;
+
+ /**
+ whether the display has GLX extension
+ */
+ static bool cbGLXPresent;
+
+ /**
+ whether texture from pixmap extension is available
+ */
+ bool mbTextureFromPixmap;
+
+ /**
+ whether to generate mipmaped textures
+ */
+ bool mbGenerateMipmap;
+
+ /**
+ whether we have visual which can be used for texture_from_pixmap extension
+ */
+// bool mbHasTFPVisual;
+
+#ifdef DEBUG
+ ptime t3;
+ ptime t4;
+ ptime t5;
+ ptime t6;
+ time_duration total_update;
+ int frame_count;
+#endif
+};
+
+// declare the static variables as some gcc versions have problems declaring them automaticaly
+/**/
+bool OGLTransitionerImpl::cbBrokenTexturesATI;
+
+float OGLTransitionerImpl::cnGLVersion;
+/**/
+bool OGLTransitionerImpl::cbMesa;
+
+bool OGLTransitionerImpl::cbGLXPresent;
+
+
+bool OGLTransitionerImpl::initialize( const Reference< presentation::XSlideShowView >& xView )
+{
+ // not thread safe
+
+ // only once. This part is needed for the hardware identification
+ // [FIXME]: is there a Mac way of doing that ?
+ static bool initialized = false;
+
+ if( !initialized ) {
+ OGLTransitionerImpl *instance;
+
+ instance = new OGLTransitionerImpl( NULL );
+ if( instance->initWindowFromSlideShowView( xView ) )
+
+ {
+ const GLubyte* version = glGetString( GL_VERSION );
+ if( version && version[0] ) {
+ cnGLVersion = version[0] - '0';
+ if( version[1] == '.' && version[2] )
+ cnGLVersion += (version[2] - '0')/10.0;
+ } else
+ cnGLVersion = 1.0;
+ OSL_TRACE("GL version: %s parsed: %f", version, cnGLVersion );
+
+ const GLubyte* vendor = glGetString( GL_VENDOR );
+ cbMesa = ( vendor && strstr( (const char *) vendor, "Mesa" ) );
+ OSL_TRACE("GL vendor: %s identified as Mesa: %d", vendor, cbMesa );
+
+ /* TODO: check for version once the bug in fglrx driver is fixed */
+ cbBrokenTexturesATI = (vendor && strcmp( (const char *) vendor, "ATI Technologies Inc." ) == 0 );
+
+ instance->disposing();
+ cbGLXPresent = true;
+ } else
+ cbGLXPresent = false;
+
+ delete instance;
+ initialized = true;
+ }
+
+ return cbGLXPresent;
+}
+
+/*bool OGLTransitionerImpl::createWindow( Window* pPWindow )
+{
+ const SystemEnvData* sysData(pPWindow->GetSystemData());
+
+ GLWin.apView = sysData->pView;
+
+ NSOpenGLPixelFormat* fmt = [AquaOpenGLView defaultPixelFormat];
+ Window *pFrameWindow = pPWindow->GetWindow(WINDOW_FRAME);
+ Size aFrameSize( pFrameWindow->GetSizePixel() );
+ Point aScreen( pPWindow->OutputToScreenPixel( Point() ) );
+ GLWin.aInitFrame = (NSRect){ { aScreen.X(), aFrameSize.Height() - GLWin.Height - aScreen.Y() }, { GLWin.Width, GLWin.Height } };
+
+ GLWin.pAquaOpenGLView = [[NSOpenGLView alloc]initWithFrame: GLWin.aInitFrame pixelFormat: fmt];
+ OSL_ENSURE(GLWin.pAquaOpenGLView, "Could not create NSOPenGLView");
+ if( !GLWin.pAquaOpenGLView )
+ return false;
+//
+ GLWin.pOpenGLContext = [GLWin.pAquaOpenGLView openGLContext];
+ [GLWin.pOpenGLContext retain];
+ [GLWin.pAquaOpenGLView setOpenGLContext:GLWin.pOpenGLContext];
+ [sysData->pView addSubview:GLWin.pAquaOpenGLView];
+//
+ if( pWindow )
+ {
+ pWindow->SetMouseTransparent( sal_True );
+ pWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ pWindow->EnableEraseBackground( sal_False );
+ pWindow->SetControlForeground();
+ pWindow->SetControlBackground();
+ pWindow->EnablePaint(sal_False);
+ pWindow->SetPosSizePixel(pPWindow->GetPosPixel(),pPWindow->GetSizePixel());
+ // GLWin.dpy = reinterpret_cast<unx::Display*>(pChildSysData->pDisplay);
+// GLWin.win = pChildSysData->aWindow;
+
+ return true;
+ }
+
+ return false;
+}
+*/
+
+bool OGLTransitionerImpl::initWindowFromSlideShowView( const Reference< presentation::XSlideShowView >& xView )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ mxView.set( xView, UNO_QUERY );
+ if( !mxView.is() )
+ return false;
+
+ /// take the XSlideShowView and extract the parent window from it. see viewmediashape.cxx
+ uno::Reference< rendering::XCanvas > xCanvas(mxView->getCanvas(), uno::UNO_QUERY_THROW);
+ uno::Sequence< uno::Any > aDeviceParams;
+ ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams );
+
+ ::rtl::OUString aImplName;
+ aDeviceParams[ 0 ] >>= aImplName;
+
+ sal_Int64 aVal = 0;
+ aDeviceParams[1] >>= aVal;
+ Window* pPWindow = reinterpret_cast< Window* >( aVal );
+ GLWin.Width = pPWindow->GetSizePixel().Width();
+ GLWin.Height = pPWindow->GetSizePixel().Height();
+
+ const SystemEnvData* sysData(pPWindow->GetSystemData());
+
+ GLWin.apView = sysData->pView;
+
+ NSOpenGLPixelFormat* fmt = [AquaOpenGLView defaultPixelFormat];
+ Window *pFrameWindow = pPWindow->GetWindow(WINDOW_FRAME);
+ Size aFrameSize( pFrameWindow->GetSizePixel() );
+ Point aScreen( pPWindow->OutputToScreenPixel( Point() ) );
+ GLWin.aInitFrame = (NSRect){ { aScreen.X(), aFrameSize.Height() - GLWin.Height - aScreen.Y() }, { GLWin.Width, GLWin.Height } };
+
+ GLWin.pAquaOpenGLView = [[NSOpenGLView alloc]initWithFrame: GLWin.aInitFrame pixelFormat: fmt];
+ OSL_ENSURE(GLWin.pAquaOpenGLView, "Could not create NSOPenGLView");
+ if( !GLWin.pAquaOpenGLView )
+ return false;
+
+ GLWin.pOpenGLContext = [GLWin.pAquaOpenGLView openGLContext];
+ [GLWin.pOpenGLContext retain];
+ [GLWin.pAquaOpenGLView setOpenGLContext:GLWin.pOpenGLContext];
+
+ if( GLWin.pOpenGLContext == NULL ) {
+ OSL_TRACE("unable to create GLX context");
+ return false;
+ }
+
+ awt::Rectangle aCanvasArea = mxView->getCanvasArea();
+
+ // needed in windowed mode only ?
+ if( (aCanvasArea.X != 0) && (aCanvasArea.Y != 0) )
+ pWindow->SetPosSizePixel(aCanvasArea.X, aCanvasArea.Y, aCanvasArea.Width, aCanvasArea.Height);
+
+ GLWin.Width = aCanvasArea.Width;
+ GLWin.Height = aCanvasArea.Height;
+ OSL_TRACE("canvas area: %d,%d - %dx%d", aCanvasArea.X, aCanvasArea.Y, aCanvasArea.Width, aCanvasArea.Height);
+
+ mbTextureFromPixmap = GLWin.HasGLXExtension( "GLX_EXT_texture_from_pixmap" );
+ mbGenerateMipmap = GLWin.HasGLExtension( "GL_SGIS_generate_mipmap" );
+
+ [GLWin.apView addSubview:GLWin.pAquaOpenGLView];
+
+ if( pWindow )
+ {
+ pWindow->SetMouseTransparent( sal_True );
+ pWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ pWindow->EnableEraseBackground( sal_False );
+ pWindow->SetControlForeground();
+ pWindow->SetControlBackground();
+ pWindow->EnablePaint(sal_False);
+ pWindow->SetPosSizePixel(pPWindow->GetPosPixel(),pPWindow->GetSizePixel());
+
+ }
+
+
+ glShadeModel( GL_SMOOTH );
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glClearColor (0.0f, 0.0f, 0.0f, 0.0f); // R G B A
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearDepth( 1.0f );
+ glEnable( GL_DEPTH_TEST );
+ glDepthFunc( GL_LEQUAL );
+ glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+ glEnable(GL_TEXTURE_2D);
+
+ glEnable(GL_LIGHTING);
+ GLfloat light_direction[] = { 0.0 , 0.0 , 1.0 };
+ GLfloat materialDiffuse[] = { 1.0 , 1.0 , 1.0 , 1.0};
+ glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
+ glMaterialfv(GL_FRONT,GL_DIFFUSE,materialDiffuse);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_NORMALIZE);
+
+ [[GLWin.pAquaOpenGLView openGLContext] flushBuffer];
+
+ if( LeavingBytes.hasElements() && EnteringBytes.hasElements())
+ GLInitSlides();//we already have uninitialized slides, let's initialize
+
+ if( pTransition && pTransition->mnRequiredGLVersion <= cnGLVersion )
+ pTransition->prepare( GLleavingSlide, GLenteringSlide );
+
+ return true;
+}
+
+void OGLTransitionerImpl::setSlides( const uno::Reference< rendering::XBitmap >& xLeavingSlide,
+ const uno::Reference< rendering::XBitmap >& xEnteringSlide )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ mxLeavingBitmap.set( xLeavingSlide , UNO_QUERY_THROW );
+ mxEnteringBitmap.set( xEnteringSlide , UNO_QUERY_THROW );
+ Reference< XFastPropertySet > xLeavingSet( xLeavingSlide , UNO_QUERY );
+ Reference< XFastPropertySet > xEnteringSet( xEnteringSlide , UNO_QUERY );
+
+ geometry::IntegerRectangle2D SlideRect;
+ SlideSize = mxLeavingBitmap->getSize();
+ SlideRect.X1 = 0;
+ SlideRect.X2 = SlideSize.Width;
+ SlideRect.Y1 = 0;
+ SlideRect.Y2 = SlideSize.Height;
+
+ OSL_TRACE("leaving bitmap area: %dx%d", SlideSize.Width, SlideSize.Height);
+ SlideSize = mxEnteringBitmap->getSize();
+ OSL_TRACE("entering bitmap area: %dx%d", SlideSize.Width, SlideSize.Height);
+
+#ifdef DEBUG
+ t1 = microsec_clock::local_time();
+#endif
+
+ mbUseLeavingPixmap = false;
+ mbUseEnteringPixmap = false;
+
+ if( !mbUseLeavingPixmap )
+ LeavingBytes = mxLeavingBitmap->getData(SlideBitmapLayout,SlideRect);
+ if( !mbUseEnteringPixmap )
+ EnteringBytes = mxEnteringBitmap->getData(SlideBitmapLayout,SlideRect);
+
+ if(GLWin.pOpenGLContext)//if we have a rendering context, let's init the slides
+ GLInitSlides();
+
+ OSL_ENSURE(SlideBitmapLayout.PlaneStride == 0,"only handle no plane stride now");
+
+ /* flush & sync */
+ mbRestoreSync = true;
+}
+
+void OGLTransitionerImpl::createTexture( GLuint* texID,
+//#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+// unx::GLXPixmap pixmap,
+// bool usePixmap,
+//#endif
+ bool useMipmap,
+ uno::Sequence<sal_Int8>& data,
+ const OGLFormat* pFormat )
+{
+ glDeleteTextures( 1, texID );
+ glGenTextures( 1, texID );
+ glBindTexture( GL_TEXTURE_2D, *texID );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+/*
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::PFNGLXBINDTEXIMAGEEXTPROC myglXBindTexImageEXT = (unx::PFNGLXBINDTEXIMAGEEXTPROC) unx::glXGetProcAddress( (const GLubyte*) "glXBindTexImageEXT" );
+
+ if( usePixmap ) {
+ if( mbGenerateMipmap )
+ glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, True);
+ myglXBindTexImageEXT (GLWin.dpy, pixmap, GLX_FRONT_LEFT_EXT, NULL);
+ if( mbGenerateMipmap && useMipmap ) {
+ OSL_TRACE("use mipmaps");
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //TRILINEAR FILTERING
+ } else {
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+ }
+ } else {
+#endif
+*/
+ if( !pFormat )
+ {
+ // force-convert color to ARGB8888 int color space
+ uno::Sequence<sal_Int8> tempBytes(
+ SlideBitmapLayout.ColorSpace->convertToIntegerColorSpace(
+ data,
+ canvas::tools::getStdColorSpace()));
+ gluBuild2DMipmaps(GL_TEXTURE_2D,
+ 4,
+ SlideSize.Width,
+ SlideSize.Height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ &tempBytes[0]);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //TRILINEAR FILTERING
+
+ //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles)
+ GLfloat largest_supported_anisotropy;
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy);
+ } else {
+ if( pTransition && !cbBrokenTexturesATI && !useMipmap) {
+ glTexImage2D( GL_TEXTURE_2D, 0, pFormat->nInternalFormat, SlideSize.Width, SlideSize.Height, 0, pFormat->eFormat, pFormat->eType, &data[0] );
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+ } else {
+ gluBuild2DMipmaps( GL_TEXTURE_2D, pFormat->nInternalFormat, SlideSize.Width, SlideSize.Height, pFormat->eFormat, pFormat->eType, &data[0] );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); //TRILINEAR FILTERING
+
+ //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles)
+ GLfloat largest_supported_anisotropy;
+ glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy );
+ }
+ }
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ }
+#endif
+ OSL_ENSURE(glIsTexture(*texID), "Can't generate Leaving slide textures in OpenGL");
+}
+
+void OGLTransitionerImpl::prepareEnvironment()
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ double EyePos(10.0);
+ double RealF(1.0);
+ double RealN(-1.0);
+ double RealL(-1.0);
+ double RealR(1.0);
+ double RealB(-1.0);
+ double RealT(1.0);
+ double ClipN(EyePos+5.0*RealN);
+ double ClipF(EyePos+15.0*RealF);
+ double ClipL(RealL*8.0);
+ double ClipR(RealR*8.0);
+ double ClipB(RealB*8.0);
+ double ClipT(RealT*8.0);
+ //This scaling is to take the plane with BottomLeftCorner(-1,-1,0) and TopRightCorner(1,1,0) and map it to the screen after the perspective division.
+ glScaled( 1.0 / ( ( ( RealR * 2.0 * ClipN ) / ( EyePos * ( ClipR - ClipL ) ) ) - ( ( ClipR + ClipL ) / ( ClipR - ClipL ) ) ),
+ 1.0 / ( ( ( RealT * 2.0 * ClipN ) / ( EyePos * ( ClipT - ClipB ) ) ) - ( ( ClipT + ClipB ) / ( ClipT - ClipB ) ) ),
+ 1.0 );
+ glFrustum(ClipL,ClipR,ClipB,ClipT,ClipN,ClipF);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslated(0,0,-EyePos);
+}
+
+const OGLFormat* OGLTransitionerImpl::chooseFormats()
+{
+ const OGLFormat* pDetectedFormat=NULL;
+ uno::Reference<rendering::XIntegerBitmapColorSpace> xIntColorSpace(
+ SlideBitmapLayout.ColorSpace);
+
+ if( (xIntColorSpace->getType() == rendering::ColorSpaceType::RGB ||
+ xIntColorSpace->getType() == rendering::ColorSpaceType::SRGB) )
+ {
+ /* table for canvas->OGL format mapping. outer index is number
+ of color components (0:3, 1:4), then comes bits per pixel
+ (0:16, 1:24, 2:32), then channel ordering: (0:rgba, 1:bgra,
+ 2:argb, 3:abgr)
+ */
+ static const OGLFormat lcl_RGB24[] =
+ {
+ // 24 bit RGB
+ {3, GL_BGR, GL_UNSIGNED_BYTE},
+ {3, GL_RGB, GL_UNSIGNED_BYTE},
+ {3, GL_BGR, GL_UNSIGNED_BYTE},
+ {3, GL_RGB, GL_UNSIGNED_BYTE}
+ };
+
+#if defined(GL_VERSION_1_2) && defined(GLU_VERSION_1_3)
+ // more format constants available
+ static const OGLFormat lcl_RGB16[] =
+ {
+ // 16 bit RGB
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}
+ };
+
+ static const OGLFormat lcl_ARGB16_4[] =
+ {
+ // 16 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4},
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}
+ };
+
+ static const OGLFormat lcl_ARGB16_5[] =
+ {
+ // 16 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_5_5_5_1},
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}
+ };
+
+ static const OGLFormat lcl_ARGB32[] =
+ {
+ // 32 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
+ {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV},
+ {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8},
+ {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}
+ };
+
+ const uno::Sequence<sal_Int8> aComponentTags(
+ xIntColorSpace->getComponentTags());
+ const uno::Sequence<sal_Int32> aComponentBitcounts(
+ xIntColorSpace->getComponentBitCounts());
+ const sal_Int32 nNumComponents( aComponentBitcounts.getLength() );
+ const sal_Int32 nBitsPerPixel( xIntColorSpace->getBitsPerPixel() );
+
+ // supported component ordering?
+ const int nComponentOrderIndex(
+ calcComponentOrderIndex(aComponentTags));
+ if( nComponentOrderIndex != -1 )
+ {
+ switch( nBitsPerPixel )
+ {
+ case 16:
+ if( nNumComponents == 3 )
+ {
+ pDetectedFormat = &lcl_RGB16[nComponentOrderIndex];
+ }
+ else if( nNumComponents == 4 )
+ {
+ if( aComponentBitcounts[1] == 4 )
+ {
+ pDetectedFormat = &lcl_ARGB16_4[nComponentOrderIndex];
+ }
+ else if( aComponentBitcounts[1] == 5 )
+ {
+ pDetectedFormat = &lcl_ARGB16_5[nComponentOrderIndex];
+ }
+ }
+ break;
+ case 24:
+ if( nNumComponents == 3 )
+ {
+ pDetectedFormat = &lcl_RGB24[nComponentOrderIndex];
+ }
+ break;
+ case 32:
+ pDetectedFormat = &lcl_ARGB32[nComponentOrderIndex];
+ break;
+ }
+ }
+#else
+ const uno::Sequence<sal_Int8> aComponentTags(
+ xIntColorSpace->getComponentTags());
+ const int nComponentOrderIndex(calcComponentOrderIndex(aComponentTags));
+ if( aComponentTags.getLength() == 3 &&
+ nComponentOrderIndex != -1 &&
+ xIntColorSpace->getBitsPerPixel() == 24 )
+ {
+ pDetectedFormat = &lcl_RGB24[nComponentOrderIndex];
+ }
+#endif
+ }
+
+ return pDetectedFormat;
+}
+
+void OGLTransitionerImpl::GLInitSlides()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed() || pTransition->mnRequiredGLVersion > cnGLVersion)
+ return;
+
+ prepareEnvironment();
+
+ const OGLFormat* pFormat = NULL;
+ if( !mbUseLeavingPixmap || !mbUseEnteringPixmap )
+ pFormat = chooseFormats();
+
+ createTexture( &GLleavingSlide,
+ pTransition->mbUseMipMapLeaving,
+ LeavingBytes,
+ pFormat );
+
+ createTexture( &GLenteringSlide,
+
+ pTransition->mbUseMipMapEntering,
+ EnteringBytes,
+ pFormat );
+
+#ifdef DEBUG
+ t2 = microsec_clock::local_time();
+ OSL_TRACE("textures created in: %s", to_simple_string( t2 - t1 ).c_str());
+#endif
+}
+
+void SAL_CALL OGLTransitionerImpl::update( double nTime ) throw (uno::RuntimeException)
+{
+#ifdef DEBUG
+ frame_count ++;
+ t3 = microsec_clock::local_time();
+ if( frame_count == 1 ) {
+ t5 = t3;
+ total_update = seconds (0);
+ }
+#endif
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed() || !cbGLXPresent || pTransition->mnRequiredGLVersion > cnGLVersion)
+ return;
+
+ if(GLWin.pOpenGLContext)
+ [GLWin.pOpenGLContext makeCurrentContext];
+
+ glEnable(GL_DEPTH_TEST);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+/*
+ if(pTransition)
+ pTransition->display( nTime, GLleavingSlide, GLenteringSlide,
+ SlideSize.Width, SlideSize.Height,
+ static_cast<double>(GLWin.Width),
+ static_cast<double>(GLWin.Height) );
+*/
+ // works but not mandatory
+#if defined(MAC_OS_X_VERSION_10_5)
+ long int swapInt = 1;
+#else /* build target 10.4 */
+ long swapInt = 1;
+#endif
+ [[GLWin.pAquaOpenGLView openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; // set to vbl sync
+
+ NSOpenGLContext* context = [GLWin.pAquaOpenGLView openGLContext];
+ [context makeCurrentContext];
+
+ if(pTransition)
+ pTransition->display( nTime, GLleavingSlide, GLenteringSlide,
+ SlideSize.Width, SlideSize.Height,
+ static_cast<double>(GLWin.Width),
+ static_cast<double>(GLWin.Height) );
+
+
+ [context flushBuffer];
+
+ if( pWindow )
+ pWindow->Show();
+
+#ifdef DEBUG
+ t4 = microsec_clock::local_time();
+
+ OSL_TRACE("update time: %f", nTime);
+ OSL_TRACE("update took: %s", to_simple_string( t4 - t3 ).c_str());
+ total_update += (t4 - t3);
+#endif
+}
+
+void SAL_CALL OGLTransitionerImpl::viewChanged( const Reference< presentation::XSlideShowView >& rView,
+ const Reference< rendering::XBitmap >& rLeavingBitmap,
+ const Reference< rendering::XBitmap >& rEnteringBitmap )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE("transitioner: view changed");
+
+ disposeTextures();
+ disposeContextAndWindow();
+
+ initWindowFromSlideShowView( rView );
+
+ setSlides( rLeavingBitmap, rEnteringBitmap );
+}
+
+void OGLTransitionerImpl::disposeContextAndWindow()
+{
+ /*
+ if(GLWin.pOpenGLContext)
+ [GLWin.pOpenGLContext makeCurrentContext];
+ if( glGetError() != GL_NO_ERROR )
+ {
+ OSL_TRACE("glError: %s", (char *)gluErrorString(glGetError()));
+ if(GLWin.pOpenGLContext)
+ [GLWin.pOpenGLContext clearGLContext];
+ }
+*/
+ if(GLWin.pAquaOpenGLView)
+ {
+ [GLWin.pAquaOpenGLView clearGLContext];// currentContext]; //clearCurrentContext];
+ [GLWin.pAquaOpenGLView willRemoveSubview:GLWin.apView];
+ [GLWin.pAquaOpenGLView removeFromSuperview];
+ [GLWin.pAquaOpenGLView release];
+ }
+
+ if( pWindow )
+ {
+ delete pWindow;
+ pWindow = NULL;
+ GLWin.pAquaOpenGLView = nil;
+ }
+}
+
+void OGLTransitionerImpl::disposeTextures()
+{
+ if(GLWin.pOpenGLContext)
+ [GLWin.pOpenGLContext makeCurrentContext];
+
+ if( !mbUseLeavingPixmap )
+ {
+ glDeleteTextures(1,&GLleavingSlide);
+ GLleavingSlide = 0;
+ }
+
+ if( !mbUseEnteringPixmap )
+ {
+ glDeleteTextures(1,&GLenteringSlide);
+ GLleavingSlide = 0;
+ }
+
+ mbUseLeavingPixmap = false;
+ mbUseEnteringPixmap = false;
+}
+
+// we are about to be disposed (someone call dispose() on us)
+void OGLTransitionerImpl::disposing()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+#ifdef DEBUG
+ OSL_TRACE("dispose %p\n", this);
+ if( frame_count ) {
+ t6 = microsec_clock::local_time();
+ time_duration duration = t6 - t5;
+ OSL_TRACE("whole transition (frames: %d) took: %s fps: %f time spent in updates: %s percentage of transition time: %f%%",
+ frame_count, to_simple_string( duration ).c_str(),
+ ((double)frame_count*1000000000.0)/duration.total_nanoseconds(),
+ to_simple_string( total_update ).c_str(),
+ 100*(((double)total_update.total_nanoseconds())/((double)duration.total_nanoseconds()))
+ );
+ }
+#endif
+
+ if( pWindow )
+ {
+ disposeTextures();
+
+ if (pTransition)
+ pTransition->finish();
+
+ disposeContextAndWindow();
+ }
+
+ if (pTransition)
+ delete pTransition;
+
+ mxLeavingBitmap.clear();
+ mxEnteringBitmap.clear();
+ mxView.clear();
+}
+
+OGLTransitionerImpl::OGLTransitionerImpl(OGLTransitionImpl* pOGLTransition) :
+ OGLTransitionerImplBase(m_aMutex),
+ GLWin(),
+ GLleavingSlide( 0 ),
+ GLenteringSlide( 0 ),
+ pWindow( NULL ),
+ mxView(),
+ EnteringBytes(),
+ LeavingBytes(),
+ mbRestoreSync( false ),
+ mbUseLeavingPixmap( false ),
+ mbUseEnteringPixmap( false ),
+ SlideBitmapLayout(),
+ SlideSize(),
+ pTransition(pOGLTransition)
+{
+ GLWin.pAquaOpenGLView = nil;
+ DBG(frame_count = 0);
+}
+
+typedef cppu::WeakComponentImplHelper1<presentation::XTransitionFactory> OGLTransitionFactoryImplBase;
+
+class OGLTransitionFactoryImpl : private cppu::BaseMutex, public OGLTransitionFactoryImplBase
+{
+public:
+ explicit OGLTransitionFactoryImpl( const uno::Reference< uno::XComponentContext >& ) :
+ OGLTransitionFactoryImplBase(m_aMutex)
+ {}
+
+ // XTransitionFactory
+ virtual ::sal_Bool SAL_CALL hasTransition( ::sal_Int16 transitionType, ::sal_Int16 transitionSubType ) throw (uno::RuntimeException)
+ {
+ if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) {
+ switch( transitionSubType )
+ {
+ case animations::TransitionSubType::ACROSS:
+ case animations::TransitionSubType::CORNERSOUT:
+ case animations::TransitionSubType::CIRCLE:
+ case animations::TransitionSubType::FANOUTHORIZONTAL:
+ case animations::TransitionSubType::CORNERSIN:
+ case animations::TransitionSubType::LEFTTORIGHT:
+ case animations::TransitionSubType::TOPTOBOTTOM:
+ case animations::TransitionSubType::TOPRIGHT:
+ case animations::TransitionSubType::TOPLEFT:
+ case animations::TransitionSubType::BOTTOMRIGHT:
+ case animations::TransitionSubType::BOTTOMLEFT:
+ case animations::TransitionSubType::TOPCENTER:
+ case animations::TransitionSubType::RIGHTCENTER:
+ case animations::TransitionSubType::BOTTOMCENTER:
+ return sal_True;
+
+ default:
+ return sal_False;
+ }
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) {
+ return sal_True;
+ } else
+ return sal_False;
+ }
+
+ virtual uno::Reference< presentation::XTransition > SAL_CALL createTransition(
+ ::sal_Int16 transitionType,
+ ::sal_Int16 transitionSubType,
+ const uno::Reference< presentation::XSlideShowView >& view,
+ const uno::Reference< rendering::XBitmap >& leavingBitmap,
+ const uno::Reference< rendering::XBitmap >& enteringBitmap )
+ throw (uno::RuntimeException)
+ {
+ if( !hasTransition( transitionType, transitionSubType ) )
+ return uno::Reference< presentation::XTransition >();
+
+ bool bGLXPresent = OGLTransitionerImpl::initialize( view );
+
+ if(
+ ( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) ||
+ ( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) ||
+ ( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) )
+ return uno::Reference< presentation::XTransition >();
+
+
+ OGLTransitionImpl* pTransition = NULL;
+
+ if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) {
+ pTransition = new OGLTransitionImpl();
+ switch( transitionSubType )
+ {
+ case animations::TransitionSubType::ACROSS:
+ pTransition->makeNByMTileFlip(8,6);
+ break;
+ case animations::TransitionSubType::CORNERSOUT:
+ pTransition->makeOutsideCubeFaceToLeft();
+ break;
+ case animations::TransitionSubType::CIRCLE:
+ pTransition->makeRevolvingCircles(8,128);
+ break;
+ case animations::TransitionSubType::FANOUTHORIZONTAL:
+ pTransition->makeHelix(20);
+ break;
+ case animations::TransitionSubType::CORNERSIN:
+ pTransition->makeInsideCubeFaceToLeft();
+ break;
+ case animations::TransitionSubType::LEFTTORIGHT:
+ pTransition->makeFallLeaving();
+ break;
+ case animations::TransitionSubType::TOPTOBOTTOM:
+ pTransition->makeTurnAround();
+ break;
+ case animations::TransitionSubType::TOPRIGHT:
+ pTransition->makeTurnDown();
+ break;
+ case animations::TransitionSubType::TOPLEFT:
+ pTransition->makeIris();
+ break;
+ case animations::TransitionSubType::BOTTOMRIGHT:
+ pTransition->makeRochade();
+ break;
+ case animations::TransitionSubType::BOTTOMLEFT:
+ pTransition->makeVenetianBlinds( true, 8 );
+ break;
+ case animations::TransitionSubType::TOPCENTER:
+ pTransition->makeVenetianBlinds( false, 6 );
+ break;
+ case animations::TransitionSubType::RIGHTCENTER:
+ pTransition->makeStatic();
+ break;
+ case animations::TransitionSubType::BOTTOMCENTER:
+ pTransition->makeDissolve();
+ break;
+ }
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeFadeSmoothly();
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeFadeThroughBlack();
+ } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeDiamond();
+ } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeNewsflash();
+ }
+
+ rtl::Reference<OGLTransitionerImpl> xRes(
+ new OGLTransitionerImpl(pTransition) );
+ if( bGLXPresent ) {
+ if( !xRes->initWindowFromSlideShowView(view))
+ return uno::Reference< presentation::XTransition >();
+ xRes->setSlides(leavingBitmap,enteringBitmap);
+ }
+
+ return uno::Reference<presentation::XTransition>(xRes.get());
+ }
+};
+
+}
+
+namespace sdecl = comphelper::service_decl;
+#if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)
+ sdecl::class_<OGLTransitionFactoryImpl> serviceImpl;
+ const sdecl::ServiceDecl OGLTransitionFactoryDecl(
+ serviceImpl,
+#else
+ const sdecl::ServiceDecl OGLTransitionFactoryDecl(
+ sdecl::class_<OGLTransitionFactoryImpl>(),
+#endif
+ "com.sun.star.comp.presentation.OGLTransitionFactory",
+ "com.sun.star.presentation.TransitionFactory" );
+
+// The C shared lib entry points
+COMPHELPER_SERVICEDECL_EXPORTS1(OGLTransitionFactoryDecl)
diff --git a/slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.h b/slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.h
new file mode 100644
index 000000000000..b4b8f9fd5f73
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * aquaOpenGLView.h
+ */
+
+@class NSOpenGLContext, NSOpenGLPixelFormat;
+
+// the most interesting is there : in OGLTrans, we use an NSView*
+// and subclass the NSView to create an OpenGLView does the trick
+
+@interface AquaOpenGLView : NSView
+{
+ @private
+ NSOpenGLContext* _openGLContext;
+ NSOpenGLPixelFormat* _pixelFormat;
+}
+
++ (NSOpenGLPixelFormat*)defaultPixelFormat;
+
+- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format;
+- (void)dealloc;
+- (void)setOpenGLContext:(NSOpenGLContext*)context;
+- (NSOpenGLContext*)openGLContext;
+- (void)clearGLContext;
+- (void)prepareOpenGL;
+- (BOOL)isOpaque;
+- (void)drawRect;
+- (void)lockFocus;
+- (void)update; // moved or resized
+// reshape is not supported, update bounds in drawRect
+- (void) _surfaceNeedsUpdate:(NSNotification*)notification;
+- (void)setPixelFormat:(NSOpenGLPixelFormat*)pixelFormat;
+- (NSOpenGLPixelFormat*)pixelFormat;
+- (void)encodeWithCoder:(NSCoder *)coder;
+- (id)initWithCoder:(NSCoder *)coder;
+
+@end
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.m b/slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.m
new file mode 100644
index 000000000000..b2c22c0bcb0b
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/aquaOpenGLView.m
@@ -0,0 +1,195 @@
+/*
+ * aquaOpenGLView.m
+ */
+
+#include <Cocoa/Cocoa.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+
+#include "aquaOpenGLView.h"
+
+@implementation AquaOpenGLView
+
++ (NSOpenGLPixelFormat*)defaultPixelFormat
+{
+// first simple implementation (let's see later with more complex )
+ NSOpenGLPixelFormatAttribute attributes [] =
+ {
+ NSOpenGLPFAWindow,
+ NSOpenGLPFADoubleBuffer, // double buffered
+ NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer
+ (NSOpenGLPixelFormatAttribute)nil
+ };
+ return [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
+}
+
+- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format
+{
+ self = [super initWithFrame:frameRect];
+ if (self != nil) {
+ _pixelFormat = [format retain];
+ }
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_surfaceNeedsUpdate:) name:NSViewGlobalFrameDidChangeNotification object:self];
+ return self;
+}
+
+- (void)dealloc
+{ // get rid of the context and pixel format
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewGlobalFrameDidChangeNotification object:self];
+ [self clearGLContext];
+ if (_pixelFormat)
+ [_pixelFormat release];
+
+ [super dealloc];
+}
+
+- (void)setOpenGLContext:(NSOpenGLContext*)context
+{
+ [self clearGLContext];
+ _openGLContext = [context retain];
+}
+
+- (NSOpenGLContext*)openGLContext
+{ // create a context the first time through
+ if (_openGLContext == NULL) {
+ _openGLContext = [[NSOpenGLContext alloc] initWithFormat:_pixelFormat != nil ? _pixelFormat : [[self class] defaultPixelFormat] shareContext:nil];
+ [_openGLContext makeCurrentContext];
+ [self prepareOpenGL]; // call to initialize OpenGL state here
+ }
+ return _openGLContext;
+}
+
+- (void)clearGLContext
+{
+ if (_openGLContext != nil) {
+ if ([_openGLContext view] == self) {
+ [_openGLContext clearDrawable];
+ }
+ [_openGLContext release];
+ _openGLContext = nil;
+ }
+}
+
+- (void)prepareOpenGL
+{
+ // for overriding to initialize OpenGL state, occurs after context creation
+#ifdef MAC_OS_X_VERSION_10_4
+ long swapInt = 1;
+#else /* build target 10.5 */
+ int swapInt = 1;
+#endif
+
+ [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; // set to vbl sync
+
+ // init GL stuff here
+ // FIXME: why is there garbage using prepareOpenGL ,
+ // but NOT, wen using the same content,
+ // directly in the OGLTrans instance ?
+ glShadeModel( GL_SMOOTH );
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glClearColor (0.0f, 0.0f, 0.0f, 0.0f); // R G B A
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearDepth( 1.0f );
+ glEnable( GL_DEPTH_TEST );
+ glDepthFunc( GL_LEQUAL );
+ glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+ glEnable(GL_TEXTURE_2D);
+
+
+ glEnable(GL_LIGHTING);
+ GLfloat light_direction[] = { 0.0 , 0.0 , 1.0 };
+ GLfloat materialDiffuse[] = { 1.0 , 1.0 , 1.0 , 1.0};
+ glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
+ glMaterialfv(GL_FRONT,GL_DIFFUSE,materialDiffuse);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_NORMALIZE);
+
+ [[self openGLContext] flushBuffer];
+}
+
+- (BOOL)isOpaque
+{
+ return YES;
+}
+
+- (void)drawRect
+{
+ // get context. will create if we don't have one yet
+ NSOpenGLContext* context = [self openGLContext];
+ [context makeCurrentContext];
+ //perform drawing here
+ [context flushBuffer];
+}
+
+- (void)lockFocus
+{
+ // get context. will create if we don't have one yet
+ NSOpenGLContext* context = [self openGLContext];
+
+ // make sure we are ready to draw
+ [super lockFocus];
+
+ // when we are about to draw, make sure we are linked to the view
+ if ([context view] != self) {
+ [context setView:self];
+ }
+
+ // make us the current OpenGL context
+ [context makeCurrentContext];
+}
+
+// no reshape will be called since NSView does not export a specific reshape method
+
+- (void)update
+{
+ if ([_openGLContext view] == self) {
+ [_openGLContext update];
+ }
+}
+
+- (void) _surfaceNeedsUpdate:(NSNotification*)notification
+{
+ [self update];
+}
+
+- (void)setPixelFormat:(NSOpenGLPixelFormat*)pixelFormat
+{
+ [_pixelFormat release];
+ _pixelFormat = [pixelFormat retain];
+}
+
+- (NSOpenGLPixelFormat*)pixelFormat
+{
+ return _pixelFormat;
+}
+
+
+- (void)encodeWithCoder:(NSCoder *)coder
+{
+
+ [super encodeWithCoder:coder];
+ if (![coder allowsKeyedCoding]) {
+ [coder encodeValuesOfObjCTypes:"@iii", &_pixelFormat];
+ } else {
+ [coder encodeObject:_pixelFormat forKey:@"NSPixelFormat"];
+ }
+}
+
+- (id)initWithCoder:(NSCoder *)coder
+{
+
+ self = [super initWithCoder:coder];
+
+ if (![coder allowsKeyedCoding]) {
+ [coder decodeValuesOfObjCTypes:"@iii", &_pixelFormat];
+ } else {
+ _pixelFormat = [[coder decodeObjectForKey:@"NSPixelFormat"] retain];
+ }
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_surfaceNeedsUpdate:) name:NSViewGlobalFrameDidChangeNotification object:self];
+
+ return self;
+}
+
+@end
diff --git a/slideshow/source/engine/OGLTrans/mac/makefile.mk b/slideshow/source/engine/OGLTrans/mac/makefile.mk
new file mode 100644
index 000000000000..aaaedb9598dd
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/mac/makefile.mk
@@ -0,0 +1,87 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..$/..
+
+.IF "$(OS)" != "MACOSX"
+all:
+ @echo "Nothing to build for this platform"
+.ELIF "$(ENABLE_OPENGL)" != "TRUE"
+all:
+ @echo "Building without OpenGL transitions"
+.ENDIF
+
+
+PRJNAME=slideshow
+TARGET=OGLTrans
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+.IF "$(OS)"=="WNT"
+IMPL_SUBDIR=win
+.ELIF "$(OS)"=="MACOSX"
+IMPL_SUBDIR=mac
+.ELSE
+IMPL_SUBDIR=unx
+.ENDIF
+
+SLOFILES = \
+ $(SLO)$/OGLTrans_Shaders.obj \
+ $(SLO)$/OGLTrans_TransitionImpl.obj \
+ $(SLO)$/aquaOpenGLView.obj \
+ $(SLO)$/OGLTrans_TransitionerImpl.obj
+
+SHL1TARGET=$(TARGET).uno
+
+SHL1STDLIBS= $(SALLIB) $(VCLLIB) $(CPPULIB) $(CPPUHELPERLIB) $(COMPHELPERLIB) $(CANVASTOOLSLIB)
+
+SHL1STDLIBS += \
+ -framework OpenGL \
+ -framework Cocoa \
+ -framework GLUT
+
+CFLAGSCXX+= -x objective-c++ -fobjc-exceptions
+
+
+SHL1IMPLIB=i$(TARGET)
+SHL1LIBS=$(SLB)$/$(TARGET).lib
+SHL1DEF=$(MISC)$/$(SHL1TARGET).def
+
+SHL1VERSIONMAP=$(SOLARENV)/src/component.map
+
+DEF1NAME=$(SHL1TARGET)
+DEF1EXPORTFILE=../exports.dxp
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/OGLTrans/ogltrans.component b/slideshow/source/engine/OGLTrans/ogltrans.component
new file mode 100644
index 000000000000..89f2384b0d6c
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/ogltrans.component
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--**********************************************************************
+*
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2000, 2010 Oracle and/or its affiliates.
+*
+* OpenOffice.org - a multi-platform office productivity suite
+*
+* This file is part of OpenOffice.org.
+*
+* OpenOffice.org is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License version 3
+* only, as published by the Free Software Foundation.
+*
+* OpenOffice.org 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 version 3 for more details
+* (a copy is included in the LICENSE file that accompanied this code).
+*
+* You should have received a copy of the GNU Lesser General Public License
+* version 3 along with OpenOffice.org. If not, see
+* <http://www.openoffice.org/license.html>
+* for a copy of the LGPLv3 License.
+*
+**********************************************************************-->
+
+<component loader="com.sun.star.loader.SharedLibrary"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.presentation.OGLTransitionFactory">
+ <service name="com.sun.star.presentation.TransitionFactory"/>
+ </implementation>
+</component>
diff --git a/slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.cxx b/slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.cxx
new file mode 100644
index 000000000000..c1beae1230b0
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include <osl/diagnose.hxx>
+
+#include "OGLTrans_Shaders.hxx"
+
+namespace unx
+{
+#include <GL/glx.h>
+#include <GL/glxext.h>
+}
+
+bool OGLShaders::cbInitialized = false;
+
+#ifdef GL_VERSION_2_0
+
+PFNGLCREATESHADERPROC OGLShaders::glCreateShader = NULL;
+PFNGLSHADERSOURCEPROC OGLShaders::glShaderSource = NULL;
+PFNGLCOMPILESHADERPROC OGLShaders::glCompileShader = NULL;
+PFNGLGETSHADERIVPROC OGLShaders::glGetShaderiv = NULL;
+PFNGLGETSHADERINFOLOGPROC OGLShaders::glGetShaderInfoLog = NULL;
+PFNGLDELETESHADERPROC OGLShaders::glDeleteShader = NULL;
+PFNGLCREATEPROGRAMPROC OGLShaders::glCreateProgram = NULL;
+PFNGLATTACHSHADERPROC OGLShaders::glAttachShader = NULL;
+PFNGLLINKPROGRAMPROC OGLShaders::glLinkProgram = NULL;
+PFNGLGETPROGRAMIVPROC OGLShaders::glGetProgramiv = NULL;
+PFNGLGETPROGRAMINFOLOGPROC OGLShaders::glGetProgramInfoLog = NULL;
+PFNGLUSEPROGRAMPROC OGLShaders::glUseProgram = NULL;
+PFNGLDELETEPROGRAMPROC OGLShaders::glDeleteProgram = NULL;
+PFNGLGETUNIFORMLOCATIONPROC OGLShaders::glGetUniformLocation = NULL;
+PFNGLUNIFORM1IPROC OGLShaders::glUniform1i = NULL;
+PFNGLUNIFORM1FPROC OGLShaders::glUniform1f = NULL;
+#endif
+
+bool OGLShaders::Initialize()
+{
+#ifdef GL_VERSION_2_0
+ if( !cbInitialized ) {
+ glCreateShader = (PFNGLCREATESHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glCreateShader" );
+ glShaderSource = (PFNGLSHADERSOURCEPROC) unx::glXGetProcAddress( (unsigned char *) "glShaderSource" );
+ glCompileShader = (PFNGLCOMPILESHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glCompileShader" );
+ glGetShaderiv = (PFNGLGETSHADERIVPROC) unx::glXGetProcAddress( (unsigned char *) "glGetShaderiv" );
+ glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) unx::glXGetProcAddress( (unsigned char *) "glGetShaderInfoLog" );
+ glDeleteShader = (PFNGLDELETESHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glDeleteShader" );
+ glCreateProgram = (PFNGLCREATEPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glCreateProgram" );
+ glAttachShader = (PFNGLATTACHSHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glAttachShader" );
+ glLinkProgram = (PFNGLLINKPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glLinkProgram" );
+ glGetProgramiv = (PFNGLGETPROGRAMIVPROC) unx::glXGetProcAddress( (unsigned char *) "glGetProgramiv" );
+ glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) unx::glXGetProcAddress( (unsigned char *) "glGetProgramInfoLog" );
+ glUseProgram = (PFNGLUSEPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glUseProgram" );
+ glDeleteProgram = (PFNGLDELETEPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glDeleteProgram" );
+ glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) unx::glXGetProcAddress( (unsigned char *) "glGetUniformLocation" );
+ glUniform1i = (PFNGLUNIFORM1IPROC) unx::glXGetProcAddress( (unsigned char *) "glUniform1i" );
+ glUniform1f = (PFNGLUNIFORM1FPROC) unx::glXGetProcAddress( (unsigned char *) "glUniform1f" );
+ cbInitialized = true;
+ }
+
+ return glCreateShader != NULL;
+#else
+ return false;
+#endif
+}
+
+GLuint OGLShaders::LinkProgram( const char *vertexShader, const char *fragmentShader )
+{
+#ifdef GL_VERSION_2_0
+ if( !Initialize() )
+ return 0;
+
+ GLhandleARB vertexObject, fragmentObject, programObject;
+ GLint vertexCompiled, fragmentCompiled, programLinked;
+ char log[1024];
+
+ vertexObject = glCreateShader( GL_VERTEX_SHADER );
+ fragmentObject = glCreateShader( GL_FRAGMENT_SHADER );
+ OSL_TRACE("checkpoint 1: shaders created (%d) vertex: %d fragment: %d", glGetError() == GL_NO_ERROR, vertexObject, fragmentObject );
+
+
+ glShaderSource( vertexObject, 1, &vertexShader, NULL );
+ glShaderSource( fragmentObject, 1, &fragmentShader, NULL );
+
+ glCompileShader( vertexObject );
+ glGetShaderInfoLog( vertexObject, sizeof( log ), NULL, log );
+ OSL_TRACE("vertex compile log: %s", log);
+ glGetShaderiv( vertexObject, GL_COMPILE_STATUS, &vertexCompiled );
+ glCompileShader( fragmentObject );
+ glGetShaderInfoLog( fragmentObject, sizeof( log ), NULL, log );
+ OSL_TRACE("fragment compile log: %s", log);
+ glGetShaderiv( fragmentObject, GL_COMPILE_STATUS, &fragmentCompiled );
+
+ if( !vertexCompiled || !fragmentCompiled )
+ return 0;
+
+ OSL_TRACE("checkpoint 2: shaders compiled (%d)", glGetError() == GL_NO_ERROR);
+
+ programObject = glCreateProgram();
+ glAttachShader( programObject, vertexObject );
+ glAttachShader( programObject, fragmentObject );
+
+ glLinkProgram( programObject );
+ glGetProgramInfoLog( programObject, sizeof( log ), NULL, log );
+ OSL_TRACE("program link log: %s", log);
+ glGetProgramiv( programObject, GL_LINK_STATUS, &programLinked );
+
+ if( !programLinked )
+ return 0;
+
+ OSL_TRACE("checkpoint 3: program linked (%d)", glGetError() == GL_NO_ERROR);
+
+ return programObject;
+#else
+ return 0;
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.hxx b/slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.hxx
new file mode 100644
index 000000000000..016f8ac5445a
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/unx/OGLTrans_Shaders.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_OGLTRANS_SHADERS_HXX_
+#define INCLUDED_OGLTRANS_SHADERS_HXX_
+
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+class OGLShaders {
+ static bool Initialize();
+ static bool cbInitialized;
+
+public:
+
+ static GLuint LinkProgram( const char *vertexShader, const char *fragmentShader );
+
+ /** GL shader functions
+ */
+#ifdef GL_VERSION_2_0
+
+ static PFNGLCREATESHADERPROC glCreateShader;
+ static PFNGLSHADERSOURCEPROC glShaderSource;
+ static PFNGLCOMPILESHADERPROC glCompileShader;
+ static PFNGLGETSHADERIVPROC glGetShaderiv;
+ static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
+ static PFNGLDELETESHADERPROC glDeleteShader;
+
+ static PFNGLCREATEPROGRAMPROC glCreateProgram;
+ static PFNGLATTACHSHADERPROC glAttachShader;
+ static PFNGLLINKPROGRAMPROC glLinkProgram;
+ static PFNGLGETPROGRAMIVPROC glGetProgramiv;
+ static PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
+ static PFNGLUSEPROGRAMPROC glUseProgram;
+ static PFNGLDELETEPROGRAMPROC glDeleteProgram;
+
+ static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
+ static PFNGLUNIFORM1IPROC glUniform1i;
+ static PFNGLUNIFORM1FPROC glUniform1f;
+#endif
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.cxx b/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.cxx
new file mode 100644
index 000000000000..8f10a856cefa
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.cxx
@@ -0,0 +1,1312 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "OGLTrans_TransitionImpl.hxx"
+#include "OGLTrans_Shaders.hxx"
+#include <GL/gl.h>
+#include <math.h>
+
+
+void OGLTransitionImpl::clear()
+{
+ for(unsigned int i( 0 ); i < OverallOperations.size(); ++i)
+ delete OverallOperations[i];
+ OverallOperations.clear();
+ maLeavingSlidePrimitives.clear();
+ maEnteringSlidePrimitives.clear();
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i)
+ delete maSceneObjects[i];
+ maSceneObjects.clear();
+
+ mbReflectSlides = false;
+
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ OGLShaders::glDeleteProgram( mProgramObject );
+ mProgramObject = 0;
+ }
+
+ if( mVertexObject ) {
+ OGLShaders::glDeleteShader( mVertexObject );
+ mVertexObject = 0;
+ }
+
+ if( mFragmentObject ) {
+ OGLShaders::glDeleteShader( mFragmentObject );
+ mFragmentObject = 0;
+ }
+#endif
+
+ if( maHelperTexture ) {
+ glDeleteTextures( 1, &maHelperTexture );
+ maHelperTexture = 0;
+ }
+
+ if( mmClearTransition )
+ (this->*mmClearTransition)();
+}
+
+OGLTransitionImpl::~OGLTransitionImpl()
+{
+ clear();
+}
+
+void OGLTransitionImpl::prepare( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex )
+{
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
+ maSceneObjects[i]->prepare();
+ }
+
+ if( mmPrepareTransition )
+ (this->*mmPrepareTransition)( glLeavingSlideTex, glEnteringSlideTex );
+}
+
+void OGLTransitionImpl::finish()
+{
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
+ maSceneObjects[i]->finish();
+ }
+}
+
+static void blendSlide( double depth )
+{
+ double showHeight = -1 + depth*2;
+ GLfloat reflectionColor[] = {0, 0, 0, 0.25};
+
+ glDisable( GL_DEPTH_TEST );
+ glBegin( GL_QUADS );
+ glColor4fv( reflectionColor );
+ glVertex3f( -1, -1, 0 );
+ glColor4f( 0, 0, 0, 1 );
+ glVertex3f(-1, showHeight, 0 );
+ glVertex3f( 1, showHeight, 0 );
+ glColor4fv( reflectionColor );
+ glVertex3f( 1, -1, 0 );
+ glEnd();
+
+ glBegin( GL_QUADS );
+ glColor4f( 0, 0, 0, 1 );
+ glVertex3f( -1, showHeight, 0 );
+ glVertex3f( -1, 1, 0 );
+ glVertex3f( 1, 1, 0 );
+ glVertex3f( 1, showHeight, 0 );
+ glEnd();
+ glEnable( GL_DEPTH_TEST );
+}
+
+static void slideShadow( double nTime, Primitive& primitive, double sw, double sh )
+{
+ double reflectionDepth = 0.3;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_LIGHTING);
+
+ glPushMatrix();
+ primitive.applyOperations( nTime, sw, sh );
+ blendSlide( reflectionDepth );
+ glPopMatrix();
+
+ glDisable(GL_BLEND);
+ glEnable(GL_LIGHTING);
+}
+
+void OGLTransitionImpl::display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ double SlideWidthScale, SlideHeightScale;
+
+ SlideWidthScale = SlideWidth/DispWidth;
+ SlideHeightScale = SlideHeight/DispHeight;
+
+ if( mmPrepare ) {
+ clear();
+ (this->*mmPrepare)( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
+ }
+
+ glPushMatrix();
+ displaySlides( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
+ displayScene( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
+ glPopMatrix();
+}
+
+void OGLTransitionImpl::applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale )
+{
+ for(unsigned int i(0); i < OverallOperations.size(); ++i)
+ OverallOperations[i]->interpolate(nTime,SlideWidthScale,SlideHeightScale);
+}
+
+void OGLTransitionImpl::displaySlide( double nTime, ::sal_Int32 glSlideTex, std::vector<Primitive>& primitives,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ //TODO change to foreach
+ glBindTexture(GL_TEXTURE_2D, glSlideTex);
+
+ // display slide reflection
+ // note that depth test is turned off while blending the shadow
+ // so the slides has to be rendered in right order, see rochade as example
+ if( mbReflectSlides ) {
+ double surfaceLevel = -0.04;
+
+ /* reflected slides */
+ glPushMatrix();
+
+ glScaled( 1, -1, 1 );
+ glTranslated( 0, 2 - surfaceLevel, 0 );
+
+ glCullFace(GL_FRONT);
+ for(unsigned int i(0); i < primitives.size(); ++i)
+ primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
+ glCullFace(GL_BACK);
+
+ slideShadow( nTime, primitives[0], SlideWidthScale, SlideHeightScale );
+
+ glPopMatrix();
+ }
+
+ for(unsigned int i(0); i < primitives.size(); ++i)
+ primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
+}
+
+void OGLTransitionImpl::displaySlides( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ if( mmDisplaySlides )
+ (this->*mmDisplaySlides)( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
+ else {
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glEnable(GL_TEXTURE_2D);
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+}
+
+void OGLTransitionImpl::displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ glEnable(GL_TEXTURE_2D);
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i)
+ maSceneObjects[i]->display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
+}
+
+void Primitive::display(double nTime, double WidthScale, double HeightScale)
+{
+ glPushMatrix();
+
+ applyOperations( nTime, WidthScale, HeightScale );
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if(!Normals.empty())
+ {
+ glNormalPointer( GL_DOUBLE , 0 , &Normals[0] );
+ glEnableClientState( GL_NORMAL_ARRAY );
+ }
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glTexCoordPointer( 2, GL_DOUBLE, 0, &TexCoords[0] );
+ glVertexPointer( 3, GL_DOUBLE, 0, &Vertices[0] );
+ glDrawArrays( GL_TRIANGLES, 0, Vertices.size() );
+ glPopMatrix();
+}
+
+void Primitive::applyOperations(double nTime, double WidthScale, double HeightScale)
+{
+ for(unsigned int i(0); i < Operations.size(); ++i)
+ Operations[i]->interpolate( nTime ,WidthScale,HeightScale);
+ glScaled(WidthScale,HeightScale,1);
+}
+
+Primitive::~Primitive()
+{
+ for(unsigned int i( 0 ); i < Operations.size(); ++i)
+ delete Operations[i];
+}
+
+
+void SceneObject::display(double nTime, double /* SlideWidth */, double /* SlideHeight */, double DispWidth, double DispHeight )
+{
+ for(unsigned int i(0); i < maPrimitives.size(); ++i) {
+ // fixme: allow various model spaces, now we make it so that
+ // it is regular -1,-1 to 1,1, where the whole display fits in
+ glPushMatrix();
+ if (DispHeight > DispWidth)
+ glScaled(DispHeight/DispWidth, 1, 1);
+ else
+ glScaled(1, DispWidth/DispHeight, 1);
+ maPrimitives[i].display(nTime, 1, 1);
+ glPopMatrix();
+ }
+}
+
+void SceneObject::pushPrimitive(const Primitive &p)
+{
+ maPrimitives.push_back(p);
+}
+
+SceneObject::SceneObject()
+ : maPrimitives()
+{
+}
+
+Iris::Iris()
+ : SceneObject ()
+{
+}
+
+void Iris::display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ glBindTexture(GL_TEXTURE_2D, maTexture);
+ SceneObject::display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
+}
+
+void Iris::prepare()
+{
+ static GLubyte img[3] = { 80, 80, 80 };
+
+ glGenTextures(1, &maTexture);
+ glBindTexture(GL_TEXTURE_2D, maTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+}
+
+void Iris::finish()
+{
+ glDeleteTextures(1, &maTexture);
+}
+
+void OGLTransitionImpl::makeOutsideCubeFaceToLeft()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),90,false,0.0,1.0));
+
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),-90,true,0.0,1.0));
+}
+
+void OGLTransitionImpl::makeInsideCubeFaceToLeft()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),-90,false,0.0,1.0));
+
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),90,true,0.0,1.0));
+}
+
+void OGLTransitionImpl::makeFallLeaving()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(1,0,0),basegfx::B3DVector(0,-1,0), 90,true,0.0,1.0));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::makeTurnAround()
+{
+ clear();
+ Primitive Slide;
+
+ mbReflectSlides = true;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0),-180,false,0.0,1.0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, -1.5),true, 0, 0.5));
+ OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1.5), true, 0.5, 1));
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0),basegfx::B3DVector(0, 0, 0), -180, true, 0.0, 1.0));
+}
+
+void OGLTransitionImpl::makeTurnDown()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 0.0001), false, -1.0, 0.0));
+ Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), -90, true, 0.0, 1.0));
+ Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), 90, false, -1.0, 0.0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ mbUseMipMapLeaving = false;
+}
+
+void OGLTransitionImpl::makeIris()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, 0.000001), false, -1, 0));
+ Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, -0.000002), false, 0.5, 1));
+ maLeavingSlidePrimitives.push_back (Slide);
+
+
+ Primitive irisPart, part;
+ int i, nSteps = 24, nParts = 7;
+ double t = 1.0/nSteps, cx, cy, lcx, lcy, lx = 1, ly = 0, x, y, cxo, cyo, lcxo, lcyo, of=2.2, f=1.42;
+
+ for (i=1; i<=nSteps; i++) {
+ x = cos ((3*2*M_PI*t)/nParts);
+ y = -sin ((3*2*M_PI*t)/nParts);
+ cx = (f*x + 1)/2;
+ cy = (f*y + 1)/2;
+ lcx = (f*lx + 1)/2;
+ lcy = (f*ly + 1)/2;
+ cxo = (of*x + 1)/2;
+ cyo = (of*y + 1)/2;
+ lcxo = (of*lx + 1)/2;
+ lcyo = (of*ly + 1)/2;
+ irisPart.pushTriangle (basegfx::B2DVector (lcx, lcy),
+ basegfx::B2DVector (lcxo, lcyo),
+ basegfx::B2DVector (cx, cy));
+ irisPart.pushTriangle (basegfx::B2DVector (cx, cy),
+ basegfx::B2DVector (lcxo, lcyo),
+ basegfx::B2DVector (cxo, cyo));
+ lx = x;
+ ly = y;
+ t += 1.0/nSteps;
+ }
+
+ Iris* pIris = new Iris();
+ double angle = 87;
+
+ for (i = 0; i < nParts; i++) {
+ irisPart.Operations.clear ();
+ double rx, ry;
+
+ rx = cos ((2*M_PI*i)/nParts);
+ ry = sin ((2*M_PI*i)/nParts);
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0), angle, true, 0.0, 0.5));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0), -angle, true, 0.5, 1));
+ if (i > 0) {
+ irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(rx, ry, 0), false, -1, 0));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(0, 0, 0), i*360.0/nParts, false, -1, 0));
+ irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(-1, 0, 0), false, -1, 0));
+ }
+ irisPart.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1), false, -2, 0.0));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(1, .5, 0), basegfx::B3DVector(1, 0, 0), -30, false, -1, 0));
+ pIris->pushPrimitive (irisPart);
+ }
+
+ maSceneObjects.push_back (pIris);
+
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::displaySlidesRochade( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glEnable(GL_TEXTURE_2D);
+
+ if( nTime > .5) {
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ } else {
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+}
+
+void OGLTransitionImpl::makeRochade()
+{
+ clear();
+ Primitive Slide;
+
+ mbReflectSlides = true;
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesRochade;
+
+ double w, h;
+
+ w = 2.2;
+ h = 10;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.25, -0.25, true, 0, 1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.clear();
+ Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.75, 0.25, true, 0, 1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, -h), false, -1, 0));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), 45, false, -1, 0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B2DVector clamp(const basegfx::B2DVector& v)
+{
+ return basegfx::B2DVector(min(max(v.getX(),-1.0),1.0),
+ min(max(v.getY(),-1.0),1.0));
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B3DVector clamp(const basegfx::B3DVector& v)
+{
+ return basegfx::B3DVector(min(max(v.getX(),-1.0),1.0),
+ min(max(v.getY(),-1.0),1.0),
+ min(max(v.getZ(),-1.0),1.0));
+}
+
+inline double randFromNeg1to1()
+{
+ return ( ( static_cast<double>( rand() ) / static_cast<double>( RAND_MAX ) ) * 2.0 ) - 1.0;
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B3DVector randNormVectorInXYPlane()
+{
+ basegfx::B3DVector toReturn(randFromNeg1to1(),randFromNeg1to1(),0.0);
+ return toReturn/toReturn.getLength();
+}
+
+void OGLTransitionImpl::makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles )
+{
+ clear();
+ double dAngle(2*3.1415926/static_cast<double>( nPointsOnCircles ));
+ if(nCircles < 2 || nPointsOnCircles < 4)
+ {
+ makeNByMTileFlip(1,1);
+ return;
+ }
+ double Radius(1.0/static_cast<double>( nCircles ));
+ double dRadius(Radius);
+ double LastRadius(0.0);
+ double NextRadius(2*Radius);
+
+ /// now we know there is at least two circles
+ /// the first will always be a full circle
+ /// the last will always be the outer shell of the slide with a circle hole
+
+ //add the full circle
+ vector<basegfx::B2DVector> unScaledTexCoords;
+ double TempAngle(0.0);
+ for(unsigned int Point(0); Point < nPointsOnCircles; ++Point)
+ {
+ unScaledTexCoords.push_back( basegfx::B2DVector( cos(TempAngle - 3.1415926/2.0) , sin(TempAngle- 3.1415926/2.0) ) );
+
+ TempAngle += dAngle;
+ }
+
+ {
+ Primitive EnteringSlide;
+ Primitive LeavingSlide;
+ for(int Point(0); Point + 1 < nPointsOnCircles; ++Point)
+ {
+ EnteringSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
+ LeavingSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5, 0.5) );
+ }
+ EnteringSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius * unScaledTexCoords[ 0 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ nPointsOnCircles - 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
+ LeavingSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+ LastRadius = Radius;
+ Radius = NextRadius;
+ NextRadius += dRadius;
+ }
+
+ for(int i(1); i < nCircles - 1; ++i)
+ {
+ Primitive LeavingSlide;
+ Primitive EnteringSlide;
+ for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
+ {
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ }
+
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+
+ LastRadius = Radius;
+ Radius = NextRadius;
+ NextRadius += dRadius;
+ }
+ {
+ Radius = sqrt(2.0);
+ Primitive LeavingSlide;
+ Primitive EnteringSlide;
+ for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
+ {
+
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
+ }
+
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+ }
+}
+
+void OGLTransitionImpl::makeHelix( ::sal_uInt16 nRows )
+{
+ clear();
+ double invN(1.0/static_cast<double>(nRows));
+ double iDn = 0.0;
+ double iPDn = invN;
+ for(unsigned int i(0); i < nRows; ++i)
+ {
+ Primitive Tile;
+
+ Tile.pushTriangle(basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
+
+ Tile.pushTriangle(basegfx::B2DVector( 1.0 , iPDn ) , basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 ,
+ true,min(max(static_cast<double>(i - nRows/2.0)*invN/2.0,0.0),1.0),
+ min(max(static_cast<double>(i + nRows/2.0)*invN/2.0,0.0),1.0) ) );
+
+ maLeavingSlidePrimitives.push_back(Tile);
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180 , false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(Tile);
+
+ iDn += invN;
+ iPDn += invN;
+ }
+}
+
+void OGLTransitionImpl::makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m )
+{
+ clear();
+ double invN(1.0/static_cast<double>(n));
+ double invM(1.0/static_cast<double>(m));
+ double iDn = 0.0;
+ double iPDn = invN;
+ for(unsigned int i(0); i < n; ++i)
+ {
+ double jDm = 0.0;
+ double jPDm = invM;
+ for(unsigned int j(0); j < m; ++j)
+ {
+ Primitive Tile;
+
+ Tile.pushTriangle(basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));
+
+ Tile.pushTriangle(basegfx::B2DVector( iPDn , jPDm ) , basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));//bottom left corner of tile
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 , true, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
+ maLeavingSlidePrimitives.push_back(Tile);
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180, false, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
+
+ maEnteringSlidePrimitives.push_back(Tile);
+
+ jDm += invM;
+ jPDm += invM;
+ }
+ iDn += invN;
+ iPDn += invN;
+ }
+}
+
+SRotate::SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+SScale::SScale(const basegfx::B3DVector& Scale,const basegfx::B3DVector& Origin, bool bInter, double T0, double T1):scale(Scale),origin(Origin)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+RotateAndScaleDepthByWidth::RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+RotateAndScaleDepthByHeight::RotateAndScaleDepthByHeight(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+
+STranslate::STranslate(const basegfx::B3DVector& Vector, bool bInter, double T0, double T1):vector(Vector)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+inline double intervalInter(double t, double T0, double T1)
+{
+ return ( t - T0 ) / ( T1 - T0 );
+}
+
+void STranslate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*t*vector.getX(),SlideHeightScale*t*vector.getY(),t*vector.getZ());
+}
+
+void SRotate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
+ glScaled(SlideWidthScale,SlideHeightScale,1);
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glScaled(1/SlideWidthScale,1/SlideHeightScale,1);
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
+}
+
+void SScale::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
+ glScaled((1-t) + t*scale.getX(),(1-t) + t*scale.getY(),(1-t) + t*scale.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
+}
+
+void RotateAndScaleDepthByWidth::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideWidthScale*origin.getZ());
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideWidthScale*origin.getZ());
+}
+
+void RotateAndScaleDepthByHeight::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideHeightScale*origin.getZ());
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideHeightScale*origin.getZ());
+}
+
+SEllipseTranslate::SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+ width = dWidth;
+ height = dHeight;
+ startPosition = dStartPosition;
+ endPosition = dEndPosition;
+}
+
+void SEllipseTranslate::interpolate(double t,double /* SlideWidthScale */,double /* SlideHeightScale */)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+
+ double a1, a2, x, y;
+ a1 = startPosition*2*M_PI;
+ a2 = (startPosition + t*(endPosition - startPosition))*2*M_PI;
+ x = width*(cos (a2) - cos (a1))/2;
+ y = height*(sin (a2) - sin (a1))/2;
+
+ glTranslated(x, 0, y);
+}
+
+STranslate* STranslate::clone()
+{
+ return new STranslate(*this);
+}
+SRotate* SRotate::clone()
+{
+ return new SRotate(*this);
+}
+
+SScale* SScale::clone()
+{
+ return new SScale(*this);
+}
+
+SEllipseTranslate* SEllipseTranslate::clone()
+{
+ return new SEllipseTranslate(*this);
+}
+
+RotateAndScaleDepthByWidth* RotateAndScaleDepthByWidth::clone()
+{
+ return new RotateAndScaleDepthByWidth(*this);
+}
+
+RotateAndScaleDepthByHeight* RotateAndScaleDepthByHeight::clone()
+{
+ return new RotateAndScaleDepthByHeight(*this);
+}
+
+const Primitive& Primitive::operator=(const Primitive& rvalue)
+{
+ for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
+ Operations.push_back(rvalue.Operations[i]->clone());
+ for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
+ Vertices.push_back(rvalue.Vertices[i]);
+ for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
+ TexCoords.push_back(rvalue.TexCoords[i]);
+ for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
+ Normals.push_back(rvalue.Normals[i]);
+ return *this;
+}
+
+Primitive::Primitive(const Primitive& rvalue)
+{
+ for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
+ Operations.push_back(rvalue.Operations[i]->clone());
+ for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
+ Vertices.push_back(rvalue.Vertices[i]);
+ for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
+ TexCoords.push_back(rvalue.TexCoords[i]);
+ for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
+ Normals.push_back(rvalue.Normals[i]);
+}
+
+void Primitive::pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2)
+{
+ vector<basegfx::B3DVector> Verts;
+ vector<basegfx::B2DVector> Texs;
+ Verts.reserve(3);
+ Texs.reserve(3);
+
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
+
+ //figure out if they're facing the correct way, and make them face the correct way.
+ basegfx::B3DVector Normal( basegfx::cross( Verts[0] - Verts[1] , Verts[1] - Verts[2] ) );
+ if(Normal.getZ() >= 0.0)//if the normal is facing us
+ {
+ Texs.push_back(SlideLocation0);
+ Texs.push_back(SlideLocation1);
+ Texs.push_back(SlideLocation2);
+ }
+ else // if the normal is facing away from us, make it face us
+ {
+ Texs.push_back(SlideLocation0);
+ Texs.push_back(SlideLocation2);
+ Texs.push_back(SlideLocation1);
+ Verts.clear();
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
+ }
+
+ Vertices.push_back(Verts[0]);
+ Vertices.push_back(Verts[1]);
+ Vertices.push_back(Verts[2]);
+
+ TexCoords.push_back(Texs[0]);
+ TexCoords.push_back(Texs[1]);
+ TexCoords.push_back(Texs[2]);
+
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+}
+
+void OGLTransitionImpl::makeDiamond()
+{
+ mmPrepare = &OGLTransitionImpl::prepareDiamond;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::prepareDiamond( double nTime, double /* SlideWidth */, double /* SlideHeight */, double /* DispWidth */, double /* DispHeight */ )
+{
+ Primitive Slide1, Slide2;
+
+ Slide1.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide1.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maEnteringSlidePrimitives.push_back (Slide1);
+
+
+ if( nTime >= 0.5 ) {
+ double m = 1 - nTime;
+
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (m,0), basegfx::B2DVector (0,m));
+ Slide2.pushTriangle (basegfx::B2DVector (nTime,0), basegfx::B2DVector (1,0), basegfx::B2DVector (1,m));
+ Slide2.pushTriangle (basegfx::B2DVector (1,nTime), basegfx::B2DVector (1,1), basegfx::B2DVector (nTime,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,nTime), basegfx::B2DVector (m,1), basegfx::B2DVector (0,1));
+ } else {
+ double l = 0.5 - nTime;
+ double h = 0.5 + nTime;
+
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0.5,l));
+ Slide2.pushTriangle (basegfx::B2DVector (0.5,l), basegfx::B2DVector (1,0), basegfx::B2DVector (h,0.5));
+ Slide2.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (1,1), basegfx::B2DVector (h,0.5));
+ Slide2.pushTriangle (basegfx::B2DVector (h,0.5), basegfx::B2DVector (1,1), basegfx::B2DVector (0.5,h));
+ Slide2.pushTriangle (basegfx::B2DVector (0.5,h), basegfx::B2DVector (1,1), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (l,0.5), basegfx::B2DVector (0.5,h), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (l,0.5), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (0.5,l), basegfx::B2DVector (l,0.5));
+ }
+ Slide2.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, 0.00000001), false, -1, 0));
+ maLeavingSlidePrimitives.push_back (Slide2);
+}
+
+void OGLTransitionImpl::makeVenetianBlinds( bool vertical, int parts )
+{
+ static double t30 = tan( M_PI/6.0 );
+ double n, ln = 0;
+ double p = 1.0/parts;
+
+ for( int i=0; i<parts; i++ ) {
+ Primitive Slide;
+ n = (i + 1)/(double)parts;
+ if( vertical ) {
+ Slide.pushTriangle (basegfx::B2DVector (ln,0), basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1));
+ Slide.pushTriangle (basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1), basegfx::B2DVector (n,1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, -t30*p), -120, true, 0.0, 1.0));
+ } else {
+ Slide.pushTriangle (basegfx::B2DVector (0,ln), basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n));
+ Slide.pushTriangle (basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n), basegfx::B2DVector (1,n));
+ Slide.Operations.push_back(new RotateAndScaleDepthByHeight(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, -t30*p), -120, true, 0.0, 1.0));
+ }
+ maLeavingSlidePrimitives.push_back (Slide);
+
+ if( vertical ) {
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(2*n - 1, 0, 0), -60, false, -1, 0));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, 0), 180, false, -1, 0));
+ } else {
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - 2*n, 0), -60, false, -1, 0));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, 0), 180, false, -1, 0));
+ }
+ maEnteringSlidePrimitives.push_back (Slide);
+ ln = n;
+ }
+}
+
+void OGLTransitionImpl::displaySlidesFadeSmoothly( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_DEPTH_TEST);
+
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4f( 1, 1, 1, nTime );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ glDisable(GL_BLEND);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_LIGHTING);
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+void OGLTransitionImpl::makeFadeSmoothly()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeSmoothly;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::displaySlidesFadeThroughBlack( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_DEPTH_TEST);
+
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ if( nTime < 0.5 ) {
+ glColor4f( 1, 1, 1, 1 - nTime*2 );
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ } else {
+ glColor4f( 1, 1, 1, (nTime - 0.5)*2 );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+ glDisable(GL_BLEND);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_LIGHTING);
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+void OGLTransitionImpl::makeFadeThroughBlack()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeThroughBlack;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+static const char* basicVertexShader = "\n\
+varying vec2 v_texturePosition;\n\
+\n\
+void main( void )\n\
+{\n\
+ gl_Position = ftransform();\n\
+ v_texturePosition = gl_MultiTexCoord0.xy;\n\
+}\n\
+";
+
+static const char* staticFragmentShader = "\n\
+uniform sampler2D leavingSlideTexture;\n\
+uniform sampler2D enteringSlideTexture;\n\
+uniform sampler2D permTexture;\n\
+uniform float time;\n\
+varying vec2 v_texturePosition;\n\
+\n\
+float snoise(vec2 P) {\n\
+\n\
+ return texture2D(permTexture, P).r;\n\
+}\n\
+\n\
+\n\
+#define PART 0.5\n\
+#define START 0.4\n\
+#define END 0.9\n\
+\n\
+void main() {\n\
+ float sn = snoise(10.0*v_texturePosition+time*0.07);\n\
+ if( time < PART ) {\n\
+ float sn1 = snoise(vec2(time*15.0, 20.0*v_texturePosition.y));\n\
+ float sn2 = snoise(v_texturePosition);\n\
+ if (sn1 > 1.0 - time*time && sn2 < 2.0*time+0.1)\n\
+ gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
+ else if (time > START )\n\
+ gl_FragColor = ((time-START)/(PART - START))*vec4(sn, sn, sn, 1.0) + (1.0 - (time - START)/(PART - START))*texture2D(leavingSlideTexture, v_texturePosition);\n\
+ else\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+ } else if ( time < PART ) {\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+ } else if ( time > END ) {\n\
+ gl_FragColor = ((1.0 - time)/(1.0 - END))*vec4(sn, sn, sn, 1.0) + ((time - END)/(1.0 - END))*texture2D(enteringSlideTexture, v_texturePosition);\n\
+ } else \n\
+ gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
+}\n\
+";
+
+static const char* dissolveFragmentShader = "\n\
+uniform sampler2D leavingSlideTexture;\n\
+uniform sampler2D enteringSlideTexture;\n\
+uniform sampler2D permTexture;\n\
+uniform float time;\n\
+varying vec2 v_texturePosition;\n\
+\n\
+float snoise(vec2 P) {\n\
+\n\
+ return texture2D(permTexture, P).r;\n\
+}\n\
+\n\
+void main() {\n\
+ float sn = snoise(10.0*v_texturePosition);\n\
+ if( sn < time)\n\
+ gl_FragColor = texture2D(enteringSlideTexture, v_texturePosition);\n\
+ else\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+}\n\
+";
+
+int permutation256 [256]= {
+215, 100, 200, 204, 233, 50, 85, 196,
+ 71, 141, 122, 160, 93, 131, 243, 234,
+162, 183, 36, 155, 4, 62, 35, 205,
+ 40, 102, 33, 27, 255, 55, 214, 156,
+ 75, 163, 134, 126, 249, 74, 197, 228,
+ 72, 90, 206, 235, 17, 22, 49, 169,
+227, 89, 16, 5, 117, 60, 248, 230,
+217, 68, 138, 96, 194, 170, 136, 10,
+112, 238, 184, 189, 176, 42, 225, 212,
+ 84, 58, 175, 244, 150, 168, 219, 236,
+101, 208, 123, 37, 164, 110, 158, 201,
+ 78, 114, 57, 48, 70, 142, 106, 43,
+232, 26, 32, 252, 239, 98, 191, 94,
+ 59, 149, 39, 187, 203, 190, 19, 13,
+133, 45, 61, 247, 23, 34, 20, 52,
+118, 209, 146, 193, 222, 18, 1, 152,
+ 46, 41, 91, 148, 115, 25, 135, 77,
+254, 147, 224, 161, 9, 213, 223, 250,
+231, 251, 127, 166, 63, 179, 81, 130,
+139, 28, 120, 151, 241, 86, 111, 0,
+ 88, 153, 172, 182, 159, 105, 178, 47,
+ 51, 167, 65, 66, 92, 73, 198, 211,
+245, 195, 31, 220, 140, 76, 221, 186,
+154, 185, 56, 83, 38, 165, 109, 67,
+124, 226, 132, 53, 229, 29, 12, 181,
+121, 24, 207, 199, 177, 113, 30, 80,
+ 3, 97, 188, 79, 216, 173, 8, 145,
+ 87, 128, 180, 237, 240, 137, 125, 104,
+ 15, 242, 119, 246, 103, 143, 95, 144,
+ 2, 44, 69, 157, 192, 174, 14, 54,
+218, 82, 64, 210, 11, 6, 129, 21,
+116, 171, 99, 202, 7, 107, 253, 108
+};
+
+void initPermTexture(GLuint *texID)
+{
+ glGenTextures(1, texID);
+ glBindTexture(GL_TEXTURE_2D, *texID);
+
+ static bool initialized = false;
+ static unsigned char permutation2D[256*256*4];
+ if( !initialized ) {
+ int x, y;
+
+ for( y=0; y < 256; y++ )
+ for( x=0; x < 256; x++ )
+ permutation2D[x*4 + y*1024] = permutation256[(y + permutation256[x]) & 0xff];
+
+ initialized = true;
+ }
+
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, permutation2D );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+}
+
+void OGLTransitionImpl::preparePermShader()
+{
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ OGLShaders::glUseProgram( mProgramObject );
+
+ GLint location = OGLShaders::glGetUniformLocation( mProgramObject, "leavingSlideTexture" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1i( location, 0 ); // texture unit 0
+ }
+
+ glActiveTexture(GL_TEXTURE1);
+ if( !maHelperTexture )
+ initPermTexture( &maHelperTexture );
+ glActiveTexture(GL_TEXTURE0);
+
+ location = OGLShaders::glGetUniformLocation( mProgramObject, "permTexture" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1i( location, 1 ); // texture unit 1
+ }
+
+ location = OGLShaders::glGetUniformLocation( mProgramObject, "enteringSlideTexture" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1i( location, 2 ); // texture unit 2
+ }
+ }
+#endif
+}
+
+void OGLTransitionImpl::prepareStatic( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
+{
+ mProgramObject = OGLShaders::LinkProgram( basicVertexShader, staticFragmentShader );
+
+ preparePermShader();
+}
+
+void OGLTransitionImpl::displaySlidesShaders( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ GLint location = OGLShaders::glGetUniformLocation( mProgramObject, "time" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1f( location, nTime );
+ }
+ }
+
+ glActiveTexture( GL_TEXTURE2 );
+ glBindTexture( GL_TEXTURE_2D, glEnteringSlideTex );
+ glActiveTexture( GL_TEXTURE0 );
+#endif
+
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+}
+
+void OGLTransitionImpl::makeStatic()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
+ mmPrepareTransition = &OGLTransitionImpl::prepareStatic;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+
+ mnRequiredGLVersion = 2.0;
+}
+
+void OGLTransitionImpl::prepareDissolve( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
+{
+ mProgramObject = OGLShaders::LinkProgram( basicVertexShader, dissolveFragmentShader );
+
+ preparePermShader();
+}
+
+void OGLTransitionImpl::makeDissolve()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
+ mmPrepareTransition = &OGLTransitionImpl::prepareDissolve;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+
+ mnRequiredGLVersion = 2.0;
+}
+
+void OGLTransitionImpl::makeNewsflash()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),3000,true,0,0.5));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),true,0,0.5));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-10000, 0, 0),false, 0.5, 2));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.clear();
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),-3000,true,0.5,1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-100, 0, 0),false, -1, 1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(100, 0, 0),false, 0.5, 1));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),false,-1,1));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(100,100,100),basegfx::B3DVector(0,0,0),true,0.5,1));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0.2,0.2,0),1080,true,0,1));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.hxx b/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.hxx
new file mode 100644
index 000000000000..934ac1284d0b
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionImpl.hxx
@@ -0,0 +1,497 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
+#define INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
+
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+
+#include <vector>
+#include <GL/gl.h>
+
+using namespace std;
+
+class Primitive;
+class Operation;
+class SceneObject;
+
+
+/** OpenGL 3D Transition class. It implicitly is constructed from XOGLTransition
+
+ This class is capable of making itself into many difference transitions. It holds Primitives and Operations on those primitives.
+*/
+class OGLTransitionImpl
+{
+public:
+ OGLTransitionImpl() :
+ mbUseMipMapLeaving( true ),
+ mbUseMipMapEntering( true ),
+ mnRequiredGLVersion( 1.0 ),
+ maLeavingSlidePrimitives(),
+ maEnteringSlidePrimitives(),
+ maSceneObjects(),
+ mbReflectSlides( false ),
+ mVertexObject( 0 ),
+ mFragmentObject( 0 ),
+ mProgramObject( 0 ),
+ maHelperTexture( 0 ),
+ mmPrepare( NULL ),
+ mmPrepareTransition( NULL ),
+ mmClearTransition( NULL ),
+ mmDisplaySlides( NULL )
+ {}
+
+ ~OGLTransitionImpl();
+
+ void prepare( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight );
+ void finish();
+
+ void makeOutsideCubeFaceToLeft();
+ void makeInsideCubeFaceToLeft();
+ void makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m );
+ void makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles );
+ void makeHelix( ::sal_uInt16 nRows );
+ void makeFallLeaving();
+ void makeTurnAround();
+ void makeTurnDown();
+ void makeIris();
+ void makeRochade();
+ void makeVenetianBlinds( bool vertical, int parts );
+ void makeStatic();
+ void makeDissolve();
+ void makeNewsflash();
+
+ /** 2D replacements
+ */
+ void makeDiamond();
+ void makeFadeSmoothly();
+ void makeFadeThroughBlack();
+
+ /** Whether to use mipmaping for slides textures
+ */
+ bool mbUseMipMapLeaving;
+ bool mbUseMipMapEntering;
+
+ /** which GL version does the transition require
+ */
+ float mnRequiredGLVersion;
+
+private:
+ /** clears all the primitives and operations
+ */
+ void clear();
+
+ /** All the primitives that use the leaving slide texture
+ */
+ vector<Primitive> maLeavingSlidePrimitives;
+
+ /** All the primitives that use the leaving slide texture
+ */
+ vector<Primitive> maEnteringSlidePrimitives;
+
+ /** All the surrounding scene objects
+ */
+ vector<SceneObject*> maSceneObjects;
+
+ /** All the operations that should be applied to both leaving and entering slide primitives. These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
+ */
+ vector<Operation*> OverallOperations;
+
+ /** Whether to reflect slides, the reflection happens on flat surface beneath the slides.
+ ** Now it only works with slides which keep their rectangular shape together.
+ */
+ bool mbReflectSlides;
+
+ /** GLSL objects, shaders and program
+ */
+ GLuint mVertexObject, mFragmentObject, mProgramObject;
+
+ /** various data */
+ GLuint maHelperTexture;
+
+ /** When this method is not NULL, it is called in display method to prepare the slides, scene, etc.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmPrepare)( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight );
+
+ /** When this method is not NULL, it is called after glx context is ready to let the transition prepare GL related things, like GLSL program.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmPrepareTransition)( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+
+ /** When this method is not NULL, it is called when the transition needs to clear after itself, like delete own textures etc.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmClearTransition)();
+
+ /** When this method is not NULL, it is called in display method to display the slides.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmDisplaySlides)( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+
+ void displaySlides( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlide( double nTime, ::sal_Int32 glSlideTex, std::vector<Primitive>& primitives, double SlideWidthScale, double SlideHeightScale );
+ void displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ void applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale );
+
+ /** various transitions helper methods
+ */
+ void prepareDiamond( double nTime, double SlideWidth, double SlideHeight,double DispWidth, double DispHeight );
+ void displaySlidesFadeSmoothly( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesFadeThroughBlack( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesRochade( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesShaders( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void prepareStatic( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void prepareDissolve( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void preparePermShader();
+};
+
+class SceneObject
+{
+public:
+ SceneObject();
+
+ virtual void prepare() {};
+ virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ virtual void finish() {};
+
+ void pushPrimitive (const Primitive &p);
+
+protected:
+ /** All the surrounding scene primitives
+ */
+ vector<Primitive> maPrimitives;
+};
+
+class Iris : public SceneObject
+{
+public:
+ Iris ();
+
+ virtual void prepare();
+ virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ virtual void finish();
+
+private:
+
+ GLuint maTexture;
+};
+
+/** This class is a list of Triangles that will share Operations, and could possibly share
+*/
+class Primitive
+{
+public:
+ Primitive() {}
+ // making copy constructor explicit makes the class un-suitable for use with stl containers
+ Primitive(const Primitive& rvalue);
+ ~Primitive();
+
+ void applyOperations(double nTime, double SlideWidthScale, double SlideHeightScale);
+ void display(double nTime, double SlideWidthScale, double SlideHeightScale);
+ const Primitive& operator=(const Primitive& rvalue);
+
+ /** PushBack a vertex,normal, and tex coord. Each SlideLocation is where on the slide is mapped to this location ( from (0,0) to (1,1) ). This will make sure the correct aspect ratio is used, and helps to make slides begin and end at the correct position. (0,0) is the top left of the slide, and (1,1) is the bottom right.
+
+ @param SlideLocation0
+ Location of first Vertex on slide
+
+ @param SlideLocation1
+ Location of second Vertex on slide
+
+ @param SlideLocation2
+ Location of third Vertex on slide
+
+ */
+ void pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2);
+
+ /** clear all the vertices, normals, tex coordinates, and normals
+ */
+ void clearTriangles();
+
+ /** guards against directly changing the vertices
+
+ @return
+ the list of vertices
+ */
+ const vector<basegfx::B3DVector>& getVertices() const {return Vertices;}
+
+ /** guards against directly changing the vertices
+ */
+ const vector<basegfx::B3DVector>& getNormals() const {return Normals;}
+
+ /** guards against directly changing the vertices
+
+ @return
+ the list of Texture Coordinates
+
+ */
+ const vector<basegfx::B2DVector>& getTexCoords() const {return TexCoords;}
+
+ /** list of Operations to be performed on this primitive.These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
+
+ @return
+ the list of Operations
+
+ */
+ vector<Operation*> Operations;
+
+private:
+ /** list of vertices
+ */
+ vector<basegfx::B3DVector> Vertices;
+
+ /** list of Normals
+ */
+ vector<basegfx::B3DVector> Normals;
+
+ /** list of Texture Coordinates
+ */
+ vector<basegfx::B2DVector> TexCoords;
+};
+
+/** This class is to be derived to make any operation (tranform) you may need in order to construct your transitions
+*/
+class Operation
+{
+public:
+ Operation(){}
+ virtual ~Operation(){}
+
+ /** Should this operation be interpolated . If TRUE, the transform will smoothly move from making no difference from t = 0.0 to nT0 to being completely transformed from t = nT1 to 1. If FALSE, the transform will be inneffectual from t = 0 to nT0, and completely transformed from t = nT0 to 1.
+ */
+ bool bInterpolate;
+
+ /** time to begin the transformation
+ */
+ double nT0;
+
+ /** time to finish the transformation
+ */
+ double nT1;
+public:
+ /** this is the function that is called to give the Operation to OpenGL.
+
+ @param t
+ time from t = 0 to t = 1
+
+ @param SlideWidthScale
+ width of slide divided by width of window
+
+ @param SlideHeightScale
+ height of slide divided by height of window
+
+ */
+ virtual void interpolate(double t,double SlideWidthScale,double SlideHeightScale) = 0;
+
+ /** return a copy of this operation
+ */
+ virtual Operation* clone() = 0;
+};
+
+/** this class is a generic CounterClockWise(CCW) rotation with an axis angle
+*/
+class SRotate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ virtual SRotate* clone();
+
+ /** Constructor
+
+ @param Axis
+ axis to rotate about
+
+ @param Origin
+ position that rotation axis runs through
+
+ @param Angle
+ angle in radians of CCW rotation
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~SRotate(){}
+private:
+ /** axis to rotate CCW about
+ */
+ basegfx::B3DVector axis;
+
+ /** position that rotation axis runs through
+ */
+ basegfx::B3DVector origin;
+
+ /** angle in radians of CCW rotation
+ */
+ double angle;
+};
+
+/** scaling transformation
+*/
+class SScale: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ SScale* clone();
+
+ /** Constructor
+
+ @param Scale
+ amount to scale by
+
+ @param Origin
+ position that rotation axis runs through
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SScale(const basegfx::B3DVector& Scale, const basegfx::B3DVector& Origin,bool bInter, double T0, double T1);
+ ~SScale(){}
+private:
+ basegfx::B3DVector scale;
+ basegfx::B3DVector origin;
+};
+
+/** translation transformation
+*/
+class STranslate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ STranslate* clone();
+
+ /** Constructor
+
+ @param Vector
+ vector to translate
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ STranslate(const basegfx::B3DVector& Vector,bool bInter, double T0, double T1);
+ ~STranslate(){}
+private:
+ /** vector to translate by
+ */
+ basegfx::B3DVector vector;
+};
+
+/** translation transformation
+*/
+class SEllipseTranslate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ SEllipseTranslate* clone();
+
+ /** Constructor
+
+ @param Vector
+ vector to translate
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1);
+ ~SEllipseTranslate(){}
+private:
+ /** width and length of the ellipse
+ */
+ double width, height;
+
+ /** start and end position on the ellipse <0,1>
+ */
+ double startPosition;
+ double endPosition;
+};
+
+/** Same as SRotate, except the depth is scaled by the width of the slide divided by the width of the window.
+*/
+class RotateAndScaleDepthByWidth: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ RotateAndScaleDepthByWidth* clone();
+
+ RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~RotateAndScaleDepthByWidth(){}
+private:
+ basegfx::B3DVector axis;
+ basegfx::B3DVector origin;
+ double angle;
+};
+
+/** Same as SRotate, except the depth is scaled by the width of the slide divided by the height of the window.
+*/
+class RotateAndScaleDepthByHeight: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ RotateAndScaleDepthByHeight* clone();
+
+ RotateAndScaleDepthByHeight(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~RotateAndScaleDepthByHeight(){}
+private:
+ basegfx::B3DVector axis;
+ basegfx::B3DVector origin;
+ double angle;
+};
+
+#endif // INCLUDED_SLIDESHOW_TRANSITION_HXX_
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionerImpl.cxx b/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionerImpl.cxx
new file mode 100644
index 000000000000..08355e7b2111
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/unx/OGLTrans_TransitionerImpl.cxx
@@ -0,0 +1,1484 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define GLX_GLXEXT_PROTOTYPES 1
+#include "OGLTrans_TransitionImpl.hxx"
+
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/presentation/XTransitionFactory.hpp>
+#include <com/sun/star/presentation/XTransition.hpp>
+#include <com/sun/star/presentation/XSlideShowView.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/geometry/IntegerSize2D.hpp>
+
+#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/factory.hxx>
+#include <rtl/ref.hxx>
+
+#include <comphelper/servicedecl.hxx>
+
+#include <canvas/canvastools.hxx>
+#include <tools/gen.hxx>
+#include <vcl/window.hxx>
+#include <vcl/syschild.hxx>
+
+#include <boost/noncopyable.hpp>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+
+#if defined( WNT )
+ #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+ #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#elif defined( OS2 )
+#elif defined( QUARTZ )
+ #include "premac.h"
+ #include <Cocoa/Cocoa.h>
+ #include "postmac.h"
+#elif defined( UNX )
+namespace unx
+{
+#include <X11/keysym.h>
+#include <X11/X.h>
+#include <GL/glx.h>
+#include <GL/glxext.h>
+}
+#endif
+#include <vcl/sysdata.hxx>
+
+#ifdef DEBUG
+#include <boost/date_time/posix_time/posix_time.hpp>
+using namespace ::boost::posix_time;
+
+static ptime t1;
+static ptime t2;
+
+#define DBG(x) x
+#else
+#define DBG(x)
+#endif
+
+using namespace ::com::sun::star;
+using ::com::sun::star::beans::XFastPropertySet;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+
+namespace
+{
+
+typedef cppu::WeakComponentImplHelper1<presentation::XTransition> OGLTransitionerImplBase;
+
+namespace
+{
+ struct OGLFormat
+ {
+ GLint nInternalFormat;
+ GLenum eFormat;
+ GLenum eType;
+ };
+
+ /* channel ordering: (0:rgba, 1:bgra, 2:argb, 3:abgr)
+ */
+ int calcComponentOrderIndex(const uno::Sequence<sal_Int8>& rTags)
+ {
+ using namespace rendering::ColorComponentTag;
+
+ static const sal_Int8 aOrderTable[] =
+ {
+ RGB_RED, RGB_GREEN, RGB_BLUE, ALPHA,
+ RGB_BLUE, RGB_GREEN, RGB_RED, ALPHA,
+ ALPHA, RGB_RED, RGB_GREEN, RGB_BLUE,
+ ALPHA, RGB_BLUE, RGB_GREEN, RGB_RED,
+ };
+
+ const sal_Int32 nNumComps(rTags.getLength());
+ const sal_Int8* pLine=aOrderTable;
+ for(int i=0; i<4; ++i)
+ {
+ int j=0;
+ while( j<4 && j<nNumComps && pLine[j] == rTags[j] )
+ ++j;
+
+ // all of the line passed, this is a match!
+ if( j==nNumComps )
+ return i;
+
+ pLine+=4;
+ }
+
+ return -1;
+ }
+}
+
+// not thread safe
+static bool errorTriggered;
+int oglErrorHandler( unx::Display* /*dpy*/, unx::XErrorEvent* /*evnt*/ )
+{
+ errorTriggered = true;
+
+ return 0;
+}
+
+/** This is the Transitioner class for OpenGL 3D transitions in
+ * slideshow. At the moment, it's Linux only. This class is implicitly
+ * constructed from XTransitionFactory.
+*/
+class OGLTransitionerImpl : private cppu::BaseMutex, private boost::noncopyable, public OGLTransitionerImplBase
+{
+public:
+ explicit OGLTransitionerImpl(OGLTransitionImpl* pOGLTransition);
+ bool initWindowFromSlideShowView( const uno::Reference< presentation::XSlideShowView >& xView );
+ void setSlides( const Reference< rendering::XBitmap >& xLeavingSlide , const uno::Reference< rendering::XBitmap >& xEnteringSlide );
+ static bool initialize( const Reference< presentation::XSlideShowView >& xView );
+
+ // XTransition
+ virtual void SAL_CALL update( double nTime )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL viewChanged( const Reference< presentation::XSlideShowView >& rView,
+ const Reference< rendering::XBitmap >& rLeavingBitmap,
+ const Reference< rendering::XBitmap >& rEnteringBitmap )
+ throw (uno::RuntimeException);
+
+protected:
+ void disposeContextAndWindow();
+ void disposeTextures();
+
+ // WeakComponentImplHelperBase
+ virtual void SAL_CALL disposing();
+
+ bool isDisposed() const
+ {
+ return (rBHelper.bDisposed || rBHelper.bInDispose);
+ }
+
+ bool createWindow( Window* pPWindow );
+ void createTexture( unsigned int* texID,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXPixmap pixmap,
+ bool usePixmap,
+#endif
+ bool useMipmap,
+ uno::Sequence<sal_Int8>& data,
+ const OGLFormat* pFormat );
+ void prepareEnvironment ();
+ const OGLFormat* chooseFormats();
+
+private:
+ /** After the window has been created, and the slides have been set, we'll initialize the slides with OpenGL.
+ */
+ void GLInitSlides();
+
+
+ /// Holds the information of our new child window
+ struct GLWindow
+ {
+#if defined( WNT )
+ HWND hWnd;
+ HDC hDC;
+ HGLRC hRC;
+#elif defined( OS2 )
+#elif defined( QUARTZ )
+#elif defined( UNX )
+ unx::Display* dpy;
+ int screen;
+ unx::Window win;
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXFBConfig fbc;
+#endif
+ unx::XVisualInfo* vi;
+ unx::GLXContext ctx;
+#endif
+ unsigned int bpp;
+ unsigned int Width;
+ unsigned int Height;
+ const char* GLXExtensions;
+ const GLubyte* GLExtensions;
+
+ bool HasGLXExtension( const char* name ) { return gluCheckExtension( (const GLubyte*) name, (const GLubyte*) GLXExtensions ); }
+ bool HasGLExtension( const char* name ) { return gluCheckExtension( (const GLubyte*) name, GLExtensions ); }
+ } GLWin;
+
+ /** OpenGL handle to the leaving slide's texture
+ */
+ unsigned int GLleavingSlide;
+ /** OpenGL handle to the entering slide's texture
+ */
+ unsigned int GLenteringSlide;
+
+ /** pointer to our window which we MIGHT create.
+ */
+ class SystemChildWindow* pWindow;
+
+ Reference< presentation::XSlideShowView > mxView;
+ Reference< rendering::XIntegerBitmap > mxLeavingBitmap;
+ Reference< rendering::XIntegerBitmap > mxEnteringBitmap;
+
+ /** raw bytes of the entering bitmap
+ */
+ uno::Sequence<sal_Int8> EnteringBytes;
+
+ /** raw bytes of the leaving bitmap
+ */
+ uno::Sequence<sal_Int8> LeavingBytes;
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXPixmap LeavingPixmap;
+ unx::GLXPixmap EnteringPixmap;
+#endif
+ bool mbRestoreSync;
+ bool mbUseLeavingPixmap;
+ bool mbUseEnteringPixmap;
+ bool mbFreeLeavingPixmap;
+ bool mbFreeEnteringPixmap;
+ unx::Pixmap maLeavingPixmap;
+ unx::Pixmap maEnteringPixmap;
+
+ /** the form the raw bytes are in for the bitmaps
+ */
+ rendering::IntegerBitmapLayout SlideBitmapLayout;
+
+ /** the size of the slides
+ */
+ geometry::IntegerSize2D SlideSize;
+
+ /** Our Transition to be used.
+ */
+ OGLTransitionImpl* pTransition;
+
+public:
+ /** whether we are running on ATI fglrx with bug related to textures
+ */
+ static bool cbBrokenTexturesATI;
+
+ /** GL version
+ */
+ static float cnGLVersion;
+ float mnGLXVersion;
+
+ /** Whether Mesa is the OpenGL vendor
+ */
+ static bool cbMesa;
+
+ /**
+ whether the display has GLX extension
+ */
+ static bool cbGLXPresent;
+
+ /**
+ whether texture from pixmap extension is available
+ */
+ bool mbTextureFromPixmap;
+
+ /**
+ whether to generate mipmaped textures
+ */
+ bool mbGenerateMipmap;
+
+ /**
+ whether we have visual which can be used for texture_from_pixmap extension
+ */
+ bool mbHasTFPVisual;
+
+#ifdef DEBUG
+ ptime t3;
+ ptime t4;
+ ptime t5;
+ ptime t6;
+ time_duration total_update;
+ int frame_count;
+#endif
+};
+
+// declare the static variables as some gcc versions have problems declaring them automaticaly
+bool OGLTransitionerImpl::cbBrokenTexturesATI;
+float OGLTransitionerImpl::cnGLVersion;
+bool OGLTransitionerImpl::cbMesa;
+bool OGLTransitionerImpl::cbGLXPresent;
+
+bool OGLTransitionerImpl::initialize( const Reference< presentation::XSlideShowView >& xView )
+{
+ // not thread safe
+ static bool initialized = false;
+
+ if( !initialized ) {
+ OGLTransitionerImpl *instance;
+
+ instance = new OGLTransitionerImpl( NULL );
+ if( instance->initWindowFromSlideShowView( xView ) ) {
+
+ const GLubyte* version = glGetString( GL_VERSION );
+ if( version && version[0] ) {
+ cnGLVersion = version[0] - '0';
+ if( version[1] == '.' && version[2] )
+ cnGLVersion += (version[2] - '0')/10.0;
+ } else
+ cnGLVersion = 1.0;
+ OSL_TRACE("GL version: %s parsed: %f", version, cnGLVersion );
+
+ const GLubyte* vendor = glGetString( GL_VENDOR );
+ cbMesa = ( vendor && strstr( (const char *) vendor, "Mesa" ) );
+ OSL_TRACE("GL vendor: %s identified as Mesa: %d", vendor, cbMesa );
+
+ /* TODO: check for version once the bug in fglrx driver is fixed */
+ cbBrokenTexturesATI = (vendor && strcmp( (const char *) vendor, "ATI Technologies Inc." ) == 0 );
+
+ instance->disposing();
+ cbGLXPresent = true;
+ } else
+ cbGLXPresent = false;
+
+ delete instance;
+ initialized = true;
+ }
+
+ return cbGLXPresent;
+}
+
+bool OGLTransitionerImpl::createWindow( Window* pPWindow )
+{
+ const SystemEnvData* sysData(pPWindow->GetSystemData());
+#if defined( WNT )
+ GLWin.hWnd = sysData->hWnd;
+#elif defined( UNX )
+ GLWin.dpy = reinterpret_cast<unx::Display*>(sysData->pDisplay);
+
+ if( unx::glXQueryExtension( GLWin.dpy, NULL, NULL ) == false )
+ return false;
+
+ GLWin.win = sysData->aWindow;
+
+ OSL_TRACE("parent window: %d", GLWin.win);
+
+ unx::XWindowAttributes xattr;
+ unx::XGetWindowAttributes( GLWin.dpy, GLWin.win, &xattr );
+
+ GLWin.screen = XScreenNumberOfScreen( xattr.screen );
+
+ unx::XVisualInfo* vi( NULL );
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::XVisualInfo* visinfo;
+ unx::XVisualInfo* firstVisual( NULL );
+#endif
+ static int attrList3[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ //single buffered
+ GLX_RED_SIZE,4,//use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,//use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,//use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,0,//no depth buffer
+ None
+ };
+ static int attrList2[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ /// single buffered
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
+ None
+ };
+ static int attrList1[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ GLX_DOUBLEBUFFER,/// only double buffer
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,0,/// no depth buffer
+ None
+ };
+ static int attrList0[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ GLX_DOUBLEBUFFER,/// only double buffer
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
+ None
+ };
+ static int* attrTable[] =
+ {
+ attrList0,
+ attrList1,
+ attrList2,
+ attrList3,
+ NULL
+ };
+ int** pAttributeTable = attrTable;
+ const SystemEnvData* pChildSysData = NULL;
+ delete pWindow;
+ pWindow=NULL;
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXFBConfig* fbconfigs = NULL;
+ int nfbconfigs, value, i = 0;
+#endif
+
+ while( *pAttributeTable )
+ {
+ // try to find a visual for the current set of attributes
+ vi = unx::glXChooseVisual( GLWin.dpy,
+ GLWin.screen,
+ *pAttributeTable );
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ if( vi ) {
+ if( !firstVisual )
+ firstVisual = vi;
+ OSL_TRACE("trying VisualID %08X", vi->visualid);
+ fbconfigs = glXGetFBConfigs (GLWin.dpy, GLWin.screen, &nfbconfigs);
+ for ( ; i < nfbconfigs; i++)
+ {
+ visinfo = glXGetVisualFromFBConfig (GLWin.dpy, fbconfigs[i]);
+ if( !visinfo || visinfo->visualid != vi->visualid )
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i], GLX_DRAWABLE_TYPE, &value);
+ if (!(value & GLX_PIXMAP_BIT))
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i],
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT,
+ &value);
+ if (!(value & GLX_TEXTURE_2D_BIT_EXT))
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i],
+ GLX_BIND_TO_TEXTURE_RGB_EXT,
+ &value);
+ if (value == sal_False)
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i],
+ GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
+ &value);
+ if (value == sal_False)
+ continue;
+
+ /* TODO: handle non Y inverted cases */
+ break;
+ }
+
+ if( i != nfbconfigs || ( firstVisual && pAttributeTable[1] == NULL ) ) {
+ if( i != nfbconfigs ) {
+ vi = glXGetVisualFromFBConfig( GLWin.dpy, fbconfigs[i] );
+ mbHasTFPVisual = true;
+ OSL_TRACE("found visual suitable for texture_from_pixmap");
+ } else {
+ vi = firstVisual;
+ mbHasTFPVisual = false;
+ OSL_TRACE("did not find visual suitable for texture_from_pixmap, using %08X", vi->visualid);
+ }
+#else
+ if( vi ) {
+#endif
+ SystemWindowData winData;
+ winData.nSize = sizeof(winData);
+ OSL_TRACE("using VisualID %08X", vi->visualid);
+ winData.pVisual = (void*)(vi->visual);
+ pWindow=new SystemChildWindow(pPWindow, 0, &winData, sal_False);
+ pChildSysData = pWindow->GetSystemData();
+ if( pChildSysData ) {
+ break;
+ } else {
+ delete pWindow, pWindow=NULL;
+ }
+ }
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ }
+#endif
+
+ ++pAttributeTable;
+ }
+#endif
+
+#if defined( WNT )
+ const SystemEnvData* pChildSysData = NULL;
+ SystemWindowData winData;
+ winData.nSize = sizeof(winData);
+ pWindow=new SystemChildWindow(pPWindow, 0, &winData, sal_False);
+ pChildSysData = pWindow->GetSystemData();
+#endif
+
+ if( pWindow )
+ {
+ pWindow->SetMouseTransparent( sal_True );
+ pWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ pWindow->EnableEraseBackground( sal_False );
+ pWindow->SetControlForeground();
+ pWindow->SetControlBackground();
+ pWindow->EnablePaint(sal_False);
+#if defined( WNT )
+ GLWin.hWnd = sysData->hWnd;
+#elif defined( UNX )
+ GLWin.dpy = reinterpret_cast<unx::Display*>(pChildSysData->pDisplay);
+ GLWin.win = pChildSysData->aWindow;
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ if( mbHasTFPVisual )
+ GLWin.fbc = fbconfigs[i];
+#endif
+ GLWin.vi = vi;
+ GLWin.GLXExtensions = unx::glXQueryExtensionsString( GLWin.dpy, GLWin.screen );
+ OSL_TRACE("available GLX extensions: %s", GLWin.GLXExtensions);
+#endif
+
+ return true;
+ }
+
+ return false;
+}
+
+bool OGLTransitionerImpl::initWindowFromSlideShowView( const Reference< presentation::XSlideShowView >& xView )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ mxView.set( xView, UNO_QUERY );
+ if( !mxView.is() )
+ return false;
+
+ /// take the XSlideShowView and extract the parent window from it. see viewmediashape.cxx
+ uno::Reference< rendering::XCanvas > xCanvas(mxView->getCanvas(), uno::UNO_QUERY_THROW);
+ uno::Sequence< uno::Any > aDeviceParams;
+ ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams );
+
+ ::rtl::OUString aImplName;
+ aDeviceParams[ 0 ] >>= aImplName;
+
+ sal_Int64 aVal = 0;
+ aDeviceParams[1] >>= aVal;
+ if( !createWindow( reinterpret_cast< Window* >( aVal ) ) )
+ return false;
+
+ awt::Rectangle aCanvasArea = mxView->getCanvasArea();
+ pWindow->SetPosSizePixel(aCanvasArea.X, aCanvasArea.Y, aCanvasArea.Width, aCanvasArea.Height);
+ GLWin.Width = aCanvasArea.Width;
+ GLWin.Height = aCanvasArea.Height;
+ OSL_TRACE("canvas area: %d,%d - %dx%d", aCanvasArea.X, aCanvasArea.Y, aCanvasArea.Width, aCanvasArea.Height);
+
+#if defined( WNT )
+ GLWin.hDC = GetDC(GLWin.hWnd);
+#elif defined( UNX )
+ GLWin.ctx = glXCreateContext(GLWin.dpy,
+ GLWin.vi,
+ 0,
+ GL_TRUE);
+ if( GLWin.ctx == NULL ) {
+ OSL_TRACE("unable to create GLX context");
+ return false;
+ }
+#endif
+
+#if defined( WNT )
+ PIXELFORMATDESCRIPTOR PixelFormatFront = // PixelFormat Tells Windows How We Want Things To Be
+ {
+ sizeof(PIXELFORMATDESCRIPTOR),
+ 1, // Version Number
+ PFD_DRAW_TO_WINDOW |
+ PFD_SUPPORT_OPENGL |
+ PFD_DOUBLEBUFFER,
+ PFD_TYPE_RGBA, // Request An RGBA Format
+ (BYTE)32, // Select Our Color Depth
+ 0, 0, 0, 0, 0, 0, // Color Bits Ignored
+ 0, // No Alpha Buffer
+ 0, // Shift Bit Ignored
+ 0, // No Accumulation Buffer
+ 0, 0, 0, 0, // Accumulation Bits Ignored
+ 64, // 32 bit Z-BUFFER
+ 0, // 0 bit stencil buffer
+ 0, // No Auxiliary Buffer
+ 0, // now ignored
+ 0, // Reserved
+ 0, 0, 0 // Layer Masks Ignored
+ };
+ int WindowPix = ChoosePixelFormat(GLWin.hDC,&PixelFormatFront);
+ SetPixelFormat(GLWin.hDC,WindowPix,&PixelFormatFront);
+ GLWin.hRC = wglCreateContext(GLWin.hDC);
+ wglMakeCurrent(GLWin.hDC,GLWin.hRC);
+#elif defined( UNX )
+ if( !glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx ) ) {
+ OSL_TRACE("unable to select current GLX context");
+ return false;
+ }
+
+ int glxMinor, glxMajor;
+ mnGLXVersion = 0;
+ if( glXQueryVersion( GLWin.dpy, &glxMajor, &glxMinor ) )
+ mnGLXVersion = glxMajor + 0.1*glxMinor;
+ OSL_TRACE("available GLX version: %f", mnGLXVersion);
+
+ GLWin.GLExtensions = glGetString( GL_EXTENSIONS );
+ OSL_TRACE("available GL extensions: %s", GLWin.GLExtensions);
+
+ mbTextureFromPixmap = GLWin.HasGLXExtension( "GLX_EXT_texture_from_pixmap" );
+ mbGenerateMipmap = GLWin.HasGLExtension( "GL_SGIS_generate_mipmap" );
+
+ if( GLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) {
+ // enable vsync
+ typedef GLint (*glXSwapIntervalProc)(GLint);
+ glXSwapIntervalProc glXSwapInterval = (glXSwapIntervalProc) unx::glXGetProcAddress( (const GLubyte*) "glXSwapIntervalSGI" );
+ if( glXSwapInterval ) {
+ int (*oldHandler)(unx::Display* /*dpy*/, unx::XErrorEvent* /*evnt*/);
+
+ // replace error handler temporarily
+ oldHandler = unx::XSetErrorHandler( oglErrorHandler );
+
+ errorTriggered = false;
+
+ glXSwapInterval( 1 );
+
+ // sync so that we possibly get an XError
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ if( errorTriggered )
+ OSL_TRACE("error when trying to set swap interval, NVIDIA or Mesa bug?");
+ else
+ OSL_TRACE("set swap interval to 1 (enable vsync)");
+
+ // restore the error handler
+ unx::XSetErrorHandler( oldHandler );
+ }
+ }
+#endif
+
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glClearColor (0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+#if defined( WNT )
+ SwapBuffers(GLWin.hDC);
+#elif defined( UNX )
+ unx::glXSwapBuffers(GLWin.dpy, GLWin.win);
+#endif
+
+ glEnable(GL_LIGHTING);
+ GLfloat light_direction[] = { 0.0 , 0.0 , 1.0 };
+ GLfloat materialDiffuse[] = { 1.0 , 1.0 , 1.0 , 1.0};
+ glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
+ glMaterialfv(GL_FRONT,GL_DIFFUSE,materialDiffuse);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_NORMALIZE);
+
+ if( LeavingBytes.hasElements() && EnteringBytes.hasElements())
+ GLInitSlides();//we already have uninitialized slides, let's initialize
+
+ if( pTransition && pTransition->mnRequiredGLVersion <= cnGLVersion )
+ pTransition->prepare( GLleavingSlide, GLenteringSlide );
+
+ return true;
+}
+
+void OGLTransitionerImpl::setSlides( const uno::Reference< rendering::XBitmap >& xLeavingSlide,
+ const uno::Reference< rendering::XBitmap >& xEnteringSlide )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ mxLeavingBitmap.set( xLeavingSlide , UNO_QUERY_THROW );
+ mxEnteringBitmap.set( xEnteringSlide , UNO_QUERY_THROW );
+ Reference< XFastPropertySet > xLeavingSet( xLeavingSlide , UNO_QUERY );
+ Reference< XFastPropertySet > xEnteringSet( xEnteringSlide , UNO_QUERY );
+
+ geometry::IntegerRectangle2D SlideRect;
+ SlideSize = mxLeavingBitmap->getSize();
+ SlideRect.X1 = 0;
+ SlideRect.X2 = SlideSize.Width;
+ SlideRect.Y1 = 0;
+ SlideRect.Y2 = SlideSize.Height;
+
+ OSL_TRACE("leaving bitmap area: %dx%d", SlideSize.Width, SlideSize.Height);
+ SlideSize = mxEnteringBitmap->getSize();
+ OSL_TRACE("entering bitmap area: %dx%d", SlideSize.Width, SlideSize.Height);
+
+#ifdef UNX
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+#endif
+
+#ifdef DEBUG
+ t1 = microsec_clock::local_time();
+#endif
+
+ mbUseLeavingPixmap = false;
+ mbUseEnteringPixmap = false;
+
+#ifdef UNX
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+
+ if( mnGLXVersion >= 1.2999 && mbTextureFromPixmap && xLeavingSet.is() && xEnteringSet.is() && mbHasTFPVisual ) {
+ Sequence< Any > leaveArgs;
+ Sequence< Any > enterArgs;
+ if( (xLeavingSet->getFastPropertyValue( 1 ) >>= leaveArgs) &&
+ (xEnteringSet->getFastPropertyValue( 1 ) >>= enterArgs) ) {
+ OSL_TRACE ("pixmaps available");
+
+ sal_Int32 depth(0);
+
+ leaveArgs[0] >>= mbFreeLeavingPixmap;
+ enterArgs[0] >>= mbFreeEnteringPixmap;
+ leaveArgs[1] >>= maLeavingPixmap;
+ enterArgs[1] >>= maEnteringPixmap;
+ leaveArgs[2] >>= depth;
+
+ int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
+ GLX_MIPMAP_TEXTURE_EXT, True,
+ None };
+
+
+ // sync so that we possibly get an pending XError, before we set our handler.
+ // this way we will not miss any error from other code
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ int (*oldHandler)(unx::Display* /*dpy*/, unx::XErrorEvent* /*evnt*/);
+
+ // replace error handler temporarily
+ oldHandler = unx::XSetErrorHandler( oglErrorHandler );
+
+ errorTriggered = false;
+ LeavingPixmap = glXCreatePixmap( GLWin.dpy, GLWin.fbc, maLeavingPixmap, pixmapAttribs );
+
+ // sync so that we possibly get an XError
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ if( !errorTriggered )
+ mbUseLeavingPixmap = true;
+ else {
+ OSL_TRACE("XError triggered");
+ if( mbFreeLeavingPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maLeavingPixmap );
+ mbFreeLeavingPixmap = false;
+ }
+ errorTriggered = false;
+ }
+
+ EnteringPixmap = glXCreatePixmap( GLWin.dpy, GLWin.fbc, maEnteringPixmap, pixmapAttribs );
+
+ // sync so that we possibly get an XError
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ OSL_TRACE("created glx pixmap %p and %p depth: %d", LeavingPixmap, EnteringPixmap, depth);
+ if( !errorTriggered )
+ mbUseEnteringPixmap = true;
+ else {
+ OSL_TRACE("XError triggered");
+ if( mbFreeEnteringPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maEnteringPixmap );
+ mbFreeEnteringPixmap = false;
+ }
+ }
+
+ // restore the error handler
+ unx::XSetErrorHandler( oldHandler );
+ }
+ }
+
+#endif
+#endif
+ if( !mbUseLeavingPixmap )
+ LeavingBytes = mxLeavingBitmap->getData(SlideBitmapLayout,SlideRect);
+ if( !mbUseEnteringPixmap )
+ EnteringBytes = mxEnteringBitmap->getData(SlideBitmapLayout,SlideRect);
+
+// TODO
+#ifdef UNX
+ if(GLWin.ctx)//if we have a rendering context, let's init the slides
+#endif
+ GLInitSlides();
+
+ OSL_ENSURE(SlideBitmapLayout.PlaneStride == 0,"only handle no plane stride now");
+
+#ifdef UNX
+ /* flush & sync */
+ unx::glXWaitGL();
+ XSync( GLWin.dpy, false );
+
+ // synchronized X still gives us much smoother play
+ // I suspect some issues in above code in slideshow
+ // synchronize whole transition for now
+ XSynchronize( GLWin.dpy, true );
+ mbRestoreSync = true;
+#endif
+}
+
+void OGLTransitionerImpl::createTexture( unsigned int* texID,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXPixmap pixmap,
+ bool usePixmap,
+#endif
+ bool useMipmap,
+ uno::Sequence<sal_Int8>& data,
+ const OGLFormat* pFormat )
+{
+ glDeleteTextures( 1, texID );
+ glGenTextures( 1, texID );
+ glBindTexture( GL_TEXTURE_2D, *texID );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::PFNGLXBINDTEXIMAGEEXTPROC myglXBindTexImageEXT = (unx::PFNGLXBINDTEXIMAGEEXTPROC) unx::glXGetProcAddress( (const GLubyte*) "glXBindTexImageEXT" );
+
+ if( usePixmap ) {
+ if( mbGenerateMipmap )
+ glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, True);
+ myglXBindTexImageEXT (GLWin.dpy, pixmap, GLX_FRONT_LEFT_EXT, NULL);
+ if( mbGenerateMipmap && useMipmap ) {
+ OSL_TRACE("use mipmaps");
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //TRILINEAR FILTERING
+ } else {
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+ }
+ } else {
+#endif
+ if( !pFormat )
+ {
+ // force-convert color to ARGB8888 int color space
+ uno::Sequence<sal_Int8> tempBytes(
+ SlideBitmapLayout.ColorSpace->convertToIntegerColorSpace(
+ data,
+ canvas::tools::getStdColorSpace()));
+ gluBuild2DMipmaps(GL_TEXTURE_2D,
+ 4,
+ SlideSize.Width,
+ SlideSize.Height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ &tempBytes[0]);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //TRILINEAR FILTERING
+
+ //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles)
+ GLfloat largest_supported_anisotropy;
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy);
+ } else {
+ if( pTransition && !cbBrokenTexturesATI && !useMipmap) {
+ glTexImage2D( GL_TEXTURE_2D, 0, pFormat->nInternalFormat, SlideSize.Width, SlideSize.Height, 0, pFormat->eFormat, pFormat->eType, &data[0] );
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+ } else {
+ gluBuild2DMipmaps( GL_TEXTURE_2D, pFormat->nInternalFormat, SlideSize.Width, SlideSize.Height, pFormat->eFormat, pFormat->eType, &data[0] );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); //TRILINEAR FILTERING
+
+ //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles)
+ GLfloat largest_supported_anisotropy;
+ glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy );
+ }
+ }
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ }
+#endif
+ OSL_ENSURE(glIsTexture(*texID), "Can't generate Leaving slide textures in OpenGL");
+}
+
+void OGLTransitionerImpl::prepareEnvironment()
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ double EyePos(10.0);
+ double RealF(1.0);
+ double RealN(-1.0);
+ double RealL(-1.0);
+ double RealR(1.0);
+ double RealB(-1.0);
+ double RealT(1.0);
+ double ClipN(EyePos+5.0*RealN);
+ double ClipF(EyePos+15.0*RealF);
+ double ClipL(RealL*8.0);
+ double ClipR(RealR*8.0);
+ double ClipB(RealB*8.0);
+ double ClipT(RealT*8.0);
+ //This scaling is to take the plane with BottomLeftCorner(-1,-1,0) and TopRightCorner(1,1,0) and map it to the screen after the perspective division.
+ glScaled( 1.0 / ( ( ( RealR * 2.0 * ClipN ) / ( EyePos * ( ClipR - ClipL ) ) ) - ( ( ClipR + ClipL ) / ( ClipR - ClipL ) ) ),
+ 1.0 / ( ( ( RealT * 2.0 * ClipN ) / ( EyePos * ( ClipT - ClipB ) ) ) - ( ( ClipT + ClipB ) / ( ClipT - ClipB ) ) ),
+ 1.0 );
+ glFrustum(ClipL,ClipR,ClipB,ClipT,ClipN,ClipF);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslated(0,0,-EyePos);
+}
+
+const OGLFormat* OGLTransitionerImpl::chooseFormats()
+{
+ const OGLFormat* pDetectedFormat=NULL;
+ uno::Reference<rendering::XIntegerBitmapColorSpace> xIntColorSpace(
+ SlideBitmapLayout.ColorSpace);
+
+ if( (xIntColorSpace->getType() == rendering::ColorSpaceType::RGB ||
+ xIntColorSpace->getType() == rendering::ColorSpaceType::SRGB) )
+ {
+ /* table for canvas->OGL format mapping. outer index is number
+ of color components (0:3, 1:4), then comes bits per pixel
+ (0:16, 1:24, 2:32), then channel ordering: (0:rgba, 1:bgra,
+ 2:argb, 3:abgr)
+ */
+ static const OGLFormat lcl_RGB24[] =
+ {
+ // 24 bit RGB
+ {3, GL_BGR, GL_UNSIGNED_BYTE},
+ {3, GL_RGB, GL_UNSIGNED_BYTE},
+ {3, GL_BGR, GL_UNSIGNED_BYTE},
+ {3, GL_RGB, GL_UNSIGNED_BYTE}
+ };
+
+#if defined(GL_VERSION_1_2) && defined(GLU_VERSION_1_3)
+ // more format constants available
+ static const OGLFormat lcl_RGB16[] =
+ {
+ // 16 bit RGB
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}
+ };
+
+ static const OGLFormat lcl_ARGB16_4[] =
+ {
+ // 16 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4},
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}
+ };
+
+ static const OGLFormat lcl_ARGB16_5[] =
+ {
+ // 16 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_5_5_5_1},
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}
+ };
+
+ static const OGLFormat lcl_ARGB32[] =
+ {
+ // 32 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
+ {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV},
+ {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8},
+ {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}
+ };
+
+ const uno::Sequence<sal_Int8> aComponentTags(
+ xIntColorSpace->getComponentTags());
+ const uno::Sequence<sal_Int32> aComponentBitcounts(
+ xIntColorSpace->getComponentBitCounts());
+ const sal_Int32 nNumComponents( aComponentBitcounts.getLength() );
+ const sal_Int32 nBitsPerPixel( xIntColorSpace->getBitsPerPixel() );
+
+ // supported component ordering?
+ const int nComponentOrderIndex(
+ calcComponentOrderIndex(aComponentTags));
+ if( nComponentOrderIndex != -1 )
+ {
+ switch( nBitsPerPixel )
+ {
+ case 16:
+ if( nNumComponents == 3 )
+ {
+ pDetectedFormat = &lcl_RGB16[nComponentOrderIndex];
+ }
+ else if( nNumComponents == 4 )
+ {
+ if( aComponentBitcounts[1] == 4 )
+ {
+ pDetectedFormat = &lcl_ARGB16_4[nComponentOrderIndex];
+ }
+ else if( aComponentBitcounts[1] == 5 )
+ {
+ pDetectedFormat = &lcl_ARGB16_5[nComponentOrderIndex];
+ }
+ }
+ break;
+ case 24:
+ if( nNumComponents == 3 )
+ {
+ pDetectedFormat = &lcl_RGB24[nComponentOrderIndex];
+ }
+ break;
+ case 32:
+ pDetectedFormat = &lcl_ARGB32[nComponentOrderIndex];
+ break;
+ }
+ }
+#else
+ const uno::Sequence<sal_Int8> aComponentTags(
+ xIntColorSpace->getComponentTags());
+ const int nComponentOrderIndex(calcComponentOrderIndex(aComponentTags));
+ if( aComponentTags.getLength() == 3 &&
+ nComponentOrderIndex != -1 &&
+ xIntColorSpace->getBitsPerPixel() == 24 )
+ {
+ pDetectedFormat = &lcl_RGB24[nComponentOrderIndex];
+ }
+#endif
+ }
+
+ return pDetectedFormat;
+}
+
+void OGLTransitionerImpl::GLInitSlides()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed() || pTransition->mnRequiredGLVersion > cnGLVersion)
+ return;
+
+ prepareEnvironment();
+
+ const OGLFormat* pFormat = NULL;
+ if( !mbUseLeavingPixmap || !mbUseEnteringPixmap )
+ pFormat = chooseFormats();
+
+ createTexture( &GLleavingSlide,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ LeavingPixmap,
+ mbUseLeavingPixmap,
+#endif
+ pTransition->mbUseMipMapLeaving,
+ LeavingBytes,
+ pFormat );
+
+ createTexture( &GLenteringSlide,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ EnteringPixmap,
+ mbUseEnteringPixmap,
+#endif
+ pTransition->mbUseMipMapEntering,
+ EnteringBytes,
+ pFormat );
+
+#ifdef UNX
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+#endif
+
+#ifdef DEBUG
+ t2 = microsec_clock::local_time();
+ OSL_TRACE("textures created in: %s", to_simple_string( t2 - t1 ).c_str());
+#endif
+}
+
+void SAL_CALL OGLTransitionerImpl::update( double nTime ) throw (uno::RuntimeException)
+{
+#ifdef DEBUG
+ frame_count ++;
+ t3 = microsec_clock::local_time();
+ if( frame_count == 1 ) {
+ t5 = t3;
+ total_update = seconds (0);
+ }
+#endif
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed() || !cbGLXPresent || pTransition->mnRequiredGLVersion > cnGLVersion)
+ return;
+
+#ifdef WNT
+ wglMakeCurrent(GLWin.hDC,GLWin.hRC);
+#endif
+#ifdef UNX
+ glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx );
+#endif
+
+ glEnable(GL_DEPTH_TEST);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if(pTransition)
+ pTransition->display( nTime, GLleavingSlide, GLenteringSlide,
+ SlideSize.Width, SlideSize.Height,
+ static_cast<double>(GLWin.Width),
+ static_cast<double>(GLWin.Height) );
+
+#if defined( WNT )
+ SwapBuffers(GLWin.hDC);
+#elif defined( UNX )
+ unx::glXSwapBuffers(GLWin.dpy, GLWin.win);
+#endif
+ if( pWindow )
+ pWindow->Show();
+
+#ifdef UNX
+ /* flush & sync */
+ unx::glXWaitGL();
+ XSync( GLWin.dpy, false );
+#endif
+
+#ifdef DEBUG
+ t4 = microsec_clock::local_time();
+
+ OSL_TRACE("update time: %f", nTime);
+ OSL_TRACE("update took: %s", to_simple_string( t4 - t3 ).c_str());
+ total_update += (t4 - t3);
+#endif
+}
+
+void SAL_CALL OGLTransitionerImpl::viewChanged( const Reference< presentation::XSlideShowView >& rView,
+ const Reference< rendering::XBitmap >& rLeavingBitmap,
+ const Reference< rendering::XBitmap >& rEnteringBitmap )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE("transitioner: view changed");
+
+ disposeTextures();
+ disposeContextAndWindow();
+
+ initWindowFromSlideShowView( rView );
+ setSlides( rLeavingBitmap, rEnteringBitmap );
+}
+
+void OGLTransitionerImpl::disposeContextAndWindow()
+{
+#if defined( WNT )
+ if (GLWin.hRC)
+ {
+ wglMakeCurrent( GLWin.hDC, 0 ); // kill Device Context
+ wglDeleteContext( GLWin.hRC ); // Kill Render Context
+ ReleaseDC( GLWin.hWnd, GLWin.hDC ); // Release Window
+ }
+#elif defined( UNX )
+ if(GLWin.ctx)
+ {
+ glXMakeCurrent(GLWin.dpy, None, NULL);
+ if( glGetError() != GL_NO_ERROR ) {
+ OSL_TRACE("glError: %s", (char *)gluErrorString(glGetError()));
+ }
+ glXDestroyContext(GLWin.dpy, GLWin.ctx);
+ GLWin.ctx = NULL;
+ }
+#endif
+ if( pWindow ) {
+ delete pWindow;
+ pWindow = NULL;
+ GLWin.win = 0;
+ }
+}
+
+void OGLTransitionerImpl::disposeTextures()
+{
+#ifdef WNT
+ wglMakeCurrent(GLWin.hDC,GLWin.hRC);
+#endif
+#ifdef UNX
+ glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx );
+#endif
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::PFNGLXRELEASETEXIMAGEEXTPROC myglXReleaseTexImageEXT = (unx::PFNGLXRELEASETEXIMAGEEXTPROC) unx::glXGetProcAddress( (const GLubyte*) "glXReleaseTexImageEXT" );
+ if( mbUseLeavingPixmap ) {
+
+ myglXReleaseTexImageEXT( GLWin.dpy, LeavingPixmap, GLX_FRONT_LEFT_EXT );
+ glXDestroyGLXPixmap( GLWin.dpy, LeavingPixmap );
+ LeavingPixmap = 0;
+ if( mbFreeLeavingPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maLeavingPixmap );
+ mbFreeLeavingPixmap = false;
+ maLeavingPixmap = 0;
+ }
+ }
+ if( mbUseEnteringPixmap ) {
+ myglXReleaseTexImageEXT( GLWin.dpy, EnteringPixmap, GLX_FRONT_LEFT_EXT );
+ glXDestroyGLXPixmap( GLWin.dpy, EnteringPixmap );
+ EnteringPixmap = 0;
+ if( mbFreeEnteringPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maEnteringPixmap );
+ mbFreeEnteringPixmap = false;
+ maEnteringPixmap = 0;
+ }
+ }
+#endif
+
+ if( !mbUseLeavingPixmap ) {
+ glDeleteTextures(1,&GLleavingSlide);
+ GLleavingSlide = 0;
+ }
+ if( !mbUseEnteringPixmap ) {
+ glDeleteTextures(1,&GLenteringSlide);
+ GLleavingSlide = 0;
+ }
+
+ mbUseLeavingPixmap = false;
+ mbUseEnteringPixmap = false;
+}
+
+// we are about to be disposed (someone call dispose() on us)
+void OGLTransitionerImpl::disposing()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+#ifdef DEBUG
+ OSL_TRACE("dispose %p\n", this);
+ if( frame_count ) {
+ t6 = microsec_clock::local_time();
+ time_duration duration = t6 - t5;
+ OSL_TRACE("whole transition (frames: %d) took: %s fps: %f time spent in updates: %s percentage of transition time: %f%%",
+ frame_count, to_simple_string( duration ).c_str(),
+ ((double)frame_count*1000000000.0)/duration.total_nanoseconds(),
+ to_simple_string( total_update ).c_str(),
+ 100*(((double)total_update.total_nanoseconds())/((double)duration.total_nanoseconds()))
+ );
+ }
+#endif
+
+ if( pWindow ) {
+
+ disposeTextures();
+
+ if (pTransition)
+ pTransition->finish();
+
+#ifdef UNX
+ if( mbRestoreSync ) {
+ // try to reestablish synchronize state
+ char* sal_synchronize = getenv("SAL_SYNCHRONIZE");
+ XSynchronize( GLWin.dpy, sal_synchronize && *sal_synchronize == '1' );
+ }
+#endif
+
+ disposeContextAndWindow();
+ }
+
+ if (pTransition)
+ delete pTransition;
+
+ mxLeavingBitmap.clear();
+ mxEnteringBitmap.clear();
+ mxView.clear();
+}
+
+OGLTransitionerImpl::OGLTransitionerImpl(OGLTransitionImpl* pOGLTransition) :
+ OGLTransitionerImplBase(m_aMutex),
+ GLWin(),
+ GLleavingSlide( 0 ),
+ GLenteringSlide( 0 ),
+ pWindow( NULL ),
+ mxView(),
+ EnteringBytes(),
+ LeavingBytes(),
+ mbRestoreSync( false ),
+ mbUseLeavingPixmap( false ),
+ mbUseEnteringPixmap( false ),
+ SlideBitmapLayout(),
+ SlideSize(),
+ pTransition(pOGLTransition)
+{
+#if defined( WNT )
+ GLWin.hWnd = 0;
+#elif defined( UNX )
+ GLWin.ctx = 0;
+#endif
+
+ DBG(frame_count = 0);
+}
+
+typedef cppu::WeakComponentImplHelper1<presentation::XTransitionFactory> OGLTransitionFactoryImplBase;
+
+class OGLTransitionFactoryImpl : private cppu::BaseMutex, public OGLTransitionFactoryImplBase
+{
+public:
+ explicit OGLTransitionFactoryImpl( const uno::Reference< uno::XComponentContext >& ) :
+ OGLTransitionFactoryImplBase(m_aMutex)
+ {}
+
+ // XTransitionFactory
+ virtual ::sal_Bool SAL_CALL hasTransition( ::sal_Int16 transitionType, ::sal_Int16 transitionSubType ) throw (uno::RuntimeException)
+ {
+ if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) {
+ switch( transitionSubType )
+ {
+ case animations::TransitionSubType::ACROSS:
+ case animations::TransitionSubType::CORNERSOUT:
+ case animations::TransitionSubType::CIRCLE:
+ case animations::TransitionSubType::FANOUTHORIZONTAL:
+ case animations::TransitionSubType::CORNERSIN:
+ case animations::TransitionSubType::LEFTTORIGHT:
+ case animations::TransitionSubType::TOPTOBOTTOM:
+ case animations::TransitionSubType::TOPRIGHT:
+ case animations::TransitionSubType::TOPLEFT:
+ case animations::TransitionSubType::BOTTOMRIGHT:
+ case animations::TransitionSubType::BOTTOMLEFT:
+ case animations::TransitionSubType::TOPCENTER:
+ case animations::TransitionSubType::RIGHTCENTER:
+ case animations::TransitionSubType::BOTTOMCENTER:
+ return sal_True;
+
+ default:
+ return sal_False;
+ }
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) {
+ return sal_True;
+ } else
+ return sal_False;
+ }
+
+ virtual uno::Reference< presentation::XTransition > SAL_CALL createTransition(
+ ::sal_Int16 transitionType,
+ ::sal_Int16 transitionSubType,
+ const uno::Reference< presentation::XSlideShowView >& view,
+ const uno::Reference< rendering::XBitmap >& leavingBitmap,
+ const uno::Reference< rendering::XBitmap >& enteringBitmap )
+ throw (uno::RuntimeException)
+ {
+ if( !hasTransition( transitionType, transitionSubType ) )
+ return uno::Reference< presentation::XTransition >();
+
+ bool bGLXPresent = OGLTransitionerImpl::initialize( view );
+
+ if( OGLTransitionerImpl::cbMesa && (
+ ( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) ||
+ ( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) ||
+ ( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) ) )
+ return uno::Reference< presentation::XTransition >();
+
+
+ OGLTransitionImpl* pTransition = NULL;
+
+ if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) {
+ pTransition = new OGLTransitionImpl();
+ switch( transitionSubType )
+ {
+ case animations::TransitionSubType::ACROSS:
+ pTransition->makeNByMTileFlip(8,6);
+ break;
+ case animations::TransitionSubType::CORNERSOUT:
+ pTransition->makeOutsideCubeFaceToLeft();
+ break;
+ case animations::TransitionSubType::CIRCLE:
+ pTransition->makeRevolvingCircles(8,128);
+ break;
+ case animations::TransitionSubType::FANOUTHORIZONTAL:
+ pTransition->makeHelix(20);
+ break;
+ case animations::TransitionSubType::CORNERSIN:
+ pTransition->makeInsideCubeFaceToLeft();
+ break;
+ case animations::TransitionSubType::LEFTTORIGHT:
+ pTransition->makeFallLeaving();
+ break;
+ case animations::TransitionSubType::TOPTOBOTTOM:
+ pTransition->makeTurnAround();
+ break;
+ case animations::TransitionSubType::TOPRIGHT:
+ pTransition->makeTurnDown();
+ break;
+ case animations::TransitionSubType::TOPLEFT:
+ pTransition->makeIris();
+ break;
+ case animations::TransitionSubType::BOTTOMRIGHT:
+ pTransition->makeRochade();
+ break;
+ case animations::TransitionSubType::BOTTOMLEFT:
+ pTransition->makeVenetianBlinds( true, 8 );
+ break;
+ case animations::TransitionSubType::TOPCENTER:
+ pTransition->makeVenetianBlinds( false, 6 );
+ break;
+ case animations::TransitionSubType::RIGHTCENTER:
+ pTransition->makeStatic();
+ break;
+ case animations::TransitionSubType::BOTTOMCENTER:
+ pTransition->makeDissolve();
+ break;
+ }
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeFadeSmoothly();
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeFadeThroughBlack();
+ } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeDiamond();
+ } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeNewsflash();
+ }
+
+ rtl::Reference<OGLTransitionerImpl> xRes(
+ new OGLTransitionerImpl(pTransition) );
+ if( bGLXPresent ) {
+ if( !xRes->initWindowFromSlideShowView(view))
+ return uno::Reference< presentation::XTransition >();
+ xRes->setSlides(leavingBitmap,enteringBitmap);
+ }
+
+ return uno::Reference<presentation::XTransition>(xRes.get());
+ }
+};
+
+}
+
+namespace sdecl = comphelper::service_decl;
+#if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)
+ sdecl::class_<OGLTransitionFactoryImpl> serviceImpl;
+ const sdecl::ServiceDecl OGLTransitionFactoryDecl(
+ serviceImpl,
+#else
+ const sdecl::ServiceDecl OGLTransitionFactoryDecl(
+ sdecl::class_<OGLTransitionFactoryImpl>(),
+#endif
+ "com.sun.star.comp.presentation.OGLTransitionFactory",
+ "com.sun.star.presentation.TransitionFactory" );
+
+// The C shared lib entry points
+COMPHELPER_SERVICEDECL_EXPORTS1(OGLTransitionFactoryDecl)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/unx/makefile.mk b/slideshow/source/engine/OGLTrans/unx/makefile.mk
new file mode 100644
index 000000000000..31066e34a997
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/unx/makefile.mk
@@ -0,0 +1,73 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..$/..
+
+PRJNAME=slideshow
+TARGET=OGLTrans
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Nothing to do if we're compiling with --disable-opengl or if nto the right OS -----------
+.IF "$(ENABLE_OPENGL)" != "TRUE" || "$(OS)" == "MACOSX"
+@all:
+ @echo "Building without OpenGL Transitions..."
+.ENDIF
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/OGLTrans_TransitionImpl.obj \
+ $(SLO)$/OGLTrans_Shaders.obj \
+ $(SLO)$/OGLTrans_TransitionerImpl.obj
+
+DLLPRE=
+SHL1TARGET=$(TARGET).uno
+
+SHL1STDLIBS= $(SALLIB) $(VCLLIB) $(CPPULIB) $(CPPUHELPERLIB) $(COMPHELPERLIB) $(CANVASTOOLSLIB)
+
+SHL1STDLIBS+= \
+ -lGL \
+ -lGLU \
+ -lX11
+
+SHL1IMPLIB=i$(TARGET)
+SHL1LIBS=$(SLB)$/$(TARGET).lib
+SHL1DEF=$(MISC)$/$(SHL1TARGET).def
+
+SHL1VERSIONMAP=$(SOLARENV)/src/component.map
+
+DEF1NAME=$(SHL1TARGET)
+DEF1EXPORTFILE=../exports.dxp
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.cxx b/slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.cxx
new file mode 100644
index 000000000000..c1beae1230b0
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include <osl/diagnose.hxx>
+
+#include "OGLTrans_Shaders.hxx"
+
+namespace unx
+{
+#include <GL/glx.h>
+#include <GL/glxext.h>
+}
+
+bool OGLShaders::cbInitialized = false;
+
+#ifdef GL_VERSION_2_0
+
+PFNGLCREATESHADERPROC OGLShaders::glCreateShader = NULL;
+PFNGLSHADERSOURCEPROC OGLShaders::glShaderSource = NULL;
+PFNGLCOMPILESHADERPROC OGLShaders::glCompileShader = NULL;
+PFNGLGETSHADERIVPROC OGLShaders::glGetShaderiv = NULL;
+PFNGLGETSHADERINFOLOGPROC OGLShaders::glGetShaderInfoLog = NULL;
+PFNGLDELETESHADERPROC OGLShaders::glDeleteShader = NULL;
+PFNGLCREATEPROGRAMPROC OGLShaders::glCreateProgram = NULL;
+PFNGLATTACHSHADERPROC OGLShaders::glAttachShader = NULL;
+PFNGLLINKPROGRAMPROC OGLShaders::glLinkProgram = NULL;
+PFNGLGETPROGRAMIVPROC OGLShaders::glGetProgramiv = NULL;
+PFNGLGETPROGRAMINFOLOGPROC OGLShaders::glGetProgramInfoLog = NULL;
+PFNGLUSEPROGRAMPROC OGLShaders::glUseProgram = NULL;
+PFNGLDELETEPROGRAMPROC OGLShaders::glDeleteProgram = NULL;
+PFNGLGETUNIFORMLOCATIONPROC OGLShaders::glGetUniformLocation = NULL;
+PFNGLUNIFORM1IPROC OGLShaders::glUniform1i = NULL;
+PFNGLUNIFORM1FPROC OGLShaders::glUniform1f = NULL;
+#endif
+
+bool OGLShaders::Initialize()
+{
+#ifdef GL_VERSION_2_0
+ if( !cbInitialized ) {
+ glCreateShader = (PFNGLCREATESHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glCreateShader" );
+ glShaderSource = (PFNGLSHADERSOURCEPROC) unx::glXGetProcAddress( (unsigned char *) "glShaderSource" );
+ glCompileShader = (PFNGLCOMPILESHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glCompileShader" );
+ glGetShaderiv = (PFNGLGETSHADERIVPROC) unx::glXGetProcAddress( (unsigned char *) "glGetShaderiv" );
+ glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) unx::glXGetProcAddress( (unsigned char *) "glGetShaderInfoLog" );
+ glDeleteShader = (PFNGLDELETESHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glDeleteShader" );
+ glCreateProgram = (PFNGLCREATEPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glCreateProgram" );
+ glAttachShader = (PFNGLATTACHSHADERPROC) unx::glXGetProcAddress( (unsigned char *) "glAttachShader" );
+ glLinkProgram = (PFNGLLINKPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glLinkProgram" );
+ glGetProgramiv = (PFNGLGETPROGRAMIVPROC) unx::glXGetProcAddress( (unsigned char *) "glGetProgramiv" );
+ glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) unx::glXGetProcAddress( (unsigned char *) "glGetProgramInfoLog" );
+ glUseProgram = (PFNGLUSEPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glUseProgram" );
+ glDeleteProgram = (PFNGLDELETEPROGRAMPROC) unx::glXGetProcAddress( (unsigned char *) "glDeleteProgram" );
+ glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) unx::glXGetProcAddress( (unsigned char *) "glGetUniformLocation" );
+ glUniform1i = (PFNGLUNIFORM1IPROC) unx::glXGetProcAddress( (unsigned char *) "glUniform1i" );
+ glUniform1f = (PFNGLUNIFORM1FPROC) unx::glXGetProcAddress( (unsigned char *) "glUniform1f" );
+ cbInitialized = true;
+ }
+
+ return glCreateShader != NULL;
+#else
+ return false;
+#endif
+}
+
+GLuint OGLShaders::LinkProgram( const char *vertexShader, const char *fragmentShader )
+{
+#ifdef GL_VERSION_2_0
+ if( !Initialize() )
+ return 0;
+
+ GLhandleARB vertexObject, fragmentObject, programObject;
+ GLint vertexCompiled, fragmentCompiled, programLinked;
+ char log[1024];
+
+ vertexObject = glCreateShader( GL_VERTEX_SHADER );
+ fragmentObject = glCreateShader( GL_FRAGMENT_SHADER );
+ OSL_TRACE("checkpoint 1: shaders created (%d) vertex: %d fragment: %d", glGetError() == GL_NO_ERROR, vertexObject, fragmentObject );
+
+
+ glShaderSource( vertexObject, 1, &vertexShader, NULL );
+ glShaderSource( fragmentObject, 1, &fragmentShader, NULL );
+
+ glCompileShader( vertexObject );
+ glGetShaderInfoLog( vertexObject, sizeof( log ), NULL, log );
+ OSL_TRACE("vertex compile log: %s", log);
+ glGetShaderiv( vertexObject, GL_COMPILE_STATUS, &vertexCompiled );
+ glCompileShader( fragmentObject );
+ glGetShaderInfoLog( fragmentObject, sizeof( log ), NULL, log );
+ OSL_TRACE("fragment compile log: %s", log);
+ glGetShaderiv( fragmentObject, GL_COMPILE_STATUS, &fragmentCompiled );
+
+ if( !vertexCompiled || !fragmentCompiled )
+ return 0;
+
+ OSL_TRACE("checkpoint 2: shaders compiled (%d)", glGetError() == GL_NO_ERROR);
+
+ programObject = glCreateProgram();
+ glAttachShader( programObject, vertexObject );
+ glAttachShader( programObject, fragmentObject );
+
+ glLinkProgram( programObject );
+ glGetProgramInfoLog( programObject, sizeof( log ), NULL, log );
+ OSL_TRACE("program link log: %s", log);
+ glGetProgramiv( programObject, GL_LINK_STATUS, &programLinked );
+
+ if( !programLinked )
+ return 0;
+
+ OSL_TRACE("checkpoint 3: program linked (%d)", glGetError() == GL_NO_ERROR);
+
+ return programObject;
+#else
+ return 0;
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.hxx b/slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.hxx
new file mode 100644
index 000000000000..016f8ac5445a
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/win/OGLTrans_Shaders.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_OGLTRANS_SHADERS_HXX_
+#define INCLUDED_OGLTRANS_SHADERS_HXX_
+
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+class OGLShaders {
+ static bool Initialize();
+ static bool cbInitialized;
+
+public:
+
+ static GLuint LinkProgram( const char *vertexShader, const char *fragmentShader );
+
+ /** GL shader functions
+ */
+#ifdef GL_VERSION_2_0
+
+ static PFNGLCREATESHADERPROC glCreateShader;
+ static PFNGLSHADERSOURCEPROC glShaderSource;
+ static PFNGLCOMPILESHADERPROC glCompileShader;
+ static PFNGLGETSHADERIVPROC glGetShaderiv;
+ static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
+ static PFNGLDELETESHADERPROC glDeleteShader;
+
+ static PFNGLCREATEPROGRAMPROC glCreateProgram;
+ static PFNGLATTACHSHADERPROC glAttachShader;
+ static PFNGLLINKPROGRAMPROC glLinkProgram;
+ static PFNGLGETPROGRAMIVPROC glGetProgramiv;
+ static PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
+ static PFNGLUSEPROGRAMPROC glUseProgram;
+ static PFNGLDELETEPROGRAMPROC glDeleteProgram;
+
+ static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
+ static PFNGLUNIFORM1IPROC glUniform1i;
+ static PFNGLUNIFORM1FPROC glUniform1f;
+#endif
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.cxx b/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.cxx
new file mode 100644
index 000000000000..66773c4eadf3
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.cxx
@@ -0,0 +1,1315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "OGLTrans_TransitionImpl.hxx"
+#include "OGLTrans_Shaders.hxx"
+#ifdef QUARTZ
+#include <OpenGL/gl.h>
+#else
+#include <GL/gl.h>
+#include <math.h>
+#endif
+
+void OGLTransitionImpl::clear()
+{
+ for(unsigned int i( 0 ); i < OverallOperations.size(); ++i)
+ delete OverallOperations[i];
+ OverallOperations.clear();
+ maLeavingSlidePrimitives.clear();
+ maEnteringSlidePrimitives.clear();
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i)
+ delete maSceneObjects[i];
+ maSceneObjects.clear();
+
+ mbReflectSlides = false;
+
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ OGLShaders::glDeleteProgram( mProgramObject );
+ mProgramObject = 0;
+ }
+
+ if( mVertexObject ) {
+ OGLShaders::glDeleteShader( mVertexObject );
+ mVertexObject = 0;
+ }
+
+ if( mFragmentObject ) {
+ OGLShaders::glDeleteShader( mFragmentObject );
+ mFragmentObject = 0;
+ }
+#endif
+
+ if( maHelperTexture ) {
+ glDeleteTextures( 1, &maHelperTexture );
+ maHelperTexture = 0;
+ }
+
+ if( mmClearTransition )
+ (this->*mmClearTransition)();
+}
+
+OGLTransitionImpl::~OGLTransitionImpl()
+{
+ clear();
+}
+
+void OGLTransitionImpl::prepare( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex )
+{
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
+ maSceneObjects[i]->prepare();
+ }
+
+ if( mmPrepareTransition )
+ (this->*mmPrepareTransition)( glLeavingSlideTex, glEnteringSlideTex );
+}
+
+void OGLTransitionImpl::finish()
+{
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i) {
+ maSceneObjects[i]->finish();
+ }
+}
+
+static void blendSlide( double depth )
+{
+ double showHeight = -1 + depth*2;
+ GLfloat reflectionColor[] = {0, 0, 0, 0.25};
+
+ glDisable( GL_DEPTH_TEST );
+ glBegin( GL_QUADS );
+ glColor4fv( reflectionColor );
+ glVertex3f( -1, -1, 0 );
+ glColor4f( 0, 0, 0, 1 );
+ glVertex3f(-1, showHeight, 0 );
+ glVertex3f( 1, showHeight, 0 );
+ glColor4fv( reflectionColor );
+ glVertex3f( 1, -1, 0 );
+ glEnd();
+
+ glBegin( GL_QUADS );
+ glColor4f( 0, 0, 0, 1 );
+ glVertex3f( -1, showHeight, 0 );
+ glVertex3f( -1, 1, 0 );
+ glVertex3f( 1, 1, 0 );
+ glVertex3f( 1, showHeight, 0 );
+ glEnd();
+ glEnable( GL_DEPTH_TEST );
+}
+
+static void slideShadow( double nTime, Primitive& primitive, double sw, double sh )
+{
+ double reflectionDepth = 0.3;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_LIGHTING);
+
+ glPushMatrix();
+ primitive.applyOperations( nTime, sw, sh );
+ blendSlide( reflectionDepth );
+ glPopMatrix();
+
+ glDisable(GL_BLEND);
+ glEnable(GL_LIGHTING);
+}
+
+void OGLTransitionImpl::display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ double SlideWidthScale, SlideHeightScale;
+
+ SlideWidthScale = SlideWidth/DispWidth;
+ SlideHeightScale = SlideHeight/DispHeight;
+
+ if( mmPrepare ) {
+ clear();
+ (this->*mmPrepare)( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
+ }
+
+ glPushMatrix();
+ displaySlides( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
+ displayScene( nTime, SlideWidth, SlideHeight, DispWidth, DispHeight );
+ glPopMatrix();
+}
+
+void OGLTransitionImpl::applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale )
+{
+ for(unsigned int i(0); i < OverallOperations.size(); ++i)
+ OverallOperations[i]->interpolate(nTime,SlideWidthScale,SlideHeightScale);
+}
+
+void OGLTransitionImpl::displaySlide( double nTime, ::sal_Int32 glSlideTex, std::vector<Primitive>& primitives,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ //TODO change to foreach
+ glBindTexture(GL_TEXTURE_2D, glSlideTex);
+
+ // display slide reflection
+ // note that depth test is turned off while blending the shadow
+ // so the slides has to be rendered in right order, see rochade as example
+ if( mbReflectSlides ) {
+ double surfaceLevel = -0.04;
+
+ /* reflected slides */
+ glPushMatrix();
+
+ glScaled( 1, -1, 1 );
+ glTranslated( 0, 2 - surfaceLevel, 0 );
+
+ glCullFace(GL_FRONT);
+ for(unsigned int i(0); i < primitives.size(); ++i)
+ primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
+ glCullFace(GL_BACK);
+
+ slideShadow( nTime, primitives[0], SlideWidthScale, SlideHeightScale );
+
+ glPopMatrix();
+ }
+
+ for(unsigned int i(0); i < primitives.size(); ++i)
+ primitives[i].display(nTime, SlideWidthScale, SlideHeightScale);
+}
+
+void OGLTransitionImpl::displaySlides( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ if( mmDisplaySlides )
+ (this->*mmDisplaySlides)( nTime, glLeavingSlideTex, glEnteringSlideTex, SlideWidthScale, SlideHeightScale );
+ else {
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glEnable(GL_TEXTURE_2D);
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+}
+
+void OGLTransitionImpl::displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ glEnable(GL_TEXTURE_2D);
+ for(unsigned int i(0); i < maSceneObjects.size(); ++i)
+ maSceneObjects[i]->display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
+}
+
+void Primitive::display(double nTime, double WidthScale, double HeightScale)
+{
+ glPushMatrix();
+
+ applyOperations( nTime, WidthScale, HeightScale );
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if(!Normals.empty())
+ {
+ glNormalPointer( GL_DOUBLE , 0 , &Normals[0] );
+ glEnableClientState( GL_NORMAL_ARRAY );
+ }
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glTexCoordPointer( 2, GL_DOUBLE, 0, &TexCoords[0] );
+ glVertexPointer( 3, GL_DOUBLE, 0, &Vertices[0] );
+ glDrawArrays( GL_TRIANGLES, 0, Vertices.size() );
+ glPopMatrix();
+}
+
+void Primitive::applyOperations(double nTime, double WidthScale, double HeightScale)
+{
+ for(unsigned int i(0); i < Operations.size(); ++i)
+ Operations[i]->interpolate( nTime ,WidthScale,HeightScale);
+ glScaled(WidthScale,HeightScale,1);
+}
+
+Primitive::~Primitive()
+{
+ for(unsigned int i( 0 ); i < Operations.size(); ++i)
+ delete Operations[i];
+}
+
+
+void SceneObject::display(double nTime, double /* SlideWidth */, double /* SlideHeight */, double DispWidth, double DispHeight )
+{
+ for(unsigned int i(0); i < maPrimitives.size(); ++i) {
+ // fixme: allow various model spaces, now we make it so that
+ // it is regular -1,-1 to 1,1, where the whole display fits in
+ glPushMatrix();
+ if (DispHeight > DispWidth)
+ glScaled(DispHeight/DispWidth, 1, 1);
+ else
+ glScaled(1, DispWidth/DispHeight, 1);
+ maPrimitives[i].display(nTime, 1, 1);
+ glPopMatrix();
+ }
+}
+
+void SceneObject::pushPrimitive(const Primitive &p)
+{
+ maPrimitives.push_back(p);
+}
+
+SceneObject::SceneObject()
+ : maPrimitives()
+{
+}
+
+Iris::Iris()
+ : SceneObject ()
+{
+}
+
+void Iris::display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight )
+{
+ glBindTexture(GL_TEXTURE_2D, maTexture);
+ SceneObject::display(nTime, SlideWidth, SlideHeight, DispWidth, DispHeight);
+}
+
+void Iris::prepare()
+{
+ static GLubyte img[3] = { 80, 80, 80 };
+
+ glGenTextures(1, &maTexture);
+ glBindTexture(GL_TEXTURE_2D, maTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, 3, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+}
+
+void Iris::finish()
+{
+ glDeleteTextures(1, &maTexture);
+}
+
+void OGLTransitionImpl::makeOutsideCubeFaceToLeft()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),90,false,0.0,1.0));
+
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,-1),-90,true,0.0,1.0));
+}
+
+void OGLTransitionImpl::makeInsideCubeFaceToLeft()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),-90,false,0.0,1.0));
+
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,1),90,true,0.0,1.0));
+}
+
+void OGLTransitionImpl::makeFallLeaving()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(1,0,0),basegfx::B3DVector(0,-1,0), 90,true,0.0,1.0));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::makeTurnAround()
+{
+ clear();
+ Primitive Slide;
+
+ mbReflectSlides = true;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0),-180,false,0.0,1.0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, -1.5),true, 0, 0.5));
+ OverallOperations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1.5), true, 0.5, 1));
+ OverallOperations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0),basegfx::B3DVector(0, 0, 0), -180, true, 0.0, 1.0));
+}
+
+void OGLTransitionImpl::makeTurnDown()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 0.0001), false, -1.0, 0.0));
+ Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), -90, true, 0.0, 1.0));
+ Slide.Operations.push_back(new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(-1, 1, 0), 90, false, -1.0, 0.0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ mbUseMipMapLeaving = false;
+}
+
+void OGLTransitionImpl::makeIris()
+{
+ clear();
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, 0.000001), false, -1, 0));
+ Slide.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, -0.000002), false, 0.5, 1));
+ maLeavingSlidePrimitives.push_back (Slide);
+
+
+ Primitive irisPart, part;
+ int i, nSteps = 24, nParts = 7;
+ double t = 1.0/nSteps, cx, cy, lcx, lcy, lx = 1, ly = 0, x, y, cxo, cyo, lcxo, lcyo, of=2.2, f=1.42;
+
+ for (i=1; i<=nSteps; i++) {
+ x = cos ((3*2*M_PI*t)/nParts);
+ y = -sin ((3*2*M_PI*t)/nParts);
+ cx = (f*x + 1)/2;
+ cy = (f*y + 1)/2;
+ lcx = (f*lx + 1)/2;
+ lcy = (f*ly + 1)/2;
+ cxo = (of*x + 1)/2;
+ cyo = (of*y + 1)/2;
+ lcxo = (of*lx + 1)/2;
+ lcyo = (of*ly + 1)/2;
+ irisPart.pushTriangle (basegfx::B2DVector (lcx, lcy),
+ basegfx::B2DVector (lcxo, lcyo),
+ basegfx::B2DVector (cx, cy));
+ irisPart.pushTriangle (basegfx::B2DVector (cx, cy),
+ basegfx::B2DVector (lcxo, lcyo),
+ basegfx::B2DVector (cxo, cyo));
+ lx = x;
+ ly = y;
+ t += 1.0/nSteps;
+ }
+
+ Iris* pIris = new Iris();
+ double angle = 87;
+
+ for (i = 0; i < nParts; i++) {
+ irisPart.Operations.clear ();
+ double rx, ry;
+
+ rx = cos ((2*M_PI*i)/nParts);
+ ry = sin ((2*M_PI*i)/nParts);
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0), angle, true, 0.0, 0.5));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(rx, ry, 0), -angle, true, 0.5, 1));
+ if (i > 0) {
+ irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(rx, ry, 0), false, -1, 0));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(0, 0, 1), basegfx::B3DVector(0, 0, 0), i*360.0/nParts, false, -1, 0));
+ irisPart.Operations.push_back (new STranslate (basegfx::B3DVector(-1, 0, 0), false, -1, 0));
+ }
+ irisPart.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, 1), false, -2, 0.0));
+ irisPart.Operations.push_back (new SRotate (basegfx::B3DVector(1, .5, 0), basegfx::B3DVector(1, 0, 0), -30, false, -1, 0));
+ pIris->pushPrimitive (irisPart);
+ }
+
+ maSceneObjects.push_back (pIris);
+
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::displaySlidesRochade( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glEnable(GL_TEXTURE_2D);
+
+ if( nTime > .5) {
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ } else {
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+}
+
+void OGLTransitionImpl::makeRochade()
+{
+ clear();
+ Primitive Slide;
+
+ mbReflectSlides = true;
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesRochade;
+
+ double w, h;
+
+ w = 2.2;
+ h = 10;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+
+ Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.25, -0.25, true, 0, 1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.clear();
+ Slide.Operations.push_back(new SEllipseTranslate(w, h, 0.75, 0.25, true, 0, 1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(0, 0, -h), false, -1, 0));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), -45, true, 0, 1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0,1,0),basegfx::B3DVector(0,0,0), 45, false, -1, 0));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B2DVector clamp(const basegfx::B2DVector& v)
+{
+ return basegfx::B2DVector(min(max(v.getX(),-1.0),1.0),
+ min(max(v.getY(),-1.0),1.0));
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B3DVector clamp(const basegfx::B3DVector& v)
+{
+ return basegfx::B3DVector(min(max(v.getX(),-1.0),1.0),
+ min(max(v.getY(),-1.0),1.0),
+ min(max(v.getZ(),-1.0),1.0));
+}
+
+inline double randFromNeg1to1()
+{
+ return ( ( static_cast<double>( rand() ) / static_cast<double>( RAND_MAX ) ) * 2.0 ) - 1.0;
+}
+
+// TODO(Q3): extract to basegfx
+inline basegfx::B3DVector randNormVectorInXYPlane()
+{
+ basegfx::B3DVector toReturn(randFromNeg1to1(),randFromNeg1to1(),0.0);
+ return toReturn/toReturn.getLength();
+}
+
+void OGLTransitionImpl::makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles )
+{
+ clear();
+ double dAngle(2*3.1415926/static_cast<double>( nPointsOnCircles ));
+ if(nCircles < 2 || nPointsOnCircles < 4)
+ {
+ makeNByMTileFlip(1,1);
+ return;
+ }
+ double Radius(1.0/static_cast<double>( nCircles ));
+ double dRadius(Radius);
+ double LastRadius(0.0);
+ double NextRadius(2*Radius);
+
+ /// now we know there is at least two circles
+ /// the first will always be a full circle
+ /// the last will always be the outer shell of the slide with a circle hole
+
+ //add the full circle
+ vector<basegfx::B2DVector> unScaledTexCoords;
+ double TempAngle(0.0);
+ for(unsigned int Point(0); Point < nPointsOnCircles; ++Point)
+ {
+ unScaledTexCoords.push_back( basegfx::B2DVector( cos(TempAngle - 3.1415926/2.0) , sin(TempAngle- 3.1415926/2.0) ) );
+
+ TempAngle += dAngle;
+ }
+
+ {
+ Primitive EnteringSlide;
+ Primitive LeavingSlide;
+ for(int Point(0); Point + 1 < nPointsOnCircles; ++Point)
+ {
+ EnteringSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
+ LeavingSlide.pushTriangle( basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point + 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ Point ] / 2.0 + basegfx::B2DVector( 0.5, 0.5) );
+ }
+ EnteringSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius * unScaledTexCoords[ 0 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) , Radius * unScaledTexCoords[ nPointsOnCircles - 1 ] / 2.0 + basegfx::B2DVector( 0.5 , 0.5 ) );
+ LeavingSlide.pushTriangle( basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+ LastRadius = Radius;
+ Radius = NextRadius;
+ NextRadius += dRadius;
+ }
+
+ for(int i(1); i < nCircles - 1; ++i)
+ {
+ Primitive LeavingSlide;
+ Primitive EnteringSlide;
+ for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
+ {
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ }
+
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(Radius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , Radius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, Radius/2.0 , (NextRadius + 1)/2.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+
+ LastRadius = Radius;
+ Radius = NextRadius;
+ NextRadius += dRadius;
+ }
+ {
+ Radius = sqrt(2.0);
+ Primitive LeavingSlide;
+ Primitive EnteringSlide;
+ for(int Side(0); Side < nPointsOnCircles - 1; ++Side)
+ {
+
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[Side])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[Side + 1]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[Side + 1])/2.0 + basegfx::B2DVector(0.5,0.5) );
+ }
+
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ EnteringSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[nPointsOnCircles - 1]/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) );
+ LeavingSlide.pushTriangle(clamp(Radius*unScaledTexCoords[nPointsOnCircles - 1])/2.0 + basegfx::B2DVector(0.5,0.5) , LastRadius*unScaledTexCoords[0]/2.0 + basegfx::B2DVector(0.5,0.5) , clamp(Radius*unScaledTexCoords[0])/2.0 + basegfx::B2DVector(0.5,0.5) );
+
+ basegfx::B3DVector axis(randNormVectorInXYPlane());
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
+ LeavingSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , 180, true, (LastRadius + dRadius)/2.0 , 1.0 ) );
+ EnteringSlide.Operations.push_back( new SRotate( axis , basegfx::B3DVector(0,0,0) , -180, false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(EnteringSlide);
+ maLeavingSlidePrimitives.push_back(LeavingSlide);
+ }
+}
+
+void OGLTransitionImpl::makeHelix( ::sal_uInt16 nRows )
+{
+ clear();
+ double invN(1.0/static_cast<double>(nRows));
+ double iDn = 0.0;
+ double iPDn = invN;
+ for(unsigned int i(0); i < nRows; ++i)
+ {
+ Primitive Tile;
+
+ Tile.pushTriangle(basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
+
+ Tile.pushTriangle(basegfx::B2DVector( 1.0 , iPDn ) , basegfx::B2DVector( 1.0 , iDn ) , basegfx::B2DVector( 0.0 , iPDn ));
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 ,
+ true,min(max(static_cast<double>(i - nRows/2.0)*invN/2.0,0.0),1.0),
+ min(max(static_cast<double>(i + nRows/2.0)*invN/2.0,0.0),1.0) ) );
+
+ maLeavingSlidePrimitives.push_back(Tile);
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 0 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180 , false,0.0,1.0) );
+
+ maEnteringSlidePrimitives.push_back(Tile);
+
+ iDn += invN;
+ iPDn += invN;
+ }
+}
+
+void OGLTransitionImpl::makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m )
+{
+ clear();
+ double invN(1.0/static_cast<double>(n));
+ double invM(1.0/static_cast<double>(m));
+ double iDn = 0.0;
+ double iPDn = invN;
+ for(unsigned int i(0); i < n; ++i)
+ {
+ double jDm = 0.0;
+ double jPDm = invM;
+ for(unsigned int j(0); j < m; ++j)
+ {
+ Primitive Tile;
+
+ Tile.pushTriangle(basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));
+
+ Tile.pushTriangle(basegfx::B2DVector( iPDn , jPDm ) , basegfx::B2DVector( iPDn , jDm ) , basegfx::B2DVector( iDn , jPDm ));//bottom left corner of tile
+
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , 180 , true, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
+ maLeavingSlidePrimitives.push_back(Tile);
+ Tile.Operations.push_back( new SRotate( basegfx::B3DVector( 1 , 1 , 0 ) , ( Tile.getVertices()[1] + Tile.getVertices()[3] )/2.0 , -180, false, iDn*jDm/2.0 , ((iPDn*jPDm)+1.0)/2.0 ) );
+
+ maEnteringSlidePrimitives.push_back(Tile);
+
+ jDm += invM;
+ jPDm += invM;
+ }
+ iDn += invN;
+ iPDn += invN;
+ }
+}
+
+SRotate::SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+SScale::SScale(const basegfx::B3DVector& Scale,const basegfx::B3DVector& Origin, bool bInter, double T0, double T1):scale(Scale),origin(Origin)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+RotateAndScaleDepthByWidth::RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+RotateAndScaleDepthByHeight::RotateAndScaleDepthByHeight(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle, bool bInter, double T0, double T1):axis(Axis),origin(Origin),angle(Angle)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+
+STranslate::STranslate(const basegfx::B3DVector& Vector, bool bInter, double T0, double T1):vector(Vector)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+}
+
+inline double intervalInter(double t, double T0, double T1)
+{
+ return ( t - T0 ) / ( T1 - T0 );
+}
+
+void STranslate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*t*vector.getX(),SlideHeightScale*t*vector.getY(),t*vector.getZ());
+}
+
+void SRotate::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
+ glScaled(SlideWidthScale,SlideHeightScale,1);
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glScaled(1/SlideWidthScale,1/SlideHeightScale,1);
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
+}
+
+void SScale::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),origin.getZ());
+ glScaled((1-t) + t*scale.getX(),(1-t) + t*scale.getY(),(1-t) + t*scale.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-origin.getZ());
+}
+
+void RotateAndScaleDepthByWidth::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideWidthScale*origin.getZ());
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideWidthScale*origin.getZ());
+}
+
+void RotateAndScaleDepthByHeight::interpolate(double t,double SlideWidthScale,double SlideHeightScale)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+ glTranslated(SlideWidthScale*origin.getX(),SlideHeightScale*origin.getY(),SlideHeightScale*origin.getZ());
+ glRotated(t*angle,axis.getX(),axis.getY(),axis.getZ());
+ glTranslated(-SlideWidthScale*origin.getX(),-SlideHeightScale*origin.getY(),-SlideHeightScale*origin.getZ());
+}
+
+SEllipseTranslate::SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1)
+{
+ nT0 = T0;
+ nT1 = T1;
+ bInterpolate = bInter;
+ width = dWidth;
+ height = dHeight;
+ startPosition = dStartPosition;
+ endPosition = dEndPosition;
+}
+
+void SEllipseTranslate::interpolate(double t,double /* SlideWidthScale */,double /* SlideHeightScale */)
+{
+ if(t <= nT0)
+ return;
+ if(!bInterpolate || t > nT1)
+ t = nT1;
+ t = intervalInter(t,nT0,nT1);
+
+ double a1, a2, x, y;
+ a1 = startPosition*2*M_PI;
+ a2 = (startPosition + t*(endPosition - startPosition))*2*M_PI;
+ x = width*(cos (a2) - cos (a1))/2;
+ y = height*(sin (a2) - sin (a1))/2;
+
+ glTranslated(x, 0, y);
+}
+
+STranslate* STranslate::clone()
+{
+ return new STranslate(*this);
+}
+SRotate* SRotate::clone()
+{
+ return new SRotate(*this);
+}
+
+SScale* SScale::clone()
+{
+ return new SScale(*this);
+}
+
+SEllipseTranslate* SEllipseTranslate::clone()
+{
+ return new SEllipseTranslate(*this);
+}
+
+RotateAndScaleDepthByWidth* RotateAndScaleDepthByWidth::clone()
+{
+ return new RotateAndScaleDepthByWidth(*this);
+}
+
+RotateAndScaleDepthByHeight* RotateAndScaleDepthByHeight::clone()
+{
+ return new RotateAndScaleDepthByHeight(*this);
+}
+
+const Primitive& Primitive::operator=(const Primitive& rvalue)
+{
+ for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
+ Operations.push_back(rvalue.Operations[i]->clone());
+ for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
+ Vertices.push_back(rvalue.Vertices[i]);
+ for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
+ TexCoords.push_back(rvalue.TexCoords[i]);
+ for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
+ Normals.push_back(rvalue.Normals[i]);
+ return *this;
+}
+
+Primitive::Primitive(const Primitive& rvalue)
+{
+ for(unsigned int i( 0 ); i < rvalue.Operations.size(); ++i)
+ Operations.push_back(rvalue.Operations[i]->clone());
+ for(unsigned int i( 0 ); i < rvalue.Vertices.size(); ++i)//SPEED! use copy or something. this is slow.
+ Vertices.push_back(rvalue.Vertices[i]);
+ for(unsigned int i( 0 ); i < rvalue.TexCoords.size(); ++i)//SPEED! use copy or something. this is slow.
+ TexCoords.push_back(rvalue.TexCoords[i]);
+ for(unsigned int i( 0 ); i < rvalue.Normals.size(); ++i)//SPEED! use copy or something. this is slow.
+ Normals.push_back(rvalue.Normals[i]);
+}
+
+void Primitive::pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2)
+{
+ vector<basegfx::B3DVector> Verts;
+ vector<basegfx::B2DVector> Texs;
+ Verts.reserve(3);
+ Texs.reserve(3);
+
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
+
+ //figure out if they're facing the correct way, and make them face the correct way.
+ basegfx::B3DVector Normal( basegfx::cross( Verts[0] - Verts[1] , Verts[1] - Verts[2] ) );
+ if(Normal.getZ() >= 0.0)//if the normal is facing us
+ {
+ Texs.push_back(SlideLocation0);
+ Texs.push_back(SlideLocation1);
+ Texs.push_back(SlideLocation2);
+ }
+ else // if the normal is facing away from us, make it face us
+ {
+ Texs.push_back(SlideLocation0);
+ Texs.push_back(SlideLocation2);
+ Texs.push_back(SlideLocation1);
+ Verts.clear();
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation0.getX() - 1, -2*SlideLocation0.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation2.getX() - 1, -2*SlideLocation2.getY() + 1 , 0.0 ));
+ Verts.push_back(basegfx::B3DVector( 2*SlideLocation1.getX() - 1, -2*SlideLocation1.getY() + 1 , 0.0 ));
+ }
+
+ Vertices.push_back(Verts[0]);
+ Vertices.push_back(Verts[1]);
+ Vertices.push_back(Verts[2]);
+
+ TexCoords.push_back(Texs[0]);
+ TexCoords.push_back(Texs[1]);
+ TexCoords.push_back(Texs[2]);
+
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+ Normals.push_back(basegfx::B3DVector(0,0,1));//all normals always face the screen when untransformed.
+}
+
+void OGLTransitionImpl::makeDiamond()
+{
+ mmPrepare = &OGLTransitionImpl::prepareDiamond;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::prepareDiamond( double nTime, double /* SlideWidth */, double /* SlideHeight */, double /* DispWidth */, double /* DispHeight */ )
+{
+ Primitive Slide1, Slide2;
+
+ Slide1.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide1.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maEnteringSlidePrimitives.push_back (Slide1);
+
+
+ if( nTime >= 0.5 ) {
+ double m = 1 - nTime;
+
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (m,0), basegfx::B2DVector (0,m));
+ Slide2.pushTriangle (basegfx::B2DVector (nTime,0), basegfx::B2DVector (1,0), basegfx::B2DVector (1,m));
+ Slide2.pushTriangle (basegfx::B2DVector (1,nTime), basegfx::B2DVector (1,1), basegfx::B2DVector (nTime,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,nTime), basegfx::B2DVector (m,1), basegfx::B2DVector (0,1));
+ } else {
+ double l = 0.5 - nTime;
+ double h = 0.5 + nTime;
+
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0.5,l));
+ Slide2.pushTriangle (basegfx::B2DVector (0.5,l), basegfx::B2DVector (1,0), basegfx::B2DVector (h,0.5));
+ Slide2.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (1,1), basegfx::B2DVector (h,0.5));
+ Slide2.pushTriangle (basegfx::B2DVector (h,0.5), basegfx::B2DVector (1,1), basegfx::B2DVector (0.5,h));
+ Slide2.pushTriangle (basegfx::B2DVector (0.5,h), basegfx::B2DVector (1,1), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (l,0.5), basegfx::B2DVector (0.5,h), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (l,0.5), basegfx::B2DVector (0,1));
+ Slide2.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (0.5,l), basegfx::B2DVector (l,0.5));
+ }
+ Slide2.Operations.push_back (new STranslate (basegfx::B3DVector (0, 0, 0.00000001), false, -1, 0));
+ maLeavingSlidePrimitives.push_back (Slide2);
+}
+
+void OGLTransitionImpl::makeVenetianBlinds( bool vertical, int parts )
+{
+ static double t30 = tan( M_PI/6.0 );
+ double n, ln = 0;
+ double p = 1.0/parts;
+
+ for( int i=0; i<parts; i++ ) {
+ Primitive Slide;
+ n = (i + 1)/(double)parts;
+ if( vertical ) {
+ Slide.pushTriangle (basegfx::B2DVector (ln,0), basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1));
+ Slide.pushTriangle (basegfx::B2DVector (n,0), basegfx::B2DVector (ln,1), basegfx::B2DVector (n,1));
+ Slide.Operations.push_back(new RotateAndScaleDepthByWidth(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, -t30*p), -120, true, 0.0, 1.0));
+ } else {
+ Slide.pushTriangle (basegfx::B2DVector (0,ln), basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n));
+ Slide.pushTriangle (basegfx::B2DVector (1,ln), basegfx::B2DVector (0,n), basegfx::B2DVector (1,n));
+ Slide.Operations.push_back(new RotateAndScaleDepthByHeight(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, -t30*p), -120, true, 0.0, 1.0));
+ }
+ maLeavingSlidePrimitives.push_back (Slide);
+
+ if( vertical ) {
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(2*n - 1, 0, 0), -60, false, -1, 0));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0, 1, 0), basegfx::B3DVector(n + ln - 1, 0, 0), 180, false, -1, 0));
+ } else {
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - 2*n, 0), -60, false, -1, 0));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(1, 0, 0), basegfx::B3DVector(0, 1 - n - ln, 0), 180, false, -1, 0));
+ }
+ maEnteringSlidePrimitives.push_back (Slide);
+ ln = n;
+ }
+}
+
+void OGLTransitionImpl::displaySlidesFadeSmoothly( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_DEPTH_TEST);
+
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4f( 1, 1, 1, nTime );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ glDisable(GL_BLEND);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_LIGHTING);
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+void OGLTransitionImpl::makeFadeSmoothly()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeSmoothly;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+void OGLTransitionImpl::displaySlidesFadeThroughBlack( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+ glDisable(GL_DEPTH_TEST);
+
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ if( nTime < 0.5 ) {
+ glColor4f( 1, 1, 1, 1 - nTime*2 );
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ } else {
+ glColor4f( 1, 1, 1, (nTime - 0.5)*2 );
+ displaySlide( nTime, glEnteringSlideTex, maEnteringSlidePrimitives, SlideWidthScale, SlideHeightScale );
+ }
+ glDisable(GL_BLEND);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_LIGHTING);
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+void OGLTransitionImpl::makeFadeThroughBlack()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesFadeThroughBlack;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+}
+
+static const char* basicVertexShader = "\n\
+varying vec2 v_texturePosition;\n\
+\n\
+void main( void )\n\
+{\n\
+ gl_Position = ftransform();\n\
+ v_texturePosition = gl_MultiTexCoord0.xy;\n\
+}\n\
+";
+
+static const char* staticFragmentShader = "\n\
+uniform sampler2D leavingSlideTexture;\n\
+uniform sampler2D enteringSlideTexture;\n\
+uniform sampler2D permTexture;\n\
+uniform float time;\n\
+varying vec2 v_texturePosition;\n\
+\n\
+float snoise(vec2 P) {\n\
+\n\
+ return texture2D(permTexture, P).r;\n\
+}\n\
+\n\
+\n\
+#define PART 0.5\n\
+#define START 0.4\n\
+#define END 0.9\n\
+\n\
+void main() {\n\
+ float sn = snoise(10.0*v_texturePosition+time*0.07);\n\
+ if( time < PART ) {\n\
+ float sn1 = snoise(vec2(time*15.0, 20.0*v_texturePosition.y));\n\
+ float sn2 = snoise(v_texturePosition);\n\
+ if (sn1 > 1.0 - time*time && sn2 < 2.0*time+0.1)\n\
+ gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
+ else if (time > START )\n\
+ gl_FragColor = ((time-START)/(PART - START))*vec4(sn, sn, sn, 1.0) + (1.0 - (time - START)/(PART - START))*texture2D(leavingSlideTexture, v_texturePosition);\n\
+ else\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+ } else if ( time < PART ) {\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+ } else if ( time > END ) {\n\
+ gl_FragColor = ((1.0 - time)/(1.0 - END))*vec4(sn, sn, sn, 1.0) + ((time - END)/(1.0 - END))*texture2D(enteringSlideTexture, v_texturePosition);\n\
+ } else \n\
+ gl_FragColor = vec4(sn, sn, sn, 1.0);\n\
+}\n\
+";
+
+static const char* dissolveFragmentShader = "\n\
+uniform sampler2D leavingSlideTexture;\n\
+uniform sampler2D enteringSlideTexture;\n\
+uniform sampler2D permTexture;\n\
+uniform float time;\n\
+varying vec2 v_texturePosition;\n\
+\n\
+float snoise(vec2 P) {\n\
+\n\
+ return texture2D(permTexture, P).r;\n\
+}\n\
+\n\
+void main() {\n\
+ float sn = snoise(10.0*v_texturePosition);\n\
+ if( sn < time)\n\
+ gl_FragColor = texture2D(enteringSlideTexture, v_texturePosition);\n\
+ else\n\
+ gl_FragColor = texture2D(leavingSlideTexture, v_texturePosition);\n\
+}\n\
+";
+
+int permutation256 [256]= {
+215, 100, 200, 204, 233, 50, 85, 196,
+ 71, 141, 122, 160, 93, 131, 243, 234,
+162, 183, 36, 155, 4, 62, 35, 205,
+ 40, 102, 33, 27, 255, 55, 214, 156,
+ 75, 163, 134, 126, 249, 74, 197, 228,
+ 72, 90, 206, 235, 17, 22, 49, 169,
+227, 89, 16, 5, 117, 60, 248, 230,
+217, 68, 138, 96, 194, 170, 136, 10,
+112, 238, 184, 189, 176, 42, 225, 212,
+ 84, 58, 175, 244, 150, 168, 219, 236,
+101, 208, 123, 37, 164, 110, 158, 201,
+ 78, 114, 57, 48, 70, 142, 106, 43,
+232, 26, 32, 252, 239, 98, 191, 94,
+ 59, 149, 39, 187, 203, 190, 19, 13,
+133, 45, 61, 247, 23, 34, 20, 52,
+118, 209, 146, 193, 222, 18, 1, 152,
+ 46, 41, 91, 148, 115, 25, 135, 77,
+254, 147, 224, 161, 9, 213, 223, 250,
+231, 251, 127, 166, 63, 179, 81, 130,
+139, 28, 120, 151, 241, 86, 111, 0,
+ 88, 153, 172, 182, 159, 105, 178, 47,
+ 51, 167, 65, 66, 92, 73, 198, 211,
+245, 195, 31, 220, 140, 76, 221, 186,
+154, 185, 56, 83, 38, 165, 109, 67,
+124, 226, 132, 53, 229, 29, 12, 181,
+121, 24, 207, 199, 177, 113, 30, 80,
+ 3, 97, 188, 79, 216, 173, 8, 145,
+ 87, 128, 180, 237, 240, 137, 125, 104,
+ 15, 242, 119, 246, 103, 143, 95, 144,
+ 2, 44, 69, 157, 192, 174, 14, 54,
+218, 82, 64, 210, 11, 6, 129, 21,
+116, 171, 99, 202, 7, 107, 253, 108
+};
+
+void initPermTexture(GLuint *texID)
+{
+ glGenTextures(1, texID);
+ glBindTexture(GL_TEXTURE_2D, *texID);
+
+ static bool initialized = false;
+ static unsigned char permutation2D[256*256*4];
+ if( !initialized ) {
+ int x, y;
+
+ for( y=0; y < 256; y++ )
+ for( x=0; x < 256; x++ )
+ permutation2D[x*4 + y*1024] = permutation256[(y + permutation256[x]) & 0xff];
+
+ initialized = true;
+ }
+
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, permutation2D );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+}
+
+void OGLTransitionImpl::preparePermShader()
+{
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ OGLShaders::glUseProgram( mProgramObject );
+
+ GLint location = OGLShaders::glGetUniformLocation( mProgramObject, "leavingSlideTexture" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1i( location, 0 ); // texture unit 0
+ }
+
+ glActiveTexture(GL_TEXTURE1);
+ if( !maHelperTexture )
+ initPermTexture( &maHelperTexture );
+ glActiveTexture(GL_TEXTURE0);
+
+ location = OGLShaders::glGetUniformLocation( mProgramObject, "permTexture" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1i( location, 1 ); // texture unit 1
+ }
+
+ location = OGLShaders::glGetUniformLocation( mProgramObject, "enteringSlideTexture" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1i( location, 2 ); // texture unit 2
+ }
+ }
+#endif
+}
+
+void OGLTransitionImpl::prepareStatic( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
+{
+ mProgramObject = OGLShaders::LinkProgram( basicVertexShader, staticFragmentShader );
+
+ preparePermShader();
+}
+
+void OGLTransitionImpl::displaySlidesShaders( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex,
+ double SlideWidthScale, double SlideHeightScale )
+{
+ applyOverallOperations( nTime, SlideWidthScale, SlideHeightScale );
+
+#ifdef GL_VERSION_2_0
+ if( mProgramObject ) {
+ GLint location = OGLShaders::glGetUniformLocation( mProgramObject, "time" );
+ if( location != -1 ) {
+ OGLShaders::glUniform1f( location, nTime );
+ }
+ }
+
+ glActiveTexture( GL_TEXTURE2 );
+ glBindTexture( GL_TEXTURE_2D, glEnteringSlideTex );
+ glActiveTexture( GL_TEXTURE0 );
+#endif
+
+ displaySlide( nTime, glLeavingSlideTex, maLeavingSlidePrimitives, SlideWidthScale, SlideHeightScale );
+}
+
+void OGLTransitionImpl::makeStatic()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
+ mmPrepareTransition = &OGLTransitionImpl::prepareStatic;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+
+ mnRequiredGLVersion = 2.0;
+}
+
+void OGLTransitionImpl::prepareDissolve( ::sal_Int32 /* glLeavingSlideTex */, ::sal_Int32 /* glEnteringSlideTex */ )
+{
+ mProgramObject = OGLShaders::LinkProgram( basicVertexShader, dissolveFragmentShader );
+
+ preparePermShader();
+}
+
+void OGLTransitionImpl::makeDissolve()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle (basegfx::B2DVector (0,0), basegfx::B2DVector (1,0), basegfx::B2DVector (0,1));
+ Slide.pushTriangle (basegfx::B2DVector (1,0), basegfx::B2DVector (0,1), basegfx::B2DVector (1,1));
+ maLeavingSlidePrimitives.push_back (Slide);
+ maEnteringSlidePrimitives.push_back (Slide);
+
+ mmDisplaySlides = &OGLTransitionImpl::displaySlidesShaders;
+ mmPrepareTransition = &OGLTransitionImpl::prepareDissolve;
+ mbUseMipMapLeaving = mbUseMipMapEntering = false;
+
+ mnRequiredGLVersion = 2.0;
+}
+
+void OGLTransitionImpl::makeNewsflash()
+{
+ Primitive Slide;
+
+ Slide.pushTriangle(basegfx::B2DVector(0,0),basegfx::B2DVector(1,0),basegfx::B2DVector(0,1));
+ Slide.pushTriangle(basegfx::B2DVector(1,0),basegfx::B2DVector(0,1),basegfx::B2DVector(1,1));
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),3000,true,0,0.5));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),true,0,0.5));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-10000, 0, 0),false, 0.5, 2));
+ maLeavingSlidePrimitives.push_back(Slide);
+
+ Slide.Operations.clear();
+ Slide.Operations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0,0,0),-3000,true,0.5,1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(-100, 0, 0),false, -1, 1));
+ Slide.Operations.push_back(new STranslate(basegfx::B3DVector(100, 0, 0),false, 0.5, 1));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(0.01,0.01,0.01),basegfx::B3DVector(0,0,0),false,-1,1));
+ Slide.Operations.push_back(new SScale(basegfx::B3DVector(100,100,100),basegfx::B3DVector(0,0,0),true,0.5,1));
+ maEnteringSlidePrimitives.push_back(Slide);
+
+ OverallOperations.push_back(new SRotate(basegfx::B3DVector(0,0,1),basegfx::B3DVector(0.2,0.2,0),1080,true,0,1));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.hxx b/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.hxx
new file mode 100644
index 000000000000..504a96bac35e
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionImpl.hxx
@@ -0,0 +1,507 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
+#define INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
+
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+
+#if defined( WNT )
+#elif defined( OS2 )
+#elif defined( QUARTZ )
+#include <OpenGL/gl.h>
+#elif defined( UNX ) && !defined( QUARTZ )
+#endif
+
+#include <vector>
+
+#if !defined( QUARTZ )
+#include <GL/gl.h>
+#endif
+
+using namespace std;
+
+class Primitive;
+class Operation;
+class SceneObject;
+
+
+/** OpenGL 3D Transition class. It implicitly is constructed from XOGLTransition
+
+ This class is capable of making itself into many difference transitions. It holds Primitives and Operations on those primitives.
+*/
+class OGLTransitionImpl
+{
+public:
+ OGLTransitionImpl() :
+ mbUseMipMapLeaving( true ),
+ mbUseMipMapEntering( true ),
+ mnRequiredGLVersion( 1.0 ),
+ maLeavingSlidePrimitives(),
+ maEnteringSlidePrimitives(),
+ maSceneObjects(),
+ mbReflectSlides( false ),
+ mVertexObject( 0 ),
+ mFragmentObject( 0 ),
+ mProgramObject( 0 ),
+ maHelperTexture( 0 ),
+ mmPrepare( NULL ),
+ mmPrepareTransition( NULL ),
+ mmClearTransition( NULL ),
+ mmDisplaySlides( NULL )
+ {}
+
+ ~OGLTransitionImpl();
+
+ void prepare( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight );
+ void finish();
+
+ void makeOutsideCubeFaceToLeft();
+ void makeInsideCubeFaceToLeft();
+ void makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m );
+ void makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles );
+ void makeHelix( ::sal_uInt16 nRows );
+ void makeFallLeaving();
+ void makeTurnAround();
+ void makeTurnDown();
+ void makeIris();
+ void makeRochade();
+ void makeVenetianBlinds( bool vertical, int parts );
+ void makeStatic();
+ void makeDissolve();
+ void makeNewsflash();
+
+ /** 2D replacements
+ */
+ void makeDiamond();
+ void makeFadeSmoothly();
+ void makeFadeThroughBlack();
+
+ /** Whether to use mipmaping for slides textures
+ */
+ bool mbUseMipMapLeaving;
+ bool mbUseMipMapEntering;
+
+ /** which GL version does the transition require
+ */
+ float mnRequiredGLVersion;
+
+private:
+ /** clears all the primitives and operations
+ */
+ void clear();
+
+ /** All the primitives that use the leaving slide texture
+ */
+ vector<Primitive> maLeavingSlidePrimitives;
+
+ /** All the primitives that use the leaving slide texture
+ */
+ vector<Primitive> maEnteringSlidePrimitives;
+
+ /** All the surrounding scene objects
+ */
+ vector<SceneObject*> maSceneObjects;
+
+ /** All the operations that should be applied to both leaving and entering slide primitives. These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
+ */
+ vector<Operation*> OverallOperations;
+
+ /** Whether to reflect slides, the reflection happens on flat surface beneath the slides.
+ ** Now it only works with slides which keep their rectangular shape together.
+ */
+ bool mbReflectSlides;
+
+ /** GLSL objects, shaders and program
+ */
+ GLuint mVertexObject, mFragmentObject, mProgramObject;
+
+ /** various data */
+ GLuint maHelperTexture;
+
+ /** When this method is not NULL, it is called in display method to prepare the slides, scene, etc.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmPrepare)( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight );
+
+ /** When this method is not NULL, it is called after glx context is ready to let the transition prepare GL related things, like GLSL program.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmPrepareTransition)( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+
+ /** When this method is not NULL, it is called when the transition needs to clear after itself, like delete own textures etc.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmClearTransition)();
+
+ /** When this method is not NULL, it is called in display method to display the slides.
+ ** We might later replace this by cleaner derived class.
+ */
+ void (OGLTransitionImpl::*mmDisplaySlides)( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+
+ void displaySlides( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlide( double nTime, ::sal_Int32 glSlideTex, std::vector<Primitive>& primitives, double SlideWidthScale, double SlideHeightScale );
+ void displayScene( double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ void applyOverallOperations( double nTime, double SlideWidthScale, double SlideHeightScale );
+
+ /** various transitions helper methods
+ */
+ void prepareDiamond( double nTime, double SlideWidth, double SlideHeight,double DispWidth, double DispHeight );
+ void displaySlidesFadeSmoothly( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesFadeThroughBlack( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesRochade( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void displaySlidesShaders( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidthScale, double SlideHeightScale );
+ void prepareStatic( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void prepareDissolve( ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex );
+ void preparePermShader();
+};
+
+class SceneObject
+{
+public:
+ SceneObject();
+
+ virtual void prepare() {};
+ virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ virtual void finish() {};
+
+ void pushPrimitive (const Primitive &p);
+
+protected:
+ /** All the surrounding scene primitives
+ */
+ vector<Primitive> maPrimitives;
+};
+
+class Iris : public SceneObject
+{
+public:
+ Iris ();
+
+ virtual void prepare();
+ virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
+ virtual void finish();
+
+private:
+
+ GLuint maTexture;
+};
+
+/** This class is a list of Triangles that will share Operations, and could possibly share
+*/
+class Primitive
+{
+public:
+ Primitive() {}
+ // making copy constructor explicit makes the class un-suitable for use with stl containers
+ Primitive(const Primitive& rvalue);
+ ~Primitive();
+
+ void applyOperations(double nTime, double SlideWidthScale, double SlideHeightScale);
+ void display(double nTime, double SlideWidthScale, double SlideHeightScale);
+ const Primitive& operator=(const Primitive& rvalue);
+
+ /** PushBack a vertex,normal, and tex coord. Each SlideLocation is where on the slide is mapped to this location ( from (0,0) to (1,1) ). This will make sure the correct aspect ratio is used, and helps to make slides begin and end at the correct position. (0,0) is the top left of the slide, and (1,1) is the bottom right.
+
+ @param SlideLocation0
+ Location of first Vertex on slide
+
+ @param SlideLocation1
+ Location of second Vertex on slide
+
+ @param SlideLocation2
+ Location of third Vertex on slide
+
+ */
+ void pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2);
+
+ /** clear all the vertices, normals, tex coordinates, and normals
+ */
+ void clearTriangles();
+
+ /** guards against directly changing the vertices
+
+ @return
+ the list of vertices
+ */
+ const vector<basegfx::B3DVector>& getVertices() const {return Vertices;}
+
+ /** guards against directly changing the vertices
+ */
+ const vector<basegfx::B3DVector>& getNormals() const {return Normals;}
+
+ /** guards against directly changing the vertices
+
+ @return
+ the list of Texture Coordinates
+
+ */
+ const vector<basegfx::B2DVector>& getTexCoords() const {return TexCoords;}
+
+ /** list of Operations to be performed on this primitive.These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
+
+ @return
+ the list of Operations
+
+ */
+ vector<Operation*> Operations;
+
+private:
+ /** list of vertices
+ */
+ vector<basegfx::B3DVector> Vertices;
+
+ /** list of Normals
+ */
+ vector<basegfx::B3DVector> Normals;
+
+ /** list of Texture Coordinates
+ */
+ vector<basegfx::B2DVector> TexCoords;
+};
+
+/** This class is to be derived to make any operation (tranform) you may need in order to construct your transitions
+*/
+class Operation
+{
+public:
+ Operation(){}
+ virtual ~Operation(){}
+
+ /** Should this operation be interpolated . If TRUE, the transform will smoothly move from making no difference from t = 0.0 to nT0 to being completely transformed from t = nT1 to 1. If FALSE, the transform will be inneffectual from t = 0 to nT0, and completely transformed from t = nT0 to 1.
+ */
+ bool bInterpolate;
+
+ /** time to begin the transformation
+ */
+ double nT0;
+
+ /** time to finish the transformation
+ */
+ double nT1;
+public:
+ /** this is the function that is called to give the Operation to OpenGL.
+
+ @param t
+ time from t = 0 to t = 1
+
+ @param SlideWidthScale
+ width of slide divided by width of window
+
+ @param SlideHeightScale
+ height of slide divided by height of window
+
+ */
+ virtual void interpolate(double t,double SlideWidthScale,double SlideHeightScale) = 0;
+
+ /** return a copy of this operation
+ */
+ virtual Operation* clone() = 0;
+};
+
+/** this class is a generic CounterClockWise(CCW) rotation with an axis angle
+*/
+class SRotate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ virtual SRotate* clone();
+
+ /** Constructor
+
+ @param Axis
+ axis to rotate about
+
+ @param Origin
+ position that rotation axis runs through
+
+ @param Angle
+ angle in radians of CCW rotation
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~SRotate(){}
+private:
+ /** axis to rotate CCW about
+ */
+ basegfx::B3DVector axis;
+
+ /** position that rotation axis runs through
+ */
+ basegfx::B3DVector origin;
+
+ /** angle in radians of CCW rotation
+ */
+ double angle;
+};
+
+/** scaling transformation
+*/
+class SScale: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ SScale* clone();
+
+ /** Constructor
+
+ @param Scale
+ amount to scale by
+
+ @param Origin
+ position that rotation axis runs through
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SScale(const basegfx::B3DVector& Scale, const basegfx::B3DVector& Origin,bool bInter, double T0, double T1);
+ ~SScale(){}
+private:
+ basegfx::B3DVector scale;
+ basegfx::B3DVector origin;
+};
+
+/** translation transformation
+*/
+class STranslate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ STranslate* clone();
+
+ /** Constructor
+
+ @param Vector
+ vector to translate
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ STranslate(const basegfx::B3DVector& Vector,bool bInter, double T0, double T1);
+ ~STranslate(){}
+private:
+ /** vector to translate by
+ */
+ basegfx::B3DVector vector;
+};
+
+/** translation transformation
+*/
+class SEllipseTranslate: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ SEllipseTranslate* clone();
+
+ /** Constructor
+
+ @param Vector
+ vector to translate
+
+ @param bInter
+ see Operation
+
+ @param T0
+ transformation starting time
+
+ @param T1
+ transformation ending time
+
+ */
+ SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1);
+ ~SEllipseTranslate(){}
+private:
+ /** width and length of the ellipse
+ */
+ double width, height;
+
+ /** start and end position on the ellipse <0,1>
+ */
+ double startPosition;
+ double endPosition;
+};
+
+/** Same as SRotate, except the depth is scaled by the width of the slide divided by the width of the window.
+*/
+class RotateAndScaleDepthByWidth: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ RotateAndScaleDepthByWidth* clone();
+
+ RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~RotateAndScaleDepthByWidth(){}
+private:
+ basegfx::B3DVector axis;
+ basegfx::B3DVector origin;
+ double angle;
+};
+
+/** Same as SRotate, except the depth is scaled by the width of the slide divided by the height of the window.
+*/
+class RotateAndScaleDepthByHeight: public Operation
+{
+public:
+ void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
+ RotateAndScaleDepthByHeight* clone();
+
+ RotateAndScaleDepthByHeight(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
+ ~RotateAndScaleDepthByHeight(){}
+private:
+ basegfx::B3DVector axis;
+ basegfx::B3DVector origin;
+ double angle;
+};
+
+#endif // INCLUDED_SLIDESHOW_TRANSITION_HXX_
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionerImpl.cxx b/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionerImpl.cxx
new file mode 100644
index 000000000000..3a5bc0b43e88
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/win/OGLTrans_TransitionerImpl.cxx
@@ -0,0 +1,1455 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#define GLX_GLXEXT_PROTOTYPES 1
+#include "OGLTrans_TransitionImpl.hxx"
+
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/presentation/XTransitionFactory.hpp>
+#include <com/sun/star/presentation/XTransition.hpp>
+#include <com/sun/star/presentation/XSlideShowView.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/geometry/IntegerSize2D.hpp>
+
+#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/factory.hxx>
+#include <rtl/ref.hxx>
+
+#include <comphelper/servicedecl.hxx>
+
+#include <canvas/canvastools.hxx>
+#include <tools/gen.hxx>
+#include <vcl/window.hxx>
+#include <vcl/syschild.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <boost/noncopyable.hpp>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+
+#ifdef DEBUG
+#include <boost/date_time/posix_time/posix_time.hpp>
+using namespace ::boost::posix_time;
+
+static ptime t1;
+static ptime t2;
+
+#define DBG(x) x
+#else
+#define DBG(x)
+#endif
+
+using namespace ::com::sun::star;
+using ::com::sun::star::beans::XFastPropertySet;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+
+namespace
+{
+
+typedef cppu::WeakComponentImplHelper1<presentation::XTransition> OGLTransitionerImplBase;
+
+namespace
+{
+ struct OGLFormat
+ {
+ GLint nInternalFormat;
+ GLenum eFormat;
+ GLenum eType;
+ };
+
+ /* channel ordering: (0:rgba, 1:bgra, 2:argb, 3:abgr)
+ */
+ int calcComponentOrderIndex(const uno::Sequence<sal_Int8>& rTags)
+ {
+ using namespace rendering::ColorComponentTag;
+
+ static const sal_Int8 aOrderTable[] =
+ {
+ RGB_RED, RGB_GREEN, RGB_BLUE, ALPHA,
+ RGB_BLUE, RGB_GREEN, RGB_RED, ALPHA,
+ ALPHA, RGB_RED, RGB_GREEN, RGB_BLUE,
+ ALPHA, RGB_BLUE, RGB_GREEN, RGB_RED,
+ };
+
+ const sal_Int32 nNumComps(rTags.getLength());
+ const sal_Int8* pLine=aOrderTable;
+ for(int i=0; i<4; ++i)
+ {
+ int j=0;
+ while( j<4 && j<nNumComps && pLine[j] == rTags[j] )
+ ++j;
+
+ // all of the line passed, this is a match!
+ if( j==nNumComps )
+ return i;
+
+ pLine+=4;
+ }
+
+ return -1;
+ }
+}
+
+// not thread safe
+static bool errorTriggered;
+int oglErrorHandler( unx::Display* /*dpy*/, unx::XErrorEvent* /*evnt*/ )
+{
+ errorTriggered = true;
+
+ return 0;
+}
+
+/** This is the Transitioner class for OpenGL 3D transitions in
+ * slideshow. At the moment, it's Linux only. This class is implicitly
+ * constructed from XTransitionFactory.
+*/
+class OGLTransitionerImpl : private cppu::BaseMutex, private boost::noncopyable, public OGLTransitionerImplBase
+{
+public:
+ explicit OGLTransitionerImpl(OGLTransitionImpl* pOGLTransition);
+ bool initWindowFromSlideShowView( const uno::Reference< presentation::XSlideShowView >& xView );
+ void setSlides( const Reference< rendering::XBitmap >& xLeavingSlide , const uno::Reference< rendering::XBitmap >& xEnteringSlide );
+ static bool initialize( const Reference< presentation::XSlideShowView >& xView );
+
+ // XTransition
+ virtual void SAL_CALL update( double nTime )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL viewChanged( const Reference< presentation::XSlideShowView >& rView,
+ const Reference< rendering::XBitmap >& rLeavingBitmap,
+ const Reference< rendering::XBitmap >& rEnteringBitmap )
+ throw (uno::RuntimeException);
+
+protected:
+ void disposeContextAndWindow();
+ void disposeTextures();
+
+ // WeakComponentImplHelperBase
+ virtual void SAL_CALL disposing();
+
+ bool isDisposed() const
+ {
+ return (rBHelper.bDisposed || rBHelper.bInDispose);
+ }
+
+ bool createWindow( Window* pPWindow );
+ void createTexture( unsigned int* texID,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXPixmap pixmap,
+ bool usePixmap,
+#endif
+ bool useMipmap,
+ uno::Sequence<sal_Int8>& data,
+ const OGLFormat* pFormat );
+ void prepareEnvironment ();
+ const OGLFormat* chooseFormats();
+
+private:
+ /** After the window has been created, and the slides have been set, we'll initialize the slides with OpenGL.
+ */
+ void GLInitSlides();
+
+
+ /// Holds the information of our new child window
+ struct GLWindow
+ {
+ HWND hWnd;
+ HDC hDC;
+ HGLRC hRC;
+ unsigned int bpp;
+ unsigned int Width;
+ unsigned int Height;
+ const char* GLXExtensions;
+ const GLubyte* GLExtensions;
+
+ bool HasGLXExtension( const char* name ) { return gluCheckExtension( (const GLubyte*) name, (const GLubyte*) GLXExtensions ); }
+ bool HasGLExtension( const char* name ) { return gluCheckExtension( (const GLubyte*) name, GLExtensions ); }
+ } GLWin;
+
+ /** OpenGL handle to the leaving slide's texture
+ */
+ unsigned int GLleavingSlide;
+ /** OpenGL handle to the entering slide's texture
+ */
+ unsigned int GLenteringSlide;
+
+ /** pointer to our window which we MIGHT create.
+ */
+ class SystemChildWindow* pWindow;
+
+ Reference< presentation::XSlideShowView > mxView;
+ Reference< rendering::XIntegerBitmap > mxLeavingBitmap;
+ Reference< rendering::XIntegerBitmap > mxEnteringBitmap;
+
+ /** raw bytes of the entering bitmap
+ */
+ uno::Sequence<sal_Int8> EnteringBytes;
+
+ /** raw bytes of the leaving bitmap
+ */
+ uno::Sequence<sal_Int8> LeavingBytes;
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXPixmap LeavingPixmap;
+ unx::GLXPixmap EnteringPixmap;
+#endif
+ bool mbRestoreSync;
+ bool mbUseLeavingPixmap;
+ bool mbUseEnteringPixmap;
+ bool mbFreeLeavingPixmap;
+ bool mbFreeEnteringPixmap;
+ unx::Pixmap maLeavingPixmap;
+ unx::Pixmap maEnteringPixmap;
+
+ /** the form the raw bytes are in for the bitmaps
+ */
+ rendering::IntegerBitmapLayout SlideBitmapLayout;
+
+ /** the size of the slides
+ */
+ geometry::IntegerSize2D SlideSize;
+
+ /** Our Transition to be used.
+ */
+ OGLTransitionImpl* pTransition;
+
+public:
+ /** whether we are running on ATI fglrx with bug related to textures
+ */
+ static bool cbBrokenTexturesATI;
+
+ /** GL version
+ */
+ static float cnGLVersion;
+ float mnGLXVersion;
+
+ /** Whether Mesa is the OpenGL vendor
+ */
+ static bool cbMesa;
+
+ /**
+ whether the display has GLX extension
+ */
+ static bool cbGLXPresent;
+
+ /**
+ whether texture from pixmap extension is available
+ */
+ bool mbTextureFromPixmap;
+
+ /**
+ whether to generate mipmaped textures
+ */
+ bool mbGenerateMipmap;
+
+ /**
+ whether we have visual which can be used for texture_from_pixmap extension
+ */
+ bool mbHasTFPVisual;
+
+#ifdef DEBUG
+ ptime t3;
+ ptime t4;
+ ptime t5;
+ ptime t6;
+ time_duration total_update;
+ int frame_count;
+#endif
+};
+
+// declare the static variables as some gcc versions have problems declaring them automaticaly
+bool OGLTransitionerImpl::cbBrokenTexturesATI;
+float OGLTransitionerImpl::cnGLVersion;
+bool OGLTransitionerImpl::cbMesa;
+bool OGLTransitionerImpl::cbGLXPresent;
+
+bool OGLTransitionerImpl::initialize( const Reference< presentation::XSlideShowView >& xView )
+{
+ // not thread safe
+ static bool initialized = false;
+
+ if( !initialized ) {
+ OGLTransitionerImpl *instance;
+
+ instance = new OGLTransitionerImpl( NULL );
+ if( instance->initWindowFromSlideShowView( xView ) ) {
+
+ const GLubyte* version = glGetString( GL_VERSION );
+ if( version && version[0] ) {
+ cnGLVersion = version[0] - '0';
+ if( version[1] == '.' && version[2] )
+ cnGLVersion += (version[2] - '0')/10.0;
+ } else
+ cnGLVersion = 1.0;
+ OSL_TRACE("GL version: %s parsed: %f", version, cnGLVersion );
+
+ const GLubyte* vendor = glGetString( GL_VENDOR );
+ cbMesa = ( vendor && strstr( (const char *) vendor, "Mesa" ) );
+ OSL_TRACE("GL vendor: %s identified as Mesa: %d", vendor, cbMesa );
+
+ /* TODO: check for version once the bug in fglrx driver is fixed */
+ cbBrokenTexturesATI = (vendor && strcmp( (const char *) vendor, "ATI Technologies Inc." ) == 0 );
+
+ instance->disposing();
+ cbGLXPresent = true;
+ } else
+ cbGLXPresent = false;
+
+ delete instance;
+ initialized = true;
+ }
+
+ return cbGLXPresent;
+}
+
+bool OGLTransitionerImpl::createWindow( Window* pPWindow )
+{
+ const SystemEnvData* sysData(pPWindow->GetSystemData());
+#if defined( WNT )
+ GLWin.hWnd = sysData->hWnd;
+#elif defined( UNX )
+ GLWin.dpy = reinterpret_cast<unx::Display*>(sysData->pDisplay);
+
+ if( unx::glXQueryExtension( GLWin.dpy, NULL, NULL ) == false )
+ return false;
+
+ GLWin.win = sysData->aWindow;
+
+ OSL_TRACE("parent window: %d", GLWin.win);
+
+ unx::XWindowAttributes xattr;
+ unx::XGetWindowAttributes( GLWin.dpy, GLWin.win, &xattr );
+
+ GLWin.screen = XScreenNumberOfScreen( xattr.screen );
+
+ unx::XVisualInfo* vi( NULL );
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::XVisualInfo* visinfo;
+ unx::XVisualInfo* firstVisual( NULL );
+#endif
+ static int attrList3[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ //single buffered
+ GLX_RED_SIZE,4,//use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,//use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,//use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,0,//no depth buffer
+ None
+ };
+ static int attrList2[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ /// single buffered
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
+ None
+ };
+ static int attrList1[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ GLX_DOUBLEBUFFER,/// only double buffer
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,0,/// no depth buffer
+ None
+ };
+ static int attrList0[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ GLX_DOUBLEBUFFER,/// only double buffer
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
+ None
+ };
+ static int* attrTable[] =
+ {
+ attrList0,
+ attrList1,
+ attrList2,
+ attrList3,
+ NULL
+ };
+ int** pAttributeTable = attrTable;
+ const SystemEnvData* pChildSysData = NULL;
+ delete pWindow;
+ pWindow=NULL;
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXFBConfig* fbconfigs = NULL;
+ int nfbconfigs, value, i = 0;
+#endif
+
+ while( *pAttributeTable )
+ {
+ // try to find a visual for the current set of attributes
+ vi = unx::glXChooseVisual( GLWin.dpy,
+ GLWin.screen,
+ *pAttributeTable );
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ if( vi ) {
+ if( !firstVisual )
+ firstVisual = vi;
+ OSL_TRACE("trying VisualID %08X", vi->visualid);
+ fbconfigs = glXGetFBConfigs (GLWin.dpy, GLWin.screen, &nfbconfigs);
+ for ( ; i < nfbconfigs; i++)
+ {
+ visinfo = glXGetVisualFromFBConfig (GLWin.dpy, fbconfigs[i]);
+ if( !visinfo || visinfo->visualid != vi->visualid )
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i], GLX_DRAWABLE_TYPE, &value);
+ if (!(value & GLX_PIXMAP_BIT))
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i],
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT,
+ &value);
+ if (!(value & GLX_TEXTURE_2D_BIT_EXT))
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i],
+ GLX_BIND_TO_TEXTURE_RGB_EXT,
+ &value);
+ if (value == sal_False)
+ continue;
+
+ glXGetFBConfigAttrib (GLWin.dpy, fbconfigs[i],
+ GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
+ &value);
+ if (value == sal_False)
+ continue;
+
+ /* TODO: handle non Y inverted cases */
+ break;
+ }
+
+ if( i != nfbconfigs || ( firstVisual && pAttributeTable[1] == NULL ) ) {
+ if( i != nfbconfigs ) {
+ vi = glXGetVisualFromFBConfig( GLWin.dpy, fbconfigs[i] );
+ mbHasTFPVisual = true;
+ OSL_TRACE("found visual suitable for texture_from_pixmap");
+ } else {
+ vi = firstVisual;
+ mbHasTFPVisual = false;
+ OSL_TRACE("did not find visual suitable for texture_from_pixmap, using %08X", vi->visualid);
+ }
+#else
+ if( vi ) {
+#endif
+ SystemWindowData winData;
+ winData.nSize = sizeof(winData);
+ OSL_TRACE("using VisualID %08X", vi->visualid);
+ winData.pVisual = (void*)(vi->visual);
+ pWindow=new SystemChildWindow(pPWindow, 0, &winData, sal_False);
+ pChildSysData = pWindow->GetSystemData();
+ if( pChildSysData ) {
+ break;
+ } else {
+ delete pWindow, pWindow=NULL;
+ }
+ }
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ }
+#endif
+
+ ++pAttributeTable;
+ }
+#endif
+
+#if defined( WNT )
+ const SystemEnvData* pChildSysData = NULL;
+ SystemWindowData winData;
+ winData.nSize = sizeof(winData);
+ pWindow=new SystemChildWindow(pPWindow, 0, &winData, sal_False);
+ pChildSysData = pWindow->GetSystemData();
+#endif
+
+ if( pWindow )
+ {
+ pWindow->SetMouseTransparent( sal_True );
+ pWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ pWindow->EnableEraseBackground( sal_False );
+ pWindow->SetControlForeground();
+ pWindow->SetControlBackground();
+ pWindow->EnablePaint(sal_False);
+#if defined( WNT )
+ GLWin.hWnd = sysData->hWnd;
+#elif defined( UNX )
+ GLWin.dpy = reinterpret_cast<unx::Display*>(pChildSysData->pDisplay);
+ GLWin.win = pChildSysData->aWindow;
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ if( mbHasTFPVisual )
+ GLWin.fbc = fbconfigs[i];
+#endif
+ GLWin.vi = vi;
+ GLWin.GLXExtensions = unx::glXQueryExtensionsString( GLWin.dpy, GLWin.screen );
+ OSL_TRACE("available GLX extensions: %s", GLWin.GLXExtensions);
+#endif
+
+ return true;
+ }
+
+ return false;
+}
+
+bool OGLTransitionerImpl::initWindowFromSlideShowView( const Reference< presentation::XSlideShowView >& xView )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ mxView.set( xView, UNO_QUERY );
+ if( !mxView.is() )
+ return false;
+
+ /// take the XSlideShowView and extract the parent window from it. see viewmediashape.cxx
+ uno::Reference< rendering::XCanvas > xCanvas(mxView->getCanvas(), uno::UNO_QUERY_THROW);
+ uno::Sequence< uno::Any > aDeviceParams;
+ ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams );
+
+ ::rtl::OUString aImplName;
+ aDeviceParams[ 0 ] >>= aImplName;
+
+ sal_Int64 aVal = 0;
+ aDeviceParams[1] >>= aVal;
+ if( !createWindow( reinterpret_cast< Window* >( aVal ) ) )
+ return false;
+
+ awt::Rectangle aCanvasArea = mxView->getCanvasArea();
+ pWindow->SetPosSizePixel(aCanvasArea.X, aCanvasArea.Y, aCanvasArea.Width, aCanvasArea.Height);
+ GLWin.Width = aCanvasArea.Width;
+ GLWin.Height = aCanvasArea.Height;
+ OSL_TRACE("canvas area: %d,%d - %dx%d", aCanvasArea.X, aCanvasArea.Y, aCanvasArea.Width, aCanvasArea.Height);
+
+#if defined( WNT )
+ GLWin.hDC = GetDC(GLWin.hWnd);
+#elif defined( UNX )
+ GLWin.ctx = glXCreateContext(GLWin.dpy,
+ GLWin.vi,
+ 0,
+ GL_TRUE);
+ if( GLWin.ctx == NULL ) {
+ OSL_TRACE("unable to create GLX context");
+ return false;
+ }
+#endif
+
+#if defined( WNT )
+ PIXELFORMATDESCRIPTOR PixelFormatFront = // PixelFormat Tells Windows How We Want Things To Be
+ {
+ sizeof(PIXELFORMATDESCRIPTOR),
+ 1, // Version Number
+ PFD_DRAW_TO_WINDOW |
+ PFD_SUPPORT_OPENGL |
+ PFD_DOUBLEBUFFER,
+ PFD_TYPE_RGBA, // Request An RGBA Format
+ (BYTE)32, // Select Our Color Depth
+ 0, 0, 0, 0, 0, 0, // Color Bits Ignored
+ 0, // No Alpha Buffer
+ 0, // Shift Bit Ignored
+ 0, // No Accumulation Buffer
+ 0, 0, 0, 0, // Accumulation Bits Ignored
+ 64, // 32 bit Z-BUFFER
+ 0, // 0 bit stencil buffer
+ 0, // No Auxiliary Buffer
+ 0, // now ignored
+ 0, // Reserved
+ 0, 0, 0 // Layer Masks Ignored
+ };
+ int WindowPix = ChoosePixelFormat(GLWin.hDC,&PixelFormatFront);
+ SetPixelFormat(GLWin.hDC,WindowPix,&PixelFormatFront);
+ GLWin.hRC = wglCreateContext(GLWin.hDC);
+ wglMakeCurrent(GLWin.hDC,GLWin.hRC);
+#elif defined( UNX )
+ if( !glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx ) ) {
+ OSL_TRACE("unable to select current GLX context");
+ return false;
+ }
+
+ int glxMinor, glxMajor;
+ mnGLXVersion = 0;
+ if( glXQueryVersion( GLWin.dpy, &glxMajor, &glxMinor ) )
+ mnGLXVersion = glxMajor + 0.1*glxMinor;
+ OSL_TRACE("available GLX version: %f", mnGLXVersion);
+
+ GLWin.GLExtensions = glGetString( GL_EXTENSIONS );
+ OSL_TRACE("available GL extensions: %s", GLWin.GLExtensions);
+
+ mbTextureFromPixmap = GLWin.HasGLXExtension( "GLX_EXT_texture_from_pixmap" );
+ mbGenerateMipmap = GLWin.HasGLExtension( "GL_SGIS_generate_mipmap" );
+
+ if( GLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) {
+ // enable vsync
+ typedef GLint (*glXSwapIntervalProc)(GLint);
+ glXSwapIntervalProc glXSwapInterval = (glXSwapIntervalProc) unx::glXGetProcAddress( (const GLubyte*) "glXSwapIntervalSGI" );
+ if( glXSwapInterval ) {
+ int (*oldHandler)(unx::Display* /*dpy*/, unx::XErrorEvent* /*evnt*/);
+
+ // replace error handler temporarily
+ oldHandler = unx::XSetErrorHandler( oglErrorHandler );
+
+ errorTriggered = false;
+
+ glXSwapInterval( 1 );
+
+ // sync so that we possibly get an XError
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ if( errorTriggered )
+ OSL_TRACE("error when trying to set swap interval, NVIDIA or Mesa bug?");
+ else
+ OSL_TRACE("set swap interval to 1 (enable vsync)");
+
+ // restore the error handler
+ unx::XSetErrorHandler( oldHandler );
+ }
+ }
+#endif
+
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glClearColor (0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+#if defined( WNT )
+ SwapBuffers(GLWin.hDC);
+#elif defined( UNX )
+ unx::glXSwapBuffers(GLWin.dpy, GLWin.win);
+#endif
+
+ glEnable(GL_LIGHTING);
+ GLfloat light_direction[] = { 0.0 , 0.0 , 1.0 };
+ GLfloat materialDiffuse[] = { 1.0 , 1.0 , 1.0 , 1.0};
+ glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
+ glMaterialfv(GL_FRONT,GL_DIFFUSE,materialDiffuse);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_NORMALIZE);
+
+ if( LeavingBytes.hasElements() && EnteringBytes.hasElements())
+ GLInitSlides();//we already have uninitialized slides, let's initialize
+
+ if( pTransition && pTransition->mnRequiredGLVersion <= cnGLVersion )
+ pTransition->prepare( GLleavingSlide, GLenteringSlide );
+
+ return true;
+}
+
+void OGLTransitionerImpl::setSlides( const uno::Reference< rendering::XBitmap >& xLeavingSlide,
+ const uno::Reference< rendering::XBitmap >& xEnteringSlide )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ mxLeavingBitmap.set( xLeavingSlide , UNO_QUERY_THROW );
+ mxEnteringBitmap.set( xEnteringSlide , UNO_QUERY_THROW );
+ Reference< XFastPropertySet > xLeavingSet( xLeavingSlide , UNO_QUERY );
+ Reference< XFastPropertySet > xEnteringSet( xEnteringSlide , UNO_QUERY );
+
+ geometry::IntegerRectangle2D SlideRect;
+ SlideSize = mxLeavingBitmap->getSize();
+ SlideRect.X1 = 0;
+ SlideRect.X2 = SlideSize.Width;
+ SlideRect.Y1 = 0;
+ SlideRect.Y2 = SlideSize.Height;
+
+ OSL_TRACE("leaving bitmap area: %dx%d", SlideSize.Width, SlideSize.Height);
+ SlideSize = mxEnteringBitmap->getSize();
+ OSL_TRACE("entering bitmap area: %dx%d", SlideSize.Width, SlideSize.Height);
+
+#ifdef UNX
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+#endif
+
+#ifdef DEBUG
+ t1 = microsec_clock::local_time();
+#endif
+
+ mbUseLeavingPixmap = false;
+ mbUseEnteringPixmap = false;
+
+#ifdef UNX
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+
+ if( mnGLXVersion >= 1.2999 && mbTextureFromPixmap && xLeavingSet.is() && xEnteringSet.is() && mbHasTFPVisual ) {
+ Sequence< Any > leaveArgs;
+ Sequence< Any > enterArgs;
+ if( (xLeavingSet->getFastPropertyValue( 1 ) >>= leaveArgs) &&
+ (xEnteringSet->getFastPropertyValue( 1 ) >>= enterArgs) ) {
+ OSL_TRACE ("pixmaps available");
+
+ sal_Int32 depth;
+
+ leaveArgs[0] >>= mbFreeLeavingPixmap;
+ enterArgs[0] >>= mbFreeEnteringPixmap;
+ leaveArgs[1] >>= maLeavingPixmap;
+ enterArgs[1] >>= maEnteringPixmap;
+ leaveArgs[2] >>= depth;
+
+ int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
+ GLX_MIPMAP_TEXTURE_EXT, True,
+ None };
+
+
+ // sync so that we possibly get an pending XError, before we set our handler.
+ // this way we will not miss any error from other code
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ int (*oldHandler)(unx::Display* /*dpy*/, unx::XErrorEvent* /*evnt*/);
+
+ // replace error handler temporarily
+ oldHandler = unx::XSetErrorHandler( oglErrorHandler );
+
+ errorTriggered = false;
+ LeavingPixmap = glXCreatePixmap( GLWin.dpy, GLWin.fbc, maLeavingPixmap, pixmapAttribs );
+
+ // sync so that we possibly get an XError
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ if( !errorTriggered )
+ mbUseLeavingPixmap = true;
+ else {
+ OSL_TRACE("XError triggered");
+ if( mbFreeLeavingPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maLeavingPixmap );
+ mbFreeLeavingPixmap = false;
+ }
+ errorTriggered = false;
+ }
+
+ EnteringPixmap = glXCreatePixmap( GLWin.dpy, GLWin.fbc, maEnteringPixmap, pixmapAttribs );
+
+ // sync so that we possibly get an XError
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+
+ OSL_TRACE("created glx pixmap %p and %p depth: %d", LeavingPixmap, EnteringPixmap, depth);
+ if( !errorTriggered )
+ mbUseEnteringPixmap = true;
+ else {
+ OSL_TRACE("XError triggered");
+ if( mbFreeEnteringPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maEnteringPixmap );
+ mbFreeEnteringPixmap = false;
+ }
+ }
+
+ // restore the error handler
+ unx::XSetErrorHandler( oldHandler );
+ }
+ }
+
+#endif
+#endif
+ if( !mbUseLeavingPixmap )
+ LeavingBytes = mxLeavingBitmap->getData(SlideBitmapLayout,SlideRect);
+ if( !mbUseEnteringPixmap )
+ EnteringBytes = mxEnteringBitmap->getData(SlideBitmapLayout,SlideRect);
+
+// TODO
+#ifdef UNX
+ if(GLWin.ctx)//if we have a rendering context, let's init the slides
+#endif
+ GLInitSlides();
+
+ OSL_ENSURE(SlideBitmapLayout.PlaneStride == 0,"only handle no plane stride now");
+
+#ifdef UNX
+ /* flush & sync */
+ unx::glXWaitGL();
+ XSync( GLWin.dpy, false );
+
+ // synchronized X still gives us much smoother play
+ // I suspect some issues in above code in slideshow
+ // synchronize whole transition for now
+ XSynchronize( GLWin.dpy, true );
+ mbRestoreSync = true;
+#endif
+}
+
+void OGLTransitionerImpl::createTexture( unsigned int* texID,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::GLXPixmap pixmap,
+ bool usePixmap,
+#endif
+ bool useMipmap,
+ uno::Sequence<sal_Int8>& data,
+ const OGLFormat* pFormat )
+{
+ glDeleteTextures( 1, texID );
+ glGenTextures( 1, texID );
+ glBindTexture( GL_TEXTURE_2D, *texID );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::PFNGLXBINDTEXIMAGEEXTPROC myglXBindTexImageEXT = (unx::PFNGLXBINDTEXIMAGEEXTPROC) unx::glXGetProcAddress( (const GLubyte*) "glXBindTexImageEXT" );
+
+ if( usePixmap ) {
+ if( mbGenerateMipmap )
+ glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, True);
+ myglXBindTexImageEXT (GLWin.dpy, pixmap, GLX_FRONT_LEFT_EXT, NULL);
+ if( mbGenerateMipmap && useMipmap ) {
+ OSL_TRACE("use mipmaps");
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //TRILINEAR FILTERING
+ } else {
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+ }
+ } else {
+#endif
+ if( !pFormat )
+ {
+ // force-convert color to ARGB8888 int color space
+ uno::Sequence<sal_Int8> tempBytes(
+ SlideBitmapLayout.ColorSpace->convertToIntegerColorSpace(
+ data,
+ canvas::tools::getStdColorSpace()));
+ gluBuild2DMipmaps(GL_TEXTURE_2D,
+ 4,
+ SlideSize.Width,
+ SlideSize.Height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ &tempBytes[0]);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //TRILINEAR FILTERING
+
+ //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles)
+ GLfloat largest_supported_anisotropy;
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy);
+ } else {
+ if( pTransition && !cbBrokenTexturesATI && !useMipmap) {
+ glTexImage2D( GL_TEXTURE_2D, 0, pFormat->nInternalFormat, SlideSize.Width, SlideSize.Height, 0, pFormat->eFormat, pFormat->eType, &data[0] );
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+ } else {
+ gluBuild2DMipmaps( GL_TEXTURE_2D, pFormat->nInternalFormat, SlideSize.Width, SlideSize.Height, pFormat->eFormat, pFormat->eType, &data[0] );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); //TRILINEAR FILTERING
+
+ //anistropic filtering (to make texturing not suck when looking at polygons from oblique angles)
+ GLfloat largest_supported_anisotropy;
+ glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy );
+ }
+ }
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ }
+#endif
+ OSL_ENSURE(glIsTexture(*texID), "Can't generate Leaving slide textures in OpenGL");
+}
+
+void OGLTransitionerImpl::prepareEnvironment()
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ double EyePos(10.0);
+ double RealF(1.0);
+ double RealN(-1.0);
+ double RealL(-1.0);
+ double RealR(1.0);
+ double RealB(-1.0);
+ double RealT(1.0);
+ double ClipN(EyePos+5.0*RealN);
+ double ClipF(EyePos+15.0*RealF);
+ double ClipL(RealL*8.0);
+ double ClipR(RealR*8.0);
+ double ClipB(RealB*8.0);
+ double ClipT(RealT*8.0);
+ //This scaling is to take the plane with BottomLeftCorner(-1,-1,0) and TopRightCorner(1,1,0) and map it to the screen after the perspective division.
+ glScaled( 1.0 / ( ( ( RealR * 2.0 * ClipN ) / ( EyePos * ( ClipR - ClipL ) ) ) - ( ( ClipR + ClipL ) / ( ClipR - ClipL ) ) ),
+ 1.0 / ( ( ( RealT * 2.0 * ClipN ) / ( EyePos * ( ClipT - ClipB ) ) ) - ( ( ClipT + ClipB ) / ( ClipT - ClipB ) ) ),
+ 1.0 );
+ glFrustum(ClipL,ClipR,ClipB,ClipT,ClipN,ClipF);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslated(0,0,-EyePos);
+}
+
+const OGLFormat* OGLTransitionerImpl::chooseFormats()
+{
+ const OGLFormat* pDetectedFormat=NULL;
+ uno::Reference<rendering::XIntegerBitmapColorSpace> xIntColorSpace(
+ SlideBitmapLayout.ColorSpace);
+
+ if( (xIntColorSpace->getType() == rendering::ColorSpaceType::RGB ||
+ xIntColorSpace->getType() == rendering::ColorSpaceType::SRGB) )
+ {
+ /* table for canvas->OGL format mapping. outer index is number
+ of color components (0:3, 1:4), then comes bits per pixel
+ (0:16, 1:24, 2:32), then channel ordering: (0:rgba, 1:bgra,
+ 2:argb, 3:abgr)
+ */
+ static const OGLFormat lcl_RGB24[] =
+ {
+ // 24 bit RGB
+ {3, GL_BGR, GL_UNSIGNED_BYTE},
+ {3, GL_RGB, GL_UNSIGNED_BYTE},
+ {3, GL_BGR, GL_UNSIGNED_BYTE},
+ {3, GL_RGB, GL_UNSIGNED_BYTE}
+ };
+
+#if defined(GL_VERSION_1_2) && defined(GLU_VERSION_1_3)
+ // more format constants available
+ static const OGLFormat lcl_RGB16[] =
+ {
+ // 16 bit RGB
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV},
+ {3, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}
+ };
+
+ static const OGLFormat lcl_ARGB16_4[] =
+ {
+ // 16 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4},
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}
+ };
+
+ static const OGLFormat lcl_ARGB16_5[] =
+ {
+ // 16 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
+ {4, GL_BGRA, GL_UNSIGNED_SHORT_5_5_5_1},
+ {4, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}
+ };
+
+ static const OGLFormat lcl_ARGB32[] =
+ {
+ // 32 bit ARGB
+ {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
+ {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV},
+ {4, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8},
+ {4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}
+ };
+
+ const uno::Sequence<sal_Int8> aComponentTags(
+ xIntColorSpace->getComponentTags());
+ const uno::Sequence<sal_Int32> aComponentBitcounts(
+ xIntColorSpace->getComponentBitCounts());
+ const sal_Int32 nNumComponents( aComponentBitcounts.getLength() );
+ const sal_Int32 nBitsPerPixel( xIntColorSpace->getBitsPerPixel() );
+
+ // supported component ordering?
+ const int nComponentOrderIndex(
+ calcComponentOrderIndex(aComponentTags));
+ if( nComponentOrderIndex != -1 )
+ {
+ switch( nBitsPerPixel )
+ {
+ case 16:
+ if( nNumComponents == 3 )
+ {
+ pDetectedFormat = &lcl_RGB16[nComponentOrderIndex];
+ }
+ else if( nNumComponents == 4 )
+ {
+ if( aComponentBitcounts[1] == 4 )
+ {
+ pDetectedFormat = &lcl_ARGB16_4[nComponentOrderIndex];
+ }
+ else if( aComponentBitcounts[1] == 5 )
+ {
+ pDetectedFormat = &lcl_ARGB16_5[nComponentOrderIndex];
+ }
+ }
+ break;
+ case 24:
+ if( nNumComponents == 3 )
+ {
+ pDetectedFormat = &lcl_RGB24[nComponentOrderIndex];
+ }
+ break;
+ case 32:
+ pDetectedFormat = &lcl_ARGB32[nComponentOrderIndex];
+ break;
+ }
+ }
+#else
+ const uno::Sequence<sal_Int8> aComponentTags(
+ xIntColorSpace->getComponentTags());
+ const int nComponentOrderIndex(calcComponentOrderIndex(aComponentTags));
+ if( aComponentTags.getLength() == 3 &&
+ nComponentOrderIndex != -1 &&
+ xIntColorSpace->getBitsPerPixel() == 24 )
+ {
+ pDetectedFormat = &lcl_RGB24[nComponentOrderIndex];
+ }
+#endif
+ }
+
+ return pDetectedFormat;
+}
+
+void OGLTransitionerImpl::GLInitSlides()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed() || pTransition->mnRequiredGLVersion > cnGLVersion)
+ return;
+
+ prepareEnvironment();
+
+ const OGLFormat* pFormat = NULL;
+ if( !mbUseLeavingPixmap || !mbUseEnteringPixmap )
+ pFormat = chooseFormats();
+
+ createTexture( &GLleavingSlide,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ LeavingPixmap,
+ mbUseLeavingPixmap,
+#endif
+ pTransition->mbUseMipMapLeaving,
+ LeavingBytes,
+ pFormat );
+
+ createTexture( &GLenteringSlide,
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ EnteringPixmap,
+ mbUseEnteringPixmap,
+#endif
+ pTransition->mbUseMipMapEntering,
+ EnteringBytes,
+ pFormat );
+
+#ifdef UNX
+ unx::glXWaitGL();
+ XSync(GLWin.dpy, false);
+#endif
+
+#ifdef DEBUG
+ t2 = microsec_clock::local_time();
+ OSL_TRACE("textures created in: %s", to_simple_string( t2 - t1 ).c_str());
+#endif
+}
+
+void SAL_CALL OGLTransitionerImpl::update( double nTime ) throw (uno::RuntimeException)
+{
+#ifdef DEBUG
+ frame_count ++;
+ t3 = microsec_clock::local_time();
+ if( frame_count == 1 ) {
+ t5 = t3;
+ total_update = seconds (0);
+ }
+#endif
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed() || !cbGLXPresent || pTransition->mnRequiredGLVersion > cnGLVersion)
+ return;
+
+#ifdef WNT
+ wglMakeCurrent(GLWin.hDC,GLWin.hRC);
+#endif
+#ifdef UNX
+ glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx );
+#endif
+
+ glEnable(GL_DEPTH_TEST);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if(pTransition)
+ pTransition->display( nTime, GLleavingSlide, GLenteringSlide,
+ SlideSize.Width, SlideSize.Height,
+ static_cast<double>(GLWin.Width),
+ static_cast<double>(GLWin.Height) );
+
+#if defined( WNT )
+ SwapBuffers(GLWin.hDC);
+#elif defined( UNX )
+ unx::glXSwapBuffers(GLWin.dpy, GLWin.win);
+#endif
+ if( pWindow )
+ pWindow->Show();
+
+#ifdef UNX
+ /* flush & sync */
+ unx::glXWaitGL();
+ XSync( GLWin.dpy, false );
+#endif
+
+#ifdef DEBUG
+ t4 = microsec_clock::local_time();
+
+ OSL_TRACE("update time: %f", nTime);
+ OSL_TRACE("update took: %s", to_simple_string( t4 - t3 ).c_str());
+ total_update += (t4 - t3);
+#endif
+}
+
+void SAL_CALL OGLTransitionerImpl::viewChanged( const Reference< presentation::XSlideShowView >& rView,
+ const Reference< rendering::XBitmap >& rLeavingBitmap,
+ const Reference< rendering::XBitmap >& rEnteringBitmap )
+ throw (uno::RuntimeException)
+{
+ OSL_TRACE("transitioner: view changed");
+
+ disposeTextures();
+ disposeContextAndWindow();
+
+ initWindowFromSlideShowView( rView );
+ setSlides( rLeavingBitmap, rEnteringBitmap );
+}
+
+void OGLTransitionerImpl::disposeContextAndWindow()
+{
+#if defined( WNT )
+ if (GLWin.hRC)
+ {
+ wglMakeCurrent( GLWin.hDC, 0 ); // kill Device Context
+ wglDeleteContext( GLWin.hRC ); // Kill Render Context
+ ReleaseDC( GLWin.hWnd, GLWin.hDC ); // Release Window
+ }
+#elif defined( UNX )
+ if(GLWin.ctx)
+ {
+ glXMakeCurrent(GLWin.dpy, None, NULL);
+ if( glGetError() != GL_NO_ERROR ) {
+ OSL_TRACE("glError: %s", (char *)gluErrorString(glGetError()));
+ }
+ glXDestroyContext(GLWin.dpy, GLWin.ctx);
+ GLWin.ctx = NULL;
+ }
+#endif
+ if( pWindow ) {
+ delete pWindow;
+ pWindow = NULL;
+ GLWin.win = 0;
+ }
+}
+
+void OGLTransitionerImpl::disposeTextures()
+{
+#ifdef WNT
+ wglMakeCurrent(GLWin.hDC,GLWin.hRC);
+#endif
+#ifdef UNX
+ glXMakeCurrent( GLWin.dpy, GLWin.win, GLWin.ctx );
+#endif
+
+#if defined( GLX_VERSION_1_3 ) && defined( GLX_EXT_texture_from_pixmap )
+ unx::PFNGLXRELEASETEXIMAGEEXTPROC myglXReleaseTexImageEXT = (unx::PFNGLXRELEASETEXIMAGEEXTPROC) unx::glXGetProcAddress( (const GLubyte*) "glXReleaseTexImageEXT" );
+ if( mbUseLeavingPixmap ) {
+
+ myglXReleaseTexImageEXT( GLWin.dpy, LeavingPixmap, GLX_FRONT_LEFT_EXT );
+ glXDestroyGLXPixmap( GLWin.dpy, LeavingPixmap );
+ LeavingPixmap = 0;
+ if( mbFreeLeavingPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maLeavingPixmap );
+ mbFreeLeavingPixmap = false;
+ maLeavingPixmap = 0;
+ }
+ }
+ if( mbUseEnteringPixmap ) {
+ myglXReleaseTexImageEXT( GLWin.dpy, EnteringPixmap, GLX_FRONT_LEFT_EXT );
+ glXDestroyGLXPixmap( GLWin.dpy, EnteringPixmap );
+ EnteringPixmap = 0;
+ if( mbFreeEnteringPixmap ) {
+ unx::XFreePixmap( GLWin.dpy, maEnteringPixmap );
+ mbFreeEnteringPixmap = false;
+ maEnteringPixmap = 0;
+ }
+ }
+#endif
+
+ if( !mbUseLeavingPixmap ) {
+ glDeleteTextures(1,&GLleavingSlide);
+ GLleavingSlide = 0;
+ }
+ if( !mbUseEnteringPixmap ) {
+ glDeleteTextures(1,&GLenteringSlide);
+ GLleavingSlide = 0;
+ }
+
+ mbUseLeavingPixmap = false;
+ mbUseEnteringPixmap = false;
+}
+
+// we are about to be disposed (someone call dispose() on us)
+void OGLTransitionerImpl::disposing()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+#ifdef DEBUG
+ OSL_TRACE("dispose %p\n", this);
+ if( frame_count ) {
+ t6 = microsec_clock::local_time();
+ time_duration duration = t6 - t5;
+ OSL_TRACE("whole transition (frames: %d) took: %s fps: %f time spent in updates: %s percentage of transition time: %f%%",
+ frame_count, to_simple_string( duration ).c_str(),
+ ((double)frame_count*1000000000.0)/duration.total_nanoseconds(),
+ to_simple_string( total_update ).c_str(),
+ 100*(((double)total_update.total_nanoseconds())/((double)duration.total_nanoseconds()))
+ );
+ }
+#endif
+
+ if( pWindow ) {
+
+ disposeTextures();
+
+ if (pTransition)
+ pTransition->finish();
+
+#ifdef UNX
+ if( mbRestoreSync ) {
+ // try to reestablish synchronize state
+ char* sal_synchronize = getenv("SAL_SYNCHRONIZE");
+ XSynchronize( GLWin.dpy, sal_synchronize && *sal_synchronize == '1' );
+ }
+#endif
+
+ disposeContextAndWindow();
+ }
+
+ if (pTransition)
+ delete pTransition;
+
+ mxLeavingBitmap.clear();
+ mxEnteringBitmap.clear();
+ mxView.clear();
+}
+
+OGLTransitionerImpl::OGLTransitionerImpl(OGLTransitionImpl* pOGLTransition) :
+ OGLTransitionerImplBase(m_aMutex),
+ GLWin(),
+ GLleavingSlide( 0 ),
+ GLenteringSlide( 0 ),
+ pWindow( NULL ),
+ mxView(),
+ EnteringBytes(),
+ LeavingBytes(),
+ mbRestoreSync( false ),
+ mbUseLeavingPixmap( false ),
+ mbUseEnteringPixmap( false ),
+ SlideBitmapLayout(),
+ SlideSize(),
+ pTransition(pOGLTransition)
+{
+#if defined( WNT )
+ GLWin.hWnd = 0;
+#elif defined( UNX )
+ GLWin.ctx = 0;
+#endif
+
+ DBG(frame_count = 0);
+}
+
+typedef cppu::WeakComponentImplHelper1<presentation::XTransitionFactory> OGLTransitionFactoryImplBase;
+
+class OGLTransitionFactoryImpl : private cppu::BaseMutex, public OGLTransitionFactoryImplBase
+{
+public:
+ explicit OGLTransitionFactoryImpl( const uno::Reference< uno::XComponentContext >& ) :
+ OGLTransitionFactoryImplBase(m_aMutex)
+ {}
+
+ // XTransitionFactory
+ virtual ::sal_Bool SAL_CALL hasTransition( ::sal_Int16 transitionType, ::sal_Int16 transitionSubType ) throw (uno::RuntimeException)
+ {
+ if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) {
+ switch( transitionSubType )
+ {
+ case animations::TransitionSubType::ACROSS:
+ case animations::TransitionSubType::CORNERSOUT:
+ case animations::TransitionSubType::CIRCLE:
+ case animations::TransitionSubType::FANOUTHORIZONTAL:
+ case animations::TransitionSubType::CORNERSIN:
+ case animations::TransitionSubType::LEFTTORIGHT:
+ case animations::TransitionSubType::TOPTOBOTTOM:
+ case animations::TransitionSubType::TOPRIGHT:
+ case animations::TransitionSubType::TOPLEFT:
+ case animations::TransitionSubType::BOTTOMRIGHT:
+ case animations::TransitionSubType::BOTTOMLEFT:
+ case animations::TransitionSubType::TOPCENTER:
+ case animations::TransitionSubType::RIGHTCENTER:
+ case animations::TransitionSubType::BOTTOMCENTER:
+ return sal_True;
+
+ default:
+ return sal_False;
+ }
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) {
+ return sal_True;
+ } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) {
+ return sal_True;
+ } else
+ return sal_False;
+ }
+
+ virtual uno::Reference< presentation::XTransition > SAL_CALL createTransition(
+ ::sal_Int16 transitionType,
+ ::sal_Int16 transitionSubType,
+ const uno::Reference< presentation::XSlideShowView >& view,
+ const uno::Reference< rendering::XBitmap >& leavingBitmap,
+ const uno::Reference< rendering::XBitmap >& enteringBitmap )
+ throw (uno::RuntimeException)
+ {
+ if( !hasTransition( transitionType, transitionSubType ) )
+ return uno::Reference< presentation::XTransition >();
+
+ bool bGLXPresent = OGLTransitionerImpl::initialize( view );
+
+ if( OGLTransitionerImpl::cbMesa && (
+ ( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) ||
+ ( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) ||
+ ( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) ) )
+ return uno::Reference< presentation::XTransition >();
+
+
+ OGLTransitionImpl* pTransition = NULL;
+
+ if( transitionType == animations::TransitionType::MISCSHAPEWIPE ) {
+ pTransition = new OGLTransitionImpl();
+ switch( transitionSubType )
+ {
+ case animations::TransitionSubType::ACROSS:
+ pTransition->makeNByMTileFlip(8,6);
+ break;
+ case animations::TransitionSubType::CORNERSOUT:
+ pTransition->makeOutsideCubeFaceToLeft();
+ break;
+ case animations::TransitionSubType::CIRCLE:
+ pTransition->makeRevolvingCircles(8,128);
+ break;
+ case animations::TransitionSubType::FANOUTHORIZONTAL:
+ pTransition->makeHelix(20);
+ break;
+ case animations::TransitionSubType::CORNERSIN:
+ pTransition->makeInsideCubeFaceToLeft();
+ break;
+ case animations::TransitionSubType::LEFTTORIGHT:
+ pTransition->makeFallLeaving();
+ break;
+ case animations::TransitionSubType::TOPTOBOTTOM:
+ pTransition->makeTurnAround();
+ break;
+ case animations::TransitionSubType::TOPRIGHT:
+ pTransition->makeTurnDown();
+ break;
+ case animations::TransitionSubType::TOPLEFT:
+ pTransition->makeIris();
+ break;
+ case animations::TransitionSubType::BOTTOMRIGHT:
+ pTransition->makeRochade();
+ break;
+ case animations::TransitionSubType::BOTTOMLEFT:
+ pTransition->makeVenetianBlinds( true, 8 );
+ break;
+ case animations::TransitionSubType::TOPCENTER:
+ pTransition->makeVenetianBlinds( false, 6 );
+ break;
+ case animations::TransitionSubType::RIGHTCENTER:
+ pTransition->makeStatic();
+ break;
+ case animations::TransitionSubType::BOTTOMCENTER:
+ pTransition->makeDissolve();
+ break;
+ }
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::CROSSFADE ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeFadeSmoothly();
+ } else if( transitionType == animations::TransitionType::FADE && transitionSubType == animations::TransitionSubType::FADEOVERCOLOR ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeFadeThroughBlack();
+ } else if( transitionType == animations::TransitionType::IRISWIPE && transitionSubType == animations::TransitionSubType::DIAMOND ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeDiamond();
+ } else if( transitionType == animations::TransitionType::ZOOM && transitionSubType == animations::TransitionSubType::ROTATEIN ) {
+ pTransition = new OGLTransitionImpl();
+ pTransition->makeNewsflash();
+ }
+
+ rtl::Reference<OGLTransitionerImpl> xRes(
+ new OGLTransitionerImpl(pTransition) );
+ if( bGLXPresent ) {
+ if( !xRes->initWindowFromSlideShowView(view))
+ return uno::Reference< presentation::XTransition >();
+ xRes->setSlides(leavingBitmap,enteringBitmap);
+ }
+
+ return uno::Reference<presentation::XTransition>(xRes.get());
+ }
+};
+
+}
+
+namespace sdecl = comphelper::service_decl;
+#if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)
+ sdecl::class_<OGLTransitionFactoryImpl> serviceImpl;
+ const sdecl::ServiceDecl OGLTransitionFactoryDecl(
+ serviceImpl,
+#else
+ const sdecl::ServiceDecl OGLTransitionFactoryDecl(
+ sdecl::class_<OGLTransitionFactoryImpl>(),
+#endif
+ "com.sun.star.comp.presentation.OGLTransitionFactory",
+ "com.sun.star.presentation.TransitionFactory" );
+
+// The C shared lib entry points
+COMPHELPER_SERVICEDECL_EXPORTS1(OGLTransitionFactoryDecl)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/OGLTrans/win/makefile.mk b/slideshow/source/engine/OGLTrans/win/makefile.mk
new file mode 100644
index 000000000000..7da37872368d
--- /dev/null
+++ b/slideshow/source/engine/OGLTrans/win/makefile.mk
@@ -0,0 +1,80 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..$/..
+
+PRJNAME=slideshow
+TARGET=OGLTrans
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Nothing to do if we're compiling with --disable-opengl -----------
+.IF "$(ENABLE_OPENGL)" != "TRUE" || "$(OS)" != "WNT"
+@all:
+ @echo "Building without OpenGL Transitions..."
+.ENDIF
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/OGLTrans_TransitionImpl.obj \
+ $(SLO)$/OGLTrans_Shaders.obj \
+ $(SLO)$/OGLTrans_TransitionerImpl.obj
+
+SHL1TARGET=$(TARGET).uno
+
+SHL1STDLIBS= $(SALLIB) $(VCLLIB) $(CPPULIB) $(CPPUHELPERLIB) $(COMPHELPERLIB) $(CANVASTOOLSLIB)
+
+SHL1STDLIBS += \
+ opengl32.lib \
+ glu32.lib \
+ gdi32.lib
+
+SHL1IMPLIB=i$(TARGET)
+SHL1LIBS=$(SLB)$/$(TARGET).lib
+SHL1DEF=$(MISC)$/$(SHL1TARGET).def
+
+SHL1VERSIONMAP=../exports.map
+
+DEF1NAME=$(SHL1TARGET)
+DEF1EXPORTFILE=../exports.dxp
+
+# ==========================================================================
+
+.INCLUDE : target.mk
+
+ALLTAR : $(MISC)/ogltrans.component
+
+$(MISC)/ogltrans.component .ERRREMOVE : $(SOLARENV)/bin/createcomponent.xslt \
+ ogltrans.component
+ $(XSLTPROC) --nonet --stringparam uri \
+ '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \
+ $(SOLARENV)/bin/createcomponent.xslt ogltrans.component
diff --git a/slideshow/source/engine/activities/accumulation.hxx b/slideshow/source/engine/activities/accumulation.hxx
new file mode 100644
index 000000000000..d901b54ecc3d
--- /dev/null
+++ b/slideshow/source/engine/activities/accumulation.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_ACCUMULATION_HXX
+#define INCLUDED_SLIDESHOW_ACCUMULATION_HXX
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Generic accumulation.
+
+ This template handles value accumulation across repeated
+ effect runs: returned is the end value times the repeat
+ count, plus the current value.
+
+ @param rEndValue
+ End value of the simple animation.
+
+ @param nRepeatCount
+ Number of completed repeats (i.e. 0 during the first
+ effect run)
+
+ @param rCurrValue
+ Current animation value
+ */
+ template< typename ValueType > ValueType accumulate( const ValueType& rEndValue,
+ sal_uInt32 nRepeatCount,
+ const ValueType& rCurrValue )
+ {
+ return nRepeatCount*rEndValue + rCurrValue;
+ }
+
+ /// Specialization for non-addable enums/constant values
+ template<> sal_Int16 accumulate< sal_Int16 >( const sal_Int16&,
+ sal_uInt32,
+ const sal_Int16& rCurrValue )
+ {
+ // always return rCurrValue, it's forbidden to add enums/constant values...
+ return rCurrValue;
+ }
+
+ /// Specialization for non-addable strings
+ template<> ::rtl::OUString accumulate< ::rtl::OUString >( const ::rtl::OUString&,
+ sal_uInt32,
+ const ::rtl::OUString& rCurrValue )
+ {
+ // always return rCurrValue, it's impossible to add strings...
+ return rCurrValue;
+ }
+
+ /// Specialization for non-addable bools
+ template<> bool accumulate< bool >( const bool&,
+ sal_uInt32,
+ const bool& bCurrValue )
+ {
+ // always return bCurrValue, SMIL spec requires to ignore
+ // cumulative behaviour for bools.
+ return bCurrValue;
+ }
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_ACCUMULATION_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/activitiesfactory.cxx b/slideshow/source/engine/activities/activitiesfactory.cxx
new file mode 100644
index 000000000000..c29a385855ce
--- /dev/null
+++ b/slideshow/source/engine/activities/activitiesfactory.cxx
@@ -0,0 +1,988 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <comphelper/sequence.hxx>
+
+#include "activitiesfactory.hxx"
+#include "smilfunctionparser.hxx"
+#include "accumulation.hxx"
+#include "activityparameters.hxx"
+#include "interpolation.hxx"
+#include "tools.hxx"
+#include "simplecontinuousactivitybase.hxx"
+#include "discreteactivitybase.hxx"
+#include "continuousactivitybase.hxx"
+#include "continuouskeytimeactivitybase.hxx"
+
+#include <boost/bind.hpp>
+#include <boost/optional.hpp>
+
+#include <cmath> // for modf
+#include <vector>
+#include <algorithm>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+/** Traits template, to take formula application only for ValueType = double
+ */
+template<typename ValueType> struct FormulaTraits
+{
+ static ValueType getPresentationValue(
+ const ValueType& rVal, const ExpressionNodeSharedPtr& )
+ {
+ return rVal;
+ }
+};
+
+/// Specialization for ValueType = double
+template<> struct FormulaTraits<double>
+{
+ static double getPresentationValue(
+ double const& rVal, ExpressionNodeSharedPtr const& rFormula )
+ {
+ return rFormula ? (*rFormula)(rVal) : rVal;
+ }
+};
+
+// Various ActivityBase specializations for different animator types
+// =================================================================
+
+/** FromToBy handler
+
+ Provides the Activity specializations for FromToBy
+ animations (e.g. those without a values list).
+
+ This template makes heavy use of SFINAE, only one of
+ the perform*() methods will compile for each of the
+ base classes.
+
+ Note that we omit the virtual keyword on the perform()
+ overrides on purpose; those that actually do override
+ baseclass virtual methods inherit the property, and
+ the others won't increase our vtable. What's more,
+ having all perform() method in the vtable actually
+ creates POIs for them, which breaks the whole SFINAE
+ concept (IOW, this template won't compile any longer).
+
+ @tpl BaseType
+ Base class to use for this activity. Only
+ ContinuousActivityBase and DiscreteActivityBase are
+ supported here.
+
+ @tpl AnimationType
+ Type of the Animation to call.
+*/
+template<class BaseType, typename AnimationType>
+class FromToByActivity : public BaseType
+{
+public:
+ typedef typename AnimationType::ValueType ValueType;
+ typedef boost::optional<ValueType> OptionalValueType;
+
+private:
+ // some compilers don't inline whose definition they haven't
+ // seen before the call site...
+ ValueType getPresentationValue( const ValueType& rVal ) const
+ {
+ return FormulaTraits<ValueType>::getPresentationValue( rVal, mpFormula);
+ }
+
+public:
+ /** Create FromToByActivity.
+
+ @param rFrom
+ From this value, the animation starts
+
+ @param rTo
+ With this value, the animation ends
+
+ @param rBy
+ With this value, the animation increments the start value
+
+ @param rParms
+ Standard Activity parameter struct
+
+ @param rAnim
+ Shared ptr to AnimationType
+
+ @param rInterpolator
+ Interpolator object to be used for lerping between
+ start and end value (need to be passed, since it
+ might contain state, e.g. interpolation direction
+ for HSL color space).
+
+ @param bCumulative
+ Whether repeated animations should cumulate the
+ value, or start fresh each time.
+ */
+ FromToByActivity(
+ const OptionalValueType& rFrom,
+ const OptionalValueType& rTo,
+ const OptionalValueType& rBy,
+ const ActivityParameters& rParms,
+ const ::boost::shared_ptr< AnimationType >& rAnim,
+ const Interpolator< ValueType >& rInterpolator,
+ bool bCumulative )
+ : BaseType( rParms ),
+ maFrom( rFrom ),
+ maTo( rTo ),
+ maBy( rBy ),
+ mpFormula( rParms.mpFormula ),
+ maStartValue(),
+ maEndValue(),
+ mpAnim( rAnim ),
+ maInterpolator( rInterpolator ),
+ mbDynamicStartValue( false ),
+ mbCumulative( bCumulative )
+ {
+ ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
+
+ ENSURE_OR_THROW(
+ rTo || rBy,
+ "From and one of To or By, or To or By alone must be valid" );
+ }
+
+ virtual void startAnimation()
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ BaseType::startAnimation();
+
+ // start animation
+ mpAnim->start( BaseType::getShape(),
+ BaseType::getShapeAttributeLayer() );
+
+ // setup start and end value. Determine animation
+ // start value only when animation actually
+ // started up (this order is part of the Animation
+ // interface contract)
+ const ValueType aAnimationStartValue( mpAnim->getUnderlyingValue() );
+
+ // first of all, determine general type of
+ // animation, by inspecting which of the FromToBy values
+ // are actually valid.
+ // See http://www.w3.org/TR/smil20/animation.html#AnimationNS-FromToBy
+ // for a definition
+ if( maFrom )
+ {
+ // From-to or From-by animation. According to
+ // SMIL spec, the To value takes precedence
+ // over the By value, if both are specified
+ if( maTo )
+ {
+ // From-To animation
+ maStartValue = *maFrom;
+ maEndValue = *maTo;
+ }
+ else if( maBy )
+ {
+ // From-By animation
+ maStartValue = *maFrom;
+ maEndValue = maStartValue + *maBy;
+ }
+ }
+ else
+ {
+ // By or To animation. According to SMIL spec,
+ // the To value takes precedence over the By
+ // value, if both are specified
+ if( maTo )
+ {
+ // To animation
+
+ // According to the SMIL spec
+ // (http://www.w3.org/TR/smil20/animation.html#animationNS-ToAnimation),
+ // the to animation interpolates between
+ // the _running_ underlying value and the to value (as the end value)
+ mbDynamicStartValue = true;
+ maEndValue = *maTo;
+ }
+ else if( maBy )
+ {
+ // By animation
+ maStartValue = aAnimationStartValue;
+ maEndValue = maStartValue + *maBy;
+ }
+ }
+ }
+
+ virtual void endAnimation()
+ {
+ // end animation
+ if (mpAnim)
+ mpAnim->end();
+ }
+
+ /// perform override for ContinuousActivityBase
+ void perform( double nModifiedTime, sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ (*mpAnim)(
+ getPresentationValue(
+ accumulate( maEndValue,
+ mbCumulative * nRepeatCount, // means: mbCumulative ? nRepeatCount : 0,
+ maInterpolator( (mbDynamicStartValue
+ ? mpAnim->getUnderlyingValue()
+ : maStartValue),
+ maEndValue,
+ nModifiedTime ) ) ) );
+ }
+
+ using BaseType::perform;
+
+ /// perform override for DiscreteActivityBase base
+ void perform( sal_uInt32 nFrame, sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ (*mpAnim)(
+ getPresentationValue(
+ accumulate( maEndValue, mbCumulative ? nRepeatCount : 0,
+ lerp( maInterpolator,
+ (mbDynamicStartValue
+ ? mpAnim->getUnderlyingValue()
+ : maStartValue),
+ maEndValue,
+ nFrame,
+ BaseType::getNumberOfKeyTimes() ) ) ) );
+ }
+
+ using BaseType::isAutoReverse;
+
+ virtual void performEnd()
+ {
+ // xxx todo: good guess
+ if (mpAnim)
+ {
+ if (isAutoReverse())
+ (*mpAnim)( getPresentationValue( maStartValue ) );
+ else
+ (*mpAnim)( getPresentationValue( maEndValue ) );
+ }
+ }
+
+ /// Disposable:
+ virtual void dispose()
+ {
+ mpAnim.reset();
+ BaseType::dispose();
+ }
+
+private:
+ const OptionalValueType maFrom;
+ const OptionalValueType maTo;
+ const OptionalValueType maBy;
+
+ ExpressionNodeSharedPtr mpFormula;
+
+ ValueType maStartValue;
+ ValueType maEndValue;
+
+ ::boost::shared_ptr< AnimationType > mpAnim;
+ Interpolator< ValueType > maInterpolator;
+ bool mbDynamicStartValue;
+ bool mbCumulative;
+};
+
+
+/** Generate Activity corresponding to given FromToBy values
+
+ @tpl BaseType
+ BaseType to use for deriving the Activity from
+
+ @tpl AnimationType
+ Subtype of the Animation object (e.g. NumberAnimation)
+*/
+template<class BaseType, typename AnimationType>
+AnimationActivitySharedPtr createFromToByActivity(
+ const uno::Any& rFromAny,
+ const uno::Any& rToAny,
+ const uno::Any& rByAny,
+ const ActivityParameters& rParms,
+ const ::boost::shared_ptr< AnimationType >& rAnim,
+ const Interpolator< typename AnimationType::ValueType >& rInterpolator,
+ bool bCumulative,
+ const ShapeSharedPtr& rShape,
+ const ::basegfx::B2DVector& rSlideBounds )
+{
+ typedef typename AnimationType::ValueType ValueType;
+ typedef boost::optional<ValueType> OptionalValueType;
+
+ OptionalValueType aFrom;
+ OptionalValueType aTo;
+ OptionalValueType aBy;
+
+ ValueType aTmpValue;
+
+ if( rFromAny.hasValue() )
+ {
+ ENSURE_OR_THROW(
+ extractValue( aTmpValue, rFromAny, rShape, rSlideBounds ),
+ "createFromToByActivity(): Could not extract from value" );
+ aFrom.reset(aTmpValue);
+ }
+ if( rToAny.hasValue() )
+ {
+ ENSURE_OR_THROW(
+ extractValue( aTmpValue, rToAny, rShape, rSlideBounds ),
+ "createFromToByActivity(): Could not extract to value" );
+ aTo.reset(aTmpValue);
+ }
+ if( rByAny.hasValue() )
+ {
+ ENSURE_OR_THROW(
+ extractValue( aTmpValue, rByAny, rShape, rSlideBounds ),
+ "createFromToByActivity(): Could not extract by value" );
+ aBy.reset(aTmpValue);
+ }
+
+ return AnimationActivitySharedPtr(
+ new FromToByActivity<BaseType, AnimationType>(
+ aFrom,
+ aTo,
+ aBy,
+ rParms,
+ rAnim,
+ rInterpolator,
+ bCumulative ) );
+}
+
+/* The following table shows which animator combines with
+ which Activity type:
+
+ NumberAnimator: all
+ PairAnimation: all
+ ColorAnimation: all
+ StringAnimation: DiscreteActivityBase
+ BoolAnimation: DiscreteActivityBase
+*/
+
+/** Values handler
+
+ Provides the Activity specializations for value lists
+ animations.
+
+ This template makes heavy use of SFINAE, only one of
+ the perform*() methods will compile for each of the
+ base classes.
+
+ Note that we omit the virtual keyword on the perform()
+ overrides on purpose; those that actually do override
+ baseclass virtual methods inherit the property, and
+ the others won't increase our vtable. What's more,
+ having all perform() method in the vtable actually
+ creates POIs for them, which breaks the whole SFINAE
+ concept (IOW, this template won't compile any longer).
+
+ @tpl BaseType
+ Base class to use for this activity. Only
+ ContinuousKeyTimeActivityBase and DiscreteActivityBase
+ are supported here. For values animation without key
+ times, the client must emulate key times by providing
+ a vector of equally spaced values between 0 and 1,
+ with the same number of entries as the values vector.
+
+ @tpl AnimationType
+ Type of the Animation to call.
+*/
+template<class BaseType, typename AnimationType>
+class ValuesActivity : public BaseType
+{
+public:
+ typedef typename AnimationType::ValueType ValueType;
+ typedef std::vector<ValueType> ValueVectorType;
+
+private:
+ // some compilers don't inline methods whose definition they haven't
+ // seen before the call site...
+ ValueType getPresentationValue( const ValueType& rVal ) const
+ {
+ return FormulaTraits<ValueType>::getPresentationValue(
+ rVal, mpFormula );
+ }
+
+public:
+ /** Create ValuesActivity.
+
+ @param rValues
+ Value vector to cycle animation through
+
+ @param rParms
+ Standard Activity parameter struct
+
+ @param rAnim
+ Shared ptr to AnimationType
+
+ @param rInterpolator
+ Interpolator object to be used for lerping between
+ start and end value (need to be passed, since it
+ might contain state, e.g. interpolation direction
+ for HSL color space).
+
+ @param bCumulative
+ Whether repeated animations should cumulate the
+ value, or start afresh each time.
+ */
+ ValuesActivity(
+ const ValueVectorType& rValues,
+ const ActivityParameters& rParms,
+ const boost::shared_ptr<AnimationType>& rAnim,
+ const Interpolator< ValueType >& rInterpolator,
+ bool bCumulative )
+ : BaseType( rParms ),
+ maValues( rValues ),
+ mpFormula( rParms.mpFormula ),
+ mpAnim( rAnim ),
+ maInterpolator( rInterpolator ),
+ mbCumulative( bCumulative )
+ {
+ ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
+ ENSURE_OR_THROW( !rValues.empty(), "Empty value vector" );
+ }
+
+ virtual void startAnimation()
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ BaseType::startAnimation();
+
+ // start animation
+ mpAnim->start( BaseType::getShape(),
+ BaseType::getShapeAttributeLayer() );
+ }
+
+ virtual void endAnimation()
+ {
+ // end animation
+ if (mpAnim)
+ mpAnim->end();
+ }
+
+ /// perform override for ContinuousKeyTimeActivityBase base
+ void perform( sal_uInt32 nIndex,
+ double nFractionalIndex,
+ sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ ENSURE_OR_THROW( nIndex+1 < maValues.size(),
+ "ValuesActivity::perform(): index out of range" );
+
+ // interpolate between nIndex and nIndex+1 values
+ (*mpAnim)(
+ getPresentationValue(
+ accumulate( maValues.back(),
+ mbCumulative ? nRepeatCount : 0,
+ maInterpolator( maValues[ nIndex ],
+ maValues[ nIndex+1 ],
+ nFractionalIndex ) ) ) );
+ }
+
+ using BaseType::perform;
+
+ /// perform override for DiscreteActivityBase base
+ void perform( sal_uInt32 nFrame, sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ ENSURE_OR_THROW( nFrame < maValues.size(),
+ "ValuesActivity::perform(): index out of range" );
+
+ // this is discrete, thus no lerp here.
+ (*mpAnim)(
+ getPresentationValue(
+ accumulate( maValues.back(),
+ mbCumulative ? nRepeatCount : 0,
+ maValues[ nFrame ] ) ) );
+ }
+
+ virtual void performEnd()
+ {
+ // xxx todo: good guess
+ if (mpAnim)
+ (*mpAnim)( getPresentationValue( maValues.back() ) );
+ }
+
+ /// Disposable:
+ virtual void dispose()
+ {
+ mpAnim.reset();
+ BaseType::dispose();
+ }
+
+private:
+ ValueVectorType maValues;
+
+ ExpressionNodeSharedPtr mpFormula;
+
+ boost::shared_ptr<AnimationType> mpAnim;
+ Interpolator< ValueType > maInterpolator;
+ bool mbCumulative;
+};
+
+/** Generate Activity corresponding to given Value vector
+
+ @tpl BaseType
+ BaseType to use for deriving the Activity from
+
+ @tpl AnimationType
+ Subtype of the Animation object (e.g. NumberAnimation)
+*/
+template<class BaseType, typename AnimationType>
+AnimationActivitySharedPtr createValueListActivity(
+ const uno::Sequence<uno::Any>& rValues,
+ const ActivityParameters& rParms,
+ const boost::shared_ptr<AnimationType>& rAnim,
+ const Interpolator<typename AnimationType::ValueType>& rInterpolator,
+ bool bCumulative,
+ const ShapeSharedPtr& rShape,
+ const ::basegfx::B2DVector& rSlideBounds )
+{
+ typedef typename AnimationType::ValueType ValueType;
+ typedef std::vector<ValueType> ValueVectorType;
+
+ ValueVectorType aValueVector;
+ aValueVector.reserve( rValues.getLength() );
+
+ for( ::std::size_t i=0, nLen=rValues.getLength(); i<nLen; ++i )
+ {
+ ValueType aValue;
+ ENSURE_OR_THROW(
+ extractValue( aValue, rValues[i], rShape, rSlideBounds ),
+ "createValueListActivity(): Could not extract values" );
+ aValueVector.push_back( aValue );
+ }
+
+ return AnimationActivitySharedPtr(
+ new ValuesActivity<BaseType, AnimationType>(
+ aValueVector,
+ rParms,
+ rAnim,
+ rInterpolator,
+ bCumulative ) );
+}
+
+/** Generate Activity for given XAnimate, corresponding to given Value vector
+
+ @tpl AnimationType
+ Subtype of the Animation object (e.g. NumberAnimation)
+
+ @param rParms
+ Common activity parameters
+
+ @param xNode
+ XAnimate node, to retrieve animation values from
+
+ @param rAnim
+ Actual animation to operate with (gets called with the
+ time-dependent values)
+
+ @param rInterpolator
+ Interpolator object to be used for lerping between
+ start and end values (need to be passed, since it
+ might contain state, e.g. interpolation direction
+ for HSL color space).
+*/
+template<typename AnimationType>
+AnimationActivitySharedPtr createActivity(
+ const ActivitiesFactory::CommonParameters& rParms,
+ const uno::Reference< animations::XAnimate >& xNode,
+ const ::boost::shared_ptr< AnimationType >& rAnim,
+ const Interpolator< typename AnimationType::ValueType >& rInterpolator
+ = Interpolator< typename AnimationType::ValueType >() )
+{
+ // setup common parameters
+ // =======================
+
+ ActivityParameters aActivityParms( rParms.mpEndEvent,
+ rParms.mrEventQueue,
+ rParms.mrActivitiesQueue,
+ rParms.mnMinDuration,
+ rParms.maRepeats,
+ rParms.mnAcceleration,
+ rParms.mnDeceleration,
+ rParms.mnMinNumberOfFrames,
+ rParms.mbAutoReverse );
+
+ // is a formula given?
+ const ::rtl::OUString& rFormulaString( xNode->getFormula() );
+ if( rFormulaString.getLength() )
+ {
+ // yep, parse and pass to ActivityParameters
+ try
+ {
+ aActivityParms.mpFormula =
+ SmilFunctionParser::parseSmilFunction(
+ rFormulaString,
+ calcRelativeShapeBounds(
+ rParms.maSlideBounds,
+ rParms.mpShape->getBounds() ) );
+ }
+ catch( ParseError& )
+ {
+ // parse error, thus no formula
+ OSL_FAIL( "createActivity(): Error parsing formula string" );
+ }
+ }
+
+ // are key times given?
+ const uno::Sequence< double >& aKeyTimes( xNode->getKeyTimes() );
+ if( aKeyTimes.hasElements() )
+ {
+ // yes, convert them from Sequence< double >
+ aActivityParms.maDiscreteTimes.resize( aKeyTimes.getLength() );
+ comphelper::sequenceToArray(
+ &aActivityParms.maDiscreteTimes[0],
+ aKeyTimes ); // saves us some temporary vectors
+ }
+
+ // values sequence given?
+ const sal_Int32 nValueLen( xNode->getValues().getLength() );
+ if( nValueLen )
+ {
+ // Value list activity
+ // ===================
+
+ // fake keytimes, if necessary
+ if( !aKeyTimes.hasElements() )
+ {
+ // create a dummy vector of key times,
+ // with aValues.getLength equally spaced entries.
+ for( sal_Int32 i=0; i<nValueLen; ++i )
+ aActivityParms.maDiscreteTimes.push_back( double(i)/nValueLen );
+ }
+
+ // determine type of animation needed here:
+ // Value list activities are possible with
+ // ContinuousKeyTimeActivityBase and DiscreteActivityBase
+ // specializations
+ const sal_Int16 nCalcMode( xNode->getCalcMode() );
+
+ switch( nCalcMode )
+ {
+ case animations::AnimationCalcMode::DISCRETE:
+ {
+ // since DiscreteActivityBase suspends itself
+ // between the frames, create a WakeupEvent for it.
+ aActivityParms.mpWakeupEvent.reset(
+ new WakeupEvent(
+ rParms.mrEventQueue.getTimer(),
+ rParms.mrActivitiesQueue ) );
+
+ AnimationActivitySharedPtr pActivity(
+ createValueListActivity< DiscreteActivityBase >(
+ xNode->getValues(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds ) );
+
+ // WakeupEvent and DiscreteActivityBase need circular
+ // references to the corresponding other object.
+ aActivityParms.mpWakeupEvent->setActivity( pActivity );
+
+ return pActivity;
+ }
+
+ default:
+ OSL_FAIL( "createActivity(): unexpected case" );
+ // FALLTHROUGH intended
+ case animations::AnimationCalcMode::PACED:
+ // FALLTHROUGH intended
+ case animations::AnimationCalcMode::SPLINE:
+ // FALLTHROUGH intended
+ case animations::AnimationCalcMode::LINEAR:
+ return createValueListActivity< ContinuousKeyTimeActivityBase >(
+ xNode->getValues(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds );
+ }
+ }
+ else
+ {
+ // FromToBy activity
+ // =================
+
+ // determine type of animation needed here:
+ // FromToBy activities are possible with
+ // ContinuousActivityBase and DiscreteActivityBase
+ // specializations
+ const sal_Int16 nCalcMode( xNode->getCalcMode() );
+
+ switch( nCalcMode )
+ {
+ case animations::AnimationCalcMode::DISCRETE:
+ {
+ // fake keytimes, if necessary
+ if( !aKeyTimes.hasElements() )
+ {
+ // create a dummy vector of 2 key times
+ const ::std::size_t nLen( 2 );
+ for( ::std::size_t i=0; i<nLen; ++i )
+ aActivityParms.maDiscreteTimes.push_back( double(i)/nLen );
+ }
+
+ // since DiscreteActivityBase suspends itself
+ // between the frames, create a WakeupEvent for it.
+ aActivityParms.mpWakeupEvent.reset(
+ new WakeupEvent(
+ rParms.mrEventQueue.getTimer(),
+ rParms.mrActivitiesQueue ) );
+
+ AnimationActivitySharedPtr pActivity(
+ createFromToByActivity< DiscreteActivityBase >(
+ xNode->getFrom(),
+ xNode->getTo(),
+ xNode->getBy(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds ) );
+
+ // WakeupEvent and DiscreteActivityBase need circular
+ // references to the corresponding other object.
+ aActivityParms.mpWakeupEvent->setActivity( pActivity );
+
+ return pActivity;
+ }
+
+ default:
+ OSL_FAIL( "createActivity(): unexpected case" );
+ // FALLTHROUGH intended
+ case animations::AnimationCalcMode::PACED:
+ // FALLTHROUGH intended
+ case animations::AnimationCalcMode::SPLINE:
+ // FALLTHROUGH intended
+ case animations::AnimationCalcMode::LINEAR:
+ return createFromToByActivity< ContinuousActivityBase >(
+ xNode->getFrom(),
+ xNode->getTo(),
+ xNode->getBy(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds );
+ }
+ }
+}
+
+/** Simple activity for ActivitiesFactory::createSimpleActivity
+
+ @tpl Direction
+ Determines direction of value generator. A 1 yields a
+ forward direction, starting with 0.0 and ending with
+ 1.0. A 0 yields a backward direction, starting with
+ 1.0 and ending with 0.0
+*/
+template<int Direction>
+class SimpleActivity : public ContinuousActivityBase
+{
+public:
+ /** Create SimpleActivity.
+
+ @param rParms
+ Standard Activity parameter struct
+ */
+ SimpleActivity( const ActivityParameters& rParms,
+ const NumberAnimationSharedPtr& rAnim ) :
+ ContinuousActivityBase( rParms ),
+ mpAnim( rAnim )
+ {
+ ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
+ }
+
+ virtual void startAnimation()
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ ContinuousActivityBase::startAnimation();
+
+ // start animation
+ mpAnim->start( getShape(),
+ getShapeAttributeLayer() );
+ }
+
+ virtual void endAnimation()
+ {
+ // end animation
+ if (mpAnim)
+ mpAnim->end();
+ }
+
+ using SimpleContinuousActivityBase::perform;
+
+ /// perform override for ContinuousActivityBase
+ virtual void perform( double nModifiedTime, sal_uInt32 ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ // no cumulation, simple [0,1] range
+ (*mpAnim)( 1.0 - Direction + nModifiedTime*(2.0*Direction - 1.0) );
+ }
+
+ virtual void performEnd()
+ {
+ // xxx todo: review
+ if (mpAnim)
+ (*mpAnim)( 1.0*Direction );
+ }
+
+ /// Disposable:
+ virtual void dispose()
+ {
+ mpAnim.reset();
+ ContinuousActivityBase::dispose();
+ }
+
+private:
+ NumberAnimationSharedPtr mpAnim;
+};
+
+} // anon namespace
+
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const NumberAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const EnumAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const ColorAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const HSLColorAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimateColor >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms,
+ uno::Reference< animations::XAnimate >(
+ xNode, uno::UNO_QUERY_THROW ),
+ rAnim,
+ // Direction==true means clockwise in SMIL API
+ Interpolator< HSLColor >( !xNode->getDirection() ) );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const PairAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const StringAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const BoolAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createSimpleActivity(
+ const CommonParameters& rParms,
+ const NumberAnimationSharedPtr& rAnim,
+ bool bDirectionForward )
+{
+ ActivityParameters aActivityParms( rParms.mpEndEvent,
+ rParms.mrEventQueue,
+ rParms.mrActivitiesQueue,
+ rParms.mnMinDuration,
+ rParms.maRepeats,
+ rParms.mnAcceleration,
+ rParms.mnDeceleration,
+ rParms.mnMinNumberOfFrames,
+ rParms.mbAutoReverse );
+
+ if( bDirectionForward )
+ return AnimationActivitySharedPtr(
+ new SimpleActivity<1>( aActivityParms, rAnim ) );
+ else
+ return AnimationActivitySharedPtr(
+ new SimpleActivity<0>( aActivityParms, rAnim ) );
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/activitybase.cxx b/slideshow/source/engine/activities/activitybase.cxx
new file mode 100644
index 000000000000..212ab1d95294
--- /dev/null
+++ b/slideshow/source/engine/activities/activitybase.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <activitybase.hxx>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ // TODO(P1): Elide some virtual function calls, by templifying this
+ // static hierarchy
+
+ ActivityBase::ActivityBase( const ActivityParameters& rParms ) :
+ mpEndEvent( rParms.mrEndEvent ),
+ mrEventQueue( rParms.mrEventQueue ),
+ mpShape(),
+ mpAttributeLayer(),
+ maRepeats( rParms.mrRepeats ),
+ mnAccelerationFraction( rParms.mnAccelerationFraction ),
+ mnDecelerationFraction( rParms.mnDecelerationFraction ),
+ mbAutoReverse( rParms.mbAutoReverse ),
+ mbFirstPerformCall( true ),
+ mbIsActive( true ) {}
+
+ void ActivityBase::dispose()
+ {
+ // deactivate
+ mbIsActive = false;
+
+ // dispose event
+ if( mpEndEvent )
+ mpEndEvent->dispose();
+
+ // release references
+ mpEndEvent.reset();
+ mpShape.reset();
+ mpAttributeLayer.reset();
+ }
+
+ double ActivityBase::calcTimeLag() const
+ {
+ // TODO(Q1): implement different init process!
+ if (isActive() && mbFirstPerformCall)
+ {
+ mbFirstPerformCall = false;
+
+ // notify derived classes that we're
+ // starting now
+ const_cast<ActivityBase *>(this)->startAnimation();
+ }
+ return 0.0;
+ }
+
+ bool ActivityBase::perform()
+ {
+ // still active?
+ if( !isActive() )
+ return false; // no, early exit.
+
+ OSL_ASSERT( ! mbFirstPerformCall );
+
+ return true;
+ }
+
+ bool ActivityBase::isActive() const
+ {
+ return mbIsActive;
+ }
+
+ void ActivityBase::setTargets( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer )
+ {
+ ENSURE_OR_THROW( rShape,
+ "ActivityBase::setTargets(): Invalid shape" );
+ ENSURE_OR_THROW( rAttrLayer,
+ "ActivityBase::setTargets(): Invalid attribute layer" );
+
+ mpShape = rShape;
+ mpAttributeLayer = rAttrLayer;
+ }
+
+ void ActivityBase::endActivity()
+ {
+ // this is a regular activity end
+ mbIsActive = false;
+
+ // Activity is ending, queue event, then
+ if( mpEndEvent )
+ mrEventQueue.addEvent( mpEndEvent );
+
+ // release references
+ mpEndEvent.reset();
+ }
+
+ void ActivityBase::dequeued()
+ {
+ // xxx todo:
+// // ignored here, if we're still active. Discrete
+// // activities are dequeued after every perform() call,
+// // thus, the call is only significant when isActive() ==
+// // false.
+ if( !isActive() )
+ endAnimation();
+ }
+
+ void ActivityBase::end()
+ {
+ if (!isActive() || isDisposed())
+ return;
+ // assure animation is started:
+ if (mbFirstPerformCall) {
+ mbFirstPerformCall = false;
+ // notify derived classes that we're starting now
+ this->startAnimation();
+ }
+
+ performEnd(); // calling private virtual
+ endAnimation();
+ endActivity();
+ }
+
+ double ActivityBase::calcAcceleratedTime( double nT ) const
+ {
+ // Handle acceleration/deceleration
+ // ================================
+
+ // clamp nT to permissible [0,1] range
+ nT = ::basegfx::clamp( nT, 0.0, 1.0 );
+
+ // take acceleration/deceleration into account. if the sum
+ // of mnAccelerationFraction and mnDecelerationFraction
+ // exceeds 1.0, ignore both (that's according to SMIL spec)
+ if( (mnAccelerationFraction > 0.0 ||
+ mnDecelerationFraction > 0.0) &&
+ mnAccelerationFraction + mnDecelerationFraction <= 1.0 )
+ {
+ /*
+ // calc accelerated/decelerated time.
+ //
+ // We have three intervals:
+ // 1 [0,a]
+ // 2 [a,d]
+ // 3 [d,1] (with a and d being acceleration/deceleration
+ // fraction, resp.)
+ //
+ // The change rate during interval 1 is constantly
+ // increasing, reaching 1 at a. It then stays at 1,
+ // starting a linear decrease at d, ending with 0 at
+ // time 1. The integral of this function is the
+ // required new time nT'.
+ //
+ // As we arbitrarily assumed 1 as the upper value of
+ // the change rate, the integral must be normalized to
+ // reach nT'=1 at the end of the interval. This
+ // normalization constant is:
+ //
+ // c = 1 - 0.5a - 0.5d
+ //
+ // The integral itself then amounts to:
+ //
+ // 0.5 nT^2 / a + (nT-a) + (nT - 0.5 nT^2 / d)
+ //
+ // (where each of the three summands correspond to the
+ // three intervals above, and are applied only if nT
+ // has reached the corresponding interval)
+ //
+ // The graph of the change rate is a trapezoid:
+ //
+ // |
+ // 1| /--------------\
+ // | / \
+ // | / \
+ // | / \
+ // -----------------------------
+ // 0 a d 1
+ //
+ //*/
+ const double nC( 1.0 - 0.5*mnAccelerationFraction - 0.5*mnDecelerationFraction );
+
+ // this variable accumulates the new time value
+ double nTPrime(0.0);
+
+ if( nT < mnAccelerationFraction )
+ {
+ nTPrime += 0.5*nT*nT/mnAccelerationFraction; // partial first interval
+ }
+ else
+ {
+ nTPrime += 0.5*mnAccelerationFraction; // full first interval
+
+ if( nT <= 1.0-mnDecelerationFraction )
+ {
+ nTPrime += nT-mnAccelerationFraction; // partial second interval
+ }
+ else
+ {
+ nTPrime += 1.0 - mnAccelerationFraction - mnDecelerationFraction; // full second interval
+
+ const double nTRelative( nT - 1.0 + mnDecelerationFraction );
+
+ nTPrime += nTRelative - 0.5*nTRelative*nTRelative / mnDecelerationFraction;
+ }
+ }
+
+ // normalize, and assign to work variable
+ nT = nTPrime / nC;
+ }
+
+ return nT;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/activitybase.hxx b/slideshow/source/engine/activities/activitybase.hxx
new file mode 100644
index 000000000000..e74a3e5ad7de
--- /dev/null
+++ b/slideshow/source/engine/activities/activitybase.hxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_ACTIVITYBASE_HXX
+#define INCLUDED_SLIDESHOW_ACTIVITYBASE_HXX
+
+#include "animationactivity.hxx"
+#include "activityparameters.hxx"
+#include "animatableshape.hxx"
+#include "shapeattributelayer.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** Base class for animation activities.
+
+ This whole class hierarchy is only for code sharing
+ between the various specializations (with or without
+ key times, fully discrete, etc.).
+*/
+class ActivityBase : public AnimationActivity
+{
+public:
+ ActivityBase( const ActivityParameters& rParms );
+
+ /// From Disposable interface
+ virtual void dispose();
+
+protected:
+ /** From Activity interface
+
+ Derived classes should override, call this first
+ and then perform their work.
+ */
+ virtual bool perform();
+ virtual double calcTimeLag() const;
+ virtual bool isActive() const;
+
+private:
+ virtual void dequeued();
+
+ // From AnimationActivity interface
+ virtual void setTargets(
+ const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer );
+
+private:
+ /** Hook for derived classes
+
+ This method will be called from the first
+ perform() invocation, to signal the start of the
+ activity.
+ */
+ virtual void startAnimation() = 0;
+
+ /** Hook for derived classes
+
+ This method will be called after the last perform()
+ invocation, and after the potential changes of that
+ perform() call are committed to screen. That is, in
+ endAnimation(), the animation objects (sprites,
+ animation) can safely be destroyed, without causing
+ visible artifacts on screen.
+ */
+ virtual void endAnimation() = 0;
+
+protected:
+
+ /** End this activity, in a regular way.
+
+ This method is for derived classes needing to signal a
+ regular activity end (i.e. because the regular
+ duration is over)
+ */
+ void endActivity();
+
+ /** Modify fractional time.
+
+ This method modifies the fractional time (total
+ duration mapped to the [0,1] range) to the
+ effective simple time, but only according to
+ acceleration/deceleration.
+ */
+ double calcAcceleratedTime( double nT ) const;
+
+ bool isDisposed() const {
+ return (!mbIsActive && !mpEndEvent && !mpShape &&
+ !mpAttributeLayer);
+ }
+
+ EventQueue& getEventQueue() const { return mrEventQueue; }
+
+ AnimatableShapeSharedPtr getShape() const { return mpShape; }
+
+ ShapeAttributeLayerSharedPtr getShapeAttributeLayer() const
+ { return mpAttributeLayer; }
+
+ bool isRepeatCountValid() const { return maRepeats; }
+ double getRepeatCount() const { return *maRepeats; }
+ bool isAutoReverse() const { return mbAutoReverse; }
+
+private:
+ /// Activity:
+ virtual void end();
+ virtual void performEnd() = 0;
+
+private:
+ EventSharedPtr mpEndEvent;
+ EventQueue& mrEventQueue;
+ AnimatableShapeSharedPtr mpShape; // only to pass on to animation
+ ShapeAttributeLayerSharedPtr mpAttributeLayer; // only to pass on to anim
+
+ ::boost::optional<double> const maRepeats;
+ const double mnAccelerationFraction;
+ const double mnDecelerationFraction;
+
+ const bool mbAutoReverse;
+
+ // true, if perform() has not yet been called:
+ mutable bool mbFirstPerformCall;
+ bool mbIsActive;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_ACTIVITYBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/activityparameters.hxx b/slideshow/source/engine/activities/activityparameters.hxx
new file mode 100644
index 000000000000..f09148988c11
--- /dev/null
+++ b/slideshow/source/engine/activities/activityparameters.hxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_ACTIVITYPARAMETERS_HXX
+#define INCLUDED_SLIDESHOW_ACTIVITYPARAMETERS_HXX
+
+#include "event.hxx"
+#include "eventqueue.hxx"
+#include "expressionnode.hxx"
+#include "wakeupevent.hxx"
+
+#include <boost/optional.hpp>
+#include <vector>
+
+namespace slideshow {
+namespace internal {
+
+/** Parameter struct for animation activities
+
+ This struct contains all common parameters needed to
+ initialize the activities generated by the ActivityFactory.
+*/
+struct ActivityParameters
+{
+ /** Create
+
+ @param rEndEvent
+ Event to be fired, when the activity ends.
+
+ @param rEventQueue
+ Queue to add end event to
+
+ @param nMinDuration
+ Minimal duration of the activity (might actually be
+ longer because of nMinNumberOfFrames). Note that this
+ duration must always be the <em>simple</em> duration,
+ i.e. without any repeat.
+
+ @param rRepeats
+ Number of repeats. If this parameter is invalid,
+ infinite repeat is assumed.
+
+ @param nAccelerationFraction
+ Value between 0 and 1, denoting the fraction of the
+ total simple duration, which the animation should
+ accelerate.
+
+ @param nDecelerationFraction
+ Value between 0 and 1, denoting the fraction of the
+ total simple duration, which the animation should
+ decelerate. Note that the ranges
+ [0,nAccelerationFraction] and
+ [nDecelerationFraction,1] must be non-overlapping!
+
+ @param bAutoReverse
+ When true, at the end of the simple duration, the
+ animation plays reversed to the start value. Note that
+ nMinDuration still specifies the simple duration,
+ i.e. when bAutoReverse is true, the implicit duration
+ doubles.
+ */
+ ActivityParameters(
+ const EventSharedPtr& rEndEvent,
+ EventQueue& rEventQueue,
+ ActivitiesQueue& rActivitiesQueue,
+ double nMinDuration,
+ ::boost::optional<double> const& rRepeats,
+ double nAccelerationFraction,
+ double nDecelerationFraction,
+ sal_uInt32 nMinNumberOfFrames,
+ bool bAutoReverse )
+ : mrEndEvent( rEndEvent ),
+ mpWakeupEvent(),
+ mrEventQueue( rEventQueue ),
+ mrActivitiesQueue( rActivitiesQueue ),
+ mpFormula(),
+ maDiscreteTimes(),
+ mnMinDuration( nMinDuration ),
+ mrRepeats( rRepeats ),
+ mnAccelerationFraction( nAccelerationFraction ),
+ mnDecelerationFraction( nDecelerationFraction ),
+ mnMinNumberOfFrames( nMinNumberOfFrames ),
+ mbAutoReverse( bAutoReverse ) {}
+
+ /// End event to fire, when activity is over
+ const EventSharedPtr& mrEndEvent;
+ /// Wakeup event to use for discrete activities
+ WakeupEventSharedPtr mpWakeupEvent;
+
+ /// EventQueue to add events to
+ EventQueue& mrEventQueue;
+
+ /// ActivitiesQueue to add events to
+ ActivitiesQueue& mrActivitiesQueue;
+
+ /// Optional formula
+ ExpressionNodeSharedPtr mpFormula;
+
+ /// Key times, for discrete and key time activities
+ ::std::vector< double > maDiscreteTimes;
+
+ /// Total duration of activity (including all repeats)
+ const double mnMinDuration;
+ ::boost::optional<double> const& mrRepeats;
+ const double mnAccelerationFraction;
+ const double mnDecelerationFraction;
+
+ /// Minimal number of frames this activity must render
+ const sal_uInt32 mnMinNumberOfFrames;
+
+ /// When true, activity is played reversed after mnDuration.
+ const bool mbAutoReverse;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_ACTIVITYPARAMETERS_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/continuousactivitybase.cxx b/slideshow/source/engine/activities/continuousactivitybase.cxx
new file mode 100644
index 000000000000..c8944c705a0a
--- /dev/null
+++ b/slideshow/source/engine/activities/continuousactivitybase.cxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <continuousactivitybase.hxx>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ContinuousActivityBase::ContinuousActivityBase( const ActivityParameters& rParms ) :
+ SimpleContinuousActivityBase( rParms )
+ {
+ }
+
+ void ContinuousActivityBase::simplePerform( double nSimpleTime,
+ sal_uInt32 nRepeatCount ) const
+ {
+ perform( calcAcceleratedTime( nSimpleTime ),
+ nRepeatCount );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/continuousactivitybase.hxx b/slideshow/source/engine/activities/continuousactivitybase.hxx
new file mode 100644
index 000000000000..0cdefbd2775a
--- /dev/null
+++ b/slideshow/source/engine/activities/continuousactivitybase.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_CONTINUOUSACTIVITYBASE_HXX
+#define INCLUDED_SLIDESHOW_CONTINUOUSACTIVITYBASE_HXX
+
+#include "simplecontinuousactivitybase.hxx"
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Simple, continuous animation.
+
+ This class implements a simple, continuous
+ animation. Only addition to ActivityBase class is an
+ explicit animation duration and a minimal number of
+ frames to display.
+ */
+ class ContinuousActivityBase : public SimpleContinuousActivityBase
+ {
+ public:
+ ContinuousActivityBase( const ActivityParameters& rParms );
+
+ using SimpleContinuousActivityBase::perform;
+
+ /** Hook for derived classes
+
+ This method will be called from perform(), already
+ equipped with the modified time (nMinNumberOfFrames, repeat,
+ acceleration and deceleration taken into account).
+
+ @param nModifiedTime
+ Already accelerated/decelerated and repeated time, always
+ in the [0,1] range.
+
+ @param nRepeatCount
+ Number of full repeats already performed
+ */
+ virtual void perform( double nModifiedTime, sal_uInt32 nRepeatCount ) const = 0;
+
+ /// From SimpleContinuousActivityBase class
+ virtual void simplePerform( double nSimpleTime,
+ sal_uInt32 nRepeatCount ) const;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_CONTINUOUSACTIVITYBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx b/slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx
new file mode 100644
index 000000000000..8e78a5f6d642
--- /dev/null
+++ b/slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <continuouskeytimeactivitybase.hxx>
+
+#include <boost/tuple/tuple.hpp>
+#include <algorithm>
+#include <iterator>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase( const ActivityParameters& rParms ) :
+ SimpleContinuousActivityBase( rParms ),
+ maLerper( rParms.maDiscreteTimes )
+ {
+ ENSURE_OR_THROW( rParms.maDiscreteTimes.size() > 1,
+ "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): key times vector must have two entries or more" );
+ ENSURE_OR_THROW( rParms.maDiscreteTimes.front() == 0.0,
+ "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): key times vector first entry must be zero" );
+ ENSURE_OR_THROW( rParms.maDiscreteTimes.back() <= 1.0,
+ "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): key times vector last entry must be less or equal 1" );
+ }
+
+ void ContinuousKeyTimeActivityBase::simplePerform( double nSimpleTime,
+ sal_uInt32 nRepeatCount ) const
+ {
+ // calc simple time from global time - sweep through the
+ // array multiple times for repeated animations (according to
+ // SMIL spec).
+ double fAlpha( calcAcceleratedTime( nSimpleTime ) );
+ std::ptrdiff_t nIndex;
+
+ boost::tuples::tie(nIndex,fAlpha) = maLerper.lerp(fAlpha);
+
+ perform(
+ nIndex,
+ fAlpha,
+ nRepeatCount );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx b/slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx
new file mode 100644
index 000000000000..5b9c10b3ead8
--- /dev/null
+++ b/slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_CONTINUOUSKEYTIMEACTIVITYBASE_HXX
+#define INCLUDED_SLIDESHOW_CONTINUOUSKEYTIMEACTIVITYBASE_HXX
+
+#include "simplecontinuousactivitybase.hxx"
+
+#include <basegfx/tools/keystoplerp.hxx>
+#include <vector>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Interpolated, key-times animation.
+
+ This class implements an interpolated key-times
+ animation, with continuous time.
+ */
+ class ContinuousKeyTimeActivityBase : public SimpleContinuousActivityBase
+ {
+ public:
+ ContinuousKeyTimeActivityBase( const ActivityParameters& rParms );
+
+ using SimpleContinuousActivityBase::perform;
+
+ /** Hook for derived classes
+
+ This method will be called from perform(), already
+ equipped with the modified time (nMinNumberOfFrames, repeat,
+ acceleration and deceleration taken into account).
+
+ @param nIndex
+ Current index of the key times/key values.
+
+ @param nFractionalIndex
+ Fractional value from the [0,1] range, specifying
+ the position between nIndex and nIndex+1.
+
+ @param nRepeatCount
+ Number of full repeats already performed
+ */
+ virtual void perform( sal_uInt32 nIndex,
+ double nFractionalIndex,
+ sal_uInt32 nRepeatCount ) const = 0;
+
+ /// From SimpleContinuousActivityBase class
+ virtual void simplePerform( double nSimpleTime,
+ sal_uInt32 nRepeatCount ) const;
+
+ private:
+ const ::basegfx::tools::KeyStopLerp maLerper;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_CONTINUOUSKEYTIMEACTIVITYBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/discreteactivitybase.cxx b/slideshow/source/engine/activities/discreteactivitybase.cxx
new file mode 100644
index 000000000000..d1cac547b200
--- /dev/null
+++ b/slideshow/source/engine/activities/discreteactivitybase.cxx
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <discreteactivitybase.hxx>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ DiscreteActivityBase::DiscreteActivityBase( const ActivityParameters& rParms ) :
+ ActivityBase( rParms ),
+ mpWakeupEvent( rParms.mpWakeupEvent ),
+ maDiscreteTimes( rParms.maDiscreteTimes ),
+ mnSimpleDuration( rParms.mnMinDuration ),
+ mnCurrPerformCalls( 0 )
+ {
+ ENSURE_OR_THROW( mpWakeupEvent,
+ "DiscreteActivityBase::DiscreteActivityBase(): Invalid wakeup event" );
+
+ ENSURE_OR_THROW( !maDiscreteTimes.empty(),
+ "DiscreteActivityBase::DiscreteActivityBase(): time vector is empty, why do you create me?" );
+
+#ifdef DBG_UTIL
+ // check parameters: rDiscreteTimes must be sorted in
+ // ascending order, and contain values only from the range
+ // [0,1]
+ for( ::std::size_t i=1, len=maDiscreteTimes.size(); i<len; ++i )
+ {
+ if( maDiscreteTimes[i] < 0.0 ||
+ maDiscreteTimes[i] > 1.0 ||
+ maDiscreteTimes[i-1] < 0.0 ||
+ maDiscreteTimes[i-1] > 1.0 )
+ {
+ ENSURE_OR_THROW( false, "DiscreteActivityBase::DiscreteActivityBase(): time values not within [0,1] range!" );
+ }
+
+ if( maDiscreteTimes[i-1] > maDiscreteTimes[i] )
+ ENSURE_OR_THROW( false, "DiscreteActivityBase::DiscreteActivityBase(): time vector is not sorted in ascending order!" );
+ }
+
+ // TODO(E2): check this also in production code?
+#endif
+ }
+
+ void DiscreteActivityBase::startAnimation()
+ {
+ // start timer on wakeup event
+ mpWakeupEvent->start();
+ }
+
+ sal_uInt32 DiscreteActivityBase::calcFrameIndex( sal_uInt32 nCurrCalls,
+ ::std::size_t nVectorSize ) const
+ {
+ if( isAutoReverse() )
+ {
+ // every full repeat run consists of one
+ // forward and one backward traversal.
+ sal_uInt32 nFrameIndex( nCurrCalls % (2*nVectorSize) );
+
+ // nFrameIndex values >= nVectorSize belong to
+ // the backward traversal
+ if( nFrameIndex >= nVectorSize )
+ nFrameIndex = 2*nVectorSize - nFrameIndex; // invert sweep
+
+ return nFrameIndex;
+ }
+ else
+ {
+ return nCurrCalls % nVectorSize ;
+ }
+ }
+
+ sal_uInt32 DiscreteActivityBase::calcRepeatCount( sal_uInt32 nCurrCalls,
+ ::std::size_t nVectorSize ) const
+ {
+ if( isAutoReverse() )
+ return nCurrCalls / (2*nVectorSize); // we've got 2 cycles per repeat
+ else
+ return nCurrCalls / nVectorSize;
+ }
+
+ bool DiscreteActivityBase::perform()
+ {
+ // call base class, for start() calls and end handling
+ if( !ActivityBase::perform() )
+ return false; // done, we're ended
+
+ const ::std::size_t nVectorSize( maDiscreteTimes.size() );
+
+ // actually perform something
+ // ==========================
+
+ // TODO(Q3): Refactor this mess
+
+ // call derived class with current frame index (modulo
+ // vector size, to cope with repeats)
+ perform( calcFrameIndex( mnCurrPerformCalls, nVectorSize ),
+ calcRepeatCount( mnCurrPerformCalls, nVectorSize ) );
+
+ // calc next index
+ ++mnCurrPerformCalls;
+
+ // calc currently reached repeat count
+ double nCurrRepeat( double(mnCurrPerformCalls) / nVectorSize );
+
+ // if auto-reverse is specified, halve the
+ // effective repeat count, since we pass every
+ // repeat run twice: once forward, once backward.
+ if( isAutoReverse() )
+ nCurrRepeat /= 2.0;
+
+ // schedule next frame, if either repeat is indefinite
+ // (repeat forever), or we've not yet reached the requested
+ // repeat count
+ if( !isRepeatCountValid() ||
+ nCurrRepeat < getRepeatCount() )
+ {
+ // add wake-up event to queue (modulo
+ // vector size, to cope with repeats).
+
+ // repeat is handled locally, only apply acceleration/deceleration.
+ // Scale time vector with simple duration, offset with full repeat
+ // times.
+ //
+ // Somewhat condensed, the argument for setNextTimeout below could
+ // be written as
+ //
+ // mnSimpleDuration*(nFullRepeats + calcAcceleratedTime( currentRepeatTime )),
+ //
+ // with currentRepeatTime = maDiscreteTimes[ currentRepeatIndex ]
+ //
+ // Note that calcAcceleratedTime() is only applied to the current repeat's value,
+ // not to the total resulting time. This is in accordance with the SMIL spec.
+ //
+ mpWakeupEvent->setNextTimeout(
+ mnSimpleDuration*(
+ calcRepeatCount(
+ mnCurrPerformCalls,
+ nVectorSize ) +
+ calcAcceleratedTime(
+ maDiscreteTimes[
+ calcFrameIndex(
+ mnCurrPerformCalls,
+ nVectorSize ) ] ) ) );
+
+ getEventQueue().addEvent( mpWakeupEvent );
+ }
+ else
+ {
+ // release event reference (relation to wakeup event
+ // is circular!)
+ mpWakeupEvent.reset();
+
+ // done with this activity
+ endActivity();
+ }
+
+ return false; // remove from queue, will be added back by the wakeup event.
+ }
+
+ void DiscreteActivityBase::dispose()
+ {
+ // dispose event
+ if( mpWakeupEvent )
+ mpWakeupEvent->dispose();
+
+ // release references
+ mpWakeupEvent.reset();
+
+ ActivityBase::dispose();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/discreteactivitybase.hxx b/slideshow/source/engine/activities/discreteactivitybase.hxx
new file mode 100644
index 000000000000..3a14f5a7354b
--- /dev/null
+++ b/slideshow/source/engine/activities/discreteactivitybase.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_DISCRETEACTIVITYBASE_HXX
+#define INCLUDED_SLIDESHOW_DISCRETEACTIVITYBASE_HXX
+
+#include "activitybase.hxx"
+#include "wakeupevent.hxx"
+
+#include <vector>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Specialization of ActivityBase for discrete time activities.
+
+ A discrete time activity is one where time proceeds in
+ discrete steps, i.e. at given time instants.
+ */
+ class DiscreteActivityBase : public ActivityBase
+ {
+ public:
+ DiscreteActivityBase( const ActivityParameters& rParms );
+
+ /** Hook for derived classes.
+
+ This method is called for each discrete time
+ instant, with nFrame denoting the frame number
+ (starting with 0)
+
+ @param nFrame
+ Current frame number.
+
+ @param nRepeatCount
+ Number of full repeats already performed
+ */
+ virtual void perform( sal_uInt32 nFrame, sal_uInt32 nRepeatCount ) const = 0;
+ virtual void dispose();
+ virtual bool perform();
+
+ protected:
+ virtual void startAnimation();
+
+ sal_uInt32 calcFrameIndex( sal_uInt32 nCurrCalls,
+ ::std::size_t nVectorSize ) const;
+
+ sal_uInt32 calcRepeatCount( sal_uInt32 nCurrCalls,
+ ::std::size_t nVectorSize ) const;
+
+ ::std::size_t getNumberOfKeyTimes() const { return maDiscreteTimes.size(); }
+
+ private:
+ WakeupEventSharedPtr mpWakeupEvent;
+ const ::std::vector< double > maDiscreteTimes;
+ const double mnSimpleDuration;
+ sal_uInt32 mnCurrPerformCalls;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_DISCRETEACTIVITYBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/interpolation.hxx b/slideshow/source/engine/activities/interpolation.hxx
new file mode 100644
index 000000000000..a8baa1e3832c
--- /dev/null
+++ b/slideshow/source/engine/activities/interpolation.hxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_INTERPOLATION_HXX
+#define INCLUDED_SLIDESHOW_INTERPOLATION_HXX
+
+#include <basegfx/tools/lerp.hxx>
+
+namespace basegfx
+{
+ namespace tools
+ {
+ // Interpolator specializations
+ // ============================
+
+ // NOTE: generic lerp is included from lerp.hxx. Following
+ // are some specializations for various
+ // not-straight-forward-interpolatable types
+
+ /// Specialization for RGBColor, to employ color-specific interpolator
+ template<> ::slideshow::internal::RGBColor lerp< ::slideshow::internal::RGBColor >(
+ const ::slideshow::internal::RGBColor& rFrom,
+ const ::slideshow::internal::RGBColor& rTo,
+ double t )
+ {
+ return interpolate( rFrom, rTo, t );
+ }
+
+ /// Specialization also for sal_Int16, although this code should not be called
+ template<> sal_Int16 lerp< sal_Int16 >( const sal_Int16&,
+ const sal_Int16& rTo,
+ double )
+ {
+ OSL_FAIL( "lerp<sal_Int16> called" );
+ return rTo;
+ }
+
+ /// Specialization also for string, although this code should not be called
+ template<> ::rtl::OUString lerp< ::rtl::OUString >( const ::rtl::OUString&,
+ const ::rtl::OUString& rTo,
+ double )
+ {
+ OSL_FAIL( "lerp<::rtl::OUString> called" );
+ return rTo;
+ }
+
+ /// Specialization also for bool, although this code should not be called
+ template<> bool lerp< bool >( const bool&,
+ const bool& rTo,
+ double )
+ {
+ OSL_FAIL( "lerp<bool> called" );
+ return rTo;
+ }
+ }
+}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ template< typename ValueType > struct Interpolator
+ {
+ ValueType operator()( const ValueType& rFrom,
+ const ValueType& rTo,
+ double t ) const
+ {
+ return basegfx::tools::lerp( rFrom, rTo, t );
+ }
+ };
+
+ /// Specialization for HSLColor, to employ color-specific interpolator
+ template<> struct Interpolator< HSLColor >
+ {
+ Interpolator( bool bCCW ) :
+ mbCCW( bCCW )
+ {
+ }
+
+ HSLColor operator()( const HSLColor& rFrom,
+ const HSLColor& rTo,
+ double t ) const
+ {
+ return interpolate( rFrom, rTo, t, mbCCW );
+ }
+
+ private:
+ /// When true: interpolate counter-clockwise
+ const bool mbCCW;
+ };
+
+
+ /** Generic linear interpolator
+
+ @tpl ValueType
+ Must have operator+ and operator* defined, and should
+ have value semantics.
+
+ @param rInterpolator
+ Interpolator to use for lerp
+
+ @param nFrame
+ Must be in the [0,nTotalFrames) range
+
+ @param nTotalFrames
+ Total number of frames. Should be greater than zero.
+ */
+ template< typename ValueType > ValueType lerp( const Interpolator< ValueType >& rInterpolator,
+ const ValueType& rFrom,
+ const ValueType& rTo,
+ sal_uInt32 nFrame,
+ ::std::size_t nTotalFrames )
+ {
+ // TODO(P1): There's a nice HAKMEM trick for that
+ // nTotalFrames > 1 condition below
+
+ // for 1 and 0 frame animations, always take end value
+ const double nFraction( nTotalFrames > 1 ? double(nFrame)/(nTotalFrames-1) : 1.0 );
+
+ return rInterpolator( rFrom, rTo, nFraction );
+ }
+
+ /// Specialization for non-interpolatable constants/enums
+ template<> sal_Int16 lerp< sal_Int16 >( const Interpolator< sal_Int16 >& /*rInterpolator*/,
+ const sal_Int16& rFrom,
+ const sal_Int16& rTo,
+ sal_uInt32 nFrame,
+ ::std::size_t nTotalFrames )
+ {
+ // until one half of the total frames are over, take from value.
+ // after that, take to value.
+ // For nFrames not divisable by 2, we prefer to over from, which
+ // also neatly yields to for 1 frame activities
+ return nFrame < nTotalFrames/2 ? rFrom : rTo;
+ }
+
+ /// Specialization for non-interpolatable strings
+ template<> ::rtl::OUString lerp< ::rtl::OUString >( const Interpolator< ::rtl::OUString >& /*rInterpolator*/,
+ const ::rtl::OUString& rFrom,
+ const ::rtl::OUString& rTo,
+ sal_uInt32 nFrame,
+ ::std::size_t nTotalFrames )
+ {
+ // until one half of the total frames are over, take from value.
+ // after that, take to value.
+ // For nFrames not divisable by 2, we prefer to over from, which
+ // also neatly yields to for 1 frame activities
+ return nFrame < nTotalFrames/2 ? rFrom : rTo;
+ }
+
+ /// Specialization for non-interpolatable bools
+ template<> bool lerp< bool >( const Interpolator< bool >& /*rInterpolator*/,
+ const bool& bFrom,
+ const bool& bTo,
+ sal_uInt32 nFrame,
+ ::std::size_t nTotalFrames )
+ {
+ // until one half of the total frames are over, take from value.
+ // after that, take to value.
+ // For nFrames not divisable by 2, we prefer to over from, which
+ // also neatly yields to for 1 frame activities
+ return nFrame < nTotalFrames/2 ? bFrom : bTo;
+ }
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_INTERPOLATION_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/makefile.mk b/slideshow/source/engine/activities/makefile.mk
new file mode 100644
index 000000000000..fc24b4042265
--- /dev/null
+++ b/slideshow/source/engine/activities/makefile.mk
@@ -0,0 +1,53 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=slideshow
+TARGET=activities
+ENABLE_EXCEPTIONS=TRUE
+PRJINC=..$/..
+
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = $(SLO)$/activitybase.obj \
+ $(SLO)$/activitiesfactory.obj \
+ $(SLO)$/continuousactivitybase.obj \
+ $(SLO)$/continuouskeytimeactivitybase.obj \
+ $(SLO)$/discreteactivitybase.obj \
+ $(SLO)$/simplecontinuousactivitybase.obj
+
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/activities/simplecontinuousactivitybase.cxx b/slideshow/source/engine/activities/simplecontinuousactivitybase.cxx
new file mode 100644
index 000000000000..af6d51ed6d8a
--- /dev/null
+++ b/slideshow/source/engine/activities/simplecontinuousactivitybase.cxx
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <simplecontinuousactivitybase.hxx>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ SimpleContinuousActivityBase::SimpleContinuousActivityBase(
+ const ActivityParameters& rParms ) :
+ ActivityBase( rParms ),
+ maTimer( rParms.mrActivitiesQueue.getTimer() ),
+ mnMinSimpleDuration( rParms.mnMinDuration ),
+ mnMinNumberOfFrames( rParms.mnMinNumberOfFrames ),
+ mnCurrPerformCalls( 0 )
+ {
+ }
+
+ void SimpleContinuousActivityBase::startAnimation()
+ {
+ // init timer. We measure animation time only when we're
+ // actually started.
+ maTimer.reset();
+ }
+
+ double SimpleContinuousActivityBase::calcTimeLag() const
+ {
+ ActivityBase::calcTimeLag();
+ if (! isActive())
+ return 0.0;
+
+ // retrieve locally elapsed time
+ const double nCurrElapsedTime( maTimer.getElapsedTime() );
+
+ // log time
+ VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): "
+ "next step is based on time: %f", nCurrElapsedTime );
+
+ // go to great length to ensure a proper animation
+ // run. Since we don't know how often we will be called
+ // here, try to spread the animator calls uniquely over
+ // the [0,1] parameter range. Be aware of the fact that
+ // perform will be called at least mnMinNumberOfTurns
+ // times.
+
+ // fraction of time elapsed
+ const double nFractionElapsedTime(
+ nCurrElapsedTime / mnMinSimpleDuration );
+
+ // fraction of minimum calls performed
+ const double nFractionRequiredCalls(
+ double(mnCurrPerformCalls) / mnMinNumberOfFrames );
+
+ // okay, so now, the decision is easy:
+ //
+ // If the fraction of time elapsed is smaller than the
+ // number of calls required to be performed, then we calc
+ // the position on the animation range according to
+ // elapsed time. That is, we're so to say ahead of time.
+ //
+ // In contrary, if the fraction of time elapsed is larger,
+ // then we're lagging, and we thus calc the position on
+ // the animation time line according to the fraction of
+ // calls performed. Thus, the animation is forced to slow
+ // down, and take the required minimal number of steps,
+ // sufficiently equally distributed across the animation
+ // time line.
+ if( nFractionElapsedTime < nFractionRequiredCalls )
+ {
+ VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): "
+ "t=%f is based on time", nFractionElapsedTime );
+ return 0.0;
+ }
+ else
+ {
+ VERBOSE_TRACE( "SimpleContinuousActivityBase::perform(): "
+ "t=%f is based on number of calls",
+ nFractionRequiredCalls );
+
+ // lag global time, so all other animations lag, too:
+ return ((nFractionElapsedTime - nFractionRequiredCalls)
+ * mnMinSimpleDuration);
+ }
+ }
+
+ bool SimpleContinuousActivityBase::perform()
+ {
+ // call base class, for start() calls and end handling
+ if( !ActivityBase::perform() )
+ return false; // done, we're ended
+
+
+ // get relative animation position
+ // ===============================
+
+ const double nCurrElapsedTime( maTimer.getElapsedTime() );
+ double nT( nCurrElapsedTime / mnMinSimpleDuration );
+
+
+ // one of the stop criteria reached?
+ // =================================
+
+ // will be set to true below, if one of the termination criteria
+ // matched.
+ bool bActivityEnding( false );
+
+ if( isRepeatCountValid() )
+ {
+ // Finite duration
+ // ===============
+
+ // When we've autoreverse on, the repeat count
+ // doubles
+ const double nRepeatCount( getRepeatCount() );
+ const double nEffectiveRepeat( isAutoReverse() ?
+ 2.0*nRepeatCount :
+ nRepeatCount );
+
+ // time (or frame count) elapsed?
+ if( nEffectiveRepeat <= nT )
+ {
+ // okee. done for now. Will not exit right here,
+ // to give animation the chance to render the last
+ // frame below
+ bActivityEnding = true;
+
+ // clamp animation to max permissible value
+ nT = nEffectiveRepeat;
+ }
+ }
+
+
+ // need to do auto-reverse?
+ // ========================
+
+ double nRepeats;
+ double nRelativeSimpleTime;
+
+ // TODO(Q3): Refactor this mess
+ if( isAutoReverse() )
+ {
+ // divert active duration into repeat and
+ // fractional part.
+ const double nFractionalActiveDuration( modf(nT, &nRepeats) );
+
+ // for auto-reverse, map ranges [1,2), [3,4), ...
+ // to ranges [0,1), [1,2), etc.
+ if( ((int)nRepeats) % 2 )
+ {
+ // we're in an odd range, reverse sweep
+ nRelativeSimpleTime = 1.0 - nFractionalActiveDuration;
+ }
+ else
+ {
+ // we're in an even range, pass on as is
+ nRelativeSimpleTime = nFractionalActiveDuration;
+ }
+
+ // effective repeat count for autoreverse is half of
+ // the input time's value (each run of an autoreverse
+ // cycle is half of a repeat)
+ nRepeats /= 2;
+ }
+ else
+ {
+ // determine repeat
+ // ================
+
+ // calc simple time and number of repeats from nT
+ // Now, that's easy, since the fractional part of
+ // nT gives the relative simple time, and the
+ // integer part the number of full repeats:
+ nRelativeSimpleTime = modf(nT, &nRepeats);
+
+ // clamp repeats to max permissible value (maRepeats.getValue() - 1.0)
+ if( isRepeatCountValid() &&
+ nRepeats >= getRepeatCount() )
+ {
+ // Note that this code here only gets
+ // triggered if maRepeats.getValue() is an
+ // _integer_. Otherwise, nRepeats will never
+ // reach nor exceed
+ // maRepeats.getValue(). Thus, the code below
+ // does not need to handle cases of fractional
+ // repeats, and can always assume that a full
+ // animation run has ended (with
+ // nRelativeSimpleTime=1.0 for
+ // non-autoreversed activities).
+
+ // with modf, nRelativeSimpleTime will never
+ // become 1.0, since nRepeats is incremented and
+ // nRelativeSimpleTime set to 0.0 then.
+ //
+ // For the animation to reach its final value,
+ // nRepeats must although become
+ // maRepeats.getValue()-1.0, and
+ // nRelativeSimpleTime=1.0.
+ nRelativeSimpleTime = 1.0;
+ nRepeats -= 1.0;
+ }
+ }
+
+ // actually perform something
+ // ==========================
+
+ simplePerform( nRelativeSimpleTime,
+ // nRepeats is already integer-valued
+ static_cast<sal_uInt32>( nRepeats ) );
+
+
+ // delayed endActivity() call from end condition check
+ // below. Issued after the simplePerform() call above, to
+ // give animations the chance to correctly reach the
+ // animation end value, without spurious bail-outs because
+ // of isActive() returning false.
+ if( bActivityEnding )
+ endActivity();
+
+ // one more frame successfully performed
+ ++mnCurrPerformCalls;
+
+ return isActive();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activities/simplecontinuousactivitybase.hxx b/slideshow/source/engine/activities/simplecontinuousactivitybase.hxx
new file mode 100644
index 000000000000..031c1e972c5b
--- /dev/null
+++ b/slideshow/source/engine/activities/simplecontinuousactivitybase.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_SIMPLECONTINUOUSACTIVITYBASE_HXX
+#define INCLUDED_SLIDESHOW_SIMPLECONTINUOUSACTIVITYBASE_HXX
+
+#include "activitybase.hxx"
+#include <canvas/elapsedtime.hxx>
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Simple, continuous animation.
+
+ This class implements a simple, continuous animation
+ without considering repeats or acceleration on the
+ perform call. Only useful as a base class, you
+ probably want to use ContinuousActivityBase.
+ */
+ class SimpleContinuousActivityBase : public ActivityBase
+ {
+ public:
+ SimpleContinuousActivityBase( const ActivityParameters& rParms );
+
+ virtual double calcTimeLag() const;
+ virtual bool perform();
+
+ protected:
+ /** Hook for derived classes
+
+ This method will be called from perform().
+
+ @param nSimpleTime
+ Simple animation time, without repeat,
+ acceleration or deceleration applied. This value
+ is always in the [0,1] range, the repeat is
+ accounted for with the nRepeatCount parameter.
+
+ @param nRepeatCount
+ Number of full repeats already performed
+ */
+ virtual void simplePerform( double nSimpleTime, sal_uInt32 nRepeatCount ) const = 0;
+
+ virtual void startAnimation();
+
+ private:
+ /// Time elapsed since activity started
+ ::canvas::tools::ElapsedTime maTimer;
+
+ /// Simple duration of activity
+ const double mnMinSimpleDuration;
+
+ /// Minimal number of frames to show (see ActivityParameters)
+ const sal_uInt32 mnMinNumberOfFrames;
+
+ /// Actual number of frames shown until now.
+ sal_uInt32 mnCurrPerformCalls;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_SIMPLECONTINUOUSACTIVITYBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/activitiesqueue.cxx b/slideshow/source/engine/activitiesqueue.cxx
new file mode 100644
index 000000000000..cc7b738d0756
--- /dev/null
+++ b/slideshow/source/engine/activitiesqueue.cxx
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include "slideshowexceptions.hxx"
+#include "activity.hxx"
+#include "activitiesqueue.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ActivitiesQueue::ActivitiesQueue(
+ const ::boost::shared_ptr< ::canvas::tools::ElapsedTime >& pPresTimer ) :
+ mpTimer( pPresTimer ),
+ maCurrentActivitiesWaiting(),
+ maCurrentActivitiesReinsert(),
+ maDequeuedActivities()
+ {
+ }
+
+ ActivitiesQueue::~ActivitiesQueue()
+ {
+ // dispose all queue entries
+ try
+ {
+ std::for_each( maCurrentActivitiesWaiting.begin(),
+ maCurrentActivitiesWaiting.end(),
+ boost::mem_fn( &Disposable::dispose ) );
+ std::for_each( maCurrentActivitiesReinsert.begin(),
+ maCurrentActivitiesReinsert.end(),
+ boost::mem_fn( &Disposable::dispose ) );
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ bool ActivitiesQueue::addActivity( const ActivitySharedPtr& pActivity )
+ {
+ OSL_ENSURE( pActivity, "ActivitiesQueue::addActivity: activity ptr NULL" );
+
+ if( !pActivity )
+ return false;
+
+ // add entry to waiting list
+ maCurrentActivitiesWaiting.push_back( pActivity );
+
+ return true;
+ }
+
+ void ActivitiesQueue::process()
+ {
+ VERBOSE_TRACE( "ActivitiesQueue: outer loop heartbeat" );
+
+ // accumulate time lag for all activities, and lag time
+ // base if necessary:
+ ActivityQueue::const_iterator iPos(
+ maCurrentActivitiesWaiting.begin() );
+ const ActivityQueue::const_iterator iEnd(
+ maCurrentActivitiesWaiting.end() );
+ double fLag = 0.0;
+ for ( ; iPos != iEnd; ++iPos )
+ fLag = std::max<double>( fLag, (*iPos)->calcTimeLag() );
+ if (fLag > 0.0)
+ {
+ mpTimer->adjustTimer( -fLag );
+ }
+
+ // process list of activities
+ while( !maCurrentActivitiesWaiting.empty() )
+ {
+ // process topmost activity
+ ActivitySharedPtr pActivity( maCurrentActivitiesWaiting.front() );
+ maCurrentActivitiesWaiting.pop_front();
+
+ bool bReinsert( false );
+
+ try
+ {
+ // fire up activity
+ bReinsert = pActivity->perform();
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ // catch anything here, we don't want
+ // to leave this scope under _any_
+ // circumstance. Although, do _not_
+ // reinsert an activity that threw
+ // once.
+
+ // NOTE: we explicitely don't catch(...) here,
+ // since this will also capture segmentation
+ // violations and the like. In such a case, we
+ // still better let our clients now...
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ catch( SlideShowException& )
+ {
+ // catch anything here, we don't want
+ // to leave this scope under _any_
+ // circumstance. Although, do _not_
+ // reinsert an activity that threw
+ // once.
+
+ // NOTE: we explicitely don't catch(...) here,
+ // since this will also capture segmentation
+ // violations and the like. In such a case, we
+ // still better let our clients now...
+ OSL_TRACE( "::presentation::internal::ActivitiesQueue: Activity threw a SlideShowException, removing from ring" );
+ }
+
+ if( bReinsert )
+ maCurrentActivitiesReinsert.push_back( pActivity );
+ else
+ maDequeuedActivities.push_back( pActivity );
+
+ VERBOSE_TRACE( "ActivitiesQueue: inner loop heartbeat" );
+ }
+
+ if( !maCurrentActivitiesReinsert.empty() )
+ {
+ // reinsert all processed, but not finished
+ // activities back to waiting queue. With swap(),
+ // we kill two birds with one stone: we reuse the
+ // list nodes, and we clear the
+ // maCurrentActivitiesReinsert list
+ maCurrentActivitiesWaiting.swap( maCurrentActivitiesReinsert );
+ }
+ }
+
+ void ActivitiesQueue::processDequeued()
+ {
+ // notify all dequeued activities from last round
+ ::std::for_each( maDequeuedActivities.begin(),
+ maDequeuedActivities.end(),
+ ::boost::mem_fn( &Activity::dequeued ) );
+ maDequeuedActivities.clear();
+ }
+
+ bool ActivitiesQueue::isEmpty() const
+ {
+ return maCurrentActivitiesWaiting.empty() && maCurrentActivitiesReinsert.empty();
+ }
+
+ void ActivitiesQueue::clear()
+ {
+ // dequeue all entries:
+ std::for_each( maCurrentActivitiesWaiting.begin(),
+ maCurrentActivitiesWaiting.end(),
+ boost::mem_fn( &Activity::dequeued ) );
+ ActivityQueue().swap( maCurrentActivitiesWaiting );
+
+ std::for_each( maCurrentActivitiesReinsert.begin(),
+ maCurrentActivitiesReinsert.end(),
+ boost::mem_fn( &Activity::dequeued ) );
+ ActivityQueue().swap( maCurrentActivitiesReinsert );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animatedsprite.cxx b/slideshow/source/engine/animatedsprite.cxx
new file mode 100644
index 000000000000..951f88bf1454
--- /dev/null
+++ b/slideshow/source/engine/animatedsprite.cxx
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <animatedsprite.hxx>
+
+#include <cppcanvas/canvas.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ AnimatedSprite::AnimatedSprite( const ViewLayerSharedPtr& rViewLayer,
+ const ::basegfx::B2DSize& rSpriteSizePixel,
+ double nSpritePrio ) :
+ mpViewLayer( rViewLayer ),
+ mpSprite(),
+ maEffectiveSpriteSizePixel( rSpriteSizePixel ),
+ maContentPixelOffset(),
+ mnSpritePrio(nSpritePrio),
+ mnAlpha(0.0),
+ maPosPixel(),
+ maClip(),
+ maTransform(),
+ mbSpriteVisible( false )
+ {
+ ENSURE_OR_THROW( mpViewLayer, "AnimatedSprite::AnimatedSprite(): Invalid view layer" );
+
+ // Add half a pixel tolerance to sprite size, since we later on compare
+ // against it in resize(). And view transformations will almost never yield
+ // the same data bits when transforming to device coordinates
+ maEffectiveSpriteSizePixel += ::basegfx::B2DSize(0.5, 0.5);
+
+ mpSprite = mpViewLayer->createSprite( maEffectiveSpriteSizePixel,
+ mnSpritePrio );
+
+ ENSURE_OR_THROW( mpSprite, "AnimatedSprite::AnimatedSprite(): Could not create sprite" );
+ }
+
+ ::cppcanvas::CanvasSharedPtr AnimatedSprite::getContentCanvas() const
+ {
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(), "AnimatedSprite::getContentCanvas(): No view layer canvas" );
+
+ const ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() );
+ pContentCanvas->clear();
+
+ // extract linear part of canvas view transformation
+ // (linear means: without translational components). The
+ // only translation that is imposed at the view transform
+ // is the local content pixel offset.
+ //
+ // We can apply that directly here, no need to call
+ // aLinearTransform.translate(), since, as said above, the
+ // last column of aLinearTransform is assumed [0 0 1]
+ ::basegfx::B2DHomMatrix aLinearTransform( mpViewLayer->getTransformation() );
+ aLinearTransform.set( 0, 2, maContentPixelOffset.getX() );
+ aLinearTransform.set( 1, 2, maContentPixelOffset.getY() );
+
+ // apply linear part of canvas view transformation to sprite canvas
+ pContentCanvas->setTransformation( aLinearTransform );
+
+ return pContentCanvas;
+ }
+
+ bool AnimatedSprite::resize( const ::basegfx::B2DSize& rSpriteSizePixel )
+ {
+ // Enlarge or reduce the sprite size, if necessary. This
+ // method employs a strategy similar to container, when
+ // allocating memory: size is doubled or halved everytime
+ // the limit is reached. This makes for amortized constant
+ // time in runtime complexity. Note that we take exact
+ // powers of two here, since several HW-accelerated canvas
+ // implementations are limited to such sprite sizes
+ // (otherwise, those implementations would internally
+ // round up, too, wasting precious mem).
+ ::basegfx::B2DSize aNewSize( maEffectiveSpriteSizePixel );
+ bool bNeedResize( false );
+
+ if( rSpriteSizePixel.getX() > maEffectiveSpriteSizePixel.getX() ||
+ rSpriteSizePixel.getX() < 0.5*maEffectiveSpriteSizePixel.getX() )
+ {
+ // enlarge or shrink width
+ aNewSize.setX( ::canvas::tools::nextPow2( ::basegfx::fround(rSpriteSizePixel.getX()) ) );
+ bNeedResize = true;
+ }
+
+ if( rSpriteSizePixel.getY() > maEffectiveSpriteSizePixel.getY() ||
+ rSpriteSizePixel.getY() < 0.5*maEffectiveSpriteSizePixel.getY() )
+ {
+ // enlarge or shrink height, by doubling it
+ aNewSize.setY( ::canvas::tools::nextPow2( ::basegfx::fround(rSpriteSizePixel.getY()) ) );
+ bNeedResize = true;
+ }
+
+ if( bNeedResize )
+ {
+ // as the old sprite might have already been altered
+ // (and therefore been placed in the update list of
+ // the spritecanvas for this frame), must hide it
+ // here, to ensure it's not visible on screen any
+ // longer.
+ mpSprite->hide();
+
+ maEffectiveSpriteSizePixel = aNewSize;
+ mpSprite = mpViewLayer->createSprite( maEffectiveSpriteSizePixel,
+ mnSpritePrio );
+
+ ENSURE_OR_THROW( mpSprite,
+ "AnimatedSprite::resize(): Could not create new sprite" );
+
+ // set attributes similar to previous sprite
+ if( mpSprite && mbSpriteVisible )
+ {
+ mpSprite->show();
+ mpSprite->setAlpha( mnAlpha );
+
+ if( maPosPixel )
+ mpSprite->movePixel( *maPosPixel );
+
+ if( maClip )
+ mpSprite->setClip( *maClip );
+ }
+ }
+
+ return mpSprite;
+ }
+
+ void AnimatedSprite::setPixelOffset( const ::basegfx::B2DSize& rPixelOffset )
+ {
+ maContentPixelOffset = rPixelOffset;
+ }
+
+ ::basegfx::B2DSize AnimatedSprite::getPixelOffset() const
+ {
+ return maContentPixelOffset;
+ }
+
+ void AnimatedSprite::movePixel( const ::basegfx::B2DPoint& rNewPos )
+ {
+ maPosPixel.reset( rNewPos );
+ mpSprite->movePixel( rNewPos );
+ }
+
+ void AnimatedSprite::setAlpha( double nAlpha )
+ {
+ mnAlpha = nAlpha;
+ mpSprite->setAlpha( nAlpha );
+ }
+
+ void AnimatedSprite::clip( const ::basegfx::B2DPolyPolygon& rClip )
+ {
+ maClip.reset( rClip );
+ mpSprite->setClipPixel( rClip );
+ }
+
+ void AnimatedSprite::clip()
+ {
+ maClip.reset();
+ mpSprite->setClip();
+ }
+
+ void AnimatedSprite::transform( const ::basegfx::B2DHomMatrix& rTransform )
+ {
+ maTransform.reset( rTransform );
+ mpSprite->transform( rTransform );
+ }
+
+ void AnimatedSprite::setPriority( double nPrio )
+ {
+ mpSprite->setPriority( nPrio );
+ }
+
+ void AnimatedSprite::hide()
+ {
+ mpSprite->hide();
+ mbSpriteVisible = false;
+ }
+
+ void AnimatedSprite::show()
+ {
+ mbSpriteVisible = true;
+ mpSprite->show();
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationfactory.cxx b/slideshow/source/engine/animationfactory.cxx
new file mode 100644
index 000000000000..b5fda4da99d3
--- /dev/null
+++ b/slideshow/source/engine/animationfactory.cxx
@@ -0,0 +1,1396 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <animationfactory.hxx>
+#include <attributemap.hxx>
+
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include <functional>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ namespace
+ {
+ // attention, there is a similar implementation of Animation in
+ // transitions/transitionfactory.cxx
+
+ template< typename ValueT > class TupleAnimation : public PairAnimation
+ {
+ public:
+ TupleAnimation( const ShapeManagerSharedPtr& rShapeManager,
+ int nFlags,
+ bool (ShapeAttributeLayer::*pIs1stValid)() const,
+ bool (ShapeAttributeLayer::*pIs2ndValid)() const,
+ const ValueT& rDefaultValue,
+ const ::basegfx::B2DSize& rReferenceSize,
+ double (ShapeAttributeLayer::*pGet1stValue)() const,
+ double (ShapeAttributeLayer::*pGet2ndValue)() const,
+ void (ShapeAttributeLayer::*pSetValue)( const ValueT& ) ) :
+ mpShape(),
+ mpAttrLayer(),
+ mpShapeManager( rShapeManager ),
+ mpIs1stValidFunc(pIs1stValid),
+ mpIs2ndValidFunc(pIs2ndValid),
+ mpGet1stValueFunc(pGet1stValue),
+ mpGet2ndValueFunc(pGet2ndValue),
+ mpSetValueFunc(pSetValue),
+ mnFlags( nFlags ),
+ maReferenceSize( rReferenceSize ),
+ maDefaultValue( rDefaultValue ),
+ mbAnimationStarted( false )
+ {
+ ENSURE_OR_THROW( rShapeManager,
+ "TupleAnimation::TupleAnimation(): Invalid ShapeManager" );
+ ENSURE_OR_THROW( pIs1stValid && pIs2ndValid && pGet1stValue && pGet2ndValue && pSetValue,
+ "TupleAnimation::TupleAnimation(): One of the method pointers is NULL" );
+ }
+
+ ~TupleAnimation()
+ {
+ end_();
+ }
+
+ // Animation interface
+ // -------------------
+ virtual void prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& )
+ {}
+
+ virtual void start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer )
+ {
+ OSL_ENSURE( !mpShape,
+ "TupleAnimation::start(): Shape already set" );
+ OSL_ENSURE( !mpAttrLayer,
+ "TupleAnimation::start(): Attribute layer already set" );
+
+ mpShape = rShape;
+ mpAttrLayer = rAttrLayer;
+
+ ENSURE_OR_THROW( rShape,
+ "TupleAnimation::start(): Invalid shape" );
+ ENSURE_OR_THROW( rAttrLayer,
+ "TupleAnimation::start(): Invalid attribute layer" );
+
+ if( !mbAnimationStarted )
+ {
+ mbAnimationStarted = true;
+
+ if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) )
+ mpShapeManager->enterAnimationMode( mpShape );
+ }
+ }
+
+ virtual void end() { end_(); }
+ void end_()
+ {
+ if( mbAnimationStarted )
+ {
+ mbAnimationStarted = false;
+
+ if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) )
+ mpShapeManager->leaveAnimationMode( mpShape );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+ }
+ }
+
+ // PairAnimation interface
+ // -----------------------
+
+ virtual bool operator()( const ::basegfx::B2DTuple& rValue )
+ {
+ ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape,
+ "TupleAnimation::operator(): Invalid ShapeAttributeLayer" );
+
+ ValueT aValue( rValue.getX(),
+ rValue.getY() );
+
+ // Activitis get values from the expression parser,
+ // which returns _relative_ sizes/positions.
+ // Convert back relative to reference coordinate system
+ aValue *= maReferenceSize;
+
+ ((*mpAttrLayer).*mpSetValueFunc)( aValue );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+
+ return true;
+ }
+
+ virtual ::basegfx::B2DTuple getUnderlyingValue() const
+ {
+ ENSURE_OR_THROW( mpAttrLayer,
+ "TupleAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" );
+
+ ::basegfx::B2DTuple aRetVal;
+
+ // deviated from the (*shared_ptr).*mpFuncPtr
+ // notation here, since gcc does not seem to parse
+ // that as a member function call anymore.
+ aRetVal.setX( (mpAttrLayer.get()->*mpIs1stValidFunc)() ?
+ (mpAttrLayer.get()->*mpGet1stValueFunc)() :
+ maDefaultValue.getX() );
+ aRetVal.setY( (mpAttrLayer.get()->*mpIs2ndValidFunc)() ?
+ (mpAttrLayer.get()->*mpGet2ndValueFunc)() :
+ maDefaultValue.getY() );
+
+ // Activities get values from the expression
+ // parser, which returns _relative_
+ // sizes/positions. Convert start value to the
+ // same coordinate space (i.e. relative to given
+ // reference size).
+ aRetVal /= maReferenceSize;
+
+ return aRetVal;
+ }
+
+ private:
+ AnimatableShapeSharedPtr mpShape;
+ ShapeAttributeLayerSharedPtr mpAttrLayer;
+ ShapeManagerSharedPtr mpShapeManager;
+ bool (ShapeAttributeLayer::*mpIs1stValidFunc)() const;
+ bool (ShapeAttributeLayer::*mpIs2ndValidFunc)() const;
+ double (ShapeAttributeLayer::*mpGet1stValueFunc)() const;
+ double (ShapeAttributeLayer::*mpGet2ndValueFunc)() const;
+ void (ShapeAttributeLayer::*mpSetValueFunc)( const ValueT& );
+
+ const int mnFlags;
+
+ const ::basegfx::B2DSize maReferenceSize;
+ const ValueT maDefaultValue;
+ bool mbAnimationStarted;
+ };
+
+
+ class PathAnimation : public NumberAnimation
+ {
+ public:
+ PathAnimation( const ::rtl::OUString& rSVGDPath,
+ sal_Int16 nAdditive,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& rSlideSize,
+ int nFlags ) :
+ maPathPoly(),
+ mpShape(),
+ mpAttrLayer(),
+ mpShapeManager( rShapeManager ),
+ maPageSize( rSlideSize ),
+ maShapeOrig(),
+ mnFlags( nFlags ),
+ mbAnimationStarted( false ),
+ mnAdditive( nAdditive )
+ {
+ ENSURE_OR_THROW( rShapeManager,
+ "PathAnimation::PathAnimation(): Invalid ShapeManager" );
+
+ ::basegfx::B2DPolyPolygon aPolyPoly;
+
+ ENSURE_OR_THROW( ::basegfx::tools::importFromSvgD( aPolyPoly, rSVGDPath ),
+ "PathAnimation::PathAnimation(): failed to parse SVG:d path" );
+ ENSURE_OR_THROW( aPolyPoly.count() == 1,
+ "PathAnimation::PathAnimation(): motion path consists of multiple/zero polygon(s)" );
+
+ // TODO(F2): Since getPositionRelative() currently
+ // cannot handle beziers, have to subdivide.
+ // AW: Should be no longer necessary; getPositionRelative is now bezier-safe
+ maPathPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly.getB2DPolygon(0) );
+ }
+
+ ~PathAnimation()
+ {
+ end_();
+ }
+
+ // Animation interface
+ // -------------------
+ virtual void prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& )
+ {}
+
+ virtual void start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer )
+ {
+ OSL_ENSURE( !mpShape,
+ "PathAnimation::start(): Shape already set" );
+ OSL_ENSURE( !mpAttrLayer,
+ "PathAnimation::start(): Attribute layer already set" );
+
+ mpShape = rShape;
+ mpAttrLayer = rAttrLayer;
+
+ ENSURE_OR_THROW( rShape,
+ "PathAnimation::start(): Invalid shape" );
+ ENSURE_OR_THROW( rAttrLayer,
+ "PathAnimation::start(): Invalid attribute layer" );
+
+ // TODO(F1): Check whether _shape_ bounds are correct here.
+ // Theoretically, our AttrLayer is way down the stack, and
+ // we only have to consider _that_ value, not the one from
+ // the top of the stack as returned by Shape::getBounds()
+ if( mnAdditive == animations::AnimationAdditiveMode::SUM )
+ maShapeOrig = mpShape->getBounds().getCenter();
+ else
+ maShapeOrig = mpShape->getDomBounds().getCenter();
+
+ if( !mbAnimationStarted )
+ {
+ mbAnimationStarted = true;
+
+ if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) )
+ mpShapeManager->enterAnimationMode( mpShape );
+ }
+ }
+
+ virtual void end() { end_(); }
+ void end_()
+ {
+ if( mbAnimationStarted )
+ {
+ mbAnimationStarted = false;
+
+ if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) )
+ mpShapeManager->leaveAnimationMode( mpShape );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+ }
+ }
+
+ // NumberAnimation interface
+ // -----------------------
+
+ virtual bool operator()( double nValue )
+ {
+ ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape,
+ "PathAnimation::operator(): Invalid ShapeAttributeLayer" );
+
+ ::basegfx::B2DPoint rOutPos = ::basegfx::tools::getPositionRelative( maPathPoly,
+ nValue );
+
+ // TODO(F1): Determine whether the path is
+ // absolute, or shape-relative.
+
+ // interpret path as page-relative. Scale up with page size
+ rOutPos *= maPageSize;
+
+ // TODO(F1): Determine whether the path origin is
+ // absolute, or shape-relative.
+
+ // interpret path as shape-originated. Offset to shape position
+
+ rOutPos += maShapeOrig;
+
+ mpAttrLayer->setPosition( rOutPos );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+
+ return true;
+ }
+
+ virtual double getUnderlyingValue() const
+ {
+ ENSURE_OR_THROW( mpAttrLayer,
+ "PathAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" );
+
+ return 0.0; // though this should be used in concert with
+ // ActivitiesFactory::createSimpleActivity, better
+ // explicitely name our start value.
+ // Permissible range for operator() above is [0,1]
+ }
+
+ private:
+ ::basegfx::B2DPolygon maPathPoly;
+ AnimatableShapeSharedPtr mpShape;
+ ShapeAttributeLayerSharedPtr mpAttrLayer;
+ ShapeManagerSharedPtr mpShapeManager;
+ const ::basegfx::B2DSize maPageSize;
+ ::basegfx::B2DPoint maShapeOrig;
+ const int mnFlags;
+ bool mbAnimationStarted;
+ sal_Int16 mnAdditive;
+ };
+
+
+ /** GenericAnimation template
+
+ This template makes heavy use of SFINAE, only one of
+ the operator()() methods will compile for each of the
+ base classes.
+
+ Note that we omit the virtual keyword on the
+ operator()() overrides and getUnderlyingValue() methods on
+ purpose; those that actually do override baseclass
+ virtual methods inherit the property, and the others
+ won't increase our vtable. What's more, having all
+ those methods in the vtable actually creates POIs for
+ them, which breaks the whole SFINAE concept (IOW, this
+ template won't compile any longer).
+
+ @tpl AnimationBase
+ Type of animation to generate (determines the
+ interface GenericAnimation will implement). Must be
+ one of NumberAnimation, ColorAnimation,
+ StringAnimation, PairAnimation or BoolAnimation.
+
+ @tpl ModifierFunctor
+ Type of a functor object, which can optionally be used to
+ modify the getter/setter values.
+ */
+ template< typename AnimationBase, typename ModifierFunctor > class GenericAnimation : public AnimationBase
+ {
+ public:
+ typedef typename AnimationBase::ValueType ValueT;
+
+ /** Create generic animation
+
+ @param pIsValid
+ Function pointer to one of the is*Valid
+ methods. Used to either take the given getter
+ method, or the given default value for the start value.
+
+ @param rDefaultValue
+ Default value, to take as the start value if
+ is*Valid returns false.
+
+ @param pGetValue
+ Getter method, to fetch start value if valid.
+
+ @param pSetValue
+ Setter method. This one puts the current animation
+ value to the ShapeAttributeLayer.
+
+ @param rGetterModifier
+ Modifies up values retrieved from the pGetValue method.
+ Must provide operator()( const ValueT& ) method.
+
+ @param rSetterModifier
+ Modifies up values before passing them to the pSetValue method.
+ Must provide operator()( const ValueT& ) method.
+ */
+ GenericAnimation( const ShapeManagerSharedPtr& rShapeManager,
+ int nFlags,
+ bool (ShapeAttributeLayer::*pIsValid)() const,
+ const ValueT& rDefaultValue,
+ ValueT (ShapeAttributeLayer::*pGetValue)() const,
+ void (ShapeAttributeLayer::*pSetValue)( const ValueT& ),
+ const ModifierFunctor& rGetterModifier,
+ const ModifierFunctor& rSetterModifier ) :
+ mpShape(),
+ mpAttrLayer(),
+ mpShapeManager( rShapeManager ),
+ mpIsValidFunc(pIsValid),
+ mpGetValueFunc(pGetValue),
+ mpSetValueFunc(pSetValue),
+ maGetterModifier( rGetterModifier ),
+ maSetterModifier( rSetterModifier ),
+ mnFlags( nFlags ),
+ maDefaultValue(rDefaultValue),
+ mbAnimationStarted( false )
+ {
+ ENSURE_OR_THROW( rShapeManager,
+ "GenericAnimation::GenericAnimation(): Invalid ShapeManager" );
+ ENSURE_OR_THROW( pIsValid && pGetValue && pSetValue,
+ "GenericAnimation::GenericAnimation(): One of the method pointers is NULL" );
+ }
+
+ ~GenericAnimation()
+ {
+ end_();
+ }
+
+ // Animation interface
+ // -------------------
+ virtual void prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& )
+ {}
+
+ virtual void start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer )
+ {
+ OSL_ENSURE( !mpShape,
+ "GenericAnimation::start(): Shape already set" );
+ OSL_ENSURE( !mpAttrLayer,
+ "GenericAnimation::start(): Attribute layer already set" );
+
+ mpShape = rShape;
+ mpAttrLayer = rAttrLayer;
+
+ ENSURE_OR_THROW( rShape,
+ "GenericAnimation::start(): Invalid shape" );
+ ENSURE_OR_THROW( rAttrLayer,
+ "GenericAnimation::start(): Invalid attribute layer" );
+
+ // only start animation once per repeated start() call,
+ // and only if sprites should be used for display
+ if( !mbAnimationStarted )
+ {
+ mbAnimationStarted = true;
+
+ if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) )
+ mpShapeManager->enterAnimationMode( mpShape );
+ }
+ }
+
+ virtual void end() { end_(); }
+ void end_()
+ {
+ // TODO(Q2): Factor out common code (most
+ // prominently start() and end()) into base class
+
+ // only stop animation once per repeated end() call,
+ // and only if sprites are used for display
+ if( mbAnimationStarted )
+ {
+ mbAnimationStarted = false;
+
+ if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) )
+ mpShapeManager->leaveAnimationMode( mpShape );
+
+ // Attention, this notifyShapeUpdate() is
+ // somewhat delicate here. Calling it
+ // unconditional (i.e. not guarded by
+ // mbAnimationStarted) will lead to shapes
+ // snapping back to their original state just
+ // before the slide ends. Not calling it at
+ // all might swallow final animation
+ // states. The current implementation relies
+ // on the fact that end() is either called by
+ // the Activity (then, the last animation
+ // state has been set, and corresponds to the
+ // shape's hold state), or by the animation
+ // node (then, it's a forced end, and we
+ // _have_ to snap back).
+ //
+ // To reiterate: normally, we're called from
+ // the Activity first, thus the
+ // notifyShapeUpdate() below will update to
+ // the last activity value.
+
+ // force shape update, activity might have changed
+ // state in the last round.
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+ }
+ }
+
+ // Derived Animation interface
+ // ---------------------------
+
+ /** For by-reference interfaces (B2DTuple, OUString)
+ */
+ bool operator()( const ValueT& x )
+ {
+ ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape,
+ "GenericAnimation::operator(): Invalid ShapeAttributeLayer" );
+
+ ((*mpAttrLayer).*mpSetValueFunc)( maSetterModifier( x ) );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+
+ return true;
+ }
+
+ /** For by-value interfaces (bool, double)
+ */
+ bool operator()( ValueT x )
+ {
+ ENSURE_OR_RETURN_FALSE( mpAttrLayer && mpShape,
+ "GenericAnimation::operator(): Invalid ShapeAttributeLayer" );
+
+ ((*mpAttrLayer).*mpSetValueFunc)( maSetterModifier( x ) );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+
+ return true;
+ }
+
+ ValueT getUnderlyingValue() const
+ {
+ ENSURE_OR_THROW( mpAttrLayer,
+ "GenericAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" );
+
+ // deviated from the (*shared_ptr).*mpFuncPtr
+ // notation here, since gcc does not seem to parse
+ // that as a member function call anymore.
+ if( (mpAttrLayer.get()->*mpIsValidFunc)() )
+ return maGetterModifier( ((*mpAttrLayer).*mpGetValueFunc)() );
+ else
+ return maDefaultValue;
+ }
+
+ private:
+ AnimatableShapeSharedPtr mpShape;
+ ShapeAttributeLayerSharedPtr mpAttrLayer;
+ ShapeManagerSharedPtr mpShapeManager;
+ bool (ShapeAttributeLayer::*mpIsValidFunc)() const;
+ ValueT (ShapeAttributeLayer::*mpGetValueFunc)() const;
+ void (ShapeAttributeLayer::*mpSetValueFunc)( const ValueT& );
+
+ ModifierFunctor maGetterModifier;
+ ModifierFunctor maSetterModifier;
+
+ const int mnFlags;
+
+ const ValueT maDefaultValue;
+ bool mbAnimationStarted;
+ };
+
+ //Current c++0x draft (apparently) has std::identity, but not operator()
+ template<typename T> struct SGI_identity : public std::unary_function<T,T>
+ {
+ T& operator()(T& x) const { return x; }
+ const T& operator()(const T& x) const { return x; }
+ };
+
+ /** Function template wrapper around GenericAnimation template
+
+ @tpl AnimationBase
+ Type of animation to generate (determines the
+ interface GenericAnimation will implement).
+ */
+ template< typename AnimationBase > ::boost::shared_ptr< AnimationBase >
+ makeGenericAnimation( const ShapeManagerSharedPtr& rShapeManager,
+ int nFlags,
+ bool (ShapeAttributeLayer::*pIsValid)() const,
+ const typename AnimationBase::ValueType& rDefaultValue,
+ typename AnimationBase::ValueType (ShapeAttributeLayer::*pGetValue)() const,
+ void (ShapeAttributeLayer::*pSetValue)( const typename AnimationBase::ValueType& ) )
+ {
+ return ::boost::shared_ptr< AnimationBase >(
+ new GenericAnimation< AnimationBase,
+ SGI_identity< typename AnimationBase::ValueType > >(
+ rShapeManager,
+ nFlags,
+ pIsValid,
+ rDefaultValue,
+ pGetValue,
+ pSetValue,
+ // no modification necessary, use identity functor here
+ SGI_identity< typename AnimationBase::ValueType >(),
+ SGI_identity< typename AnimationBase::ValueType >() ) );
+ }
+
+ class Scaler
+ {
+ public:
+ Scaler( double nScale ) :
+ mnScale( nScale )
+ {
+ }
+
+ double operator()( double nVal ) const
+ {
+ return mnScale * nVal;
+ }
+
+ private:
+ double mnScale;
+ };
+
+ /** Overload for NumberAnimations which need scaling (width,height,x,y currently)
+ */
+ NumberAnimationSharedPtr makeGenericAnimation( const ShapeManagerSharedPtr& rShapeManager,
+ int nFlags,
+ bool (ShapeAttributeLayer::*pIsValid)() const,
+ double nDefaultValue,
+ double (ShapeAttributeLayer::*pGetValue)() const,
+ void (ShapeAttributeLayer::*pSetValue)( const double& ),
+ double nScaleValue )
+ {
+ return NumberAnimationSharedPtr(
+ new GenericAnimation< NumberAnimation, Scaler >( rShapeManager,
+ nFlags,
+ pIsValid,
+ nDefaultValue / nScaleValue,
+ pGetValue,
+ pSetValue,
+ Scaler( 1.0/nScaleValue ),
+ Scaler( nScaleValue ) ) );
+ }
+
+
+ uno::Any getShapeDefault( const AnimatableShapeSharedPtr& rShape,
+ const ::rtl::OUString& rPropertyName )
+ {
+ uno::Reference< drawing::XShape > xShape( rShape->getXShape() );
+
+ if( !xShape.is() )
+ return uno::Any(); // no regular shape, no defaults available
+
+
+ // extract relevant value from XShape's PropertySet
+ uno::Reference< beans::XPropertySet > xPropSet( xShape,
+ uno::UNO_QUERY );
+
+ ENSURE_OR_THROW( xPropSet.is(),
+ "getShapeDefault(): Cannot query property set from shape" );
+
+ return xPropSet->getPropertyValue( rPropertyName );
+ }
+
+ template< typename ValueType > ValueType getDefault( const AnimatableShapeSharedPtr& rShape,
+ const ::rtl::OUString& rPropertyName )
+ {
+ const uno::Any& rAny( getShapeDefault( rShape,
+ rPropertyName ) );
+
+ if( !rAny.hasValue() )
+ {
+ OSL_FAIL( "getDefault(): cannot get requested shape property" );
+ OSL_TRACE( "getDefault(): cannot get '%s' shape property",
+ ::rtl::OUStringToOString( rPropertyName,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ return ValueType();
+ }
+ else
+ {
+ ValueType aValue = ValueType();
+
+ if( !(rAny >>= aValue) )
+ {
+ OSL_FAIL( "getDefault(): cannot extract requested shape property" );
+ OSL_TRACE( "getDefault(): cannot extract '%s' shape property",
+ ::rtl::OUStringToOString( rPropertyName,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ return ValueType();
+ }
+
+ return aValue;
+ }
+ }
+
+ template<> RGBColor getDefault< RGBColor >( const AnimatableShapeSharedPtr& rShape,
+ const ::rtl::OUString& rPropertyName )
+ {
+ const uno::Any& rAny( getShapeDefault( rShape,
+ rPropertyName ) );
+
+ if( !rAny.hasValue() )
+ {
+ OSL_FAIL( "getDefault(): cannot get requested shape color property" );
+ OSL_TRACE( "getDefault(): cannot get '%s' shape color property",
+ ::rtl::OUStringToOString( rPropertyName,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ return RGBColor();
+ }
+ else
+ {
+ sal_Int32 nValue = 0;
+
+ if( !(rAny >>= nValue) )
+ {
+ OSL_FAIL( "getDefault(): cannot extract requested shape color property" );
+ OSL_TRACE( "getDefault(): cannot extract '%s' shape color property",
+ ::rtl::OUStringToOString( rPropertyName,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ return RGBColor();
+ }
+
+ // convert from 0xAARRGGBB API color to 0xRRGGBB00
+ // canvas color
+ return RGBColor( (nValue << 8U) & 0xFFFFFF00U );
+ }
+ }
+ }
+
+ AnimationFactory::AttributeClass AnimationFactory::classifyAttributeName( const ::rtl::OUString& rAttrName )
+ {
+ // ATTENTION: When changing this map, also the create*PropertyAnimation() methods must
+ // be checked and possibly adapted in their switch statements
+
+ // TODO(Q2): Since this map must be coherent with the various switch statements
+ // in the create*PropertyAnimation methods, try to unify into a single method or table
+ switch( mapAttributeName( rAttrName ) )
+ {
+ default:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_INVALID:
+ return CLASS_UNKNOWN_PROPERTY;
+
+ case ATTRIBUTE_CHAR_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_DIMCOLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_COLOR:
+ return CLASS_COLOR_PROPERTY;
+
+ case ATTRIBUTE_CHAR_FONT_NAME:
+ return CLASS_STRING_PROPERTY;
+
+ case ATTRIBUTE_VISIBILITY:
+ return CLASS_BOOL_PROPERTY;
+
+ case ATTRIBUTE_CHAR_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_WEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_ROTATION:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_OPACITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_ROTATE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_Y:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_WIDTH:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_Y:
+ return CLASS_NUMBER_PROPERTY;
+
+ case ATTRIBUTE_CHAR_UNDERLINE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_POSTURE:
+ return CLASS_ENUM_PROPERTY;
+ }
+ }
+
+ NumberAnimationSharedPtr AnimationFactory::createNumberPropertyAnimation( const ::rtl::OUString& rAttrName,
+ const AnimatableShapeSharedPtr& rShape,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& rSlideSize,
+ int nFlags )
+ {
+ // ATTENTION: When changing this map, also the classifyAttributeName() method must
+ // be checked and possibly adapted in their switch statement
+ switch( mapAttributeName( rAttrName ) )
+ {
+ default:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_INVALID:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createNumberPropertyAnimation(): Unknown attribute" );
+ break;
+
+ case ATTRIBUTE_CHAR_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_FONT_NAME:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_POSTURE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_UNDERLINE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_DIMCOLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_VISIBILITY:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createNumberPropertyAnimation(): Attribute type mismatch" );
+ break;
+
+ case ATTRIBUTE_CHAR_HEIGHT:
+ return makeGenericAnimation<NumberAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isCharScaleValid,
+ 1.0, // CharHeight is a relative attribute, thus
+ // default is 1.0
+ &ShapeAttributeLayer::getCharScale,
+ &ShapeAttributeLayer::setCharScale );
+
+ case ATTRIBUTE_CHAR_WEIGHT:
+ return makeGenericAnimation<NumberAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isCharWeightValid,
+ getDefault<double>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getCharWeight,
+ &ShapeAttributeLayer::setCharWeight );
+
+ case ATTRIBUTE_CHAR_ROTATION:
+ return makeGenericAnimation<NumberAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isCharRotationAngleValid,
+ getDefault<double>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getCharRotationAngle,
+ &ShapeAttributeLayer::setCharRotationAngle );
+
+ case ATTRIBUTE_HEIGHT:
+ return makeGenericAnimation( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isHeightValid,
+ // TODO(F1): Check whether _shape_ bounds are correct here.
+ // Theoretically, our AttrLayer is way down the stack, and
+ // we only have to consider _that_ value, not the one from
+ // the top of the stack as returned by Shape::getBounds()
+ rShape->getBounds().getHeight(),
+ &ShapeAttributeLayer::getHeight,
+ &ShapeAttributeLayer::setHeight,
+ // convert expression parser value from relative page size
+ rSlideSize.getY() );
+
+ case ATTRIBUTE_OPACITY:
+ return makeGenericAnimation<NumberAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isAlphaValid,
+ // TODO(F1): Provide shape default here (FillTransparency?)
+ 1.0,
+ &ShapeAttributeLayer::getAlpha,
+ &ShapeAttributeLayer::setAlpha );
+
+ case ATTRIBUTE_ROTATE:
+ return makeGenericAnimation<NumberAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isRotationAngleValid,
+ // NOTE: Since we paint the shape as-is from metafile,
+ // rotation angle is always 0.0, even for rotated shapes
+ 0.0,
+ &ShapeAttributeLayer::getRotationAngle,
+ &ShapeAttributeLayer::setRotationAngle );
+
+ case ATTRIBUTE_SKEW_X:
+ return makeGenericAnimation<NumberAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isShearXAngleValid,
+ // TODO(F1): Is there any shape property for skew?
+ 0.0,
+ &ShapeAttributeLayer::getShearXAngle,
+ &ShapeAttributeLayer::setShearXAngle );
+
+ case ATTRIBUTE_SKEW_Y:
+ return makeGenericAnimation<NumberAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isShearYAngleValid,
+ // TODO(F1): Is there any shape property for skew?
+ 0.0,
+ &ShapeAttributeLayer::getShearYAngle,
+ &ShapeAttributeLayer::setShearYAngle );
+
+ case ATTRIBUTE_WIDTH:
+ return makeGenericAnimation( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isWidthValid,
+ // TODO(F1): Check whether _shape_ bounds are correct here.
+ // Theoretically, our AttrLayer is way down the stack, and
+ // we only have to consider _that_ value, not the one from
+ // the top of the stack as returned by Shape::getBounds()
+ rShape->getBounds().getWidth(),
+ &ShapeAttributeLayer::getWidth,
+ &ShapeAttributeLayer::setWidth,
+ // convert expression parser value from relative page size
+ rSlideSize.getX() );
+
+ case ATTRIBUTE_POS_X:
+ return makeGenericAnimation( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isPosXValid,
+ // TODO(F1): Check whether _shape_ bounds are correct here.
+ // Theoretically, our AttrLayer is way down the stack, and
+ // we only have to consider _that_ value, not the one from
+ // the top of the stack as returned by Shape::getBounds()
+ rShape->getBounds().getCenterX(),
+ &ShapeAttributeLayer::getPosX,
+ &ShapeAttributeLayer::setPosX,
+ // convert expression parser value from relative page size
+ rSlideSize.getX() );
+
+ case ATTRIBUTE_POS_Y:
+ return makeGenericAnimation( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isPosYValid,
+ // TODO(F1): Check whether _shape_ bounds are correct here.
+ // Theoretically, our AttrLayer is way down the stack, and
+ // we only have to consider _that_ value, not the one from
+ // the top of the stack as returned by Shape::getBounds()
+ rShape->getBounds().getCenterY(),
+ &ShapeAttributeLayer::getPosY,
+ &ShapeAttributeLayer::setPosY,
+ // convert expression parser value from relative page size
+ rSlideSize.getY() );
+ }
+
+ return NumberAnimationSharedPtr();
+ }
+
+ EnumAnimationSharedPtr AnimationFactory::createEnumPropertyAnimation( const ::rtl::OUString& rAttrName,
+ const AnimatableShapeSharedPtr& rShape,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& /*rSlideSize*/,
+ int nFlags )
+ {
+ // ATTENTION: When changing this map, also the classifyAttributeName() method must
+ // be checked and possibly adapted in their switch statement
+ switch( mapAttributeName( rAttrName ) )
+ {
+ default:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_INVALID:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createEnumPropertyAnimation(): Unknown attribute" );
+ break;
+
+ case ATTRIBUTE_CHAR_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_FONT_NAME:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_DIMCOLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_VISIBILITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_WEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_ROTATION:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_OPACITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_ROTATE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_Y:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_WIDTH:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_Y:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createEnumPropertyAnimation(): Attribute type mismatch" );
+ break;
+
+
+ case ATTRIBUTE_FILL_STYLE:
+ return makeGenericAnimation<EnumAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isFillStyleValid,
+ sal::static_int_cast<sal_Int16>(
+ getDefault<drawing::FillStyle>( rShape, rAttrName )),
+ &ShapeAttributeLayer::getFillStyle,
+ &ShapeAttributeLayer::setFillStyle );
+
+ case ATTRIBUTE_LINE_STYLE:
+ return makeGenericAnimation<EnumAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isLineStyleValid,
+ sal::static_int_cast<sal_Int16>(
+ getDefault<drawing::LineStyle>( rShape, rAttrName )),
+ &ShapeAttributeLayer::getLineStyle,
+ &ShapeAttributeLayer::setLineStyle );
+
+ case ATTRIBUTE_CHAR_POSTURE:
+ return makeGenericAnimation<EnumAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isCharPostureValid,
+ sal::static_int_cast<sal_Int16>(
+ getDefault<awt::FontSlant>( rShape, rAttrName )),
+ &ShapeAttributeLayer::getCharPosture,
+ &ShapeAttributeLayer::setCharPosture );
+
+ case ATTRIBUTE_CHAR_UNDERLINE:
+ return makeGenericAnimation<EnumAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isUnderlineModeValid,
+ getDefault<sal_Int16>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getUnderlineMode,
+ &ShapeAttributeLayer::setUnderlineMode );
+ }
+
+ return EnumAnimationSharedPtr();
+ }
+
+ ColorAnimationSharedPtr AnimationFactory::createColorPropertyAnimation( const ::rtl::OUString& rAttrName,
+ const AnimatableShapeSharedPtr& rShape,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& /*rSlideSize*/,
+ int nFlags )
+ {
+ // ATTENTION: When changing this map, also the classifyAttributeName() method must
+ // be checked and possibly adapted in their switch statement
+ switch( mapAttributeName( rAttrName ) )
+ {
+ default:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_INVALID:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createColorPropertyAnimation(): Unknown attribute" );
+ break;
+
+ case ATTRIBUTE_CHAR_FONT_NAME:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_POSTURE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_ROTATION:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_UNDERLINE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_WEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_OPACITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_ROTATE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_Y:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_VISIBILITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_WIDTH:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_Y:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createColorPropertyAnimation(): Attribute type mismatch" );
+ break;
+
+ case ATTRIBUTE_CHAR_COLOR:
+ return makeGenericAnimation<ColorAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isCharColorValid,
+ getDefault<RGBColor>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getCharColor,
+ &ShapeAttributeLayer::setCharColor );
+
+ case ATTRIBUTE_COLOR:
+ // TODO(F2): This is just mapped to fill color to make it work
+ return makeGenericAnimation<ColorAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isFillColorValid,
+ getDefault<RGBColor>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getFillColor,
+ &ShapeAttributeLayer::setFillColor );
+
+ case ATTRIBUTE_DIMCOLOR:
+ return makeGenericAnimation<ColorAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isDimColorValid,
+ getDefault<RGBColor>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getDimColor,
+ &ShapeAttributeLayer::setDimColor );
+
+ case ATTRIBUTE_FILL_COLOR:
+ return makeGenericAnimation<ColorAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isFillColorValid,
+ getDefault<RGBColor>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getFillColor,
+ &ShapeAttributeLayer::setFillColor );
+
+ case ATTRIBUTE_LINE_COLOR:
+ return makeGenericAnimation<ColorAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isLineColorValid,
+ getDefault<RGBColor>( rShape, rAttrName ),
+ &ShapeAttributeLayer::getLineColor,
+ &ShapeAttributeLayer::setLineColor );
+ }
+
+ return ColorAnimationSharedPtr();
+ }
+
+ PairAnimationSharedPtr AnimationFactory::createPairPropertyAnimation( const AnimatableShapeSharedPtr& rShape,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& rSlideSize,
+ sal_Int16 nTransformType,
+ int nFlags )
+ {
+ const ::basegfx::B2DRectangle& rBounds( rShape->getBounds() );
+
+ switch( nTransformType )
+ {
+ case animations::AnimationTransformType::SCALE:
+ return PairAnimationSharedPtr(
+ new TupleAnimation< ::basegfx::B2DSize >(
+ rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isWidthValid,
+ &ShapeAttributeLayer::isHeightValid,
+ // TODO(F1): Check whether _shape_ bounds are correct here.
+ // Theoretically, our AttrLayer is way down the stack, and
+ // we only have to consider _that_ value, not the one from
+ // the top of the stack as returned by Shape::getBounds()
+ rBounds.getRange(),
+ rBounds.getRange(),
+ &ShapeAttributeLayer::getWidth,
+ &ShapeAttributeLayer::getHeight,
+ &ShapeAttributeLayer::setSize ) );
+
+ case animations::AnimationTransformType::TRANSLATE:
+ return PairAnimationSharedPtr(
+ new TupleAnimation< ::basegfx::B2DPoint >(
+ rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isPosXValid,
+ &ShapeAttributeLayer::isPosYValid,
+ // TODO(F1): Check whether _shape_ bounds are correct here.
+ // Theoretically, our AttrLayer is way down the stack, and
+ // we only have to consider _that_ value, not the one from
+ // the top of the stack as returned by Shape::getBounds()
+ rBounds.getCenter(),
+ rSlideSize,
+ &ShapeAttributeLayer::getPosX,
+ &ShapeAttributeLayer::getPosY,
+ &ShapeAttributeLayer::setPosition ) );
+
+ default:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createPairPropertyAnimation(): Attribute type mismatch" );
+ break;
+ }
+
+ return PairAnimationSharedPtr();
+ }
+
+ StringAnimationSharedPtr AnimationFactory::createStringPropertyAnimation( const ::rtl::OUString& rAttrName,
+ const AnimatableShapeSharedPtr& rShape,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& /*rSlideSize*/,
+ int nFlags )
+ {
+ // ATTENTION: When changing this map, also the classifyAttributeName() method must
+ // be checked and possibly adapted in their switch statement
+ switch( mapAttributeName( rAttrName ) )
+ {
+ default:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_INVALID:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createStringPropertyAnimation(): Unknown attribute" );
+ break;
+
+ case ATTRIBUTE_CHAR_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_ROTATION:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_UNDERLINE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_DIMCOLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_OPACITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_ROTATE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_Y:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_VISIBILITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_WIDTH:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_Y:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_POSTURE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_WEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_STYLE:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createStringPropertyAnimation(): Attribute type mismatch" );
+ break;
+
+ case ATTRIBUTE_CHAR_FONT_NAME:
+ return makeGenericAnimation<StringAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isFontFamilyValid,
+ getDefault< ::rtl::OUString >( rShape, rAttrName ),
+ &ShapeAttributeLayer::getFontFamily,
+ &ShapeAttributeLayer::setFontFamily );
+ }
+
+ return StringAnimationSharedPtr();
+ }
+
+ BoolAnimationSharedPtr AnimationFactory::createBoolPropertyAnimation( const ::rtl::OUString& rAttrName,
+ const AnimatableShapeSharedPtr& /*rShape*/,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& /*rSlideSize*/,
+ int nFlags )
+ {
+ // ATTENTION: When changing this map, also the classifyAttributeName() method must
+ // be checked and possibly adapted in their switch statement
+ switch( mapAttributeName( rAttrName ) )
+ {
+ default:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_INVALID:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createBoolPropertyAnimation(): Unknown attribute" );
+ break;
+
+ case ATTRIBUTE_CHAR_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_FONT_NAME:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_POSTURE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_ROTATION:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_WEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_DIMCOLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_FILL_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_HEIGHT:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_COLOR:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_LINE_STYLE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_OPACITY:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_ROTATE:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_SKEW_Y:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_WIDTH:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_X:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_POS_Y:
+ // FALLTHROUGH intended
+ case ATTRIBUTE_CHAR_UNDERLINE:
+ ENSURE_OR_THROW( false,
+ "AnimationFactory::createBoolPropertyAnimation(): Attribute type mismatch" );
+ break;
+
+ case ATTRIBUTE_VISIBILITY:
+ return makeGenericAnimation<BoolAnimation>( rShapeManager,
+ nFlags,
+ &ShapeAttributeLayer::isVisibilityValid,
+ // TODO(F1): Is there a corresponding shape property?
+ true,
+ &ShapeAttributeLayer::getVisibility,
+ &ShapeAttributeLayer::setVisibility );
+ }
+
+ return BoolAnimationSharedPtr();
+ }
+
+ NumberAnimationSharedPtr AnimationFactory::createPathMotionAnimation( const ::rtl::OUString& rSVGDPath,
+ sal_Int16 nAdditive,
+ const AnimatableShapeSharedPtr& /*rShape*/,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& rSlideSize,
+ int nFlags )
+ {
+ return NumberAnimationSharedPtr(
+ new PathAnimation( rSVGDPath, nAdditive,
+ rShapeManager,
+ rSlideSize,
+ nFlags ) );
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationaudionode.cxx b/slideshow/source/engine/animationnodes/animationaudionode.cxx
new file mode 100644
index 000000000000..64c91e2a2519
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationaudionode.cxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include "eventqueue.hxx"
+#include "animationaudionode.hxx"
+#include "delayevent.hxx"
+#include "tools.hxx"
+#include "nodetools.hxx"
+#include "boost/bind.hpp"
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+AnimationAudioNode::AnimationAudioNode(
+ const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ : BaseNode( xNode, rParent, rContext ),
+ mxAudioNode( xNode, uno::UNO_QUERY_THROW ),
+ maSoundURL(),
+ mpPlayer()
+{
+ mxAudioNode->getSource() >>= maSoundURL;
+
+ OSL_ENSURE( maSoundURL.getLength(),
+ "could not extract sound source URL/empty URL string" );
+
+ ENSURE_OR_THROW( getContext().mxComponentContext.is(),
+ "Invalid component context" );
+}
+
+void AnimationAudioNode::dispose()
+{
+ resetPlayer();
+ mxAudioNode.clear();
+ BaseNode::dispose();
+}
+
+void AnimationAudioNode::activate_st()
+{
+ createPlayer();
+
+ AnimationEventHandlerSharedPtr aHandler(
+ boost::dynamic_pointer_cast<AnimationEventHandler>( getSelf() ) );
+ OSL_ENSURE( aHandler,
+ "could not cast self to AnimationEventHandler?" );
+ getContext().mrEventMultiplexer.addCommandStopAudioHandler( aHandler );
+
+ if (mpPlayer && mpPlayer->startPlayback())
+ {
+ // TODO(F2): Handle end time attribute, too
+ if( getXAnimationNode()->getDuration().hasValue() )
+ {
+ scheduleDeactivationEvent();
+ }
+ else
+ {
+ // no node duration. Take inherent media time, then
+ scheduleDeactivationEvent(
+ makeDelay( boost::bind( &AnimationNode::deactivate, getSelf() ),
+ mpPlayer->getDuration(),
+ "AnimationAudioNode::deactivate with delay") );
+ }
+ }
+ else
+ {
+ // deactivate ASAP:
+ scheduleDeactivationEvent(
+ makeEvent( boost::bind( &AnimationNode::deactivate, getSelf() ),
+ "AnimationAudioNode::deactivate without delay") );
+ }
+}
+
+// TODO(F2): generate deactivation event, when sound
+// is over
+
+void AnimationAudioNode::deactivate_st( NodeState /*eDestState*/ )
+{
+ AnimationEventHandlerSharedPtr aHandler(
+ boost::dynamic_pointer_cast<AnimationEventHandler>( getSelf() ) );
+ OSL_ENSURE( aHandler,
+ "could not cas self to AnimationEventHandler?" );
+ getContext().mrEventMultiplexer.removeCommandStopAudioHandler( aHandler );
+
+ // force-end sound
+ if (mpPlayer)
+ {
+ mpPlayer->stopPlayback();
+ resetPlayer();
+ }
+
+ // notify _after_ state change:
+ getContext().mrEventQueue.addEvent(
+ makeEvent( boost::bind( &EventMultiplexer::notifyAudioStopped,
+ boost::ref(getContext().mrEventMultiplexer),
+ getSelf() ),
+ "AnimationAudioNode::notifyAudioStopped") );
+}
+
+bool AnimationAudioNode::hasPendingAnimation() const
+{
+ // force slide to use the animation framework
+ // (otherwise, a single sound on the slide would
+ // not be played).
+ return true;
+}
+
+void AnimationAudioNode::createPlayer() const
+{
+ if (mpPlayer)
+ return;
+
+ try
+ {
+ mpPlayer = SoundPlayer::create( getContext().mrEventMultiplexer,
+ maSoundURL,
+ getContext().mxComponentContext );
+ }
+ catch( lang::NoSupportException& )
+ {
+ // catch possible exceptions from SoundPlayer,
+ // since being not able to playback the sound
+ // is not a hard error here (remainder of the
+ // animations should still work).
+ }
+}
+
+void AnimationAudioNode::resetPlayer() const
+{
+ if (mpPlayer)
+ {
+ mpPlayer->stopPlayback();
+ mpPlayer->dispose();
+ mpPlayer.reset();
+ }
+}
+
+bool AnimationAudioNode::handleAnimationEvent(
+ const AnimationNodeSharedPtr& /*rNode*/ )
+{
+ // TODO(F2): for now we support only STOPAUDIO events.
+ deactivate();
+ return true;
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationaudionode.hxx b/slideshow/source/engine/animationnodes/animationaudionode.hxx
new file mode 100644
index 000000000000..ab2877a99784
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationaudionode.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONAUDIONODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONAUDIONODE_HXX
+
+#include "basecontainernode.hxx"
+#include "soundplayer.hxx"
+#include "com/sun/star/animations/XAnimationNode.hpp"
+#include "com/sun/star/animations/XAudio.hpp"
+
+namespace slideshow {
+namespace internal {
+
+/** Audio node.
+
+ This animation node contains an audio effect. Duration and
+ start/stop behaviour is affected by the referenced audio
+ file.
+*/
+class AnimationAudioNode : public BaseNode, public AnimationEventHandler
+{
+public:
+ AnimationAudioNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext );
+
+protected:
+ virtual void dispose();
+
+private:
+ virtual void activate_st();
+ virtual void deactivate_st( NodeState eDestState );
+ virtual bool hasPendingAnimation() const;
+
+ /// overriden, because we need to deal with STOPAUDIO commands
+ virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode );
+
+private:
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAudio > mxAudioNode;
+ ::rtl::OUString maSoundURL;
+ mutable SoundPlayerSharedPtr mpPlayer;
+
+ void createPlayer() const;
+ void resetPlayer() const;
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONAUDIONODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationbasenode.cxx b/slideshow/source/engine/animationnodes/animationbasenode.cxx
new file mode 100644
index 000000000000..22c4266ee00c
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationbasenode.cxx
@@ -0,0 +1,492 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/anytostring.hxx>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+
+#include "nodetools.hxx"
+#include "doctreenode.hxx"
+#include "animationbasenode.hxx"
+#include "delayevent.hxx"
+#include "framerate.hxx"
+
+#include <boost/bind.hpp>
+#include <boost/optional.hpp>
+#include <algorithm>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+AnimationBaseNode::AnimationBaseNode(
+ const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ : BaseNode( xNode, rParent, rContext ),
+ mxAnimateNode( xNode, uno::UNO_QUERY_THROW ),
+ maAttributeLayerHolder(),
+ maSlideSize( rContext.maSlideSize ),
+ mpActivity(),
+ mpShape(),
+ mpShapeSubset(),
+ mpSubsetManager(rContext.maContext.mpSubsettableShapeManager),
+ mbIsIndependentSubset( rContext.mbIsIndependentSubset )
+{
+ // extract native node targets
+ // ===========================
+
+ // plain shape target
+ uno::Reference< drawing::XShape > xShape( mxAnimateNode->getTarget(),
+ uno::UNO_QUERY );
+
+ // distinguish 5 cases:
+ //
+ // - plain shape target
+ // (NodeContext.mpMasterShapeSubset full set)
+ //
+ // - parent-generated subset (generate an
+ // independent subset)
+ //
+ // - parent-generated subset from iteration
+ // (generate a dependent subset)
+ //
+ // - XShape target at the XAnimatioNode (generate
+ // a plain shape target)
+ //
+ // - ParagraphTarget target at the XAnimationNode
+ // (generate an independent shape subset)
+ if( rContext.mpMasterShapeSubset )
+ {
+ if( rContext.mpMasterShapeSubset->isFullSet() )
+ {
+ // case 1: plain shape target from parent
+ mpShape = rContext.mpMasterShapeSubset->getSubsetShape();
+ }
+ else
+ {
+ // cases 2 & 3: subset shape
+ mpShapeSubset = rContext.mpMasterShapeSubset;
+ }
+ }
+ else
+ {
+ // no parent-provided shape, try to extract
+ // from XAnimationNode - cases 4 and 5
+
+ if( xShape.is() )
+ {
+ mpShape = lookupAttributableShape( getContext().mpSubsettableShapeManager,
+ xShape );
+ }
+ else
+ {
+ // no shape provided. Maybe a ParagraphTarget?
+ presentation::ParagraphTarget aTarget;
+
+ if( !(mxAnimateNode->getTarget() >>= aTarget) )
+ ENSURE_OR_THROW(
+ false, "could not extract any target information" );
+
+ xShape = aTarget.Shape;
+
+ ENSURE_OR_THROW( xShape.is(), "invalid shape in ParagraphTarget" );
+
+ mpShape = lookupAttributableShape( getContext().mpSubsettableShapeManager,
+ xShape );
+
+ // NOTE: For shapes with ParagraphTarget, we ignore
+ // the SubItem property. We implicitely assume that it
+ // is set to ONLY_TEXT.
+ OSL_ENSURE(
+ mxAnimateNode->getSubItem() ==
+ presentation::ShapeAnimationSubType::ONLY_TEXT ||
+ mxAnimateNode->getSubItem() ==
+ presentation::ShapeAnimationSubType::AS_WHOLE,
+ "ParagraphTarget given, but subitem not AS_TEXT or AS_WHOLE? "
+ "Make up your mind, I'll ignore the subitem." );
+
+ // okay, found a ParagraphTarget with a valid XShape. Does the shape
+ // provide the given paragraph?
+ const DocTreeNode& rTreeNode(
+ mpShape->getTreeNodeSupplier().getTreeNode(
+ aTarget.Paragraph,
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ) );
+
+ // CAUTION: the creation of the subset shape
+ // _must_ stay in the node constructor, since
+ // Slide::prefetchShow() initializes shape
+ // attributes right after animation import (or
+ // the Slide class must be changed).
+ mpShapeSubset.reset(
+ new ShapeSubset( mpShape,
+ rTreeNode,
+ mpSubsetManager ));
+
+ // Override NodeContext, and flag this node as
+ // a special independent subset one. This is
+ // important when applying initial attributes:
+ // independent shape subsets must be setup
+ // when the slide starts, since they, as their
+ // name suggest, can have state independent to
+ // the master shape. The following example
+ // might illustrate that: a master shape has
+ // no effect, one of the text paragraphs
+ // within it has an appear effect. Now, the
+ // respective paragraph must be invisible when
+ // the slide is initially shown, and become
+ // visible only when the effect starts.
+ mbIsIndependentSubset = true;
+
+ // already enable subset right here, the
+ // setup of initial shape attributes of
+ // course needs the subset shape
+ // generated, to apply e.g. visibility
+ // changes.
+ mpShapeSubset->enableSubsetShape();
+ }
+ }
+}
+
+void AnimationBaseNode::dispose()
+{
+ if (mpActivity) {
+ mpActivity->dispose();
+ mpActivity.reset();
+ }
+
+ maAttributeLayerHolder.reset();
+ mxAnimateNode.clear();
+ mpShape.reset();
+ mpShapeSubset.reset();
+
+ BaseNode::dispose();
+}
+
+bool AnimationBaseNode::init_st()
+{
+ // if we've still got an old activity lying around, dispose it:
+ if (mpActivity) {
+ mpActivity->dispose();
+ mpActivity.reset();
+ }
+
+ // note: actually disposing the activity too early might cause problems,
+ // because on dequeued() it calls endAnimation(pAnim->end()), thus ending
+ // animation _after_ last screen update.
+ // review that end() is properly called (which calls endAnimation(), too).
+
+ try {
+ // TODO(F2): For restart functionality, we must regenerate activities,
+ // since they are not able to reset their state (or implement _that_)
+ mpActivity = createActivity();
+ }
+ catch (uno::Exception const&) {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(cppu::getCaughtException()),
+ RTL_TEXTENCODING_UTF8 ) );
+ // catch and ignore. We later handle empty activities, but for
+ // other nodes to function properly, the core functionality of
+ // this node must remain up and running.
+ }
+ return true;
+}
+
+bool AnimationBaseNode::resolve_st()
+{
+ // enable shape subset for automatically generated
+ // subsets. Independent subsets are already setup
+ // during construction time. Doing it only here
+ // saves us a lot of sprites and shapes lying
+ // around. This is especially important for
+ // character-wise iterations, since the shape
+ // content (e.g. thousands of characters) would
+ // otherwise be painted character-by-character.
+ if (isDependentSubsettedShape() && mpShapeSubset) {
+ mpShapeSubset->enableSubsetShape();
+ }
+ return true;
+}
+
+void AnimationBaseNode::activate_st()
+{
+ // create new attribute layer
+ maAttributeLayerHolder.createAttributeLayer( getShape() );
+
+ ENSURE_OR_THROW( maAttributeLayerHolder.get(),
+ "Could not generate shape attribute layer" );
+
+ // TODO(Q2): This affects the way mpActivity
+ // works, but is performed here because of
+ // locality (we're fiddling with the additive mode
+ // here, anyway, and it's the only place where we
+ // do). OTOH, maybe the complete additive mode
+ // setup should be moved to the activities.
+
+ // for simple by-animations, the SMIL spec
+ // requires us to emulate "0,by-value" value list
+ // behaviour, with additive mode forced to "sum",
+ // no matter what the input is
+ // (http://www.w3.org/TR/smil20/animation.html#adef-by).
+ if( mxAnimateNode->getBy().hasValue() &&
+ !mxAnimateNode->getTo().hasValue() &&
+ !mxAnimateNode->getFrom().hasValue() )
+ {
+ // force attribute mode to REPLACE (note the
+ // subtle discrepancy to the paragraph above,
+ // where SMIL requires SUM. This is internally
+ // handled by the FromToByActivity, and is
+ // because otherwise DOM values would not be
+ // handled correctly: the activity cannot
+ // determine whether an
+ // Activity::getUnderlyingValue() yields the
+ // DOM value, or already a summed-up conglomerate)
+ //
+ // Note that this poses problems with our
+ // hybrid activity duration (time or min number of frames),
+ // since if activities
+ // exceed their duration, wrong 'by' start
+ // values might arise ('Laser effect')
+ maAttributeLayerHolder.get()->setAdditiveMode(
+ animations::AnimationAdditiveMode::REPLACE );
+ }
+ else
+ {
+ // apply additive mode to newly created Attribute layer
+ maAttributeLayerHolder.get()->setAdditiveMode(
+ mxAnimateNode->getAdditive() );
+ }
+
+ // fake normal animation behaviour, even if we
+ // show nothing. This is the appropriate way to
+ // handle errors on Activity generation, because
+ // maybe all other effects on the slide are
+ // correctly initialized (but won't run, if we
+ // signal an error here)
+ if (mpActivity) {
+ // supply Activity (and the underlying Animation) with
+ // it's AttributeLayer, to perform the animation on
+ mpActivity->setTargets( getShape(), maAttributeLayerHolder.get() );
+
+ // add to activities queue
+ getContext().mrActivitiesQueue.addActivity( mpActivity );
+ }
+ else {
+ // Actually, DO generate the event for empty activity,
+ // to keep the chain of animations running
+ BaseNode::scheduleDeactivationEvent();
+ }
+}
+
+void AnimationBaseNode::deactivate_st( NodeState eDestState )
+{
+ if (eDestState == FROZEN) {
+ if (mpActivity)
+ mpActivity->end();
+ }
+
+ if (isDependentSubsettedShape()) {
+ // for dependent subsets, remove subset shape
+ // from layer, re-integrate subsetted part
+ // back into original shape. For independent
+ // subsets, we cannot make any assumptions
+ // about subset attribute state relative to
+ // master shape, thus, have to keep it. This
+ // will effectively re-integrate the subsetted
+ // part into the original shape (whose
+ // animation will hopefully have ended, too)
+
+ // this statement will save a whole lot of
+ // sprites for iterated text effects, since
+ // those sprites will only exist during the
+ // actual lifetime of the effects
+ if (mpShapeSubset) {
+ mpShapeSubset->disableSubsetShape();
+ }
+ }
+
+ if (eDestState == ENDED) {
+
+ // no shape anymore, no layer needed:
+ maAttributeLayerHolder.reset();
+
+ if (! isDependentSubsettedShape()) {
+
+ // for all other shapes, removing the
+ // attribute layer quite possibly changes
+ // shape display. Thus, force update
+ AttributableShapeSharedPtr const pShape( getShape() );
+
+ // don't anybody dare to check against
+ // pShape->isVisible() here, removing the
+ // attribute layer might actually make the
+ // shape invisible!
+ getContext().mpSubsettableShapeManager->notifyShapeUpdate( pShape );
+ }
+
+ if (mpActivity) {
+ // kill activity, if still running
+ mpActivity->dispose();
+ mpActivity.reset();
+ }
+ }
+}
+
+bool AnimationBaseNode::hasPendingAnimation() const
+{
+ // TODO(F1): This might not always be true. Are there 'inactive'
+ // animation nodes?
+ return true;
+}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+void AnimationBaseNode::showState() const
+{
+ BaseNode::showState();
+
+ VERBOSE_TRACE( "AnimationBaseNode info: independent subset=%s",
+ mbIsIndependentSubset ? "y" : "n" );
+}
+#endif
+
+ActivitiesFactory::CommonParameters
+AnimationBaseNode::fillCommonParameters() const
+{
+ double nDuration = 0.0;
+
+ // TODO(F3): Duration/End handling is barely there
+ if( !(mxAnimateNode->getDuration() >>= nDuration) ) {
+ mxAnimateNode->getEnd() >>= nDuration; // Wah.
+ }
+
+ // minimal duration we fallback to (avoid 0 here!)
+ nDuration = ::std::max( 0.001, nDuration );
+
+ const bool bAutoReverse( mxAnimateNode->getAutoReverse() );
+
+ boost::optional<double> aRepeats;
+ double nRepeats = 0;
+ if( (mxAnimateNode->getRepeatCount() >>= nRepeats) ) {
+ aRepeats.reset( nRepeats );
+ }
+ else {
+ if( (mxAnimateNode->getRepeatDuration() >>= nRepeats) ) {
+ // when repeatDuration is given,
+ // autoreverse does _not_ modify the
+ // active duration. Thus, calc repeat
+ // count with already adapted simple
+ // duration (twice the specified duration)
+
+ // convert duration back to repeat counts
+ if( bAutoReverse )
+ aRepeats.reset( nRepeats / (2.0 * nDuration) );
+ else
+ aRepeats.reset( nRepeats / nDuration );
+ }
+ else {
+ // no double value for both values - Timing::INDEFINITE?
+ animations::Timing eTiming;
+
+ if( !(mxAnimateNode->getRepeatDuration() >>= eTiming) ||
+ eTiming != animations::Timing_INDEFINITE )
+ {
+ if( !(mxAnimateNode->getRepeatCount() >>= eTiming) ||
+ eTiming != animations::Timing_INDEFINITE )
+ {
+ // no indefinite timing, no other values given -
+ // use simple run, i.e. repeat of 1.0
+ aRepeats.reset( 1.0 );
+ }
+ }
+ }
+ }
+
+ // calc accel/decel:
+ double nAcceleration = 0.0;
+ double nDeceleration = 0.0;
+ BaseNodeSharedPtr const pSelf( getSelf() );
+ for ( boost::shared_ptr<BaseNode> pNode( pSelf );
+ pNode; pNode = pNode->getParentNode() )
+ {
+ uno::Reference<animations::XAnimationNode> const xAnimationNode(
+ pNode->getXAnimationNode() );
+ nAcceleration = std::max( nAcceleration,
+ xAnimationNode->getAcceleration() );
+ nDeceleration = std::max( nDeceleration,
+ xAnimationNode->getDecelerate() );
+ }
+
+ EventSharedPtr pEndEvent;
+ if (pSelf) {
+ pEndEvent = makeEvent(
+ boost::bind( &AnimationNode::deactivate, pSelf ),
+ "AnimationBaseNode::deactivate");
+ }
+
+ // Calculate the minimum frame count that depends on the duration and
+ // the minimum frame count.
+ const sal_Int32 nMinFrameCount (basegfx::clamp<sal_Int32>(
+ basegfx::fround(nDuration * FrameRate::MinimumFramesPerSecond), 1, 10));
+
+ return ActivitiesFactory::CommonParameters(
+ pEndEvent,
+ getContext().mrEventQueue,
+ getContext().mrActivitiesQueue,
+ nDuration,
+ nMinFrameCount,
+ bAutoReverse,
+ aRepeats,
+ nAcceleration,
+ nDeceleration,
+ getShape(),
+ getSlideSize());
+}
+
+AttributableShapeSharedPtr AnimationBaseNode::getShape() const
+{
+ // any subsetting at all?
+ if (mpShapeSubset)
+ return mpShapeSubset->getSubsetShape();
+ else
+ return mpShape; // nope, plain shape always
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationbasenode.hxx b/slideshow/source/engine/animationnodes/animationbasenode.hxx
new file mode 100644
index 000000000000..b15047d78c4f
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationbasenode.hxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONBASENODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONBASENODE_HXX
+
+#include <com/sun/star/animations/XAnimate.hpp>
+
+#include "basecontainernode.hxx"
+#include "activitiesfactory.hxx"
+#include "shapeattributelayer.hxx"
+#include "shapeattributelayerholder.hxx"
+#include "attributableshape.hxx"
+#include "shapesubset.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** Common base class for all leaf animation nodes.
+
+ This class basically holds the target shape
+*/
+class AnimationBaseNode : public BaseNode
+{
+public:
+ AnimationBaseNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext );
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual void showState() const;
+#endif
+
+protected:
+ virtual void dispose();
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimate> const& getXAnimateNode() const
+ { return mxAnimateNode; }
+
+ /// Create parameter struct for ActivitiesFactory
+ ActivitiesFactory::CommonParameters fillCommonParameters() const;
+ ::basegfx::B2DVector const& getSlideSize() const { return maSlideSize; }
+ AttributableShapeSharedPtr getShape() const;
+
+private:
+ virtual bool hasPendingAnimation() const;
+
+private: // state transition callbacks
+ virtual bool init_st();
+ virtual bool resolve_st();
+ virtual void activate_st();
+ virtual void deactivate_st( NodeState eDestState );
+ virtual AnimationActivitySharedPtr createActivity() const = 0;
+
+private:
+ /** Returns true, if this is a subset animation, and
+ the subset is autogenerated (e.g. from an
+ iteration)
+ */
+ bool isDependentSubsettedShape() const
+ { return mpShapeSubset && !mbIsIndependentSubset; }
+
+ ShapeAttributeLayerHolder const & getAttributeLayerHolder() const
+ { return maAttributeLayerHolder; }
+
+private:
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimate> mxAnimateNode;
+ ShapeAttributeLayerHolder maAttributeLayerHolder;
+ ::basegfx::B2DVector maSlideSize;
+ AnimationActivitySharedPtr mpActivity;
+
+ /// When valid, this node has a plain target shape
+ AttributableShapeSharedPtr mpShape;
+ /// When valid, this is a subsetted target shape
+ ShapeSubsetSharedPtr mpShapeSubset;
+ SubsettableShapeManagerSharedPtr mpSubsetManager;
+ bool mbIsIndependentSubset;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONBASENODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationcolornode.cxx b/slideshow/source/engine/animationnodes/animationcolornode.cxx
new file mode 100644
index 000000000000..6f1536d8ebee
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationcolornode.cxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <com/sun/star/animations/AnimationColorSpace.hpp>
+
+#include "coloranimation.hxx"
+#include "hslcoloranimation.hxx"
+#include "animationcolornode.hxx"
+#include "animationfactory.hxx"
+#include "activitiesfactory.hxx"
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+/** Little wrapper for HSL to RGB mapping.
+
+ This class implements the HSLColorAnimation interface,
+ internally converting to RGB and forwarding to
+ ColorAnimation.
+*/
+class HSLWrapper : public HSLColorAnimation
+{
+public:
+ HSLWrapper( const ColorAnimationSharedPtr& rAnimation )
+ : mpAnimation( rAnimation )
+ {
+ ENSURE_OR_THROW(
+ mpAnimation,
+ "HSLWrapper::HSLWrapper(): Invalid color animation delegate" );
+ }
+
+ virtual void prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& )
+ {}
+
+ virtual void start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer )
+ {
+ mpAnimation->start( rShape, rAttrLayer );
+ }
+
+ virtual void end()
+ {
+ mpAnimation->end();
+ }
+
+ virtual bool operator()( const HSLColor& rColor )
+ {
+ return (*mpAnimation)( RGBColor( rColor ) );
+ }
+
+ virtual HSLColor getUnderlyingValue() const
+ {
+ return HSLColor( mpAnimation->getUnderlyingValue() );
+ }
+
+private:
+ ColorAnimationSharedPtr mpAnimation;
+};
+
+} // anon namespace
+
+AnimationActivitySharedPtr AnimationColorNode::createActivity() const
+{
+ ActivitiesFactory::CommonParameters aParms( fillCommonParameters() );
+
+ switch( mxColorNode->getColorInterpolation() )
+ {
+ case animations::AnimationColorSpace::RGB:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createColorPropertyAnimation(
+ mxColorNode->getAttributeName(),
+ getShape(),
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ getXAnimateNode() );
+
+ case animations::AnimationColorSpace::HSL:
+ // Wrap a plain ColorAnimation with the HSL
+ // wrapper, which implements the HSLColorAnimation
+ // interface, and internally converts HSL to RGB color
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ HSLColorAnimationSharedPtr(
+ new HSLWrapper(
+ AnimationFactory::createColorPropertyAnimation(
+ mxColorNode->getAttributeName(),
+ getShape(),
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ))),
+ mxColorNode );
+
+ default:
+ ENSURE_OR_THROW( false, "AnimationColorNode::createColorActivity(): "
+ "Unexpected color space" );
+ }
+
+ return AnimationActivitySharedPtr();
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationcolornode.hxx b/slideshow/source/engine/animationnodes/animationcolornode.hxx
new file mode 100644
index 000000000000..68c1dc856823
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationcolornode.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONCOLORNODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONCOLORNODE_HXX
+
+#include "animationbasenode.hxx"
+#include "com/sun/star/animations/XAnimateColor.hpp"
+
+namespace slideshow {
+namespace internal {
+
+class AnimationColorNode : public AnimationBaseNode
+{
+public:
+ AnimationColorNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext )
+ : AnimationBaseNode( xNode, pParent, rContext ),
+ mxColorNode( xNode, ::com::sun::star::uno::UNO_QUERY_THROW ) {}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual const char* getDescription() const { return "AnimationColorNode"; }
+#endif
+
+private:
+ virtual AnimationActivitySharedPtr createActivity() const;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimateColor > mxColorNode;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONCOLORNODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationcommandnode.cxx b/slideshow/source/engine/animationnodes/animationcommandnode.cxx
new file mode 100644
index 000000000000..69a41ab13978
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationcommandnode.cxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include "animationcommandnode.hxx"
+#include "delayevent.hxx"
+#include "tools.hxx"
+#include "nodetools.hxx"
+
+#include <boost/bind.hpp>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace EffectCommands = com::sun::star::presentation::EffectCommands;
+
+AnimationCommandNode::AnimationCommandNode( uno::Reference<animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext ) :
+ BaseNode( xNode, pParent, rContext ),
+ mpShape(),
+ mxCommandNode( xNode, ::com::sun::star::uno::UNO_QUERY_THROW )
+{
+ uno::Reference< drawing::XShape > xShape( mxCommandNode->getTarget(),
+ uno::UNO_QUERY );
+ ShapeSharedPtr pShape( getContext().mpSubsettableShapeManager->lookupShape( xShape ) );
+ mpShape = ::boost::dynamic_pointer_cast< ExternalMediaShape >( pShape );
+}
+
+void AnimationCommandNode::dispose()
+{
+ mxCommandNode.clear();
+ mpShape.reset();
+ BaseNode::dispose();
+}
+
+void AnimationCommandNode::activate_st()
+{
+ switch( mxCommandNode->getCommand() ) {
+ // the command is user defined
+ case EffectCommands::CUSTOM: break;
+ // the command is an ole verb.
+ case EffectCommands::VERB: break;
+ // the command starts playing on a media object
+ case EffectCommands::PLAY:
+ {
+ double fMediaTime=0.0;
+ beans::PropertyValue aMediaTime;
+ if( (mxCommandNode->getParameter() >>= aMediaTime) &&
+ aMediaTime.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("MediaTime") ))
+ {
+ aMediaTime.Value >>= fMediaTime;
+ }
+ if( mpShape )
+ {
+ mpShape->setMediaTime(fMediaTime/1000.0);
+ mpShape->play();
+ }
+ break;
+ }
+ // the command toggles the pause status on a media object
+ case EffectCommands::TOGGLEPAUSE:
+ {
+ if( mpShape )
+ {
+ if( mpShape->isPlaying() )
+ mpShape->pause();
+ else
+ mpShape->play();
+ }
+ break;
+ }
+ // the command stops the animation on a media object
+ case EffectCommands::STOP:
+ {
+ if( mpShape )
+ mpShape->stop();
+ break;
+ }
+ // the command stops all currently running sound effects
+ case EffectCommands::STOPAUDIO:
+ getContext().mrEventMultiplexer.notifyCommandStopAudio( getSelf() );
+ break;
+ }
+
+ // deactivate ASAP:
+ scheduleDeactivationEvent(
+ makeEvent( boost::bind( &AnimationNode::deactivate, getSelf() ),
+ "AnimationCommandNode::deactivate" ) );
+}
+
+bool AnimationCommandNode::hasPendingAnimation() const
+{
+ return mxCommandNode->getCommand() == EffectCommands::STOPAUDIO || mpShape;
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationcommandnode.hxx b/slideshow/source/engine/animationnodes/animationcommandnode.hxx
new file mode 100644
index 000000000000..2c1b6aff2bee
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationcommandnode.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONCOMMANDNODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONCOMMANDNODE_HXX
+
+#include "basecontainernode.hxx"
+#include "externalmediashape.hxx"
+#include "soundplayer.hxx"
+#include "com/sun/star/animations/XCommand.hpp"
+
+namespace slideshow {
+namespace internal {
+
+/** Command node.
+
+ This animation node encapsulates a command. Not yet implemented:
+ verb & custom.
+*/
+class AnimationCommandNode : public BaseNode
+{
+public:
+ AnimationCommandNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext );
+
+protected:
+ virtual void dispose();
+
+private:
+ virtual void activate_st();
+ virtual bool hasPendingAnimation() const;
+
+private:
+ ExternalMediaShapeSharedPtr mpShape;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XCommand > mxCommandNode;
+ bool mbIsPaused;
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONAUDIONODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationnodefactory.cxx b/slideshow/source/engine/animationnodes/animationnodefactory.cxx
new file mode 100644
index 000000000000..f4ab9343087e
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationnodefactory.cxx
@@ -0,0 +1,621 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <com/sun/star/animations/XAnimateSet.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <animations/animationnodehelper.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+#include "animationnodefactory.hxx"
+#include "paralleltimecontainer.hxx"
+#include "sequentialtimecontainer.hxx"
+#include "propertyanimationnode.hxx"
+#include "animationsetnode.hxx"
+#include "animationpathmotionnode.hxx"
+#include "animationcolornode.hxx"
+#include "animationtransformnode.hxx"
+#include "animationtransitionfilternode.hxx"
+#include "animationaudionode.hxx"
+#include "animationcommandnode.hxx"
+#include "nodetools.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+
+using namespace ::com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+// forward declaration needed by NodeCreator
+BaseNodeSharedPtr implCreateAnimationNode(
+ const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext );
+
+class NodeCreator
+{
+public:
+ NodeCreator( BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ : mrParent( rParent ), mrContext( rContext ) {}
+
+ void operator()(
+ const uno::Reference< animations::XAnimationNode >& xChildNode ) const
+ {
+ createChild( xChildNode, mrContext );
+ }
+
+protected:
+ void createChild(
+ const uno::Reference< animations::XAnimationNode >& xChildNode,
+ const NodeContext& rContext ) const
+ {
+ BaseNodeSharedPtr pChild( implCreateAnimationNode( xChildNode,
+ mrParent,
+ rContext ) );
+
+ OSL_ENSURE( pChild,
+ "NodeCreator::operator(): child creation failed" );
+
+ // TODO(Q1): This yields circular references, which, it seems, is
+ // unavoidable here
+ if( pChild )
+ mrParent->appendChildNode( pChild );
+ }
+
+ BaseContainerNodeSharedPtr& mrParent;
+ const NodeContext& mrContext;
+};
+
+/** Same as NodeCreator, only that NodeContext's
+ SubsetShape is cloned for every child node.
+
+ This is used for iterated animation node generation
+*/
+class CloningNodeCreator : private NodeCreator
+{
+public:
+ CloningNodeCreator( BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ : NodeCreator( rParent, rContext ) {}
+
+ void operator()(
+ const uno::Reference< animations::XAnimationNode >& xChildNode ) const
+ {
+ NodeContext aContext( mrContext );
+
+ // TODO(Q1): There's a catch here. If you clone a
+ // subset whose actual subsetting has already been
+ // realized (i.e. if enableSubsetShape() has been
+ // called already), and the original of your clone
+ // goes out of scope, then your subset will be
+ // gone (SubsettableShapeManager::revokeSubset() be
+ // called). As of now, this behaviour is not
+ // triggered here (we either clone, XOR we enable
+ // subset initially), but one might consider
+ // reworking DrawShape/ShapeSubset to avoid this.
+
+ // clone ShapeSubset, since each node needs their
+ // own version of the ShapeSubset (otherwise,
+ // e.g. activity counting does not work - subset
+ // would be removed after first animation node
+ // disables it).
+ //
+ // NOTE: this is only a problem for animation
+ // nodes that explicitely call
+ // disableSubsetShape(). Independent shape subsets
+ // (like those created for ParagraphTargets)
+ // solely rely on the ShapeSubset destructor to
+ // normalize things, which does the right thing
+ // here: the subset is only removed after _the
+ // last_ animation node releases the shared ptr.
+ aContext.mpMasterShapeSubset.reset(
+ new ShapeSubset( *aContext.mpMasterShapeSubset ) );
+
+ createChild( xChildNode, aContext );
+ }
+};
+
+/** Create animation nodes for text iterations
+
+ This method clones the animation nodes below xIterNode
+ for every iterated shape entity.
+*/
+bool implCreateIteratedNodes(
+ const uno::Reference< animations::XIterateContainer >& xIterNode,
+ BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+{
+ ENSURE_OR_THROW( xIterNode.is(),
+ "implCreateIteratedNodes(): Invalid node" );
+
+ const double nIntervalTimeout( xIterNode->getIterateInterval() );
+
+ // valid iterate interval? We're ruling out monstrous
+ // values here, to avoid pseudo 'hangs' in the
+ // presentation
+ if( nIntervalTimeout < 0.0 ||
+ nIntervalTimeout > 1000.0 )
+ {
+ return false; // not an active iteration
+ }
+
+ if( ::basegfx::fTools::equalZero( nIntervalTimeout ) )
+ OSL_TRACE( "implCreateIteratedNodes(): "
+ "iterate interval close to zero, there's "
+ "no point in defining such an effect "
+ "(visually equivalent to whole-shape effect)" );
+
+ // Determine target shape (or subset)
+ // ==================================
+
+ // TODO(E1): I'm not too sure what to expect here...
+ ENSURE_OR_RETURN_FALSE(
+ xIterNode->getTarget().hasValue(),
+ "implCreateIteratedNodes(): no target on ITERATE node" );
+
+ uno::Reference< drawing::XShape > xTargetShape( xIterNode->getTarget(),
+ uno::UNO_QUERY );
+
+ presentation::ParagraphTarget aTarget;
+ sal_Int16 nSubItem( xIterNode->getSubItem() );
+ bool bParagraphTarget( false );
+
+ if( !xTargetShape.is() )
+ {
+ // no shape provided. Maybe a ParagraphTarget?
+ if( !(xIterNode->getTarget() >>= aTarget) )
+ ENSURE_OR_RETURN_FALSE(
+ false,
+ "implCreateIteratedNodes(): could not extract any "
+ "target information" );
+
+ xTargetShape = aTarget.Shape;
+
+ ENSURE_OR_RETURN_FALSE(
+ xTargetShape.is(),
+ "implCreateIteratedNodes(): invalid shape in ParagraphTarget" );
+
+ // we've a paragraph target to iterate over, thus,
+ // the whole animation container refers only to
+ // the text
+ nSubItem = presentation::ShapeAnimationSubType::ONLY_TEXT;
+
+ bParagraphTarget = true;
+ }
+
+ // Lookup shape, and fill NodeContext
+ // ==================================
+
+ AttributableShapeSharedPtr pTargetShape(
+ lookupAttributableShape( rContext.maContext.mpSubsettableShapeManager,
+ xTargetShape ) );
+
+ const DocTreeNodeSupplier& rTreeNodeSupplier(
+ pTargetShape->getTreeNodeSupplier() );
+
+ ShapeSubsetSharedPtr pTargetSubset;
+
+ NodeContext aContext( rContext );
+
+ // paragraph targets already need a subset as the
+ // master shape (they're representing only a single
+ // paragraph)
+ if( bParagraphTarget )
+ {
+ ENSURE_OR_RETURN_FALSE(
+ aTarget.Paragraph >= 0 &&
+ rTreeNodeSupplier.getNumberOfTreeNodes(
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ) > aTarget.Paragraph,
+ "implCreateIteratedNodes(): paragraph index out of range" );
+
+ pTargetSubset.reset(
+ new ShapeSubset(
+ pTargetShape,
+ // retrieve index aTarget.Paragraph of
+ // type PARAGRAPH from this shape
+ rTreeNodeSupplier.getTreeNode(
+ aTarget.Paragraph,
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ),
+ rContext.maContext.mpSubsettableShapeManager ) );
+
+ // iterate target is not the whole shape, but only
+ // the selected paragraph - subset _must_ be
+ // independent, to be able to affect visibility
+ // independent of master shape
+ aContext.mbIsIndependentSubset = true;
+
+ // already enable parent subset right here, to
+ // make potentially generated subsets subtract
+ // their content from the parent subset (and not
+ // the original shape). Otherwise, already
+ // subsetted parents (e.g. paragraphs) would not
+ // have their characters removed, when the child
+ // iterations start.
+ // Furthermore, the setup of initial shape
+ // attributes of course needs the subset shape
+ // generated, to apply e.g. visibility changes.
+ pTargetSubset->enableSubsetShape();
+ }
+ else
+ {
+ pTargetSubset.reset(
+ new ShapeSubset( pTargetShape,
+ rContext.maContext.mpSubsettableShapeManager ));
+ }
+
+ aContext.mpMasterShapeSubset = pTargetSubset;
+ uno::Reference< animations::XAnimationNode > xNode( xIterNode,
+ uno::UNO_QUERY_THROW );
+
+ // Generate subsets
+ // ================
+
+ if( bParagraphTarget ||
+ nSubItem != presentation::ShapeAnimationSubType::ONLY_TEXT )
+ {
+ // prepend with animations for
+ // full Shape (will be subtracted
+ // from the subset parts within
+ // the Shape::createSubset()
+ // method). For ONLY_TEXT effects,
+ // we skip this part, to animate
+ // only the text.
+ //
+ // OR
+ //
+ // prepend with subset animation for full
+ // _paragraph_, from which the individual
+ // paragraph subsets are subtracted. Note that the
+ // subitem is superfluous here, we always assume
+ // ONLY_TEXT, if a paragraph is referenced as the
+ // master of an iteration effect.
+ NodeCreator aCreator( rParent, aContext );
+ if( !::anim::for_each_childNode( xNode,
+ aCreator ) )
+ {
+ ENSURE_OR_RETURN_FALSE(
+ false,
+ "implCreateIteratedNodes(): iterated child node creation failed" );
+ }
+ }
+
+ // TODO(F2): This does not do the correct
+ // thing. Having nSubItem be set to ONLY_BACKGROUND
+ // should result in the text staying unanimated in the
+ // foreground, while the shape moves in the background
+ // (this behaviour is perfectly possible with the
+ // slideshow engine, only that the text won't be
+ // currently visible, because animations are always in
+ // the foreground)
+ if( nSubItem != presentation::ShapeAnimationSubType::ONLY_BACKGROUND )
+ {
+ // determine type of subitem iteration (logical
+ // text unit to animate)
+ DocTreeNode::NodeType eIterateNodeType(
+ DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL );
+
+ switch( xIterNode->getIterateType() )
+ {
+ case presentation::TextAnimationType::BY_PARAGRAPH:
+ eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH;
+ break;
+
+ case presentation::TextAnimationType::BY_WORD:
+ eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_WORD;
+ break;
+
+ case presentation::TextAnimationType::BY_LETTER:
+ eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL;
+ break;
+
+ default:
+ ENSURE_OR_THROW(
+ false, "implCreateIteratedNodes(): "
+ "Unexpected IterateType on XIterateContainer");
+ break;
+ }
+
+ if( bParagraphTarget &&
+ eIterateNodeType != DocTreeNode::NODETYPE_LOGICAL_WORD &&
+ eIterateNodeType != DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL )
+ {
+ // will not animate the whole paragraph, when
+ // only the paragraph is animated at all.
+ OSL_FAIL( "implCreateIteratedNodes(): Ignoring paragraph iteration for paragraph master" );
+ }
+ else
+ {
+ // setup iteration parameters
+ // --------------------------
+
+ // iterate target is the whole shape (or the
+ // whole parent subshape), thus, can save
+ // loads of subset shapes by generating them
+ // only when the effects become active -
+ // before and after the effect active
+ // duration, all attributes are shared by
+ // master shape and subset (since the iterated
+ // effects are all the same).
+ aContext.mbIsIndependentSubset = false;
+
+ // determine number of nodes for given subitem
+ // type
+ sal_Int32 nTreeNodes( 0 );
+ if( bParagraphTarget )
+ {
+ // create the iterated subset _relative_ to
+ // the given paragraph index (i.e. animate the
+ // given subset type, but only when it's part
+ // of the given paragraph)
+ nTreeNodes = rTreeNodeSupplier.getNumberOfSubsetTreeNodes(
+ pTargetSubset->getSubset(),
+ eIterateNodeType );
+ }
+ else
+ {
+ // generate normal subset
+ nTreeNodes = rTreeNodeSupplier.getNumberOfTreeNodes(
+ eIterateNodeType );
+ }
+
+
+ // iterate node, generate copies of the children for each subset
+ // -------------------------------------------------------------
+
+ // NodeContext::mnStartDelay contains additional node delay.
+ // This will make the duplicated nodes for each iteration start
+ // increasingly later.
+ aContext.mnStartDelay = nIntervalTimeout;
+
+ for( sal_Int32 i=0; i<nTreeNodes; ++i )
+ {
+ // create subset with the corresponding tree nodes
+ if( bParagraphTarget )
+ {
+ // create subsets relative to paragraph subset
+ aContext.mpMasterShapeSubset.reset(
+ new ShapeSubset(
+ pTargetSubset,
+ rTreeNodeSupplier.getSubsetTreeNode(
+ pTargetSubset->getSubset(),
+ i,
+ eIterateNodeType ) ) );
+ }
+ else
+ {
+ // create subsets from main shape
+ aContext.mpMasterShapeSubset.reset(
+ new ShapeSubset( pTargetSubset,
+ rTreeNodeSupplier.getTreeNode(
+ i,
+ eIterateNodeType ) ) );
+ }
+
+ CloningNodeCreator aCreator( rParent, aContext );
+ if( !::anim::for_each_childNode( xNode,
+ aCreator ) )
+ {
+ ENSURE_OR_RETURN_FALSE(
+ false, "implCreateIteratedNodes(): "
+ "iterated child node creation failed" );
+ }
+
+ aContext.mnStartDelay += nIntervalTimeout;
+ }
+ }
+ }
+
+ // done with iterate child generation
+ return true;
+}
+
+BaseNodeSharedPtr implCreateAnimationNode(
+ const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+{
+ ENSURE_OR_THROW( xNode.is(),
+ "implCreateAnimationNode(): invalid XAnimationNode" );
+
+ BaseNodeSharedPtr pCreatedNode;
+ BaseContainerNodeSharedPtr pCreatedContainer;
+
+ // create the internal node, corresponding to xNode
+ switch( xNode->getType() )
+ {
+ case animations::AnimationNodeType::CUSTOM:
+ OSL_FAIL( "implCreateAnimationNode(): "
+ "CUSTOM not yet implemented" );
+ return pCreatedNode;
+
+ case animations::AnimationNodeType::PAR:
+ pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr(
+ new ParallelTimeContainer( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ITERATE:
+ // map iterate container to ParallelTimeContainer.
+ // the iterating functionality is to be found
+ // below, (see method implCreateIteratedNodes)
+ pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr(
+ new ParallelTimeContainer( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::SEQ:
+ pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr(
+ new SequentialTimeContainer( xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATE:
+ pCreatedNode.reset( new PropertyAnimationNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::SET:
+ pCreatedNode.reset( new AnimationSetNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATEMOTION:
+ pCreatedNode.reset( new AnimationPathMotionNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATECOLOR:
+ pCreatedNode.reset( new AnimationColorNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::ANIMATETRANSFORM:
+ pCreatedNode.reset( new AnimationTransformNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::TRANSITIONFILTER:
+ pCreatedNode.reset( new AnimationTransitionFilterNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::AUDIO:
+ pCreatedNode.reset( new AnimationAudioNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ case animations::AnimationNodeType::COMMAND:
+ pCreatedNode.reset( new AnimationCommandNode(
+ xNode, rParent, rContext ) );
+ break;
+
+ default:
+ OSL_FAIL( "implCreateAnimationNode(): "
+ "invalid AnimationNodeType" );
+ return pCreatedNode;
+ }
+
+ // TODO(Q1): This yields circular references, which, it seems, is
+ // unavoidable here
+
+ // HACK: node objects need shared_ptr to themselves,
+ // which we pass them here.
+ pCreatedNode->setSelf( pCreatedNode );
+
+ // if we've got a container node object, recursively add
+ // its children
+ if( pCreatedContainer )
+ {
+ uno::Reference< animations::XIterateContainer > xIterNode(
+ xNode, uno::UNO_QUERY );
+
+ // when this node is an XIterateContainer with
+ // active iterations, this method will generate
+ // the appropriate children
+ if( xIterNode.is() )
+ {
+ // note that implCreateIteratedNodes() might
+ // choose not to generate any child nodes
+ // (e.g. when the iterate timeout is outside
+ // sensible limits). Then, no child nodes are
+ // generated at all, since typically, child
+ // node attribute are incomplete for iteration
+ // children.
+ implCreateIteratedNodes( xIterNode,
+ pCreatedContainer,
+ rContext );
+ }
+ else
+ {
+ // no iterate subset node, just plain child generation now
+ NodeCreator aCreator( pCreatedContainer, rContext );
+ if( !::anim::for_each_childNode( xNode, aCreator ) )
+ {
+ OSL_FAIL( "implCreateAnimationNode(): "
+ "child node creation failed" );
+ return BaseNodeSharedPtr();
+ }
+ }
+ }
+
+ return pCreatedNode;
+}
+
+} // anon namespace
+
+AnimationNodeSharedPtr AnimationNodeFactory::createAnimationNode(
+ const uno::Reference< animations::XAnimationNode >& xNode,
+ const ::basegfx::B2DVector& rSlideSize,
+ const SlideShowContext& rContext )
+{
+ ENSURE_OR_THROW(
+ xNode.is(),
+ "AnimationNodeFactory::createAnimationNode(): invalid XAnimationNode" );
+
+ return BaseNodeSharedPtr( implCreateAnimationNode(
+ xNode,
+ BaseContainerNodeSharedPtr(), // no parent
+ NodeContext( rContext,
+ rSlideSize )));
+}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+void AnimationNodeFactory::showTree( AnimationNodeSharedPtr& pRootNode )
+{
+ if( pRootNode )
+ DEBUG_NODES_SHOWTREE( boost::dynamic_pointer_cast<BaseContainerNode>(
+ pRootNode).get() );
+}
+#endif
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationpathmotionnode.cxx b/slideshow/source/engine/animationnodes/animationpathmotionnode.cxx
new file mode 100644
index 000000000000..d0ffe8b59da4
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationpathmotionnode.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include "animationpathmotionnode.hxx"
+#include "animationfactory.hxx"
+
+namespace slideshow {
+namespace internal {
+
+void AnimationPathMotionNode::dispose()
+{
+ mxPathMotionNode.clear();
+ AnimationBaseNode::dispose();
+}
+
+AnimationActivitySharedPtr AnimationPathMotionNode::createActivity() const
+{
+ rtl::OUString aString;
+ ENSURE_OR_THROW( (mxPathMotionNode->getPath() >>= aString),
+ "no string-based SVG:d path found" );
+
+ ActivitiesFactory::CommonParameters const aParms( fillCommonParameters() );
+ return ActivitiesFactory::createSimpleActivity(
+ aParms,
+ AnimationFactory::createPathMotionAnimation(
+ aString,
+ mxPathMotionNode->getAdditive(),
+ getShape(),
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ true );
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationpathmotionnode.hxx b/slideshow/source/engine/animationnodes/animationpathmotionnode.hxx
new file mode 100644
index 000000000000..02fbc99fab83
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationpathmotionnode.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONPATHMOTIONNODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONPATHMOTIONNODE_HXX
+
+#include "animationbasenode.hxx"
+#include "com/sun/star/animations/XAnimateMotion.hpp"
+
+namespace slideshow {
+namespace internal {
+
+class AnimationPathMotionNode : public AnimationBaseNode
+{
+public:
+ AnimationPathMotionNode(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ : AnimationBaseNode( xNode, rParent, rContext ),
+ mxPathMotionNode( xNode, ::com::sun::star::uno::UNO_QUERY_THROW ) {}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual const char* getDescription() const
+ { return "AnimationPathMotionNode"; }
+#endif
+
+protected:
+ virtual void dispose();
+
+private:
+ virtual AnimationActivitySharedPtr createActivity() const;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimateMotion > mxPathMotionNode;
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONPATHMOTIONNODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationsetnode.cxx b/slideshow/source/engine/animationnodes/animationsetnode.cxx
new file mode 100644
index 000000000000..b09e5d041889
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationsetnode.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include "animationfactory.hxx"
+#include "setactivity.hxx"
+#include "animationsetnode.hxx"
+#include "nodetools.hxx"
+#include "tools.hxx"
+#include "delayevent.hxx"
+
+#include <boost/bind.hpp>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+void AnimationSetNode::implScheduleDeactivationEvent()
+{
+ scheduleDeactivationEvent();
+}
+
+AnimationActivitySharedPtr AnimationSetNode::createActivity() const
+{
+ ActivitiesFactory::CommonParameters aParms( fillCommonParameters() );
+ uno::Reference<animations::XAnimate> const xAnimateNode = getXAnimateNode();
+ rtl::OUString const attrName( xAnimateNode->getAttributeName() );
+ AttributableShapeSharedPtr const pShape( getShape() );
+
+ // make deactivation a two-step procedure. Normally, we
+ // could solely rely on
+ // BaseNode::scheduleDeactivationEvent() to deactivate()
+ // us. Unfortunately, that method on the one hand ignores
+ // indefinite timing, on the other hand generates
+ // zero-timeout delays, which might get fired _before_ our
+ // set activity has taken place. Therefore, we enforce
+ // sequentiality by letting only the set activity schedule
+ // the deactivation event (and AnimationBaseNode
+ // takes care for the fact when mpActivity should be zero).
+
+ // AnimationBaseNode::fillCommonParameters() has set up
+ // immediate deactivation as default when activity ends, but
+ if (! isIndefiniteTiming( xAnimateNode->getDuration() )) {
+ boost::shared_ptr<AnimationSetNode> const pSelf(
+ boost::dynamic_pointer_cast<AnimationSetNode>(getSelf()) );
+ ENSURE_OR_THROW(
+ pSelf, "cannot cast getSelf() to my type!" );
+ aParms.mpEndEvent = makeEvent(
+ boost::bind( &AnimationSetNode::implScheduleDeactivationEvent,
+ pSelf ),
+ "AnimationSetNode::implScheduleDeactivationEvent");
+ }
+
+ switch (AnimationFactory::classifyAttributeName( attrName )) {
+ default:
+ case AnimationFactory::CLASS_UNKNOWN_PROPERTY:
+ ENSURE_OR_THROW(
+ false, "AnimationSetNode::createSetActivity(): "
+ "Unexpected attribute class" );
+ break;
+
+ case AnimationFactory::CLASS_NUMBER_PROPERTY:
+ {
+ NumberAnimation::ValueType aValue;
+
+ ENSURE_OR_THROW(
+ extractValue( aValue,
+ xAnimateNode->getTo(),
+ pShape,
+ getSlideSize() ),
+ "AnimationSetNode::createSetActivity(): "
+ "Could not import numeric to value" );
+
+ return makeSetActivity(
+ aParms,
+ AnimationFactory::createNumberPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize(),
+ AnimationFactory::FLAG_NO_SPRITE ),
+ aValue );
+ }
+
+ case AnimationFactory::CLASS_ENUM_PROPERTY:
+ {
+ EnumAnimation::ValueType aValue;
+
+ ENSURE_OR_THROW(
+ extractValue( aValue,
+ xAnimateNode->getTo(),
+ pShape,
+ getSlideSize() ),
+ "AnimationSetNode::createSetActivity(): "
+ "Could not import enum to value" );
+
+ return makeSetActivity(
+ aParms,
+ AnimationFactory::createEnumPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize(),
+ AnimationFactory::FLAG_NO_SPRITE ),
+ aValue );
+ }
+
+ case AnimationFactory::CLASS_COLOR_PROPERTY:
+ {
+ ColorAnimation::ValueType aValue;
+
+ ENSURE_OR_THROW(
+ extractValue( aValue,
+ xAnimateNode->getTo(),
+ pShape,
+ getSlideSize() ),
+ "AnimationSetNode::createSetActivity(): "
+ "Could not import color to value" );
+
+ return makeSetActivity(
+ aParms,
+ AnimationFactory::createColorPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize(),
+ AnimationFactory::FLAG_NO_SPRITE ),
+ aValue );
+ }
+
+ case AnimationFactory::CLASS_STRING_PROPERTY:
+ {
+ StringAnimation::ValueType aValue;
+
+ ENSURE_OR_THROW(
+ extractValue( aValue,
+ xAnimateNode->getTo(),
+ pShape,
+ getSlideSize() ),
+ "AnimationSetNode::createSetActivity(): "
+ "Could not import string to value" );
+
+ return makeSetActivity(
+ aParms,
+ AnimationFactory::createStringPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize(),
+ AnimationFactory::FLAG_NO_SPRITE ),
+ aValue );
+ }
+
+ case AnimationFactory::CLASS_BOOL_PROPERTY:
+ {
+ BoolAnimation::ValueType aValue;
+
+ ENSURE_OR_THROW(
+ extractValue( aValue,
+ xAnimateNode->getTo(),
+ pShape,
+ getSlideSize() ),
+ "AnimationSetNode::createSetActivity(): "
+ "Could not import bool to value" );
+
+ return makeSetActivity(
+ aParms,
+ AnimationFactory::createBoolPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize(),
+ AnimationFactory::FLAG_NO_SPRITE ),
+ aValue );
+ }
+ }
+
+ return AnimationActivitySharedPtr();
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationsetnode.hxx b/slideshow/source/engine/animationnodes/animationsetnode.hxx
new file mode 100644
index 000000000000..a836b9ae0f38
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationsetnode.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONSETNODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONSETNODE_HXX
+
+#include "animationbasenode.hxx"
+
+namespace slideshow {
+namespace internal {
+
+class AnimationSetNode : public AnimationBaseNode
+{
+public:
+ AnimationSetNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext )
+ : AnimationBaseNode( xNode, pParent, rContext ) {}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual const char* getDescription() const { return "AnimationSetNode"; }
+#endif
+
+private:
+ virtual AnimationActivitySharedPtr createActivity() const;
+ void implScheduleDeactivationEvent();
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONSETNODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationtransformnode.cxx b/slideshow/source/engine/animationnodes/animationtransformnode.cxx
new file mode 100644
index 000000000000..cfa22104c417
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationtransformnode.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+
+#include "animationtransformnode.hxx"
+#include "animationfactory.hxx"
+#include "activitiesfactory.hxx"
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+void AnimationTransformNode::dispose()
+{
+ mxTransformNode.clear();
+ AnimationBaseNode::dispose();
+}
+
+AnimationActivitySharedPtr AnimationTransformNode::createActivity() const
+{
+ ActivitiesFactory::CommonParameters aParms( fillCommonParameters() );
+
+ const sal_Int16 nTransformType( mxTransformNode->getTransformType() );
+
+ const AttributableShapeSharedPtr& rShape( getShape() );
+
+ switch( nTransformType )
+ {
+ default:
+ ENSURE_OR_THROW(
+ false, "AnimationTransformNode::createTransformActivity(): "
+ "Unknown transform type" );
+
+ case animations::AnimationTransformType::TRANSLATE:
+ // FALLTHROUGH intended
+ case animations::AnimationTransformType::SCALE:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createPairPropertyAnimation(
+ rShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize(),
+ nTransformType ),
+ getXAnimateNode() );
+
+ case animations::AnimationTransformType::ROTATE:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createNumberPropertyAnimation(
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("Rotate") ),
+ rShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ getXAnimateNode() );
+
+ case animations::AnimationTransformType::SKEWX:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createNumberPropertyAnimation(
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("SkewX") ),
+ rShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ getXAnimateNode() );
+
+ case animations::AnimationTransformType::SKEWY:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createNumberPropertyAnimation(
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("SkewY") ),
+ rShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ getXAnimateNode() );
+ }
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationtransformnode.hxx b/slideshow/source/engine/animationnodes/animationtransformnode.hxx
new file mode 100644
index 000000000000..e2416b72a7f3
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationtransformnode.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONTRANSFORMNODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONTRANSFORMNODE_HXX
+
+#include "animationbasenode.hxx"
+#include "com/sun/star/animations/XAnimateTransform.hpp"
+
+namespace slideshow {
+namespace internal {
+
+class AnimationTransformNode : public AnimationBaseNode
+{
+public:
+ AnimationTransformNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext )
+ : AnimationBaseNode( xNode, pParent, rContext ),
+ mxTransformNode( xNode, ::com::sun::star::uno::UNO_QUERY_THROW ) {}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual const char* getDescription() const
+ { return "AnimationTransformNode"; }
+#endif
+
+protected:
+ virtual void dispose();
+
+private:
+ virtual AnimationActivitySharedPtr createActivity() const;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimateTransform > mxTransformNode;
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONTRANSFORMNODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationtransitionfilternode.cxx b/slideshow/source/engine/animationnodes/animationtransitionfilternode.cxx
new file mode 100644
index 000000000000..feb88fe8f3d9
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationtransitionfilternode.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include "animationtransitionfilternode.hxx"
+#include "transitionfactory.hxx"
+
+namespace slideshow {
+namespace internal {
+
+void AnimationTransitionFilterNode::dispose()
+{
+ mxTransitionFilterNode.clear();
+ AnimationBaseNode::dispose();
+}
+
+AnimationActivitySharedPtr
+AnimationTransitionFilterNode::createActivity() const
+{
+ return TransitionFactory::createShapeTransition(
+ fillCommonParameters(),
+ getShape(),
+ getContext().mpSubsettableShapeManager,
+ getSlideSize(),
+ mxTransitionFilterNode );
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/animationtransitionfilternode.hxx b/slideshow/source/engine/animationnodes/animationtransitionfilternode.hxx
new file mode 100644
index 000000000000..506ab668050c
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/animationtransitionfilternode.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_ANIMATIONTRANSITIONFILTERNODE_HXX
+#define INCLUDED_SLIDESHOW_ANIMATIONTRANSITIONFILTERNODE_HXX
+
+#include "animationbasenode.hxx"
+#include "com/sun/star/animations/XTransitionFilter.hpp"
+
+namespace slideshow {
+namespace internal {
+
+class AnimationTransitionFilterNode : public AnimationBaseNode
+{
+public:
+ AnimationTransitionFilterNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext )
+ : AnimationBaseNode( xNode, pParent, rContext ),
+ mxTransitionFilterNode( xNode, ::com::sun::star::uno::UNO_QUERY_THROW)
+ {}
+
+#if defined(VERBOSE)
+ virtual const char* getDescription() const
+ { return "AnimationTransitionFilterNode"; }
+#endif
+
+protected:
+ virtual void dispose();
+
+private:
+ virtual AnimationActivitySharedPtr createActivity() const;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XTransitionFilter> mxTransitionFilterNode;
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_ANIMATIONTRANSITIONFILTERNODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/basecontainernode.cxx b/slideshow/source/engine/animationnodes/basecontainernode.cxx
new file mode 100644
index 000000000000..9d513fa367e4
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/basecontainernode.cxx
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include "basecontainernode.hxx"
+#include "tools.hxx"
+#include "nodetools.hxx"
+#include "delayevent.hxx"
+
+#include <boost/mem_fn.hpp>
+#include <algorithm>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+BaseContainerNode::BaseContainerNode(
+ const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ : BaseNode( xNode, rParent, rContext ),
+ maChildren(),
+ mnFinishedChildren(0),
+ mbDurationIndefinite( isIndefiniteTiming( xNode->getEnd() ) &&
+ isIndefiniteTiming( xNode->getDuration() ) )
+{
+}
+
+void BaseContainerNode::dispose()
+{
+ forEachChildNode( boost::mem_fn(&Disposable::dispose) );
+ maChildren.clear();
+ BaseNode::dispose();
+}
+
+bool BaseContainerNode::init_st()
+{
+ mnFinishedChildren = 0;
+ // initialize all children
+ return (std::count_if(
+ maChildren.begin(), maChildren.end(),
+ boost::mem_fn(&AnimationNode::init) ) ==
+ static_cast<VectorOfNodes::difference_type>(maChildren.size()));
+}
+
+void BaseContainerNode::deactivate_st( NodeState eDestState )
+{
+ if (eDestState == FROZEN) {
+ // deactivate all children that are not FROZEN or ENDED:
+ forEachChildNode( boost::mem_fn(&AnimationNode::deactivate),
+ ~(FROZEN | ENDED) );
+ }
+ else {
+ // end all children that are not ENDED:
+ forEachChildNode( boost::mem_fn(&AnimationNode::end), ~ENDED );
+ }
+}
+
+bool BaseContainerNode::hasPendingAnimation() const
+{
+ // does any of our children returns "true" on
+ // AnimationNode::hasPendingAnimation()?
+ // If yes, we, too, return true
+ VectorOfNodes::const_iterator const iEnd( maChildren.end() );
+ return (std::find_if(
+ maChildren.begin(), iEnd,
+ boost::mem_fn(&AnimationNode::hasPendingAnimation) ) != iEnd);
+}
+
+void BaseContainerNode::appendChildNode( AnimationNodeSharedPtr const& pNode )
+{
+ if (! checkValidNode())
+ return;
+
+ // register derived classes as end listeners at all children.
+ // this is necessary to control the children animation
+ // sequence, and to determine our own end event
+ if (pNode->registerDeactivatingListener( getSelf() )) {
+ maChildren.push_back( pNode );
+ }
+}
+
+bool BaseContainerNode::isChildNode( AnimationNodeSharedPtr const& pNode ) const
+{
+ // find given notifier in child vector
+ VectorOfNodes::const_iterator const iBegin( maChildren.begin() );
+ VectorOfNodes::const_iterator const iEnd( maChildren.end() );
+ VectorOfNodes::const_iterator const iFind(
+ std::find( iBegin, iEnd, pNode ) );
+ return (iFind != iEnd);
+}
+
+bool BaseContainerNode::notifyDeactivatedChild(
+ AnimationNodeSharedPtr const& pChildNode )
+{
+ OSL_ASSERT( pChildNode->getState() == FROZEN ||
+ pChildNode->getState() == ENDED );
+ // early exit on invalid nodes
+ OSL_ASSERT( getState() != INVALID );
+ if( getState() == INVALID )
+ return false;
+
+ if (! isChildNode(pChildNode)) {
+ OSL_FAIL( "unknown notifier!" );
+ return false;
+ }
+
+ std::size_t const nSize = maChildren.size();
+ OSL_ASSERT( mnFinishedChildren < nSize );
+ ++mnFinishedChildren;
+ bool const bFinished = (mnFinishedChildren >= nSize);
+
+ // all children finished, and we've got indefinite duration?
+ // think of ParallelTimeContainer::notifyDeactivating()
+ // if duration given, we will be deactivated by some end event
+ // @see fillCommonParameters()
+ if (bFinished && isDurationIndefinite()) {
+ deactivate();
+ }
+
+ return bFinished;
+}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+void BaseContainerNode::showState() const
+{
+ for( std::size_t i=0; i<maChildren.size(); ++i )
+ {
+ BaseNodeSharedPtr pNode =
+ boost::shared_dynamic_cast<BaseNode>(maChildren[i]);
+ VERBOSE_TRACE(
+ "Node connection: n0x%X -> n0x%X",
+ (const char*)this+debugGetCurrentOffset(),
+ (const char*)pNode.get()+debugGetCurrentOffset() );
+ pNode->showState();
+ }
+
+ BaseNode::showState();
+}
+#endif
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/basecontainernode.hxx b/slideshow/source/engine/animationnodes/basecontainernode.hxx
new file mode 100644
index 000000000000..8523d122f722
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/basecontainernode.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_BASECONTAINERNODE_HXX
+#define INCLUDED_SLIDESHOW_BASECONTAINERNODE_HXX
+
+#include "basenode.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** This interface extends BaseNode with child handling methods.
+ Used for XAnimationNode objects which have children
+*/
+class BaseContainerNode : public BaseNode
+{
+public:
+ BaseContainerNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext );
+
+ /** Add given child node to this container
+ */
+ void appendChildNode( AnimationNodeSharedPtr const& pNode );
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual void showState() const;
+ virtual const char* getDescription() const { return "BaseContainerNode"; }
+#endif
+
+protected:
+ // overrides from BaseNode
+ virtual void dispose();
+
+private:
+ virtual bool init_st();
+ virtual void deactivate_st( NodeState eDestState );
+ virtual bool hasPendingAnimation() const;
+ // force to be implemented by derived class:
+ virtual void activate_st() = 0;
+ virtual void notifyDeactivating(
+ AnimationNodeSharedPtr const& rNotifier ) = 0;
+
+protected:
+ bool isDurationIndefinite() const { return mbDurationIndefinite; }
+
+ bool isChildNode( AnimationNodeSharedPtr const& pNode ) const;
+
+ /// @return true: if all children have been deactivated
+ bool notifyDeactivatedChild( AnimationNodeSharedPtr const& pChildNode );
+
+ template <typename FuncT>
+ inline void forEachChildNode( FuncT const& func,
+ int nodeStateMask = -1 ) const
+ {
+ VectorOfNodes::const_iterator iPos( maChildren.begin() );
+ VectorOfNodes::const_iterator const iEnd( maChildren.end() );
+ for ( ; iPos != iEnd; ++iPos ) {
+ AnimationNodeSharedPtr const& pNode = *iPos;
+ if (nodeStateMask != -1 && (pNode->getState() & nodeStateMask) == 0)
+ continue;
+ func(pNode);
+ }
+ }
+
+ typedef ::std::vector<AnimationNodeSharedPtr> VectorOfNodes;
+ VectorOfNodes maChildren;
+ ::std::size_t mnFinishedChildren;
+
+private:
+ const bool mbDurationIndefinite;
+};
+
+typedef ::boost::shared_ptr< BaseContainerNode > BaseContainerNodeSharedPtr;
+
+} // namespace interface
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_BASECONTAINERNODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/basenode.cxx b/slideshow/source/engine/animationnodes/basenode.cxx
new file mode 100644
index 000000000000..cc3cd5b6da55
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/basenode.cxx
@@ -0,0 +1,771 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include "basenode.hxx"
+#include "eventmultiplexer.hxx"
+#include "basecontainernode.hxx"
+#include "eventqueue.hxx"
+#include "delayevent.hxx"
+#include "tools.hxx"
+#include "nodetools.hxx"
+#include "generateevent.hxx"
+#include "debug.hxx"
+
+#include <boost/bind.hpp>
+#include <vector>
+#include <algorithm>
+#include <iterator>
+
+using namespace ::com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+typedef int StateTransitionTable[17];
+
+// State transition tables
+// =========================================================================
+
+const int* getStateTransitionTable( sal_Int16 nRestartMode,
+ sal_Int16 nFillMode )
+{
+ // TODO(F2): restart issues in below tables
+
+ // transition table for restart=NEVER, fill=REMOVE
+ static const StateTransitionTable stateTransitionTable_Never_Remove = {
+ AnimationNode::INVALID,
+ AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
+ AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
+ AnimationNode::INVALID,
+ AnimationNode::ENDED, // active successors for ACTIVE: no freeze here
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID, // active successors for FROZEN: this state is unreachable here
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED // active successors for ENDED: this state is a sink here (cannot restart)
+ };
+
+ // transition table for restart=WHEN_NOT_ACTIVE, fill=REMOVE
+ static const StateTransitionTable stateTransitionTable_NotActive_Remove = {
+ AnimationNode::INVALID,
+ AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
+ AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
+ AnimationNode::INVALID,
+ AnimationNode::ENDED, // active successors for ACTIVE: no freeze here
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID, // active successors for FROZEN:
+ // this state is unreachable here
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED:
+ // restart possible when ended
+ };
+
+ // transition table for restart=ALWAYS, fill=REMOVE
+ static const StateTransitionTable stateTransitionTable_Always_Remove = {
+ AnimationNode::INVALID,
+ AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
+ AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
+ AnimationNode::INVALID,
+ AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: restart
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID, // active successors for FROZEN:
+ // this state is unreachable here
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart
+ };
+
+ // transition table for restart=NEVER, fill=FREEZE
+ static const StateTransitionTable stateTransitionTable_Never_Freeze = {
+ AnimationNode::INVALID,
+ AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
+ AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
+ AnimationNode::INVALID,
+ AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED, // active successors for FROZEN: end
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED, // active successors for ENDED: this state is a sink here (cannot restart)
+ };
+
+ // transition table for restart=WHEN_NOT_ACTIVE, fill=FREEZE
+ static const StateTransitionTable stateTransitionTable_NotActive_Freeze = {
+ AnimationNode::INVALID,
+ AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
+ AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
+ AnimationNode::INVALID,
+ AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN:
+ // restart possible when ended
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED:
+ // restart possible when ended
+ };
+
+ // transition table for restart=ALWAYS, fill=FREEZE
+ static const StateTransitionTable stateTransitionTable_Always_Freeze = {
+ AnimationNode::INVALID,
+ AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
+ AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
+ AnimationNode::INVALID,
+ AnimationNode::FROZEN|AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE:
+ // end object, restart
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: restart possible
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::INVALID,
+ AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart
+ };
+
+ static const StateTransitionTable* tableGuide[] = {
+ &stateTransitionTable_Never_Remove,
+ &stateTransitionTable_NotActive_Remove,
+ &stateTransitionTable_Always_Remove,
+ &stateTransitionTable_Never_Freeze,
+ &stateTransitionTable_NotActive_Freeze,
+ &stateTransitionTable_Always_Freeze
+ };
+
+ int nRestartValue;
+ switch( nRestartMode ) {
+ default:
+ case animations::AnimationRestart::DEFAULT:
+ // same value: animations::AnimationRestart::INHERIT:
+ OSL_FAIL(
+ "getStateTransitionTable(): unexpected case for restart" );
+ // FALLTHROUGH intended
+ case animations::AnimationRestart::NEVER:
+ nRestartValue = 0;
+ break;
+ case animations::AnimationRestart::WHEN_NOT_ACTIVE:
+ nRestartValue = 1;
+ break;
+ case animations::AnimationRestart::ALWAYS:
+ nRestartValue = 2;
+ break;
+ }
+
+ int nFillValue;
+ switch( nFillMode ) {
+ default:
+ case animations::AnimationFill::AUTO:
+ case animations::AnimationFill::DEFAULT:
+ // same value: animations::AnimationFill::INHERIT:
+ OSL_FAIL(
+ "getStateTransitionTable(): unexpected case for fill" );
+ // FALLTHROUGH intended
+ case animations::AnimationFill::REMOVE:
+ nFillValue = 0;
+ break;
+ case animations::AnimationFill::FREEZE:
+ case animations::AnimationFill::HOLD:
+ case animations::AnimationFill::TRANSITION:
+ nFillValue = 1;
+ break;
+ }
+
+ return *tableGuide[ 3*nFillValue + nRestartValue ];
+}
+
+/// Little helper predicate, to detect main sequence root node
+bool isMainSequenceRootNode_(
+ const uno::Reference< animations::XAnimationNode >& xNode )
+{
+ // detect main sequence root node (need that for
+ // end-of-mainsequence signalling below)
+ beans::NamedValue const aSearchKey(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ),
+ uno::makeAny( presentation::EffectNodeType::MAIN_SEQUENCE ) );
+
+ uno::Sequence<beans::NamedValue> const userData(xNode->getUserData());
+ return findNamedValue( userData, aSearchKey );
+}
+
+} // anon namespace
+
+// BaseNode implementation
+//=========================================================================
+
+/** state transition handling
+ */
+class BaseNode::StateTransition : private boost::noncopyable
+{
+public:
+ enum Options { NONE, FORCE };
+
+ explicit StateTransition( BaseNode * pNode )
+ : mpNode(pNode), meToState(INVALID) {}
+
+ ~StateTransition() {
+ clear();
+ }
+
+ bool enter( NodeState eToState, int options = NONE )
+ {
+ OSL_ENSURE( meToState == INVALID,
+ "### commit() before enter()ing again!" );
+ if (meToState != INVALID)
+ return false;
+ bool const bForce = ((options & FORCE) != 0);
+ if (!bForce && !mpNode->isTransition( mpNode->meCurrState, eToState ))
+ return false;
+ // recursion detection:
+ if ((mpNode->meCurrentStateTransition & eToState) != 0)
+ return false; // already in wanted transition
+ // mark transition:
+ mpNode->meCurrentStateTransition |= eToState;
+ meToState = eToState;
+ return true; // in transition
+ }
+
+ void commit() {
+ OSL_ENSURE( meToState != INVALID, "### nothing to commit!" );
+ if (meToState != INVALID) {
+ mpNode->meCurrState = meToState;
+ clear();
+ }
+
+ // Uncomment the following line to write the node tree to file on
+ // every state change of one of its nodes.
+ // Debug_ShowNodeTree(mpNode->mpSelf);
+ }
+
+ void clear() {
+ if (meToState != INVALID) {
+ OSL_ASSERT( (mpNode->meCurrentStateTransition & meToState) != 0 );
+ mpNode->meCurrentStateTransition &= ~meToState;
+ meToState = INVALID;
+ }
+ }
+
+private:
+ BaseNode *const mpNode;
+ NodeState meToState;
+};
+
+BaseNode::BaseNode( const uno::Reference< animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext ) :
+ maContext( rContext.maContext ),
+ maDeactivatingListeners(),
+ mxAnimationNode( xNode ),
+ mpParent( rParent ),
+ mpSelf(),
+ mpStateTransitionTable( NULL ),
+ mnStartDelay( rContext.mnStartDelay ),
+ meCurrState( UNRESOLVED ),
+ meCurrentStateTransition( 0 ),
+ mpCurrentEvent(),
+ mbIsMainSequenceRootNode( isMainSequenceRootNode_( xNode ) )
+{
+ ENSURE_OR_THROW( mxAnimationNode.is(),
+ "BaseNode::BaseNode(): Invalid XAnimationNode" );
+
+ // setup state transition table
+ mpStateTransitionTable = getStateTransitionTable( getRestartMode(),
+ getFillMode() );
+}
+
+void BaseNode::dispose()
+{
+ meCurrState = INVALID;
+
+ // discharge a loaded event, if any:
+ if (mpCurrentEvent) {
+ mpCurrentEvent->dispose();
+ mpCurrentEvent.reset();
+ }
+ maDeactivatingListeners.clear();
+ mxAnimationNode.clear();
+ mpParent.reset();
+ mpSelf.reset();
+ maContext.dispose();
+}
+
+
+sal_Int16 BaseNode::getRestartMode()
+{
+ const sal_Int16 nTmp( mxAnimationNode->getRestart() );
+ return (nTmp != animations::AnimationRestart::DEFAULT &&
+ nTmp != animations::AnimationRestart::INHERIT)
+ ? nTmp : getRestartDefaultMode();
+}
+
+sal_Int16 BaseNode::getFillMode()
+{
+ const sal_Int16 nTmp( mxAnimationNode->getFill() );
+ const sal_Int16 nFill((nTmp != animations::AnimationFill::DEFAULT &&
+ nTmp != animations::AnimationFill::INHERIT)
+ ? nTmp : getFillDefaultMode());
+
+ // For AUTO fill mode, SMIL specifies that fill mode is FREEZE,
+ // if no explicit active duration is given
+ // (no duration, end, repeatCount or repeatDuration given),
+ // and REMOVE otherwise
+ if( nFill == animations::AnimationFill::AUTO ) {
+ return (isIndefiniteTiming( mxAnimationNode->getDuration() ) &&
+ isIndefiniteTiming( mxAnimationNode->getEnd() ) &&
+ !mxAnimationNode->getRepeatCount().hasValue() &&
+ isIndefiniteTiming( mxAnimationNode->getRepeatDuration() ))
+ ? animations::AnimationFill::FREEZE
+ : animations::AnimationFill::REMOVE;
+ }
+ else {
+ return nFill;
+ }
+}
+
+sal_Int16 BaseNode::getFillDefaultMode() const
+{
+ sal_Int16 nFillDefault = mxAnimationNode->getFillDefault();
+ if (nFillDefault == animations::AnimationFill::DEFAULT) {
+ nFillDefault = (mpParent != 0
+ ? mpParent->getFillDefaultMode()
+ : animations::AnimationFill::AUTO);
+ }
+ return nFillDefault;
+}
+
+sal_Int16 BaseNode::getRestartDefaultMode() const
+{
+ sal_Int16 nRestartDefaultMode = mxAnimationNode->getRestartDefault();
+ if (nRestartDefaultMode == animations::AnimationRestart::DEFAULT) {
+ nRestartDefaultMode = (mpParent != 0
+ ? mpParent->getRestartDefaultMode()
+ : animations::AnimationRestart::ALWAYS);
+ }
+ return nRestartDefaultMode;
+}
+
+uno::Reference<animations::XAnimationNode> BaseNode::getXAnimationNode() const
+{
+ return mxAnimationNode;
+}
+
+bool BaseNode::init()
+{
+ if (! checkValidNode())
+ return false;
+ meCurrState = UNRESOLVED;
+ // discharge a loaded event, if any:
+ if (mpCurrentEvent) {
+ mpCurrentEvent->dispose();
+ mpCurrentEvent.reset();
+ }
+ return init_st(); // may call derived class
+}
+
+bool BaseNode::init_st()
+{
+ return true;
+}
+
+bool BaseNode::resolve()
+{
+ if (! checkValidNode())
+ return false;
+
+ OSL_ASSERT( meCurrState != RESOLVED );
+ if (inStateOrTransition( RESOLVED ))
+ return true;
+
+ StateTransition st(this);
+ if (st.enter( RESOLVED ) &&
+ isTransition( RESOLVED, ACTIVE ) &&
+ resolve_st() /* may call derived class */)
+ {
+ st.commit(); // changing state
+
+ // discharge a loaded event, if any:
+ if (mpCurrentEvent)
+ mpCurrentEvent->dispose();
+
+ // schedule activation event:
+
+ // This method takes the NodeContext::mnStartDelay value into account,
+ // to cater for iterate container time shifts. We cannot put different
+ // iterations of the iterate container's children into different
+ // subcontainer (such as a 'DelayContainer', which delays resolving its
+ // children by a fixed amount), since all iterations' nodes must be
+ // resolved at the same time (otherwise, the delayed subset creation
+ // will not work, i.e. deactivate the subsets too late in the master
+ // shape).
+ uno::Any const aBegin( mxAnimationNode->getBegin() );
+ if (aBegin.hasValue()) {
+ mpCurrentEvent = generateEvent(
+ aBegin, boost::bind( &AnimationNode::activate, mpSelf ),
+ maContext, mnStartDelay );
+ }
+ else {
+ // For some leaf nodes, PPT import yields empty begin time,
+ // although semantically, it should be 0.0
+ // TODO(F3): That should really be provided by the PPT import
+
+ // schedule delayed activation event. Take iterate node
+ // timeout into account
+ mpCurrentEvent = makeDelay(
+ boost::bind( &AnimationNode::activate, mpSelf ),
+ mnStartDelay,
+ "AnimationNode::activate with delay");
+ maContext.mrEventQueue.addEvent( mpCurrentEvent );
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool BaseNode::resolve_st()
+{
+ return true;
+}
+
+
+bool BaseNode::activate()
+{
+ if (! checkValidNode())
+ return false;
+
+ OSL_ASSERT( meCurrState != ACTIVE );
+ if (inStateOrTransition( ACTIVE ))
+ return true;
+
+ StateTransition st(this);
+ if (st.enter( ACTIVE )) {
+
+ activate_st(); // calling derived class
+
+ st.commit(); // changing state
+
+ maContext.mrEventMultiplexer.notifyAnimationStart( mpSelf );
+
+ return true;
+ }
+
+ return false;
+}
+
+void BaseNode::activate_st()
+{
+ scheduleDeactivationEvent();
+}
+
+void BaseNode::scheduleDeactivationEvent( EventSharedPtr const& pEvent )
+{
+ if (mpCurrentEvent) {
+ mpCurrentEvent->dispose();
+ mpCurrentEvent.reset();
+ }
+ if (pEvent) {
+ if (maContext.mrEventQueue.addEvent( pEvent ))
+ mpCurrentEvent = pEvent;
+ }
+ else {
+ // This method need not take the
+ // NodeContext::mnStartDelay value into account,
+ // because the deactivation event is only scheduled
+ // when the effect is started: the timeout is then
+ // already respected.
+
+ // xxx todo:
+ // think about set node, anim base node!
+ // if anim base node has no activity, this is called to schedule deactivatiion,
+ // but what if it does not schedule anything?
+
+ // TODO(F2): Handle end time attribute, too
+ mpCurrentEvent = generateEvent(
+ mxAnimationNode->getDuration(),
+ boost::bind( &AnimationNode::deactivate, mpSelf ),
+ maContext, 0.0 );
+ }
+}
+
+void BaseNode::deactivate()
+{
+ if (inStateOrTransition( ENDED | FROZEN ) || !checkValidNode())
+ return;
+
+ if (isTransition( meCurrState, FROZEN, false /* no OSL_ASSERT */ )) {
+ // do transition to FROZEN:
+ StateTransition st(this);
+ if (st.enter( FROZEN, StateTransition::FORCE )) {
+
+ deactivate_st( FROZEN );
+ st.commit();
+
+ notifyEndListeners();
+
+ // discharge a loaded event, before going on:
+ if (mpCurrentEvent) {
+ mpCurrentEvent->dispose();
+ mpCurrentEvent.reset();
+ }
+ }
+ }
+ else {
+ // use end instead:
+ end();
+ }
+ // state has changed either to FROZEN or ENDED
+}
+
+void BaseNode::deactivate_st( NodeState )
+{
+}
+
+void BaseNode::end()
+{
+ bool const bIsFrozenOrInTransitionToFrozen = inStateOrTransition( FROZEN );
+ if (inStateOrTransition( ENDED ) || !checkValidNode())
+ return;
+
+ // END must always be reachable. If not, that's an error in the
+ // transition tables
+ OSL_ENSURE( isTransition( meCurrState, ENDED ),
+ "end state not reachable in transition table" );
+
+ StateTransition st(this);
+ if (st.enter( ENDED, StateTransition::FORCE )) {
+
+ deactivate_st( ENDED );
+ st.commit(); // changing state
+
+ // if is FROZEN or is to be FROZEN, then
+ // will/already notified deactivating listeners
+ if (!bIsFrozenOrInTransitionToFrozen)
+ notifyEndListeners();
+
+ // discharge a loaded event, before going on:
+ if (mpCurrentEvent) {
+ mpCurrentEvent->dispose();
+ mpCurrentEvent.reset();
+ }
+ }
+}
+
+void BaseNode::notifyDeactivating( const AnimationNodeSharedPtr& rNotifier )
+{
+ (void) rNotifier; // avoid warning
+ OSL_ASSERT( rNotifier->getState() == FROZEN ||
+ rNotifier->getState() == ENDED );
+ // TODO(F1): for end sync functionality, this might indeed be used some day
+}
+
+void BaseNode::notifyEndListeners() const
+{
+ // notify all listeners
+ std::for_each( maDeactivatingListeners.begin(),
+ maDeactivatingListeners.end(),
+ boost::bind( &AnimationNode::notifyDeactivating, _1,
+ boost::cref(mpSelf) ) );
+
+ // notify state change
+ maContext.mrEventMultiplexer.notifyAnimationEnd( mpSelf );
+
+ // notify main sequence end (iff we're the main
+ // sequence root node). This is because the main
+ // sequence determines the active duration of the
+ // slide. All other sequences are secondary, in that
+ // they don't prevent a slide change from happening,
+ // even if they have not been completed. In other
+ // words, all sequences except the main sequence are
+ // optional for the slide lifetime.
+ if (isMainSequenceRootNode())
+ maContext.mrEventMultiplexer.notifySlideAnimationsEnd();
+}
+
+AnimationNode::NodeState BaseNode::getState() const
+{
+ return meCurrState;
+}
+
+bool BaseNode::registerDeactivatingListener(
+ const AnimationNodeSharedPtr& rNotifee )
+{
+ if (! checkValidNode())
+ return false;
+
+ ENSURE_OR_RETURN_FALSE(
+ rNotifee,
+ "BaseNode::registerDeactivatingListener(): invalid notifee" );
+ maDeactivatingListeners.push_back( rNotifee );
+
+ return true;
+}
+
+void BaseNode::setSelf( const BaseNodeSharedPtr& rSelf )
+{
+ ENSURE_OR_THROW( rSelf.get() == this,
+ "BaseNode::setSelf(): got ptr to different object" );
+ ENSURE_OR_THROW( !mpSelf,
+ "BaseNode::setSelf(): called multiple times" );
+
+ mpSelf = rSelf;
+}
+
+// Debug
+//=========================================================================
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+void BaseNode::showState() const
+{
+ const AnimationNode::NodeState eNodeState( getState() );
+
+ if( eNodeState == AnimationNode::INVALID )
+ VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled,"
+ "fillcolor=\"0.5,0.2,0.5\"]",
+ (const char*)this+debugGetCurrentOffset(),
+ getDescription() );
+ else
+ VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled,"
+ "fillcolor=\"%f,1.0,1.0\"]",
+ (const char*)this+debugGetCurrentOffset(),
+ getDescription(),
+ log(double(getState()))/4.0 );
+
+ // determine additional node information
+ uno::Reference<animations::XAnimate> const xAnimate( mxAnimationNode,
+ uno::UNO_QUERY );
+ if( xAnimate.is() )
+ {
+ uno::Reference< drawing::XShape > xTargetShape( xAnimate->getTarget(),
+ uno::UNO_QUERY );
+
+ if( !xTargetShape.is() )
+ {
+ ::com::sun::star::presentation::ParagraphTarget aTarget;
+
+ // no shape provided. Maybe a ParagraphTarget?
+ if( (xAnimate->getTarget() >>= aTarget) )
+ xTargetShape = aTarget.Shape;
+ }
+
+ if( xTargetShape.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xTargetShape,
+ uno::UNO_QUERY );
+
+ // read shape name
+ ::rtl::OUString aName;
+ if( (xPropSet->getPropertyValue(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) )
+ >>= aName) )
+ {
+ const ::rtl::OString& rAsciiName(
+ ::rtl::OUStringToOString( aName,
+ RTL_TEXTENCODING_ASCII_US ) );
+
+ VERBOSE_TRACE( "Node info: n0x%X, name \"%s\"",
+ (const char*)this+debugGetCurrentOffset(),
+ rAsciiName.getStr() );
+ }
+ }
+ }
+}
+
+const char* BaseNode::getDescription() const
+{
+ return "BaseNode";
+}
+
+void BaseNode::showTreeFromWithin() const
+{
+ // find root node
+ BaseNodeSharedPtr pCurrNode( mpSelf );
+ while( pCurrNode->mpParent ) pCurrNode = pCurrNode->mpParent;
+
+ pCurrNode->showState();
+}
+#endif
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/basenode.hxx b/slideshow/source/engine/animationnodes/basenode.hxx
new file mode 100644
index 000000000000..ad2d09a59e78
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/basenode.hxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_BASENODE_HXX
+#define INCLUDED_SLIDESHOW_BASENODE_HXX
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.hxx>
+
+#include "event.hxx"
+#include "animationnode.hxx"
+#include "slideshowcontext.hxx"
+#include "shapesubset.hxx"
+
+#include <boost/noncopyable.hpp>
+#include <vector>
+
+namespace slideshow {
+namespace internal {
+
+/** Context for every node.
+
+ Besides the global AnimationNodeFactory::Context data,
+ this struct also contains the current DocTree subset
+ for this node. If start and end index of the
+ DocTreeNode are equal, the node should use the
+ complete shape.
+*/
+struct NodeContext
+{
+ NodeContext( const SlideShowContext& rContext,
+ const ::basegfx::B2DVector& rSlideSize )
+ : maContext( rContext ),
+ maSlideSize( rSlideSize ),
+ mpMasterShapeSubset(),
+ mnStartDelay(0.0),
+ mbIsIndependentSubset( true )
+ {}
+
+ void dispose()
+ {
+ maContext.dispose();
+ mpMasterShapeSubset.reset();
+ }
+
+ /// Context as passed to createAnimationNode()
+ SlideShowContext maContext;
+
+ /// Size in user coordinate space of the corresponding slide
+ ::basegfx::B2DVector maSlideSize;
+
+ /// Shape to be used (provided by parent, e.g. for iterations)
+ ShapeSubsetSharedPtr mpMasterShapeSubset;
+
+ /// Additional delay to node begin (to offset iterate effects)
+ double mnStartDelay;
+
+ /// When true, subset must be created during slide initialization
+ bool mbIsIndependentSubset;
+};
+
+class BaseContainerNode;
+
+/** This interface extends AnimationNode with some
+ file-private accessor methods.
+*/
+class BaseNode : public AnimationNode,
+ public ::osl::DebugBase<BaseNode>,
+ private ::boost::noncopyable
+{
+public:
+ BaseNode( ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext );
+
+ /** Provide the node with a shared_ptr to itself.
+
+ Since implementation has to create objects which need
+ a shared_ptr to this node, and a pointee cannot
+ retrieve a shared_ptr to itself internally, have to
+ set that from the outside.
+ */
+ void setSelf( const ::boost::shared_ptr< BaseNode >& rSelf );
+
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual void showState() const;
+ virtual const char* getDescription() const;
+ void showTreeFromWithin() const;
+#endif
+
+ const ::boost::shared_ptr< BaseContainerNode >& getParentNode() const
+ { return mpParent; }
+
+ // Disposable:
+ virtual void dispose();
+
+ // AnimationNode:
+ virtual bool init();
+ virtual bool resolve();
+ virtual bool activate();
+ virtual void deactivate();
+ virtual void end();
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> getXAnimationNode() const;
+ virtual NodeState getState() const;
+ virtual bool registerDeactivatingListener(
+ const AnimationNodeSharedPtr& rNotifee );
+ // nop:
+ virtual void notifyDeactivating( const AnimationNodeSharedPtr& rNotifier );
+
+ bool isMainSequenceRootNode() const { return mbIsMainSequenceRootNode; }
+
+protected:
+ void scheduleDeactivationEvent( EventSharedPtr const& pEvent =
+ EventSharedPtr() );
+
+ SlideShowContext const& getContext() const { return maContext; }
+ ::boost::shared_ptr<BaseNode> const& getSelf() const { return mpSelf; }
+
+ bool checkValidNode() const {
+ ENSURE_OR_THROW( mpSelf, "no self ptr set!" );
+ bool const bRet = (meCurrState != INVALID);
+ OSL_ENSURE( bRet, "### INVALID node!" );
+ return bRet;
+ }
+
+private:
+ // all state affecting methods have "_st" counterparts being called at
+ // derived classes when in state transistion: no-ops here at BaseNode...
+ virtual bool init_st();
+ virtual bool resolve_st();
+ virtual void activate_st();
+ virtual void deactivate_st( NodeState eDestState );
+
+private:
+ /// notifies
+ /// - all registered deactivation listeners
+ /// - single animation end (every node)
+ /// - slide animations (if main sequence root node)
+ void notifyEndListeners() const;
+
+ /// Get the node's restart mode
+ sal_Int16 getRestartMode();
+
+ /** Get the default restart mode
+
+ If this node's default mode is
+ AnimationRestart::DEFAULT, this method recursively
+ calls the parent node.
+ */
+ sal_Int16 getRestartDefaultMode() const;
+
+ /// Get the node's fill mode
+ sal_Int16 getFillMode();
+
+ /** Get the default fill mode.
+
+ If this node's default mode is AnimationFill::DEFAULT,
+ this method recursively calls the parent node.
+ */
+ sal_Int16 getFillDefaultMode() const;
+
+ bool isTransition( NodeState eFromState, NodeState eToState,
+ bool debugAssert = true ) const {
+ (void) debugAssert; // avoid warning
+ bool const bRet =((mpStateTransitionTable[eFromState] & eToState) != 0);
+ OSL_ENSURE( !debugAssert || bRet, "### state unreachable!" );
+ return bRet;
+ }
+
+ bool inStateOrTransition( int mask ) const {
+ return ((meCurrState & mask) != 0 ||
+ (meCurrentStateTransition & mask) != 0);
+ }
+
+ class StateTransition;
+ friend class StateTransition;
+
+private:
+ SlideShowContext maContext;
+
+ typedef ::std::vector< AnimationNodeSharedPtr > ListenerVector;
+
+ ListenerVector maDeactivatingListeners;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode > mxAnimationNode;
+ ::boost::shared_ptr< BaseContainerNode > mpParent;
+ ::boost::shared_ptr< BaseNode > mpSelf;
+ const int* mpStateTransitionTable;
+ const double mnStartDelay;
+ NodeState meCurrState;
+ int meCurrentStateTransition;
+ EventSharedPtr mpCurrentEvent;
+ const bool mbIsMainSequenceRootNode;
+};
+
+typedef ::boost::shared_ptr< BaseNode > BaseNodeSharedPtr;
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_BASENODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/generateevent.cxx b/slideshow/source/engine/animationnodes/generateevent.cxx
new file mode 100644
index 000000000000..62904feb9d0f
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/generateevent.cxx
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/animations/Event.hpp>
+
+#include "shape.hxx"
+#include "subsettableshapemanager.hxx"
+#include "usereventqueue.hxx"
+#include "slideshowcontext.hxx"
+#include "delayevent.hxx"
+
+namespace slideshow {
+namespace internal {
+
+using namespace com::sun::star;
+
+EventSharedPtr generateEvent(
+ uno::Any const& rEventDescription,
+ Delay::FunctorT const& rFunctor,
+ SlideShowContext const& rContext,
+ double nAdditionalDelay )
+{
+ EventSharedPtr pEvent;
+
+ if (! rEventDescription.hasValue())
+ return pEvent;
+
+ animations::Timing eTiming;
+ animations::Event aEvent;
+ uno::Sequence<uno::Any> aSequence;
+ double nDelay1 = 0;
+
+ if (rEventDescription >>= eTiming) {
+ switch (eTiming) {
+ case animations::Timing_INDEFINITE:
+ break; // don't schedule no event
+ case animations::Timing_MEDIA:
+ OSL_FAIL( "MEDIA timing not yet implemented!" );
+ break;
+ default:
+ ENSURE_OR_THROW( false, "unexpected case!" );
+ }
+ }
+ else if (rEventDescription >>= aEvent) {
+
+ // try to extract additional event delay
+ double nDelay2 = 0.0;
+ if (aEvent.Offset.hasValue() && !(aEvent.Offset >>= nDelay2)) {
+ OSL_FAIL( "offset values apart from DOUBLE not "
+ "recognized in animations::Event!" );
+ }
+
+ // common vars used inside switch
+ uno::Reference<animations::XAnimationNode> xNode;
+ uno::Reference<drawing::XShape> xShape;
+ ShapeSharedPtr pShape;
+
+ // TODO(F1): Respect aEvent.Repeat value
+
+ switch (aEvent.Trigger) {
+ default:
+ ENSURE_OR_THROW( false, "unexpected event trigger!" );
+ case animations::EventTrigger::NONE:
+ // no event at all
+ break;
+ case animations::EventTrigger::ON_BEGIN:
+ OSL_FAIL( "event trigger ON_BEGIN not yet implemented!" );
+ break;
+ case animations::EventTrigger::ON_END:
+ OSL_FAIL( "event trigger ON_END not yet implemented!" );
+ break;
+ case animations::EventTrigger::BEGIN_EVENT:
+ // try to extract XAnimationNode event source
+ if (aEvent.Source >>= xNode) {
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, BEGIN_EVENT");
+ rContext.mrUserEventQueue.registerAnimationStartEvent(
+ pEvent, xNode );
+ }
+ else {
+ OSL_FAIL("could not extract source XAnimationNode "
+ "for BEGIN_EVENT!" );
+ }
+ break;
+ case animations::EventTrigger::END_EVENT:
+ // try to extract XAnimationNode event source
+ if (aEvent.Source >>= xNode) {
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, END_EVENT");
+ rContext.mrUserEventQueue.registerAnimationEndEvent(
+ pEvent, xNode );
+ }
+ else {
+ OSL_FAIL( "could not extract source XAnimationNode "
+ "for END_EVENT!" );
+ }
+ break;
+ case animations::EventTrigger::ON_CLICK:
+ // try to extract XShape event source
+ if ((aEvent.Source >>= xShape) &&
+ (pShape = rContext.mpSubsettableShapeManager->lookupShape(xShape)).get())
+ {
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, ON_CLICK");
+ rContext.mrUserEventQueue.registerShapeClickEvent(
+ pEvent, pShape );
+ }
+ else {
+ OSL_FAIL( "could not extract source XAnimationNode "
+ "for ON_CLICK!" );
+ }
+ break;
+ case animations::EventTrigger::ON_DBL_CLICK:
+ // try to extract XShape event source
+ if ((aEvent.Source >>= xShape) &&
+ (pShape = rContext.mpSubsettableShapeManager->lookupShape(xShape)).get())
+ {
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, ON_DBL_CLICK");
+ rContext.mrUserEventQueue.registerShapeDoubleClickEvent(
+ pEvent, pShape );
+ }
+ else {
+ OSL_FAIL( "could not extract source XAnimationNode "
+ "for ON_DBL_CLICK!" );
+ }
+ break;
+ case animations::EventTrigger::ON_MOUSE_ENTER:
+ // try to extract XShape event source
+ if ((aEvent.Source >>= xShape) &&
+ (pShape = rContext.mpSubsettableShapeManager->lookupShape(xShape)).get())
+ {
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, ON_MOUSE_ENTER");
+ rContext.mrUserEventQueue.registerMouseEnterEvent(
+ pEvent, pShape );
+ }
+ else {
+ OSL_FAIL( "could not extract source XAnimationNode "
+ "for ON_MOUSE_ENTER!" );
+ }
+ break;
+ case animations::EventTrigger::ON_MOUSE_LEAVE:
+ // try to extract XShape event source
+ if ((aEvent.Source >>= xShape) &&
+ (pShape = rContext.mpSubsettableShapeManager->lookupShape(xShape)).get())
+ {
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, ON_MOUSE_LEAVE");
+ rContext.mrUserEventQueue.registerMouseLeaveEvent(
+ pEvent, pShape );
+ }
+ else {
+ OSL_FAIL( "could not extract source XAnimationNode "
+ "for ON_MOUSE_LEAVE!" );
+ }
+ break;
+ case animations::EventTrigger::ON_PREV:
+ OSL_FAIL( "event trigger ON_PREV not yet implemented, "
+ "mapped to ON_NEXT!" );
+ // FALLTHROUGH intended
+ case animations::EventTrigger::ON_NEXT:
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, ON_NEXT");
+ rContext.mrUserEventQueue.registerNextEffectEvent( pEvent );
+ break;
+ case animations::EventTrigger::ON_STOP_AUDIO:
+ // try to extract XAnimationNode event source
+ if (aEvent.Source >>= xNode) {
+ pEvent = makeDelay( rFunctor,
+ nDelay2 + nAdditionalDelay,
+ "generateEvent, ON_STOP_AUDIO");
+ rContext.mrUserEventQueue.registerAudioStoppedEvent(
+ pEvent, xNode );
+ }
+ else {
+ OSL_FAIL( "could not extract source XAnimationNode "
+ "for ON_STOP_AUDIO!" );
+ }
+ break;
+ case animations::EventTrigger::REPEAT:
+ OSL_FAIL( "event trigger REPEAT not yet implemented!" );
+ break;
+ }
+ }
+ else if (rEventDescription >>= aSequence) {
+ OSL_FAIL( "sequence of timing primitives "
+ "not yet implemented!" );
+ }
+ else if (rEventDescription >>= nDelay1) {
+ pEvent = makeDelay( rFunctor,
+ nDelay1 + nAdditionalDelay,
+ "generateEvent with delay");
+ // schedule delay event
+ rContext.mrEventQueue.addEvent( pEvent );
+ }
+
+ return pEvent;
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/generateevent.hxx b/slideshow/source/engine/animationnodes/generateevent.hxx
new file mode 100644
index 000000000000..9c0104e5a254
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/generateevent.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_GENERATEEVENT_HXX
+#define INCLUDED_SLIDESHOW_GENERATEEVENT_HXX
+
+#include "slideshowcontext.hxx"
+#include "delayevent.hxx"
+#include "com/sun/star/uno/Any.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** Create an event for the given description, calling the given functor.
+
+ @param rEventDescription
+ Directly from API
+
+ @param rFunctor
+ Functor to call when event fires.
+
+ @param rContext
+ Context struct, to provide event queue
+
+ @param nAdditionalDelay
+ Additional delay, gets added on top of timeout.
+*/
+EventSharedPtr generateEvent(
+ ::com::sun::star::uno::Any const& rEventDescription,
+ Delay::FunctorT const& rFunctor,
+ SlideShowContext const& rContext,
+ double nAdditionalDelay );
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_GENERATEEVENT_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/makefile.mk b/slideshow/source/engine/animationnodes/makefile.mk
new file mode 100644
index 000000000000..fc1c80352703
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/makefile.mk
@@ -0,0 +1,61 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=slideshow
+TARGET=animationnodes
+ENABLE_EXCEPTIONS=TRUE
+PRJINC=..$/..
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = $(SLO)$/animationaudionode.obj \
+ $(SLO)$/animationcommandnode.obj \
+ $(SLO)$/animationbasenode.obj \
+ $(SLO)$/animationcolornode.obj \
+ $(SLO)$/animationnodefactory.obj \
+ $(SLO)$/animationpathmotionnode.obj \
+ $(SLO)$/animationsetnode.obj \
+ $(SLO)$/animationtransformnode.obj \
+ $(SLO)$/animationtransitionfilternode.obj \
+ $(SLO)$/basecontainernode.obj \
+ $(SLO)$/basenode.obj \
+ $(SLO)$/nodetools.obj \
+ $(SLO)$/paralleltimecontainer.obj \
+ $(SLO)$/propertyanimationnode.obj \
+ $(SLO)$/sequentialtimecontainer.obj \
+ $(SLO)$/generateevent.obj
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/animationnodes/nodetools.cxx b/slideshow/source/engine/animationnodes/nodetools.cxx
new file mode 100644
index 000000000000..756f6b1969b0
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/nodetools.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <com/sun/star/animations/Timing.hpp>
+
+#include <tools.hxx>
+#include <nodetools.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ int& debugGetCurrentOffset()
+ {
+ static int lcl_nOffset = 0; // to make each tree output distinct
+
+ return lcl_nOffset;
+ }
+
+ void debugNodesShowTree( const BaseNode* pNode )
+ {
+ if( pNode )
+ pNode->showState();
+
+ ++debugGetCurrentOffset();
+ }
+
+ void debugNodesShowTreeWithin( const BaseNode* pNode )
+ {
+ if( pNode )
+ pNode->showTreeFromWithin();
+
+ ++debugGetCurrentOffset();
+ }
+#endif
+
+ AttributableShapeSharedPtr lookupAttributableShape( const ShapeManagerSharedPtr& rShapeManager,
+ const uno::Reference< drawing::XShape >& xShape )
+ {
+ ENSURE_OR_THROW( rShapeManager,
+ "lookupAttributableShape(): invalid ShapeManager" );
+
+ ShapeSharedPtr pShape( rShapeManager->lookupShape( xShape ) );
+
+ ENSURE_OR_THROW( pShape,
+ "lookupAttributableShape(): no shape found for given XShape" );
+
+ AttributableShapeSharedPtr pRes(
+ ::boost::dynamic_pointer_cast< AttributableShape >( pShape ) );
+
+ // TODO(E3): Cannot throw here, people might set animation info
+ // for non-animatable shapes from the API. AnimationNodes must catch
+ // the exception and handle that differently
+ ENSURE_OR_THROW( pRes,
+ "lookupAttributableShape(): shape found does not implement AttributableShape interface" );
+
+ return pRes;
+ }
+
+ bool isIndefiniteTiming( const uno::Any& rAny )
+ {
+ if( !rAny.hasValue() )
+ return true;
+
+ animations::Timing eTiming;
+
+ if( !(rAny >>= eTiming) ||
+ eTiming != animations::Timing_INDEFINITE )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /// Extract the node type from the user data
+ bool getNodeType( sal_Int16& o_rNodeType,
+ const uno::Sequence< beans::NamedValue >& rValues )
+ {
+ beans::NamedValue aNamedValue;
+
+ if( findNamedValue( &aNamedValue,
+ rValues,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("node-type") ) ) )
+ {
+ if( (aNamedValue.Value >>= o_rNodeType) )
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/nodetools.hxx b/slideshow/source/engine/animationnodes/nodetools.hxx
new file mode 100644
index 000000000000..df120c159ac8
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/nodetools.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_NODETOOLS_HXX
+#define INCLUDED_SLIDESHOW_NODETOOLS_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include "shapemanager.hxx"
+#include "basenode.hxx"
+#include "doctreenode.hxx"
+#include "attributableshape.hxx"
+
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+# define DEBUG_NODES_SHOWTREE(a) debugNodesShowTree(a);
+# define DEBUG_NODES_SHOWTREE_WITHIN(a) debugNodesShowTreeWithin(a);
+#else
+# define DEBUG_NODES_SHOWTREE(a)
+# define DEBUG_NODES_SHOWTREE_WITHIN(a)
+#endif
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ // Tools
+ //=========================================================================
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ int& debugGetCurrentOffset();
+ void debugNodesShowTree( const BaseNode* );
+ void debugNodesShowTreeWithin( const BaseNode* );
+#endif
+
+ /** Look up an AttributableShape from ShapeManager.
+
+ This method retrieves an AttributableShape pointer, given
+ an XShape and a LayerManager.
+
+ Throws a runtime exception if there's no such shape, or if
+ it does not implement the AttributableShape interface.
+ */
+ AttributableShapeSharedPtr lookupAttributableShape( const ShapeManagerSharedPtr& rShapeManager,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape );
+
+ /** Predicate whether a Begin, Duration or End timing is
+ indefinite, i.e. either contains no value, or the
+ value Timing_INDEFINITE.
+ */
+ bool isIndefiniteTiming( const ::com::sun::star::uno::Any& rAny );
+
+ /// Extract the node type from the user data
+ bool getNodeType( sal_Int16& o_rNodeType,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::beans::NamedValue >& rValues );
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_NODETOOLS_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/paralleltimecontainer.cxx b/slideshow/source/engine/animationnodes/paralleltimecontainer.cxx
new file mode 100644
index 000000000000..9e5ffa89bc29
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/paralleltimecontainer.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include "paralleltimecontainer.hxx"
+#include "delayevent.hxx"
+
+#include <boost/bind.hpp>
+
+namespace slideshow {
+namespace internal {
+
+void ParallelTimeContainer::activate_st()
+{
+ // resolve all children:
+ std::size_t const nResolvedNodes =
+ static_cast<std::size_t>(std::count_if(
+ maChildren.begin(), maChildren.end(),
+ boost::mem_fn(&AnimationNode::resolve) ));
+ (void) nResolvedNodes; // avoid warning
+ OSL_ENSURE( nResolvedNodes == maChildren.size(),
+ "### resolving all children failed!" );
+
+ if (isDurationIndefinite() && maChildren.empty()) {
+ // deactivate ASAP:
+ scheduleDeactivationEvent(
+ makeEvent( boost::bind( &AnimationNode::deactivate, getSelf() ),
+ "ParallelTimeContainer::deactivate") );
+ }
+ else { // use default
+ scheduleDeactivationEvent();
+ }
+}
+
+void ParallelTimeContainer::notifyDeactivating(
+ AnimationNodeSharedPtr const& pChildNode )
+{
+ notifyDeactivatedChild( pChildNode );
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/paralleltimecontainer.hxx b/slideshow/source/engine/animationnodes/paralleltimecontainer.hxx
new file mode 100644
index 000000000000..abeacb7cda6f
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/paralleltimecontainer.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_PARALLELTIMECONTAINER_HXX
+#define INCLUDED_SLIDESHOW_PARALLELTIMECONTAINER_HXX
+
+#include "basecontainernode.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** This class implements parallel node containers
+
+ All children of this node are played in parallel
+*/
+class ParallelTimeContainer : public BaseContainerNode
+{
+public:
+ ParallelTimeContainer(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode >& xNode,
+ const BaseContainerNodeSharedPtr& rParent,
+ const NodeContext& rContext )
+ : BaseContainerNode( xNode, rParent, rContext ) {}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual const char* getDescription() const
+ { return "ParallelTimeContainer"; }
+#endif
+
+private:
+ virtual void activate_st();
+ virtual void notifyDeactivating( AnimationNodeSharedPtr const& pChildNode );
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_PARALLELTIMECONTAINER_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/propertyanimationnode.cxx b/slideshow/source/engine/animationnodes/propertyanimationnode.cxx
new file mode 100644
index 000000000000..669f000bd6c7
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/propertyanimationnode.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include "propertyanimationnode.hxx"
+#include "animationfactory.hxx"
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+AnimationActivitySharedPtr PropertyAnimationNode::createActivity() const
+{
+ // Create AnimationActivity from common XAnimate parameters:
+ ActivitiesFactory::CommonParameters aParms( fillCommonParameters() );
+ uno::Reference<animations::XAnimate> const& xAnimateNode =getXAnimateNode();
+ rtl::OUString const attrName( xAnimateNode->getAttributeName() );
+ AttributableShapeSharedPtr const pShape( getShape() );
+
+ switch (AnimationFactory::classifyAttributeName( attrName )) {
+ default:
+ case AnimationFactory::CLASS_UNKNOWN_PROPERTY:
+ ENSURE_OR_THROW(
+ false,
+ "Unexpected attribute class (unknown or empty attribute name)" );
+ break;
+
+ case AnimationFactory::CLASS_NUMBER_PROPERTY:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createNumberPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ xAnimateNode );
+
+ case AnimationFactory::CLASS_ENUM_PROPERTY:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createEnumPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ xAnimateNode );
+
+ case AnimationFactory::CLASS_COLOR_PROPERTY:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createColorPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ xAnimateNode );
+
+ case AnimationFactory::CLASS_STRING_PROPERTY:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createStringPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ xAnimateNode );
+
+ case AnimationFactory::CLASS_BOOL_PROPERTY:
+ return ActivitiesFactory::createAnimateActivity(
+ aParms,
+ AnimationFactory::createBoolPropertyAnimation(
+ attrName,
+ pShape,
+ getContext().mpSubsettableShapeManager,
+ getSlideSize() ),
+ xAnimateNode );
+ }
+
+ return AnimationActivitySharedPtr();
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/propertyanimationnode.hxx b/slideshow/source/engine/animationnodes/propertyanimationnode.hxx
new file mode 100644
index 000000000000..66232ccf8063
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/propertyanimationnode.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_PROPERTYANIMATIONNODE_HXX
+#define INCLUDED_SLIDESHOW_PROPERTYANIMATIONNODE_HXX
+
+#include "animationbasenode.hxx"
+
+namespace slideshow {
+namespace internal {
+
+class PropertyAnimationNode : public AnimationBaseNode
+{
+public:
+ PropertyAnimationNode(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ ::boost::shared_ptr<BaseContainerNode> const& pParent,
+ NodeContext const& rContext )
+ : AnimationBaseNode( xNode, pParent, rContext ) {}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual const char* getDescription() const
+ { return "PropertyAnimationNode"; }
+#endif
+
+private:
+ virtual AnimationActivitySharedPtr createActivity() const;
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_PROPERTYANIMATIONNODE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx b/slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx
new file mode 100644
index 000000000000..298900b67d25
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/sequentialtimecontainer.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include "delayevent.hxx"
+#include "eventqueue.hxx"
+#include "usereventqueue.hxx"
+#include "sequentialtimecontainer.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace slideshow {
+namespace internal {
+
+void SequentialTimeContainer::activate_st()
+{
+ // resolve first possible child, ignore
+ for ( ; mnFinishedChildren < maChildren.size(); ++mnFinishedChildren ) {
+ if (resolveChild( maChildren[mnFinishedChildren] ))
+ break;
+ else {
+ // node still UNRESOLVED, no need to deactivate or end...
+ OSL_FAIL( "### resolving child failed!" );
+ }
+ }
+
+ if (isDurationIndefinite() &&
+ (maChildren.empty() || mnFinishedChildren >= maChildren.size()))
+ {
+ // deactivate ASAP:
+ scheduleDeactivationEvent(
+ makeEvent(
+ boost::bind< void >( boost::mem_fn( &AnimationNode::deactivate ), getSelf() ),
+ "SequentialTimeContainer::deactivate") );
+ }
+ else // use default
+ scheduleDeactivationEvent();
+}
+
+void SequentialTimeContainer::dispose()
+{
+ BaseContainerNode::dispose();
+ if (mpCurrentSkipEvent) {
+ mpCurrentSkipEvent->dispose();
+ mpCurrentSkipEvent.reset();
+ }
+ if (mpCurrentRewindEvent) {
+ mpCurrentRewindEvent->dispose();
+ mpCurrentRewindEvent.reset();
+ }
+}
+
+void SequentialTimeContainer::skipEffect(
+ AnimationNodeSharedPtr const& pChildNode )
+{
+ if (isChildNode(pChildNode)) {
+ // empty all events ignoring timings => until next effect
+ getContext().mrEventQueue.forceEmpty();
+ getContext().mrEventQueue.addEvent(
+ makeEvent(
+ boost::bind<void>( boost::mem_fn( &AnimationNode::deactivate ), pChildNode ),
+ "SequentialTimeContainer::deactivate, skipEffect with delay") );
+ }
+ else
+ OSL_FAIL( "unknown notifier!" );
+}
+
+void SequentialTimeContainer::rewindEffect(
+ AnimationNodeSharedPtr const& /*pChildNode*/ )
+{
+ // xxx todo: ...
+}
+
+bool SequentialTimeContainer::resolveChild(
+ AnimationNodeSharedPtr const& pChildNode )
+{
+ bool const bResolved = pChildNode->resolve();
+ if (bResolved && isMainSequenceRootNode()) {
+ // discharge events:
+ if (mpCurrentSkipEvent)
+ mpCurrentSkipEvent->dispose();
+ if (mpCurrentRewindEvent)
+ mpCurrentRewindEvent->dispose();
+
+ // event that will deactivate the resolved/running child:
+ mpCurrentSkipEvent = makeEvent(
+ boost::bind( &SequentialTimeContainer::skipEffect,
+ boost::dynamic_pointer_cast<SequentialTimeContainer>( getSelf() ),
+ pChildNode ),
+ "SequentialTimeContainer::skipEffect, resolveChild");
+ // event that will reresolve the resolved/activated child:
+ mpCurrentRewindEvent = makeEvent(
+ boost::bind( &SequentialTimeContainer::rewindEffect,
+ boost::dynamic_pointer_cast<SequentialTimeContainer>( getSelf() ),
+ pChildNode ),
+ "SequentialTimeContainer::rewindEffect, resolveChild");
+
+ // deactivate child node when skip event occurs:
+ getContext().mrUserEventQueue.registerSkipEffectEvent(
+ mpCurrentSkipEvent,
+ mnFinishedChildren+1<maChildren.size());
+ // rewind to previous child:
+ getContext().mrUserEventQueue.registerRewindEffectEvent(
+ mpCurrentRewindEvent );
+ }
+ return bResolved;
+}
+
+void SequentialTimeContainer::notifyDeactivating(
+ AnimationNodeSharedPtr const& rNotifier )
+{
+ if (notifyDeactivatedChild( rNotifier ))
+ return;
+
+ OSL_ASSERT( mnFinishedChildren < maChildren.size() );
+ AnimationNodeSharedPtr const& pNextChild = maChildren[mnFinishedChildren];
+ OSL_ASSERT( pNextChild->getState() == UNRESOLVED );
+
+ if (! resolveChild( pNextChild )) {
+ // could not resolve child - since we risk to
+ // stall the chain of events here, play it safe
+ // and deactivate this node (only if we have
+ // indefinite duration - otherwise, we'll get a
+ // deactivation event, anyways).
+ deactivate();
+ }
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/sequentialtimecontainer.hxx b/slideshow/source/engine/animationnodes/sequentialtimecontainer.hxx
new file mode 100644
index 000000000000..003d80333074
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/sequentialtimecontainer.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_SEQUENTIALTIMECONTAINER_HXX
+#define INCLUDED_SLIDESHOW_SEQUENTIALTIMECONTAINER_HXX
+
+#include "basecontainernode.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** This class implements sequential node containers
+
+ All children of this node are played sequentially
+*/
+class SequentialTimeContainer : public BaseContainerNode
+{
+public:
+ SequentialTimeContainer(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode> const& xNode,
+ BaseContainerNodeSharedPtr const& pParent,
+ NodeContext const& rContext )
+ : BaseContainerNode( xNode, pParent, rContext ) {}
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ virtual const char* getDescription() const
+ { return "SequentialTimeContainer"; }
+#endif
+
+protected:
+ virtual void dispose();
+
+private:
+ virtual void activate_st();
+ virtual void notifyDeactivating( AnimationNodeSharedPtr const& rNotifier );
+
+ void skipEffect( AnimationNodeSharedPtr const& pChildNode );
+ void rewindEffect( AnimationNodeSharedPtr const& pChildNode );
+
+private:
+ bool resolveChild( AnimationNodeSharedPtr const& pChildNode );
+
+ EventSharedPtr mpCurrentSkipEvent;
+ EventSharedPtr mpCurrentRewindEvent;
+};
+
+} // namespace internal
+} // namespace slideshow
+
+#endif /* INCLUDED_SLIDESHOW_SEQUENTIALTIMECONTAINER_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/animationnodes/setactivity.hxx b/slideshow/source/engine/animationnodes/setactivity.hxx
new file mode 100644
index 000000000000..821971115ea6
--- /dev/null
+++ b/slideshow/source/engine/animationnodes/setactivity.hxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_SETACTIVITY_HXX
+#define INCLUDED_SLIDESHOW_SETACTIVITY_HXX
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include "animationactivity.hxx"
+#include "animation.hxx"
+#include "animatableshape.hxx"
+#include "shapeattributelayer.hxx"
+#include "activitiesfactory.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** Templated setter for animation values
+
+ This template class implements the AnimationActivity
+ interface, but only the perform() and
+ setAttributeLayer() methods are functional. To be used for set animations.
+
+ @see AnimationSetNode.
+*/
+template <class AnimationT>
+class SetActivity : public AnimationActivity
+{
+public:
+ typedef ::boost::shared_ptr< AnimationT > AnimationSharedPtrT;
+ typedef typename AnimationT::ValueType ValueT;
+
+ SetActivity( const ActivitiesFactory::CommonParameters& rParms,
+ const AnimationSharedPtrT& rAnimation,
+ const ValueT& rToValue )
+ : mpAnimation( rAnimation ),
+ mpShape(),
+ mpAttributeLayer(),
+ mpEndEvent( rParms.mpEndEvent ),
+ mrEventQueue( rParms.mrEventQueue ),
+ maToValue( rToValue ),
+ mbIsActive(true)
+ {
+ ENSURE_OR_THROW( mpAnimation, "Invalid animation" );
+ }
+
+ virtual void dispose()
+ {
+ mbIsActive = false;
+ mpAnimation.reset();
+ mpShape.reset();
+ mpAttributeLayer.reset();
+ // discharge end event:
+ if (mpEndEvent && mpEndEvent->isCharged())
+ mpEndEvent->dispose();
+ mpEndEvent.reset();
+ }
+
+ virtual double calcTimeLag() const
+ {
+ return 0.0;
+ }
+
+ virtual bool perform()
+ {
+ if (! isActive())
+ return false;
+ // we're going inactive immediately:
+ mbIsActive = false;
+
+ if (mpAnimation && mpAttributeLayer && mpShape) {
+ mpAnimation->start( mpShape, mpAttributeLayer );
+ (*mpAnimation)(maToValue);
+ mpAnimation->end();
+ }
+ // fire end event, if any
+ if (mpEndEvent)
+ mrEventQueue.addEvent( mpEndEvent );
+
+ return false; // don't reinsert
+ }
+
+ virtual bool isActive() const
+ {
+ return mbIsActive;
+ }
+
+ virtual void dequeued()
+ {
+ }
+
+ virtual void end()
+ {
+ perform();
+ }
+
+ virtual void setTargets( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer )
+ {
+ ENSURE_OR_THROW( rShape, "Invalid shape" );
+ ENSURE_OR_THROW( rAttrLayer, "Invalid attribute layer" );
+
+ mpShape = rShape;
+ mpAttributeLayer = rAttrLayer;
+ }
+
+private:
+ AnimationSharedPtrT mpAnimation;
+ AnimatableShapeSharedPtr mpShape;
+ ShapeAttributeLayerSharedPtr mpAttributeLayer;
+ EventSharedPtr mpEndEvent;
+ EventQueue& mrEventQueue;
+ ValueT maToValue;
+ bool mbIsActive;
+};
+
+template <class AnimationT> AnimationActivitySharedPtr makeSetActivity(
+ const ActivitiesFactory::CommonParameters& rParms,
+ const ::boost::shared_ptr< AnimationT >& rAnimation,
+ const typename AnimationT::ValueType& rToValue )
+{
+ return AnimationActivitySharedPtr(
+ new SetActivity<AnimationT>(rParms,rAnimation,rToValue) );
+}
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_SETACTIVITY_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/arith-grammar.txt b/slideshow/source/engine/arith-grammar.txt
new file mode 100644
index 000000000000..b12d320ef3bf
--- /dev/null
+++ b/slideshow/source/engine/arith-grammar.txt
@@ -0,0 +1,61 @@
+Based on the C grammar for arithmetic expressions
+=================================================
+
+number_digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
+
+number_exponent = 'e'|'E'
+
+basic_number = basic_number number_digit | number_digit
+
+number =
+ basic_number |
+
+ basic_number number_exponent basic_number |
+ basic_number number_exponent '-' basic_number |
+ basic_number number_exponent '+' basic_number |
+
+ '.' basic_number number_exponent basic_number |
+ '.' basic_number number_exponent '-' basic_number |
+ '.' basic_number number_exponent '+' basic_number |
+
+ basic_number '.' number_exponent basic_number |
+ basic_number '.' number_exponent '-' basic_number |
+ basic_number '.' number_exponent '+' basic_number |
+
+ basic_number '.' basic_number number_exponent basic_number |
+ basic_number '.' basic_number number_exponent '-' basic_number |
+ basic_number '.' basic_number number_exponent '+' basic_number
+
+
+identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height'
+ ^ ^ ^ ^ ^
+ | | | | |
+ '$' in PPT | | | |
+ '#ppt_x' in PPT | | |
+ '#ppt_y' in PPT | |
+ '#ppt_w' in PPT |
+ '#ppt_h' in PPT
+
+unary_function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log'
+binary_function = 'min'|'max'
+
+
+basic_expression =
+ number |
+ identifier |
+ unary_function '(' additive_expression ')' |
+ binary_function '(' additive_expression ',' additive_expression ')' |
+ '(' additive_expression ')'
+
+unary_expression = '-' basic_expression
+
+multiplicative_expression =
+ basic_expression |
+ multiplicative_expression '*' basic_expression |
+ multiplicative_expression '/' basic_expression
+
+additive_expression =
+ multiplicative_expression |
+ additive_expression '+' multiplicative_expression |
+ additive_expression '-' multiplicative_expression
+
diff --git a/slideshow/source/engine/attributemap.cxx b/slideshow/source/engine/attributemap.cxx
new file mode 100644
index 000000000000..360cd8119e38
--- /dev/null
+++ b/slideshow/source/engine/attributemap.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/canvastools.hxx>
+
+#include "attributemap.hxx"
+#include "tools.hxx"
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ typedef ::canvas::tools::ValueMap< AttributeType > AnimateAttributeMap;
+
+ AttributeType mapAttributeName( const ::rtl::OUString& rAttrName )
+ {
+ /** Maps attribute name to AttributeType enum.
+
+ String entries are all case-insensitive and MUST
+ BE STORED lowercase.
+
+ String entries MUST BE SORTED in ascending order!
+ */
+ static AnimateAttributeMap::MapEntry lcl_attributeMap[] =
+ {
+ { "charcolor", ATTRIBUTE_CHAR_COLOR },
+ { "charfontname", ATTRIBUTE_CHAR_FONT_NAME },
+ { "charheight", ATTRIBUTE_CHAR_HEIGHT },
+ { "charposture", ATTRIBUTE_CHAR_POSTURE },
+ // TODO(Q1): This should prolly be changed in PPT import
+ // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
+ { "charrotation", ATTRIBUTE_ROTATE },
+ { "charunderline", ATTRIBUTE_CHAR_UNDERLINE },
+ { "charweight", ATTRIBUTE_CHAR_WEIGHT },
+ { "color", ATTRIBUTE_COLOR },
+ { "dimcolor", ATTRIBUTE_DIMCOLOR },
+ { "fillcolor", ATTRIBUTE_FILL_COLOR },
+ { "fillstyle", ATTRIBUTE_FILL_STYLE },
+ { "height", ATTRIBUTE_HEIGHT },
+ { "linecolor", ATTRIBUTE_LINE_COLOR },
+ { "linestyle", ATTRIBUTE_LINE_STYLE },
+ { "opacity", ATTRIBUTE_OPACITY },
+ { "rotate", ATTRIBUTE_ROTATE },
+ { "skewx", ATTRIBUTE_SKEW_X },
+ { "skewy", ATTRIBUTE_SKEW_Y },
+ { "visibility", ATTRIBUTE_VISIBILITY },
+ { "width", ATTRIBUTE_WIDTH },
+ { "x", ATTRIBUTE_POS_X },
+ { "y", ATTRIBUTE_POS_Y }
+ };
+
+ static AnimateAttributeMap aMap( lcl_attributeMap,
+ sizeof(lcl_attributeMap)/sizeof(*lcl_attributeMap),
+ false );
+
+ AttributeType eAttributeType = ATTRIBUTE_INVALID;
+
+ // determine the type from the attribute name
+ if( !aMap.lookup( rAttrName,
+ eAttributeType ) )
+ {
+ OSL_TRACE( "mapAttributeName(): attribute name %s not found in map.",
+ ::rtl::OUStringToOString( rAttrName,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ return ATTRIBUTE_INVALID;
+ }
+
+ return eAttributeType;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/color.cxx b/slideshow/source/engine/color.cxx
new file mode 100644
index 000000000000..dfa8b1409706
--- /dev/null
+++ b/slideshow/source/engine/color.cxx
@@ -0,0 +1,390 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <hslcolor.hxx>
+#include <rgbcolor.hxx>
+
+#include <basegfx/numeric/ftools.hxx>
+
+#include <cmath> // for fmod
+#include <algorithm>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ namespace
+ {
+ // helper functions
+ // ================
+
+ double getMagic( double nLuminance, double nSaturation )
+ {
+ if( nLuminance <= 0.5 )
+ return nLuminance*(1.0 + nSaturation);
+ else
+ return nLuminance + nSaturation - nLuminance*nSaturation;
+ }
+
+ HSLColor::HSLTriple rgb2hsl( double nRed, double nGreen, double nBlue )
+ {
+ // r,g,b in [0,1], h in [0,360] and s,l in [0,1]
+ HSLColor::HSLTriple aRes;
+
+ const double nMax( ::std::max(nRed,::std::max(nGreen, nBlue)) );
+ const double nMin( ::std::min(nRed,::std::min(nGreen, nBlue)) );
+
+ const double nDelta( nMax - nMin );
+
+ aRes.mnLuminance = (nMax + nMin) / 2.0;
+
+ if( ::basegfx::fTools::equalZero( nDelta ) )
+ {
+ aRes.mnSaturation = 0.0;
+
+ // hue undefined (achromatic case)
+ aRes.mnHue = 0.0;
+ }
+ else
+ {
+ aRes.mnSaturation = aRes.mnLuminance > 0.5 ?
+ nDelta/(2.0-nMax-nMin) :
+ nDelta/(nMax + nMin);
+
+ if( nRed == nMax )
+ aRes.mnHue = (nGreen - nBlue)/nDelta;
+ else if( nGreen == nMax )
+ aRes.mnHue = 2.0 + (nBlue - nRed)/nDelta;
+ else if( nBlue == nMax )
+ aRes.mnHue = 4.0 + (nRed - nGreen)/nDelta;
+
+ aRes.mnHue *= 60.0;
+
+ if( aRes.mnHue < 0.0 )
+ aRes.mnHue += 360.0;
+ }
+
+ return aRes;
+ }
+
+ double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
+ {
+ // clamp hue to [0,360]
+ nHue = fmod( nHue, 360.0 );
+
+ // cope with wrap-arounds
+ if( nHue < 0.0 )
+ nHue += 360.0;
+
+ if( nHue < 60.0 )
+ return nValue1 + (nValue2 - nValue1)*nHue/60.0;
+ else if( nHue < 180.0 )
+ return nValue2;
+ else if( nHue < 240.0 )
+ return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
+ else
+ return nValue1;
+ }
+
+ RGBColor::RGBTriple hsl2rgb( double nHue, double nSaturation, double nLuminance )
+ {
+ if( ::basegfx::fTools::equalZero( nSaturation ) )
+ return RGBColor::RGBTriple(0.0, 0.0, nLuminance );
+
+ const double nVal1( getMagic(nLuminance, nSaturation) );
+ const double nVal2( 2.0*nLuminance - nVal1 );
+
+ RGBColor::RGBTriple aRes;
+
+ aRes.mnRed = hsl2rgbHelper( nVal2,
+ nVal1,
+ nHue + 120.0 );
+ aRes.mnGreen = hsl2rgbHelper( nVal2,
+ nVal1,
+ nHue );
+ aRes.mnBlue = hsl2rgbHelper( nVal2,
+ nVal1,
+ nHue - 120.0 );
+
+ return aRes;
+ }
+
+ /// Truncate range of value to [0,1]
+ double truncateRangeStd( double nVal )
+ {
+ return ::std::max( 0.0,
+ ::std::min( 1.0,
+ nVal ) );
+ }
+
+ /// Truncate range of value to [0,360]
+ double truncateRangeHue( double nVal )
+ {
+ return ::std::max( 0.0,
+ ::std::min( 360.0,
+ nVal ) );
+ }
+
+ /// convert RGB color to sal_uInt8, truncate range appropriately before
+ sal_uInt8 colorToInt( double nCol )
+ {
+ return static_cast< sal_uInt8 >(
+ ::basegfx::fround( truncateRangeStd( nCol ) * 255.0 ) );
+ }
+ }
+
+
+
+ // HSLColor
+ // ===============================================
+
+ HSLColor::HSLTriple::HSLTriple() :
+ mnHue(),
+ mnSaturation(),
+ mnLuminance()
+ {
+ }
+
+ HSLColor::HSLTriple::HSLTriple( double nHue, double nSaturation, double nLuminance ) :
+ mnHue( nHue ),
+ mnSaturation( nSaturation ),
+ mnLuminance( nLuminance )
+ {
+ }
+
+ HSLColor::HSLColor() :
+ maHSLTriple( 0.0, 0.0, 0.0 ),
+ mnMagicValue( getMagic( maHSLTriple.mnLuminance,
+ maHSLTriple.mnSaturation ) )
+ {
+ }
+
+ HSLColor::HSLColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
+ maHSLTriple( rgb2hsl( ::cppcanvas::getRed( nRGBColor ) / 255.0,
+ ::cppcanvas::getGreen( nRGBColor ) / 255.0,
+ ::cppcanvas::getBlue( nRGBColor ) / 255.0 ) ),
+ mnMagicValue( getMagic( maHSLTriple.mnLuminance,
+ maHSLTriple.mnSaturation ) )
+ {
+ }
+
+ HSLColor::HSLColor( double nHue, double nSaturation, double nLuminance ) :
+ maHSLTriple( nHue, nSaturation, nLuminance ),
+ mnMagicValue( getMagic( maHSLTriple.mnLuminance,
+ maHSLTriple.mnSaturation ) )
+ {
+ }
+
+ HSLColor::HSLColor( const RGBColor& rColor ) :
+ maHSLTriple( rgb2hsl( truncateRangeStd( rColor.getRed() ),
+ truncateRangeStd( rColor.getGreen() ),
+ truncateRangeStd( rColor.getBlue() ) ) ),
+ mnMagicValue( getMagic( maHSLTriple.mnLuminance,
+ maHSLTriple.mnSaturation ) )
+ {
+ }
+
+ double HSLColor::getHue() const
+ {
+ return maHSLTriple.mnHue;
+ }
+
+ double HSLColor::getSaturation() const
+ {
+ return maHSLTriple.mnSaturation;
+ }
+
+ double HSLColor::getLuminance() const
+ {
+ return maHSLTriple.mnLuminance;
+ }
+
+ HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS )
+ {
+ return HSLColor( rLHS.getHue() + rRHS.getHue(),
+ rLHS.getSaturation() + rRHS.getSaturation(),
+ rLHS.getLuminance() + rRHS.getLuminance() );
+ }
+
+ HSLColor operator*( const HSLColor& rLHS, const HSLColor& rRHS )
+ {
+ return HSLColor( rLHS.getHue() * rRHS.getHue(),
+ rLHS.getSaturation() * rRHS.getSaturation(),
+ rLHS.getLuminance() * rRHS.getLuminance() );
+ }
+
+ HSLColor operator*( double nFactor, const HSLColor& rRHS )
+ {
+ return HSLColor( nFactor * rRHS.getHue(),
+ nFactor * rRHS.getSaturation(),
+ nFactor * rRHS.getLuminance() );
+ }
+
+ HSLColor interpolate( const HSLColor& rFrom, const HSLColor& rTo, double t, bool bCCW )
+ {
+ const double nFromHue( rFrom.getHue() );
+ const double nToHue ( rTo.getHue() );
+
+ double nHue=0.0;
+
+ if( nFromHue <= nToHue && !bCCW )
+ {
+ // interpolate hue clockwise. That is, hue starts at
+ // high values and ends at low ones. Therefore, we
+ // must 'cross' the 360 degrees and start at low
+ // values again (imagine the hues to lie on the
+ // circle, where values above 360 degrees are mapped
+ // back to [0,360)).
+ nHue = (1.0-t)*(nFromHue + 360.0) + t*nToHue;
+ }
+ else if( nFromHue > nToHue && bCCW )
+ {
+ // interpolate hue counter-clockwise. That is, hue
+ // starts at high values and ends at low
+ // ones. Therefore, we must 'cross' the 360 degrees
+ // and start at low values again (imagine the hues to
+ // lie on the circle, where values above 360 degrees
+ // are mapped back to [0,360)).
+ nHue = (1.0-t)*nFromHue + t*(nToHue + 360.0);
+ }
+ else
+ {
+ // interpolate hue counter-clockwise. That is, hue
+ // starts at low values and ends at high ones (imagine
+ // the hue value as degrees on a circle, with
+ // increasing values going counter-clockwise)
+ nHue = (1.0-t)*nFromHue + t*nToHue;
+ }
+
+ return HSLColor( nHue,
+ (1.0-t)*rFrom.getSaturation() + t*rTo.getSaturation(),
+ (1.0-t)*rFrom.getLuminance() + t*rTo.getLuminance() );
+ }
+
+
+
+ // RGBColor
+ // ===============================================
+
+
+ RGBColor::RGBTriple::RGBTriple() :
+ mnRed(),
+ mnGreen(),
+ mnBlue()
+ {
+ }
+
+ RGBColor::RGBTriple::RGBTriple( double nRed, double nGreen, double nBlue ) :
+ mnRed( nRed ),
+ mnGreen( nGreen ),
+ mnBlue( nBlue )
+ {
+ }
+
+ RGBColor::RGBColor() :
+ maRGBTriple( 0.0, 0.0, 0.0 )
+ {
+ }
+
+ RGBColor::RGBColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
+ maRGBTriple( ::cppcanvas::getRed( nRGBColor ) / 255.0,
+ ::cppcanvas::getGreen( nRGBColor ) / 255.0,
+ ::cppcanvas::getBlue( nRGBColor ) / 255.0 )
+ {
+ }
+
+ RGBColor::RGBColor( double nRed, double nGreen, double nBlue ) :
+ maRGBTriple( nRed, nGreen, nBlue )
+ {
+ }
+
+ RGBColor::RGBColor( const HSLColor& rColor ) :
+ maRGBTriple( hsl2rgb( truncateRangeHue( rColor.getHue() ),
+ truncateRangeStd( rColor.getSaturation() ),
+ truncateRangeStd( rColor.getLuminance() ) ) )
+ {
+ }
+
+ double RGBColor::getRed() const
+ {
+ return maRGBTriple.mnRed;
+ }
+
+ double RGBColor::getGreen() const
+ {
+ return maRGBTriple.mnGreen;
+ }
+
+ double RGBColor::getBlue() const
+ {
+ return maRGBTriple.mnBlue;
+ }
+
+ ::cppcanvas::Color::IntSRGBA RGBColor::getIntegerColor() const
+ {
+ return ::cppcanvas::makeColor( colorToInt( getRed() ),
+ colorToInt( getGreen() ),
+ colorToInt( getBlue() ),
+ 255 );
+ }
+
+ RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS )
+ {
+ return RGBColor( rLHS.getRed() + rRHS.getRed(),
+ rLHS.getGreen() + rRHS.getGreen(),
+ rLHS.getBlue() + rRHS.getBlue() );
+ }
+
+ RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS )
+ {
+ return RGBColor( rLHS.getRed() * rRHS.getRed(),
+ rLHS.getGreen() * rRHS.getGreen(),
+ rLHS.getBlue() * rRHS.getBlue() );
+ }
+
+ RGBColor operator*( double nFactor, const RGBColor& rRHS )
+ {
+ return RGBColor( nFactor * rRHS.getRed(),
+ nFactor * rRHS.getGreen(),
+ nFactor * rRHS.getBlue() );
+ }
+
+ RGBColor interpolate( const RGBColor& rFrom, const RGBColor& rTo, double t )
+ {
+ return RGBColor( (1.0-t)*rFrom.getRed() + t*rTo.getRed(),
+ (1.0-t)*rFrom.getGreen() + t*rTo.getGreen(),
+ (1.0-t)*rFrom.getBlue() + t*rTo.getBlue() );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/debug.cxx b/slideshow/source/engine/debug.cxx
new file mode 100644
index 000000000000..bc5f24f95509
--- /dev/null
+++ b/slideshow/source/engine/debug.cxx
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_slideshow.hxx"
+
+#include "debug.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+
+#include "animationnodes/basecontainernode.hxx"
+#include "animationnodes/paralleltimecontainer.hxx"
+#include "animationnodes/sequentialtimecontainer.hxx"
+#include "animationnodes/animationtransitionfilternode.hxx"
+#include "animationnodes/animationaudionode.hxx"
+#include "animationnodes/animationcolornode.hxx"
+#include "animationnodes/animationcommandnode.hxx"
+#include "animationnodes/animationpathmotionnode.hxx"
+#include "animationnodes/animationsetnode.hxx"
+#include "animationnodes/animationtransformnode.hxx"
+#include "animationnodes/propertyanimationnode.hxx"
+
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/Event.hpp>
+
+#include <cstdio>
+#include <cstdarg>
+
+using ::rtl::OUString;
+using namespace ::com::sun::star;
+
+
+namespace slideshow { namespace internal {
+
+namespace {
+
+class NodeContainer : public BaseContainerNode
+{
+public:
+ void ShowChildrenState (void) const;
+};
+
+
+
+
+OUString DebugGetDescription (const AnimationNodeSharedPtr& rpNode)
+{
+ if (::boost::dynamic_pointer_cast<BaseContainerNode>(rpNode))
+ {
+ // Node is a container.
+ if (::boost::dynamic_pointer_cast<ParallelTimeContainer>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("ParallelTimeContainer"));
+ else if (::boost::dynamic_pointer_cast<SequentialTimeContainer>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("SequentialTimeContainer"));
+ else
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("<unknown container>"));
+ }
+ else if (::boost::dynamic_pointer_cast<AnimationTransitionFilterNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("AnimationTransitionFilterNode"));
+ else if (::boost::dynamic_pointer_cast<AnimationAudioNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("AnimationAudioNode"));
+ else if (::boost::dynamic_pointer_cast<AnimationColorNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("AnimationColorNode"));
+ else if (::boost::dynamic_pointer_cast<AnimationCommandNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("AnimationCommandNode"));
+ else if (::boost::dynamic_pointer_cast<AnimationPathMotionNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("AnimationPathMotionNode"));
+ else if (::boost::dynamic_pointer_cast<AnimationSetNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("AnimationSetNode"));
+ else if (::boost::dynamic_pointer_cast<AnimationTransformNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("AnimationTransformNode"));
+ else if (::boost::dynamic_pointer_cast<PropertyAnimationNode>(rpNode))
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("PropertyAnimationNode"));
+ else
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("<unknown node type>"));
+}
+
+
+
+
+void DebugShowState (const AnimationNodeSharedPtr& rpNode)
+{
+ if ( ! rpNode)
+ return;
+
+ OUString sState;
+ OUString sStateColor;
+ switch (rpNode->getState())
+ {
+ default:
+ case AnimationNode::INVALID:
+ sState = OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid"));
+ sStateColor = OUString(RTL_CONSTASCII_USTRINGPARAM("firebrick1"));
+ break;
+ case AnimationNode::UNRESOLVED:
+ sState = OUString(RTL_CONSTASCII_USTRINGPARAM("Unresolved"));
+ sStateColor = OUString(RTL_CONSTASCII_USTRINGPARAM("dodgerblue4"));
+ break;
+ case AnimationNode::RESOLVED:
+ sState = OUString(RTL_CONSTASCII_USTRINGPARAM("Resolved"));
+ sStateColor = OUString(RTL_CONSTASCII_USTRINGPARAM("dodgerblue"));
+ break;
+ case AnimationNode::ACTIVE:
+ sState = OUString(RTL_CONSTASCII_USTRINGPARAM("Active"));
+ sStateColor = OUString(RTL_CONSTASCII_USTRINGPARAM("seagreen1"));
+ break;
+ case AnimationNode::FROZEN:
+ sState = OUString(RTL_CONSTASCII_USTRINGPARAM("Frozen"));
+ sStateColor = OUString(RTL_CONSTASCII_USTRINGPARAM("lightskyblue1"));
+ break;
+ case AnimationNode::ENDED:
+ sState = OUString(RTL_CONSTASCII_USTRINGPARAM("Ended"));
+ sStateColor = OUString(RTL_CONSTASCII_USTRINGPARAM("slategray3"));
+ break;
+ }
+
+ const uno::Any aBegin (rpNode->getXAnimationNode()->getBegin());
+ OUString sTrigger;
+ if (aBegin.hasValue())
+ {
+ animations::Event aEvent;
+ double nTimeOffset;
+ const static char* sEventTriggers[] = {
+ "NONE", "ON_BEGIN", "ON_END", "BEGIN_EVENT", "END_EVENT", "ON_CLICK",
+ "ON_DBL_CLICK", "ON_MOUSE_ENTER", "ON_MOUSE_LEAVE", "ON_NEXT", "ON_PREV",
+ "ON_STOP_AUDIO", "REPEAT"};
+ if (aBegin >>= aEvent)
+ {
+ sTrigger = OUString::createFromAscii(sEventTriggers[aEvent.Trigger]);
+ }
+ else if (aBegin >>= nTimeOffset)
+ {
+ sTrigger = OUString::valueOf(nTimeOffset);
+ }
+ else
+ {
+ sTrigger = OUString(RTL_CONSTASCII_USTRINGPARAM("other"));
+ }
+ }
+ else
+ sTrigger = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("void"));
+
+ TRACE("Node state: n%x [label=\"%x / %x / %s\\n%s\\n%s\",style=filled,fillcolor=\"%s\"]\r",
+ rpNode.get(),
+ rpNode.get(),
+ rpNode->getXAnimationNode().get(),
+ ::rtl::OUStringToOString(sState, RTL_TEXTENCODING_ASCII_US).getStr(),
+ ::rtl::OUStringToOString(DebugGetDescription(rpNode), RTL_TEXTENCODING_ASCII_US).getStr(),
+ ::rtl::OUStringToOString(sTrigger, RTL_TEXTENCODING_ASCII_US).getStr(),
+ ::rtl::OUStringToOString(sStateColor, RTL_TEXTENCODING_ASCII_US).getStr());
+
+ BaseContainerNodeSharedPtr pContainer (
+ ::boost::dynamic_pointer_cast<BaseContainerNode>(rpNode));
+ if (pContainer)
+ ::boost::static_pointer_cast<NodeContainer>(rpNode)->ShowChildrenState();
+}
+
+
+
+
+void NodeContainer::ShowChildrenState (void) const
+{
+ for (std::size_t nIndex=0; nIndex<maChildren.size(); ++nIndex)
+ {
+ TRACE("Node connection: n%x -> n%x", this, maChildren[nIndex].get());
+ DebugShowState(maChildren[nIndex]);
+ }
+}
+
+
+
+
+AnimationNodeSharedPtr DebugGetTreeRoot (const BaseNodeSharedPtr& rpNode)
+{
+ BaseNodeSharedPtr pNode (rpNode);
+ if (pNode)
+ {
+ BaseNodeSharedPtr pParent (pNode->getParentNode());
+ while (pParent)
+ {
+ pNode = pParent;
+ pParent = pNode->getParentNode();
+ }
+ }
+ return pNode;
+}
+
+} // end of anonymous namespace
+
+
+
+
+void Debug_ShowNodeTree (const AnimationNodeSharedPtr& rpNode)
+{
+ DebugTraceScope aTraceScope ("NodeTree");
+
+ DebugShowState(DebugGetTreeRoot(::boost::dynamic_pointer_cast<BaseNode>(rpNode)));
+}
+
+
+
+
+//----- Tracing ---------------------------------------------------------------
+
+extern "C" {
+
+ namespace {
+
+ class TraceData
+ {
+ public:
+ TraceData (void)
+ : mnIndentation(0),
+ mpFile(fopen(TRACE_LOG_FILE_NAME, "w")),
+ maTime()
+ {
+ }
+
+ int mnIndentation;
+ FILE* mpFile;
+ ::canvas::tools::ElapsedTime maTime;
+ };
+ static TraceData gTraceData;
+
+ inline void SAL_CALL DebugTrace (
+ const int nIndentationOffset,
+ const sal_Char* sFormat,
+ va_list args)
+ {
+ if (gTraceData.mpFile != NULL)
+ {
+ // Write line head with current time and indentation.
+ // Adapt indentation.
+ if (nIndentationOffset < 0)
+ gTraceData.mnIndentation += nIndentationOffset;
+ fprintf(gTraceData.mpFile, "%10.8f ", gTraceData.maTime.getElapsedTime());
+ for (int nIndentation=0; nIndentation<gTraceData.mnIndentation; ++nIndentation)
+ fprintf(gTraceData.mpFile, " ");
+ if (nIndentationOffset > 0)
+ gTraceData.mnIndentation += nIndentationOffset;
+
+ // Write message.
+ vfprintf(gTraceData.mpFile, sFormat, args);
+ fprintf(gTraceData.mpFile, "\n");
+ fflush(gTraceData.mpFile);
+ }
+ }
+
+} // end of anonymous namespace
+
+
+} // end of extern "C"
+
+void SAL_CALL DebugTraceBegin (const sal_Char* sFormat, ...)
+{
+ va_list args;
+ va_start(args, sFormat);
+ DebugTrace(+1,sFormat, args);
+ va_end(args);
+}
+
+void SAL_CALL DebugTraceEnd (const sal_Char* sFormat, ...)
+{
+ va_list args;
+ va_start(args, sFormat);
+ DebugTrace(-1,sFormat, args);
+ va_end(args);
+}
+
+void SAL_CALL DebugTraceMessage (const sal_Char* sFormat, ...)
+{
+ va_list args;
+ va_start(args, sFormat);
+ DebugTrace(0,sFormat, args);
+ va_end(args);
+}
+
+
+
+DebugTraceScope::DebugTraceScope (const sal_Char* sFormat, ...)
+ : msMessage(new sal_Char[mnBufferSize])
+{
+ va_list args;
+ va_start(args, sFormat);
+
+ msMessage[mnBufferSize-1] = 0;
+ vsnprintf(msMessage, mnBufferSize-1, sFormat, args);
+ TRACE_BEGIN("[ %s", msMessage);
+ va_end(args);
+}
+
+DebugTraceScope::~DebugTraceScope (void)
+{
+ TRACE_END("] %s", msMessage);
+ delete [] msMessage;
+}
+
+
+} }
+
+#endif // OSL_DEBUG_LEVEL > 1
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/delayevent.cxx b/slideshow/source/engine/delayevent.cxx
new file mode 100644
index 000000000000..3554d1cd8d6f
--- /dev/null
+++ b/slideshow/source/engine/delayevent.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <osl/diagnose.h>
+#include "delayevent.hxx"
+
+namespace slideshow {
+namespace internal {
+
+bool Delay::fire()
+{
+ OSL_ASSERT( isCharged() );
+ if (isCharged()) {
+ mbWasFired = true;
+ maFunc();
+ maFunc.clear(); // early release of payload
+ }
+ return true;
+}
+
+bool Delay::isCharged() const
+{
+ return !mbWasFired;
+}
+
+double Delay::getActivationTime( double nCurrentTime ) const
+{
+ return nCurrentTime + mnTimeout;
+}
+
+void Delay::dispose()
+{
+ // don't clear unconditionally, because it may currently be executed:
+ if (isCharged()) {
+ mbWasFired = true;
+ maFunc.clear(); // release of payload
+ }
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/effectrewinder.cxx b/slideshow/source/engine/effectrewinder.cxx
new file mode 100644
index 000000000000..9d58ab9f19fd
--- /dev/null
+++ b/slideshow/source/engine/effectrewinder.cxx
@@ -0,0 +1,436 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_slideshow.hxx"
+
+#include "effectrewinder.hxx"
+#include "eventqueue.hxx"
+#include "usereventqueue.hxx"
+#include "mouseeventhandler.hxx"
+#include "animationnodes/basecontainernode.hxx"
+#include "delayevent.hxx"
+
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+using ::com::sun::star::uno::Reference;
+using namespace ::com::sun::star;
+
+namespace slideshow { namespace internal {
+
+
+namespace {
+
+class RewinderEventHandler : public EventHandler
+{
+public:
+ typedef ::boost::function<bool(void)> Action;
+ RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
+ virtual ~RewinderEventHandler (void) {}
+private:
+ const Action maAction;
+ virtual bool handleEvent (void) { return maAction(); }
+};
+
+
+
+class RewinderAnimationEventHandler : public AnimationEventHandler
+{
+public:
+ typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action;
+ RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
+ virtual ~RewinderAnimationEventHandler (void) {}
+private:
+ const Action maAction;
+ virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode)
+ { return maAction(rpNode); }
+};
+
+
+
+} // end of anonymous namespace
+
+
+//----- EffectRewinder --------------------------------------------------------------
+
+EffectRewinder::EffectRewinder (
+ EventMultiplexer& rEventMultiplexer,
+ EventQueue& rEventQueue,
+ UserEventQueue& rUserEventQueue)
+ : mrEventMultiplexer(rEventMultiplexer),
+ mrEventQueue(rEventQueue),
+ mrUserEventQueue(rUserEventQueue),
+ mpSlideStartHandler(),
+ mpSlideEndHandler(),
+ mpAnimationStartHandler(),
+ mnMainSequenceEffectCount(0),
+ mpAsynchronousRewindEvent(),
+ mxCurrentAnimationRootNode(),
+ mbNonUserTriggeredMainSequenceEffectSeen(false)
+{
+ initialize();
+}
+
+
+
+
+void EffectRewinder::initialize (void)
+{
+ // Add some event handlers so that we are informed when
+ // a) an animation is started (we then check whether that belongs to a
+ // main sequence effect and if so, increase the respective counter),
+ // b,c) a slide was started or ended (in which case the effect counter
+ // is reset.
+
+ mpAnimationStartHandler.reset(
+ new RewinderAnimationEventHandler(
+ ::boost::bind(&EffectRewinder::notifyAnimationStart, this, _1)));
+ mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
+
+ mpSlideStartHandler.reset(
+ new RewinderEventHandler(
+ ::boost::bind(&EffectRewinder::resetEffectCount, this)));
+ mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
+
+ mpSlideEndHandler.reset(
+ new RewinderEventHandler(
+ ::boost::bind(&EffectRewinder::resetEffectCount, this)));
+ mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
+}
+
+
+
+
+EffectRewinder::~EffectRewinder (void)
+{
+ dispose();
+}
+
+
+
+
+void EffectRewinder::dispose (void)
+{
+ if (mpAsynchronousRewindEvent)
+ {
+ mpAsynchronousRewindEvent->dispose();
+ mpAsynchronousRewindEvent.reset();
+ }
+
+ if (mpAnimationStartHandler)
+ {
+ mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
+ mpAnimationStartHandler.reset();
+ }
+
+ if (mpSlideStartHandler)
+ {
+ mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
+ mpSlideStartHandler.reset();
+ }
+
+ if (mpSlideEndHandler)
+ {
+ mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
+ mpSlideEndHandler.reset();
+ }
+}
+
+
+
+
+void EffectRewinder::setRootAnimationNode (
+ const uno::Reference<animations::XAnimationNode>& xRootNode)
+{
+ mxCurrentAnimationRootNode = xRootNode;
+}
+
+
+
+
+bool EffectRewinder::rewind (
+ const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
+ const ::boost::function<void(void)>& rSlideRewindFunctor,
+ const ::boost::function<void(void)>& rPreviousSlideFunctor)
+{
+ mpPaintLock = rpPaintLock;
+
+ // Do not allow nested rewinds.
+ if (mpAsynchronousRewindEvent)
+ {
+ OSL_ASSERT( ! mpAsynchronousRewindEvent);
+ return false;
+ }
+
+ // Abort (and skip over the rest of) any currently active animation.
+ mrUserEventQueue.callSkipEffectEventHandler();
+ mrEventQueue.forceEmpty();
+
+ const int nSkipCount (mnMainSequenceEffectCount - 1);
+ if (nSkipCount < 0)
+ {
+ if ( ! rPreviousSlideFunctor)
+ {
+ OSL_ASSERT(rPreviousSlideFunctor);
+ return false;
+ }
+
+ // No main sequence effects to rewind on the current slide.
+ // Go back to the previous slide.
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::asynchronousRewindToPreviousSlide,
+ this,
+ rPreviousSlideFunctor),
+ "EffectRewinder::asynchronousRewindToPreviousSlide");
+ }
+ else
+ {
+ // The actual rewinding is done asynchronously so that we can safely
+ // call other methods.
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::asynchronousRewind,
+ this,
+ nSkipCount,
+ true,
+ rSlideRewindFunctor),
+ "EffectRewinder::asynchronousRewind");
+ }
+
+ if (mpAsynchronousRewindEvent)
+ mrEventQueue.addEvent(mpAsynchronousRewindEvent);
+
+ return mpAsynchronousRewindEvent.get()!=NULL;
+}
+
+
+
+
+void EffectRewinder::skipAllMainSequenceEffects (void)
+{
+ // Do not allow nested rewinds.
+ if (mpAsynchronousRewindEvent)
+ {
+ OSL_ASSERT(!mpAsynchronousRewindEvent);
+ return;
+ }
+
+ const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::asynchronousRewind,
+ this,
+ nTotalMainSequenceEffectCount,
+ false,
+ ::boost::function<void(void)>()),
+ "EffectRewinder::asynchronousRewind");
+ mrEventQueue.addEvent(mpAsynchronousRewindEvent);
+}
+
+
+
+
+sal_Int32 EffectRewinder::countMainSequenceEffects (void)
+{
+ // Determine the number of main sequence effects.
+ sal_Int32 nMainSequenceNodeCount (0);
+
+ ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
+ aNodeQueue.push(mxCurrentAnimationRootNode);
+ while ( ! aNodeQueue.empty())
+ {
+ const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
+ aNodeQueue.pop();
+
+ // Does the current node belong to the main sequence?
+ if (xNode.is())
+ {
+ animations::Event aEvent;
+ if (xNode->getBegin() >>= aEvent)
+ if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
+ ++nMainSequenceNodeCount;
+ }
+
+ // If the current node is a container then prepare its children for investigation.
+ uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
+ if (xEnumerationAccess.is())
+ {
+ uno::Reference<container::XEnumeration> xEnumeration (
+ xEnumerationAccess->createEnumeration());
+ if (xEnumeration.is())
+ while (xEnumeration->hasMoreElements())
+ {
+ aNodeQueue.push(
+ uno::Reference<animations::XAnimationNode>(
+ xEnumeration->nextElement(), uno::UNO_QUERY));
+ }
+ }
+ }
+
+ return nMainSequenceNodeCount;
+
+ // // Skip all main sequence nodes.
+ // SkipSomeMainSequenceEffects(nMainSequenceNodeCount);
+}
+
+
+
+
+void EffectRewinder::skipSomeMainSequenceEffects (sal_Int32 nSkipCount)
+{
+ while (--nSkipCount >= 0)
+ skipSingleMainSequenceEffects();
+}
+
+
+
+
+void EffectRewinder::skipSingleMainSequenceEffects (void)
+{
+ // This basically just starts the next effect and then skips over its
+ // animation.
+ mrEventMultiplexer.notifyNextEffect();
+ mrEventQueue.forceEmpty();
+ mrUserEventQueue.callSkipEffectEventHandler();
+ mrEventQueue.forceEmpty();
+}
+
+
+
+
+bool EffectRewinder::resetEffectCount (void)
+{
+ mnMainSequenceEffectCount = 0;
+ return false;
+}
+
+
+
+
+bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
+{
+ // This notification is only relevant for us when the rpNode belongs to
+ // the main sequence.
+ BaseNodeSharedPtr pBaseNode (::boost::dynamic_pointer_cast<BaseNode>(rpNode));
+ if ( ! pBaseNode)
+ return false;
+
+ BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
+ if ( ! (pParent && pParent->isMainSequenceRootNode()))
+ return false;
+
+ // This notification is only relevant for us when the effect is user
+ // triggered.
+ bool bIsUserTriggered (false);
+
+ Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
+ if (xNode.is())
+ {
+ animations::Event aEvent;
+ if ((xNode->getBegin() >>= aEvent))
+ bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
+ }
+
+ if (bIsUserTriggered)
+ ++mnMainSequenceEffectCount;
+ else
+ mbNonUserTriggeredMainSequenceEffectSeen = true;
+
+ return false;
+}
+
+
+
+
+void EffectRewinder::asynchronousRewind (
+ sal_Int32 nEffectCount,
+ const bool bRedisplayCurrentSlide,
+ const boost::function<void(void)>& rSlideRewindFunctor)
+{
+ OSL_ASSERT(mpAsynchronousRewindEvent);
+
+ if (bRedisplayCurrentSlide)
+ {
+ mpPaintLock->Activate();
+ // Re-display the current slide.
+ if (rSlideRewindFunctor)
+ rSlideRewindFunctor();
+ mpAsynchronousRewindEvent = makeEvent(
+ ::boost::bind(
+ &EffectRewinder::asynchronousRewind,
+ this,
+ nEffectCount,
+ false,
+ rSlideRewindFunctor),
+ "EffectRewinder::asynchronousRewind");
+ mrEventQueue.addEvent(mpAsynchronousRewindEvent);
+ }
+ else
+ {
+ // Process initial events and skip any animations that are started
+ // when the slide is shown.
+ mbNonUserTriggeredMainSequenceEffectSeen = false;
+ mrEventQueue.forceEmpty();
+ if (mbNonUserTriggeredMainSequenceEffectSeen)
+ {
+ mrUserEventQueue.callSkipEffectEventHandler();
+ mrEventQueue.forceEmpty();
+ }
+
+ while (--nEffectCount >= 0)
+ skipSingleMainSequenceEffects();
+
+ mpAsynchronousRewindEvent.reset();
+ mpPaintLock.reset();
+ }
+}
+
+
+
+
+void EffectRewinder::asynchronousRewindToPreviousSlide (
+ const ::boost::function<void(void)>& rSlideRewindFunctor)
+{
+ OSL_ASSERT(mpAsynchronousRewindEvent);
+
+ mpAsynchronousRewindEvent.reset();
+ rSlideRewindFunctor();
+}
+
+
+
+
+} } // end of namespace ::slideshow::internal
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/effectrewinder.hxx b/slideshow/source/engine/effectrewinder.hxx
new file mode 100644
index 000000000000..85b81722f5ef
--- /dev/null
+++ b/slideshow/source/engine/effectrewinder.hxx
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_EFFECT_REWINDER_HXX
+#define INCLUDED_SLIDESHOW_EFFECT_REWINDER_HXX
+
+#include "animationnode.hxx"
+#include "eventhandler.hxx"
+#include "animationeventhandler.hxx"
+#include "event.hxx"
+#include "screenupdater.hxx"
+
+#include <com/sun/star/presentation/XSlideShow.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
+#include <vector>
+
+namespace css = ::com::sun::star;
+
+namespace slideshow { namespace internal {
+
+class EventMultiplexer;
+class EventQueue;
+class UserEventQueue;
+
+/** Rewind single effects of the main effect sequence. A rewind is
+ initiated by calling the Rewind() method. Part of the processing is
+ done asynchronously. Multiple EventQueue::update() calls may be
+ necessary to finish a rewind.
+
+ Remember to call SetRootAnimationNode() when switching to a different
+ slide so that the EffectRewinder can determine the number of main
+ sequence effects.
+*/
+class EffectRewinder
+{
+public:
+ EffectRewinder (
+ EventMultiplexer& rEventMultiplexer,
+ EventQueue& rEventQueue,
+ UserEventQueue& rUserEventQueue);
+ ~EffectRewinder (void);
+
+ /** Call Dispose() before the ownder of an EffectRewinder object dies so
+ that the EffectRewinder can release all references to the owner.
+
+ */
+ void dispose (void);
+
+ /** Store the root node of the animation tree. It is used in
+ CountMainSequenceEffects() to count the number of main sequence
+ effects (or effect groups.)
+ */
+ void setRootAnimationNode (
+ const css::uno::Reference<css::animations::XAnimationNode>& xRootNode);
+
+ /** Rewind one effect of the main effect sequence. When the current
+ slide has not effects or no main sequence effect has yet been played
+ then switch to the previous slide and replay all of its main
+ sequence effects.
+ The caller has to pass two functors that redisplay the current slide
+ or switch to the previous slide so that it does not have to expose
+ its internals to us. Only one of the two functors is called.
+ @param rpPaintLock
+ This paint lock is released after the whole asynchronous
+ procoess of rewinding the current effect is completed. It
+ prevents intermediate repaints that would show partial replay
+ of effects.
+ @param rSlideRewindFunctor
+ This functor is called when the current slide is to be
+ redisplayed. When it is called then the other functor is not
+ called.
+ @param rPreviousSlideFunctor
+ This functor is called to switch to the previous slide. When it
+ is called then the other functor is not called.
+ */
+ bool rewind (
+ const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
+ const ::boost::function<void(void)>& rSlideRewindFunctor,
+ const ::boost::function<void(void)>& rPreviousSlideFunctor);
+
+ /** Call this method after gotoPreviousEffect() triggered a slide change
+ to the previous slide.
+ */
+ void skipAllMainSequenceEffects (void);
+
+private:
+ EventMultiplexer& mrEventMultiplexer;
+ EventQueue& mrEventQueue;
+ UserEventQueue& mrUserEventQueue;
+
+ EventHandlerSharedPtr mpSlideStartHandler;
+ EventHandlerSharedPtr mpSlideEndHandler;
+ AnimationEventHandlerSharedPtr mpAnimationStartHandler;
+
+ /** The number off main sequence effects so far.
+ */
+ sal_Int32 mnMainSequenceEffectCount;
+
+ /** This is the currently scheduled event that executes the asynchronous
+ part of the effect rewinding. It is also used as flag that prevents
+ nested rewinds.
+ */
+ EventSharedPtr mpAsynchronousRewindEvent;
+
+ css::uno::Reference<css::animations::XAnimationNode> mxCurrentAnimationRootNode;
+ ::boost::shared_ptr<ScreenUpdater::UpdateLock> mpPaintLock;
+
+ bool mbNonUserTriggeredMainSequenceEffectSeen;
+
+ void initialize (void);
+
+ bool resetEffectCount (void);
+ /** Called by listeners when an animation (not necessarily of a main
+ sequence effect) starts.
+ */
+ bool notifyAnimationStart (const AnimationNodeSharedPtr& rpNode);
+
+ /** Count the number of effects (or effect groups) in the main effect
+ sequence.
+ */
+ sal_Int32 countMainSequenceEffects (void);
+
+ /** Skip the next main sequence effect.
+ */
+ void skipSingleMainSequenceEffects (void);
+
+ /** Skip the specified number of main sequence effects.
+ */
+ void skipSomeMainSequenceEffects (const sal_Int32 nSkipCount);
+
+ /** Rewind the last effect of the main effect sequence by replaying all
+ previous effects.
+ @param nEffectCount
+ The number of main sequence effects to replay.
+ @param bRedisplayCurrentSlide
+ When <TRUE/> then the current slide is redisplayed before the
+ effects are replayed.
+ @param rSlideRewindFunctor
+ This functor is used to redisplay the current slide.
+ */
+ void asynchronousRewind (
+ sal_Int32 nEffectCount,
+ const bool bRedisplayCurrentSlide,
+ const boost::function<void(void)>& rSlideRewindFunctor);
+
+ /** Go to the previous slide and replay all of its main sequence effects
+ (or effect groups).
+ @param rPreviousSlideFunctor
+ This functor is used to go to the previous slide.
+ */
+ void asynchronousRewindToPreviousSlide (
+ const ::boost::function<void(void)>& rPreviousSlideFunctor);
+};
+
+} } // end of namespace ::slideshow::internal
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/eventmultiplexer.cxx b/slideshow/source/engine/eventmultiplexer.cxx
new file mode 100644
index 000000000000..1d2185cf8495
--- /dev/null
+++ b/slideshow/source/engine/eventmultiplexer.cxx
@@ -0,0 +1,1280 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <rtl/ref.hxx>
+#include <cppuhelper/compbase2.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <com/sun/star/awt/XMouseListener.hpp>
+#include <com/sun/star/awt/XMouseMotionListener.hpp>
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/presentation/XSlideShowView.hpp>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+#include "tools.hxx"
+#include "eventqueue.hxx"
+#include "eventmultiplexer.hxx"
+#include "listenercontainer.hxx"
+#include "delayevent.hxx"
+#include "unoview.hxx"
+#include "unoviewcontainer.hxx"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/bind.hpp>
+
+#include <vector>
+#include <boost/unordered_map.hpp>
+#include <algorithm>
+
+using namespace ::com::sun::star;
+
+namespace boost
+{
+ // add operator== for weak_ptr
+ template<typename T> bool operator==( weak_ptr<T> const& rLHS,
+ weak_ptr<T> const& rRHS )
+ {
+ return !(rLHS<rRHS) && !(rRHS<rLHS);
+ }
+}
+
+namespace slideshow {
+namespace internal {
+
+template <typename HandlerT>
+class PrioritizedHandlerEntry
+{
+ typedef boost::shared_ptr<HandlerT> HandlerSharedPtrT;
+ HandlerSharedPtrT mpHandler;
+ double mnPrio;
+
+public:
+ PrioritizedHandlerEntry( HandlerSharedPtrT const& pHandler,
+ double nPrio ) :
+ mpHandler(pHandler),
+ mnPrio(nPrio)
+ {}
+
+ HandlerSharedPtrT const& getHandler() const { return mpHandler; }
+
+ /// To sort according to priority
+ bool operator<( PrioritizedHandlerEntry const& rRHS ) const
+ {
+ // reversed order - high prioritized entries
+ // should be at the beginning of the queue
+ return mnPrio > rRHS.mnPrio;
+ }
+
+ /// To permit std::remove in removeHandler template
+ bool operator==( PrioritizedHandlerEntry const& rRHS ) const
+ {
+ // ignore prio, for removal, only the handler ptr matters
+ return mpHandler == rRHS.mpHandler;
+ }
+};
+
+template<typename T> inline T* get_pointer(PrioritizedHandlerEntry<T> const& handler)
+{
+ return handler.getHandler().get();
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////
+
+
+typedef cppu::WeakComponentImplHelper2<
+ awt::XMouseListener,
+ awt::XMouseMotionListener > Listener_UnoBase;
+
+/** Listener class, to decouple UNO lifetime from EventMultiplexer
+
+ This class gets registered as the XMouse(Motion)Listener on the
+ XSlideViews, and passes on the events to the EventMultiplexer (via
+ EventQueue indirection, to force the events into the main thread)
+ */
+class EventMultiplexerListener : private cppu::BaseMutex,
+ public Listener_UnoBase,
+ private ::boost::noncopyable
+{
+public:
+ EventMultiplexerListener( EventQueue& rEventQueue,
+ EventMultiplexerImpl& rEventMultiplexer ) :
+ Listener_UnoBase( m_aMutex ),
+ mpEventQueue( &rEventQueue ),
+ mpEventMultiplexer( &rEventMultiplexer )
+ {
+ }
+
+ // WeakComponentImplHelperBase::disposing
+ virtual void SAL_CALL disposing();
+
+private:
+ virtual void SAL_CALL disposing( const lang::EventObject& Source )
+ throw (uno::RuntimeException);
+
+ // XMouseListener implementation
+ virtual void SAL_CALL mousePressed( const awt::MouseEvent& e )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL mouseReleased( const awt::MouseEvent& e )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL mouseEntered( const awt::MouseEvent& e )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL mouseExited( const awt::MouseEvent& e )
+ throw (uno::RuntimeException);
+
+ // XMouseMotionListener implementation
+ virtual void SAL_CALL mouseDragged( const awt::MouseEvent& e )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL mouseMoved( const awt::MouseEvent& e )
+ throw (uno::RuntimeException);
+
+
+ EventQueue* mpEventQueue;
+ EventMultiplexerImpl* mpEventMultiplexer;
+};
+
+
+////////////////////////////////////////////////////////////////////////////
+
+
+struct EventMultiplexerImpl
+{
+ EventMultiplexerImpl( EventQueue& rEventQueue,
+ UnoViewContainer const& rViewContainer ) :
+ mrEventQueue(rEventQueue),
+ mrViewContainer(rViewContainer),
+ mxListener( new EventMultiplexerListener(rEventQueue,
+ *this) ),
+ maNextEffectHandlers(),
+ maSlideStartHandlers(),
+ maSlideEndHandlers(),
+ maAnimationStartHandlers(),
+ maAnimationEndHandlers(),
+ maSlideAnimationsEndHandlers(),
+ maAudioStoppedHandlers(),
+ maCommandStopAudioHandlers(),
+ maPauseHandlers(),
+ maViewHandlers(),
+ maViewRepaintHandlers(),
+ maShapeListenerHandlers(),
+ maUserPaintEventHandlers(),
+ maShapeCursorHandlers(),
+ maMouseClickHandlers(),
+ maMouseDoubleClickHandlers(),
+ maMouseMoveHandlers(),
+ maHyperlinkHandlers(),
+ mnTimeout(0.0),
+ mpTickEvent(),
+ mbIsAutoMode(false)
+ {}
+
+ ~EventMultiplexerImpl()
+ {
+ if( mxListener.is() )
+ mxListener->dispose();
+ }
+
+ /// Remove all handlers
+ void clear();
+
+ // actual handler callbacks (get called from the UNO interface
+ // listeners via event queue)
+ void mousePressed( const awt::MouseEvent& e );
+ void mouseReleased( const awt::MouseEvent& e );
+ void mouseDragged( const awt::MouseEvent& e );
+ void mouseMoved( const awt::MouseEvent& e );
+
+ bool isMouseListenerRegistered() const;
+
+ typedef ThreadUnsafeListenerContainer<
+ PrioritizedHandlerEntry<EventHandler>,
+ std::vector<
+ PrioritizedHandlerEntry<EventHandler> > > ImplNextEffectHandlers;
+ typedef PrioritizedHandlerEntry<MouseEventHandler> ImplMouseHandlerEntry;
+ typedef ThreadUnsafeListenerContainer<
+ ImplMouseHandlerEntry,
+ std::vector<ImplMouseHandlerEntry> > ImplMouseHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ EventHandlerSharedPtr,
+ std::vector<EventHandlerSharedPtr> > ImplEventHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ AnimationEventHandlerSharedPtr,
+ std::vector<AnimationEventHandlerSharedPtr> > ImplAnimationHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ PauseEventHandlerSharedPtr,
+ std::vector<PauseEventHandlerSharedPtr> > ImplPauseHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ ViewEventHandlerWeakPtr,
+ std::vector<ViewEventHandlerWeakPtr> > ImplViewHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ ViewRepaintHandlerSharedPtr,
+ std::vector<ViewRepaintHandlerSharedPtr> > ImplRepaintHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ ShapeListenerEventHandlerSharedPtr,
+ std::vector<ShapeListenerEventHandlerSharedPtr> > ImplShapeListenerHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ UserPaintEventHandlerSharedPtr,
+ std::vector<UserPaintEventHandlerSharedPtr> > ImplUserPaintEventHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ ShapeCursorEventHandlerSharedPtr,
+ std::vector<ShapeCursorEventHandlerSharedPtr> > ImplShapeCursorHandlers;
+ typedef ThreadUnsafeListenerContainer<
+ PrioritizedHandlerEntry<HyperlinkHandler>,
+ std::vector<PrioritizedHandlerEntry<HyperlinkHandler> > > ImplHyperLinkHandlers;
+
+ template <typename XSlideShowViewFunc>
+ void forEachView( XSlideShowViewFunc pViewMethod );
+
+ UnoViewSharedPtr findUnoView(const uno::Reference<
+ presentation::XSlideShowView>& xView) const;
+
+ template< typename RegisterFunction >
+ void addMouseHandler( ImplMouseHandlers& rHandlerContainer,
+ const MouseEventHandlerSharedPtr& rHandler,
+ double nPriority,
+ RegisterFunction pRegisterListener );
+
+ bool notifyAllAnimationHandlers( ImplAnimationHandlers const& rContainer,
+ AnimationNodeSharedPtr const& rNode );
+
+ bool notifyMouseHandlers(
+ const ImplMouseHandlers& rQueue,
+ bool (MouseEventHandler::*pHandlerMethod)(
+ const awt::MouseEvent& ),
+ const awt::MouseEvent& e );
+
+ bool notifyNextEffect();
+
+ /// Called for automatic nextEffect
+ void tick();
+
+ /// Schedules a tick event
+ void scheduleTick();
+
+ /// Schedules tick events, if mbIsAutoMode is true
+ void handleTicks();
+
+
+ EventQueue& mrEventQueue;
+ UnoViewContainer const& mrViewContainer;
+ ::rtl::Reference<
+ EventMultiplexerListener> mxListener;
+
+ ImplNextEffectHandlers maNextEffectHandlers;
+ ImplEventHandlers maSlideStartHandlers;
+ ImplEventHandlers maSlideEndHandlers;
+ ImplAnimationHandlers maAnimationStartHandlers;
+ ImplAnimationHandlers maAnimationEndHandlers;
+ ImplEventHandlers maSlideAnimationsEndHandlers;
+ ImplAnimationHandlers maAudioStoppedHandlers;
+ ImplAnimationHandlers maCommandStopAudioHandlers;
+ ImplPauseHandlers maPauseHandlers;
+ ImplViewHandlers maViewHandlers;
+ ImplRepaintHandlers maViewRepaintHandlers;
+ ImplShapeListenerHandlers maShapeListenerHandlers;
+ ImplUserPaintEventHandlers maUserPaintEventHandlers;
+ ImplShapeCursorHandlers maShapeCursorHandlers;
+ ImplMouseHandlers maMouseClickHandlers;
+ ImplMouseHandlers maMouseDoubleClickHandlers;
+ ImplMouseHandlers maMouseMoveHandlers;
+ ImplHyperLinkHandlers maHyperlinkHandlers;
+
+ /// automatic next effect mode timeout
+ double mnTimeout;
+
+ /** Holds ptr to optional tick event weakly
+
+ When event queue is cleansed, the next
+ setAutomaticMode(true) call is then able to
+ regenerate the event.
+ */
+ ::boost::weak_ptr< Event > mpTickEvent;
+ bool mbIsAutoMode;
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+void SAL_CALL EventMultiplexerListener::disposing()
+{
+ osl::MutexGuard const guard( m_aMutex );
+ mpEventQueue = NULL;
+ mpEventMultiplexer = NULL;
+}
+
+void SAL_CALL EventMultiplexerListener::disposing(
+ const lang::EventObject& /*rSource*/ ) throw (uno::RuntimeException)
+{
+ // there's no real point in acting on this message - after all,
+ // the event sources are the XSlideShowViews, which must be
+ // explicitely removed from the slideshow via
+ // XSlideShow::removeView(). thus, if a XSlideShowView has
+ // properly removed itself from the slideshow, it will not be
+ // found here. and if it hasn't, there'll be other references at
+ // other places within the slideshow, anyway...
+}
+
+void SAL_CALL EventMultiplexerListener::mousePressed(
+ const awt::MouseEvent& e ) throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // notify mouse press. Don't call handlers directly, this
+ // might not be the main thread!
+ if( mpEventQueue )
+ mpEventQueue->addEvent(
+ makeEvent( boost::bind( &EventMultiplexerImpl::mousePressed,
+ mpEventMultiplexer,
+ e ),
+ "EventMultiplexerImpl::mousePressed") );
+}
+
+void SAL_CALL EventMultiplexerListener::mouseReleased(
+ const awt::MouseEvent& e ) throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // notify mouse release. Don't call handlers directly,
+ // this might not be the main thread!
+ if( mpEventQueue )
+ mpEventQueue->addEvent(
+ makeEvent( boost::bind( &EventMultiplexerImpl::mouseReleased,
+ mpEventMultiplexer,
+ e ),
+ "EventMultiplexerImpl::mouseReleased") );
+}
+
+void SAL_CALL EventMultiplexerListener::mouseEntered(
+ const awt::MouseEvent& /*e*/ ) throw (uno::RuntimeException)
+{
+ // not used here
+}
+
+void SAL_CALL EventMultiplexerListener::mouseExited(
+ const awt::MouseEvent& /*e*/ ) throw (uno::RuntimeException)
+{
+ // not used here
+}
+
+// XMouseMotionListener implementation
+void SAL_CALL EventMultiplexerListener::mouseDragged(
+ const awt::MouseEvent& e ) throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // notify mouse drag. Don't call handlers directly, this
+ // might not be the main thread!
+ if( mpEventQueue )
+ mpEventQueue->addEvent(
+ makeEvent( boost::bind( &EventMultiplexerImpl::mouseDragged,
+ mpEventMultiplexer,
+ e ),
+ "EventMultiplexerImpl::mouseDragged") );
+}
+
+void SAL_CALL EventMultiplexerListener::mouseMoved(
+ const awt::MouseEvent& e ) throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // notify mouse move. Don't call handlers directly, this
+ // might not be the main thread!
+ if( mpEventQueue )
+ mpEventQueue->addEvent(
+ makeEvent( boost::bind( &EventMultiplexerImpl::mouseMoved,
+ mpEventMultiplexer,
+ e ),
+ "EventMultiplexerImpl::mouseMoved") );
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+bool EventMultiplexerImpl::notifyAllAnimationHandlers( ImplAnimationHandlers const& rContainer,
+ AnimationNodeSharedPtr const& rNode )
+{
+ return rContainer.applyAll(
+ boost::bind( &AnimationEventHandler::handleAnimationEvent,
+ _1, boost::cref(rNode) ) );
+}
+
+template <typename XSlideShowViewFunc>
+void EventMultiplexerImpl::forEachView( XSlideShowViewFunc pViewMethod )
+{
+ if( pViewMethod )
+ {
+ // (un)register mouse listener on all views
+ for( UnoViewVector::const_iterator aIter( mrViewContainer.begin() ),
+ aEnd( mrViewContainer.end() ); aIter != aEnd; ++aIter )
+ {
+ uno::Reference<presentation::XSlideShowView> xView ((*aIter)->getUnoView());
+ if (xView.is())
+ {
+ (xView.get()->*pViewMethod)( mxListener.get() );
+ }
+ else
+ {
+ OSL_ASSERT(xView.is());
+ }
+ }
+ }
+}
+
+UnoViewSharedPtr EventMultiplexerImpl::findUnoView(
+ const uno::Reference<presentation::XSlideShowView>& xView) const
+{
+ // find view from which the change originated
+ UnoViewVector::const_iterator aIter;
+ const UnoViewVector::const_iterator aEnd ( mrViewContainer.end() );
+ if( (aIter=std::find_if( mrViewContainer.begin(),
+ aEnd,
+ boost::bind(
+ std::equal_to<uno::Reference<presentation::XSlideShowView> >(),
+ boost::cref( xView ),
+ boost::bind( &UnoView::getUnoView, _1 )))) == aEnd )
+ {
+ OSL_FAIL("EventMultiplexer::findUnoView(): unexpected message source" );
+ return UnoViewSharedPtr();
+ }
+
+ return *aIter;
+}
+
+template< typename RegisterFunction >
+void EventMultiplexerImpl::addMouseHandler(
+ ImplMouseHandlers& rHandlerContainer,
+ const MouseEventHandlerSharedPtr& rHandler,
+ double nPriority,
+ RegisterFunction pRegisterListener )
+{
+ ENSURE_OR_THROW(
+ rHandler,
+ "EventMultiplexer::addMouseHandler(): Invalid handler" );
+
+ // register mouse listener on all views
+ forEachView( pRegisterListener );
+
+ // add into sorted container:
+ rHandlerContainer.addSorted(
+ typename ImplMouseHandlers::container_type::value_type(
+ rHandler,
+ nPriority ));
+}
+
+bool EventMultiplexerImpl::isMouseListenerRegistered() const
+{
+ return !(maMouseClickHandlers.isEmpty() &&
+ maMouseDoubleClickHandlers.isEmpty());
+}
+
+void EventMultiplexerImpl::tick()
+{
+ if( !mbIsAutoMode )
+ return; // this event is just a left-over, ignore
+
+ notifyNextEffect();
+
+ if( !maNextEffectHandlers.isEmpty() )
+ {
+ // still handlers left, schedule next timeout
+ // event. Will also set mbIsTickEventOn back to true
+ scheduleTick();
+ }
+}
+
+void EventMultiplexerImpl::scheduleTick()
+{
+ EventSharedPtr pEvent(
+ makeDelay( boost::bind( &EventMultiplexerImpl::tick,
+ this ),
+ mnTimeout,
+ "EventMultiplexerImpl::tick with delay"));
+
+ // store weak reference to generated event, to notice when
+ // the event queue gets cleansed (we then have to
+ // regenerate the tick event!)
+ mpTickEvent = pEvent;
+
+ // enabled auto mode: simply schedule a timeout event,
+ // which will eventually call our tick() method
+ mrEventQueue.addEventForNextRound( pEvent );
+}
+
+void EventMultiplexerImpl::handleTicks()
+{
+ if( !mbIsAutoMode )
+ return; // nothing to do, don't need no ticks
+
+ EventSharedPtr pTickEvent( mpTickEvent.lock() );
+ if( pTickEvent )
+ return; // nothing to do, there's already a tick
+ // pending
+
+ // schedule initial tick (which reschedules itself
+ // after that, all by itself)
+ scheduleTick();
+}
+
+
+void EventMultiplexerImpl::clear()
+{
+ // deregister from all views.
+ if( isMouseListenerRegistered() )
+ {
+ for( UnoViewVector::const_iterator aIter=mrViewContainer.begin(),
+ aEnd=mrViewContainer.end();
+ aIter!=aEnd;
+ ++aIter )
+ {
+ if( (*aIter)->getUnoView().is() )
+ (*aIter)->getUnoView()->removeMouseListener( mxListener.get() );
+ }
+ }
+
+ if( !maMouseMoveHandlers.isEmpty() )
+ {
+ for( UnoViewVector::const_iterator aIter=mrViewContainer.begin(),
+ aEnd=mrViewContainer.end();
+ aIter!=aEnd;
+ ++aIter )
+ {
+ if( (*aIter)->getUnoView().is() )
+ (*aIter)->getUnoView()->removeMouseMotionListener( mxListener.get() );
+ }
+ }
+
+ // clear all handlers (releases all references)
+ maNextEffectHandlers.clear();
+ maSlideStartHandlers.clear();
+ maSlideEndHandlers.clear();
+ maAnimationStartHandlers.clear();
+ maAnimationEndHandlers.clear();
+ maSlideAnimationsEndHandlers.clear();
+ maAudioStoppedHandlers.clear();
+ maCommandStopAudioHandlers.clear();
+ maPauseHandlers.clear();
+ maViewHandlers.clear();
+ maViewRepaintHandlers.clear();
+ maMouseClickHandlers.clear();
+ maMouseDoubleClickHandlers.clear();
+ maMouseMoveHandlers.clear();
+ maHyperlinkHandlers.clear();
+ mpTickEvent.reset();
+}
+
+// XMouseListener implementation
+bool EventMultiplexerImpl::notifyMouseHandlers(
+ const ImplMouseHandlers& rQueue,
+ bool (MouseEventHandler::*pHandlerMethod)( const awt::MouseEvent& ),
+ const awt::MouseEvent& e )
+{
+ uno::Reference<presentation::XSlideShowView> xView(
+ e.Source, uno::UNO_QUERY );
+
+ ENSURE_OR_RETURN_FALSE( xView.is(), "EventMultiplexer::notifyHandlers(): "
+ "event source is not an XSlideShowView" );
+
+ // find corresponding view (to map mouse position into user
+ // coordinate space)
+ UnoViewVector::const_iterator aIter;
+ const UnoViewVector::const_iterator aBegin( mrViewContainer.begin() );
+ const UnoViewVector::const_iterator aEnd ( mrViewContainer.end() );
+ if( (aIter=::std::find_if(
+ aBegin, aEnd,
+ boost::bind( std::equal_to< uno::Reference<
+ presentation::XSlideShowView > >(),
+ boost::cref( xView ),
+ boost::bind( &UnoView::getUnoView, _1 ) ) ) ) == aEnd)
+ {
+ ENSURE_OR_RETURN_FALSE(
+ false, "EventMultiplexer::notifyHandlers(): "
+ "event source not found under registered views" );
+ }
+
+ // convert mouse position to user coordinate space
+ ::basegfx::B2DPoint aPosition( e.X, e.Y );
+ ::basegfx::B2DHomMatrix aMatrix( (*aIter)->getTransformation() );
+ if( !aMatrix.invert() )
+ ENSURE_OR_THROW( false, "EventMultiplexer::notifyHandlers():"
+ " view matrix singular" );
+ aPosition *= aMatrix;
+
+ awt::MouseEvent aEvent( e );
+ aEvent.X = ::basegfx::fround( aPosition.getX() );
+ aEvent.Y = ::basegfx::fround( aPosition.getY() );
+
+ // fire event on handlers, try in order of precedence. If
+ // one high-priority handler rejects the event
+ // (i.e. returns false), try next handler.
+ return rQueue.apply(
+ boost::bind(
+ pHandlerMethod,
+ boost::bind(
+ &ImplMouseHandlers::container_type::value_type::getHandler,
+ _1 ),
+ aEvent ));
+}
+
+void EventMultiplexerImpl::mousePressed( const awt::MouseEvent& e )
+{
+ // fire double-click events for every second click
+ sal_Int32 nCurrClickCount = e.ClickCount;
+ while( nCurrClickCount > 1 &&
+ notifyMouseHandlers( maMouseDoubleClickHandlers,
+ &MouseEventHandler::handleMousePressed,
+ e ))
+ {
+ nCurrClickCount -= 2;
+ }
+
+ // fire single-click events for all remaining clicks
+ while( nCurrClickCount > 0 &&
+ notifyMouseHandlers( maMouseClickHandlers,
+ &MouseEventHandler::handleMousePressed,
+ e ))
+ {
+ --nCurrClickCount;
+ }
+}
+
+void EventMultiplexerImpl::mouseReleased( const awt::MouseEvent& e )
+{
+ // fire double-click events for every second click
+ sal_Int32 nCurrClickCount = e.ClickCount;
+ while( nCurrClickCount > 1 &&
+ notifyMouseHandlers( maMouseDoubleClickHandlers,
+ &MouseEventHandler::handleMouseReleased,
+ e ))
+ {
+ nCurrClickCount -= 2;
+ }
+
+ // fire single-click events for all remaining clicks
+ while( nCurrClickCount > 0 &&
+ notifyMouseHandlers( maMouseClickHandlers,
+ &MouseEventHandler::handleMouseReleased,
+ e ))
+ {
+ --nCurrClickCount;
+ }
+}
+
+void EventMultiplexerImpl::mouseDragged( const awt::MouseEvent& e )
+{
+ notifyMouseHandlers( maMouseMoveHandlers,
+ &MouseEventHandler::handleMouseDragged,
+ e );
+}
+
+void EventMultiplexerImpl::mouseMoved( const awt::MouseEvent& e )
+{
+ notifyMouseHandlers( maMouseMoveHandlers,
+ &MouseEventHandler::handleMouseMoved,
+ e );
+}
+
+bool EventMultiplexerImpl::notifyNextEffect()
+{
+ // fire event on handlers, try in order of precedence. If one
+ // high-priority handler rejects the event (i.e. returns false),
+ // try next handler.
+ return maNextEffectHandlers.apply(
+ boost::bind(
+ &EventHandler::handleEvent,
+ boost::bind(
+ &ImplNextEffectHandlers::container_type::value_type::getHandler,
+ _1 )) );
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+
+EventMultiplexer::EventMultiplexer( EventQueue& rEventQueue,
+ UnoViewContainer const& rViewContainer ) :
+ mpImpl( new EventMultiplexerImpl(rEventQueue, rViewContainer) )
+{
+}
+
+EventMultiplexer::~EventMultiplexer()
+{
+ // outline because of EventMultiplexerImpl's incomplete type
+}
+
+void EventMultiplexer::clear()
+{
+ mpImpl->clear();
+}
+
+void EventMultiplexer::setAutomaticMode( bool bIsAuto )
+{
+ if( bIsAuto == mpImpl->mbIsAutoMode )
+ return; // no change, nothing to do
+
+ mpImpl->mbIsAutoMode = bIsAuto;
+
+ mpImpl->handleTicks();
+}
+
+bool EventMultiplexer::getAutomaticMode() const
+{
+ return mpImpl->mbIsAutoMode;
+}
+
+void EventMultiplexer::setAutomaticTimeout( double nTimeout )
+{
+ mpImpl->mnTimeout = nTimeout;
+}
+
+double EventMultiplexer::getAutomaticTimeout() const
+{
+ return mpImpl->mnTimeout;
+}
+
+void EventMultiplexer::addNextEffectHandler(
+ EventHandlerSharedPtr const& rHandler,
+ double nPriority )
+{
+ mpImpl->maNextEffectHandlers.addSorted(
+ EventMultiplexerImpl::ImplNextEffectHandlers::container_type::value_type(
+ rHandler,
+ nPriority) );
+
+ // Enable tick events, if not done already
+ mpImpl->handleTicks();
+}
+
+void EventMultiplexer::removeNextEffectHandler(
+ const EventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maNextEffectHandlers.remove(
+ EventMultiplexerImpl::ImplNextEffectHandlers::container_type::value_type(
+ rHandler,
+ 0.0) );
+}
+
+void EventMultiplexer::addSlideStartHandler(
+ const EventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maSlideStartHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeSlideStartHandler(
+ const EventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maSlideStartHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addSlideEndHandler(
+ const EventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maSlideEndHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeSlideEndHandler(
+ const EventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maSlideEndHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addAnimationStartHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maAnimationStartHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeAnimationStartHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maAnimationStartHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addAnimationEndHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maAnimationEndHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeAnimationEndHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maAnimationEndHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addSlideAnimationsEndHandler(
+ const EventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maSlideAnimationsEndHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeSlideAnimationsEndHandler(
+ const EventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maSlideAnimationsEndHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addAudioStoppedHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maAudioStoppedHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeAudioStoppedHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maAudioStoppedHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addCommandStopAudioHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maCommandStopAudioHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeCommandStopAudioHandler(
+ const AnimationEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maCommandStopAudioHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addPauseHandler(
+ const PauseEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maPauseHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removePauseHandler(
+ const PauseEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maPauseHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addViewHandler(
+ const ViewEventHandlerWeakPtr& rHandler )
+{
+ mpImpl->maViewHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeViewHandler( const ViewEventHandlerWeakPtr& rHandler )
+{
+ mpImpl->maViewHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addViewRepaintHandler( const ViewRepaintHandlerSharedPtr& rHandler )
+{
+ mpImpl->maViewRepaintHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeViewRepaintHandler( const ViewRepaintHandlerSharedPtr& rHandler )
+{
+ mpImpl->maViewRepaintHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addShapeListenerHandler( const ShapeListenerEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maShapeListenerHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeShapeListenerHandler( const ShapeListenerEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maShapeListenerHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addUserPaintHandler( const UserPaintEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maUserPaintEventHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeUserPaintHandler( const UserPaintEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maUserPaintEventHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addShapeCursorHandler( const ShapeCursorEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maShapeCursorHandlers.add( rHandler );
+}
+
+void EventMultiplexer::removeShapeCursorHandler( const ShapeCursorEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maShapeCursorHandlers.remove( rHandler );
+}
+
+void EventMultiplexer::addClickHandler(
+ const MouseEventHandlerSharedPtr& rHandler,
+ double nPriority )
+{
+ mpImpl->addMouseHandler(
+ mpImpl->maMouseClickHandlers,
+ rHandler,
+ nPriority,
+ mpImpl->isMouseListenerRegistered()
+ ? NULL
+ : &presentation::XSlideShowView::addMouseListener );
+}
+
+void EventMultiplexer::removeClickHandler(
+ const MouseEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maMouseClickHandlers.remove(
+ EventMultiplexerImpl::ImplMouseHandlers::container_type::value_type(
+ rHandler,
+ 0.0) );
+
+ if( !mpImpl->isMouseListenerRegistered() )
+ mpImpl->forEachView( &presentation::XSlideShowView::removeMouseListener );
+}
+
+void EventMultiplexer::addDoubleClickHandler(
+ const MouseEventHandlerSharedPtr& rHandler,
+ double nPriority )
+{
+ mpImpl->addMouseHandler(
+ mpImpl->maMouseDoubleClickHandlers,
+ rHandler,
+ nPriority,
+ mpImpl->isMouseListenerRegistered()
+ ? NULL
+ : &presentation::XSlideShowView::addMouseListener );
+}
+
+void EventMultiplexer::removeDoubleClickHandler(
+ const MouseEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maMouseDoubleClickHandlers.remove(
+ EventMultiplexerImpl::ImplMouseHandlers::container_type::value_type(
+ rHandler,
+ 0.0) );
+
+ if( !mpImpl->isMouseListenerRegistered() )
+ mpImpl->forEachView( &presentation::XSlideShowView::removeMouseListener );
+}
+
+void EventMultiplexer::addMouseMoveHandler(
+ const MouseEventHandlerSharedPtr& rHandler,
+ double nPriority )
+{
+ mpImpl->addMouseHandler(
+ mpImpl->maMouseMoveHandlers,
+ rHandler,
+ nPriority,
+ mpImpl->maMouseMoveHandlers.isEmpty()
+ ? &presentation::XSlideShowView::addMouseMotionListener
+ : NULL );
+}
+
+void EventMultiplexer::removeMouseMoveHandler(
+ const MouseEventHandlerSharedPtr& rHandler )
+{
+ mpImpl->maMouseMoveHandlers.remove(
+ EventMultiplexerImpl::ImplMouseHandlers::container_type::value_type(
+ rHandler,
+ 0.0) );
+
+ if( mpImpl->maMouseMoveHandlers.isEmpty() )
+ mpImpl->forEachView(
+ &presentation::XSlideShowView::removeMouseMotionListener );
+}
+
+void EventMultiplexer::addHyperlinkHandler( const HyperlinkHandlerSharedPtr& rHandler,
+ double nPriority )
+{
+ mpImpl->maHyperlinkHandlers.addSorted(
+ EventMultiplexerImpl::ImplHyperLinkHandlers::container_type::value_type(
+ rHandler,
+ nPriority) );
+}
+
+void EventMultiplexer::removeHyperlinkHandler( const HyperlinkHandlerSharedPtr& rHandler )
+{
+ mpImpl->maHyperlinkHandlers.remove(
+ EventMultiplexerImpl::ImplHyperLinkHandlers::container_type::value_type(
+ rHandler,
+ 0.0) );
+}
+
+bool EventMultiplexer::notifyShapeListenerAdded(
+ const uno::Reference<presentation::XShapeEventListener>& xListener,
+ const uno::Reference<drawing::XShape>& xShape )
+{
+ return mpImpl->maShapeListenerHandlers.applyAll(
+ boost::bind(&ShapeListenerEventHandler::listenerAdded,
+ _1,
+ boost::cref(xListener),
+ boost::cref(xShape)) );
+}
+
+bool EventMultiplexer::notifyShapeListenerRemoved(
+ const uno::Reference<presentation::XShapeEventListener>& xListener,
+ const uno::Reference<drawing::XShape>& xShape )
+{
+ return mpImpl->maShapeListenerHandlers.applyAll(
+ boost::bind(&ShapeListenerEventHandler::listenerRemoved,
+ _1,
+ boost::cref(xListener),
+ boost::cref(xShape)) );
+}
+
+bool EventMultiplexer::notifyShapeCursorChange(
+ const uno::Reference<drawing::XShape>& xShape,
+ sal_Int16 nPointerShape )
+{
+ return mpImpl->maShapeCursorHandlers.applyAll(
+ boost::bind(&ShapeCursorEventHandler::cursorChanged,
+ _1,
+ boost::cref(xShape),
+ nPointerShape));
+}
+
+bool EventMultiplexer::notifyUserPaintColor( RGBColor const& rUserColor )
+{
+ return mpImpl->maUserPaintEventHandlers.applyAll(
+ boost::bind(&UserPaintEventHandler::colorChanged,
+ _1,
+ boost::cref(rUserColor)));
+}
+
+bool EventMultiplexer::notifyUserPaintStrokeWidth( double rUserStrokeWidth )
+{
+ return mpImpl->maUserPaintEventHandlers.applyAll(
+ boost::bind(&UserPaintEventHandler::widthChanged,
+ _1,
+ rUserStrokeWidth));
+}
+
+bool EventMultiplexer::notifyUserPaintDisabled()
+{
+ return mpImpl->maUserPaintEventHandlers.applyAll(
+ boost::mem_fn(&UserPaintEventHandler::disable));
+}
+
+bool EventMultiplexer::notifySwitchPenMode(){
+ return mpImpl->maUserPaintEventHandlers.applyAll(
+ boost::mem_fn(&UserPaintEventHandler::switchPenMode));
+}
+
+bool EventMultiplexer::notifySwitchEraserMode(){
+ return mpImpl->maUserPaintEventHandlers.applyAll(
+ boost::mem_fn(&UserPaintEventHandler::switchEraserMode));
+}
+
+//adding erasing all ink features with UserPaintOverlay
+bool EventMultiplexer::notifyEraseAllInk( bool const& rEraseAllInk )
+{
+ return mpImpl->maUserPaintEventHandlers.applyAll(
+ boost::bind(&UserPaintEventHandler::eraseAllInkChanged,
+ _1,
+ boost::cref(rEraseAllInk)));
+}
+
+//adding erasing features with UserPaintOverlay
+bool EventMultiplexer::notifyEraseInkWidth( sal_Int32 rEraseInkSize )
+{
+ return mpImpl->maUserPaintEventHandlers.applyAll(
+ boost::bind(&UserPaintEventHandler::eraseInkWidthChanged,
+ _1,
+ boost::cref(rEraseInkSize)));
+}
+
+bool EventMultiplexer::notifyNextEffect()
+{
+ return mpImpl->notifyNextEffect();
+}
+
+bool EventMultiplexer::notifySlideStartEvent()
+{
+ return mpImpl->maSlideStartHandlers.applyAll(
+ boost::mem_fn(&EventHandler::handleEvent) );
+}
+
+bool EventMultiplexer::notifySlideEndEvent()
+{
+ return mpImpl->maSlideEndHandlers.applyAll(
+ boost::mem_fn(&EventHandler::handleEvent) );
+}
+
+bool EventMultiplexer::notifyAnimationStart(
+ const AnimationNodeSharedPtr& rNode )
+{
+ return mpImpl->notifyAllAnimationHandlers( mpImpl->maAnimationStartHandlers,
+ rNode );
+}
+
+bool EventMultiplexer::notifyAnimationEnd(
+ const AnimationNodeSharedPtr& rNode )
+{
+ return mpImpl->notifyAllAnimationHandlers( mpImpl->maAnimationEndHandlers,
+ rNode );
+}
+
+bool EventMultiplexer::notifySlideAnimationsEnd()
+{
+ return mpImpl->maSlideAnimationsEndHandlers.applyAll(
+ boost::mem_fn(&EventHandler::handleEvent));
+}
+
+bool EventMultiplexer::notifyAudioStopped(
+ const AnimationNodeSharedPtr& rNode )
+{
+ return mpImpl->notifyAllAnimationHandlers(
+ mpImpl->maAudioStoppedHandlers,
+ rNode );
+}
+
+bool EventMultiplexer::notifyCommandStopAudio(
+ const AnimationNodeSharedPtr& rNode )
+{
+ return mpImpl->notifyAllAnimationHandlers(
+ mpImpl->maCommandStopAudioHandlers,
+ rNode );
+}
+
+bool EventMultiplexer::notifyPauseMode( bool bPauseShow )
+{
+ return mpImpl->maPauseHandlers.applyAll(
+ boost::bind( &PauseEventHandler::handlePause,
+ _1, bPauseShow ));
+}
+
+bool EventMultiplexer::notifyViewAdded( const UnoViewSharedPtr& rView )
+{
+ ENSURE_OR_THROW( rView, "EventMultiplexer::notifyViewAdded(): Invalid view");
+
+ // register event listener
+ uno::Reference<presentation::XSlideShowView> const rUnoView(
+ rView->getUnoView() );
+
+ if( mpImpl->isMouseListenerRegistered() )
+ rUnoView->addMouseListener(
+ mpImpl->mxListener.get() );
+
+ if( !mpImpl->maMouseMoveHandlers.isEmpty() )
+ rUnoView->addMouseMotionListener(
+ mpImpl->mxListener.get() );
+
+ return mpImpl->maViewHandlers.applyAll(
+ boost::bind( &ViewEventHandler::viewAdded,
+ _1,
+ boost::cref(rView) ));
+}
+
+bool EventMultiplexer::notifyViewRemoved( const UnoViewSharedPtr& rView )
+{
+ ENSURE_OR_THROW( rView,
+ "EventMultiplexer::removeView(): Invalid view" );
+
+ // revoke event listeners
+ uno::Reference<presentation::XSlideShowView> const rUnoView(
+ rView->getUnoView() );
+
+ if( mpImpl->isMouseListenerRegistered() )
+ rUnoView->removeMouseListener(
+ mpImpl->mxListener.get() );
+
+ if( !mpImpl->maMouseMoveHandlers.isEmpty() )
+ rUnoView->removeMouseMotionListener(
+ mpImpl->mxListener.get() );
+
+ return mpImpl->maViewHandlers.applyAll(
+ boost::bind( &ViewEventHandler::viewRemoved,
+ _1,
+ boost::cref(rView) ));
+}
+
+bool EventMultiplexer::notifyViewChanged( const UnoViewSharedPtr& rView )
+{
+ return mpImpl->maViewHandlers.applyAll(
+ boost::bind( &ViewEventHandler::viewChanged,
+ _1,
+ boost::cref(rView) ));
+}
+
+bool EventMultiplexer::notifyViewChanged( const uno::Reference<presentation::XSlideShowView>& xView )
+{
+ UnoViewSharedPtr pView( mpImpl->findUnoView(xView) );
+
+ if( !pView )
+ return false; // view not registered here
+
+ return notifyViewChanged( pView );
+}
+
+bool EventMultiplexer::notifyViewsChanged()
+{
+ return mpImpl->maViewHandlers.applyAll(
+ boost::mem_fn( &ViewEventHandler::viewsChanged ));
+}
+
+bool EventMultiplexer::notifyViewClobbered(
+ const uno::Reference<presentation::XSlideShowView>& xView )
+{
+ UnoViewSharedPtr pView( mpImpl->findUnoView(xView) );
+
+ if( !pView )
+ return false; // view not registered here
+
+ return mpImpl->maViewRepaintHandlers.applyAll(
+ boost::bind( &ViewRepaintHandler::viewClobbered,
+ _1,
+ boost::cref(pView) ));
+}
+
+bool EventMultiplexer::notifyHyperlinkClicked(
+ rtl::OUString const& hyperLink )
+{
+ return mpImpl->maHyperlinkHandlers.apply(
+ boost::bind(&HyperlinkHandler::handleHyperlink,
+ _1,
+ boost::cref(hyperLink)) );
+}
+
+bool EventMultiplexer::notifySlideTransitionStarted()
+{
+ return true;
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/eventqueue.cxx b/slideshow/source/engine/eventqueue.cxx
new file mode 100644
index 000000000000..cc19ede90867
--- /dev/null
+++ b/slideshow/source/engine/eventqueue.cxx
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+#include "debug.hxx"
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <event.hxx>
+#include <eventqueue.hxx>
+#include <slideshowexceptions.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <limits>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ bool EventQueue::EventEntry::operator<( const EventEntry& rEvent ) const
+ {
+ // negate comparison, we want priority queue to be sorted
+ // in increasing order of activation times
+ return this->nTime > rEvent.nTime;
+ }
+
+
+ EventQueue::EventQueue(
+ boost::shared_ptr<canvas::tools::ElapsedTime> const & pPresTimer )
+ : maMutex(),
+ maEvents(),
+ maNextEvents(),
+ maNextNextEvents(),
+ mpTimer( pPresTimer )
+ {
+ }
+
+ EventQueue::~EventQueue()
+ {
+ // add in all that have been added explicitly for this round:
+ EventEntryVector::const_iterator const iEnd( maNextEvents.end() );
+ for ( EventEntryVector::const_iterator iPos( maNextEvents.begin() );
+ iPos != iEnd; ++iPos )
+ {
+ maEvents.push(*iPos);
+ }
+ EventEntryVector().swap( maNextEvents );
+
+ // dispose event queue
+ while( !maEvents.empty() )
+ {
+ try
+ {
+ maEvents.top().pEvent->dispose();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ maEvents.pop();
+ }
+ }
+
+ bool EventQueue::addEvent( const EventSharedPtr& rEvent )
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+#if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS)
+ OSL_TRACE("adding at %f event [%s] at %x with delay %f\r",
+ mpTimer->getElapsedTime(),
+ OUStringToOString(rEvent->GetDescription(), RTL_TEXTENCODING_UTF8).getStr(),
+ rEvent.get(),
+ rEvent->getActivationTime(0.0));
+#endif
+ ENSURE_OR_RETURN_FALSE( rEvent,
+ "EventQueue::addEvent: event ptr NULL" );
+
+ // prepare entry
+
+ // A seemingly obvious optimization cannot be used here,
+ // because it breaks assumed order of notification: zero
+ // timeout events could be fired() immediately, but that
+ // would not unwind the stack and furthermore changes
+ // order of notification
+
+ // add entry
+ maEvents.push( EventEntry( rEvent, rEvent->getActivationTime(
+ mpTimer->getElapsedTime()) ) );
+ return true;
+ }
+
+ bool EventQueue::addEventForNextRound( EventSharedPtr const& rEvent )
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+#if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS)
+ OSL_TRACE("adding at %f event [%s] at %x for next round with delay %f\r",
+ mpTimer->getElapsedTime(),
+ OUStringToOString(rEvent->GetDescription(), RTL_TEXTENCODING_UTF8).getStr(),
+ rEvent.get(),
+ rEvent->getActivationTime(0.0));
+#endif
+
+ ENSURE_OR_RETURN_FALSE( rEvent.get() != NULL,
+ "EventQueue::addEvent: event ptr NULL" );
+ maNextEvents.push_back(
+ EventEntry( rEvent, rEvent->getActivationTime(
+ mpTimer->getElapsedTime()) ) );
+ return true;
+ }
+
+ bool EventQueue::addEventWhenQueueIsEmpty (const EventSharedPtr& rpEvent)
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+#if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS)
+ OSL_TRACE("adding at %f event [%s] at %x for execution when queue is empty with delay %f\r",
+ mpTimer->getElapsedTime(),
+ OUStringToOString(rpEvent->GetDescription(), RTL_TEXTENCODING_UTF8).getStr(),
+ rpEvent.get(),
+ rpEvent->getActivationTime(0.0));
+#endif
+
+ ENSURE_OR_RETURN_FALSE(
+ rpEvent.get() != NULL,
+ "EventQueue::addEvent: event ptr NULL");
+
+ maNextNextEvents.push(
+ EventEntry(
+ rpEvent,
+ rpEvent->getActivationTime(mpTimer->getElapsedTime())));
+
+ return true;
+ }
+
+ void EventQueue::forceEmpty()
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+ process_(true);
+ }
+
+ void EventQueue::process()
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+ process_(false);
+ }
+
+ void EventQueue::process_( bool bFireAllEvents )
+ {
+ VERBOSE_TRACE( "EventQueue: heartbeat" );
+
+ // add in all that have been added explicitly for this round:
+ EventEntryVector::const_iterator const iEnd( maNextEvents.end() );
+ for ( EventEntryVector::const_iterator iPos( maNextEvents.begin() );
+ iPos != iEnd; ++iPos ) {
+ maEvents.push(*iPos);
+ }
+ EventEntryVector().swap( maNextEvents );
+
+ // perform topmost, ready-to-execute event
+ // =======================================
+
+ const double nCurrTime( mpTimer->getElapsedTime() );
+
+ // When maEvents does not contain any events that are due now
+ // then process one event from maNextNextEvents.
+ if (!maNextNextEvents.empty()
+ && !bFireAllEvents
+ && (maEvents.empty() || maEvents.top().nTime > nCurrTime))
+ {
+ const EventEntry aEvent (maNextNextEvents.top());
+ maNextNextEvents.pop();
+ maEvents.push(aEvent);
+ }
+
+ // process ready/elapsed events. Note that the 'perceived'
+ // current time remains constant for this loop, thus we're
+ // processing only those events which where ready when we
+ // entered this method.
+ while( !maEvents.empty() &&
+ (bFireAllEvents || maEvents.top().nTime <= nCurrTime) )
+ {
+ EventEntry event( maEvents.top() );
+ maEvents.pop();
+
+ // only process event, if it is still 'charged',
+ // i.e. the fire() call effects something. This is
+ // used when e.g. having events registered at multiple
+ // places, which should fire only once: after the
+ // initial fire() call, those events become inactive
+ // and return false on isCharged. This frees us from
+ // the need to prune queues of those inactive shells.
+ if( event.pEvent->isCharged() )
+ {
+ try
+ {
+#if OSL_DEBUG_LEVEL > 0
+ VERBOSE_TRACE( "Firing event: unknown (0x%X), timeout was: %f",
+ event.pEvent.get(),
+ event.pEvent->getActivationTime(0.0) );
+#endif
+#if OSL_DEBUG_LEVEL > 1 && defined (SLIDESHOW_ADD_DESCRIPTIONS_TO_EVENTS)
+ OSL_TRACE("firing at %f event [%s] at %x with delay %f\r",
+ mpTimer->getElapsedTime(),
+ OUStringToOString(event.pEvent->GetDescription(),
+ RTL_TEXTENCODING_UTF8).getStr(),
+ event.pEvent.get(),
+ event.pEvent->getActivationTime(0.0));
+#endif
+
+ event.pEvent->fire();
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ // catch anything here, we don't want
+ // to leave this scope under _any_
+ // circumstance. Although, do _not_
+ // reinsert an activity that threw
+ // once.
+
+ // NOTE: we explicitely don't catch(...) here,
+ // since this will also capture segmentation
+ // violations and the like. In such a case, we
+ // still better let our clients now...
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ catch( SlideShowException& )
+ {
+ // catch anything here, we don't want
+ // to leave this scope under _any_
+ // circumstance. Although, do _not_
+ // reinsert an activity that threw
+ // once.
+
+ // NOTE: we explicitely don't catch(...) here,
+ // since this will also capture segmentation
+ // violations and the like. In such a case, we
+ // still better let our clients now...
+ OSL_TRACE( "::presentation::internal::EventQueue: Event threw a SlideShowException, action might not have been fully performed" );
+ }
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 0
+ VERBOSE_TRACE( "Ignoring discharged event: unknown (0x%X), timeout was: %f",
+ event.pEvent.get(),
+ event.pEvent->getActivationTime(0.0) );
+#endif
+ }
+ }
+ }
+
+ bool EventQueue::isEmpty() const
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+ return maEvents.empty() && maNextEvents.empty() && maNextNextEvents.empty();
+ }
+
+ double EventQueue::nextTimeout() const
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+ // return time for next entry (if any)
+ double nTimeout (::std::numeric_limits<double>::max());
+ const double nCurrentTime (mpTimer->getElapsedTime());
+ if ( ! maEvents.empty())
+ nTimeout = maEvents.top().nTime - nCurrentTime;
+ if ( ! maNextEvents.empty())
+ nTimeout = ::std::min(nTimeout, maNextEvents.front().nTime - nCurrentTime);
+ if ( ! maNextNextEvents.empty())
+ nTimeout = ::std::min(nTimeout, maNextNextEvents.top().nTime - nCurrentTime);
+
+ return nTimeout;
+ }
+
+ void EventQueue::clear()
+ {
+ ::osl::MutexGuard aGuard( maMutex );
+
+ // TODO(P1): Maybe a plain vector and vector.swap will
+ // be faster here. Profile.
+ maEvents = ImplQueueType();
+
+ maNextEvents.clear();
+ maNextNextEvents = ImplQueueType();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/expressionnodefactory.cxx b/slideshow/source/engine/expressionnodefactory.cxx
new file mode 100644
index 000000000000..f766eafdfabc
--- /dev/null
+++ b/slideshow/source/engine/expressionnodefactory.cxx
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <expressionnodefactory.hxx>
+
+#include <canvas/verbosetrace.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+
+#include <functional>
+#include <algorithm>
+
+
+/* Implementation of ExpressionNodeFactory class */
+
+namespace slideshow
+{
+ namespace internal
+ {
+ namespace
+ {
+ class ConstantValueExpression : public ExpressionNode
+ {
+ public:
+ ConstantValueExpression( double rValue ) :
+ maValue( rValue )
+ {
+ }
+
+ virtual double operator()( double /*t*/ ) const
+ {
+ return maValue;
+ }
+
+ virtual bool isConstant() const
+ {
+ return true;
+ }
+
+ private:
+ double maValue;
+ };
+
+ class TValueExpression : public ExpressionNode
+ {
+ public:
+ TValueExpression()
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return t;
+ }
+
+ virtual bool isConstant() const
+ {
+ return false;
+ }
+ };
+
+ /** Base class for following binary functions (*+-/)
+
+ Does not pay off to have all this as a template, since
+ we'd have to hold the functor as a member (+33% object
+ size).
+ */
+ class BinaryExpressionBase : public ExpressionNode
+ {
+ public:
+ BinaryExpressionBase( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ mpFirstArg( rFirstArg ),
+ mpSecondArg( rSecondArg )
+ {
+ }
+
+ virtual bool isConstant() const
+ {
+ return
+ mpFirstArg->isConstant() &&
+ mpSecondArg->isConstant();
+ }
+
+ protected:
+ ExpressionNodeSharedPtr mpFirstArg;
+ ExpressionNodeSharedPtr mpSecondArg;
+ };
+
+ class PlusExpression : public BinaryExpressionBase
+ {
+ public:
+ PlusExpression( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ BinaryExpressionBase( rFirstArg, rSecondArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return (*mpFirstArg)(t) + (*mpSecondArg)(t);
+ }
+ };
+
+ class MinusExpression : public BinaryExpressionBase
+ {
+ public:
+ MinusExpression( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ BinaryExpressionBase( rFirstArg, rSecondArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return (*mpFirstArg)(t) - (*mpSecondArg)(t);
+ }
+ };
+
+ class MultipliesExpression : public BinaryExpressionBase
+ {
+ public:
+ MultipliesExpression( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ BinaryExpressionBase( rFirstArg, rSecondArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return (*mpFirstArg)(t) * (*mpSecondArg)(t);
+ }
+ };
+
+ class DividesExpression : public BinaryExpressionBase
+ {
+ public:
+ DividesExpression( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ BinaryExpressionBase( rFirstArg, rSecondArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return (*mpFirstArg)(t) / (*mpSecondArg)(t);
+ }
+ };
+
+ class ComposedExpression : public BinaryExpressionBase
+ {
+ public:
+ ComposedExpression( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ BinaryExpressionBase( rFirstArg, rSecondArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return (*mpFirstArg)( (*mpSecondArg)(t) );
+ }
+ };
+
+ class MinExpression : public BinaryExpressionBase
+ {
+ public:
+ MinExpression( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ BinaryExpressionBase( rFirstArg, rSecondArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return ::std::min( (*mpFirstArg)(t), (*mpSecondArg)(t) );
+ }
+ };
+
+ class MaxExpression : public BinaryExpressionBase
+ {
+ public:
+ MaxExpression( const ExpressionNodeSharedPtr& rFirstArg,
+ const ExpressionNodeSharedPtr& rSecondArg ) :
+ BinaryExpressionBase( rFirstArg, rSecondArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return ::std::max( (*mpFirstArg)(t), (*mpSecondArg)(t) );
+ }
+ };
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createConstantValueExpression( double rConstantValue )
+ {
+ return ExpressionNodeSharedPtr( new ConstantValueExpression(rConstantValue) );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createValueTExpression()
+ {
+ return ExpressionNodeSharedPtr( new TValueExpression() );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createPlusExpression( const ExpressionNodeSharedPtr& rLHS,
+ const ExpressionNodeSharedPtr& rRHS )
+ {
+ return ExpressionNodeSharedPtr( new PlusExpression(rLHS, rRHS) );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createMinusExpression( const ExpressionNodeSharedPtr& rLHS,
+ const ExpressionNodeSharedPtr& rRHS )
+ {
+ return ExpressionNodeSharedPtr( new MinusExpression(rLHS, rRHS) );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createMultipliesExpression( const ExpressionNodeSharedPtr& rLHS,
+ const ExpressionNodeSharedPtr& rRHS )
+ {
+ return ExpressionNodeSharedPtr( new MultipliesExpression(rLHS, rRHS) );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createDividesExpression( const ExpressionNodeSharedPtr& rLHS,
+ const ExpressionNodeSharedPtr& rRHS )
+ {
+ return ExpressionNodeSharedPtr( new DividesExpression(rLHS, rRHS) );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createComposedExpression ( const ExpressionNodeSharedPtr& rOuterFunction,
+ const ExpressionNodeSharedPtr& rInnerFunction )
+ {
+ return ExpressionNodeSharedPtr( new ComposedExpression(rOuterFunction, rInnerFunction) );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createMinExpression ( const ExpressionNodeSharedPtr& rOuterFunction,
+ const ExpressionNodeSharedPtr& rInnerFunction )
+ {
+ return ExpressionNodeSharedPtr( new MinExpression(rOuterFunction, rInnerFunction) );
+ }
+
+ ExpressionNodeSharedPtr ExpressionNodeFactory::createMaxExpression ( const ExpressionNodeSharedPtr& rOuterFunction,
+ const ExpressionNodeSharedPtr& rInnerFunction )
+ {
+ return ExpressionNodeSharedPtr( new MaxExpression(rOuterFunction, rInnerFunction) );
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/makefile.mk b/slideshow/source/engine/makefile.mk
new file mode 100644
index 000000000000..da01c928569f
--- /dev/null
+++ b/slideshow/source/engine/makefile.mk
@@ -0,0 +1,98 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=slideshow
+TARGET=engine
+ENABLE_EXCEPTIONS=TRUE
+
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+ENVCFLAGS += -DBOOST_SPIRIT_USE_OLD_NAMESPACE
+
+.IF "$(OS)"=="SOLARIS"
+.IF "$(CCNUMVER)"=="00050009"
+# SunStudio12: anachronism warning in boost code (smilfunctionparser.cxx)
+# reevaluate with newer boost or compiler version
+CFLAGSWARNCXX!:=$(CFLAGSWARNCXX),badargtype2w
+.ENDIF
+.ENDIF
+
+# Disable optimization for SunCC Sparc (funny loops
+# when parsing e.g. "x+width/2")
+# Do not disable optimization for SunCC++ 5.5 Solaris x86,
+# this compiler has an ICE on smilfunctionparser.cxx *without*
+# optimization
+.IF "$(OS)$(CPU)"=="SOLARISS" && "$(COM)"!="GCC"
+NOOPTFILES= $(SLO)$/smilfunctionparser.obj
+.ENDIF
+# same issue for MACOSX
+.IF "$(OS)"=="MACOSX"
+NOOPTFILES= $(SLO)$/smilfunctionparser.obj
+.ENDIF
+
+SLOFILES = $(SLO)$/activitiesqueue.obj \
+ $(SLO)$/animatedsprite.obj \
+ $(SLO)$/animationfactory.obj \
+ $(SLO)$/attributemap.obj \
+ $(SLO)$/color.obj \
+ $(SLO)$/delayevent.obj \
+ $(SLO)$/effectrewinder.obj \
+ $(SLO)$/eventmultiplexer.obj \
+ $(SLO)$/eventqueue.obj \
+ $(SLO)$/expressionnodefactory.obj \
+ $(SLO)$/rehearsetimingsactivity.obj \
+ $(SLO)$/screenupdater.obj \
+ $(SLO)$/shapeattributelayer.obj \
+ $(SLO)$/shapesubset.obj \
+ $(SLO)$/slidebitmap.obj \
+ $(SLO)$/slideshowcontext.obj \
+ $(SLO)$/slideshowimpl.obj \
+ $(SLO)$/slideview.obj \
+ $(SLO)$/smilfunctionparser.obj \
+ $(SLO)$/soundplayer.obj \
+ $(SLO)$/tools.obj \
+ $(SLO)$/unoviewcontainer.obj \
+ $(SLO)$/usereventqueue.obj \
+ $(SLO)$/waitsymbol.obj \
+ $(SLO)$/wakeupevent.obj \
+ $(SLO)$/debug.obj
+
+.IF "$(debug)"!="" || "$(DEBUG)"!=""
+SLOFILES += $(SLO)$/sp_debug.obj
+.ENDIF
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/rehearsetimingsactivity.cxx b/slideshow/source/engine/rehearsetimingsactivity.cxx
new file mode 100644
index 000000000000..808a9756e17c
--- /dev/null
+++ b/slideshow/source/engine/rehearsetimingsactivity.cxx
@@ -0,0 +1,585 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <boost/current_function.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/metric.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <basegfx/range/b2drange.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/rendering/XBitmap.hpp>
+
+#include "eventqueue.hxx"
+#include "screenupdater.hxx"
+#include "eventmultiplexer.hxx"
+#include "activitiesqueue.hxx"
+#include "slideshowcontext.hxx"
+#include "mouseeventhandler.hxx"
+#include "rehearsetimingsactivity.hxx"
+
+#include <boost/bind.hpp>
+#include <o3tl/compat_functional.hxx>
+#include <algorithm>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+
+namespace slideshow {
+namespace internal {
+
+class RehearseTimingsActivity::WakeupEvent : public Event,
+ private ::boost::noncopyable
+{
+public:
+ WakeupEvent( boost::shared_ptr< ::canvas::tools::ElapsedTime > const& pTimeBase,
+ ActivitySharedPtr const& rActivity,
+ ActivitiesQueue & rActivityQueue ) :
+#if OSL_DEBUG_LEVEL > 1
+ Event(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("WakeupEvent"))),
+#endif
+ maTimer(pTimeBase),
+ mnNextTime(0.0),
+ mpActivity(rActivity),
+ mrActivityQueue( rActivityQueue )
+ {}
+
+ virtual void dispose() {}
+ virtual bool fire()
+ {
+ ActivitySharedPtr pActivity( mpActivity.lock() );
+ if( !pActivity )
+ return false;
+
+ return mrActivityQueue.addActivity( pActivity );
+ }
+
+ virtual bool isCharged() const { return true; }
+ virtual double getActivationTime( double nCurrentTime ) const
+ {
+ const double nElapsedTime( maTimer.getElapsedTime() );
+
+ return ::std::max( nCurrentTime,
+ nCurrentTime - nElapsedTime + mnNextTime );
+ }
+
+ /// Start the internal timer
+ void start() { maTimer.reset(); }
+
+ /** Set the next timeout this object should generate.
+
+ @param nextTime
+ Absolute time, measured from the last start() call,
+ when this event should wakeup the Activity again. If
+ your time is relative, simply call start() just before
+ every setNextTimeout() call.
+ */
+ void setNextTimeout( double nextTime ) { mnNextTime = nextTime; }
+
+private:
+ ::canvas::tools::ElapsedTime maTimer;
+ double mnNextTime;
+ boost::weak_ptr<Activity> mpActivity;
+ ActivitiesQueue& mrActivityQueue;
+};
+
+class RehearseTimingsActivity::MouseHandler : public MouseEventHandler,
+ private boost::noncopyable
+{
+public:
+ explicit MouseHandler( RehearseTimingsActivity& rta );
+
+ void reset();
+ bool hasBeenClicked() const { return mbHasBeenClicked; }
+
+ // MouseEventHandler
+ virtual bool handleMousePressed( awt::MouseEvent const & evt );
+ virtual bool handleMouseReleased( awt::MouseEvent const & evt );
+ virtual bool handleMouseEntered( awt::MouseEvent const & evt );
+ virtual bool handleMouseExited( awt::MouseEvent const & evt );
+ virtual bool handleMouseDragged( awt::MouseEvent const & evt );
+ virtual bool handleMouseMoved( awt::MouseEvent const & evt );
+
+private:
+ bool isInArea( com::sun::star::awt::MouseEvent const & evt ) const;
+ void updatePressedState( const bool pressedState ) const;
+
+ RehearseTimingsActivity& mrActivity;
+ bool mbHasBeenClicked;
+ bool mbMouseStartedInArea;
+};
+
+const sal_Int32 LEFT_BORDER_SPACE = 10;
+const sal_Int32 LOWER_BORDER_SPACE = 30;
+
+RehearseTimingsActivity::RehearseTimingsActivity( const SlideShowContext& rContext ) :
+ mrEventQueue(rContext.mrEventQueue),
+ mrScreenUpdater(rContext.mrScreenUpdater),
+ mrEventMultiplexer(rContext.mrEventMultiplexer),
+ mrActivitiesQueue(rContext.mrActivitiesQueue),
+ maElapsedTime( rContext.mrEventQueue.getTimer() ),
+ maViews(),
+ maSpriteRectangle(),
+ maFont( Application::GetSettings().GetStyleSettings().GetInfoFont() ),
+ mpWakeUpEvent(),
+ mpMouseHandler(),
+ maSpriteSizePixel(),
+ mnYOffset(0),
+ mbActive(false),
+ mbDrawPressed(false)
+{
+ maFont.SetHeight( maFont.GetHeight() * 2 );
+ maFont.SetWidth( maFont.GetWidth() * 2 );
+ maFont.SetAlign( ALIGN_BASELINE );
+ maFont.SetColor( COL_BLACK );
+
+ // determine sprite size (in pixel):
+ VirtualDevice blackHole;
+ blackHole.EnableOutput(false);
+ blackHole.SetFont( maFont );
+ blackHole.SetMapMode( MAP_PIXEL );
+ Rectangle rect;
+ const FontMetric metric( blackHole.GetFontMetric() );
+ blackHole.GetTextBoundRect(
+ rect, String(RTL_CONSTASCII_USTRINGPARAM("XX:XX:XX")) );
+ maSpriteSizePixel.setX( rect.getWidth() * 12 / 10 );
+ maSpriteSizePixel.setY( metric.GetLineHeight() * 11 / 10 );
+ mnYOffset = (metric.GetAscent() + (metric.GetLineHeight() / 20));
+
+ std::for_each( rContext.mrViewContainer.begin(),
+ rContext.mrViewContainer.end(),
+ boost::bind( &RehearseTimingsActivity::viewAdded,
+ this,
+ _1 ));
+}
+
+RehearseTimingsActivity::~RehearseTimingsActivity()
+{
+ try
+ {
+ stop();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+}
+
+boost::shared_ptr<RehearseTimingsActivity> RehearseTimingsActivity::create(
+ const SlideShowContext& rContext )
+{
+ boost::shared_ptr<RehearseTimingsActivity> pActivity(
+ new RehearseTimingsActivity( rContext ));
+
+ pActivity->mpMouseHandler.reset(
+ new MouseHandler(*pActivity.get()) );
+ pActivity->mpWakeUpEvent.reset(
+ new WakeupEvent( rContext.mrEventQueue.getTimer(),
+ pActivity,
+ rContext.mrActivitiesQueue ));
+
+ rContext.mrEventMultiplexer.addViewHandler( pActivity );
+
+ return pActivity;
+}
+
+void RehearseTimingsActivity::start()
+{
+ maElapsedTime.reset();
+ mbDrawPressed = false;
+ mbActive = true;
+
+ // paint and show all sprites:
+ paintAllSprites();
+ for_each_sprite( boost::bind( &cppcanvas::Sprite::show, _1 ) );
+
+ mrActivitiesQueue.addActivity( shared_from_this() );
+
+ mpMouseHandler->reset();
+ mrEventMultiplexer.addClickHandler(
+ mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
+ mrEventMultiplexer.addMouseMoveHandler(
+ mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
+}
+
+double RehearseTimingsActivity::stop()
+{
+ mrEventMultiplexer.removeMouseMoveHandler( mpMouseHandler );
+ mrEventMultiplexer.removeClickHandler( mpMouseHandler );
+
+ mbActive = false; // will be removed from queue
+
+ for_each_sprite( boost::bind( &cppcanvas::Sprite::hide, _1 ) );
+
+ return maElapsedTime.getElapsedTime();
+}
+
+bool RehearseTimingsActivity::hasBeenClicked() const
+{
+ if (mpMouseHandler)
+ return mpMouseHandler->hasBeenClicked();
+ return false;
+}
+
+// Disposable:
+void RehearseTimingsActivity::dispose()
+{
+ stop();
+
+ mpWakeUpEvent.reset();
+ mpMouseHandler.reset();
+
+ ViewsVecT().swap( maViews );
+}
+
+// Activity:
+double RehearseTimingsActivity::calcTimeLag() const
+{
+ return 0.0;
+}
+
+bool RehearseTimingsActivity::perform()
+{
+ if( !isActive() )
+ return false;
+
+ if( !mpWakeUpEvent )
+ return false;
+
+ mpWakeUpEvent->start();
+ mpWakeUpEvent->setNextTimeout( 0.5 );
+ mrEventQueue.addEvent( mpWakeUpEvent );
+
+ paintAllSprites();
+
+ // sprites changed, need screen update
+ mrScreenUpdater.notifyUpdate();
+
+ return false; // don't reinsert, WakeupEvent will perform
+ // that after the given timeout
+}
+
+bool RehearseTimingsActivity::isActive() const
+{
+ return mbActive;
+}
+
+void RehearseTimingsActivity::dequeued()
+{
+ // not used here
+}
+
+void RehearseTimingsActivity::end()
+{
+ if (isActive())
+ {
+ stop();
+ mbActive = false;
+ }
+}
+
+basegfx::B2DRange RehearseTimingsActivity::calcSpriteRectangle( UnoViewSharedPtr const& rView ) const
+{
+ const Reference<rendering::XBitmap> xBitmap( rView->getCanvas()->getUNOCanvas(),
+ UNO_QUERY );
+ if( !xBitmap.is() )
+ return basegfx::B2DRange();
+
+ const geometry::IntegerSize2D realSize( xBitmap->getSize() );
+ // pixel:
+ basegfx::B2DPoint spritePos(
+ std::min<sal_Int32>( realSize.Width, LEFT_BORDER_SPACE ),
+ std::max<sal_Int32>( 0, realSize.Height - maSpriteSizePixel.getY()
+ - LOWER_BORDER_SPACE ) );
+ basegfx::B2DHomMatrix transformation( rView->getTransformation() );
+ transformation.invert();
+ spritePos *= transformation;
+ basegfx::B2DSize spriteSize( maSpriteSizePixel.getX(),
+ maSpriteSizePixel.getY() );
+ spriteSize *= transformation;
+ return basegfx::B2DRange(
+ spritePos.getX(), spritePos.getY(),
+ spritePos.getX() + spriteSize.getX(),
+ spritePos.getY() + spriteSize.getY() );
+}
+
+void RehearseTimingsActivity::viewAdded( const UnoViewSharedPtr& rView )
+{
+ cppcanvas::CustomSpriteSharedPtr sprite(
+ rView->createSprite( basegfx::B2DSize(
+ maSpriteSizePixel.getX()+2,
+ maSpriteSizePixel.getY()+2 ),
+ 1001.0 )); // sprite should be in front of all
+ // other sprites
+ sprite->setAlpha( 0.8 );
+ const basegfx::B2DRange spriteRectangle(
+ calcSpriteRectangle( rView ) );
+ sprite->move( basegfx::B2DPoint(
+ spriteRectangle.getMinX(),
+ spriteRectangle.getMinY() ) );
+
+ if( maViews.empty() )
+ maSpriteRectangle = spriteRectangle;
+
+ maViews.push_back( ViewsVecT::value_type( rView, sprite ) );
+
+ if (isActive())
+ sprite->show();
+}
+
+void RehearseTimingsActivity::viewRemoved( const UnoViewSharedPtr& rView )
+{
+ maViews.erase(
+ std::remove_if(
+ maViews.begin(), maViews.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( o3tl::select1st<ViewsVecT::value_type>(), _1 ))),
+ maViews.end() );
+}
+
+void RehearseTimingsActivity::viewChanged( const UnoViewSharedPtr& rView )
+{
+ // find entry corresponding to modified view
+ ViewsVecT::iterator aModifiedEntry(
+ std::find_if(
+ maViews.begin(),
+ maViews.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( o3tl::select1st<ViewsVecT::value_type>(), _1 ))));
+
+ OSL_ASSERT( aModifiedEntry != maViews.end() );
+ if( aModifiedEntry == maViews.end() )
+ return;
+
+ // new sprite pos, transformation might have changed:
+ maSpriteRectangle = calcSpriteRectangle( rView );
+
+ // reposition sprite:
+ aModifiedEntry->second->move( maSpriteRectangle.getMinimum() );
+
+ // sprites changed, need screen update
+ mrScreenUpdater.notifyUpdate( rView );
+}
+
+void RehearseTimingsActivity::viewsChanged()
+{
+ if( !maViews.empty() )
+ {
+ // new sprite pos, transformation might have changed:
+ maSpriteRectangle = calcSpriteRectangle( maViews.front().first );
+
+ // reposition sprites
+ for_each_sprite( boost::bind( &cppcanvas::Sprite::move,
+ _1,
+ boost::cref(maSpriteRectangle.getMinimum())) );
+
+ // sprites changed, need screen update
+ mrScreenUpdater.notifyUpdate();
+ }
+}
+
+void RehearseTimingsActivity::paintAllSprites() const
+{
+ for_each_sprite(
+ boost::bind( &RehearseTimingsActivity::paint, this,
+ // call getContentCanvas() on each sprite:
+ boost::bind(
+ &cppcanvas::CustomSprite::getContentCanvas, _1 ) ) );
+}
+
+void RehearseTimingsActivity::paint( cppcanvas::CanvasSharedPtr const & canvas ) const
+{
+ // build timer string:
+ const sal_Int32 nTimeSecs =
+ static_cast<sal_Int32>(maElapsedTime.getElapsedTime());
+ rtl::OUStringBuffer buf;
+ sal_Int32 n = (nTimeSecs / 3600);
+ if (n < 10)
+ buf.append( static_cast<sal_Unicode>('0') );
+ buf.append( n );
+ buf.append( static_cast<sal_Unicode>(':') );
+ n = ((nTimeSecs % 3600) / 60);
+ if (n < 10)
+ buf.append( static_cast<sal_Unicode>('0') );
+ buf.append( n );
+ buf.append( static_cast<sal_Unicode>(':') );
+ n = (nTimeSecs % 60);
+ if (n < 10)
+ buf.append( static_cast<sal_Unicode>('0') );
+ buf.append( n );
+ const rtl::OUString time = buf.makeStringAndClear();
+
+ // create the MetaFile:
+ GDIMetaFile metaFile;
+ VirtualDevice blackHole;
+ metaFile.Record( &blackHole );
+ metaFile.SetPrefSize( Size( 1, 1 ) );
+ blackHole.EnableOutput(false);
+ blackHole.SetMapMode( MAP_PIXEL );
+ blackHole.SetFont( maFont );
+ Rectangle rect = Rectangle( 0,0,
+ maSpriteSizePixel.getX(),
+ maSpriteSizePixel.getY());
+ if (mbDrawPressed)
+ {
+ blackHole.SetTextColor( COL_BLACK );
+ blackHole.SetFillColor( COL_LIGHTGRAY );
+ blackHole.SetLineColor( COL_GRAY );
+ }
+ else
+ {
+ blackHole.SetTextColor( COL_BLACK );
+ blackHole.SetFillColor( COL_WHITE );
+ blackHole.SetLineColor( COL_GRAY );
+ }
+ blackHole.DrawRect( rect );
+ blackHole.GetTextBoundRect( rect, time );
+ blackHole.DrawText(
+ Point( (maSpriteSizePixel.getX() - rect.getWidth()) / 2,
+ mnYOffset ), time );
+
+ metaFile.Stop();
+ metaFile.WindStart();
+
+ cppcanvas::RendererSharedPtr renderer(
+ cppcanvas::VCLFactory::getInstance().createRenderer(
+ canvas, metaFile, cppcanvas::Renderer::Parameters() ) );
+ const bool succ = renderer->draw();
+ OSL_ASSERT( succ );
+ (void)succ;
+}
+
+
+RehearseTimingsActivity::MouseHandler::MouseHandler( RehearseTimingsActivity& rta ) :
+ mrActivity(rta),
+ mbHasBeenClicked(false),
+ mbMouseStartedInArea(false)
+{}
+
+void RehearseTimingsActivity::MouseHandler::reset()
+{
+ mbHasBeenClicked = false;
+ mbMouseStartedInArea = false;
+}
+
+bool RehearseTimingsActivity::MouseHandler::isInArea(
+ awt::MouseEvent const & evt ) const
+{
+ return mrActivity.maSpriteRectangle.isInside(
+ basegfx::B2DPoint( evt.X, evt.Y ) );
+}
+
+void RehearseTimingsActivity::MouseHandler::updatePressedState(
+ const bool pressedState ) const
+{
+ if( pressedState != mrActivity.mbDrawPressed )
+ {
+ mrActivity.mbDrawPressed = pressedState;
+ mrActivity.paintAllSprites();
+
+ mrActivity.mrScreenUpdater.notifyUpdate();
+ }
+}
+
+// MouseEventHandler
+bool RehearseTimingsActivity::MouseHandler::handleMousePressed(
+ awt::MouseEvent const & evt )
+{
+ if( evt.Buttons == awt::MouseButton::LEFT && isInArea(evt) )
+ {
+ mbMouseStartedInArea = true;
+ updatePressedState(true);
+ return true; // consume event
+ }
+ return false;
+}
+
+bool RehearseTimingsActivity::MouseHandler::handleMouseReleased(
+ awt::MouseEvent const & evt )
+{
+ if( evt.Buttons == awt::MouseButton::LEFT && mbMouseStartedInArea )
+ {
+ mbHasBeenClicked = isInArea(evt); // fini if in
+ mbMouseStartedInArea = false;
+ updatePressedState(false);
+ if( !mbHasBeenClicked )
+ return true; // consume event, else next slide (manual advance)
+ }
+ return false;
+}
+
+bool RehearseTimingsActivity::MouseHandler::handleMouseEntered(
+ awt::MouseEvent const & /*evt*/ )
+{
+ return false;
+}
+
+bool RehearseTimingsActivity::MouseHandler::handleMouseExited(
+ awt::MouseEvent const & /*evt*/ )
+{
+ return false;
+}
+
+bool RehearseTimingsActivity::MouseHandler::handleMouseDragged(
+ awt::MouseEvent const & evt )
+{
+ if( mbMouseStartedInArea )
+ updatePressedState( isInArea(evt) );
+ return false;
+}
+
+bool RehearseTimingsActivity::MouseHandler::handleMouseMoved(
+ awt::MouseEvent const & /*evt*/ )
+{
+ return false;
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/rehearsetimingsactivity.hxx b/slideshow/source/engine/rehearsetimingsactivity.hxx
new file mode 100644
index 000000000000..881443fc35a7
--- /dev/null
+++ b/slideshow/source/engine/rehearsetimingsactivity.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_REHEARSETIMINGSACTIVITY_HXX
+#define INCLUDED_SLIDESHOW_REHEARSETIMINGSACTIVITY_HXX
+
+#include "activity.hxx"
+
+#include <basegfx/range/b2drange.hxx>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <vector>
+#include <utility>
+
+class Font;
+namespace canvas{ namespace tools{ class ElapsedTime; }}
+namespace cppcanvas{ class CustomSprite; }
+namespace basegfx
+{
+ class B2IVector;
+ class B2DRange;
+}
+
+namespace slideshow {
+namespace internal {
+
+struct SlideShowContext;
+class EventMultiplexer;
+class ScreenUpdater;
+class RehearseTimingsActivity : public Activity,
+ public ViewEventHandler,
+ public boost::enable_shared_from_this<RehearseTimingsActivity>,
+ private ::boost::noncopyable
+{
+public:
+ /** Creates the activity.
+ */
+ static boost::shared_ptr<RehearseTimingsActivity> create(
+ const SlideShowContext& rContext );
+
+ virtual ~RehearseTimingsActivity();
+
+ /** Starts and shows the timer; adds to activity queue.
+ */
+ void start();
+
+ /** Stops and hides the timer.
+ @return elapsed time
+ */
+ double stop();
+
+ /** Determines whether the timer button has been clicked.
+ */
+ bool hasBeenClicked() const;
+
+ // ViewEventHandler interface
+ virtual void viewAdded( const UnoViewSharedPtr& rView );
+ virtual void viewRemoved( const UnoViewSharedPtr& rView );
+ virtual void viewChanged( const UnoViewSharedPtr& rView );
+ virtual void viewsChanged();
+
+ // Disposable:
+ virtual void dispose();
+ // Activity:
+ virtual double calcTimeLag() const;
+ virtual bool perform();
+ virtual bool isActive() const;
+ virtual void dequeued();
+ virtual void end();
+
+private:
+ class WakeupEvent;
+
+ explicit RehearseTimingsActivity( const SlideShowContext& rContext );
+
+ void paint( ::cppcanvas::CanvasSharedPtr const & canvas ) const;
+ void paintAllSprites() const;
+
+ class MouseHandler;
+ friend class MouseHandler;
+
+ typedef ::std::vector<
+ ::std::pair<UnoViewSharedPtr,
+ boost::shared_ptr<cppcanvas::CustomSprite> > > ViewsVecT;
+
+ template <typename func_type>
+ void for_each_sprite( func_type const & func ) const
+ {
+ ViewsVecT::const_iterator iPos( maViews.begin() );
+ const ViewsVecT::const_iterator iEnd( maViews.end() );
+ for ( ; iPos != iEnd; ++iPos )
+ func( iPos->second );
+ }
+
+ ::basegfx::B2DRange calcSpriteRectangle(
+ UnoViewSharedPtr const & rView ) const;
+
+ EventQueue& mrEventQueue;
+ ScreenUpdater& mrScreenUpdater;
+ EventMultiplexer& mrEventMultiplexer;
+ ActivitiesQueue& mrActivitiesQueue;
+ canvas::tools::ElapsedTime maElapsedTime;
+
+ ViewsVecT maViews;
+
+ /// screen rect of sprite (in view coordinates!)
+ ::basegfx::B2DRange maSpriteRectangle;
+
+ Font maFont;
+ boost::shared_ptr<WakeupEvent> mpWakeUpEvent;
+ boost::shared_ptr<MouseHandler> mpMouseHandler;
+ ::basegfx::B2IVector maSpriteSizePixel;
+ sal_Int32 mnYOffset;
+ bool mbActive;
+ bool mbDrawPressed;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_REHEARSETIMINGSACTIVITY_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/screenupdater.cxx b/slideshow/source/engine/screenupdater.cxx
new file mode 100644
index 000000000000..307fd127c88c
--- /dev/null
+++ b/slideshow/source/engine/screenupdater.cxx
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#include "precompiled_slideshow.hxx"
+
+#include "screenupdater.hxx"
+#include "listenercontainer.hxx"
+
+#include <boost/bind.hpp>
+#include <vector>
+#include <algorithm>
+
+namespace {
+ class UpdateLock : public ::slideshow::internal::ScreenUpdater::UpdateLock
+ {
+ public:
+ UpdateLock (::slideshow::internal::ScreenUpdater& rUpdater, const bool bStartLocked);
+ virtual ~UpdateLock (void);
+ virtual void Activate (void);
+ private:
+ ::slideshow::internal::ScreenUpdater& mrUpdater;
+ bool mbIsActivated;
+ };
+}
+
+namespace slideshow
+{
+namespace internal
+{
+ typedef std::vector<
+ std::pair<UnoViewSharedPtr,bool> > UpdateRequestVector;
+
+ struct ScreenUpdater::ImplScreenUpdater
+ {
+ /** List of registered ViewUpdaters, to consult for necessary
+ updates
+ */
+ ThreadUnsafeListenerContainer<
+ ViewUpdateSharedPtr,
+ std::vector<ViewUpdateSharedPtr> > maUpdaters;
+
+ /// Views that have been notified for update
+ UpdateRequestVector maViewUpdateRequests;
+
+ /// List of View. Used to issue screen updates on.
+ UnoViewContainer const& mrViewContainer;
+
+ /// True, if a notifyUpdate() for all views has been issued.
+ bool mbUpdateAllRequest;
+
+ /// True, if at least one notifyUpdate() call had bViewClobbered set
+ bool mbViewClobbered;
+
+ /// The screen is updated only when mnLockCount==0
+ sal_Int32 mnLockCount;
+
+ explicit ImplScreenUpdater( UnoViewContainer const& rViewContainer ) :
+ maUpdaters(),
+ maViewUpdateRequests(),
+ mrViewContainer(rViewContainer),
+ mbUpdateAllRequest(false),
+ mbViewClobbered(false),
+ mnLockCount(0)
+ {}
+ };
+
+ ScreenUpdater::ScreenUpdater( UnoViewContainer const& rViewContainer ) :
+ mpImpl(new ImplScreenUpdater(rViewContainer) )
+ {
+ }
+
+ ScreenUpdater::~ScreenUpdater()
+ {
+ // outline because of pimpl
+ }
+
+ void ScreenUpdater::notifyUpdate()
+ {
+ mpImpl->mbUpdateAllRequest = true;
+ }
+
+ void ScreenUpdater::notifyUpdate( const UnoViewSharedPtr& rView,
+ bool bViewClobbered )
+ {
+ mpImpl->maViewUpdateRequests.push_back(
+ std::make_pair(rView, bViewClobbered) );
+
+ if( bViewClobbered )
+ mpImpl->mbViewClobbered = true;
+ }
+
+ void ScreenUpdater::commitUpdates()
+ {
+ if (mpImpl->mnLockCount > 0)
+ return;
+
+ // cases:
+ //
+ // (a) no update necessary at all
+ //
+ // (b) no ViewUpdate-generated update
+ // I. update all views requested -> for_each( mrViewContainer )
+ // II. update some views requested -> for_each( maViewUpdateRequests )
+ //
+ // (c) ViewUpdate-triggered update - update all views
+ //
+
+ // any ViewUpdate-triggered updates?
+ const bool bViewUpdatesNeeded(
+ mpImpl->maUpdaters.apply(
+ boost::mem_fn(&ViewUpdate::needsUpdate)) );
+
+ if( bViewUpdatesNeeded )
+ {
+ mpImpl->maUpdaters.applyAll(
+ boost::mem_fn((bool (ViewUpdate::*)())&ViewUpdate::update) );
+ }
+
+ if( bViewUpdatesNeeded ||
+ mpImpl->mbUpdateAllRequest )
+ {
+ // unconditionally update all views
+ std::for_each( mpImpl->mrViewContainer.begin(),
+ mpImpl->mrViewContainer.end(),
+ mpImpl->mbViewClobbered ?
+ boost::mem_fn(&View::paintScreen) :
+ boost::mem_fn(&View::updateScreen) );
+ }
+ else if( !mpImpl->maViewUpdateRequests.empty() )
+ {
+ // update notified views only
+ UpdateRequestVector::const_iterator aIter(
+ mpImpl->maViewUpdateRequests.begin() );
+ const UpdateRequestVector::const_iterator aEnd(
+ mpImpl->maViewUpdateRequests.end() );
+ while( aIter != aEnd )
+ {
+ // TODO(P1): this is O(n^2) in the number of views, if
+ // lots of views notify updates.
+ const UnoViewVector::const_iterator aEndOfViews(
+ mpImpl->mrViewContainer.end() );
+ UnoViewVector::const_iterator aFoundView;
+ if( (aFoundView=std::find(mpImpl->mrViewContainer.begin(),
+ aEndOfViews,
+ aIter->first)) != aEndOfViews )
+ {
+ if( aIter->second )
+ (*aFoundView)->paintScreen(); // force-paint
+ else
+ (*aFoundView)->updateScreen(); // update changes only
+ }
+
+ ++aIter;
+ }
+ }
+
+ // done - clear requests
+ mpImpl->mbViewClobbered = false;
+ mpImpl->mbUpdateAllRequest = false;
+ UpdateRequestVector().swap( mpImpl->maViewUpdateRequests );
+ }
+
+ void ScreenUpdater::addViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
+ {
+ mpImpl->maUpdaters.add( rViewUpdate );
+ }
+
+ void ScreenUpdater::removeViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
+ {
+ mpImpl->maUpdaters.remove( rViewUpdate );
+ }
+
+ void ScreenUpdater::requestImmediateUpdate()
+ {
+ if (mpImpl->mnLockCount > 0)
+ return;
+
+ // TODO(F2): This will interfere with other updates, since it
+ // happens out-of-sync with main animation loop. Might cause
+ // artifacts.
+ std::for_each( mpImpl->mrViewContainer.begin(),
+ mpImpl->mrViewContainer.end(),
+ boost::mem_fn(&View::updateScreen) );
+ }
+
+ void ScreenUpdater::lockUpdates (void)
+ {
+ ++mpImpl->mnLockCount;
+ OSL_ASSERT(mpImpl->mnLockCount>0);
+ }
+
+ void ScreenUpdater::unlockUpdates (void)
+ {
+ OSL_ASSERT(mpImpl->mnLockCount>0);
+ if (mpImpl->mnLockCount > 0)
+ {
+ --mpImpl->mnLockCount;
+ if (mpImpl->mnLockCount)
+ commitUpdates();
+ }
+ }
+
+ ::boost::shared_ptr<ScreenUpdater::UpdateLock> ScreenUpdater::createLock (const bool bStartLocked)
+ {
+ return ::boost::shared_ptr<ScreenUpdater::UpdateLock>(new ::UpdateLock(*this, bStartLocked));
+ }
+
+
+} // namespace internal
+} // namespace slideshow
+
+namespace {
+
+UpdateLock::UpdateLock (
+ ::slideshow::internal::ScreenUpdater& rUpdater,
+ const bool bStartLocked)
+ : mrUpdater(rUpdater),
+ mbIsActivated(false)
+{
+ if (bStartLocked)
+ Activate();
+}
+
+
+
+
+UpdateLock::~UpdateLock (void)
+{
+ if (mbIsActivated)
+ mrUpdater.unlockUpdates();
+}
+
+
+
+
+void UpdateLock::Activate (void)
+{
+ if ( ! mbIsActivated)
+ {
+ mbIsActivated = true;
+ mrUpdater.lockUpdates();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapeattributelayer.cxx b/slideshow/source/engine/shapeattributelayer.cxx
new file mode 100644
index 000000000000..a86c7c916326
--- /dev/null
+++ b/slideshow/source/engine/shapeattributelayer.cxx
@@ -0,0 +1,859 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <shapeattributelayer.hxx>
+
+#include <canvas/verbosetrace.hxx>
+
+
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <rtl/math.hxx>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Update state ids
+
+ This method updates all state IDs from possible
+ children. Whenever a child's state ID changed, we
+ increment ours.
+ */
+ void ShapeAttributeLayer::updateStateIds()
+ {
+ if( haveChild() )
+ {
+ if( mnTransformationState != mpChild->getTransformationState() )
+ ++mnTransformationState;
+ if( mnClipState != mpChild->getClipState() )
+ ++mnClipState;
+ if( mnAlphaState != mpChild->getAlphaState() )
+ ++mnAlphaState;
+ if( mnPositionState != mpChild->getPositionState() )
+ ++mnPositionState;
+ if( mnContentState != mpChild->getContentState() )
+ ++mnContentState;
+ if( mnVisibilityState != mpChild->getVisibilityState() )
+ ++mnVisibilityState;
+ }
+ }
+
+ /** Calc attribute value.
+
+ This method determines the current attribute value,
+ appropriately combining it with children values (by
+ evaluating the mnAdditiveMode member).
+ */
+ template< typename T > T ShapeAttributeLayer::calcValue( const T& rCurrValue,
+ bool bThisInstanceValid,
+ bool (ShapeAttributeLayer::*pIsValid)() const,
+ T (ShapeAttributeLayer::*pGetValue)() const ) const
+ {
+ // deviated from the (*shared_ptr).*mpFuncPtr notation
+ // here, since gcc does not seem to parse that as a member
+ // function call anymore.
+ const bool bChildInstanceValueValid( haveChild() ? (mpChild.get()->*pIsValid)() : false );
+
+ if( bThisInstanceValid )
+ {
+ if( bChildInstanceValueValid )
+ {
+ // merge with child value
+ switch( mnAdditiveMode )
+ {
+ default:
+ // FALTHROUGH intended
+ case animations::AnimationAdditiveMode::NONE:
+ // FALTHROUGH intended
+ case animations::AnimationAdditiveMode::BASE:
+ // FALTHROUGH intended
+ case animations::AnimationAdditiveMode::REPLACE:
+ // TODO(F2): reverse-engineer the semantics of these
+ // values
+
+ // currently, treat them the same and replace
+ // the child value by our own
+ return rCurrValue;
+
+ case animations::AnimationAdditiveMode::SUM:
+ return rCurrValue + ((*mpChild).*pGetValue)();
+
+ case animations::AnimationAdditiveMode::MULTIPLY:
+ return rCurrValue * ((*mpChild).*pGetValue)();
+ }
+ }
+ else
+ {
+ // this object is the only one defining
+ // the value, so take it
+ return rCurrValue;
+ }
+ }
+ else
+ {
+ return bChildInstanceValueValid ?
+ ((*mpChild).*pGetValue)() :
+ T(); // pass on child value, regardless
+ // if it's valid or not. If not, it's
+ // a default anyway
+ }
+ }
+
+ ShapeAttributeLayer::ShapeAttributeLayer( const ShapeAttributeLayerSharedPtr& rChildLayer ) :
+ mpChild( rChildLayer ),
+
+ maSize(),
+ maPosition(),
+ maClip(),
+
+ maFontFamily(),
+
+ mnRotationAngle(),
+ mnShearXAngle(),
+ mnShearYAngle(),
+ mnAlpha(),
+ mnCharRotationAngle(),
+ mnCharScale(),
+ mnCharWeight(),
+
+ meFillStyle( drawing::FillStyle_NONE ),
+ meLineStyle( drawing::LineStyle_NONE ),
+ meCharPosture( awt::FontSlant_NONE ),
+ mnUnderlineMode(),
+
+ maDimColor(),
+ maFillColor(),
+ maLineColor(),
+ maCharColor(),
+
+ mnTransformationState( rChildLayer ? rChildLayer->getTransformationState() : 0 ),
+ mnClipState( rChildLayer ? rChildLayer->getClipState() : 0),
+ mnAlphaState( rChildLayer ? rChildLayer->getAlphaState() : 0),
+ mnPositionState( rChildLayer ? rChildLayer->getPositionState() : 0 ),
+ mnContentState( rChildLayer ? rChildLayer->getContentState() : 0 ),
+ mnVisibilityState( rChildLayer ? rChildLayer->getVisibilityState() : 0 ),
+
+ mnAdditiveMode( animations::AnimationAdditiveMode::BASE ),
+
+ mbVisibility( false ),
+
+ mbWidthValid( false ),
+ mbHeightValid( false ),
+ mbPosXValid( false ),
+ mbPosYValid( false ),
+ mbClipValid( false ),
+
+ mbFontFamilyValid( false ),
+
+ mbRotationAngleValid( false ),
+ mbShearXAngleValid( false ),
+ mbShearYAngleValid( false ),
+
+ mbAlphaValid( false ),
+
+ mbCharRotationAngleValid( false ),
+ mbCharScaleValid( false ),
+
+ mbDimColorValid( false ),
+ mbFillColorValid( false ),
+ mbLineColorValid( false ),
+ mbCharColorValid( false ),
+
+ mbFillStyleValid( false ),
+ mbLineStyleValid( false ),
+ mbCharWeightValid( false ),
+ mbUnderlineModeValid( false ),
+ mbCharPostureValid( false ),
+ mbVisibilityValid( false )
+ {
+ }
+
+ bool ShapeAttributeLayer::revokeChildLayer( const ShapeAttributeLayerSharedPtr& rChildLayer )
+ {
+ ENSURE_OR_RETURN_FALSE( rChildLayer,
+ "ShapeAttributeLayer::revokeChildLayer(): Will not remove NULL child" );
+
+ if( !haveChild() )
+ return false; // no children, nothing to revoke.
+
+ if( mpChild == rChildLayer )
+ {
+ // we have it - replace by removed child's sibling.
+ mpChild = rChildLayer->getChildLayer();
+
+ // if we're now the first one, defensively increment _all_
+ // state ids: possibly all underlying attributes have now
+ // changed to default
+ if( !haveChild() )
+ {
+ // TODO(P1): Check whether it pays off to check more
+ // detailed, which attributes really change
+ ++mnTransformationState;
+ ++mnClipState;
+ ++mnAlphaState;
+ ++mnPositionState;
+ ++mnContentState;
+ ++mnVisibilityState;
+ }
+ }
+ else
+ {
+ // we don't have it - pass on the request
+ if( !mpChild->revokeChildLayer( rChildLayer ) )
+ return false; // nobody has it - bail out
+ }
+
+ // something might have changed - update ids.
+ updateStateIds();
+
+ return true;
+ }
+
+ ShapeAttributeLayerSharedPtr ShapeAttributeLayer::getChildLayer() const
+ {
+ return mpChild;
+ }
+
+ void ShapeAttributeLayer::setAdditiveMode( sal_Int16 nMode )
+ {
+ if( mnAdditiveMode != nMode )
+ {
+ // TODO(P1): Check whether it pays off to check more
+ // detailed, which attributes really change
+
+ // defensively increment all states - possibly each of them
+ // will change with different additive mode
+ ++mnTransformationState;
+ ++mnClipState;
+ ++mnAlphaState;
+ ++mnPositionState;
+ ++mnContentState;
+ ++mnVisibilityState;
+ }
+
+ mnAdditiveMode = nMode;
+ }
+
+ bool ShapeAttributeLayer::isWidthValid() const
+ {
+ return mbWidthValid ? true : haveChild() ? mpChild->isWidthValid() : false;
+ }
+
+ double ShapeAttributeLayer::getWidth() const
+ {
+ return calcValue< double >(
+ maSize.getX(),
+ mbWidthValid,
+ &ShapeAttributeLayer::isWidthValid,
+ &ShapeAttributeLayer::getWidth );
+ }
+
+ void ShapeAttributeLayer::setWidth( const double& rNewWidth )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewWidth),
+ "ShapeAttributeLayer::setWidth(): Invalid width" );
+
+ maSize.setX( rNewWidth );
+ mbWidthValid = true;
+ ++mnTransformationState;
+ }
+
+ bool ShapeAttributeLayer::isHeightValid() const
+ {
+ return mbHeightValid ? true : haveChild() ? mpChild->isHeightValid() : false;
+ }
+
+ double ShapeAttributeLayer::getHeight() const
+ {
+ return calcValue< double >(
+ maSize.getY(),
+ mbHeightValid,
+ &ShapeAttributeLayer::isHeightValid,
+ &ShapeAttributeLayer::getHeight );
+ }
+
+ void ShapeAttributeLayer::setHeight( const double& rNewHeight )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewHeight),
+ "ShapeAttributeLayer::setHeight(): Invalid height" );
+
+ maSize.setY( rNewHeight );
+ mbHeightValid = true;
+ ++mnTransformationState;
+ }
+
+ void ShapeAttributeLayer::setSize( const ::basegfx::B2DSize& rNewSize )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewSize.getX()) &&
+ ::rtl::math::isFinite(rNewSize.getY()),
+ "ShapeAttributeLayer::setSize(): Invalid size" );
+
+ maSize = rNewSize;
+ mbWidthValid = mbHeightValid = true;
+ ++mnTransformationState;
+ }
+
+ bool ShapeAttributeLayer::isPosXValid() const
+ {
+ return mbPosXValid ? true : haveChild() ? mpChild->isPosXValid() : false;
+ }
+
+ double ShapeAttributeLayer::getPosX() const
+ {
+ return calcValue< double >(
+ maPosition.getX(),
+ mbPosXValid,
+ &ShapeAttributeLayer::isPosXValid,
+ &ShapeAttributeLayer::getPosX );
+ }
+
+ void ShapeAttributeLayer::setPosX( const double& rNewX )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewX),
+ "ShapeAttributeLayer::setPosX(): Invalid position" );
+
+ maPosition.setX( rNewX );
+ mbPosXValid = true;
+ ++mnPositionState;
+ }
+
+ bool ShapeAttributeLayer::isPosYValid() const
+ {
+ return mbPosYValid ? true : haveChild() ? mpChild->isPosYValid() : false;
+ }
+
+ double ShapeAttributeLayer::getPosY() const
+ {
+ return calcValue< double >(
+ maPosition.getY(),
+ mbPosYValid,
+ &ShapeAttributeLayer::isPosYValid,
+ &ShapeAttributeLayer::getPosY );
+ }
+
+ void ShapeAttributeLayer::setPosY( const double& rNewY )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewY),
+ "ShapeAttributeLayer::setPosY(): Invalid position" );
+
+ maPosition.setY( rNewY );
+ mbPosYValid = true;
+ ++mnPositionState;
+ }
+
+ void ShapeAttributeLayer::setPosition( const ::basegfx::B2DPoint& rNewPos )
+ {
+ maPosition = rNewPos;
+ mbPosXValid = mbPosYValid = true;
+ ++mnPositionState;
+ }
+
+ bool ShapeAttributeLayer::isRotationAngleValid() const
+ {
+ return mbRotationAngleValid ? true : haveChild() ? mpChild->isRotationAngleValid() : false;
+ }
+
+ double ShapeAttributeLayer::getRotationAngle() const
+ {
+ return calcValue< double >(
+ mnRotationAngle,
+ mbRotationAngleValid,
+ &ShapeAttributeLayer::isRotationAngleValid,
+ &ShapeAttributeLayer::getRotationAngle );
+ }
+
+ void ShapeAttributeLayer::setRotationAngle( const double& rNewAngle )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle),
+ "ShapeAttributeLayer::setRotationAngle(): Invalid angle" );
+
+ mnRotationAngle = rNewAngle;
+ mbRotationAngleValid = true;
+ ++mnTransformationState;
+ }
+
+ bool ShapeAttributeLayer::isShearXAngleValid() const
+ {
+ return mbShearXAngleValid ? true : haveChild() ? mpChild->isShearXAngleValid() : false;
+ }
+
+ double ShapeAttributeLayer::getShearXAngle() const
+ {
+ return calcValue( mnShearXAngle,
+ mbShearXAngleValid,
+ &ShapeAttributeLayer::isShearXAngleValid,
+ &ShapeAttributeLayer::getShearXAngle );
+ }
+
+ void ShapeAttributeLayer::setShearXAngle( const double& rNewAngle )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle),
+ "ShapeAttributeLayer::setShearXAngle(): Invalid angle" );
+
+ mnShearXAngle = rNewAngle;
+ mbShearXAngleValid = true;
+ ++mnTransformationState;
+ }
+
+ bool ShapeAttributeLayer::isShearYAngleValid() const
+ {
+ return mbShearYAngleValid ? true : haveChild() ? mpChild->isShearYAngleValid() : false;
+ }
+
+ double ShapeAttributeLayer::getShearYAngle() const
+ {
+ return calcValue( mnShearYAngle,
+ mbShearYAngleValid,
+ &ShapeAttributeLayer::isShearYAngleValid,
+ &ShapeAttributeLayer::getShearYAngle );
+ }
+
+ void ShapeAttributeLayer::setShearYAngle( const double& rNewAngle )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle),
+ "ShapeAttributeLayer::setShearYAngle(): Invalid angle" );
+
+ mnShearYAngle = rNewAngle;
+ mbShearYAngleValid = true;
+ ++mnTransformationState;
+ }
+
+ bool ShapeAttributeLayer::isAlphaValid() const
+ {
+ return mbAlphaValid ? true : haveChild() ? mpChild->isAlphaValid() : false;
+ }
+
+ double ShapeAttributeLayer::getAlpha() const
+ {
+ return calcValue( mnAlpha,
+ mbAlphaValid,
+ &ShapeAttributeLayer::isAlphaValid,
+ &ShapeAttributeLayer::getAlpha );
+ }
+
+ void ShapeAttributeLayer::setAlpha( const double& rNewValue )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewValue),
+ "ShapeAttributeLayer::setAlpha(): Invalid alpha" );
+
+ mnAlpha = rNewValue;
+ mbAlphaValid = true;
+ ++mnAlphaState;
+ }
+
+ bool ShapeAttributeLayer::isClipValid() const
+ {
+ return mbClipValid ? true : haveChild() ? mpChild->isClipValid() : false;
+ }
+
+ ::basegfx::B2DPolyPolygon ShapeAttributeLayer::getClip() const
+ {
+ // TODO(F1): Implement polygon algebra for additive modes
+ if( mbClipValid )
+ return maClip;
+ else if( haveChild() )
+ return mpChild->getClip();
+ else
+ return ::basegfx::B2DPolyPolygon();
+ }
+
+ void ShapeAttributeLayer::setClip( const ::basegfx::B2DPolyPolygon& rNewClip )
+ {
+ maClip = rNewClip;
+ mbClipValid = true;
+ ++mnClipState;
+ }
+
+ bool ShapeAttributeLayer::isDimColorValid() const
+ {
+ return mbDimColorValid ? true : haveChild() ? mpChild->isDimColorValid() : false;
+ }
+
+ RGBColor ShapeAttributeLayer::getDimColor() const
+ {
+ return calcValue( maDimColor,
+ mbDimColorValid,
+ &ShapeAttributeLayer::isDimColorValid,
+ &ShapeAttributeLayer::getDimColor );
+ }
+
+ void ShapeAttributeLayer::setDimColor( const RGBColor& nNewColor )
+ {
+ maDimColor = nNewColor;
+ mbDimColorValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isFillColorValid() const
+ {
+ return mbFillColorValid ? true : haveChild() ? mpChild->isFillColorValid() : false;
+ }
+
+ RGBColor ShapeAttributeLayer::getFillColor() const
+ {
+ return calcValue( maFillColor,
+ mbFillColorValid,
+ &ShapeAttributeLayer::isFillColorValid,
+ &ShapeAttributeLayer::getFillColor );
+ }
+
+ void ShapeAttributeLayer::setFillColor( const RGBColor& nNewColor )
+ {
+ maFillColor = nNewColor;
+ mbFillColorValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isLineColorValid() const
+ {
+ return mbLineColorValid ? true : haveChild() ? mpChild->isLineColorValid() : false;
+ }
+
+ RGBColor ShapeAttributeLayer::getLineColor() const
+ {
+ return calcValue( maLineColor,
+ mbLineColorValid,
+ &ShapeAttributeLayer::isLineColorValid,
+ &ShapeAttributeLayer::getLineColor );
+ }
+
+ void ShapeAttributeLayer::setLineColor( const RGBColor& nNewColor )
+ {
+ maLineColor = nNewColor;
+ mbLineColorValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isFillStyleValid() const
+ {
+ return mbFillStyleValid ? true : haveChild() ? mpChild->isFillStyleValid() : false;
+ }
+
+ sal_Int16 ShapeAttributeLayer::getFillStyle() const
+ {
+ // mnAdditiveMode is ignored, cannot combine strings in
+ // any sensible way
+ if( mbFillStyleValid )
+ return sal::static_int_cast<sal_Int16>(meFillStyle);
+ else if( haveChild() )
+ return sal::static_int_cast<sal_Int16>(mpChild->getFillStyle());
+ else
+ return sal::static_int_cast<sal_Int16>(drawing::FillStyle_SOLID);
+ }
+
+ void ShapeAttributeLayer::setFillStyle( const sal_Int16& rStyle )
+ {
+ // TODO(Q1): Check range here.
+ meFillStyle = (drawing::FillStyle)rStyle;
+ mbFillStyleValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isLineStyleValid() const
+ {
+ return mbLineStyleValid ? true : haveChild() ? mpChild->isLineStyleValid() : false;
+ }
+
+ sal_Int16 ShapeAttributeLayer::getLineStyle() const
+ {
+ // mnAdditiveMode is ignored, cannot combine strings in
+ // any sensible way
+ if( mbLineStyleValid )
+ return sal::static_int_cast<sal_Int16>(meLineStyle);
+ else if( haveChild() )
+ return sal::static_int_cast<sal_Int16>(mpChild->getLineStyle());
+ else
+ return sal::static_int_cast<sal_Int16>(drawing::LineStyle_SOLID);
+ }
+
+ void ShapeAttributeLayer::setLineStyle( const sal_Int16& rStyle )
+ {
+ // TODO(Q1): Check range here.
+ meLineStyle = (drawing::LineStyle)rStyle;
+ mbLineStyleValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isVisibilityValid() const
+ {
+ return mbVisibilityValid ? true : haveChild() ? mpChild->isVisibilityValid() : false;
+ }
+
+ bool ShapeAttributeLayer::getVisibility() const
+ {
+ // mnAdditiveMode is ignored, SMIL spec requires to not combine
+ // bools in any sensible way
+ if( mbVisibilityValid )
+ return mbVisibility;
+ else if( haveChild() )
+ return mpChild->getVisibility();
+ else
+ return true; // default is always visible
+ }
+
+ void ShapeAttributeLayer::setVisibility( const bool& bVisible )
+ {
+ mbVisibility = bVisible;
+ mbVisibilityValid = true;
+ ++mnVisibilityState;
+ }
+
+ bool ShapeAttributeLayer::isCharColorValid() const
+ {
+ return mbCharColorValid ? true : haveChild() ? mpChild->isCharColorValid() : false;
+ }
+
+ RGBColor ShapeAttributeLayer::getCharColor() const
+ {
+ return calcValue( maCharColor,
+ mbCharColorValid,
+ &ShapeAttributeLayer::isCharColorValid,
+ &ShapeAttributeLayer::getCharColor );
+ }
+
+ void ShapeAttributeLayer::setCharColor( const RGBColor& nNewColor )
+ {
+ maCharColor = nNewColor;
+ mbCharColorValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isCharRotationAngleValid() const
+ {
+ return mbCharRotationAngleValid ? true : haveChild() ? mpChild->isCharRotationAngleValid() : false;
+ }
+
+ double ShapeAttributeLayer::getCharRotationAngle() const
+ {
+ return calcValue( mnCharRotationAngle,
+ mbCharRotationAngleValid,
+ &ShapeAttributeLayer::isCharRotationAngleValid,
+ &ShapeAttributeLayer::getCharRotationAngle );
+ }
+
+ void ShapeAttributeLayer::setCharRotationAngle( const double& rNewAngle )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewAngle),
+ "ShapeAttributeLayer::setCharRotationAngle(): Invalid angle" );
+
+ mnCharRotationAngle = rNewAngle;
+ mbCharRotationAngleValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isCharWeightValid() const
+ {
+ return mbCharWeightValid ? true : haveChild() ? mpChild->isCharWeightValid() : false;
+ }
+
+ double ShapeAttributeLayer::getCharWeight() const
+ {
+ // mnAdditiveMode is ignored, cannot combine strings in
+ // any sensible way
+ if( mbCharWeightValid )
+ return mnCharWeight;
+ else if( haveChild() )
+ return mpChild->getCharWeight();
+ else
+ return awt::FontWeight::NORMAL;
+ }
+
+ void ShapeAttributeLayer::setCharWeight( const double& rValue )
+ {
+ // TODO(Q1): Check range here.
+ mnCharWeight = rValue;
+ mbCharWeightValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isUnderlineModeValid() const
+ {
+ return mbUnderlineModeValid ? true : haveChild() ? mpChild->isUnderlineModeValid() : false;
+ }
+
+ sal_Int16 ShapeAttributeLayer::getUnderlineMode() const
+ {
+ // mnAdditiveMode is ignored, SMIL spec requires to not combine
+ // bools in any sensible way
+ if( mbUnderlineModeValid )
+ return mnUnderlineMode;
+ else if( haveChild() )
+ return mpChild->getUnderlineMode();
+ else
+ return awt::FontUnderline::NONE; // default is no underline
+ }
+
+ void ShapeAttributeLayer::setUnderlineMode( const sal_Int16& rUnderlineMode )
+ {
+ // TODO(Q1): Check range here.
+ mnUnderlineMode = rUnderlineMode;
+ mbUnderlineModeValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isFontFamilyValid() const
+ {
+ return mbFontFamilyValid ? true : haveChild() ? mpChild->isFontFamilyValid() : false;
+ }
+
+ ::rtl::OUString ShapeAttributeLayer::getFontFamily() const
+ {
+ // mnAdditiveMode is ignored, cannot combine strings in
+ // any sensible way
+ if( mbFontFamilyValid )
+ return maFontFamily;
+ else if( haveChild() )
+ return mpChild->getFontFamily();
+ else
+ return ::rtl::OUString();
+ }
+
+ void ShapeAttributeLayer::setFontFamily( const ::rtl::OUString& rName )
+ {
+ maFontFamily = rName;
+ mbFontFamilyValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isCharPostureValid() const
+ {
+ return mbCharPostureValid ? true : haveChild() ? mpChild->isCharPostureValid() : false;
+ }
+
+ sal_Int16 ShapeAttributeLayer::getCharPosture() const
+ {
+ // mnAdditiveMode is ignored, cannot combine strings in
+ // any sensible way
+ if( mbCharPostureValid )
+ return sal::static_int_cast<sal_Int16>(meCharPosture);
+ else if( haveChild() )
+ return sal::static_int_cast<sal_Int16>(mpChild->getCharPosture());
+ else
+ return sal::static_int_cast<sal_Int16>(awt::FontSlant_NONE);
+ }
+
+ void ShapeAttributeLayer::setCharPosture( const sal_Int16& rStyle )
+ {
+ // TODO(Q1): Check range here.
+ meCharPosture = (awt::FontSlant)rStyle;
+ mbCharPostureValid = true;
+ ++mnContentState;
+ }
+
+ bool ShapeAttributeLayer::isCharScaleValid() const
+ {
+ return mbCharScaleValid ? true : haveChild() ? mpChild->isCharScaleValid() : false;
+ }
+
+ double ShapeAttributeLayer::getCharScale() const
+ {
+ return calcValue( mnCharScale,
+ mbCharScaleValid,
+ &ShapeAttributeLayer::isCharScaleValid,
+ &ShapeAttributeLayer::getCharScale );
+ }
+
+ void ShapeAttributeLayer::setCharScale( const double& rNewHeight )
+ {
+ ENSURE_OR_THROW( ::rtl::math::isFinite(rNewHeight),
+ "ShapeAttributeLayer::setCharScale(): Invalid height" );
+
+ mnCharScale = rNewHeight;
+ mbCharScaleValid = true;
+ ++mnContentState;
+ }
+
+ State::StateId ShapeAttributeLayer::getTransformationState() const
+ {
+ return haveChild() ?
+ ::std::max( mnTransformationState,
+ mpChild->getTransformationState() ) :
+ mnTransformationState;
+ }
+
+ State::StateId ShapeAttributeLayer::getClipState() const
+ {
+ return haveChild() ?
+ ::std::max( mnClipState,
+ mpChild->getClipState() ) :
+ mnClipState;
+ }
+
+ State::StateId ShapeAttributeLayer::getAlphaState() const
+ {
+ return haveChild() ?
+ ::std::max( mnAlphaState,
+ mpChild->getAlphaState() ) :
+ mnAlphaState;
+ }
+
+ State::StateId ShapeAttributeLayer::getPositionState() const
+ {
+ return haveChild() ?
+ ::std::max( mnPositionState,
+ mpChild->getPositionState() ) :
+ mnPositionState;
+ }
+
+ State::StateId ShapeAttributeLayer::getContentState() const
+ {
+ return haveChild() ?
+ ::std::max( mnContentState,
+ mpChild->getContentState() ) :
+ mnContentState;
+ }
+
+ State::StateId ShapeAttributeLayer::getVisibilityState() const
+ {
+ return haveChild() ?
+ ::std::max( mnVisibilityState,
+ mpChild->getVisibilityState() ) :
+ mnVisibilityState;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/appletshape.cxx b/slideshow/source/engine/shapes/appletshape.cxx
new file mode 100644
index 000000000000..4b1cb5398fee
--- /dev/null
+++ b/slideshow/source/engine/shapes/appletshape.cxx
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <boost/shared_ptr.hpp>
+
+#include "appletshape.hxx"
+#include "externalshapebase.hxx"
+#include "vieweventhandler.hxx"
+#include "viewappletshape.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Represents an applet shape.
+
+ This implementation offers support for applet shapes (both
+ Java applets, and Netscape plugins). Such shapes need
+ special treatment.
+ */
+ class AppletShape : public ExternalShapeBase
+ {
+ public:
+ /** Create a shape for the given XShape for a applet object
+
+ @param xShape
+ The XShape to represent.
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param rServiceName
+ Service name to use, when creating the actual viewer
+ component
+
+ @param pPropCopyTable
+ Table of plain ASCII property names, to copy from
+ xShape to applet.
+
+ @param nNumPropEntries
+ Number of property table entries (in pPropCopyTable)
+ */
+ AppletShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ private:
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+
+ // ExternalShapeBase methods
+ //------------------------------------------------------------------
+
+ virtual bool implRender( const ::basegfx::B2DRange& rCurrBounds ) const;
+ virtual void implViewChanged( const UnoViewSharedPtr& rView );
+ virtual void implViewsChanged();
+ virtual bool implStartIntrinsicAnimation();
+ virtual bool implEndIntrinsicAnimation();
+ virtual bool implPauseIntrinsicAnimation();
+ virtual bool implIsIntrinsicAnimationPlaying() const;
+ virtual void implSetIntrinsicAnimationTime(double);
+
+ const ::rtl::OUString maServiceName;
+ const char** mpPropCopyTable;
+ const sal_Size mnNumPropEntries;
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewAppletShapeSharedPtr > ViewAppletShapeVector;
+ ViewAppletShapeVector maViewAppletShapes;
+ bool mbIsPlaying;
+ };
+
+ AppletShape::AppletShape( const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext ) :
+ ExternalShapeBase( xShape, nPrio, rContext ),
+ maServiceName( rServiceName ),
+ mpPropCopyTable( pPropCopyTable ),
+ mnNumPropEntries( nNumPropEntries ),
+ maViewAppletShapes(),
+ mbIsPlaying(false)
+ {
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::implViewChanged( const UnoViewSharedPtr& rView )
+ {
+ // determine ViewAppletShape that needs update
+ ViewAppletShapeVector::const_iterator aIter(maViewAppletShapes.begin());
+ ViewAppletShapeVector::const_iterator const aEnd (maViewAppletShapes.end());
+ while( aIter != aEnd )
+ {
+ if( (*aIter)->getViewLayer()->isOnView(rView) )
+ (*aIter)->resize(getBounds());
+
+ ++aIter;
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::implViewsChanged()
+ {
+ // resize all ViewShapes
+ ::std::for_each( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::bind(
+ &ViewAppletShape::resize,
+ _1,
+ ::boost::cref( AppletShape::getBounds())) );
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ try
+ {
+ maViewAppletShapes.push_back(
+ ViewAppletShapeSharedPtr( new ViewAppletShape( rNewLayer,
+ getXShape(),
+ maServiceName,
+ mpPropCopyTable,
+ mnNumPropEntries,
+ mxComponentContext )));
+
+ // push new size to view shape
+ maViewAppletShapes.back()->resize( getBounds() );
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ maViewAppletShapes.back()->render( getBounds() );
+ }
+ catch(uno::Exception&)
+ {
+ // ignore failed shapes - slideshow should run with
+ // the remaining content
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewAppletShapeVector::iterator aEnd( maViewAppletShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewAppletShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewAppletShape::getViewLayer, _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "AppletShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewAppletShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewAppletShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewAppletShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewAppletShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::clearAllViewLayers()
+ {
+ maViewAppletShapes.clear();
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implRender( const ::basegfx::B2DRange& rCurrBounds ) const
+ {
+ // redraw all view shapes, by calling their update() method
+ if( ::std::count_if( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::bind<bool>(
+ ::boost::mem_fn( &ViewAppletShape::render ),
+ _1,
+ ::boost::cref( rCurrBounds ) ) )
+ != static_cast<ViewAppletShapeVector::difference_type>(maViewAppletShapes.size()) )
+ {
+ // at least one of the ViewShape::update() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implStartIntrinsicAnimation()
+ {
+ ::std::for_each( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::bind( &ViewAppletShape::startApplet,
+ _1,
+ ::boost::cref( getBounds() )));
+ mbIsPlaying = true;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implEndIntrinsicAnimation()
+ {
+ ::std::for_each( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::mem_fn( &ViewAppletShape::endApplet ) );
+
+ mbIsPlaying = false;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implPauseIntrinsicAnimation()
+ {
+ // TODO(F1): any way of temporarily disabling/deactivating
+ // applets?
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implIsIntrinsicAnimationPlaying() const
+ {
+ return mbIsPlaying;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::implSetIntrinsicAnimationTime(double)
+ {
+ // No way of doing this, or?
+ }
+
+ boost::shared_ptr<Shape> createAppletShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext )
+ {
+ boost::shared_ptr< AppletShape > pAppletShape(
+ new AppletShape(xShape,
+ nPrio,
+ rServiceName,
+ pPropCopyTable,
+ nNumPropEntries,
+ rContext) );
+
+ return pAppletShape;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/appletshape.hxx b/slideshow/source/engine/shapes/appletshape.hxx
new file mode 100644
index 000000000000..e967b9b381fb
--- /dev/null
+++ b/slideshow/source/engine/shapes/appletshape.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_APPLETSHAPE_HXX
+#define INCLUDED_SLIDESHOW_APPLETSHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <boost/shared_ptr.hpp>
+
+namespace com { namespace sun { namespace star { namespace drawing
+{
+ class XShape;
+} } } }
+namespace rtl {
+ class OUString;
+}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ struct SlideShowContext;
+ class Shape;
+
+ boost::shared_ptr<Shape> createAppletShape(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext );
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_APPLETSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/backgroundshape.cxx b/slideshow/source/engine/shapes/backgroundshape.cxx
new file mode 100644
index 000000000000..7d13d9247455
--- /dev/null
+++ b/slideshow/source/engine/shapes/backgroundshape.cxx
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <rtl/logfile.hxx>
+
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+
+#include <basegfx/numeric/ftools.hxx>
+
+#include <boost/bind.hpp>
+
+#include <cmath> // for trigonometry and fabs
+#include <algorithm>
+#include <functional>
+#include <limits>
+
+#include "backgroundshape.hxx"
+#include "slideshowexceptions.hxx"
+#include "slideshowcontext.hxx"
+#include "gdimtftools.hxx"
+#include "shape.hxx"
+#include "viewbackgroundshape.hxx"
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Representation of a draw document's background shape.
+
+ This class implements the Shape interface for the
+ background shape. Since the background shape is neither
+ animatable nor attributable, those more specialized
+ derivations of the Shape interface are not implemented
+ here.
+
+ @attention this class is to be treated 'final', i.e. one
+ should not derive from it.
+ */
+ class BackgroundShape : public Shape
+ {
+ public:
+ /** Create the background shape.
+
+ This method creates a shape that handles the
+ peculiarities of the draw API regarding background
+ content.
+ */
+ BackgroundShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xDrawPage,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > getXShape() const;
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+
+ // attribute methods
+ //------------------------------------------------------------------
+
+ virtual ::basegfx::B2DRectangle getBounds() const;
+ virtual ::basegfx::B2DRectangle getDomBounds() const;
+ virtual ::basegfx::B2DRectangle getUpdateArea() const;
+ virtual bool isVisible() const;
+ virtual double getPriority() const;
+ virtual bool isBackgroundDetached() const;
+
+
+ // render methods
+ //------------------------------------------------------------------
+
+ virtual bool update() const;
+ virtual bool render() const;
+ virtual bool isContentChanged() const;
+
+ private:
+ /// The metafile actually representing the Shape
+ GDIMetaFileSharedPtr mpMtf;
+
+ // The attributes of this Shape
+ ::basegfx::B2DRectangle maBounds; // always needed for rendering
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewBackgroundShapeSharedPtr > ViewBackgroundShapeVector;
+ ViewBackgroundShapeVector maViewShapes;
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ BackgroundShape::BackgroundShape( const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Reference< drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext ) :
+ mpMtf(),
+ maBounds(),
+ maViewShapes()
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
+ uno::UNO_QUERY_THROW );
+ GDIMetaFileSharedPtr pMtf( new GDIMetaFile() );
+
+ // first try the page background (overrides
+ // masterpage background), then try masterpage
+ if( !getMetaFile( uno::Reference<lang::XComponent>(xDrawPage, uno::UNO_QUERY),
+ xDrawPage, *pMtf, MTF_LOAD_BACKGROUND_ONLY,
+ rContext.mxComponentContext ) &&
+ !getMetaFile( uno::Reference<lang::XComponent>(xMasterPage, uno::UNO_QUERY),
+ xDrawPage, *pMtf, MTF_LOAD_BACKGROUND_ONLY,
+ rContext.mxComponentContext ))
+ {
+ throw ShapeLoadFailedException();
+ }
+
+ // there is a special background shape, add it
+ // as the first one
+ // ---------------------------------------------------
+
+ sal_Int32 nDocWidth=0;
+ sal_Int32 nDocHeight=0;
+ xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Width") ) ) >>= nDocWidth;
+ xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Height") ) ) >>= nDocHeight;
+
+ mpMtf = pMtf;
+ maBounds = ::basegfx::B2DRectangle( 0,0,nDocWidth, nDocHeight );
+ }
+
+ uno::Reference< drawing::XShape > BackgroundShape::getXShape() const
+ {
+ // no real XShape representative
+ return uno::Reference< drawing::XShape >();
+ }
+
+ void BackgroundShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ ViewBackgroundShapeVector::iterator aEnd( maViewShapes.end() );
+
+ // already added?
+ if( ::std::find_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewBackgroundShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rNewLayer ) ) ) != aEnd )
+ {
+ // yes, nothing to do
+ return;
+ }
+
+ maViewShapes.push_back(
+ ViewBackgroundShapeSharedPtr(
+ new ViewBackgroundShape( rNewLayer,
+ maBounds ) ) );
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ maViewShapes.back()->render( mpMtf );
+ }
+
+ bool BackgroundShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewBackgroundShapeVector::iterator aEnd( maViewShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewBackgroundShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "BackgroundShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewBackgroundShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewBackgroundShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ bool BackgroundShape::clearAllViewLayers()
+ {
+ maViewShapes.clear();
+ return true;
+ }
+
+ ::basegfx::B2DRectangle BackgroundShape::getBounds() const
+ {
+ return maBounds;
+ }
+
+ ::basegfx::B2DRectangle BackgroundShape::getDomBounds() const
+ {
+ return maBounds;
+ }
+
+ ::basegfx::B2DRectangle BackgroundShape::getUpdateArea() const
+ {
+ // TODO(F1): Need to expand background, too, when
+ // antialiasing?
+
+ // no transformation etc. possible for background shape
+ return maBounds;
+ }
+
+ bool BackgroundShape::isVisible() const
+ {
+ return true;
+ }
+
+ double BackgroundShape::getPriority() const
+ {
+ return 0.0; // lowest prio, we're the background
+ }
+
+ bool BackgroundShape::update() const
+ {
+ return render();
+ }
+
+ bool BackgroundShape::render() const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::BackgroundShape::render()" );
+ RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::presentation::internal::BackgroundShape: 0x%X", this );
+
+ // gcc again...
+ const ::basegfx::B2DRectangle& rCurrBounds( BackgroundShape::getBounds() );
+
+ if( rCurrBounds.getRange().equalZero() )
+ {
+ // zero-sized shapes are effectively invisible,
+ // thus, we save us the rendering...
+ return true;
+ }
+
+ // redraw all view shapes, by calling their render() method
+ if( ::std::count_if( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::bind( &ViewBackgroundShape::render,
+ _1,
+ ::boost::cref( mpMtf ) ) )
+ != static_cast<ViewBackgroundShapeVector::difference_type>(maViewShapes.size()) )
+ {
+ // at least one of the ViewBackgroundShape::render() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ return true;
+ }
+
+ bool BackgroundShape::isContentChanged() const
+ {
+ return false;
+ }
+
+ bool BackgroundShape::isBackgroundDetached() const
+ {
+ return false; // we're not animatable
+ }
+
+ //////////////////////////////////////////////////////////
+
+ ShapeSharedPtr createBackgroundShape(
+ const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Reference< drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext )
+ {
+ return ShapeSharedPtr(
+ new BackgroundShape(
+ xDrawPage,
+ xMasterPage,
+ rContext ));
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/backgroundshape.hxx b/slideshow/source/engine/shapes/backgroundshape.hxx
new file mode 100644
index 000000000000..eb495b9b1aec
--- /dev/null
+++ b/slideshow/source/engine/shapes/backgroundshape.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_BACKGROUNDSHAPE_HXX
+#define INCLUDED_SLIDESHOW_BACKGROUNDSHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <boost/shared_ptr.hpp>
+
+namespace com { namespace sun { namespace star { namespace drawing
+{
+ class XDrawPage;
+} } } }
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class Shape;
+ struct SlideShowContext;
+
+ /** Representation of a draw document's background shape.
+
+ This function generates the Shape for the background
+ shape. Since the background shape is neither animatable
+ nor attributable, those more specialized derivations of
+ the Shape interface are not implemented here.
+ */
+ boost::shared_ptr<Shape> createBackgroundShape(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xDrawPage,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_BACKGROUNDSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawinglayeranimation.cxx b/slideshow/source/engine/shapes/drawinglayeranimation.cxx
new file mode 100644
index 000000000000..323f16849123
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawinglayeranimation.cxx
@@ -0,0 +1,983 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/elapsedtime.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <rtl/math.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/metaact.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/TextAnimationKind.hpp>
+#include <com/sun/star/drawing/TextAnimationDirection.hpp>
+#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/HomogenMatrix3.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+#include "activity.hxx"
+#include "wakeupevent.hxx"
+#include "eventqueue.hxx"
+#include "drawshapesubsetting.hxx"
+#include "drawshape.hxx"
+#include "shapesubset.hxx"
+#include "shapeattributelayerholder.hxx"
+#include "slideshowcontext.hxx"
+#include "tools.hxx"
+#include "gdimtftools.hxx"
+#include "eventmultiplexer.hxx"
+#include "intrinsicanimationactivity.hxx"
+#include "intrinsicanimationeventhandler.hxx"
+
+#include <boost/weak_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+#include <vector>
+
+using namespace com::sun::star;
+using namespace ::slideshow::internal;
+
+namespace {
+
+class ScrollTextAnimNode
+{
+ sal_uInt32 mnDuration; // single duration
+ sal_uInt32 mnRepeat; // 0 -> endless
+ double mfStart;
+ double mfStop;
+ sal_uInt32 mnFrequency; // in ms
+ // forth and back change at mnRepeat%2:
+ bool mbAlternate;
+
+public:
+ ScrollTextAnimNode(
+ sal_uInt32 nDuration, sal_uInt32 nRepeat, double fStart, double fStop,
+ sal_uInt32 nFrequency, bool bAlternate)
+ : mnDuration(nDuration),
+ mnRepeat(nRepeat),
+ mfStart(fStart),
+ mfStop(fStop),
+ mnFrequency(nFrequency),
+ mbAlternate(bAlternate)
+ {}
+
+ sal_uInt32 GetDuration() const { return mnDuration; }
+ sal_uInt32 GetRepeat() const { return mnRepeat; }
+ sal_uInt32 GetFullTime() const { return mnDuration * mnRepeat; }
+ double GetStart() const { return mfStart; }
+ double GetStop() const { return mfStop; }
+ sal_uInt32 GetFrequency() const { return mnFrequency; }
+ bool DoAlternate() const { return mbAlternate; }
+
+ double GetStateAtRelativeTime(sal_uInt32 nRelativeTime) const;
+};
+
+double ScrollTextAnimNode::GetStateAtRelativeTime(
+ sal_uInt32 nRelativeTime) const
+{
+ // Avoid division by zero.
+ if( mnDuration == 0 )
+ return mfStop;
+
+ if(mnRepeat)
+ {
+ // ending
+ const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
+ sal_uInt32 nFrameTime(nRelativeTime - (nRepeatCount * mnDuration));
+
+ if(DoAlternate() && (nRepeatCount + 1L) % 2L)
+ nFrameTime = mnDuration - nFrameTime;
+
+ return mfStart + ((mfStop - mfStart) *
+ (double(nFrameTime) / mnDuration));
+ }
+ else
+ {
+ // endless
+ sal_uInt32 nFrameTime(nRelativeTime % mnDuration);
+
+ if(DoAlternate())
+ {
+ const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
+
+ if((nRepeatCount + 1L) % 2L)
+ nFrameTime = mnDuration - nFrameTime;
+ }
+
+ return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration));
+ }
+}
+
+class ActivityImpl : public Activity,
+ public boost::enable_shared_from_this<ActivityImpl>,
+ private boost::noncopyable
+{
+public:
+ virtual ~ActivityImpl();
+
+ ActivityImpl(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
+ boost::shared_ptr<DrawShape> const& pDrawShape );
+
+ bool enableAnimations();
+
+ // Disposable:
+ virtual void dispose();
+ // Activity:
+ virtual double calcTimeLag() const;
+ virtual bool perform();
+ virtual bool isActive() const;
+ virtual void dequeued();
+ virtual void end();
+
+private:
+ void updateShapeAttributes( double fTime,
+ basegfx::B2DRectangle const& parentBounds );
+
+ // Access to VisibleWhenSTarted flags
+ sal_Bool IsVisibleWhenStarted() const { return mbVisibleWhenStarted; }
+ sal_Bool IsVisibleWhenStopped() const { return mbVisibleWhenStopped; }
+
+ // scroll horizontal? if sal_False, scroll is vertical.
+ bool ScrollHorizontal() const {
+ return (drawing::TextAnimationDirection_LEFT == meDirection ||
+ drawing::TextAnimationDirection_RIGHT == meDirection);
+ }
+
+ // Access to StepWidth in logical units
+ sal_uInt32 GetStepWidthLogic() const;
+
+ // is the animation direction opposite?
+ bool DoScrollForward() const {
+ return (drawing::TextAnimationDirection_RIGHT == meDirection ||
+ drawing::TextAnimationDirection_DOWN == meDirection);
+ }
+
+ // do alternate text directions?
+ bool DoAlternate() const { return mbAlternate; }
+
+ // do scroll in?
+ bool DoScrollIn() const { return mbScrollIn; }
+
+ // Scroll helper methods
+ void ImpForceScrollTextAnimNodes();
+ ScrollTextAnimNode* ImpGetScrollTextAnimNode(
+ sal_uInt32 nTime, sal_uInt32& rRelativeTime );
+ sal_uInt32 ImpRegisterAgainScrollTextMixerState(
+ sal_uInt32 nTime);
+
+ // calculate the MixerState value for given time
+ double GetMixerState(sal_uInt32 nTime);
+
+ ////////////////////////////////////////////////////////////////////
+
+ SlideShowContext maContext;
+ boost::shared_ptr<WakeupEvent> mpWakeupEvent;
+ boost::weak_ptr<DrawShape> mpParentDrawShape;
+ DrawShapeSharedPtr mpDrawShape;
+ ShapeAttributeLayerHolder maShapeAttrLayer;
+ GDIMetaFileSharedPtr mpMetaFile;
+ IntrinsicAnimationEventHandlerSharedPtr mpListener;
+ canvas::tools::ElapsedTime maTimer;
+ double mfRotationAngle;
+ bool mbIsShapeAnimated;
+ bool mbIsDisposed;
+ bool mbIsActive;
+ drawing::TextAnimationKind meAnimKind;
+
+ // The blink frequency in ms
+ sal_uInt32 mnFrequency;
+
+ // The repeat count, init to 0L which means endless
+ sal_uInt32 mnRepeat;
+
+ // Flag to decide if text will be shown when animation has ended
+ bool mbVisibleWhenStopped;
+ bool mbVisibleWhenStarted;
+
+ // Flag decides if TextScroll alternates. Default is sal_False.
+ bool mbAlternate;
+
+ // Flag to remember if this is a simple scrollin text
+ bool mbScrollIn;
+
+ // start time for this animation
+ sal_uInt32 mnStartTime;
+
+ // The AnimationDirection
+ drawing::TextAnimationDirection meDirection;
+
+ // Get width per Step. Negative means pixel, positive logical units
+ sal_Int32 mnStepWidth;
+
+ // The single anim steps
+ std::vector< ScrollTextAnimNode > maVector;
+
+ // the scroll rectangle
+ Rectangle maScrollRectangleLogic;
+
+ // the paint rectangle
+ Rectangle maPaintRectangleLogic;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler,
+ private boost::noncopyable
+{
+public:
+ explicit IntrinsicAnimationListener( ActivityImpl& rActivity ) :
+ mrActivity( rActivity )
+ {}
+
+private:
+
+ virtual bool enableAnimations() { return mrActivity.enableAnimations(); }
+ virtual bool disableAnimations() { mrActivity.end(); return true; }
+
+ ActivityImpl& mrActivity;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+double ActivityImpl::GetMixerState( sal_uInt32 nTime )
+{
+ if( meAnimKind == drawing::TextAnimationKind_BLINK )
+ {
+ // from AInfoBlinkText:
+ double fRetval(0.0);
+ sal_Bool bDone(sal_False);
+ const sal_uInt32 nLoopTime(2 * mnFrequency);
+
+ if(mnRepeat)
+ {
+ const sal_uInt32 nEndTime(mnRepeat * nLoopTime);
+
+ if(nTime >= nEndTime)
+ {
+ if(mbVisibleWhenStopped)
+ fRetval = 0.0;
+ else
+ fRetval = 1.0;
+
+ bDone = sal_True;
+ }
+ }
+
+ if(!bDone)
+ {
+ sal_uInt32 nTimeInLoop(nTime % nLoopTime);
+ fRetval = double(nTimeInLoop) / nLoopTime;
+ }
+
+ return fRetval;
+ }
+ else
+ {
+ // from AInfoScrollText:
+ double fRetval(0.0);
+ ImpForceScrollTextAnimNodes();
+
+ if(!maVector.empty())
+ {
+ sal_uInt32 nRelativeTime;
+ ScrollTextAnimNode* pNode =
+ ImpGetScrollTextAnimNode(nTime, nRelativeTime);
+
+ if(pNode)
+ {
+ // use node
+ fRetval = pNode->GetStateAtRelativeTime(nRelativeTime);
+ }
+ else
+ {
+ // end of animation, take last entry's end
+ fRetval = maVector[maVector.size() - 1L].GetStop();
+ }
+ }
+
+ return fRetval;
+ }
+}
+
+// Access to StepWidth in logical units
+sal_uInt32 ActivityImpl::GetStepWidthLogic() const
+{
+ // #i69847# Assuming higher DPI
+ sal_uInt32 const PIXEL_TO_LOGIC = 30;
+
+ sal_uInt32 nRetval(0L);
+
+ if(mnStepWidth < 0L)
+ {
+ // is in pixels, convert to logical units
+ nRetval = (-mnStepWidth * PIXEL_TO_LOGIC);
+ }
+ else if(mnStepWidth > 0L)
+ {
+ // is in logical units
+ nRetval = mnStepWidth;
+ }
+
+ if(0L == nRetval)
+ {
+ // step 1 pixel, canned value
+
+ // with very high DPIs like in PDF export, this can
+ // still get zero. for that cases, set a default, too (taken
+ // from ainfoscrolltext.cxx)
+ nRetval = 100L;
+ }
+
+ return nRetval;
+}
+
+void ActivityImpl::ImpForceScrollTextAnimNodes()
+{
+ if(maVector.empty())
+ {
+ // prepare values
+ sal_uInt32 nLoopTime;
+ double fZeroLogic, fOneLogic, fInitLogic, fDistanceLogic;
+ double fZeroLogicAlternate = 0.0, fOneLogicAlternate = 0.0;
+ double fZeroRelative, fOneRelative, fInitRelative;
+
+ if(ScrollHorizontal())
+ {
+ if(DoAlternate())
+ {
+ if(maPaintRectangleLogic.GetWidth() >
+ maScrollRectangleLogic.GetWidth())
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
+ fOneLogicAlternate = maScrollRectangleLogic.Left();
+ }
+ else
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Left();
+ fOneLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
+ }
+ }
+
+ fZeroLogic = maScrollRectangleLogic.Left() - maPaintRectangleLogic.GetWidth();
+ fOneLogic = maScrollRectangleLogic.Right();
+ fInitLogic = maPaintRectangleLogic.Left();
+ }
+ else
+ {
+ if(DoAlternate())
+ {
+ if(maPaintRectangleLogic.GetHeight() > maScrollRectangleLogic.GetHeight())
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
+ fOneLogicAlternate = maScrollRectangleLogic.Top();
+ }
+ else
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Top();
+ fOneLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
+ }
+ }
+
+ fZeroLogic = maScrollRectangleLogic.Top() - maPaintRectangleLogic.GetHeight();
+ fOneLogic = maScrollRectangleLogic.Bottom();
+ fInitLogic = maPaintRectangleLogic.Top();
+ }
+
+ fDistanceLogic = fOneLogic - fZeroLogic;
+ fInitRelative = (fInitLogic - fZeroLogic) / fDistanceLogic;
+
+ if(DoAlternate())
+ {
+ fZeroRelative =
+ (fZeroLogicAlternate - fZeroLogic) / fDistanceLogic;
+ fOneRelative =
+ (fOneLogicAlternate - fZeroLogic) / fDistanceLogic;
+ }
+ else
+ {
+ fZeroRelative = 0.0;
+ fOneRelative = 1.0;
+ }
+
+ if(mnStartTime)
+ {
+ // Start time loop
+ ScrollTextAnimNode aStartNode(
+ mnStartTime, 1L, 0.0, 0.0, mnStartTime, false);
+ maVector.push_back(aStartNode);
+ }
+
+ if(IsVisibleWhenStarted())
+ {
+ double fRelativeStartValue, fRelativeEndValue,fRelativeDistance;
+
+ if(DoScrollForward())
+ {
+ fRelativeStartValue = fInitRelative;
+ fRelativeEndValue = fOneRelative;
+ fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
+ }
+ else
+ {
+ fRelativeStartValue = fInitRelative;
+ fRelativeEndValue = fZeroRelative;
+ fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
+ }
+
+ const double fNumberSteps =
+ (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
+ nLoopTime = FRound(fNumberSteps * mnFrequency);
+
+ // init loop
+ ScrollTextAnimNode aInitNode(
+ nLoopTime, 1L,
+ fRelativeStartValue, fRelativeEndValue,
+ mnFrequency, false);
+ maVector.push_back(aInitNode);
+ }
+
+ // prepare main loop values
+ {
+ double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
+
+ if(DoScrollForward())
+ {
+ fRelativeStartValue = fZeroRelative;
+ fRelativeEndValue = fOneRelative;
+ fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
+ }
+ else
+ {
+ fRelativeStartValue = fOneRelative;
+ fRelativeEndValue = fZeroRelative;
+ fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
+ }
+
+ const double fNumberSteps =
+ (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
+ nLoopTime = FRound(fNumberSteps * mnFrequency);
+
+ if(0L == mnRepeat)
+ {
+ if(!DoScrollIn())
+ {
+ // endless main loop
+ ScrollTextAnimNode aMainNode(
+ nLoopTime, 0L,
+ fRelativeStartValue, fRelativeEndValue,
+ mnFrequency, DoAlternate());
+ maVector.push_back(aMainNode);
+ }
+ }
+ else
+ {
+ sal_uInt32 nNumRepeat(mnRepeat);
+
+ if(DoAlternate() && (nNumRepeat + 1L) % 2L)
+ nNumRepeat += 1L;
+
+ // ending main loop
+ ScrollTextAnimNode aMainNode(
+ nLoopTime, nNumRepeat,
+ fRelativeStartValue, fRelativeEndValue,
+ mnFrequency, DoAlternate());
+ maVector.push_back(aMainNode);
+ }
+ }
+
+ if(IsVisibleWhenStopped())
+ {
+ double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
+
+ if(DoScrollForward())
+ {
+ fRelativeStartValue = fZeroRelative;
+ fRelativeEndValue = fInitRelative;
+ fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
+ }
+ else
+ {
+ fRelativeStartValue = fOneRelative;
+ fRelativeEndValue = fInitRelative;
+ fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
+ }
+
+ const double fNumberSteps =
+ (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
+ nLoopTime = FRound(fNumberSteps * mnFrequency);
+
+ // exit loop
+ ScrollTextAnimNode aExitNode(
+ nLoopTime, 1L,
+ fRelativeStartValue, fRelativeEndValue, mnFrequency, false);
+ maVector.push_back(aExitNode);
+ }
+ }
+}
+
+ScrollTextAnimNode* ActivityImpl::ImpGetScrollTextAnimNode(
+ sal_uInt32 nTime, sal_uInt32& rRelativeTime )
+{
+ ScrollTextAnimNode* pRetval = 0L;
+ ImpForceScrollTextAnimNodes();
+
+ if(!maVector.empty())
+ {
+ rRelativeTime = nTime;
+
+ for(sal_uInt32 a(0L); !pRetval && a < maVector.size(); a++)
+ {
+ ScrollTextAnimNode & rNode = maVector[a];
+ if(!rNode.GetRepeat())
+ {
+ // endless loop, use it
+ pRetval = &rNode;
+ }
+ else if(rNode.GetFullTime() > rRelativeTime)
+ {
+ // ending node
+ pRetval = &rNode;
+ }
+ else
+ {
+ // look at next
+ rRelativeTime -= rNode.GetFullTime();
+ }
+ }
+ }
+
+ return pRetval;
+}
+
+sal_uInt32 ActivityImpl::ImpRegisterAgainScrollTextMixerState(sal_uInt32 nTime)
+{
+ sal_uInt32 nRetval(0L);
+ ImpForceScrollTextAnimNodes();
+
+ if(maVector.size())
+ {
+ sal_uInt32 nRelativeTime;
+ ScrollTextAnimNode* pNode = ImpGetScrollTextAnimNode(nTime, nRelativeTime);
+
+ if(pNode)
+ {
+ // take register time
+ nRetval = pNode->GetFrequency();
+ }
+ }
+ else
+ {
+ // #i38135# not initialized, return default
+ nRetval = mnFrequency;
+ }
+
+ return nRetval;
+}
+
+void ActivityImpl::updateShapeAttributes(
+ double fTime, basegfx::B2DRectangle const& parentBounds )
+{
+ OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
+ if( meAnimKind == drawing::TextAnimationKind_NONE )
+ return;
+
+ double const fMixerState = GetMixerState(
+ static_cast<sal_uInt32>(fTime * 1000.0) );
+
+ if( meAnimKind == drawing::TextAnimationKind_BLINK )
+ {
+ // show/hide text:
+ maShapeAttrLayer.get()->setVisibility( fMixerState < 0.5 );
+ }
+ else if(mpMetaFile) // scroll mode:
+ {
+ //
+ // keep care: the below code is highly sensible to changes...
+ //
+
+ // rectangle of the pure text:
+ double const fPaintWidth = maPaintRectangleLogic.GetWidth();
+ double const fPaintHeight = maPaintRectangleLogic.GetHeight();
+ // rectangle where the scrolling takes place (-> clipping):
+ double const fScrollWidth = maScrollRectangleLogic.GetWidth();
+ double const fScrollHeight = maScrollRectangleLogic.GetHeight();
+
+ basegfx::B2DPoint pos, clipPos;
+
+ if(ScrollHorizontal())
+ {
+ double const fOneEquiv( fScrollWidth );
+ double const fZeroEquiv( -fPaintWidth );
+
+ pos.setX( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
+
+ clipPos.setX( -pos.getX() );
+ clipPos.setY( -pos.getY() );
+
+ // #i69844# Compensation for text-wider-than-shape case
+ if( fPaintWidth > fScrollWidth )
+ pos.setX( pos.getX() + (fPaintWidth-fScrollWidth) / 2.0 );
+ }
+ else
+ {
+ // scroll vertical:
+ double const fOneEquiv( fScrollHeight );
+ double const fZeroEquiv( -fPaintHeight );
+
+ pos.setY( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
+
+ clipPos.setX( -pos.getX() );
+ clipPos.setY( -pos.getY() );
+
+ // #i69844# Compensation for text-higher-than-shape case
+ if( fPaintHeight > fScrollHeight )
+ pos.setY( pos.getY() + (fPaintHeight-fScrollHeight) / 2.0 );
+ }
+
+ basegfx::B2DPolygon clipPoly(
+ basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRectangle( clipPos.getX(),
+ clipPos.getY(),
+ clipPos.getX() + fScrollWidth,
+ clipPos.getY() + fScrollHeight ) ) );
+
+ if( !::basegfx::fTools::equalZero( mfRotationAngle ))
+ {
+ maShapeAttrLayer.get()->setRotationAngle( mfRotationAngle );
+ double const fRotate = (mfRotationAngle * M_PI / 180.0);
+ basegfx::B2DHomMatrix aTransform;
+ // position:
+ aTransform.rotate( fRotate );
+ pos *= aTransform;
+ }
+
+ pos += parentBounds.getCenter();
+ maShapeAttrLayer.get()->setPosition( pos );
+ maShapeAttrLayer.get()->setClip( basegfx::B2DPolyPolygon(clipPoly) );
+ }
+}
+
+bool ActivityImpl::perform()
+{
+ if( !isActive() )
+ return false;
+
+ ENSURE_OR_RETURN_FALSE(
+ mpDrawShape,
+ "ActivityImpl::perform(): still active, but NULL draw shape" );
+
+ DrawShapeSharedPtr const pParentDrawShape( mpParentDrawShape );
+ if( !pParentDrawShape )
+ return false; // parent has vanished
+
+ if( pParentDrawShape->isVisible() )
+ {
+ if( !mbIsShapeAnimated )
+ {
+ mpDrawShape->setVisibility(true); // shape may be initially hidden
+ maContext.mpSubsettableShapeManager->enterAnimationMode( mpDrawShape );
+ maTimer.reset();
+ mbIsShapeAnimated = true;
+ }
+ // update attributes related to current time:
+ basegfx::B2DRectangle const parentBounds(
+ pParentDrawShape->getBounds() );
+
+ const double nCurrTime( maTimer.getElapsedTime() );
+ updateShapeAttributes( nCurrTime, parentBounds );
+
+ const sal_uInt32 nFrequency(
+ ImpRegisterAgainScrollTextMixerState(
+ static_cast<sal_uInt32>(nCurrTime * 1000.0)) );
+
+ if(nFrequency)
+ {
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout(
+ std::max(0.1,nFrequency/1000.0) );
+ maContext.mrEventQueue.addEvent( mpWakeupEvent );
+
+ if( mpDrawShape->isContentChanged() )
+ maContext.mpSubsettableShapeManager->notifyShapeUpdate( mpDrawShape );
+ }
+ // else: finished, not need to wake up again.
+ }
+ else
+ {
+ // busy-wait, until parent shape gets visible
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout( 2.0 );
+ }
+
+ // don't reinsert, WakeupEvent will perform that after the given timeout:
+ return false;
+}
+
+ActivityImpl::ActivityImpl(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
+ boost::shared_ptr<DrawShape> const& pParentDrawShape )
+ : maContext(rContext),
+ mpWakeupEvent(pWakeupEvent),
+ mpParentDrawShape(pParentDrawShape),
+ mpListener( new IntrinsicAnimationListener(*this) ),
+ maTimer(rContext.mrEventQueue.getTimer()),
+ mbIsShapeAnimated(false),
+ mbIsDisposed(false),
+ mbIsActive(true),
+ meAnimKind(drawing::TextAnimationKind_NONE),
+ mnStartTime(0L)
+{
+ // get doctreenode:
+ sal_Int32 const nNodes = pParentDrawShape->getNumberOfTreeNodes(
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH );
+
+ DocTreeNode scrollTextNode(
+ pParentDrawShape->getTreeNode(
+ 0, DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ));
+ // xxx todo: remove this hack
+ if( nNodes > 1 )
+ scrollTextNode.setEndIndex(
+ pParentDrawShape->getTreeNode(
+ nNodes - 1,
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ).getEndIndex());
+
+ // TODO(Q3): Doing this manually, instead of using
+ // ShapeSubset. This is because of lifetime issues (ShapeSubset
+ // generates circular references to parent shape)
+ mpDrawShape = boost::dynamic_pointer_cast<DrawShape>(
+ maContext.mpSubsettableShapeManager->getSubsetShape(
+ pParentDrawShape,
+ scrollTextNode ));
+
+ mpMetaFile = mpDrawShape->forceScrollTextMetaFile();
+
+ // make scroll text invisible for slide transition bitmaps
+ mpDrawShape->setVisibility(false);
+
+ basegfx::B2DRectangle aScrollRect, aPaintRect;
+ ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
+ aPaintRect,
+ mpMetaFile ),
+ "ActivityImpl::ActivityImpl(): Could not extract "
+ "scroll anim rectangles from mtf" );
+
+ maScrollRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
+ aScrollRect );
+ maPaintRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
+ aPaintRect );
+
+ maShapeAttrLayer.createAttributeLayer(mpDrawShape);
+
+ uno::Reference<drawing::XShape> const xShape( mpDrawShape->getXShape() );
+ uno::Reference<beans::XPropertySet> const xProps( xShape, uno::UNO_QUERY_THROW );
+
+ getPropertyValue( meAnimKind, xProps, OUSTR("TextAnimationKind") );
+ OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
+ mbAlternate = (meAnimKind == drawing::TextAnimationKind_ALTERNATE);
+ mbScrollIn = (meAnimKind == drawing::TextAnimationKind_SLIDE);
+
+ // adopted from in AInfoBlinkText::ImplInit():
+ sal_Int16 nRepeat(0);
+ getPropertyValue( nRepeat, xProps, OUSTR("TextAnimationCount") );
+ mnRepeat = nRepeat;
+
+ if(mbAlternate)
+ {
+ // force visible when started for scroll-forth-and-back, because
+ // slide has been coming in with visible text in the middle:
+ mbVisibleWhenStarted = true;
+ }
+ else
+ {
+ getPropertyValue( mbVisibleWhenStarted, xProps,
+ OUSTR("TextAnimationStartInside") );
+ }
+
+ // set visible when stopped
+ getPropertyValue( mbVisibleWhenStopped, xProps,
+ OUSTR("TextAnimatiogonStopInside") );
+ // rotation:
+ getPropertyValue( mfRotationAngle, xProps,
+ OUSTR("RotateAngle") );
+ mfRotationAngle /= -100.0; // (switching direction)
+
+ // set frequency
+ sal_Int16 nDelay(0);
+ getPropertyValue( nDelay, xProps, OUSTR("TextAnimationDelay") );
+ // set delay if not automatic
+ mnFrequency = (nDelay ? nDelay :
+ // default:
+ meAnimKind == drawing::TextAnimationKind_BLINK
+ ? 250L : 50L );
+
+ // adopted from in AInfoScrollText::ImplInit():
+
+ // If it is a simple m_bScrollIn, reset some parameters
+ if( DoScrollIn() )
+ {
+ // most parameters are set correctly from the dialog logic, but
+ // eg VisisbleWhenStopped is grayed out and needs to be corrected here.
+ mbVisibleWhenStopped = true;
+ mbVisibleWhenStarted = false;
+ mnRepeat = 0L;
+ }
+
+ // Get animation direction
+ getPropertyValue( meDirection, xProps, OUSTR("TextAnimationDirection") );
+
+ // Get step width. Negative means pixel, positive logical units
+ getPropertyValue( mnStepWidth, xProps, OUSTR("TextAnimationAmount") );
+
+ maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
+ mpListener );
+}
+
+bool ActivityImpl::enableAnimations()
+{
+ mbIsActive = true;
+ return maContext.mrActivitiesQueue.addActivity(
+ shared_from_this() );
+}
+
+ActivityImpl::~ActivityImpl()
+{
+}
+
+void ActivityImpl::dispose()
+{
+ if( !mbIsDisposed )
+ {
+ end();
+
+ // only remove subset here, since end() is called on slide end
+ // (and we must not spoil the slide preview bitmap with scroll
+ // text)
+ maShapeAttrLayer.reset();
+ if( mpDrawShape )
+ {
+ // TODO(Q3): Doing this manually, instead of using
+ // ShapeSubset. This is because of lifetime issues
+ // (ShapeSubset generates circular references to parent
+ // shape)
+ DrawShapeSharedPtr pParent( mpParentDrawShape.lock() );
+ if( pParent )
+ maContext.mpSubsettableShapeManager->revokeSubset(
+ pParent,
+ mpDrawShape );
+ }
+
+ mpMetaFile.reset();
+ mpDrawShape.reset();
+ mpParentDrawShape.reset();
+ mpWakeupEvent.reset();
+ maContext.dispose();
+ mbIsDisposed = true;
+
+ maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
+ mpListener );
+ }
+}
+
+double ActivityImpl::calcTimeLag() const
+{
+ return 0.0;
+}
+
+bool ActivityImpl::isActive() const
+{
+ return mbIsActive;
+}
+
+void ActivityImpl::dequeued()
+{
+ // not used here
+}
+
+void ActivityImpl::end()
+{
+ // not used here
+ mbIsActive = false;
+
+ if( mbIsShapeAnimated )
+ {
+ maContext.mpSubsettableShapeManager->leaveAnimationMode( mpDrawShape );
+ mbIsShapeAnimated = false;
+ }
+}
+
+} // anon namespace
+
+namespace slideshow {
+namespace internal {
+
+boost::shared_ptr<Activity> createDrawingLayerAnimActivity(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<DrawShape> const& pDrawShape )
+{
+ boost::shared_ptr<Activity> pActivity;
+
+ try
+ {
+ boost::shared_ptr<WakeupEvent> const pWakeupEvent(
+ new WakeupEvent( rContext.mrEventQueue.getTimer(),
+ rContext.mrActivitiesQueue ) );
+ pActivity.reset( new ActivityImpl( rContext, pWakeupEvent, pDrawShape ) );
+ pWakeupEvent->setActivity( pActivity );
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ // translate any error into empty factory product.
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+
+ return pActivity;
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawinglayeranimation.hxx b/slideshow/source/engine/shapes/drawinglayeranimation.hxx
new file mode 100644
index 000000000000..45d9afe91f03
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawinglayeranimation.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_DRAWINGLAYERANIMATION_HXX
+#define INCLUDED_DRAWINGLAYERANIMATION_HXX
+
+#include <sal/config.h>
+#include <boost/shared_ptr.hpp>
+
+namespace slideshow {
+namespace internal {
+
+class Activity;
+struct SlideShowContext;
+class DrawShape;
+
+boost::shared_ptr<Activity> createDrawingLayerAnimActivity(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<DrawShape> const& pDrawShape );
+
+} // namespace internal
+} // namespace presentation
+
+#endif // ! defined INCLUDED_DRAWINGLAYERANIMATION_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshape.cxx b/slideshow/source/engine/shapes/drawshape.cxx
new file mode 100644
index 000000000000..e2492a4ddd3a
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshape.cxx
@@ -0,0 +1,1481 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <rtl/logfile.hxx>
+#include <osl/diagnose.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/wrkwin.hxx>
+
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/range/rangeexpander.hxx>
+
+#include <rtl/math.hxx>
+
+#include <com/sun/star/drawing/TextAnimationKind.hpp>
+
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <tools/stream.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+#include <comphelper/scopeguard.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <cmath> // for trigonometry and fabs
+#include <algorithm>
+#include <functional>
+#include <limits>
+
+#include "drawshapesubsetting.hxx"
+#include "drawshape.hxx"
+#include "eventqueue.hxx"
+#include "wakeupevent.hxx"
+#include "subsettableshapemanager.hxx"
+#include "intrinsicanimationactivity.hxx"
+#include "slideshowexceptions.hxx"
+#include "tools.hxx"
+#include "gdimtftools.hxx"
+#include "drawinglayeranimation.hxx"
+
+#include <boost/bind.hpp>
+#include <math.h>
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
+ //metafiles are resolution dependent when bitmaps are contained with is the case for 3D scenes for example
+ //in addition a chart has resolution dependent content as it might skip points that are not visible for a given resolution (this is done for performance reasons)
+ bool local_getMetafileForChart( const uno::Reference< lang::XComponent >& xSource,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& rMtf )
+ {
+ //get the chart model
+ uno::Reference< beans::XPropertySet > xPropSet( xSource, uno::UNO_QUERY );
+ uno::Reference< frame::XModel > xChartModel;
+ getPropertyValue( xChartModel, xPropSet, OUSTR("Model"));
+ uno::Reference< lang::XMultiServiceFactory > xFact( xChartModel, uno::UNO_QUERY );
+ OSL_ENSURE( xFact.is(), "Chart cannot be painted pretty!\n" );
+ if(!xFact.is())
+ return false;
+
+ //get the chart view
+ uno::Reference< datatransfer::XTransferable > xChartViewTransferable(
+ xFact->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.ChartView" ) ) ), uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySet > xChartViewProp( xChartViewTransferable, uno::UNO_QUERY );
+ OSL_ENSURE( xChartViewProp.is(), "Chart cannot be painted pretty!\n" );
+ if( !xChartViewProp.is() )
+ return false;
+
+ //estimate zoom and resolution (this is only a workaround, correct would be to know and use the exact zoom and resoltion during slideshow display)
+ sal_Int32 nScaleXNumerator = 100;//zoom factor -> exact values are important for the quality of the created bitmap especially for 3D charts
+ sal_Int32 nScaleYNumerator = 100;
+ sal_Int32 nScaleXDenominator = 100;
+ sal_Int32 nScaleYDenominator = 100;
+ awt::Size aPixelPerChart( 1000, 1000 );//when data points happen to be on the same pixel as their predecessor no shape is created to safe performance
+
+ Window* pActiveTopWindow( Application::GetActiveTopWindow() );
+ WorkWindow* pWorkWindow( dynamic_cast<WorkWindow*>(pActiveTopWindow));
+ if( pWorkWindow && pWorkWindow->IsPresentationMode() )
+ {
+ Size aPixScreenSize( pActiveTopWindow->GetOutputSizePixel() );
+ aPixelPerChart = awt::Size( aPixScreenSize.getWidth(), aPixScreenSize.getHeight() );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
+
+ uno::Reference< beans::XPropertySet > xPageProp( xContainingPage, uno::UNO_QUERY );
+ sal_Int32 nLogicPageWidth=1;
+ sal_Int32 nLogicPageHeight=1;
+ if( getPropertyValue( nLogicPageWidth, xPageProp, OUSTR("Width")) &&
+ getPropertyValue( nLogicPageHeight, xPageProp, OUSTR("Height")) )
+ {
+ Size aLogicScreenSize( pActiveTopWindow->PixelToLogic( aPixScreenSize, MAP_100TH_MM ) );
+ nScaleXNumerator = aLogicScreenSize.getWidth();
+ nScaleYNumerator = aLogicScreenSize.getHeight();
+ nScaleXDenominator = nLogicPageWidth;
+ nScaleYDenominator = nLogicPageHeight;
+ }
+ }
+ else
+ {
+ long nMaxPixWidth = 0;
+ long nMaxPixHeight = 0;
+ unsigned int nScreenCount( Application::GetScreenCount() );
+ for( unsigned int nScreen=0; nScreen<nScreenCount; nScreen++ )
+ {
+ Rectangle aCurScreenRect( Application::GetScreenPosSizePixel( nScreen ) );
+ if( aCurScreenRect.GetWidth() > nMaxPixWidth )
+ nMaxPixWidth = aCurScreenRect.GetWidth();
+ if( aCurScreenRect.GetHeight() > nMaxPixHeight )
+ nMaxPixHeight = aCurScreenRect.GetHeight();
+ }
+ if(nMaxPixWidth>1 && nMaxPixHeight>1)
+ aPixelPerChart = awt::Size( nMaxPixWidth, nMaxPixHeight );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
+ }
+
+ try
+ {
+ uno::Sequence< beans::PropertyValue > aZoomFactors(4);
+ aZoomFactors[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXNumerator") );
+ aZoomFactors[0].Value = uno::makeAny( nScaleXNumerator );
+ aZoomFactors[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXDenominator") );
+ aZoomFactors[1].Value = uno::makeAny( nScaleXDenominator );
+ aZoomFactors[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYNumerator") );
+ aZoomFactors[2].Value = uno::makeAny( nScaleYNumerator );
+ aZoomFactors[3].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYDenominator") );
+ aZoomFactors[3].Value = uno::makeAny( nScaleYDenominator );
+
+ xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZoomFactors") ), uno::makeAny( aZoomFactors ));
+ xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Resolution") ), uno::makeAny( aPixelPerChart ));
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+
+ //get a metafile from the prepared chart view
+ datatransfer::DataFlavor aDataFlavor(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"") ),
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GDIMetaFile" ) ),
+ ::getCppuType( (const uno::Sequence< sal_Int8 >*) 0 ) );
+ uno::Any aData( xChartViewTransferable->getTransferData( aDataFlavor ) );
+ uno::Sequence< sal_Int8 > aSeq;
+ if( aData >>= aSeq )
+ {
+ ::std::auto_ptr< SvMemoryStream > pSrcStm( new SvMemoryStream( (char*) aSeq.getConstArray(), aSeq.getLength(), STREAM_WRITE | STREAM_TRUNC ) );
+ *(pSrcStm.get() ) >> rMtf;
+ return true;
+ }
+ return false;
+ }
+
+ //same as getMetafile with an exception for charts
+ //for charts a metafile with a higher resolution is created, because charts have resolution dependent content
+ bool local_getMetaFile_WithSpecialChartHandling( const uno::Reference< lang::XComponent >& xSource,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& rMtf,
+ int mtfLoadFlags,
+ const uno::Reference< uno::XComponentContext >& rxContext )
+ {
+ uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
+ rtl::OUString sCLSID;
+ getPropertyValue( sCLSID, xProp, OUSTR("CLSID"));
+ if( sCLSID.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("12DCAE26-281F-416F-a234-c3086127382e")) && local_getMetafileForChart( xSource, xContainingPage, rMtf ) )
+ return true;
+ return getMetaFile( xSource, xContainingPage, rMtf, mtfLoadFlags, rxContext );
+ }
+
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Private methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ GDIMetaFileSharedPtr DrawShape::forceScrollTextMetaFile()
+ {
+ if ((mnCurrMtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != MTF_LOAD_SCROLL_TEXT_MTF)
+ {
+ // reload with added flags:
+ mpCurrMtf.reset( new GDIMetaFile );
+ mnCurrMtfLoadFlags |= MTF_LOAD_SCROLL_TEXT_MTF;
+ local_getMetaFile_WithSpecialChartHandling(
+ uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
+ mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
+ mxComponentContext );
+
+ // TODO(F1): Currently, the scroll metafile will
+ // never contain any verbose text comments. Thus,
+ // can only display the full mtf content, no
+ // subsets.
+ maSubsetting.reset( mpCurrMtf );
+
+ // adapt maBounds. the requested scroll text metafile
+ // will typically have dimension different from the
+ // actual shape
+ ::basegfx::B2DRectangle aScrollRect, aPaintRect;
+ ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
+ aPaintRect,
+ mpCurrMtf ),
+ "DrawShape::forceScrollTextMetaFile(): Could "
+ "not extract scroll anim rectangles from mtf" );
+
+ // take the larger one of the two rectangles (that
+ // should be the bound rect of the retrieved
+ // metafile)
+ if( aScrollRect.isInside( aPaintRect ) )
+ maBounds = aScrollRect;
+ else
+ maBounds = aPaintRect;
+ }
+ return mpCurrMtf;
+ }
+
+ void DrawShape::updateStateIds() const
+ {
+ // Update the states, we've just redrawn or created a new
+ // attribute layer.
+ if( mpAttributeLayer )
+ {
+ mnAttributeTransformationState = mpAttributeLayer->getTransformationState();
+ mnAttributeClipState = mpAttributeLayer->getClipState();
+ mnAttributeAlphaState = mpAttributeLayer->getAlphaState();
+ mnAttributePositionState = mpAttributeLayer->getPositionState();
+ mnAttributeContentState = mpAttributeLayer->getContentState();
+ mnAttributeVisibilityState = mpAttributeLayer->getVisibilityState();
+ }
+ }
+
+ void DrawShape::ensureVerboseMtfComments() const
+ {
+ // TODO(F1): Text effects don't currently work for drawing
+ // layer animations.
+
+ // only touch mpCurrMtf, if we're not a DrawingLayer
+ // animation.
+ if( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) == 0 &&
+ maAnimationFrames.empty() )
+ {
+ ENSURE_OR_THROW( !maSubsetting.hasSubsetShapes(),
+ "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
+ "with active child subsets will wreak havoc on the view!" );
+ ENSURE_OR_THROW( maSubsetting.getSubsetNode().isEmpty(),
+ "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
+ "for an ALREADY SUBSETTED shape is not possible!" );
+
+ // re-fetch metafile with comments
+ // note that, in case of shapes without text, the new
+ // metafile might still not provide any useful
+ // subsetting information!
+ mpCurrMtf.reset( new GDIMetaFile );
+ mnCurrMtfLoadFlags |= MTF_LOAD_VERBOSE_COMMENTS;
+ local_getMetaFile_WithSpecialChartHandling(
+ uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
+ mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
+ mxComponentContext );
+
+ maSubsetting.reset( maSubsetting.getSubsetNode(),
+ mpCurrMtf );
+ }
+ }
+
+ ViewShape::RenderArgs DrawShape::getViewRenderArgs() const
+ {
+ return ViewShape::RenderArgs(
+ maBounds,
+ getUpdateArea(),
+ getBounds(),
+ getActualUnitShapeBounds(),
+ mpAttributeLayer,
+ maSubsetting.getActiveSubsets(),
+ mnPriority);
+ }
+
+ bool DrawShape::implRender( int nUpdateFlags ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShape::implRender()" );
+ RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::presentation::internal::DrawShape: 0x%X", this );
+
+ // will perform the update now, clear update-enforcing
+ // flags
+ mbForceUpdate = false;
+ mbAttributeLayerRevoked = false;
+
+ ENSURE_OR_RETURN_FALSE( !maViewShapes.empty(),
+ "DrawShape::implRender(): render called on DrawShape without views" );
+
+ if( maBounds.isEmpty() )
+ {
+ // zero-sized shapes are effectively invisible,
+ // thus, we save us the rendering...
+ return true;
+ }
+
+ // redraw all view shapes, by calling their update() method
+ if( ::std::count_if( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::bind<bool>(
+ ::boost::mem_fn( &ViewShape::update ), // though _theoretically_,
+ // bind should eat this even
+ // with _1 being a shared_ptr,
+ // it does _not_ for MSVC without
+ // the extra mem_fn. WTF.
+ _1,
+ ::boost::cref( mpCurrMtf ),
+ ::boost::cref(
+ getViewRenderArgs() ),
+ nUpdateFlags,
+ isVisible() ) )
+ != static_cast<ViewShapeVector::difference_type>(maViewShapes.size()) )
+ {
+ // at least one of the ViewShape::update() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ // successfully redrawn - update state IDs to detect next changes
+ updateStateIds();
+
+ return true;
+ }
+
+ int DrawShape::getUpdateFlags() const
+ {
+ // default: update nothing, unless ShapeAttributeStack
+ // tells us below, or if the attribute layer was revoked
+ int nUpdateFlags(ViewShape::NONE);
+
+ // possibly the whole shape content changed
+ if( mbAttributeLayerRevoked )
+ nUpdateFlags = ViewShape::CONTENT;
+
+
+ // determine what has to be updated
+ // --------------------------------
+
+ // do we have an attribute layer?
+ if( mpAttributeLayer )
+ {
+ // Prevent nUpdateFlags to be modified when the shape is not
+ // visible, except when it just was hidden.
+ if (mpAttributeLayer->getVisibility()
+ || mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
+ {
+ if (mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
+ {
+ // Change of the visibility state is mapped to
+ // content change because when the visibility
+ // changes then usually a sprite is shown or hidden
+ // and the background under has to be painted once.
+ nUpdateFlags |= ViewShape::CONTENT;
+ }
+
+ // TODO(P1): This can be done without conditional branching.
+ // See HAKMEM.
+ if( mpAttributeLayer->getPositionState() != mnAttributePositionState )
+ {
+ nUpdateFlags |= ViewShape::POSITION;
+ }
+ if( mpAttributeLayer->getAlphaState() != mnAttributeAlphaState )
+ {
+ nUpdateFlags |= ViewShape::ALPHA;
+ }
+ if( mpAttributeLayer->getClipState() != mnAttributeClipState )
+ {
+ nUpdateFlags |= ViewShape::CLIP;
+ }
+ if( mpAttributeLayer->getTransformationState() != mnAttributeTransformationState )
+ {
+ nUpdateFlags |= ViewShape::TRANSFORMATION;
+ }
+ if( mpAttributeLayer->getContentState() != mnAttributeContentState )
+ {
+ nUpdateFlags |= ViewShape::CONTENT;
+ }
+ }
+ }
+
+ return nUpdateFlags;
+ }
+
+ ::basegfx::B2DRectangle DrawShape::getActualUnitShapeBounds() const
+ {
+ ENSURE_OR_THROW( !maViewShapes.empty(),
+ "DrawShape::getActualUnitShapeBounds(): called on DrawShape without views" );
+
+ const VectorOfDocTreeNodes& rSubsets(
+ maSubsetting.getActiveSubsets() );
+
+ const ::basegfx::B2DRectangle aDefaultBounds( 0.0,0.0,1.0,1.0 );
+
+ // perform the cheapest check first
+ if( rSubsets.empty() )
+ {
+ // if subset contains the whole shape, no need to call
+ // the somewhat expensive bound calculation, since as
+ // long as the subset is empty, this branch will be
+ // taken.
+ return aDefaultBounds;
+ }
+ else
+ {
+ OSL_ENSURE( rSubsets.size() != 1 ||
+ !rSubsets.front().isEmpty(),
+ "DrawShape::getActualUnitShapeBounds() expects a "
+ "_non-empty_ subset vector for a subsetted shape!" );
+
+ // are the cached bounds still valid?
+ if( !maCurrentShapeUnitBounds )
+ {
+ // no, (re)generate them
+ // =====================
+
+ // setup cached values to defaults (might fail to
+ // retrieve true bounds below)
+ maCurrentShapeUnitBounds.reset( aDefaultBounds );
+
+ // TODO(P2): the subset of the master shape (that from
+ // which the subsets are subtracted) changes
+ // relatively often (every time a subset shape is
+ // added or removed). Maybe we should exclude it here,
+ // always assuming full bounds?
+
+ ::cppcanvas::CanvasSharedPtr pDestinationCanvas(
+ maViewShapes.front()->getViewLayer()->getCanvas() );
+
+ // TODO(Q2): Although this _is_ currently
+ // view-agnostic, it might not stay like
+ // that. Maybe this method should again be moved
+ // to the ViewShape
+ ::cppcanvas::RendererSharedPtr pRenderer(
+ maViewShapes.front()->getRenderer(
+ pDestinationCanvas, mpCurrMtf, mpAttributeLayer ) );
+
+ // If we cannot not prefetch, be defensive and assume
+ // full shape size
+ if( pRenderer )
+ {
+ // temporarily, switch total transformation to identity
+ // (need the bounds in the [0,1]x[0,1] unit coordinate
+ // system.
+ ::basegfx::B2DHomMatrix aEmptyTransformation;
+
+ ::basegfx::B2DHomMatrix aOldTransform( pDestinationCanvas->getTransformation() );
+ pDestinationCanvas->setTransformation( aEmptyTransformation );
+ pRenderer->setTransformation( aEmptyTransformation );
+
+ // restore old transformation when leaving the scope
+ const ::comphelper::ScopeGuard aGuard(
+ boost::bind( &::cppcanvas::Canvas::setTransformation,
+ pDestinationCanvas, aOldTransform ) );
+
+
+ // retrieve bounds for subset of whole metafile
+ // --------------------------------------------
+
+ ::basegfx::B2DRange aTotalBounds;
+
+ // cannot use ::boost::bind, ::basegfx::B2DRange::expand()
+ // is overloaded.
+ VectorOfDocTreeNodes::const_iterator aCurr( rSubsets.begin() );
+ const VectorOfDocTreeNodes::const_iterator aEnd( rSubsets.end() );
+ while( aCurr != aEnd )
+ {
+ aTotalBounds.expand( pRenderer->getSubsetArea(
+ aCurr->getStartIndex(),
+ aCurr->getEndIndex() ) );
+ ++aCurr;
+ }
+
+ OSL_ENSURE( aTotalBounds.getMinX() >= -0.1 &&
+ aTotalBounds.getMinY() >= -0.1 &&
+ aTotalBounds.getMaxX() <= 1.1 &&
+ aTotalBounds.getMaxY() <= 1.1,
+ "DrawShape::getActualUnitShapeBounds(): bounds noticeably larger than original shape - clipping!" );
+
+ // really make sure no shape appears larger than its
+ // original bounds (there _are_ some pathologic cases,
+ // especially when imported from PPT, that have
+ // e.g. obscenely large polygon bounds)
+ aTotalBounds.intersect(
+ ::basegfx::B2DRange( 0.0, 0.0,
+ 1.0, 1.0 ));
+
+ maCurrentShapeUnitBounds.reset( aTotalBounds );
+ }
+ }
+
+ return *maCurrentShapeUnitBounds;
+ }
+ }
+
+ DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext ) :
+ mxShape( xShape ),
+ mxPage( xContainingPage ),
+ maAnimationFrames(), // empty, we don't have no intrinsic animation
+ mnCurrFrame(0),
+ mpCurrMtf(),
+ mnCurrMtfLoadFlags( bForeignSource
+ ? MTF_LOAD_FOREIGN_SOURCE : MTF_LOAD_NONE ),
+ maCurrentShapeUnitBounds(),
+ mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
+ maBounds( getAPIShapeBounds( xShape ) ),
+ mpAttributeLayer(),
+ mpIntrinsicAnimationActivity(),
+ mnAttributeTransformationState(0),
+ mnAttributeClipState(0),
+ mnAttributeAlphaState(0),
+ mnAttributePositionState(0),
+ mnAttributeContentState(0),
+ mnAttributeVisibilityState(0),
+ maViewShapes(),
+ mxComponentContext( rContext.mxComponentContext ),
+ maHyperlinkIndices(),
+ maHyperlinkRegions(),
+ maSubsetting(),
+ mnIsAnimatedCount(0),
+ mnAnimationLoopCount(0),
+ meCycleMode(CYCLE_LOOP),
+ mbIsVisible( true ),
+ mbForceUpdate( false ),
+ mbAttributeLayerRevoked( false ),
+ mbDrawingLayerAnim( false )
+ {
+ ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
+ ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
+
+ // check for drawing layer animations:
+ drawing::TextAnimationKind eKind = drawing::TextAnimationKind_NONE;
+ uno::Reference<beans::XPropertySet> xPropSet( mxShape,
+ uno::UNO_QUERY );
+ if( xPropSet.is() )
+ getPropertyValue( eKind, xPropSet,
+ OUSTR("TextAnimationKind") );
+ mbDrawingLayerAnim = (eKind != drawing::TextAnimationKind_NONE);
+
+ // must NOT be called from within initializer list, uses
+ // state from mnCurrMtfLoadFlags!
+ mpCurrMtf.reset( new GDIMetaFile );
+ local_getMetaFile_WithSpecialChartHandling(
+ uno::Reference<lang::XComponent>(xShape, uno::UNO_QUERY),
+ xContainingPage, *mpCurrMtf, mnCurrMtfLoadFlags,
+ mxComponentContext );
+ ENSURE_OR_THROW( mpCurrMtf,
+ "DrawShape::DrawShape(): Invalid metafile" );
+ maSubsetting.reset( mpCurrMtf );
+
+ prepareHyperlinkIndices();
+ }
+
+ DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext ) :
+ mxShape( xShape ),
+ mxPage( xContainingPage ),
+ maAnimationFrames(),
+ mnCurrFrame(0),
+ mpCurrMtf(),
+ mnCurrMtfLoadFlags( MTF_LOAD_NONE ),
+ maCurrentShapeUnitBounds(),
+ mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
+ maBounds( getAPIShapeBounds( xShape ) ),
+ mpAttributeLayer(),
+ mpIntrinsicAnimationActivity(),
+ mnAttributeTransformationState(0),
+ mnAttributeClipState(0),
+ mnAttributeAlphaState(0),
+ mnAttributePositionState(0),
+ mnAttributeContentState(0),
+ mnAttributeVisibilityState(0),
+ maViewShapes(),
+ mxComponentContext( rContext.mxComponentContext ),
+ maHyperlinkIndices(),
+ maHyperlinkRegions(),
+ maSubsetting(),
+ mnIsAnimatedCount(0),
+ mnAnimationLoopCount(0),
+ meCycleMode(CYCLE_LOOP),
+ mbIsVisible( true ),
+ mbForceUpdate( false ),
+ mbAttributeLayerRevoked( false ),
+ mbDrawingLayerAnim( false )
+ {
+ ENSURE_OR_THROW( rGraphic.IsAnimated(),
+ "DrawShape::DrawShape(): Graphic is no animation" );
+
+ getAnimationFromGraphic( maAnimationFrames,
+ mnAnimationLoopCount,
+ meCycleMode,
+ rGraphic );
+
+ ENSURE_OR_THROW( !maAnimationFrames.empty() &&
+ maAnimationFrames.front().mpMtf,
+ "DrawShape::DrawShape(): " );
+ mpCurrMtf = maAnimationFrames.front().mpMtf;
+
+ ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
+ ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
+ ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
+ }
+
+ DrawShape::DrawShape( const DrawShape& rSrc,
+ const DocTreeNode& rTreeNode,
+ double nPrio ) :
+ mxShape( rSrc.mxShape ),
+ mxPage( rSrc.mxPage ),
+ maAnimationFrames(), // don't copy animations for subsets,
+ // only the current frame!
+ mnCurrFrame(0),
+ mpCurrMtf( rSrc.mpCurrMtf ),
+ mnCurrMtfLoadFlags( rSrc.mnCurrMtfLoadFlags ),
+ maCurrentShapeUnitBounds(),
+ mnPriority( nPrio ),
+ maBounds( rSrc.maBounds ),
+ mpAttributeLayer(),
+ mpIntrinsicAnimationActivity(),
+ mnAttributeTransformationState(0),
+ mnAttributeClipState(0),
+ mnAttributeAlphaState(0),
+ mnAttributePositionState(0),
+ mnAttributeContentState(0),
+ mnAttributeVisibilityState(0),
+ maViewShapes(),
+ mxComponentContext( rSrc.mxComponentContext ),
+ maHyperlinkIndices(),
+ maHyperlinkRegions(),
+ maSubsetting( rTreeNode, mpCurrMtf ),
+ mnIsAnimatedCount(0),
+ mnAnimationLoopCount(0),
+ meCycleMode(CYCLE_LOOP),
+ mbIsVisible( rSrc.mbIsVisible ),
+ mbForceUpdate( false ),
+ mbAttributeLayerRevoked( false ),
+ mbDrawingLayerAnim( false )
+ {
+ ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
+ ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
+
+ // xxx todo: currently not implemented for subsetted shapes;
+ // would mean modifying set of hyperlink regions when
+ // subsetting text portions. N.B.: there's already an
+ // issue for this #i72828#
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Public methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ DrawShapeSharedPtr DrawShape::create(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext )
+ {
+ DrawShapeSharedPtr pShape( new DrawShape(xShape,
+ xContainingPage,
+ nPrio,
+ bForeignSource,
+ rContext) );
+
+ if( pShape->hasIntrinsicAnimation() )
+ {
+ OSL_ASSERT( pShape->maAnimationFrames.empty() );
+ if( pShape->getNumberOfTreeNodes(
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH) > 0 )
+ {
+ pShape->mpIntrinsicAnimationActivity =
+ createDrawingLayerAnimActivity(
+ rContext,
+ pShape);
+ }
+ }
+
+ if( pShape->hasHyperlinks() )
+ rContext.mpSubsettableShapeManager->addHyperlinkArea( pShape );
+
+ return pShape;
+ }
+
+ DrawShapeSharedPtr DrawShape::create(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext )
+ {
+ DrawShapeSharedPtr pShape( new DrawShape(xShape,
+ xContainingPage,
+ nPrio,
+ rGraphic,
+ rContext) );
+
+ if( pShape->hasIntrinsicAnimation() )
+ {
+ OSL_ASSERT( !pShape->maAnimationFrames.empty() );
+
+ std::vector<double> aTimeout;
+ std::transform(
+ pShape->maAnimationFrames.begin(),
+ pShape->maAnimationFrames.end(),
+ std::back_insert_iterator< std::vector<double> >( aTimeout ),
+ boost::mem_fn(&MtfAnimationFrame::getDuration) );
+
+ WakeupEventSharedPtr pWakeupEvent(
+ new WakeupEvent( rContext.mrEventQueue.getTimer(),
+ rContext.mrActivitiesQueue ) );
+
+ ActivitySharedPtr pActivity =
+ createIntrinsicAnimationActivity(
+ rContext,
+ pShape,
+ pWakeupEvent,
+ aTimeout,
+ pShape->mnAnimationLoopCount,
+ pShape->meCycleMode);
+
+ pWakeupEvent->setActivity( pActivity );
+ pShape->mpIntrinsicAnimationActivity = pActivity;
+ }
+
+ OSL_ENSURE( !pShape->hasHyperlinks(),
+ "DrawShape::create(): graphic-only shapes must not have hyperlinks!" );
+
+ return pShape;
+ }
+
+ DrawShape::~DrawShape()
+ {
+ try
+ {
+ // dispose intrinsic animation activity, else, it will
+ // linger forever
+ ActivitySharedPtr pActivity( mpIntrinsicAnimationActivity.lock() );
+ if( pActivity )
+ pActivity->dispose();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ uno::Reference< drawing::XShape > DrawShape::getXShape() const
+ {
+ return mxShape;
+ }
+
+ void DrawShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ ViewShapeVector::iterator aEnd( maViewShapes.end() );
+
+ // already added?
+ if( ::std::find_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rNewLayer ) ) ) != aEnd )
+ {
+ // yes, nothing to do
+ return;
+ }
+
+ ViewShapeSharedPtr pNewShape( new ViewShape( rNewLayer ) );
+
+ maViewShapes.push_back( pNewShape );
+
+ // pass on animation state
+ if( mnIsAnimatedCount )
+ {
+ for( int i=0; i<mnIsAnimatedCount; ++i )
+ pNewShape->enterAnimationMode();
+ }
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ {
+ pNewShape->update( mpCurrMtf,
+ getViewRenderArgs(),
+ ViewShape::FORCE,
+ isVisible() );
+ }
+ }
+
+ bool DrawShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewShapeVector::iterator aEnd( maViewShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "DrawShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ bool DrawShape::clearAllViewLayers()
+ {
+ maViewShapes.clear();
+ return true;
+ }
+
+ bool DrawShape::update() const
+ {
+ if( mbForceUpdate )
+ {
+ return render();
+ }
+ else
+ {
+ return implRender( getUpdateFlags() );
+ }
+ }
+
+ bool DrawShape::render() const
+ {
+ // force redraw. Have to also pass on the update flags,
+ // because e.g. content update (regeneration of the
+ // metafile renderer) is normally not performed. A simple
+ // ViewShape::FORCE would only paint the metafile in its
+ // old state.
+ return implRender( ViewShape::FORCE | getUpdateFlags() );
+ }
+
+ bool DrawShape::isContentChanged() const
+ {
+ return mbForceUpdate ?
+ true :
+ getUpdateFlags() != ViewShape::NONE;
+ }
+
+
+ ::basegfx::B2DRectangle DrawShape::getBounds() const
+ {
+ // little optimization: for non-modified shapes, we don't
+ // create an ShapeAttributeStack, and therefore also don't
+ // have to check it.
+ return getShapePosSize( maBounds,
+ mpAttributeLayer );
+ }
+
+ ::basegfx::B2DRectangle DrawShape::getDomBounds() const
+ {
+ return maBounds;
+ }
+
+ namespace
+ {
+ /** Functor expanding AA border for each passed ViewShape
+
+ Could not use ::boost::bind here, since
+ B2DRange::expand is overloaded (which yields one or
+ the other template type deduction ambiguous)
+ */
+ class Expander
+ {
+ public:
+ Expander( ::basegfx::B2DSize& rBounds ) :
+ mrBounds( rBounds )
+ {
+ }
+
+ void operator()( const ViewShapeSharedPtr& rShape ) const
+ {
+ const ::basegfx::B2DSize& rShapeBorder( rShape->getAntialiasingBorder() );
+
+ mrBounds.setX(
+ ::std::max(
+ rShapeBorder.getX(),
+ mrBounds.getX() ) );
+ mrBounds.setY(
+ ::std::max(
+ rShapeBorder.getY(),
+ mrBounds.getY() ) );
+ }
+
+ private:
+ ::basegfx::B2DSize& mrBounds;
+ };
+ }
+
+ ::basegfx::B2DRectangle DrawShape::getUpdateArea() const
+ {
+ ::basegfx::B2DRectangle aBounds;
+
+ // an already empty shape bound need no further
+ // treatment. In fact, any changes applied below would
+ // actually remove the special empty state, thus, don't
+ // change!
+ if( !maBounds.isEmpty() )
+ {
+ basegfx::B2DRectangle aUnitBounds(0.0,0.0,1.0,1.0);
+
+ if( !maViewShapes.empty() )
+ aUnitBounds = getActualUnitShapeBounds();
+
+ if( !aUnitBounds.isEmpty() )
+ {
+ if( mpAttributeLayer )
+ {
+ // calc actual shape area (in user coordinate
+ // space) from the transformation as given by the
+ // shape attribute layer
+ aBounds = getShapeUpdateArea( aUnitBounds,
+ getShapeTransformation( getBounds(),
+ mpAttributeLayer ),
+ mpAttributeLayer );
+ }
+ else
+ {
+ // no attribute layer, thus, the true shape bounds
+ // can be directly derived from the XShape bound
+ // attribute
+ aBounds = getShapeUpdateArea( aUnitBounds,
+ maBounds );
+ }
+
+ if( !maViewShapes.empty() )
+ {
+ // determine border needed for antialiasing the shape
+ ::basegfx::B2DSize aAABorder(0.0,0.0);
+
+ // for every view, get AA border and 'expand' aAABorder
+ // appropriately.
+ ::std::for_each( maViewShapes.begin(),
+ maViewShapes.end(),
+ Expander( aAABorder ) );
+
+ // add calculated AA border to aBounds
+ aBounds = ::basegfx::B2DRectangle( aBounds.getMinX() - aAABorder.getX(),
+ aBounds.getMinY() - aAABorder.getY(),
+ aBounds.getMaxX() + aAABorder.getX(),
+ aBounds.getMaxY() + aAABorder.getY() );
+ }
+ }
+ }
+
+ return aBounds;
+ }
+
+ bool DrawShape::isVisible() const
+ {
+ bool bIsVisible( mbIsVisible );
+
+ if( mpAttributeLayer )
+ {
+ // check whether visibility and alpha are not default
+ // (mpAttributeLayer->isVisibilityValid() returns true
+ // then): bVisible becomes true, if shape visibility
+ // is on and alpha is not 0.0 (fully transparent)
+ if( mpAttributeLayer->isVisibilityValid() )
+ bIsVisible = mpAttributeLayer->getVisibility();
+
+ // only touch bIsVisible, if the shape is still
+ // visible - if getVisibility already made us
+ // invisible, no alpha value will make us appear
+ // again.
+ if( bIsVisible && mpAttributeLayer->isAlphaValid() )
+ bIsVisible = !::basegfx::fTools::equalZero( mpAttributeLayer->getAlpha() );
+ }
+
+ return bIsVisible;
+ }
+
+ double DrawShape::getPriority() const
+ {
+ return mnPriority;
+ }
+
+ bool DrawShape::isBackgroundDetached() const
+ {
+ return mnIsAnimatedCount > 0;
+ }
+
+ bool DrawShape::hasIntrinsicAnimation() const
+ {
+ return (!maAnimationFrames.empty() || mbDrawingLayerAnim);
+ }
+
+ bool DrawShape::setIntrinsicAnimationFrame( ::std::size_t nCurrFrame )
+ {
+ ENSURE_OR_RETURN_FALSE( nCurrFrame < maAnimationFrames.size(),
+ "DrawShape::setIntrinsicAnimationFrame(): frame index out of bounds" );
+
+ if( mnCurrFrame != nCurrFrame )
+ {
+ mnCurrFrame = nCurrFrame;
+ mpCurrMtf = maAnimationFrames[ mnCurrFrame ].mpMtf;
+ mbForceUpdate = true;
+ }
+
+ return true;
+ }
+
+ // hyperlink support
+ void DrawShape::prepareHyperlinkIndices() const
+ {
+ if ( !maHyperlinkIndices.empty())
+ {
+ maHyperlinkIndices.clear();
+ maHyperlinkRegions.clear();
+ }
+
+ sal_Int32 nIndex = 0;
+ for ( MetaAction * pCurrAct = mpCurrMtf->FirstAction();
+ pCurrAct != 0; pCurrAct = mpCurrMtf->NextAction() )
+ {
+ if (pCurrAct->GetType() == META_COMMENT_ACTION) {
+ MetaCommentAction * pAct =
+ static_cast<MetaCommentAction *>(pCurrAct);
+ // skip comment if not a special XTEXT comment
+ if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN") ) ==
+ COMPARE_EQUAL &&
+ // e.g. date field doesn't have data!
+ // currently assuming that only url field, this is
+ // somehow fragile! xxx todo if possible
+ pAct->GetData() != 0 &&
+ pAct->GetDataSize() > 0)
+ {
+ if (!maHyperlinkIndices.empty() &&
+ maHyperlinkIndices.back().second == -1) {
+ OSL_FAIL( "### pending FIELD_SEQ_END!" );
+ maHyperlinkIndices.pop_back();
+ maHyperlinkRegions.pop_back();
+ }
+ maHyperlinkIndices.push_back(
+ HyperlinkIndexPair( nIndex + 1,
+ -1 /* to be filled below */ ) );
+ maHyperlinkRegions.push_back(
+ HyperlinkRegion(
+ basegfx::B2DRectangle(),
+ rtl::OUString(
+ reinterpret_cast<sal_Unicode const*>(
+ pAct->GetData()),
+ pAct->GetDataSize() / sizeof(sal_Unicode) )
+ ) );
+ }
+ else if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_END")) ==
+ COMPARE_EQUAL &&
+ // pending end is expected:
+ !maHyperlinkIndices.empty() &&
+ maHyperlinkIndices.back().second == -1)
+ {
+ maHyperlinkIndices.back().second = nIndex;
+ }
+ ++nIndex;
+ }
+ else
+ nIndex += getNextActionOffset(pCurrAct);
+ }
+ if (!maHyperlinkIndices.empty() &&
+ maHyperlinkIndices.back().second == -1) {
+ OSL_FAIL( "### pending FIELD_SEQ_END!" );
+ maHyperlinkIndices.pop_back();
+ maHyperlinkRegions.pop_back();
+ }
+ OSL_ASSERT( maHyperlinkIndices.size() == maHyperlinkRegions.size());
+ }
+
+ bool DrawShape::hasHyperlinks() const
+ {
+ return ! maHyperlinkRegions.empty();
+ }
+
+ HyperlinkArea::HyperlinkRegions DrawShape::getHyperlinkRegions() const
+ {
+ OSL_ASSERT( !maViewShapes.empty() );
+
+ if( !isVisible() )
+ return HyperlinkArea::HyperlinkRegions();
+
+ // late init, determine regions:
+ if( !maHyperlinkRegions.empty() &&
+ !maViewShapes.empty() &&
+ // region already inited?
+ maHyperlinkRegions.front().first.getWidth() == 0 &&
+ maHyperlinkRegions.front().first.getHeight() == 0 &&
+ maHyperlinkRegions.size() == maHyperlinkIndices.size() )
+ {
+ // TODO(Q2): Although this _is_ currently
+ // view-agnostic, it might not stay like that.
+ ViewShapeSharedPtr const& pViewShape = maViewShapes.front();
+ cppcanvas::CanvasSharedPtr const pCanvas(
+ pViewShape->getViewLayer()->getCanvas() );
+
+ // reuse Renderer of first view shape:
+ cppcanvas::RendererSharedPtr const pRenderer(
+ pViewShape->getRenderer(
+ pCanvas, mpCurrMtf, mpAttributeLayer ) );
+
+ OSL_ASSERT( pRenderer );
+
+ if (pRenderer)
+ {
+ basegfx::B2DHomMatrix const aOldTransform(
+ pCanvas->getTransformation() );
+ basegfx::B2DHomMatrix aTransform;
+ pCanvas->setTransformation( aTransform /* empty */ );
+
+ comphelper::ScopeGuard const resetOldTransformation(
+ boost::bind( &cppcanvas::Canvas::setTransformation,
+ pCanvas.get(),
+ boost::cref(aOldTransform) ));
+
+ aTransform.scale( maBounds.getWidth(),
+ maBounds.getHeight() );
+ pRenderer->setTransformation( aTransform );
+ pRenderer->setClip();
+
+ for( std::size_t pos = maHyperlinkRegions.size(); pos--; )
+ {
+ // get region:
+ HyperlinkIndexPair const& rIndices = maHyperlinkIndices[pos];
+ basegfx::B2DRectangle const region(
+ pRenderer->getSubsetArea( rIndices.first,
+ rIndices.second ));
+ maHyperlinkRegions[pos].first = region;
+ }
+ }
+ }
+
+ // shift shape-relative hyperlink regions to
+ // slide-absolute position
+
+ HyperlinkRegions aTranslatedRegions;
+ const basegfx::B2DPoint& rOffset(getBounds().getMinimum());
+ HyperlinkRegions::const_iterator aIter( maHyperlinkRegions.begin() );
+ HyperlinkRegions::const_iterator const aEnd ( maHyperlinkRegions.end() );
+ while( aIter != aEnd )
+ {
+ basegfx::B2DRange const& relRegion( aIter->first );
+ aTranslatedRegions.push_back(
+ std::make_pair(
+ basegfx::B2DRange(
+ relRegion.getMinimum() + rOffset,
+ relRegion.getMaximum() + rOffset),
+ aIter->second) );
+ ++aIter;
+ }
+
+ return aTranslatedRegions;
+ }
+
+ double DrawShape::getHyperlinkPriority() const
+ {
+ return getPriority();
+ }
+
+
+ // AnimatableShape methods
+ // ======================================================
+
+ void DrawShape::enterAnimationMode()
+ {
+ OSL_ENSURE( !maViewShapes.empty(),
+ "DrawShape::enterAnimationMode(): called on DrawShape without views" );
+
+ if( mnIsAnimatedCount == 0 )
+ {
+ // notify all ViewShapes, by calling their enterAnimationMode method.
+ // We're now entering animation mode
+ ::std::for_each( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::mem_fn( &ViewShape::enterAnimationMode ) );
+ }
+
+ ++mnIsAnimatedCount;
+ }
+
+ void DrawShape::leaveAnimationMode()
+ {
+ OSL_ENSURE( !maViewShapes.empty(),
+ "DrawShape::leaveAnimationMode(): called on DrawShape without views" );
+
+ --mnIsAnimatedCount;
+
+ if( mnIsAnimatedCount == 0 )
+ {
+ // notify all ViewShapes, by calling their leaveAnimationMode method.
+ // we're now leaving animation mode
+ ::std::for_each( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::mem_fn( &ViewShape::leaveAnimationMode ) );
+ }
+ }
+
+
+ // AttributableShape methods
+ // ======================================================
+
+ ShapeAttributeLayerSharedPtr DrawShape::createAttributeLayer()
+ {
+ // create new layer, with last as its new child
+ mpAttributeLayer.reset( new ShapeAttributeLayer( mpAttributeLayer ) );
+
+ // Update the local state ids to reflect those of the new layer.
+ updateStateIds();
+
+ return mpAttributeLayer;
+ }
+
+ bool DrawShape::revokeAttributeLayer( const ShapeAttributeLayerSharedPtr& rLayer )
+ {
+ if( !mpAttributeLayer )
+ return false; // no layers
+
+ if( mpAttributeLayer == rLayer )
+ {
+ // it's the toplevel layer
+ mpAttributeLayer = mpAttributeLayer->getChildLayer();
+
+ // force content redraw, all state variables have
+ // possibly changed
+ mbAttributeLayerRevoked = true;
+
+ return true;
+ }
+ else
+ {
+ // pass on to the layer, to try its children
+ return mpAttributeLayer->revokeChildLayer( rLayer );
+ }
+ }
+
+ ShapeAttributeLayerSharedPtr DrawShape::getTopmostAttributeLayer() const
+ {
+ return mpAttributeLayer;
+ }
+
+ void DrawShape::setVisibility( bool bVisible )
+ {
+ if( mbIsVisible != bVisible )
+ {
+ mbIsVisible = bVisible;
+ mbForceUpdate = true;
+ }
+ }
+
+ const DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier() const
+ {
+ return *this;
+ }
+
+ DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier()
+ {
+ return *this;
+ }
+
+ DocTreeNode DrawShape::getSubsetNode() const
+ {
+ ensureVerboseMtfComments();
+
+ // forward to delegate
+ return maSubsetting.getSubsetNode();
+ }
+
+ AttributableShapeSharedPtr DrawShape::getSubset( const DocTreeNode& rTreeNode ) const
+ {
+ ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
+ "DrawShape::getSubset(): subset query on shape with apparently no subsets" );
+
+ // forward to delegate
+ return maSubsetting.getSubsetShape( rTreeNode );
+ }
+
+ bool DrawShape::createSubset( AttributableShapeSharedPtr& o_rSubset,
+ const DocTreeNode& rTreeNode )
+ {
+ ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
+ "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
+
+ // subset shape already created for this DocTreeNode?
+ AttributableShapeSharedPtr pSubset( maSubsetting.getSubsetShape( rTreeNode ) );
+
+ // when true, this method has created a new subset
+ // DrawShape
+ bool bNewlyCreated( false );
+
+ if( pSubset )
+ {
+ o_rSubset = pSubset;
+
+ // reusing existing subset
+ }
+ else
+ {
+ // not yet created, init entry
+ o_rSubset.reset( new DrawShape( *this,
+ rTreeNode,
+ // TODO(Q3): That's a
+ // hack. We assume
+ // that start and end
+ // index will always
+ // be less than 65535
+ mnPriority +
+ rTreeNode.getStartIndex()/double(SAL_MAX_INT16) ));
+
+ bNewlyCreated = true; // subset newly created
+ }
+
+ // always register shape at DrawShapeSubsetting, to keep
+ // refcount up-to-date
+ maSubsetting.addSubsetShape( o_rSubset );
+
+ // flush bounds cache
+ maCurrentShapeUnitBounds.reset();
+
+ return bNewlyCreated;
+ }
+
+ bool DrawShape::revokeSubset( const AttributableShapeSharedPtr& rShape )
+ {
+ ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
+ "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
+
+ // flush bounds cache
+ maCurrentShapeUnitBounds.reset();
+
+ // forward to delegate
+ if( maSubsetting.revokeSubsetShape( rShape ) )
+ {
+ // force redraw, our content has possibly changed (as
+ // one of the subsets now display within our shape
+ // again).
+ mbForceUpdate = true;
+
+ // #i47428# TEMP FIX: synchronize visibility of subset
+ // with parent.
+
+ // TODO(F3): Remove here, and implement
+ // TEXT_ONLY/BACKGROUND_ONLY with the proverbial
+ // additional level of indirection: create a
+ // persistent subset, containing all text/only the
+ // background respectively. From _that_ object,
+ // generate the temporary character subset shapes.
+ const ShapeAttributeLayerSharedPtr& rAttrLayer(
+ rShape->getTopmostAttributeLayer() );
+ if( rAttrLayer &&
+ rAttrLayer->isVisibilityValid() &&
+ rAttrLayer->getVisibility() != isVisible() )
+ {
+ const bool bVisibility( rAttrLayer->getVisibility() );
+
+ // visibilities differ - adjust ours, then
+ if( mpAttributeLayer )
+ mpAttributeLayer->setVisibility( bVisibility );
+ else
+ mbIsVisible = bVisibility;
+ }
+
+ // END TEMP FIX
+
+ return true;
+ }
+
+ return false;
+ }
+
+ sal_Int32 DrawShape::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ return maSubsetting.getNumberOfTreeNodes( eNodeType );
+ }
+
+ DocTreeNode DrawShape::getTreeNode( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ if ( hasHyperlinks())
+ {
+ prepareHyperlinkIndices();
+ }
+
+ return maSubsetting.getTreeNode( nNodeIndex, eNodeType );
+ }
+
+ sal_Int32 DrawShape::getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ return maSubsetting.getNumberOfSubsetTreeNodes( rParentNode, eNodeType );
+ }
+
+ DocTreeNode DrawShape::getSubsetTreeNode( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ return maSubsetting.getSubsetTreeNode( rParentNode, nNodeIndex, eNodeType );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshape.hxx b/slideshow/source/engine/shapes/drawshape.hxx
new file mode 100644
index 000000000000..1800ab3a5fe8
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshape.hxx
@@ -0,0 +1,385 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_DRAWSHAPE_HXX
+#define INCLUDED_SLIDESHOW_DRAWSHAPE_HXX
+
+#include <osl/diagnose.hxx>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include "attributableshape.hxx"
+#include "doctreenodesupplier.hxx"
+#include "gdimtftools.hxx"
+#include "viewshape.hxx"
+#include "hyperlinkarea.hxx"
+
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <set>
+#include <vector>
+
+class Graphic;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class Activity;
+ struct SlideShowContext;
+ class DrawShapeSubsetting;
+ class DrawShape;
+ typedef ::boost::shared_ptr< DrawShape > DrawShapeSharedPtr;
+
+ /** This class is the representation of a draw document's
+ XShape, and implements the Shape, AnimatableShape, and
+ AttributableShape interfaces.
+
+ @attention this class is to be treated 'final', i.e. one
+ should not derive from it.
+ */
+ class DrawShape : public AttributableShape,
+ public DocTreeNodeSupplier,
+ public HyperlinkArea,
+ public ::osl::DebugBase<DrawShape>
+ {
+ public:
+ /** Create a shape for the given XShape
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param bForeignSource
+ When true, the source of the shape metafile might be a
+ foreign application. The metafile is checked against
+ unsupported content, and, if necessary, returned as a
+ pre-rendererd bitmap.
+ */
+ static DrawShapeSharedPtr create(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ /** Create a shape for the given XShape and graphic content
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param rGraphic
+ Graphic to display in the shape's bound rect. If this
+ Graphic contains animatable content, the created
+ DrawShape will register itself for intrinsic animation
+ events.
+ */
+ static DrawShapeSharedPtr create(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > getXShape() const;
+
+ virtual ~DrawShape();
+
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+ // attribute methods
+ //------------------------------------------------------------------
+
+ virtual ShapeAttributeLayerSharedPtr createAttributeLayer();
+ virtual bool revokeAttributeLayer( const ShapeAttributeLayerSharedPtr& rLayer );
+ virtual ShapeAttributeLayerSharedPtr getTopmostAttributeLayer() const;
+ virtual void setVisibility( bool bVisible );
+ virtual ::basegfx::B2DRectangle getBounds() const;
+ virtual ::basegfx::B2DRectangle getDomBounds() const;
+ virtual ::basegfx::B2DRectangle getUpdateArea() const;
+ virtual bool isVisible() const;
+ virtual double getPriority() const;
+
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ virtual void enterAnimationMode();
+ virtual void leaveAnimationMode();
+ virtual bool isBackgroundDetached() const;
+
+ // render methods
+ //------------------------------------------------------------------
+
+ virtual bool update() const;
+ virtual bool render() const;
+ virtual bool isContentChanged() const;
+
+ // Sub item specialities
+ //------------------------------------------------------------------
+
+ virtual const DocTreeNodeSupplier& getTreeNodeSupplier() const;
+ virtual DocTreeNodeSupplier& getTreeNodeSupplier();
+
+ virtual DocTreeNode getSubsetNode() const;
+ virtual AttributableShapeSharedPtr getSubset( const DocTreeNode& rTreeNode ) const;
+ virtual bool createSubset( AttributableShapeSharedPtr& o_rSubset,
+ const DocTreeNode& rTreeNode );
+ virtual bool revokeSubset( const AttributableShapeSharedPtr& rShape );
+
+
+ // DocTreeNodeSupplier methods
+ //------------------------------------------------------------------
+
+ virtual sal_Int32 getNumberOfTreeNodes ( DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+ virtual DocTreeNode getTreeNode ( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+ virtual sal_Int32 getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+ virtual DocTreeNode getSubsetTreeNode ( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+
+ // HyperlinkArea methods
+ //------------------------------------------------------------------
+
+ virtual HyperlinkRegions getHyperlinkRegions() const;
+ virtual double getHyperlinkPriority() const;
+
+
+ // intrinsic animation methods
+ //------------------------------------------------------------------
+
+ /** Display next frame of an intrinsic animation.
+
+ Used by IntrinsicAnimationActivity, to show the next
+ animation frame.
+ */
+ bool setIntrinsicAnimationFrame( ::std::size_t nCurrFrame );
+
+ /** forces the drawshape to load and return a specially
+ crafted metafile, usable to display drawing layer text
+ animations.
+ */
+ GDIMetaFileSharedPtr forceScrollTextMetaFile();
+
+ private:
+ /** Create a shape for the given XShape
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param bForeignSource
+ When true, the source of the shape metafile might be a
+ foreign application. The metafile is checked against
+ unsupported content, and, if necessary, returned as a
+ pre-rendererd bitmap.
+ */
+ DrawShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ /** Create a shape for the given XShape and graphic content
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param rGraphic
+ Graphic to display in the shape's bound rect. If this
+ Graphic contains animatable content, the created
+ DrawShape will register itself for intrinsic animation
+ events.
+ */
+ DrawShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ /** Private copy constructor
+
+ Used to create subsetted shapes
+ */
+ DrawShape( const DrawShape&, const DocTreeNode& rTreeNode, double nPrio );
+
+ int getUpdateFlags() const;
+ bool implRender( int nUpdateFlags ) const;
+ void updateStateIds() const;
+
+ ViewShape::RenderArgs getViewRenderArgs() const;
+ ::basegfx::B2DRectangle getActualUnitShapeBounds() const;
+
+ void ensureVerboseMtfComments() const;
+ bool hasIntrinsicAnimation() const;
+ bool hasHyperlinks() const;
+ void prepareHyperlinkIndices() const;
+
+ /// The associated XShape
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > mxShape;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage > mxPage;
+
+ /** A vector of metafiles actually representing the Shape.
+
+ If this shape is not animated, only a single entry is
+ available.
+ */
+ mutable VectorOfMtfAnimationFrames maAnimationFrames;
+ ::std::size_t mnCurrFrame;
+
+ /// Metafile of currently active frame (static for shapes w/o intrinsic animation)
+ mutable GDIMetaFileSharedPtr mpCurrMtf;
+
+ /// loadflags of current meta file
+ mutable int mnCurrMtfLoadFlags;
+
+ /// Contains the current shape bounds, in unit rect space
+ mutable ::boost::optional<basegfx::B2DRectangle> maCurrentShapeUnitBounds;
+
+ // The attributes of this Shape
+ const double mnPriority;
+ ::basegfx::B2DRectangle maBounds; // always needed for rendering.
+ // for subset shapes, this member
+ // might change when views are
+ // added, as minimal bounds are
+ // calculated
+
+ // Pointer to modifiable shape attributes
+ ShapeAttributeLayerSharedPtr mpAttributeLayer; // only created lazily
+
+ // held here, to signal our destruction
+ boost::weak_ptr<Activity> mpIntrinsicAnimationActivity;
+
+ // The attribute states, to detect attribute changes,
+ // without buffering and querying each single attribute
+ mutable State::StateId mnAttributeTransformationState;
+ mutable State::StateId mnAttributeClipState;
+ mutable State::StateId mnAttributeAlphaState;
+ mutable State::StateId mnAttributePositionState;
+ mutable State::StateId mnAttributeContentState;
+ mutable State::StateId mnAttributeVisibilityState;
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewShapeSharedPtr > ViewShapeVector;
+ ViewShapeVector maViewShapes;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext> mxComponentContext;
+
+ /// hyperlink support
+ typedef ::std::pair<sal_Int32 /* mtf start */,
+ sal_Int32 /* mtf end */> HyperlinkIndexPair;
+ typedef ::std::vector<HyperlinkIndexPair> HyperlinkIndexPairVector;
+ mutable HyperlinkIndexPairVector maHyperlinkIndices;
+ mutable HyperlinkRegions maHyperlinkRegions;
+
+ /// Delegated subset handling
+ mutable DrawShapeSubsetting maSubsetting;
+
+ /// Whether this shape is currently in animation mode (value != 0)
+ int mnIsAnimatedCount;
+
+ /// Number of times the bitmap animation shall loop
+ ::std::size_t mnAnimationLoopCount;
+
+ /// Cycle mode for bitmap animation
+ CycleMode meCycleMode;
+
+ /// Whether shape is visible (without attribute layers)
+ bool mbIsVisible;
+
+ /// Whether redraw is necessary, regardless of state ids
+ mutable bool mbForceUpdate;
+
+ /// Whether attribute layer was revoked (making a redraw necessary)
+ mutable bool mbAttributeLayerRevoked;
+
+ /// whether a drawing layer animation has to be performed
+ bool mbDrawingLayerAnim;
+
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_DRAWSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshapesubsetting.cxx b/slideshow/source/engine/shapes/drawshapesubsetting.cxx
new file mode 100644
index 000000000000..f0ede5bf4bea
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshapesubsetting.cxx
@@ -0,0 +1,867 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <rtl/math.hxx>
+#include <rtl/logfile.hxx>
+
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+#include "drawshapesubsetting.hxx"
+#include "drawshape.hxx"
+
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <limits>
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Private methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ void DrawShapeSubsetting::ensureInitializedNodeTree() const
+ {
+ ENSURE_OR_THROW( mpMtf,
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
+
+ if( mbNodeTreeInitialized )
+ return; // done, already initialized.
+
+ // init doctree vector
+ maActionClassVector.clear();
+ maActionClassVector.reserve( mpMtf->GetActionCount() );
+
+ // search metafile for text output
+ MetaAction* pCurrAct;
+
+ sal_Int32 nActionIndex(0);
+ sal_Int32 nLastTextActionIndex(0);
+ for( pCurrAct = mpMtf->FirstAction(); pCurrAct; pCurrAct = mpMtf->NextAction() )
+ {
+ // check for one of our special text doctree comments
+ switch( pCurrAct->GetType() )
+ {
+ case META_COMMENT_ACTION:
+ {
+ MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
+
+ // skip comment if not a special XTEXT comment
+ if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT", 5 ) == COMPARE_EQUAL )
+ {
+ // fill classification vector with NOOPs,
+ // then insert corresponding classes at
+ // the given index
+ maActionClassVector.resize( nActionIndex+1, CLASS_NOOP );
+
+ if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOC" ) == COMPARE_EQUAL )
+ {
+ // special, because can happen
+ // in-between of portions - set
+ // character-end classificator at
+ // given index (relative to last text
+ // action).
+ const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
+
+ ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
+
+ maActionClassVector[ nIndex ] = CLASS_CHARACTER_CELL_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOW" ) == COMPARE_EQUAL )
+ {
+ // special, because can happen
+ // in-between of portions - set
+ // word-end classificator at given
+ // index (relative to last text
+ // action).
+ const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
+
+ ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
+
+ maActionClassVector[ nIndex ] = CLASS_WORD_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOS" ) == COMPARE_EQUAL )
+ {
+ // special, because can happen
+ // in-between of portions - set
+ // sentence-end classificator at given
+ // index (relative to last text
+ // action).
+ const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
+
+ ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
+
+ maActionClassVector[ nIndex ] = CLASS_SENTENCE_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOL" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_LINE_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOP" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_PARAGRAPH_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_PAINTSHAPE_END" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_SHAPE_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_PAINTSHAPE_BEGIN" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_SHAPE_START;
+ }
+ }
+ ++nActionIndex;
+ break;
+ }
+ case META_TEXT_ACTION:
+ case META_TEXTARRAY_ACTION:
+ case META_STRETCHTEXT_ACTION:
+ nLastTextActionIndex = nActionIndex;
+ // fallthrough intended
+ default:
+ // comment action and all actions not
+ // explicitely handled here:
+ nActionIndex += getNextActionOffset(pCurrAct);
+ break;
+ }
+ }
+
+ mbNodeTreeInitialized = true;
+ }
+
+ void DrawShapeSubsetting::updateSubsetBounds( const SubsetEntry& rSubsetEntry )
+ {
+ // TODO(F1): This removes too much from non-contiguous subsets
+ mnMinSubsetActionIndex = ::std::min(
+ mnMinSubsetActionIndex,
+ rSubsetEntry.mnStartActionIndex );
+ mnMaxSubsetActionIndex = ::std::max(
+ mnMaxSubsetActionIndex,
+ rSubsetEntry.mnEndActionIndex );
+ }
+
+ void DrawShapeSubsetting::updateSubsets()
+ {
+ maCurrentSubsets.clear();
+
+ if( !maSubsetShapes.empty() )
+ {
+ if( maSubset.isEmpty() )
+ {
+ // non-subsetted node, with some child subsets
+ // that subtract from it
+ maCurrentSubsets.push_back( DocTreeNode( 0,
+ mnMinSubsetActionIndex,
+ DocTreeNode::NODETYPE_INVALID ) );
+ maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
+ maActionClassVector.size(),
+ DocTreeNode::NODETYPE_INVALID ) );
+ }
+ else
+ {
+ // subsetted node, from which some further child
+ // subsets subtract content
+ maCurrentSubsets.push_back( DocTreeNode( maSubset.getStartIndex(),
+ mnMinSubsetActionIndex,
+ DocTreeNode::NODETYPE_INVALID ) );
+ maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
+ maSubset.getEndIndex(),
+ DocTreeNode::NODETYPE_INVALID ) );
+ }
+ }
+ else
+ {
+ // no further child subsets, simply add our subset (if any)
+ if( !maSubset.isEmpty() )
+ {
+ // subsetted node, without any subset children
+ maCurrentSubsets.push_back( maSubset );
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Public methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ DrawShapeSubsetting::DrawShapeSubsetting() :
+ maActionClassVector(),
+ mpMtf(),
+ maSubset(),
+ maSubsetShapes(),
+ mnMinSubsetActionIndex( SAL_MAX_INT32 ),
+ mnMaxSubsetActionIndex(0),
+ maCurrentSubsets(),
+ mbNodeTreeInitialized( false )
+ {
+ }
+
+ DrawShapeSubsetting::DrawShapeSubsetting( const GDIMetaFileSharedPtr& rMtf ) :
+ maActionClassVector(),
+ mpMtf( rMtf ),
+ maSubset(),
+ maSubsetShapes(),
+ mnMinSubsetActionIndex( SAL_MAX_INT32 ),
+ mnMaxSubsetActionIndex(0),
+ maCurrentSubsets(),
+ mbNodeTreeInitialized( false )
+ {
+ ENSURE_OR_THROW( mpMtf,
+ "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
+
+ initCurrentSubsets();
+ }
+
+ DrawShapeSubsetting::DrawShapeSubsetting( const DocTreeNode& rShapeSubset,
+ const GDIMetaFileSharedPtr& rMtf ) :
+ maActionClassVector(),
+ mpMtf( rMtf ),
+ maSubset( rShapeSubset ),
+ maSubsetShapes(),
+ mnMinSubsetActionIndex( SAL_MAX_INT32 ),
+ mnMaxSubsetActionIndex(0),
+ maCurrentSubsets(),
+ mbNodeTreeInitialized( false )
+ {
+ ENSURE_OR_THROW( mpMtf,
+ "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
+
+ initCurrentSubsets();
+ }
+
+ void DrawShapeSubsetting::reset()
+ {
+ maActionClassVector.clear();
+ mpMtf.reset();
+ maSubset.reset();
+ maSubsetShapes.clear();
+ mnMinSubsetActionIndex = SAL_MAX_INT32;
+ mnMaxSubsetActionIndex = 0;
+ maCurrentSubsets.clear();
+ mbNodeTreeInitialized = false;
+ }
+
+ void DrawShapeSubsetting::reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf )
+ {
+ reset();
+ mpMtf = rMtf;
+
+ initCurrentSubsets();
+ }
+
+ void DrawShapeSubsetting::reset( const DocTreeNode& rShapeSubset,
+ const ::boost::shared_ptr< GDIMetaFile >& rMtf )
+ {
+ reset();
+ mpMtf = rMtf;
+ maSubset = rShapeSubset;
+
+ initCurrentSubsets();
+ }
+
+ void DrawShapeSubsetting::initCurrentSubsets()
+ {
+ // only add subset to vector, if it's not empty - that's
+ // because the vector's content is later literally used
+ // for e.g. painting.
+ if( !maSubset.isEmpty() )
+ maCurrentSubsets.push_back( maSubset );
+ }
+
+ DocTreeNode DrawShapeSubsetting::getSubsetNode() const
+ {
+ return maSubset;
+ }
+
+ bool DrawShapeSubsetting::hasSubsetShapes() const
+ {
+ return !maSubsetShapes.empty();
+ }
+
+ AttributableShapeSharedPtr DrawShapeSubsetting::getSubsetShape( const DocTreeNode& rTreeNode ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
+
+ // subset shape already created for this DocTreeNode?
+ SubsetEntry aEntry;
+
+ aEntry.mnStartActionIndex = rTreeNode.getStartIndex();
+ aEntry.mnEndActionIndex = rTreeNode.getEndIndex();
+
+ ShapeSet::const_iterator aIter;
+ if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
+ {
+ // already created, return found entry
+ return aIter->mpShape;
+ }
+
+ return AttributableShapeSharedPtr();
+ }
+
+ void DrawShapeSubsetting::addSubsetShape( const AttributableShapeSharedPtr& rShape )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
+
+ // subset shape already created for this DocTreeNode?
+ SubsetEntry aEntry;
+ const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
+
+ aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
+ aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
+
+ ShapeSet::const_iterator aIter;
+ if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
+ {
+ // already created, increment use count and return
+
+ // safe cast, since set order does not depend on
+ // mnSubsetQueriedCount
+ const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount++;
+ }
+ else
+ {
+ // not yet created, init entry
+ aEntry.mnSubsetQueriedCount = 1;
+ aEntry.mpShape = rShape;
+
+ maSubsetShapes.insert( aEntry );
+
+ // update cached subset borders
+ updateSubsetBounds( aEntry );
+ updateSubsets();
+ }
+ }
+
+ bool DrawShapeSubsetting::revokeSubsetShape( const AttributableShapeSharedPtr& rShape )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
+
+ // lookup subset shape
+ SubsetEntry aEntry;
+ const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
+
+ aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
+ aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
+
+ ShapeSet::iterator aIter;
+ if( (aIter=maSubsetShapes.find( aEntry )) == maSubsetShapes.end() )
+ return false; // not found, subset was never queried
+
+ // last client of the subset revoking?
+ if( aIter->mnSubsetQueriedCount > 1 )
+ {
+ // no, still clients out there. Just decrement use count
+ // safe cast, since order does not depend on mnSubsetQueriedCount
+ const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount--;
+
+ VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, revoked subset has refcount %d",
+ this,
+ maSubsetShapes.size(),
+ aIter->mnSubsetQueriedCount );
+
+ return false; // not the last client
+ }
+
+ VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, cleared subset has range [%d,%d]",
+ this,
+ maSubsetShapes.size(),
+ aEntry.mnStartActionIndex,
+ aEntry.mnEndActionIndex );
+
+ // yes, remove from set
+ maSubsetShapes.erase( aIter );
+
+
+ // update currently active subset for _our_ shape (the
+ // part of this shape that is visible, i.e. not displayed
+ // in subset shapes)
+ // ======================================================
+
+ // init bounds
+ mnMinSubsetActionIndex = SAL_MAX_INT32;
+ mnMaxSubsetActionIndex = 0;
+
+ // TODO(P2): This is quite expensive, when
+ // after every subset effect end, we have to scan
+ // the whole shape set
+
+ // determine new subset range
+ ::std::for_each( maSubsetShapes.begin(),
+ maSubsetShapes.end(),
+ ::boost::bind(&DrawShapeSubsetting::updateSubsetBounds,
+ this,
+ _1 ) );
+
+ updateSubsets();
+
+ return true;
+ }
+
+ namespace
+ {
+ /** Iterate over all action classification entries in the
+ given range, pass each element range found to the
+ given functor.
+
+ This method extracts, for each of the different action
+ classifications, the count and the ranges for each of
+ them, and calls the provided functor with that
+ information.
+
+ @tpl FunctorT
+ This is the functor's operator() calling signature,
+ with eCurrElemClassification denoting the current
+ classification type the functor is called for,
+ nCurrElemCount the running total of elements visited
+ for the given class (starting from 0), and
+ rCurrElemBegin/rCurrElemEnd the range of the current
+ element (i.e. the iterators from the start to the end
+ of this element).
+ <pre>
+ bool operator()( IndexClassificator eCurrElemClassification
+ sal_Int32 nCurrElemCount,
+ const IndexClassificatorVector::const_iterator& rCurrElemBegin,
+ const IndexClassificatorVector::const_iterator& rCurrElemEnd );
+ </pre>
+ If the functor returns false, iteration over the
+ shapes is immediately stopped.
+
+ @param io_pFunctor
+ This functor is called for every shape found.
+
+ @param rBegin
+ Start of range to iterate over
+
+ @param rEnd
+ End of range to iterate over
+
+ @return the number of shapes found in the metafile
+ */
+ template< typename FunctorT > void iterateActionClassifications(
+ FunctorT& io_rFunctor,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
+ {
+ sal_Int32 nCurrShapeCount( 0 );
+ sal_Int32 nCurrParaCount( 0 );
+ sal_Int32 nCurrLineCount( 0 );
+ sal_Int32 nCurrSentenceCount( 0 );
+ sal_Int32 nCurrWordCount( 0 );
+ sal_Int32 nCurrCharCount( 0 );
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastShapeStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastParaStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastLineStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastSentenceStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastWordStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastCharStart(rBegin);
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext;
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aCurr( rBegin );
+ while( aCurr != rEnd )
+ {
+ // aNext will hold an iterator to the next element
+ // (or the past-the-end iterator, if aCurr
+ // references the last element). Used to pass a
+ // valid half-open range to the functors.
+ aNext = aCurr;
+ ++aNext;
+
+ switch( *aCurr )
+ {
+ default:
+ ENSURE_OR_THROW( false,
+ "Unexpected type in iterateDocShapes()" );
+ case DrawShapeSubsetting::CLASS_NOOP:
+ // ignore NOOP actions
+ break;
+
+ case DrawShapeSubsetting::CLASS_SHAPE_START:
+ // regardless of ending action
+ // classifications before: a new shape
+ // always also starts contained elements
+ // anew
+ aLastShapeStart =
+ aLastParaStart =
+ aLastLineStart =
+ aLastSentenceStart =
+ aLastWordStart =
+ aLastCharStart = aCurr;
+ break;
+
+ case DrawShapeSubsetting::CLASS_SHAPE_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
+ nCurrShapeCount,
+ aLastShapeStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrShapeCount;
+ // FALLTHROUGH intended: shape end also
+ // ends lines
+ case DrawShapeSubsetting::CLASS_PARAGRAPH_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END,
+ nCurrParaCount,
+ aLastParaStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrParaCount;
+ aLastParaStart = aNext;
+ // FALLTHROUGH intended: para end also
+ // ends line
+ case DrawShapeSubsetting::CLASS_LINE_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
+ nCurrLineCount,
+ aLastLineStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrLineCount;
+ aLastLineStart = aNext;
+
+ if( *aCurr == DrawShapeSubsetting::CLASS_LINE_END )
+ {
+ // DON'T fall through here, as a line
+ // does NOT end neither a sentence,
+ // nor a word. OTOH, all parent
+ // structures (paragraph and shape),
+ // which itself fall through to this
+ // code, DO end word, sentence and
+ // character cell.
+
+ // TODO(F1): Maybe a line should end a
+ // character cell, OTOH?
+ break;
+ }
+ // FALLTHROUGH intended
+ case DrawShapeSubsetting::CLASS_SENTENCE_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END,
+ nCurrSentenceCount,
+ aLastSentenceStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrSentenceCount;
+ aLastSentenceStart = aNext;
+ // FALLTHROUGH intended
+ case DrawShapeSubsetting::CLASS_WORD_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
+ nCurrWordCount,
+ aLastWordStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrWordCount;
+ aLastWordStart = aNext;
+ // FALLTHROUGH intended
+ case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END,
+ nCurrCharCount,
+ aLastCharStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrCharCount;
+ aLastCharStart = aNext;
+ break;
+ }
+
+ aCurr = aNext;
+ }
+ }
+
+ DrawShapeSubsetting::IndexClassificator mapDocTreeNode( DocTreeNode::NodeType eNodeType )
+ {
+ switch( eNodeType )
+ {
+ case DocTreeNode::NODETYPE_INVALID:
+ // FALLTHROUGH intended
+ default:
+ OSL_FAIL("DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
+ return DrawShapeSubsetting::CLASS_NOOP;
+
+ case DocTreeNode::NODETYPE_LOGICAL_SHAPE:
+ // FALLTHROUGH intended
+ case DocTreeNode::NODETYPE_FORMATTING_SHAPE:
+ return DrawShapeSubsetting::CLASS_SHAPE_END;
+
+ case DocTreeNode::NODETYPE_FORMATTING_LINE:
+ return DrawShapeSubsetting::CLASS_LINE_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH:
+ return DrawShapeSubsetting::CLASS_PARAGRAPH_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_SENTENCE:
+ return DrawShapeSubsetting::CLASS_SENTENCE_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_WORD:
+ return DrawShapeSubsetting::CLASS_WORD_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL:
+ return DrawShapeSubsetting::CLASS_CHARACTER_CELL_END;
+ };
+ }
+
+ /// Counts number of class occurrences
+ class CountClassFunctor
+ {
+ public:
+ CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
+ meClass( eClass ),
+ mnCurrCount(0)
+ {
+ }
+
+ bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
+ sal_Int32 /*nCurrElemCount*/,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemBegin*/,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemEnd*/ )
+ {
+ if( eCurrElemClassification == meClass )
+ ++mnCurrCount;
+
+ return true; // never stop, count all occurrences
+ }
+
+ sal_Int32 getCount() const
+ {
+ return mnCurrCount;
+ }
+
+ private:
+ DrawShapeSubsetting::IndexClassificator meClass;
+ sal_Int32 mnCurrCount;
+ };
+ }
+
+ sal_Int32 DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ const IndexClassificator eRequestedClass(
+ mapDocTreeNode( eNodeType ) );
+
+ // create a counting functor for the requested class of
+ // actions
+ CountClassFunctor aFunctor( eRequestedClass );
+
+ // count all occurrences in the given range
+ iterateActionClassifications( aFunctor, rBegin, rEnd );
+
+ return aFunctor.getCount();
+ }
+
+ sal_Int32 DrawShapeSubsetting::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ return implGetNumberOfTreeNodes( maActionClassVector.begin(),
+ maActionClassVector.end(),
+ eNodeType );
+ }
+
+ namespace
+ {
+ /** This functor finds the nth occurrence of a given
+ action class.
+
+ The operator() compares the given index value with the
+ requested index, as given on the functor's
+ constructor. Then, the operator() returns false,
+ denoting that the requested action is found.
+ */
+ class FindNthElementFunctor
+ {
+ public:
+ FindNthElementFunctor( sal_Int32 nNodeIndex,
+ DrawShapeSubsetting::IndexClassificator eClass ) :
+ mnNodeIndex( nNodeIndex ),
+ meClass( eClass )
+ {
+ }
+
+ bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
+ sal_Int32 nCurrElemCount,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemEnd )
+ {
+ if( eCurrElemClassification == meClass &&
+ nCurrElemCount == mnNodeIndex )
+ {
+ maLastBegin = rCurrElemBegin;
+ maLastEnd = rCurrElemEnd;
+
+ return false; // abort iteration, we've
+ // already found what we've been
+ // looking for
+ }
+
+ return true; // keep on truckin'
+ }
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator getBeginElement() const
+ {
+ return maLastBegin;
+ }
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator getEndElement() const
+ {
+ return maLastEnd;
+ }
+
+ private:
+ sal_Int32 mnNodeIndex;
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator maLastBegin;
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator maLastEnd;
+ DrawShapeSubsetting::IndexClassificator meClass;
+ };
+
+ DocTreeNode makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rStart,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
+ DocTreeNode::NodeType eNodeType )
+ {
+ return DocTreeNode( ::std::distance(rBegin,
+ rStart),
+ ::std::distance(rBegin,
+ rEnd),
+ eNodeType );
+ }
+ }
+
+ DocTreeNode DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
+ const IndexClassificatorVector::const_iterator& rEnd,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ const IndexClassificator eRequestedClass(
+ mapDocTreeNode( eNodeType ) );
+
+ // create a nth element functor for the requested class of
+ // actions, and nNodeIndex as the target index
+ FindNthElementFunctor aFunctor( nNodeIndex,
+ eRequestedClass );
+
+ // find given index in the given range
+ iterateActionClassifications( aFunctor, rBegin, rEnd );
+
+ return makeTreeNode( maActionClassVector.begin(),
+ aFunctor.getBeginElement(),
+ aFunctor.getEndElement(),
+ eNodeType );
+ }
+
+ DocTreeNode DrawShapeSubsetting::getTreeNode( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ return implGetTreeNode( maActionClassVector.begin(),
+ maActionClassVector.end(),
+ nNodeIndex,
+ eNodeType );
+ }
+
+ sal_Int32 DrawShapeSubsetting::getNumberOfSubsetTreeNodes( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ // convert from vector indices to vector iterators
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
+
+ return implGetNumberOfTreeNodes( aParentBegin,
+ aParentEnd,
+ eNodeType );
+ }
+
+ DocTreeNode DrawShapeSubsetting::getSubsetTreeNode( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ // convert from vector indices to vector iterators
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
+
+ return implGetTreeNode( aParentBegin,
+ aParentEnd,
+ nNodeIndex,
+ eNodeType );
+ }
+
+ const VectorOfDocTreeNodes& DrawShapeSubsetting::getActiveSubsets() const
+ {
+ return maCurrentSubsets;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshapesubsetting.hxx b/slideshow/source/engine/shapes/drawshapesubsetting.hxx
new file mode 100644
index 000000000000..1dc560a9b97c
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshapesubsetting.hxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_DRAWSHAPESUBSETTING_HXX
+#define INCLUDED_SLIDESHOW_DRAWSHAPESUBSETTING_HXX
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "doctreenode.hxx"
+#include "attributableshape.hxx"
+
+
+class GDIMetaFile;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class encapsulates the subsetting aspects of a
+ DrawShape.
+ */
+ class DrawShapeSubsetting : private boost::noncopyable
+ {
+ public:
+ /** Create empty shape subset handling.
+
+ This method creates a subset handler which contains no
+ subset information. All methods will return default
+ values.
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ DrawShapeSubsetting();
+
+ /** Create new shape subset handling.
+
+ This method creates a subset handler which initially
+ displays the whole shape.
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ explicit DrawShapeSubsetting( const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+ /** Create new shape subset handling.
+
+ @param rShapeSubset
+ The subset this object represents (can be empty, then
+ denoting 'represents a whole shape')
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ DrawShapeSubsetting( const DocTreeNode& rShapeSubset,
+ const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+ /** Reset metafile.
+
+ Use this method to completely reset the
+ ShapeSubsetting, with a new metafile. Note that any
+ information previously set will be lost, including
+ added subset shapes!
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ void reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+ /** Reset metafile and subset.
+
+ Use this method to completely reset the
+ ShapeSubsetting, with a new metafile and subset
+ range. Note that any information previously set will
+ be lost, including added subset shapes!
+
+ @param rShapeSubset
+ The subset this object represents (can be empty, then
+ denoting 'represents a whole shape')
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ void reset( const DocTreeNode& rShapeSubset,
+ const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+
+ // Shape subsetting methods
+ // ========================================================
+
+ /// Return subset node for this shape
+ DocTreeNode getSubsetNode () const;
+
+ /// Return true, if any child subset shapes exist
+ bool hasSubsetShapes () const;
+
+ /// Get subset shape for given node, if any
+ AttributableShapeSharedPtr getSubsetShape ( const DocTreeNode& rTreeNode ) const;
+
+ /// Add child subset shape (or increase use count, if already existent)
+ void addSubsetShape ( const AttributableShapeSharedPtr& rShape );
+
+ /** Revoke subset shape
+
+ This method revokes a subset shape, decrementing the
+ use count for this subset by one. If the use count
+ reaches zero (i.e. when the number of addSubsetShape()
+ matches the number of revokeSubsetShape() calls for
+ the same subset), the subset entry is removed from the
+ internal list, and subsequent getSubsetShape() calls
+ will return the empty pointer for this subset.
+
+ @return true, if the subset shape was physically
+ removed from the list (false is returned, when nothing
+ was removed, either because only the use count was
+ decremented, or there was no such subset found, in the
+ first place).
+ */
+ bool revokeSubsetShape ( const AttributableShapeSharedPtr& rShape );
+
+
+ // Doc tree methods
+ // ========================================================
+
+ /// Return overall number of nodes for given type
+ sal_Int32 getNumberOfTreeNodes ( DocTreeNode::NodeType eNodeType ) const;
+
+ /// Return tree node of given index and given type
+ DocTreeNode getTreeNode ( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ /// Return number of nodes of given type, below parent node
+ sal_Int32 getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ /// Return tree node of given index and given type, relative to parent node
+ DocTreeNode getSubsetTreeNode ( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ // Helper
+ // ========================================================
+
+ /** Return a vector of currently active subsets.
+
+ Needed when rendering a shape, this method provides a
+ vector of subsets currently visible (the range as
+ returned by getEffectiveSubset(), minus the parts that
+ are currently hidden, because displayed by child
+ shapes).
+ */
+ const VectorOfDocTreeNodes& getActiveSubsets() const;
+
+ /** This enum classifies each action index in the
+ metafile.
+
+ Of interest are, of course, the places where
+ structural shape and/or text elements end. The
+ remainder of the action gets classified as 'noop'
+ */
+ enum IndexClassificator
+ {
+ CLASS_NOOP,
+ CLASS_SHAPE_START,
+ CLASS_SHAPE_END,
+
+ CLASS_LINE_END,
+ CLASS_PARAGRAPH_END,
+ CLASS_SENTENCE_END,
+ CLASS_WORD_END,
+ CLASS_CHARACTER_CELL_END
+ };
+
+ typedef ::std::vector< IndexClassificator > IndexClassificatorVector;
+
+ private:
+ /** Entry for subset shape
+
+ This struct contains data for every subset shape
+ generated. Note that for a given start/end action
+ index combination, only one subset instance is
+ generated (and reused for subsequent queries).
+ */
+ struct SubsetEntry
+ {
+ AttributableShapeSharedPtr mpShape;
+ sal_Int32 mnStartActionIndex;
+ sal_Int32 mnEndActionIndex;
+
+ /// Number of times this subset was queried, and not yet revoked
+ int mnSubsetQueriedCount;
+
+ sal_Int32 getHashValue() const
+ {
+ // TODO(Q3): That's a hack. We assume that start
+ // index will always be less than 65535 (if this
+ // assumption is violated, hash map performance
+ // will degrade severely)
+ return mnStartActionIndex*SAL_MAX_INT16 + mnEndActionIndex;
+ }
+
+ /// The shape set is ordered according to this method
+ bool operator<(const SubsetEntry& rOther) const
+ {
+ return getHashValue() < rOther.getHashValue();
+ }
+
+ };
+
+ typedef ::std::set< SubsetEntry > ShapeSet;
+
+ void ensureInitializedNodeTree() const;
+ void updateSubsetBounds( const SubsetEntry& rSubsetEntry );
+ void updateSubsets();
+ void initCurrentSubsets();
+ void reset();
+
+ sal_Int32 implGetNumberOfTreeNodes( const IndexClassificatorVector::const_iterator& rBegin,
+ const IndexClassificatorVector::const_iterator& rEnd,
+ DocTreeNode::NodeType eNodeType ) const;
+ DocTreeNode implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
+ const IndexClassificatorVector::const_iterator& rEnd,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ mutable IndexClassificatorVector maActionClassVector;
+
+ /// Metafile to retrieve subset info from
+ ::boost::shared_ptr< GDIMetaFile > mpMtf;
+
+ /// Subset of the metafile represented by this object
+ DocTreeNode maSubset;
+
+ /// the list of subset shapes spawned from this one.
+ ShapeSet maSubsetShapes;
+
+ /// caches minimal subset index from maSubsetShapes
+ sal_Int32 mnMinSubsetActionIndex;
+
+ /// caches maximal subset index from maSubsetShapes
+ sal_Int32 mnMaxSubsetActionIndex;
+
+ /** Current number of subsets to render (calculated from
+ maSubset and mnMin/MaxSubsetActionIndex).
+
+ Note that this is generally _not_ equivalent to
+ maSubset, as it excludes all active subset children!
+ */
+ mutable VectorOfDocTreeNodes maCurrentSubsets;
+
+ /// Whether the shape's doc tree has been initialized successfully, or not
+ mutable bool mbNodeTreeInitialized;
+ };
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_DRAWSHAPESUBSETTING_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/externalshapebase.cxx b/slideshow/source/engine/shapes/externalshapebase.cxx
new file mode 100644
index 000000000000..25ffa679a789
--- /dev/null
+++ b/slideshow/source/engine/shapes/externalshapebase.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include "externalshapebase.hxx"
+#include "eventmultiplexer.hxx"
+#include "vieweventhandler.hxx"
+#include "intrinsicanimationeventhandler.hxx"
+#include "tools.hxx"
+
+#include <boost/noncopyable.hpp>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class ExternalShapeBase::ExternalShapeBaseListener : public ViewEventHandler,
+ public IntrinsicAnimationEventHandler,
+ private boost::noncopyable
+ {
+ public:
+ explicit ExternalShapeBaseListener( ExternalShapeBase& rBase ) :
+ mrBase( rBase )
+ {}
+
+
+ private:
+ // ViewEventHandler
+ // -------------------------------------------------
+
+ virtual void viewAdded( const UnoViewSharedPtr& ) {}
+ virtual void viewRemoved( const UnoViewSharedPtr& ) {}
+ virtual void viewChanged( const UnoViewSharedPtr& rView )
+ {
+ mrBase.implViewChanged(rView);
+ }
+ virtual void viewsChanged()
+ {
+ mrBase.implViewsChanged();
+ }
+
+
+ // IntrinsicAnimationEventHandler
+ // -------------------------------------------------
+
+ virtual bool enableAnimations()
+ {
+ return mrBase.implStartIntrinsicAnimation();
+ }
+ virtual bool disableAnimations()
+ {
+ return mrBase.implEndIntrinsicAnimation();
+ }
+
+ ExternalShapeBase& mrBase;
+ };
+
+
+ ExternalShapeBase::ExternalShapeBase( const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ) :
+ mxComponentContext( rContext.mxComponentContext ),
+ mxShape( xShape ),
+ mpListener( new ExternalShapeBaseListener(*this) ),
+ mpShapeManager( rContext.mpSubsettableShapeManager ),
+ mrEventMultiplexer( rContext.mrEventMultiplexer ),
+ mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
+ maBounds( getAPIShapeBounds( xShape ) )
+ {
+ ENSURE_OR_THROW( mxShape.is(), "ExternalShapeBase::ExternalShapeBase(): Invalid XShape" );
+
+ mpShapeManager->addIntrinsicAnimationHandler( mpListener );
+ mrEventMultiplexer.addViewHandler( mpListener );
+ }
+
+ // ---------------------------------------------------------------------
+
+ ExternalShapeBase::~ExternalShapeBase()
+ {
+ try
+ {
+ mrEventMultiplexer.removeViewHandler( mpListener );
+ mpShapeManager->removeIntrinsicAnimationHandler( mpListener );
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ uno::Reference< drawing::XShape > ExternalShapeBase::getXShape() const
+ {
+ return mxShape;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::play()
+ {
+ implStartIntrinsicAnimation();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::stop()
+ {
+ implEndIntrinsicAnimation();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::pause()
+ {
+ implPauseIntrinsicAnimation();
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isPlaying() const
+ {
+ return implIsIntrinsicAnimationPlaying();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::setMediaTime(double fTime)
+ {
+ implSetIntrinsicAnimationTime(fTime);
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::update() const
+ {
+ return render();
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::render() const
+ {
+ if( maBounds.getRange().equalZero() )
+ {
+ // zero-sized shapes are effectively invisible,
+ // thus, we save us the rendering...
+ return true;
+ }
+
+ return implRender( maBounds );
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isContentChanged() const
+ {
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ ::basegfx::B2DRectangle ExternalShapeBase::getBounds() const
+ {
+ return maBounds;
+ }
+
+ // ---------------------------------------------------------------------
+
+ ::basegfx::B2DRectangle ExternalShapeBase::getDomBounds() const
+ {
+ return maBounds;
+ }
+
+ // ---------------------------------------------------------------------
+
+ ::basegfx::B2DRectangle ExternalShapeBase::getUpdateArea() const
+ {
+ return maBounds;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isVisible() const
+ {
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ double ExternalShapeBase::getPriority() const
+ {
+ return mnPriority;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isBackgroundDetached() const
+ {
+ // external shapes always have their own window/surface
+ return true;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/externalshapebase.hxx b/slideshow/source/engine/shapes/externalshapebase.hxx
new file mode 100644
index 000000000000..ecde71bc7b54
--- /dev/null
+++ b/slideshow/source/engine/shapes/externalshapebase.hxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_EXTERNALSHAPEBASE_HXX
+#define INCLUDED_SLIDESHOW_EXTERNALSHAPEBASE_HXX
+
+#include <vector>
+
+#include "externalmediashape.hxx"
+#include "unoview.hxx"
+#include "subsettableshapemanager.hxx"
+#include "slideshowexceptions.hxx"
+#include "slideshowcontext.hxx"
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Base class for shapes rendered by external engines.
+
+ Used as the common base for e.g. MediaShape or
+ AppletShape, all of which are rendered by external
+ components (and all employ distinct windows).
+
+ Please note that this base class indeed assumes the shape
+ does not interfere with the internal shapes in any way
+ (including mutual overdraw). It therefore reports yes for
+ the isBackgroundDetached() question.
+ */
+ class ExternalShapeBase : public ExternalMediaShape
+ {
+ public:
+ /** Create a shape for the given XShape for an external shape
+
+ @param xShape
+ The XShape to represent.
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+ */
+ ExternalShapeBase( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+ virtual ~ExternalShapeBase();
+
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > getXShape() const;
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ virtual void play();
+ virtual void stop();
+ virtual void pause();
+ virtual bool isPlaying() const;
+ virtual void setMediaTime(double);
+
+ // render methods
+ //------------------------------------------------------------------
+
+ virtual bool update() const;
+ virtual bool render() const;
+ virtual bool isContentChanged() const;
+
+
+ // Shape attributes
+ //------------------------------------------------------------------
+
+ virtual ::basegfx::B2DRectangle getBounds() const;
+ virtual ::basegfx::B2DRectangle getDomBounds() const;
+ virtual ::basegfx::B2DRectangle getUpdateArea() const;
+ virtual bool isVisible() const;
+ virtual double getPriority() const;
+ virtual bool isBackgroundDetached() const;
+
+ protected:
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext> mxComponentContext;
+
+ private:
+ class ExternalShapeBaseListener; friend class ExternalShapeBaseListener;
+
+ /// override in derived class to render preview
+ virtual bool implRender( const ::basegfx::B2DRange& rCurrBounds ) const = 0;
+
+ /// override in derived class to resize
+ virtual void implViewChanged( const UnoViewSharedPtr& rView ) = 0;
+ /// override in derived class to resize
+ virtual void implViewsChanged() = 0;
+
+ /// override in derived class to start external viewer
+ virtual bool implStartIntrinsicAnimation() = 0;
+ /// override in derived class to stop external viewer
+ virtual bool implEndIntrinsicAnimation() = 0;
+ /// override in derived class to pause external viewer
+ virtual bool implPauseIntrinsicAnimation() = 0;
+ /// override in derived class to return status of animation
+ virtual bool implIsIntrinsicAnimationPlaying() const = 0;
+ /// override in derived class to set media time
+ virtual void implSetIntrinsicAnimationTime(double) = 0;
+
+
+ /// The associated XShape
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > mxShape;
+
+ boost::shared_ptr<ExternalShapeBaseListener> mpListener;
+
+ SubsettableShapeManagerSharedPtr mpShapeManager;
+ EventMultiplexer& mrEventMultiplexer;
+
+ // The attributes of this Shape
+ const double mnPriority;
+ ::basegfx::B2DRectangle maBounds;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_EXTERNALSHAPEBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/gdimtftools.cxx b/slideshow/source/engine/shapes/gdimtftools.cxx
new file mode 100644
index 000000000000..9e914c41c088
--- /dev/null
+++ b/slideshow/source/engine/shapes/gdimtftools.cxx
@@ -0,0 +1,551 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <gdimtftools.hxx>
+
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/XGraphicRenderer.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase1.hxx>
+
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+#include <tools/stream.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/animate.hxx>
+#include <vcl/graph.hxx>
+
+#include <unotools/streamwrap.hxx>
+
+#include "tools.hxx"
+
+using namespace ::com::sun::star;
+
+
+// free support functions
+// ======================
+
+namespace slideshow
+{
+namespace internal
+{
+// TODO(E2): Detect the case when svx/drawing layer is not
+// in-process, or even not on the same machine, and
+// fallback to metafile streaming!
+
+// For fixing #i48102#, have to be a _lot_ more selective
+// on which metafiles to convert to bitmaps. The problem
+// here is that we _always_ get the shape content as a
+// metafile, even if we have a bitmap graphic shape. Thus,
+// calling GetBitmapEx on such a Graphic (see below) will
+// result in one poorly scaled bitmap into another,
+// somewhat arbitrarily sized bitmap.
+bool hasUnsupportedActions( const GDIMetaFile& rMtf )
+{
+ // search metafile for RasterOp action
+ MetaAction* pCurrAct;
+
+ // TODO(Q3): avoid const-cast
+ for( pCurrAct = const_cast<GDIMetaFile&>(rMtf).FirstAction();
+ pCurrAct;
+ pCurrAct = const_cast<GDIMetaFile&>(rMtf).NextAction() )
+ {
+ switch( pCurrAct->GetType() )
+ {
+ case META_RASTEROP_ACTION:
+ // overpaint is okay - that's the default, anyway
+ if( ROP_OVERPAINT ==
+ static_cast<MetaRasterOpAction*>(pCurrAct)->GetRasterOp() )
+ {
+ break;
+ }
+ // FALLTHROUGH intended
+ case META_MOVECLIPREGION_ACTION:
+ // FALLTHROUGH intended
+ case META_REFPOINT_ACTION:
+ // FALLTHROUGH intended
+ case META_WALLPAPER_ACTION:
+ return true; // at least one unsupported
+ // action encountered
+ }
+ }
+
+ return false; // no unsupported action found
+}
+
+namespace {
+
+typedef ::cppu::WeakComponentImplHelper1< graphic::XGraphicRenderer > DummyRenderer_Base;
+
+class DummyRenderer :
+ public DummyRenderer_Base,
+ public cppu::BaseMutex
+{
+public:
+ DummyRenderer() :
+ DummyRenderer_Base( m_aMutex ),
+ mxGraphic()
+ {
+ }
+
+ //--- XGraphicRenderer -----------------------------------
+ virtual void SAL_CALL render( const uno::Reference< graphic::XGraphic >& rGraphic ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mxGraphic = rGraphic;
+ }
+
+ /** Retrieve GDIMetaFile from renderer
+
+ @param bForeignSource
+ When true, the source of the metafile might be a
+ foreign application. The metafile is checked
+ against unsupported content, and, if necessary,
+ returned as a pre-rendererd bitmap.
+ */
+ GDIMetaFile getMtf( bool bForeignSource ) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Graphic aGraphic( mxGraphic );
+
+ if( aGraphic.GetType() == GRAPHIC_BITMAP ||
+ (bForeignSource &&
+ hasUnsupportedActions(aGraphic.GetGDIMetaFile()) ) )
+ {
+ // wrap bitmap into GDIMetafile
+ GDIMetaFile aMtf;
+ ::Point aEmptyPoint;
+
+ ::BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
+
+ aMtf.AddAction( new MetaBmpExAction( aEmptyPoint,
+ aBmpEx ) );
+ aMtf.SetPrefSize( aBmpEx.GetPrefSize() );
+ aMtf.SetPrefMapMode( aBmpEx.GetPrefMapMode() );
+
+ return aMtf;
+ }
+ else
+ {
+ return aGraphic.GetGDIMetaFile();
+ }
+ }
+
+private:
+ uno::Reference< graphic::XGraphic > mxGraphic;
+};
+
+} // anon namespace
+
+// Quick'n'dirty way: tunnel Graphic (only works for
+// in-process slideshow, of course)
+bool getMetaFile( const uno::Reference< lang::XComponent >& xSource,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& rMtf,
+ int mtfLoadFlags,
+ const uno::Reference< uno::XComponentContext >& rxContext )
+{
+ ENSURE_OR_RETURN_FALSE( rxContext.is(),
+ "getMetaFile(): Invalid context" );
+
+ // create dummy XGraphicRenderer, which receives the
+ // generated XGraphic from the GraphicExporter
+
+ // TODO(P3): Move creation of DummyRenderer out of the
+ // loop! Either by making it static, or transforming
+ // the whole thing here into a class.
+ DummyRenderer* pRenderer( new DummyRenderer() );
+ uno::Reference< graphic::XGraphicRenderer > xRenderer( pRenderer );
+
+ // -> stuff that into UnoGraphicExporter.
+ uno::Reference<lang::XMultiComponentFactory> xFactory(
+ rxContext->getServiceManager() );
+
+ OSL_ENSURE( xFactory.is(), "### no UNO?!" );
+ if( !xFactory.is() )
+ return false;
+
+ // creating the graphic exporter
+ uno::Reference< document::XExporter > xExporter(
+ xFactory->createInstanceWithContext(
+ OUSTR("com.sun.star.drawing.GraphicExportFilter"),
+ rxContext),
+ uno::UNO_QUERY );
+ uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY );
+
+ OSL_ENSURE( xExporter.is() && xFilter.is(), "### no graphic exporter?!" );
+ if( !xExporter.is() || !xFilter.is() )
+ return false;
+
+ uno::Sequence< beans::PropertyValue > aProps(3);
+ aProps[0].Name = OUSTR("FilterName");
+ aProps[0].Value <<= OUSTR("SVM");
+
+ aProps[1].Name = OUSTR("GraphicRenderer");
+ aProps[1].Value <<= xRenderer;
+
+ uno::Sequence< beans::PropertyValue > aFilterData(5);
+ aFilterData[0].Name = OUSTR("VerboseComments");
+ aFilterData[0].Value <<= ((mtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0);
+
+ aFilterData[1].Name = OUSTR("ScrollText");
+ aFilterData[1].Value <<= ((mtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != 0);
+
+ aFilterData[2].Name = OUSTR("ExportOnlyBackground");
+ aFilterData[2].Value <<= ((mtfLoadFlags & MTF_LOAD_BACKGROUND_ONLY) != 0);
+
+ aFilterData[3].Name = OUSTR("Version");
+ aFilterData[3].Value <<= static_cast<sal_Int32>( SOFFICE_FILEFORMAT_50 );
+
+ aFilterData[4].Name = OUSTR("CurrentPage");
+ aFilterData[4].Value <<= uno::Reference< uno::XInterface >( xContainingPage,
+ uno::UNO_QUERY_THROW );
+
+ aProps[2].Name = OUSTR("FilterData");
+ aProps[2].Value <<= aFilterData;
+
+ xExporter->setSourceDocument( xSource );
+ if( !xFilter->filter( aProps ) )
+ return false;
+
+ rMtf = pRenderer->getMtf( (mtfLoadFlags & MTF_LOAD_FOREIGN_SOURCE) != 0 );
+
+ // pRenderer is automatically destroyed when xRenderer
+ // goes out of scope
+
+ // TODO(E3): Error handling. Exporter might have
+ // generated nothing, a bitmap, threw an exception,
+ // whatever.
+ return true;
+}
+
+void removeTextActions( GDIMetaFile& rMtf )
+{
+ // search metafile for text output
+ MetaAction* pCurrAct;
+
+ int nActionIndex(0);
+ pCurrAct = rMtf.FirstAction();
+ while( pCurrAct )
+ {
+ switch( pCurrAct->GetType() )
+ {
+ case META_TEXTCOLOR_ACTION:
+ case META_TEXTFILLCOLOR_ACTION:
+ case META_TEXTLINECOLOR_ACTION:
+ case META_TEXTALIGN_ACTION:
+ case META_FONT_ACTION:
+ case META_LAYOUTMODE_ACTION:
+ case META_TEXT_ACTION:
+ case META_TEXTARRAY_ACTION:
+ case META_TEXTRECT_ACTION:
+ case META_STRETCHTEXT_ACTION:
+ case META_TEXTLINE_ACTION:
+ {
+ // remove every text-related actions
+ pCurrAct = rMtf.NextAction();
+
+ rMtf.RemoveAction( nActionIndex );
+ break;
+ }
+
+ default:
+ pCurrAct = rMtf.NextAction();
+ ++nActionIndex;
+ break;
+ }
+ }
+}
+
+sal_Int32 getNextActionOffset( MetaAction * pCurrAct )
+{
+ // Special handling for actions that represent
+ // more than one indexable action
+ // ===========================================
+
+ switch (pCurrAct->GetType()) {
+ case META_TEXT_ACTION: {
+ MetaTextAction * pAct = static_cast<MetaTextAction *>(pCurrAct);
+ return (pAct->GetLen() == (sal_uInt16)STRING_LEN
+ ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
+ }
+ case META_TEXTARRAY_ACTION: {
+ MetaTextArrayAction * pAct =
+ static_cast<MetaTextArrayAction *>(pCurrAct);
+ return (pAct->GetLen() == (sal_uInt16)STRING_LEN
+ ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
+ }
+ case META_STRETCHTEXT_ACTION: {
+ MetaStretchTextAction * pAct =
+ static_cast<MetaStretchTextAction *>(pCurrAct);
+ return (pAct->GetLen() == (sal_uInt16)STRING_LEN
+ ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
+ }
+ case META_FLOATTRANSPARENT_ACTION: {
+ MetaFloatTransparentAction * pAct =
+ static_cast<MetaFloatTransparentAction*>(pCurrAct);
+ // TODO(F2): Recurse into action metafile
+ // (though this is currently not used from the
+ // DrawingLayer - shape transparency gradients
+ // don't affect shape text)
+ return pAct->GetGDIMetaFile().GetActionCount();
+ }
+ default:
+ return 1;
+ }
+}
+
+bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames,
+ ::std::size_t& o_rLoopCount,
+ CycleMode& o_eCycleMode,
+ const Graphic& rGraphic )
+{
+ o_rFrames.clear();
+
+ if( !rGraphic.IsAnimated() )
+ return false;
+
+ // some loop invariants
+ Animation aAnimation( rGraphic.GetAnimation() );
+ const Point aEmptyPoint;
+ const Size aAnimSize( aAnimation.GetDisplaySizePixel() );
+
+ // setup VDev, into which all bitmaps are painted (want to
+ // normalize animations to n bitmaps of same size. An Animation,
+ // though, can contain bitmaps of varying sizes and different
+ // update modes)
+ VirtualDevice aVDev;
+ aVDev.SetOutputSizePixel( aAnimSize );
+ aVDev.EnableMapMode( sal_False );
+
+ // setup mask VDev (alpha VDev is currently rather slow)
+ VirtualDevice aVDevMask;
+ aVDevMask.SetOutputSizePixel( aAnimSize );
+ aVDevMask.EnableMapMode( sal_False );
+
+ switch( aAnimation.GetCycleMode() )
+ {
+ case CYCLE_NOT:
+ o_rLoopCount = 1;
+ o_eCycleMode = CYCLE_LOOP;
+ break;
+
+ case CYCLE_FALLBACK:
+ // FALLTHROUGH intended
+ case CYCLE_NORMAL:
+ o_rLoopCount = aAnimation.GetLoopCount();
+ o_eCycleMode = CYCLE_LOOP;
+ break;
+
+ case CYCLE_REVERS:
+ // FALLTHROUGH intended
+ case CYCLE_REVERS_FALLBACK:
+ o_rLoopCount = aAnimation.GetLoopCount();
+ o_eCycleMode = CYCLE_PINGPONGLOOP;
+ break;
+
+ default:
+ ENSURE_OR_RETURN_FALSE(false,
+ "getAnimationFromGraphic(): Unexpected case" );
+ break;
+ }
+
+ for( sal_uInt16 i=0, nCount=aAnimation.Count(); i<nCount; ++i )
+ {
+ const AnimationBitmap& rAnimBmp( aAnimation.Get(i) );
+ switch(rAnimBmp.eDisposal)
+ {
+ case DISPOSE_NOT:
+ {
+ aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx);
+ Bitmap aMask = rAnimBmp.aBmpEx.GetMask();
+
+ if( aMask.IsEmpty() )
+ {
+ const Point aEmpty;
+ const Rectangle aRect(aEmptyPoint,
+ aVDevMask.GetOutputSizePixel());
+ const Wallpaper aWallpaper(COL_BLACK);
+ aVDevMask.DrawWallpaper(aRect,
+ aWallpaper);
+ }
+ else
+ {
+ BitmapEx aTmpMask = BitmapEx(aMask,
+ aMask);
+ aVDevMask.DrawBitmapEx(rAnimBmp.aPosPix,
+ aTmpMask );
+ }
+ break;
+ }
+
+ case DISPOSE_BACK:
+ {
+ // #i70772# react on no mask
+ const Bitmap aMask(rAnimBmp.aBmpEx.GetMask());
+ const Bitmap aContent(rAnimBmp.aBmpEx.GetBitmap());
+
+ aVDevMask.Erase();
+ aVDev.DrawBitmap(rAnimBmp.aPosPix, aContent);
+
+ if(aMask.IsEmpty())
+ {
+ const Rectangle aRect(rAnimBmp.aPosPix, aContent.GetSizePixel());
+ aVDevMask.SetFillColor(COL_BLACK);
+ aVDevMask.SetLineColor();
+ aVDevMask.DrawRect(aRect);
+ }
+ else
+ {
+ aVDevMask.DrawBitmap(rAnimBmp.aPosPix, aMask);
+ }
+ break;
+ }
+
+ case DISPOSE_FULL:
+ {
+ aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx);
+ break;
+ }
+
+ case DISPOSE_PREVIOUS :
+ {
+ aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx);
+ aVDevMask.DrawBitmap(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx.GetMask());
+ break;
+ }
+ }
+
+ // extract current aVDev content into a new animation
+ // frame
+ GDIMetaFileSharedPtr pMtf( new GDIMetaFile() );
+ pMtf->AddAction(
+ new MetaBmpExAction( aEmptyPoint,
+ BitmapEx(
+ aVDev.GetBitmap(
+ aEmptyPoint,
+ aAnimSize ),
+ aVDevMask.GetBitmap(
+ aEmptyPoint,
+ aAnimSize ))));
+
+ // setup mtf dimensions and pref map mode (for
+ // simplicity, keep it all in pixel. the metafile
+ // renderer scales it down to (1, 1) box anyway)
+ pMtf->SetPrefMapMode( MapMode() );
+ pMtf->SetPrefSize( aAnimSize );
+
+ // Take care of special value for MultiPage TIFFs. ATM these shall just
+ // show their first page for _quite_ some time.
+ sal_Int32 nWaitTime100thSeconds( rAnimBmp.nWait );
+ if( ANIMATION_TIMEOUT_ON_CLICK == nWaitTime100thSeconds )
+ {
+ // ATM the huge value would block the timer, so use a long
+ // time to show first page (whole day)
+ nWaitTime100thSeconds = 100 * 60 * 60 * 24;
+ }
+
+ // There are animated GIFs with no WaitTime set. Take 0.1 sec, the
+ // same duration that is used by the edit view.
+ if( nWaitTime100thSeconds == 0 )
+ nWaitTime100thSeconds = 10;
+
+ o_rFrames.push_back( MtfAnimationFrame( pMtf,
+ nWaitTime100thSeconds / 100.0 ) );
+ }
+
+ return !o_rFrames.empty();
+}
+
+bool getRectanglesFromScrollMtf( ::basegfx::B2DRectangle& o_rScrollRect,
+ ::basegfx::B2DRectangle& o_rPaintRect,
+ const GDIMetaFileSharedPtr& rMtf )
+{
+ // extract bounds: scroll rect, paint rect
+ bool bScrollRectSet(false);
+ bool bPaintRectSet(false);
+
+ for ( MetaAction * pCurrAct = rMtf->FirstAction();
+ pCurrAct != 0; pCurrAct = rMtf->NextAction() )
+ {
+ if (pCurrAct->GetType() == META_COMMENT_ACTION)
+ {
+ MetaCommentAction * pAct =
+ static_cast<MetaCommentAction *>(pCurrAct);
+ // skip comment if not a special XTEXT comment
+ if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ RTL_CONSTASCII_STRINGPARAM("XTEXT") ) == COMPARE_EQUAL)
+ {
+ if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ "XTEXT_SCROLLRECT" ) == COMPARE_EQUAL) {
+ o_rScrollRect = ::vcl::unotools::b2DRectangleFromRectangle(
+ *reinterpret_cast<Rectangle const *>(
+ pAct->GetData() ) );
+
+ bScrollRectSet = true;
+ }
+ else if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ "XTEXT_PAINTRECT" ) == COMPARE_EQUAL) {
+ o_rPaintRect = ::vcl::unotools::b2DRectangleFromRectangle(
+ *reinterpret_cast<Rectangle const *>(
+ pAct->GetData() ) );
+
+ bPaintRectSet = true;
+ }
+ }
+ }
+ }
+
+ return bScrollRectSet && bPaintRectSet;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/gdimtftools.hxx b/slideshow/source/engine/shapes/gdimtftools.hxx
new file mode 100644
index 000000000000..072880739e14
--- /dev/null
+++ b/slideshow/source/engine/shapes/gdimtftools.hxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_GDIMTFTOOLS_HXX
+#define INCLUDED_SLIDESHOW_GDIMTFTOOLS_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <boost/shared_ptr.hpp>
+
+#include "tools.hxx"
+
+#include <vector>
+
+class MetaAction;
+class GDIMetaFile;
+class Graphic;
+
+// -----------------------------------------------------------------------------
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /// meta file loading specialities:
+ enum mtf_load_flags {
+ /// no flags
+ MTF_LOAD_NONE = 0,
+ /// annotate text actions with verbose comments,
+ /// denoting logical and physical text entities.
+ MTF_LOAD_VERBOSE_COMMENTS = 1,
+ /// the source of the metafile might be a foreign
+ /// application. The metafile is checked against unsupported
+ /// content, and, if necessary, returned as a pre-rendererd
+ /// bitmap.
+ MTF_LOAD_FOREIGN_SOURCE = 2,
+ /// retrieve a meta file for the page background only
+ MTF_LOAD_BACKGROUND_ONLY = 4,
+ /// retrieve the drawing layer scroll text metafile
+ MTF_LOAD_SCROLL_TEXT_MTF = 8
+ };
+
+ // Animation info
+ // ==============
+
+ struct MtfAnimationFrame
+ {
+ MtfAnimationFrame( const GDIMetaFileSharedPtr& rMtf,
+ double nDuration ) :
+ mpMtf( rMtf ),
+ mnDuration( nDuration )
+ {
+ }
+
+ /// Enables STL algos to be used for duration extraction
+ double getDuration() const
+ {
+ return mnDuration;
+ }
+
+ GDIMetaFileSharedPtr mpMtf;
+ double mnDuration;
+ };
+
+ typedef ::std::vector< MtfAnimationFrame > VectorOfMtfAnimationFrames;
+
+
+ /** Retrieve a meta file for the given shape
+
+ @param xShape
+ XShape to retrieve a metafile for.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param o_rMtf
+ Metafile to extract shape content into
+ */
+ bool getMetaFile( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xSource,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& o_rMtf,
+ int mtfLoadFlags,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext >& rxContext );
+
+ /** Remove all text actions from the given metafile.
+ */
+ void removeTextActions( GDIMetaFile& io_rMtf );
+
+ /** Gets the next action offset for iterating meta actions which is most
+ often returns 1.
+ */
+ sal_Int32 getNextActionOffset( MetaAction * pCurrAct );
+
+ /** Extract a vector of animation frames from given Graphic.
+
+ @param o_rFrames
+ Resulting vector of animated metafiles
+
+ @param o_rLoopCount
+ Number of times the bitmap animation shall be repeated
+
+ @param o_eCycleMode
+ Repeat mode (normal, or ping-pong mode)
+
+ @param rGraphic
+ Input graphic object, to extract animations from
+ */
+ bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames,
+ ::std::size_t& o_rLoopCount,
+ CycleMode& o_eCycleMode,
+ const Graphic& rGraphic );
+
+ /** Retrieve scroll text animation rectangles from given metafile
+
+ @return true, if both rectangles have been found, false
+ otherwise.
+ */
+ bool getRectanglesFromScrollMtf( ::basegfx::B2DRectangle& o_rScrollRect,
+ ::basegfx::B2DRectangle& o_rPaintRect,
+ const GDIMetaFileSharedPtr& rMtf );
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_GDIMTFTOOLS_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/intrinsicanimationactivity.cxx b/slideshow/source/engine/shapes/intrinsicanimationactivity.cxx
new file mode 100644
index 000000000000..fb5179545821
--- /dev/null
+++ b/slideshow/source/engine/shapes/intrinsicanimationactivity.cxx
@@ -0,0 +1,293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include "drawshapesubsetting.hxx"
+#include "subsettableshapemanager.hxx"
+#include "eventqueue.hxx"
+#include "eventmultiplexer.hxx"
+#include "intrinsicanimationactivity.hxx"
+#include "intrinsicanimationeventhandler.hxx"
+
+#include <boost/noncopyable.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/weak_ptr.hpp>
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Activity for intrinsic shape animations
+
+ This is an Activity interface implementation for intrinsic
+ shape animations. Intrinsic shape animations are
+ animations directly within a shape, e.g. drawing layer
+ animations, or GIF animations.
+ */
+ class IntrinsicAnimationActivity : public Activity,
+ public boost::enable_shared_from_this<IntrinsicAnimationActivity>,
+ private boost::noncopyable
+ {
+ public:
+ /** Create an IntrinsicAnimationActivity.
+
+ @param rContext
+ Common slideshow objects
+
+ @param rDrawShape
+ Shape to control the intrinsic animation for
+
+ @param rWakeupEvent
+ Externally generated wakeup event, to set this
+ activity to sleep during inter-frame intervals. Must
+ come frome the outside, since wakeup event and this
+ object have mutual references to each other.
+
+ @param rTimeouts
+ Vector of timeout values, to wait before the next
+ frame is shown.
+ */
+ IntrinsicAnimationActivity( const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode );
+
+ virtual void dispose();
+ virtual double calcTimeLag() const;
+ virtual bool perform();
+ virtual bool isActive() const;
+ virtual void dequeued();
+ virtual void end();
+
+ bool enableAnimations();
+
+ private:
+ SlideShowContext maContext;
+ boost::weak_ptr<DrawShape> mpDrawShape;
+ WakeupEventSharedPtr mpWakeupEvent;
+ IntrinsicAnimationEventHandlerSharedPtr mpListener;
+ ::std::vector<double> maTimeouts;
+ CycleMode meCycleMode;
+ ::std::size_t mnCurrIndex;
+ ::std::size_t mnNumLoops;
+ ::std::size_t mnLoopCount;
+ bool mbIsActive;
+ };
+
+ //////////////////////////////////////////////////////////////////////
+
+ class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler,
+ private boost::noncopyable
+ {
+ public:
+ explicit IntrinsicAnimationListener( IntrinsicAnimationActivity& rActivity ) :
+ mrActivity( rActivity )
+ {}
+
+ private:
+
+ virtual bool enableAnimations() { return mrActivity.enableAnimations(); }
+ virtual bool disableAnimations() { mrActivity.end(); return true; }
+
+ IntrinsicAnimationActivity& mrActivity;
+ };
+
+ //////////////////////////////////////////////////////////////////////
+
+ IntrinsicAnimationActivity::IntrinsicAnimationActivity( const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode ) :
+ maContext( rContext ),
+ mpDrawShape( rDrawShape ),
+ mpWakeupEvent( rWakeupEvent ),
+ mpListener( new IntrinsicAnimationListener(*this) ),
+ maTimeouts( rTimeouts ),
+ meCycleMode( eCycleMode ),
+ mnCurrIndex(0),
+ mnNumLoops(nNumLoops),
+ mnLoopCount(0),
+ mbIsActive(false)
+ {
+ ENSURE_OR_THROW( rContext.mpSubsettableShapeManager,
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid shape manager" );
+ ENSURE_OR_THROW( rDrawShape,
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid draw shape" );
+ ENSURE_OR_THROW( rWakeupEvent,
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid wakeup event" );
+ ENSURE_OR_THROW( !rTimeouts.empty(),
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Empty timeout vector" );
+
+ maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
+ mpListener );
+ }
+
+ void IntrinsicAnimationActivity::dispose()
+ {
+ end();
+
+ if( mpWakeupEvent )
+ mpWakeupEvent->dispose();
+
+ maContext.dispose();
+ mpDrawShape.reset();
+ mpWakeupEvent.reset();
+ maTimeouts.clear();
+ mnCurrIndex = 0;
+
+ maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
+ mpListener );
+ }
+
+ double IntrinsicAnimationActivity::calcTimeLag() const
+ {
+ return 0.0;
+ }
+
+ bool IntrinsicAnimationActivity::perform()
+ {
+ if( !isActive() )
+ return false;
+
+ DrawShapeSharedPtr pDrawShape( mpDrawShape.lock() );
+ if( !pDrawShape || !mpWakeupEvent )
+ {
+ // event or draw shape vanished, no sense living on ->
+ // commit suicide.
+ dispose();
+ return false;
+ }
+
+ // mnNumLoops == 0 means infinite looping
+ if( mnNumLoops != 0 &&
+ mnLoopCount >= mnNumLoops )
+ {
+ // #i55294# After finishing the loops, display the first frame
+ pDrawShape->setIntrinsicAnimationFrame( 0 );
+ maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape );
+
+ end();
+
+ return false;
+ }
+
+ ::std::size_t nNewIndex = 0;
+ const ::std::size_t nNumFrames(maTimeouts.size());
+ switch( meCycleMode )
+ {
+ case CYCLE_LOOP:
+ {
+ pDrawShape->setIntrinsicAnimationFrame( mnCurrIndex );
+
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout( maTimeouts[mnCurrIndex] );
+
+ mnLoopCount += (mnCurrIndex + 1) / nNumFrames;
+ nNewIndex = (mnCurrIndex + 1) % nNumFrames;
+ break;
+ }
+
+ case CYCLE_PINGPONGLOOP:
+ {
+ ::std::size_t nTrueIndex( mnCurrIndex < nNumFrames ?
+ mnCurrIndex :
+ 2*nNumFrames - mnCurrIndex - 1 );
+ pDrawShape->setIntrinsicAnimationFrame( nTrueIndex );
+
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout( maTimeouts[nTrueIndex] );
+
+ mnLoopCount += (mnCurrIndex + 1) / (2*nNumFrames);
+ nNewIndex = (mnCurrIndex + 1) % 2*nNumFrames;
+ break;
+ }
+ }
+
+ maContext.mrEventQueue.addEvent( mpWakeupEvent );
+ maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape );
+ mnCurrIndex = nNewIndex;
+
+ return false; // don't reinsert, WakeupEvent will perform
+ // that after the given timeout
+ }
+
+ bool IntrinsicAnimationActivity::isActive() const
+ {
+ return mbIsActive;
+ }
+
+ void IntrinsicAnimationActivity::dequeued()
+ {
+ // not used here
+ }
+
+ void IntrinsicAnimationActivity::end()
+ {
+ // there is no dedicated end state, just become inactive:
+ mbIsActive = false;
+ }
+
+ bool IntrinsicAnimationActivity::enableAnimations()
+ {
+ mbIsActive = true;
+ return maContext.mrActivitiesQueue.addActivity(
+ shared_from_this() );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+
+ ActivitySharedPtr createIntrinsicAnimationActivity(
+ const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode )
+ {
+ return ActivitySharedPtr(
+ new IntrinsicAnimationActivity(rContext,
+ rDrawShape,
+ rWakeupEvent,
+ rTimeouts,
+ nNumLoops,
+ eCycleMode) );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/intrinsicanimationactivity.hxx b/slideshow/source/engine/shapes/intrinsicanimationactivity.hxx
new file mode 100644
index 000000000000..a48ae8f1117e
--- /dev/null
+++ b/slideshow/source/engine/shapes/intrinsicanimationactivity.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_INTRINSICANIMATIONACTIVITY_HXX
+#define INCLUDED_SLIDESHOW_INTRINSICANIMATIONACTIVITY_HXX
+
+#include "wakeupevent.hxx"
+#include "activity.hxx"
+#include "slideshowcontext.hxx"
+#include "drawshape.hxx"
+#include "tools.hxx"
+
+/* Definition of IntrinsicAnimationActivity class */
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Create an IntrinsicAnimationActivity.
+
+ This is an Activity interface implementation for intrinsic
+ shape animations. Intrinsic shape animations are
+ animations directly within a shape, e.g. drawing layer
+ animations, or GIF animations.
+
+ @param rContext
+ Common slideshow objects
+
+ @param rDrawShape
+ Shape to control the intrinsic animation for
+
+ @param rWakeupEvent
+ Externally generated wakeup event, to set this
+ activity to sleep during inter-frame intervals. Must
+ come frome the outside, since wakeup event and this
+ object have mutual references to each other.
+
+ @param rTimeouts
+ Vector of timeout values, to wait before the next
+ frame is shown.
+ */
+ ActivitySharedPtr createIntrinsicAnimationActivity(
+ const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode );
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_INTRINSICANIMATIONACTIVITY_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/makefile.mk b/slideshow/source/engine/shapes/makefile.mk
new file mode 100644
index 000000000000..1d40c165707c
--- /dev/null
+++ b/slideshow/source/engine/shapes/makefile.mk
@@ -0,0 +1,60 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=slideshow
+TARGET=shapes
+ENABLE_EXCEPTIONS=TRUE
+PRJINC=..$/..
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = $(SLO)$/appletshape.obj \
+ $(SLO)$/backgroundshape.obj \
+ $(SLO)$/drawinglayeranimation.obj \
+ $(SLO)$/drawshape.obj \
+ $(SLO)$/drawshapesubsetting.obj \
+ $(SLO)$/externalshapebase.obj \
+ $(SLO)$/gdimtftools.obj \
+ $(SLO)$/intrinsicanimationactivity.obj \
+ $(SLO)$/mediashape.obj \
+ $(SLO)$/shapeimporter.obj \
+ $(SLO)$/viewappletshape.obj \
+ $(SLO)$/viewbackgroundshape.obj \
+ $(SLO)$/viewmediashape.obj \
+ $(SLO)$/viewshape.obj
+
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/shapes/mediashape.cxx b/slideshow/source/engine/shapes/mediashape.cxx
new file mode 100644
index 000000000000..9bcf66a030f6
--- /dev/null
+++ b/slideshow/source/engine/shapes/mediashape.cxx
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include "mediashape.hxx"
+#include "viewmediashape.hxx"
+#include "externalshapebase.hxx"
+#include "slideshowcontext.hxx"
+#include "shape.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Represents a media shape.
+
+ This implementation offers support for media shapes.
+ Such shapes need special treatment.
+ */
+ class MediaShape : public ExternalShapeBase
+ {
+ public:
+ /** Create a shape for the given XShape for a media object
+
+ @param xShape
+ The XShape to represent.
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+ */
+ MediaShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ private:
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+
+ // ExternalShapeBase methods
+ //------------------------------------------------------------------
+
+ virtual bool implRender( const ::basegfx::B2DRange& rCurrBounds ) const;
+ virtual void implViewChanged( const UnoViewSharedPtr& rView );
+ virtual void implViewsChanged();
+ virtual bool implStartIntrinsicAnimation();
+ virtual bool implEndIntrinsicAnimation();
+ virtual bool implPauseIntrinsicAnimation();
+ virtual bool implIsIntrinsicAnimationPlaying() const;
+ virtual void implSetIntrinsicAnimationTime(double);
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewMediaShapeSharedPtr > ViewMediaShapeVector;
+ ViewMediaShapeVector maViewMediaShapes;
+ bool mbIsPlaying;
+ };
+
+
+ MediaShape::MediaShape( const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ) :
+ ExternalShapeBase( xShape, nPrio, rContext ),
+ maViewMediaShapes(),
+ mbIsPlaying(false)
+ {
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::implViewChanged( const UnoViewSharedPtr& rView )
+ {
+ // determine ViewMediaShape that needs update
+ ViewMediaShapeVector::const_iterator aIter(maViewMediaShapes.begin());
+ ViewMediaShapeVector::const_iterator const aEnd (maViewMediaShapes.end());
+ while( aIter != aEnd )
+ {
+ if( (*aIter)->getViewLayer()->isOnView(rView) )
+ (*aIter)->resize(getBounds());
+
+ ++aIter;
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::implViewsChanged()
+ {
+ // resize all ViewShapes
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::bind(
+ &ViewMediaShape::resize,
+ _1,
+ ::boost::cref( getBounds())) );
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ maViewMediaShapes.push_back(
+ ViewMediaShapeSharedPtr( new ViewMediaShape( rNewLayer,
+ getXShape(),
+ mxComponentContext )));
+
+ // push new size to view shape
+ maViewMediaShapes.back()->resize( getBounds() );
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ maViewMediaShapes.back()->render( getBounds() );
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewMediaShapeVector::iterator aEnd( maViewMediaShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewMediaShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewMediaShape::getViewLayer, _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "MediaShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewMediaShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewMediaShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewMediaShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewMediaShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::clearAllViewLayers()
+ {
+ maViewMediaShapes.clear();
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implRender( const ::basegfx::B2DRange& rCurrBounds ) const
+ {
+ // redraw all view shapes, by calling their update() method
+ if( ::std::count_if( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::bind<bool>(
+ ::boost::mem_fn( &ViewMediaShape::render ),
+ _1,
+ ::boost::cref( rCurrBounds ) ) )
+ != static_cast<ViewMediaShapeVector::difference_type>(maViewMediaShapes.size()) )
+ {
+ // at least one of the ViewShape::update() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implStartIntrinsicAnimation()
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::mem_fn( &ViewMediaShape::startMedia ) );
+
+ mbIsPlaying = true;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implEndIntrinsicAnimation()
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::mem_fn( &ViewMediaShape::endMedia ) );
+
+ mbIsPlaying = false;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implPauseIntrinsicAnimation()
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::mem_fn( &ViewMediaShape::pauseMedia ) );
+
+ mbIsPlaying = false;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implIsIntrinsicAnimationPlaying() const
+ {
+ return mbIsPlaying;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::implSetIntrinsicAnimationTime(double fTime)
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::bind( &ViewMediaShape::setMediaTime,
+ _1, boost::cref(fTime)) );
+ }
+
+ // ---------------------------------------------------------------------
+
+ ShapeSharedPtr createMediaShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext)
+ {
+ boost::shared_ptr< MediaShape > pMediaShape(
+ new MediaShape(xShape, nPrio, rContext));
+
+ return pMediaShape;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/mediashape.hxx b/slideshow/source/engine/shapes/mediashape.hxx
new file mode 100644
index 000000000000..babe30e8b122
--- /dev/null
+++ b/slideshow/source/engine/shapes/mediashape.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_MEDIASHAPE_HXX
+#define INCLUDED_SLIDESHOW_MEDIASHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <boost/shared_ptr.hpp>
+
+
+namespace com { namespace sun { namespace star { namespace drawing
+{
+ class XShape;
+} } } }
+
+namespace slideshow
+{
+ namespace internal
+ {
+ struct SlideShowContext;
+ class Shape;
+
+ boost::shared_ptr<Shape> createMediaShape(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext);
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_MEDIASHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/shapeimporter.cxx b/slideshow/source/engine/shapes/shapeimporter.cxx
new file mode 100644
index 000000000000..5971082a4242
--- /dev/null
+++ b/slideshow/source/engine/shapes/shapeimporter.cxx
@@ -0,0 +1,672 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/stream.hxx>
+#include <svtools/grfmgr.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <cppcanvas/polypolygon.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/drawing/XLayerSupplier.hpp>
+#include <com/sun/star/drawing/XLayerManager.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+
+#include "drawshapesubsetting.hxx"
+#include "drawshape.hxx"
+#include "backgroundshape.hxx"
+#include "mediashape.hxx"
+#include "appletshape.hxx"
+#include "shapeimporter.hxx"
+#include "slideshowexceptions.hxx"
+#include "gdimtftools.hxx"
+#include "tools.hxx"
+#include "slideshowcontext.hxx"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+
+using namespace com::sun::star;
+using namespace ::comphelper;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+bool importShapeGraphic(
+ GraphicObject & o_rGraphic,
+ uno::Reference<beans::XPropertySet> const& xPropSet )
+{
+ rtl::OUString aURL;
+ if( !getPropertyValue( aURL, xPropSet, OUSTR("GraphicURL")) ||
+ aURL.getLength() == 0 )
+ {
+ // no or empty property - cannot import shape graphic
+ return false;
+ }
+
+ rtl::OUString const aVndUrl(
+ RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.GraphicObject:" ) );
+ sal_Int32 nIndex( aURL.indexOf( aVndUrl ) );
+
+ if(nIndex != -1)
+ {
+ // skip past the end of the "vnd..." prefix
+ nIndex += aVndUrl.getLength();
+
+ if(nIndex >= aURL.getLength())
+ {
+ OSL_FAIL( "ShapeImporter::importShape(): "
+ "embedded graphic has no graphic ID" );
+ return false;
+ }
+
+ // unique ID string found in URL, extract
+ // to separate string
+ rtl::OUString const aUniqueId(
+ aURL.copy( nIndex, aURL.getLength() - nIndex ) );
+
+ // TODO(T2): Creating a GraphicObject is not
+ // thread safe (internally calls VCL, and has
+ // unguarded internal singleton mpGlobalMgr)
+
+ // fetch already loaded graphic from graphic manager.
+ ByteString const aOldString( static_cast<String>(aUniqueId),
+ RTL_TEXTENCODING_UTF8 );
+ o_rGraphic = GraphicObject( aOldString );
+
+
+ if( GRAPHIC_DEFAULT == o_rGraphic.GetType()
+ || GRAPHIC_NONE == o_rGraphic.GetType() )
+ {
+ // even the GrfMgr does not seem to know this graphic
+ return false;
+ }
+ }
+ else
+ {
+ // no special string found, graphic must be
+ // external. Load via GraphicIm porter
+ INetURLObject aTmp( aURL );
+ boost::scoped_ptr<SvStream> pGraphicStream(
+ utl::UcbStreamHelper::CreateStream(
+ aTmp.GetMainURL( INetURLObject::NO_DECODE ),
+ STREAM_READ ) );
+ if( !pGraphicStream )
+ {
+ OSL_FAIL( "ShapeImporter::importShape(): "
+ "cannot create input stream for graphic" );
+ return false;
+ }
+
+ Graphic aTmpGraphic;
+ if( GraphicConverter::Import(
+ *pGraphicStream, aTmpGraphic ) != ERRCODE_NONE )
+ {
+ OSL_FAIL( "ShapeImporter::importShape(): "
+ "Failed to import shape graphic from given URL" );
+ return false;
+ }
+
+ o_rGraphic = GraphicObject( aTmpGraphic );
+ }
+ return true;
+}
+
+/** This shape implementation just acts as a dummy for the layermanager.
+ Its sole role is for hit test detection of group shapes.
+*/
+class ShapeOfGroup : public Shape
+{
+public:
+ ShapeOfGroup( ShapeSharedPtr const& pGroupShape,
+ uno::Reference<drawing::XShape> const& xShape,
+ uno::Reference<beans::XPropertySet> const& xPropSet,
+ double nPrio );
+
+ // Shape:
+ virtual uno::Reference<drawing::XShape> getXShape() const;
+ virtual void addViewLayer( ViewLayerSharedPtr const& pNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( ViewLayerSharedPtr const& pNewLayer );
+ virtual bool clearAllViewLayers();
+ virtual bool update() const;
+ virtual bool render() const;
+ virtual bool isContentChanged() const;
+ virtual basegfx::B2DRectangle getBounds() const;
+ virtual basegfx::B2DRectangle getDomBounds() const;
+ virtual basegfx::B2DRectangle getUpdateArea() const;
+ virtual bool isVisible() const;
+ virtual double getPriority() const;
+ virtual bool isBackgroundDetached() const;
+
+private:
+ ShapeSharedPtr const mpGroupShape;
+ uno::Reference<drawing::XShape> const mxShape;
+ double const mnPrio;
+ basegfx::B2DPoint maPosOffset;
+ double mnWidth;
+ double mnHeight;
+};
+
+ShapeOfGroup::ShapeOfGroup( ShapeSharedPtr const& pGroupShape,
+ uno::Reference<drawing::XShape> const& xShape,
+ uno::Reference<beans::XPropertySet> const& xPropSet,
+ double nPrio ) :
+ mpGroupShape(pGroupShape),
+ mxShape(xShape),
+ mnPrio(nPrio)
+{
+ // read bound rect
+ uno::Any const aTmpRect_( xPropSet->getPropertyValue( OUSTR("BoundRect") ));
+ awt::Rectangle const aTmpRect( aTmpRect_.get<awt::Rectangle>() );
+ basegfx::B2DRectangle const groupPosSize( pGroupShape->getBounds() );
+ maPosOffset = basegfx::B2DPoint( aTmpRect.X - groupPosSize.getMinX(),
+ aTmpRect.Y - groupPosSize.getMinY() );
+ mnWidth = aTmpRect.Width;
+ mnHeight = aTmpRect.Height;
+}
+
+uno::Reference<drawing::XShape> ShapeOfGroup::getXShape() const
+{
+ return mxShape;
+}
+
+void ShapeOfGroup::addViewLayer( ViewLayerSharedPtr const& /*pNewLayer*/,
+ bool /*bRedrawLayer*/ )
+{
+}
+
+bool ShapeOfGroup::removeViewLayer( ViewLayerSharedPtr const& /*pNewLayer*/ )
+{
+ return true;
+}
+
+bool ShapeOfGroup::clearAllViewLayers()
+{
+ return true;
+}
+
+bool ShapeOfGroup::update() const
+{
+ return true;
+}
+
+bool ShapeOfGroup::render() const
+{
+ return true;
+}
+
+bool ShapeOfGroup::isContentChanged() const
+{
+ return false;
+}
+
+basegfx::B2DRectangle ShapeOfGroup::getBounds() const
+{
+ basegfx::B2DRectangle const groupPosSize( mpGroupShape->getBounds() );
+ double const posX = (groupPosSize.getMinX() + maPosOffset.getX());
+ double const posY = (groupPosSize.getMinY() + maPosOffset.getY());
+ return basegfx::B2DRectangle( posX, posY, posX + mnWidth, posY + mnHeight );
+}
+
+basegfx::B2DRectangle ShapeOfGroup::getDomBounds() const
+{
+ return getBounds();
+}
+
+basegfx::B2DRectangle ShapeOfGroup::getUpdateArea() const
+{
+ return getBounds();
+}
+
+bool ShapeOfGroup::isVisible() const
+{
+ return mpGroupShape->isVisible();
+}
+
+double ShapeOfGroup::getPriority() const
+{
+ return mnPrio;
+}
+
+bool ShapeOfGroup::isBackgroundDetached() const
+{
+ return false;
+}
+
+} // anon namespace
+
+ShapeSharedPtr ShapeImporter::createShape(
+ uno::Reference<drawing::XShape> const& xCurrShape,
+ uno::Reference<beans::XPropertySet> const& xPropSet,
+ rtl::OUString const& shapeType ) const
+{
+ if( shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.MediaShape") ) ||
+ shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.MediaShape") ) )
+ {
+ // Media shape (video etc.). This is a special object
+ return createMediaShape(xCurrShape,
+ mnAscendingPrio,
+ mrContext);
+ }
+ else if( shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.PluginShape") ))
+ {
+ // PropertyValues to copy from XShape to plugin
+ static const char* aPropertyValues[] =
+ {
+ "PluginURL",
+ "PluginMimeType",
+ "PluginCommands"
+ };
+
+ // (Netscape)Plugin shape. This is a special object
+ return createAppletShape( xCurrShape,
+ mnAscendingPrio,
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.comp.sfx2.PluginObject" )),
+ aPropertyValues,
+ sizeof(aPropertyValues)/sizeof(*aPropertyValues),
+ mrContext );
+ }
+ else if( shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.AppletShape") ))
+ {
+ // PropertyValues to copy from XShape to applet
+ static const char* aPropertyValues[] =
+ {
+ "AppletCodeBase",
+ "AppletName",
+ "AppletCode",
+ "AppletCommands",
+ "AppletIsScript"
+ };
+
+ // (Java)Applet shape. This is a special object
+ return createAppletShape( xCurrShape,
+ mnAscendingPrio,
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.comp.sfx2.AppletObject" )),
+ aPropertyValues,
+ sizeof(aPropertyValues)/sizeof(*aPropertyValues),
+ mrContext );
+ }
+ else if( shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.OLE2Shape") ) ||
+ shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.OLE2Shape") ) )
+ {
+ // #i46224# Mark OLE shapes as foreign content - scan them for
+ // unsupported actions, and fallback to bitmap, if necessary
+ return DrawShape::create( xCurrShape,
+ mxPage,
+ mnAscendingPrio,
+ true,
+ mrContext );
+ }
+ else if( shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM(
+ "com.sun.star.drawing.GraphicObjectShape") ) ||
+ shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM(
+ "com.sun.star.presentation.GraphicObjectShape") ) )
+ {
+ GraphicObject aGraphicObject;
+
+ // to get hold of GIF animations, inspect Graphic
+ // objects more thoroughly (the plain-jane shape
+ // metafile of course would only contain the first
+ // animation frame)
+ if( !importShapeGraphic( aGraphicObject, xPropSet ) )
+ return ShapeSharedPtr(); // error loading graphic -
+ // no placeholders in
+ // slideshow
+
+ if( !aGraphicObject.IsAnimated() )
+ {
+ // no animation - simply utilize plain draw shape import
+
+ // import shape as bitmap - either its a bitmap
+ // anyway, or its a metafile, which currently the
+ // metafile renderer might not display correctly.
+ return DrawShape::create( xCurrShape,
+ mxPage,
+ mnAscendingPrio,
+ true,
+ mrContext );
+ }
+
+
+ // now extract relevant shape attributes via API
+ // ---------------------------------------------
+
+ drawing::ColorMode eColorMode( drawing::ColorMode_STANDARD );
+ sal_Int16 nLuminance(0);
+ sal_Int16 nContrast(0);
+ sal_Int16 nRed(0);
+ sal_Int16 nGreen(0);
+ sal_Int16 nBlue(0);
+ double nGamma(1.0);
+ sal_Int16 nTransparency(0);
+ sal_Int32 nRotation(0);
+
+ getPropertyValue( eColorMode, xPropSet, OUSTR("GraphicColorMode") );
+ getPropertyValue( nLuminance, xPropSet, OUSTR("AdjustLuminance") );
+ getPropertyValue( nContrast, xPropSet, OUSTR("AdjustContrast") );
+ getPropertyValue( nRed, xPropSet, OUSTR("AdjustRed") );
+ getPropertyValue( nGreen, xPropSet, OUSTR("AdjustGreen") );
+ getPropertyValue( nBlue, xPropSet, OUSTR("AdjustBlue") );
+ getPropertyValue( nGamma, xPropSet, OUSTR("Gamma") );
+ getPropertyValue( nTransparency, xPropSet, OUSTR("Transparency") );
+ getPropertyValue( nRotation, xPropSet, OUSTR("RotateAngle") );
+
+ GraphicAttr aGraphAttrs;
+ aGraphAttrs.SetDrawMode( (GraphicDrawMode)eColorMode );
+ aGraphAttrs.SetLuminance( nLuminance );
+ aGraphAttrs.SetContrast( nContrast );
+ aGraphAttrs.SetChannelR( nRed );
+ aGraphAttrs.SetChannelG( nGreen );
+ aGraphAttrs.SetChannelB( nBlue );
+ aGraphAttrs.SetGamma( nGamma );
+ aGraphAttrs.SetTransparency( static_cast<sal_uInt8>(nTransparency) );
+ aGraphAttrs.SetRotation( static_cast<sal_uInt16>(nRotation*10) );
+
+ text::GraphicCrop aGraphCrop;
+ if( getPropertyValue( aGraphCrop, xPropSet, OUSTR("GraphicCrop") ))
+ {
+ aGraphAttrs.SetCrop( aGraphCrop.Left,
+ aGraphCrop.Top,
+ aGraphCrop.Right,
+ aGraphCrop.Bottom );
+ }
+
+ // fetch readily transformed and color-modified
+ // graphic
+ // ---------------------------------------------
+
+ Graphic aGraphic(
+ aGraphicObject.GetTransformedGraphic(
+ aGraphicObject.GetPrefSize(),
+ aGraphicObject.GetPrefMapMode(),
+ aGraphAttrs ) );
+
+ return DrawShape::create( xCurrShape,
+ mxPage,
+ mnAscendingPrio,
+ aGraphic,
+ mrContext );
+ }
+ else
+ {
+ return DrawShape::create( xCurrShape,
+ mxPage,
+ mnAscendingPrio,
+ false,
+ mrContext );
+ }
+}
+
+bool ShapeImporter::isSkip(
+ uno::Reference<beans::XPropertySet> const& xPropSet,
+ rtl::OUString const& shapeType,
+ uno::Reference< drawing::XLayer> const& xLayer )
+{
+ // skip empty presentation objects:
+ bool bEmpty = false;
+ if( getPropertyValue( bEmpty,
+ xPropSet,
+ OUSTR("IsEmptyPresentationObject")) &&
+ bEmpty )
+ {
+ return true;
+ }
+
+ //skip shapes which corresponds to annotations
+ if(xLayer.is())
+ {
+ rtl::OUString layerName;
+ uno::Reference<beans::XPropertySet> xPropLayerSet(
+ xLayer, uno::UNO_QUERY );
+ const uno::Any& a(xPropLayerSet->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Name"))) );
+ bool const bRet = (a >>= layerName);
+ if(bRet)
+ {
+ if( layerName.equals(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DrawnInSlideshow"))))
+ {
+ //Transform shapes into PolyPolygons
+ importPolygons(xPropSet);
+
+ return true;
+ }
+ }
+ }
+
+ // don't export presentation placeholders on masterpage
+ // they can be non empty when user edits the default texts
+ if(mbConvertingMasterPage)
+ {
+ if(shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation."
+ "TitleTextShape") ) ||
+ shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation."
+ "OutlinerShape") ))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void ShapeImporter::importPolygons(uno::Reference<beans::XPropertySet> const& xPropSet) {
+
+ drawing::PointSequenceSequence aRetval;
+ sal_Int32 nLineColor=0;
+ double fLineWidth;
+ getPropertyValue( aRetval, xPropSet, OUSTR("PolyPolygon") );
+ getPropertyValue( nLineColor, xPropSet, OUSTR("LineColor") );
+ getPropertyValue( fLineWidth, xPropSet, OUSTR("LineWidth") );
+
+ drawing::PointSequence* pOuterSequence = aRetval.getArray();
+ awt::Point* pInnerSequence = pOuterSequence->getArray();
+
+ ::basegfx::B2DPolygon aPoly;
+ basegfx::B2DPoint aPoint;
+ for( sal_Int32 nCurrPoly=0; nCurrPoly<pOuterSequence->getLength(); ++nCurrPoly, ++pInnerSequence )
+ {
+ aPoint.setX((*pInnerSequence).X);
+ aPoint.setY((*pInnerSequence).Y);
+ aPoly.append( aPoint );
+ }
+ UnoViewVector::const_iterator aIter=(mrContext.mrViewContainer).begin();
+ UnoViewVector::const_iterator aEnd=(mrContext.mrViewContainer).end();
+ while(aIter != aEnd)
+ {
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
+ ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( (*aIter)->getCanvas(),
+ aPoly ) );
+ if( pPolyPoly )
+ {
+ pPolyPoly->setRGBALineColor( unoColor2RGBColor( nLineColor ).getIntegerColor() );
+ pPolyPoly->setStrokeWidth(fLineWidth);
+ pPolyPoly->draw();
+ maPolygons.push_back(pPolyPoly);
+ }
+ ++aIter;
+ }
+}
+
+ShapeSharedPtr ShapeImporter::importBackgroundShape() // throw (ShapeLoadFailedException)
+{
+ if( maShapesStack.empty() )
+ throw ShapeLoadFailedException();
+
+ XShapesEntry& rTop = maShapesStack.top();
+ ShapeSharedPtr pBgShape(
+ createBackgroundShape(mxPage,
+ uno::Reference<drawing::XDrawPage>(
+ rTop.mxShapes,
+ uno::UNO_QUERY_THROW),
+ mrContext) );
+ mnAscendingPrio += 1.0;
+
+ return pBgShape;
+}
+
+ShapeSharedPtr ShapeImporter::importShape() // throw (ShapeLoadFailedException)
+{
+ ShapeSharedPtr pRet;
+ bool bIsGroupShape = false;
+
+ while( !maShapesStack.empty() && !pRet )
+ {
+ XShapesEntry& rTop = maShapesStack.top();
+ if( rTop.mnPos < rTop.mnCount )
+ {
+ uno::Reference<drawing::XShape> const xCurrShape(
+ rTop.mxShapes->getByIndex( rTop.mnPos ), uno::UNO_QUERY );
+ ++rTop.mnPos;
+ uno::Reference<beans::XPropertySet> xPropSet(
+ xCurrShape, uno::UNO_QUERY );
+ if( !xPropSet.is() )
+ {
+ // we definitely need the properties of
+ // the shape here. This will also fail,
+ // if getByIndex did not return a valid
+ // shape
+ throw ShapeLoadFailedException();
+ }
+
+ //Retrieve the layer for the current shape
+ uno::Reference< drawing::XLayer > xDrawnInSlideshow;
+
+ uno::Reference< drawing::XLayerSupplier > xLayerSupplier(mxPagesSupplier, uno::UNO_QUERY);
+ if(xLayerSupplier.is())
+ {
+ uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
+
+ uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
+
+ xDrawnInSlideshow = xLayerManager->getLayerForShape(xCurrShape);
+ }
+
+ rtl::OUString const shapeType( xCurrShape->getShapeType());
+
+ // is this shape presentation-invisible?
+ if( !isSkip(xPropSet, shapeType, xDrawnInSlideshow) )
+ {
+ bIsGroupShape = shapeType.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM(
+ "com.sun.star.drawing.GroupShape") );
+
+ if( rTop.mpGroupShape ) // in group particle mode?
+ {
+ pRet.reset( new ShapeOfGroup(
+ rTop.mpGroupShape /* container shape */,
+ xCurrShape, xPropSet,
+ mnAscendingPrio ) );
+ }
+ else
+ {
+ pRet = createShape( xCurrShape, xPropSet, shapeType );
+ }
+ mnAscendingPrio += 1.0;
+ }
+ }
+ if( rTop.mnPos >= rTop.mnCount )
+ {
+ // group or top-level shapes finished:
+ maShapesStack.pop();
+ }
+ if( bIsGroupShape && pRet )
+ {
+ // push new group on the stack: group traversal
+ maShapesStack.push( XShapesEntry( pRet ) );
+ }
+ }
+
+ return pRet;
+}
+
+bool ShapeImporter::isImportDone() const
+{
+ return maShapesStack.empty();
+}
+
+PolyPolygonVector ShapeImporter::getPolygons()
+{
+ return maPolygons;
+}
+
+ShapeImporter::ShapeImporter( uno::Reference<drawing::XDrawPage> const& xPage,
+ uno::Reference<drawing::XDrawPage> const& xActualPage,
+ uno::Reference<drawing::XDrawPagesSupplier> const& xPagesSupplier,
+ const SlideShowContext& rContext,
+ sal_Int32 nOrdNumStart,
+ bool bConvertingMasterPage ) :
+ mxPage( xActualPage ),
+ mxPagesSupplier( xPagesSupplier ),
+ mrContext( rContext ),
+ maPolygons(),
+ maShapesStack(),
+ mnAscendingPrio( nOrdNumStart ),
+ mbConvertingMasterPage( bConvertingMasterPage )
+{
+ uno::Reference<drawing::XShapes> const xShapes(
+ xPage, uno::UNO_QUERY_THROW );
+ maShapesStack.push( XShapesEntry(xShapes) );
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewappletshape.cxx b/slideshow/source/engine/shapes/viewappletshape.cxx
new file mode 100644
index 000000000000..e7e638a632b3
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewappletshape.cxx
@@ -0,0 +1,303 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/verbosetrace.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/debug.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/tools/canvastools.hxx>
+
+#include <cppcanvas/spritecanvas.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/awt/WindowDescriptor.hpp>
+#include <com/sun/star/awt/XToolkit.hpp>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/awt/WindowAttribute.hpp>
+#include <com/sun/star/awt/VclWindowPeerAttribute.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
+
+#include "viewappletshape.hxx"
+#include "tools.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ViewAppletShape::ViewAppletShape( const ViewLayerSharedPtr& rViewLayer,
+ const uno::Reference< drawing::XShape >& rxShape,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ mpViewLayer( rViewLayer ),
+ mxViewer(),
+ mxFrame(),
+ mxComponentContext( rxContext )
+ {
+ ENSURE_OR_THROW( rxShape.is(), "ViewAppletShape::ViewAppletShape(): Invalid Shape" );
+ ENSURE_OR_THROW( mpViewLayer, "ViewAppletShape::ViewAppletShape(): Invalid View" );
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewAppletShape::ViewAppletShape(): Invalid ViewLayer canvas" );
+ ENSURE_OR_THROW( mxComponentContext.is(), "ViewAppletShape::ViewAppletShape(): Invalid component context" );
+
+ uno::Reference<lang::XMultiComponentFactory> xFactory(
+ mxComponentContext->getServiceManager(),
+ uno::UNO_QUERY_THROW );
+
+ mxViewer.set( xFactory->createInstanceWithContext( rServiceName,
+ mxComponentContext),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< beans::XPropertySet > xShapePropSet( rxShape,
+ uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > mxViewerPropSet( mxViewer,
+ uno::UNO_QUERY_THROW );
+
+ // copy shape properties to applet viewer
+ ::rtl::OUString aPropName;
+ for( sal_Size i=0; i<nNumPropEntries; ++i )
+ {
+ aPropName = ::rtl::OUString::createFromAscii( pPropCopyTable[i] );
+ mxViewerPropSet->setPropertyValue( aPropName,
+ xShapePropSet->getPropertyValue(
+ aPropName ));
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewAppletShape::~ViewAppletShape()
+ {
+ try
+ {
+ endApplet();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewLayerSharedPtr ViewAppletShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewAppletShape::startApplet( const ::basegfx::B2DRectangle& rBounds )
+ {
+ ENSURE_OR_RETURN_FALSE( mpViewLayer && mpViewLayer->getCanvas() && mpViewLayer->getCanvas()->getUNOCanvas().is(),
+ "ViewAppletShape::startApplet(): Invalid or disposed view" );
+ try
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();
+
+ uno::Reference< beans::XPropertySet > xPropSet( pCanvas->getUNOCanvas()->getDevice(),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< awt::XWindow2 > xParentWindow(
+ xPropSet->getPropertyValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Window" ))),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference<lang::XMultiComponentFactory> xFactory(
+ mxComponentContext->getServiceManager() );
+
+ if( xFactory.is() )
+ {
+ // create an awt window to contain the applet
+ // ==========================================
+
+ uno::Reference< awt::XToolkit > xToolkit(
+ xFactory->createInstanceWithContext(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" )),
+ mxComponentContext ),
+ uno::UNO_QUERY_THROW );
+
+ awt::WindowDescriptor aOwnWinDescriptor( awt::WindowClass_SIMPLE,
+ ::rtl::OUString(),
+ uno::Reference< awt::XWindowPeer >(xParentWindow,
+ uno::UNO_QUERY_THROW),
+ 0,
+ awt::Rectangle(),
+ awt::WindowAttribute::SHOW
+ | awt::VclWindowPeerAttribute::CLIPCHILDREN );
+
+ uno::Reference< awt::XWindowPeer > xNewWinPeer(
+ xToolkit->createWindow( aOwnWinDescriptor ));
+ uno::Reference< awt::XWindow > xOwnWindow( xNewWinPeer,
+ uno::UNO_QUERY_THROW );
+
+
+ // create a frame, and load the applet into it
+ // ===========================================
+
+ mxFrame.set(
+ xFactory->createInstanceWithContext(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Frame" )),
+ mxComponentContext ),
+ uno::UNO_QUERY_THROW );
+
+ mxFrame->initialize( xOwnWindow );
+
+ uno::Reference < frame::XSynchronousFrameLoader > xLoader( mxViewer,
+ uno::UNO_QUERY_THROW );
+ xLoader->load( uno::Sequence < beans::PropertyValue >(),
+ mxFrame );
+
+
+ // resize surrounding window and applet to current shape size
+ // ==========================================================
+
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rPixelBounds(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ uno::Reference< awt::XWindow > xSurroundingWindow( mxFrame->getContainerWindow() );
+ if( xSurroundingWindow.is() )
+ xSurroundingWindow->setPosSize( static_cast<sal_Int32>(rPixelBounds.getMinX()),
+ static_cast<sal_Int32>(rPixelBounds.getMinY()),
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+
+ uno::Reference< awt::XWindow > xAppletWindow( mxFrame->getComponentWindow() );
+ if( xAppletWindow.is() )
+ xAppletWindow->setPosSize( 0, 0,
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+ }
+ }
+ catch (uno::Exception &)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewAppletShape::endApplet()
+ {
+ uno::Reference<util::XCloseable> xCloseable(
+ mxFrame,
+ uno::UNO_QUERY );
+
+ if( xCloseable.is() )
+ {
+ xCloseable->close( sal_True );
+ mxFrame.clear();
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewAppletShape::render( const ::basegfx::B2DRectangle& rBounds ) const
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();
+
+ if( !pCanvas )
+ return false;
+
+ if( !mxFrame.is() )
+ {
+ // fill the shape background with black
+ fillRect( pCanvas,
+ rBounds,
+ 0xFFFFFFFFU );
+ }
+
+ return true;
+ }
+
+ bool ViewAppletShape::resize( const ::basegfx::B2DRectangle& rBounds ) const
+ {
+ if( !mxFrame.is() )
+ return false;
+
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rPixelBounds(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ uno::Reference< awt::XWindow > xFrameWindow( mxFrame->getContainerWindow() );
+ if( xFrameWindow.is() )
+ xFrameWindow->setPosSize( static_cast<sal_Int32>(rPixelBounds.getMinX()),
+ static_cast<sal_Int32>(rPixelBounds.getMinY()),
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+
+ uno::Reference< awt::XWindow > xAppletWindow( mxFrame->getComponentWindow() );
+ if( xAppletWindow.is() )
+ xAppletWindow->setPosSize( 0, 0,
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+
+ return true;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewappletshape.hxx b/slideshow/source/engine/shapes/viewappletshape.hxx
new file mode 100644
index 000000000000..29e81c4e2bc5
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewappletshape.hxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWAPPLETSHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWAPPLETSHAPE_HXX
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <com/sun/star/awt/Point.hpp>
+
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "viewlayer.hxx"
+
+namespace com { namespace sun { namespace star {
+namespace frame {
+ class XSynchronousFrameLoader;
+ class XFrame;
+}
+namespace uno {
+ class XComponentContext;
+}
+namespace drawing {
+ class XShape;
+}}}}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's applet object, associated to a specific View
+
+ The class is able to render the associated applet on View
+ implementations.
+ */
+ class ViewAppletShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewAppletShape for the given View
+
+ @param rViewLayer
+ The associated View object.
+
+ @param rxShape
+ The associated Shape
+
+ @param rServiceName
+ The service name to use, when actually creating the
+ viewer component
+
+ @param pPropCopyTable
+ Table of plain ASCII property names, to copy from
+ xShape to applet.
+
+ @param nNumPropEntries
+ Number of property table entries (in pPropCopyTable)
+ */
+ ViewAppletShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& rxShape,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext >& rxContext );
+
+ /** destroy the object
+ */
+ virtual ~ViewAppletShape();
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ /** Notify the ViewShape that an animation starts now
+
+ This method enters animation mode on the associate
+ target view. The shape can be animated in parallel on
+ different views.
+
+ @param rBounds
+ The current applet shape bounds
+
+ @return whether the mode change finished successfully.
+ */
+ bool startApplet( const ::basegfx::B2DRectangle& rBounds );
+
+ /** Notify the ViewShape that it is no longer animated
+
+ This methods ends animation mode on the associate
+ target view
+ */
+ void endApplet();
+
+ // render methods
+ //------------------------------------------------------------------
+
+ /** Render the ViewShape
+
+ This method renders the ViewAppletShape on the associated view.
+
+ @param rBounds
+ The current applet shape bounds
+
+ @return whether the rendering finished successfully.
+ */
+ bool render( const ::basegfx::B2DRectangle& rBounds ) const;
+
+ /** Resize the ViewShape
+
+ This method resizes the ViewAppletShape on the
+ associated view. It does not render.
+
+ @param rBounds
+ The current applet shape bounds
+
+ @return whether the resize finished successfully.
+ */
+ bool resize( const ::basegfx::B2DRectangle& rBounds ) const;
+
+ private:
+
+ ViewLayerSharedPtr mpViewLayer;
+
+ /// the actual viewer component for this applet
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::frame::XSynchronousFrameLoader> mxViewer;
+
+ /// the frame containing the applet
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::frame::XFrame> mxFrame;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext> mxComponentContext;
+ };
+
+ typedef ::boost::shared_ptr< ViewAppletShape > ViewAppletShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWAPPLETSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewbackgroundshape.cxx b/slideshow/source/engine/shapes/viewbackgroundshape.cxx
new file mode 100644
index 000000000000..18f9bc94a956
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewbackgroundshape.cxx
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "viewbackgroundshape.hxx"
+#include "tools.hxx"
+
+#include <rtl/logfile.hxx>
+#include <rtl/math.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <cppcanvas/renderer.hxx>
+#include <cppcanvas/bitmap.hxx>
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ bool ViewBackgroundShape::prefetch( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewBackgroundShape::prefetch()" );
+ ENSURE_OR_RETURN_FALSE( rMtf,
+ "ViewBackgroundShape::prefetch(): no valid metafile!" );
+
+ const ::basegfx::B2DHomMatrix& rCanvasTransform(
+ mpViewLayer->getTransformation() );
+
+ if( !mxBitmap.is() ||
+ rMtf != mpLastMtf ||
+ rCanvasTransform != maLastTransformation )
+ {
+ // buffered bitmap is invalid, re-create
+
+ // determine transformed page bounds
+ ::basegfx::B2DRectangle aTmpRect;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRect,
+ maBounds,
+ rCanvasTransform );
+
+ // determine pixel size of bitmap (choose it one pixel
+ // larger, as polygon rendering takes one pixel more
+ // to the right and to the bottom)
+ const ::basegfx::B2ISize aBmpSizePixel(
+ ::basegfx::fround( aTmpRect.getRange().getX() + 1),
+ ::basegfx::fround( aTmpRect.getRange().getY() + 1) );
+
+ // create a bitmap of appropriate size
+ ::cppcanvas::BitmapSharedPtr pBitmap(
+ ::cppcanvas::BaseGfxFactory::getInstance().createBitmap(
+ rDestinationCanvas,
+ aBmpSizePixel ) );
+
+ ENSURE_OR_THROW( pBitmap,
+ "ViewBackgroundShape::prefetch(): Cannot create background bitmap" );
+
+ ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas( pBitmap->getBitmapCanvas() );
+
+ ENSURE_OR_THROW( pBitmapCanvas,
+ "ViewBackgroundShape::prefetch(): Cannot create background bitmap canvas" );
+
+ // clear bitmap
+ initSlideBackground( pBitmapCanvas,
+ aBmpSizePixel );
+
+ // apply linear part of destination canvas transformation (linear means in this context:
+ // transformation without any translational components)
+ ::basegfx::B2DHomMatrix aLinearTransform( rCanvasTransform );
+ aLinearTransform.set( 0, 2, 0.0 );
+ aLinearTransform.set( 1, 2, 0.0 );
+ pBitmapCanvas->setTransformation( aLinearTransform );
+
+ const basegfx::B2DHomMatrix aShapeTransform(basegfx::tools::createScaleTranslateB2DHomMatrix(
+ maBounds.getWidth(), maBounds.getHeight(),
+ maBounds.getMinX(), maBounds.getMinY()));
+
+ ::cppcanvas::RendererSharedPtr pRenderer(
+ ::cppcanvas::VCLFactory::getInstance().createRenderer(
+ pBitmapCanvas,
+ *rMtf.get(),
+ ::cppcanvas::Renderer::Parameters() ) );
+
+ ENSURE_OR_RETURN_FALSE( pRenderer,
+ "ViewBackgroundShape::prefetch(): Could not create Renderer" );
+
+ pRenderer->setTransformation( aShapeTransform );
+ pRenderer->draw();
+
+ mxBitmap = pBitmap->getUNOBitmap();
+ }
+
+ mpLastMtf = rMtf;
+ maLastTransformation = rCanvasTransform;
+
+ return mxBitmap.is();
+ }
+
+ ViewBackgroundShape::ViewBackgroundShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::basegfx::B2DRectangle& rShapeBounds ) :
+ mpViewLayer( rViewLayer ),
+ mxBitmap(),
+ mpLastMtf(),
+ maLastTransformation(),
+ maBounds( rShapeBounds )
+ {
+ ENSURE_OR_THROW( mpViewLayer, "ViewBackgroundShape::ViewBackgroundShape(): Invalid View" );
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewBackgroundShape::ViewBackgroundShape(): Invalid ViewLayer canvas" );
+ }
+
+ ViewLayerSharedPtr ViewBackgroundShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ bool ViewBackgroundShape::render( const GDIMetaFileSharedPtr& rMtf ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewBackgroundShape::draw()" );
+
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas( mpViewLayer->getCanvas() );
+
+ if( !prefetch( rDestinationCanvas, rMtf ) )
+ return false;
+
+ ENSURE_OR_RETURN_FALSE( mxBitmap.is(),
+ "ViewBackgroundShape::draw(): Invalid background bitmap" );
+
+ ::basegfx::B2DHomMatrix aTransform( mpViewLayer->getTransformation() );
+
+ // invert the linear part of the view transformation
+ // (i.e. the view transformation without translational
+ // components), to be able to leave the canvas
+ // transformation intact (would otherwise destroy possible
+ // clippings, as the clip polygon is relative to the view
+ // coordinate system).
+ aTransform.set(0,2, 0.0 );
+ aTransform.set(1,2, 0.0 );
+ aTransform.invert();
+
+ rendering::RenderState aRenderState;
+ ::canvas::tools::initRenderState( aRenderState );
+
+ ::canvas::tools::setRenderStateTransform( aRenderState, aTransform );
+
+ try
+ {
+ rDestinationCanvas->getUNOCanvas()->drawBitmap( mxBitmap,
+ rDestinationCanvas->getViewState(),
+ aRenderState );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewbackgroundshape.hxx b/slideshow/source/engine/shapes/viewbackgroundshape.hxx
new file mode 100644
index 000000000000..da7beb7b03be
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewbackgroundshape.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWBACKGROUNDSHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWBACKGROUNDSHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/rendering/XBitmap.hpp>
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <cppcanvas/spritecanvas.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+#include "gdimtftools.hxx"
+#include "viewlayer.hxx"
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's background, associated to a specific View
+
+ The class is able to render the associated background on
+ View implementations.
+ */
+ class ViewBackgroundShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewBackgroundShape for the given View
+
+ @param rView
+ The associated View object.
+
+ @param rShapeBounds
+ Bounds of the background shape, in document coordinate
+ system.
+ */
+ ViewBackgroundShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::basegfx::B2DRectangle& rShapeBounds );
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ bool render( const GDIMetaFileSharedPtr& rMtf ) const;
+
+ private:
+ /** Prefetch bitmap for given canvas
+ */
+ bool prefetch( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf ) const;
+
+ /** The view layer this object is part of.
+ */
+ ViewLayerSharedPtr mpViewLayer;
+
+ /// Generated content bitmap, already with correct output size
+ mutable ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap > mxBitmap;
+
+ /// The last metafile a render object was generated for
+ mutable GDIMetaFileSharedPtr mpLastMtf;
+
+ /// The canvas, mpRenderer is associated with
+ mutable ::basegfx::B2DHomMatrix maLastTransformation;
+
+ const ::basegfx::B2DRectangle maBounds;
+ };
+
+ typedef ::boost::shared_ptr< ViewBackgroundShape > ViewBackgroundShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWBACKGROUNDSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewmediashape.cxx b/slideshow/source/engine/shapes/viewmediashape.cxx
new file mode 100644
index 000000000000..61937a9ea791
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewmediashape.cxx
@@ -0,0 +1,551 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <math.h>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <vcl/window.hxx>
+#include <vcl/syschild.hxx>
+#include <vcl/salbtype.hxx>
+
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <canvas/canvastools.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <avmedia/mediawindow.hxx>
+
+#include <com/sun/star/media/XManager.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <com/sun/star/media/XPlayerWindow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/lang/XComponent.hdl>
+
+#include "viewmediashape.hxx"
+#include "mediashape.hxx"
+#include "tools.hxx"
+#include "unoview.hxx"
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ViewMediaShape::ViewMediaShape( const ViewLayerSharedPtr& rViewLayer,
+ const uno::Reference< drawing::XShape >& rxShape,
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ mpViewLayer( rViewLayer ),
+ mpMediaWindow(),
+ maWindowOffset( 0, 0 ),
+ maBounds(),
+ mxShape( rxShape ),
+ mxPlayer(),
+ mxPlayerWindow(),
+ mxComponentContext( rxContext ),
+ mbIsSoundEnabled(true)
+ {
+ ENSURE_OR_THROW( mxShape.is(), "ViewMediaShape::ViewMediaShape(): Invalid Shape" );
+ ENSURE_OR_THROW( mpViewLayer, "ViewMediaShape::ViewMediaShape(): Invalid View" );
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewMediaShape::ViewMediaShape(): Invalid ViewLayer canvas" );
+ ENSURE_OR_THROW( mxComponentContext.is(), "ViewMediaShape::ViewMediaShape(): Invalid component context" );
+
+ UnoViewSharedPtr pUnoView (::boost::dynamic_pointer_cast<UnoView>(rViewLayer));
+ if (pUnoView)
+ {
+ mbIsSoundEnabled = pUnoView->isSoundEnabled();
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewMediaShape::~ViewMediaShape()
+ {
+ try
+ {
+ endMedia();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewLayerSharedPtr ViewMediaShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::startMedia()
+ {
+ if( !mxPlayer.is() )
+ implInitialize( maBounds );
+
+ if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
+ mxPlayer->start();
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::endMedia()
+ {
+ // shutdown player window
+ if( mxPlayerWindow.is() )
+ {
+ uno::Reference< lang::XComponent > xComponent( mxPlayerWindow, uno::UNO_QUERY );
+
+ if( xComponent.is() )
+ xComponent->dispose();
+
+ mxPlayerWindow.clear();
+ }
+
+ mpMediaWindow = ::std::auto_ptr< SystemChildWindow >();
+
+ // shutdown player
+ if( mxPlayer.is() )
+ {
+ mxPlayer->stop();
+
+ uno::Reference< lang::XComponent > xComponent( mxPlayer, uno::UNO_QUERY );
+
+ if( xComponent.is() )
+ xComponent->dispose();
+
+ mxPlayer.clear();
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::pauseMedia()
+ {
+ if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
+ mxPlayer->stop();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::setMediaTime(double fTime)
+ {
+ if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
+ mxPlayer->setMediaTime(fTime);
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::render( const ::basegfx::B2DRectangle& rBounds ) const
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();;
+
+ if( !pCanvas )
+ return false;
+
+ if( !mpMediaWindow.get() && !mxPlayerWindow.is() )
+ {
+ // fill the shape background with black
+ fillRect( pCanvas,
+ rBounds,
+ 0x000000FFU );
+ }
+
+ return true;
+ }
+
+ bool ViewMediaShape::resize( const ::basegfx::B2DRectangle& rNewBounds ) const
+ {
+ maBounds = rNewBounds;
+
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();;
+
+ if( !pCanvas )
+ return false;
+
+ if( !mxPlayerWindow.is() )
+ return true;
+
+ uno::Reference< beans::XPropertySet > xPropSet( pCanvas->getUNOCanvas()->getDevice(),
+ uno::UNO_QUERY );
+
+ uno::Reference< awt::XWindow > xParentWindow;
+ if( xPropSet.is() &&
+ getPropertyValue( xParentWindow,
+ xPropSet,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Window" ))) )
+ {
+ const awt::Rectangle aRect( xParentWindow->getPosSize() );
+
+ maWindowOffset.X = aRect.X;
+ maWindowOffset.Y = aRect.Y;
+ }
+
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rNewBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rRangePix(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ mxPlayerWindow->setEnable( !rRangePix.isEmpty() );
+
+ if( rRangePix.isEmpty() )
+ return true;
+
+ const Point aPosPixel( rRangePix.getMinX() + maWindowOffset.X,
+ rRangePix.getMinY() + maWindowOffset.Y );
+ const Size aSizePixel( rRangePix.getMaxX() - rRangePix.getMinX(),
+ rRangePix.getMaxY() - rRangePix.getMinY() );
+
+ if( mpMediaWindow.get() )
+ {
+ mpMediaWindow->SetPosSizePixel( aPosPixel, aSizePixel );
+ mxPlayerWindow->setPosSize( 0, 0,
+ aSizePixel.Width(), aSizePixel.Height(),
+ 0 );
+ }
+ else
+ {
+ mxPlayerWindow->setPosSize( aPosPixel.X(), aPosPixel.Y(),
+ aSizePixel.Width(), aSizePixel.Height(),
+ 0 );
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::implInitialize( const ::basegfx::B2DRectangle& rBounds )
+ {
+ if( !mxPlayer.is() && mxShape.is() )
+ {
+ ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(),
+ "ViewMediaShape::update(): Invalid layer canvas" );
+
+ uno::Reference< rendering::XCanvas > xCanvas( mpViewLayer->getCanvas()->getUNOCanvas() );
+
+ if( xCanvas.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet;
+ ::rtl::OUString aURL;
+
+ try
+ {
+ xPropSet.set( mxShape, uno::UNO_QUERY );
+
+ // create Player
+ if( xPropSet.is() &&
+ ( xPropSet->getPropertyValue(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaURL" ) ) ) >>=aURL ) )
+ {
+ implInitializeMediaPlayer( aURL );
+ }
+
+ // create visible object
+ uno::Sequence< uno::Any > aDeviceParams;
+
+ if( ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams ).getLength() > 1 )
+ {
+ ::rtl::OUString aImplName;
+
+ aDeviceParams[ 0 ] >>= aImplName;
+
+ if( aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("VCL") ) || aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("Cairo") ) )
+ {
+ implInitializeVCLBasedPlayerWindow( rBounds, aDeviceParams );
+ }
+ else if( aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("DX")) ||
+ aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("DX9")))
+ {
+ implInitializeDXBasedPlayerWindow( rBounds, aDeviceParams );
+ }
+ }
+
+ // set player properties
+ implSetMediaProperties( xPropSet );
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ }
+
+ return mxPlayer.is() || mxPlayerWindow.is();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::implSetMediaProperties( const uno::Reference< beans::XPropertySet >& rxProps )
+ {
+ if( mxPlayer.is() )
+ {
+ mxPlayer->setMediaTime( 0.0 );
+
+ if( rxProps.is() )
+ {
+ sal_Bool bLoop( false );
+ getPropertyValue( bLoop,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Loop" )));
+ mxPlayer->setPlaybackLoop( bLoop );
+
+ sal_Bool bMute( false );
+ getPropertyValue( bMute,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Mute" )));
+ mxPlayer->setMute( bMute || !mbIsSoundEnabled);
+
+ sal_Int16 nVolumeDB(0);
+ getPropertyValue( nVolumeDB,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VolumeDB" )));
+ mxPlayer->setVolumeDB( nVolumeDB );
+
+ if( mxPlayerWindow.is() )
+ {
+ media::ZoomLevel eZoom(media::ZoomLevel_FIT_TO_WINDOW);
+ getPropertyValue( eZoom,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Zoom" )));
+ mxPlayerWindow->setZoomLevel( eZoom );
+ }
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::implInitializeMediaPlayer( const ::rtl::OUString& rMediaURL )
+ {
+ if( !mxPlayer.is() )
+ {
+ try
+ {
+ if( rMediaURL.getLength() )
+ {
+ mxPlayer.set( avmedia::MediaWindow::createPlayer( rMediaURL ),
+ uno::UNO_QUERY );
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( const uno::Exception& )
+ {
+ throw lang::NoSupportException(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "No video support for ") ) + rMediaURL,
+ uno::Reference<uno::XInterface>() );
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::implInitializeVCLBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const uno::Sequence< uno::Any >& rVCLDeviceParams)
+ {
+ OSL_TRACE( "ViewMediaShape::implInitializeVCLBasedPlayerWindow" );
+ if( !mpMediaWindow.get() && !rBounds.isEmpty() )
+ {
+ try
+ {
+ sal_Int64 aVal=0;
+
+ rVCLDeviceParams[ 1 ] >>= aVal;
+
+ Window* pWindow = reinterpret_cast< Window* >( aVal );
+
+ if( pWindow )
+ {
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rRangePix(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ if( !rRangePix.isEmpty() )
+ {
+ uno::Sequence< uno::Any > aArgs( 3 );
+ awt::Rectangle aAWTRect( rRangePix.getMinX(),
+ rRangePix.getMinY(),
+ rRangePix.getMaxX() - rRangePix.getMinX(),
+ rRangePix.getMaxY() - rRangePix.getMinY() );
+
+ mpMediaWindow = ::std::auto_ptr< SystemChildWindow >( new
+ SystemChildWindow( pWindow, WB_CLIPCHILDREN ) );
+ mpMediaWindow = ::std::auto_ptr< SystemChildWindow >( new SystemChildWindow( pWindow, WB_CLIPCHILDREN ) );
+ mpMediaWindow->SetBackground( Color( COL_BLACK ) );
+ mpMediaWindow->SetPosSizePixel( Point( aAWTRect.X, aAWTRect.Y ),
+ Size( aAWTRect.Width, aAWTRect.Height ) );
+ mpMediaWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ mpMediaWindow->EnableEraseBackground( sal_False );
+ mpMediaWindow->EnablePaint( sal_False );
+ mpMediaWindow->SetForwardKey( sal_True );
+ mpMediaWindow->SetMouseTransparent( sal_True );
+ mpMediaWindow->Show();
+
+ if( mxPlayer.is() )
+ {
+ aArgs[ 0 ] = uno::makeAny(
+ sal::static_int_cast< sal_IntPtr >( mpMediaWindow->GetParentWindowHandle() ) );
+
+ aAWTRect.X = aAWTRect.Y = 0;
+ aArgs[ 1 ] = uno::makeAny( aAWTRect );
+
+ aArgs[ 2 ] = uno::makeAny( reinterpret_cast< sal_IntPtr >( mpMediaWindow.get() ) );
+
+ mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
+
+ if( mxPlayerWindow.is() )
+ {
+ mxPlayerWindow->setVisible( true );
+ mxPlayerWindow->setEnable( true );
+ }
+ }
+ }
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ return mxPlayerWindow.is();
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::implInitializeDXBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const uno::Sequence< uno::Any >& rDXDeviceParams )
+ {
+ if( !mxPlayerWindow.is() )
+ {
+ try
+ {
+ if( rDXDeviceParams.getLength() == 2 )
+ {
+ sal_Int64 aWNDVal=0;
+
+ rDXDeviceParams[ 1 ] >>= aWNDVal;
+
+ if( aWNDVal )
+ {
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rRangePix(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ if( !rRangePix.isEmpty() )
+ {
+ uno::Sequence< uno::Any > aArgs( 2 );
+ awt::Rectangle aAWTRect( rRangePix.getMinX() + maWindowOffset.X,
+ rRangePix.getMinY() + maWindowOffset.Y,
+ rRangePix.getMaxX() - rRangePix.getMinX(),
+ rRangePix.getMaxY() - rRangePix.getMinY() );
+
+ if( mxPlayer.is() )
+ {
+ aArgs[ 0 ] = uno::makeAny( sal::static_int_cast< sal_Int32 >( aWNDVal) );
+ aArgs[ 1 ] = uno::makeAny( aAWTRect );
+
+ mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
+ }
+ }
+ }
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ return mxPlayerWindow.is();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewmediashape.hxx b/slideshow/source/engine/shapes/viewmediashape.hxx
new file mode 100644
index 000000000000..5eba4a8c6a42
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewmediashape.hxx
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWMEDIASHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWMEDIASHAPE_HXX
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <com/sun/star/awt/Point.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+#include "viewlayer.hxx"
+
+class SystemChildWindow;
+
+namespace com { namespace sun { namespace star { namespace drawing {
+ class XShape;
+}
+namespace media {
+ class XPlayer;
+ class XPlayerWindow;
+}
+namespace uno {
+ class XComponentContext;
+}
+namespace beans{
+ class XPropertySet;
+} } } }
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's media object, associated to a specific View
+
+ The class is able to render the associated media shape on
+ View implementations.
+ */
+ class ViewMediaShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewMediaShape for the given View
+
+ @param rView
+ The associated View object.
+ */
+ ViewMediaShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& rxShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext >& rxContext );
+
+ /** destroy the object
+ */
+ virtual ~ViewMediaShape();
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ /** Notify the ViewShape that an animation starts now
+
+ This method enters animation mode on the associate
+ target view. The shape can be animated in parallel on
+ different views.
+
+ @return whether the mode change finished successfully.
+ */
+ bool startMedia();
+
+ /** Notify the ViewShape that it is no longer animated
+
+ This methods ends animation mode on the associate
+ target view
+ */
+ void endMedia();
+
+ /** Notify the ViewShape that it should pause playback
+
+ This methods pauses animation on the associate
+ target view. The content stays visible (for video)
+ */
+ void pauseMedia();
+
+ /** Set current time of media.
+
+ @param fTime
+ Local media time that should now be presented, in seconds.
+ */
+ void setMediaTime(double fTime);
+
+ // render methods
+ //------------------------------------------------------------------
+
+ /** Render the ViewShape
+
+ This method renders the ViewMediaShape on the associated view.
+
+ @param rBounds
+ The current media shape bounds
+
+ @return whether the rendering finished successfully.
+ */
+ bool render( const ::basegfx::B2DRectangle& rBounds ) const;
+
+ /** Resize the ViewShape
+
+ This method updates the ViewMediaShape size on the
+ associated view. It does not render.
+
+ @param rBounds
+ The current media shape bounds
+
+ @return whether the resize finished successfully.
+ */
+ bool resize( const ::basegfx::B2DRectangle& rNewBounds ) const;
+
+ private:
+
+ bool implInitialize( const ::basegfx::B2DRectangle& rBounds );
+ void implSetMediaProperties( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& rxProps );
+ void implInitializeMediaPlayer( const ::rtl::OUString& rMediaURL );
+ bool implInitializeVCLBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rVCLDeviceParams );
+ bool implInitializeDXBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rDXDeviceParams );
+
+ ViewLayerSharedPtr mpViewLayer;
+ ::std::auto_ptr< SystemChildWindow > mpMediaWindow;
+ mutable ::com::sun::star::awt::Point maWindowOffset;
+ mutable ::basegfx::B2DRectangle maBounds;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > mxShape;
+ ::com::sun::star::uno::Reference< ::com::sun::star::media::XPlayer > mxPlayer;
+ ::com::sun::star::uno::Reference< ::com::sun::star::media::XPlayerWindow > mxPlayerWindow;
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> mxComponentContext;
+ bool mbIsSoundEnabled;
+ };
+
+ typedef ::boost::shared_ptr< ViewMediaShape > ViewMediaShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWMEDIASHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewshape.cxx b/slideshow/source/engine/shapes/viewshape.cxx
new file mode 100644
index 000000000000..128642cc2ce4
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewshape.cxx
@@ -0,0 +1,901 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <math.h>
+
+#include <rtl/logfile.hxx>
+#include <rtl/math.hxx>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/rendering/PanoseLetterForm.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/anytostring.hxx>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include "viewshape.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ // TODO(F2): Provide sensible setup for mtf-related attributes (fill mode,
+ // char rotation etc.). Do that via mtf argument at this object
+
+ bool ViewShape::prefetch( RendererCacheEntry& io_rCacheEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::prefetch()" );
+ ENSURE_OR_RETURN_FALSE( rMtf,
+ "ViewShape::prefetch(): no valid metafile!" );
+
+ if( rMtf != io_rCacheEntry.mpMtf ||
+ rDestinationCanvas != io_rCacheEntry.getDestinationCanvas() )
+ {
+ // buffered renderer invalid, re-create
+ ::cppcanvas::Renderer::Parameters aParms;
+
+ // rendering attribute override parameter struct. For
+ // every valid attribute, the corresponding struct
+ // member is filled, which in the metafile renderer
+ // forces rendering with the given attribute.
+ if( rAttr )
+ {
+ if( rAttr->isFillColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+ aParms.maFillColor =
+ rAttr->getFillColor().getIntegerColor();
+ }
+ if( rAttr->isLineColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+ aParms.maLineColor =
+ rAttr->getLineColor().getIntegerColor();
+ }
+ if( rAttr->isCharColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+ aParms.maTextColor =
+ rAttr->getCharColor().getIntegerColor();
+ }
+ if( rAttr->isDimColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+
+ // dim color overrides all other colors
+ aParms.maFillColor =
+ aParms.maLineColor =
+ aParms.maTextColor =
+ rAttr->getDimColor().getIntegerColor();
+ }
+ if( rAttr->isFontFamilyValid() )
+ {
+ aParms.maFontName =
+ rAttr->getFontFamily();
+ }
+ if( rAttr->isCharScaleValid() )
+ {
+ ::basegfx::B2DHomMatrix aMatrix;
+
+ // enlarge text by given scale factor. Do that
+ // with the middle of the shape as the center
+ // of scaling.
+ aMatrix.translate( -0.5, -0.5 );
+ aMatrix.scale( rAttr->getCharScale(),
+ rAttr->getCharScale() );
+ aMatrix.translate( 0.5, 0.5 );
+
+ aParms.maTextTransformation = aMatrix;
+ }
+ if( rAttr->isCharWeightValid() )
+ {
+ aParms.maFontWeight =
+ static_cast< sal_Int8 >(
+ ::basegfx::fround(
+ ::std::max( 0.0,
+ ::std::min( 11.0,
+ rAttr->getCharWeight() / 20.0 ) ) ) );
+ }
+ if( rAttr->isCharPostureValid() )
+ {
+ aParms.maFontLetterForm =
+ rAttr->getCharPosture() == awt::FontSlant_NONE ?
+ rendering::PanoseLetterForm::ANYTHING :
+ rendering::PanoseLetterForm::OBLIQUE_CONTACT;
+ }
+ if( rAttr->isUnderlineModeValid() )
+ {
+ aParms.maFontUnderline =
+ rAttr->getUnderlineMode();
+ }
+ }
+
+ io_rCacheEntry.mpRenderer = ::cppcanvas::VCLFactory::getInstance().createRenderer( rDestinationCanvas,
+ *rMtf.get(),
+ aParms );
+
+ io_rCacheEntry.mpMtf = rMtf;
+ io_rCacheEntry.mpDestinationCanvas = rDestinationCanvas;
+
+ // also invalidate alpha compositing bitmap (created
+ // new renderer, which possibly generates different
+ // output). Do NOT invalidate, if we're incidentally
+ // rendering INTO it.
+ if( rDestinationCanvas != io_rCacheEntry.mpLastBitmapCanvas )
+ {
+ io_rCacheEntry.mpLastBitmapCanvas.reset();
+ io_rCacheEntry.mpLastBitmap.reset();
+ }
+ }
+
+ return io_rCacheEntry.mpRenderer;
+ }
+
+ bool ViewShape::draw( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ const ::basegfx::B2DPolyPolygon* pClip,
+ const VectorOfDocTreeNodes& rSubsets ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::draw()" );
+
+ ::cppcanvas::RendererSharedPtr pRenderer(
+ getRenderer( rDestinationCanvas, rMtf, rAttr ) );
+
+ ENSURE_OR_RETURN_FALSE( pRenderer, "ViewShape::draw(): Invalid renderer" );
+
+ pRenderer->setTransformation( rTransform );
+#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
+ rendering::RenderState aRenderState;
+ ::canvas::tools::initRenderState(aRenderState);
+ ::canvas::tools::setRenderStateTransform(aRenderState,
+ rTransform);
+ aRenderState.DeviceColor.realloc(4);
+ aRenderState.DeviceColor[0] = 1.0;
+ aRenderState.DeviceColor[1] = 0.0;
+ aRenderState.DeviceColor[2] = 0.0;
+ aRenderState.DeviceColor[3] = 1.0;
+
+ try
+ {
+ rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(0.0,0.0),
+ geometry::RealPoint2D(1.0,1.0),
+ rDestinationCanvas->getViewState(),
+ aRenderState );
+ rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0),
+ geometry::RealPoint2D(0.0,1.0),
+ rDestinationCanvas->getViewState(),
+ aRenderState );
+ }
+ catch( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+#endif
+ if( pClip )
+ pRenderer->setClip( *pClip );
+ else
+ pRenderer->setClip();
+
+ if( rSubsets.empty() )
+ {
+ return pRenderer->draw();
+ }
+ else
+ {
+ // render subsets of whole metafile
+ // --------------------------------
+
+ bool bRet(true);
+ VectorOfDocTreeNodes::const_iterator aIter( rSubsets.begin() );
+ const VectorOfDocTreeNodes::const_iterator aEnd ( rSubsets.end() );
+ while( aIter != aEnd )
+ {
+ if( !pRenderer->drawSubset( aIter->getStartIndex(),
+ aIter->getEndIndex() ) )
+ bRet = false;
+
+ ++aIter;
+ }
+
+ return bRet;
+ }
+ }
+
+ namespace
+ {
+ /// Convert untransformed shape update area to device pixel.
+ ::basegfx::B2DRectangle shapeArea2AreaPixel( const ::basegfx::B2DHomMatrix& rCanvasTransformation,
+ const ::basegfx::B2DRectangle& rUntransformedArea )
+ {
+ // convert area to pixel, and add anti-aliasing border
+
+ // TODO(P1): Should the view transform some
+ // day contain rotation/shear, transforming
+ // the original bounds with the total
+ // transformation might result in smaller
+ // overall bounds.
+
+ ::basegfx::B2DRectangle aBoundsPixel;
+ ::canvas::tools::calcTransformedRectBounds( aBoundsPixel,
+ rUntransformedArea,
+ rCanvasTransformation );
+
+ // add antialiasing border around the shape (AA
+ // touches pixel _outside_ the nominal bound rect)
+ aBoundsPixel.grow( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE );
+
+ return aBoundsPixel;
+ }
+
+ /// Convert shape unit rect to device pixel.
+ ::basegfx::B2DRectangle calcUpdateAreaPixel( const ::basegfx::B2DRectangle& rUnitBounds,
+ const ::basegfx::B2DHomMatrix& rShapeTransformation,
+ const ::basegfx::B2DHomMatrix& rCanvasTransformation,
+ const ShapeAttributeLayerSharedPtr& pAttr )
+ {
+ // calc update area for whole shape (including
+ // character scaling)
+ return shapeArea2AreaPixel( rCanvasTransformation,
+ getShapeUpdateArea( rUnitBounds,
+ rShapeTransformation,
+ pAttr ) );
+ }
+ }
+
+ bool ViewShape::renderSprite( const ViewLayerSharedPtr& rViewLayer,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rOrigBounds,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUnitBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ double nPrio,
+ bool bIsVisible ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::renderSprite()" );
+
+ // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
+ // in that all the common setup steps here are refactored to Shape (would then
+ // have to be performed only _once_ per Shape paint).
+
+ if( !bIsVisible ||
+ rUnitBounds.isEmpty() ||
+ rOrigBounds.isEmpty() ||
+ rBounds.isEmpty() )
+ {
+ // shape is invisible or has zero size, no need to
+ // update anything.
+ if( mpSprite )
+ mpSprite->hide();
+
+ return true;
+ }
+
+
+ // calc sprite position, size and content transformation
+ // =====================================================
+
+ // the shape transformation for a sprite is always a
+ // simple scale-up to the nominal shape size. Everything
+ // else is handled via the sprite transformation
+ ::basegfx::B2DHomMatrix aNonTranslationalShapeTransformation;
+ aNonTranslationalShapeTransformation.scale( rOrigBounds.getWidth(),
+ rOrigBounds.getHeight() );
+ ::basegfx::B2DHomMatrix aShapeTransformation( aNonTranslationalShapeTransformation );
+ aShapeTransformation.translate( rOrigBounds.getMinX(),
+ rOrigBounds.getMinY() );
+
+ const ::basegfx::B2DHomMatrix& rCanvasTransform(
+ rViewLayer->getSpriteTransformation() );
+
+ // area actually needed for the sprite
+ const ::basegfx::B2DRectangle& rSpriteBoundsPixel(
+ calcUpdateAreaPixel( rUnitBounds,
+ aShapeTransformation,
+ rCanvasTransform,
+ pAttr ) );
+
+ // actual area for the shape (without subsetting, but
+ // including char scaling)
+ const ::basegfx::B2DRectangle& rShapeBoundsPixel(
+ calcUpdateAreaPixel( ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
+ aShapeTransformation,
+ rCanvasTransform,
+ pAttr ) );
+
+ // nominal area for the shape (without subsetting, without
+ // char scaling). NOTE: to cancel the shape translation,
+ // contained in rSpriteBoundsPixel, this is _without_ any
+ // translational component.
+ ::basegfx::B2DRectangle aLogShapeBounds;
+ const ::basegfx::B2DRectangle& rNominalShapeBoundsPixel(
+ shapeArea2AreaPixel( rCanvasTransform,
+ ::canvas::tools::calcTransformedRectBounds(
+ aLogShapeBounds,
+ ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
+ aNonTranslationalShapeTransformation ) ) );
+
+ // create (or resize) sprite with sprite's pixel size, if
+ // not done already
+ const ::basegfx::B2DSize& rSpriteSizePixel(rSpriteBoundsPixel.getRange());
+ if( !mpSprite )
+ {
+ mpSprite.reset(
+ new AnimatedSprite( mpViewLayer,
+ rSpriteSizePixel,
+ nPrio ));
+ }
+ else
+ {
+ // TODO(F2): when the sprite _actually_ gets resized,
+ // content needs a repaint!
+ mpSprite->resize( rSpriteSizePixel );
+ }
+
+ ENSURE_OR_RETURN_FALSE( mpSprite, "ViewShape::renderSprite(): No sprite" );
+
+ VERBOSE_TRACE( "ViewShape::renderSprite(): Rendering sprite 0x%X",
+ mpSprite.get() );
+
+
+ // always show the sprite (might have been hidden before)
+ mpSprite->show();
+
+ // determine center of sprite output position in pixel
+ // (assumption here: all shape transformations have the
+ // shape center as the pivot point). From that, subtract
+ // distance of rSpriteBoundsPixel's left, top edge from
+ // rShapeBoundsPixel's center. This moves the sprite at
+ // the appropriate output position within the virtual
+ // rShapeBoundsPixel area.
+ ::basegfx::B2DPoint aSpritePosPixel( rBounds.getCenter() );
+ aSpritePosPixel *= rCanvasTransform;
+ aSpritePosPixel -= rShapeBoundsPixel.getCenter() - rSpriteBoundsPixel.getMinimum();
+
+ // the difference between rShapeBoundsPixel and
+ // rSpriteBoundsPixel upper, left corner is: the offset we
+ // have to move sprite output to the right, top (to make
+ // the desired subset content visible at all)
+ const ::basegfx::B2DSize& rSpriteCorrectionOffset(
+ rSpriteBoundsPixel.getMinimum() - rNominalShapeBoundsPixel.getMinimum() );
+
+ // offset added top, left for anti-aliasing (otherwise,
+ // shapes fully filling the sprite will have anti-aliased
+ // pixel cut off)
+ const ::basegfx::B2DSize aAAOffset(
+ ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE,
+ ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE );
+
+ // set pixel output offset to sprite: we always leave
+ // ANTIALIASING_EXTRA_SIZE room atop and to the left, and,
+ // what's more, for subsetted shapes, we _have_ to cancel
+ // the effect of the shape renderer outputting the subset
+ // at its absolute position inside the shape, instead of
+ // at the origin.
+ // NOTE: As for now, sprites are always positioned on
+ // integer pixel positions on screen, have to round to
+ // nearest integer here, too
+ mpSprite->setPixelOffset(
+ aAAOffset - ::basegfx::B2DSize(
+ ::basegfx::fround( rSpriteCorrectionOffset.getX() ),
+ ::basegfx::fround( rSpriteCorrectionOffset.getY() ) ) );
+
+ // always set sprite position and transformation, since
+ // they do not relate directly to the update flags
+ // (e.g. sprite position changes when sprite size changes)
+ mpSprite->movePixel( aSpritePosPixel );
+ mpSprite->transform( getSpriteTransformation( rSpriteSizePixel,
+ rOrigBounds.getRange(),
+ pAttr ) );
+
+
+ // process flags
+ // =============
+
+ bool bRedrawRequired( mbForceUpdate || (nUpdateFlags & FORCE) );
+
+ if( mbForceUpdate || (nUpdateFlags & ALPHA) )
+ {
+ mpSprite->setAlpha( (pAttr && pAttr->isAlphaValid()) ?
+ ::basegfx::clamp(pAttr->getAlpha(),
+ 0.0,
+ 1.0) :
+ 1.0 );
+ }
+ if( mbForceUpdate || (nUpdateFlags & CLIP) )
+ {
+ if( pAttr && pAttr->isClipValid() )
+ {
+ ::basegfx::B2DPolyPolygon aClipPoly( pAttr->getClip() );
+
+ // extract linear part of canvas view transformation
+ // (linear means: without translational components)
+ ::basegfx::B2DHomMatrix aViewTransform(
+ mpViewLayer->getTransformation() );
+ aViewTransform.set( 0, 2, 0.0 );
+ aViewTransform.set( 1, 2, 0.0 );
+
+ // make the clip 2*ANTIALIASING_EXTRA_SIZE larger
+ // such that it's again centered over the sprite.
+ aViewTransform.scale(rSpriteSizePixel.getX()/
+ (rSpriteSizePixel.getX()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE),
+ rSpriteSizePixel.getY()/
+ (rSpriteSizePixel.getY()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE));
+
+ // transform clip polygon from view to device
+ // coordinate space
+ aClipPoly.transform( aViewTransform );
+
+ mpSprite->clip( aClipPoly );
+ }
+ else
+ mpSprite->clip();
+ }
+ if( mbForceUpdate || (nUpdateFlags & CONTENT) )
+ {
+ bRedrawRequired = true;
+
+ // TODO(P1): maybe provide some appearance change methods at
+ // the Renderer interface
+
+ // force the renderer to be regenerated below, for the
+ // different attributes to take effect
+ invalidateRenderer();
+ }
+
+ mbForceUpdate = false;
+
+ if( !bRedrawRequired )
+ return true;
+
+
+ // sprite needs repaint - output to sprite canvas
+ // ==============================================
+
+ ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() );
+
+ return draw( pContentCanvas,
+ rMtf,
+ pAttr,
+ aShapeTransformation,
+ NULL, // clipping is done via Sprite::clip()
+ rSubsets );
+ }
+
+ bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUpdateBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ bool bIsVisible ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::render()" );
+
+ // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
+ // in that all the common setup steps here are refactored to Shape (would then
+ // have to be performed only _once_ per Shape paint).
+
+ if( !bIsVisible )
+ {
+ VERBOSE_TRACE( "ViewShape::render(): skipping shape %X", this );
+
+ // shape is invisible, no need to update anything.
+ return true;
+ }
+
+ // since we have no sprite here, _any_ update request
+ // translates into a required redraw.
+ bool bRedrawRequired( mbForceUpdate || nUpdateFlags != 0 );
+
+ if( (nUpdateFlags & CONTENT) )
+ {
+ // TODO(P1): maybe provide some appearance change methods at
+ // the Renderer interface
+
+ // force the renderer to be regenerated below, for the
+ // different attributes to take effect
+ invalidateRenderer();
+ }
+
+ mbForceUpdate = false;
+
+ if( !bRedrawRequired )
+ return true;
+
+ VERBOSE_TRACE( "ViewShape::render(): rendering shape %X at position (%f,%f)",
+ this,
+ rBounds.getMinX(),
+ rBounds.getMinY() );
+
+
+ // shape needs repaint - setup all that's needed
+ // ---------------------------------------------
+
+ boost::optional<basegfx::B2DPolyPolygon> aClip;
+
+ if( pAttr )
+ {
+ // setup clip poly
+ if( pAttr->isClipValid() )
+ aClip.reset( pAttr->getClip() );
+
+ // emulate global shape alpha by first rendering into
+ // a temp bitmap, and then to screen (this would have
+ // been much easier if we'd be currently a sprite -
+ // see above)
+ if( pAttr->isAlphaValid() )
+ {
+ const double nAlpha( pAttr->getAlpha() );
+
+ if( !::basegfx::fTools::equalZero( nAlpha ) &&
+ !::rtl::math::approxEqual(nAlpha, 1.0) )
+ {
+ // render with global alpha - have to prepare
+ // a bitmap, and render that with modulated
+ // alpha
+ // -------------------------------------------
+
+ const ::basegfx::B2DHomMatrix aTransform(
+ getShapeTransformation( rBounds,
+ pAttr ) );
+
+ // TODO(P1): Should the view transform some
+ // day contain rotation/shear, transforming
+ // the original bounds with the total
+ // transformation might result in smaller
+ // overall bounds.
+
+ // determine output rect of _shape update
+ // area_ in device pixel
+ const ::basegfx::B2DHomMatrix aCanvasTransform(
+ rDestinationCanvas->getTransformation() );
+ ::basegfx::B2DRectangle aTmpRect;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRect,
+ rUpdateBounds,
+ aCanvasTransform );
+
+ // pixel size of cache bitmap: round up to
+ // nearest int
+ const ::basegfx::B2ISize aBmpSize( static_cast<sal_Int32>( aTmpRect.getWidth() )+1,
+ static_cast<sal_Int32>( aTmpRect.getHeight() )+1 );
+
+ // try to fetch temporary surface for alpha
+ // compositing (to achieve the global alpha
+ // blend effect, have to first render shape as
+ // a whole, then blit that surface with global
+ // alpha to the destination)
+ const RendererCacheVector::iterator aCompositingSurface(
+ getCacheEntry( rDestinationCanvas ) );
+
+ if( !aCompositingSurface->mpLastBitmapCanvas ||
+ aCompositingSurface->mpLastBitmapCanvas->getSize() != aBmpSize )
+ {
+ // create a bitmap of appropriate size
+ ::cppcanvas::BitmapSharedPtr pBitmap(
+ ::cppcanvas::BaseGfxFactory::getInstance().createAlphaBitmap(
+ rDestinationCanvas,
+ aBmpSize ) );
+
+ ENSURE_OR_THROW(pBitmap,
+ "ViewShape::render(): Could not create compositing surface");
+
+ aCompositingSurface->mpDestinationCanvas = rDestinationCanvas;
+ aCompositingSurface->mpLastBitmap = pBitmap;
+ aCompositingSurface->mpLastBitmapCanvas = pBitmap->getBitmapCanvas();
+ }
+
+ // buffer aCompositingSurface iterator content
+ // - said one might get invalidated during
+ // draw() below.
+ ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
+ aCompositingSurface->mpLastBitmapCanvas );
+
+ ::cppcanvas::BitmapSharedPtr pBitmap(
+ aCompositingSurface->mpLastBitmap);
+
+ // setup bitmap canvas transformation -
+ // which happens to be the destination
+ // canvas transformation without any
+ // translational components.
+ //
+ // But then, the render transformation as
+ // calculated by getShapeTransformation()
+ // above outputs the shape at its real
+ // destination position. Thus, we have to
+ // offset the output back to the origin,
+ // for which we simply plug in the
+ // negative position of the left, top edge
+ // of the shape's bound rect in device
+ // pixel into aLinearTransform below.
+ ::basegfx::B2DHomMatrix aAdjustedCanvasTransform( aCanvasTransform );
+ aAdjustedCanvasTransform.translate( -aTmpRect.getMinX(),
+ -aTmpRect.getMinY() );
+
+ pBitmapCanvas->setTransformation( aAdjustedCanvasTransform );
+
+ // TODO(P2): If no update flags, or only
+ // alpha_update is set, we can save us the
+ // rendering into the bitmap (uh, it's not
+ // _that_ easy - for a forced redraw,
+ // e.g. when ending an animation, we always
+ // get UPDATE_FORCE here).
+
+ // render into this bitmap
+ if( !draw( pBitmapCanvas,
+ rMtf,
+ pAttr,
+ aTransform,
+ !aClip ? NULL : &(*aClip),
+ rSubsets ) )
+ {
+ return false;
+ }
+
+ // render bitmap to screen, with given global
+ // alpha. Since the bitmap already contains
+ // pixel-equivalent output, we have to use the
+ // inverse view transformation, adjusted with
+ // the final shape output position (note:
+ // cannot simply change the view
+ // transformation here, as that would affect a
+ // possibly set clip!)
+ ::basegfx::B2DHomMatrix aBitmapTransform( aCanvasTransform );
+ OSL_ENSURE( aBitmapTransform.isInvertible(),
+ "ViewShape::render(): View transformation is singular!" );
+
+ aBitmapTransform.invert();
+
+ const basegfx::B2DHomMatrix aTranslation(basegfx::tools::createTranslateB2DHomMatrix(
+ aTmpRect.getMinX(), aTmpRect.getMinY()));
+
+ aBitmapTransform = aBitmapTransform * aTranslation;
+ pBitmap->setTransformation( aBitmapTransform );
+
+ // finally, render bitmap alpha-modulated
+ pBitmap->drawAlphaModulated( nAlpha );
+
+ return true;
+ }
+ }
+ }
+
+ // retrieve shape transformation, _with_ shape translation
+ // to actual page position.
+ const ::basegfx::B2DHomMatrix aTransform(
+ getShapeTransformation( rBounds,
+ pAttr ) );
+
+ return draw( rDestinationCanvas,
+ rMtf,
+ pAttr,
+ aTransform,
+ !aClip ? NULL : &(*aClip),
+ rSubsets );
+ }
+
+
+ // -------------------------------------------------------------------------------------
+
+ ViewShape::ViewShape( const ViewLayerSharedPtr& rViewLayer ) :
+ mpViewLayer( rViewLayer ),
+ maRenderers(),
+ mpSprite(),
+ mbAnimationMode( false ),
+ mbForceUpdate( true )
+ {
+ ENSURE_OR_THROW( mpViewLayer, "ViewShape::ViewShape(): Invalid View" );
+ }
+
+ ViewLayerSharedPtr ViewShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ ViewShape::RendererCacheVector::iterator ViewShape::getCacheEntry( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas ) const
+ {
+ // lookup destination canvas - is there already a renderer
+ // created for that target?
+ RendererCacheVector::iterator aIter;
+ const RendererCacheVector::iterator aEnd( maRenderers.end() );
+
+ // already there?
+ if( (aIter=::std::find_if( maRenderers.begin(),
+ aEnd,
+ ::boost::bind(
+ ::std::equal_to< ::cppcanvas::CanvasSharedPtr >(),
+ ::boost::cref( rDestinationCanvas ),
+ ::boost::bind(
+ &RendererCacheEntry::getDestinationCanvas,
+ _1 ) ) ) ) == aEnd )
+ {
+ if( maRenderers.size() >= MAX_RENDER_CACHE_ENTRIES )
+ {
+ // cache size exceeded - prune entries. For now,
+ // simply remove the first one, which of course
+ // breaks for more complex access schemes. But in
+ // general, this leads to most recently used
+ // entries to reside at the end of the vector.
+ maRenderers.erase( maRenderers.begin() );
+
+ // ATTENTION: after this, both aIter and aEnd are
+ // invalid!
+ }
+
+ // not yet in cache - add default-constructed cache
+ // entry, to have something to return
+ maRenderers.push_back( RendererCacheEntry() );
+ aIter = maRenderers.end()-1;
+ }
+
+ return aIter;
+ }
+
+ ::cppcanvas::RendererSharedPtr ViewShape::getRenderer( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const
+ {
+ // lookup destination canvas - is there already a renderer
+ // created for that target?
+ const RendererCacheVector::iterator aIter(
+ getCacheEntry( rDestinationCanvas ) );
+
+ // now we have a valid entry, either way. call prefetch()
+ // on it, nevertheless - maybe the metafile changed, and
+ // the renderer still needs an update (prefetch() will
+ // detect that)
+ if( prefetch( *aIter,
+ rDestinationCanvas,
+ rMtf,
+ rAttr ) )
+ {
+ return aIter->mpRenderer;
+ }
+ else
+ {
+ // prefetch failed - renderer is invalid
+ return ::cppcanvas::RendererSharedPtr();
+ }
+ }
+
+ void ViewShape::invalidateRenderer() const
+ {
+ // simply clear the cache. Subsequent getRenderer() calls
+ // will regenerate the Renderers.
+ maRenderers.clear();
+ }
+
+ ::basegfx::B2DSize ViewShape::getAntialiasingBorder() const
+ {
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(),
+ "ViewShape::getAntialiasingBorder(): Invalid ViewLayer canvas" );
+
+ const ::basegfx::B2DHomMatrix& rViewTransform(
+ mpViewLayer->getTransformation() );
+
+ // TODO(F1): As a quick shortcut (did not want to invert
+ // whole matrix here), taking only scale components of
+ // view transformation matrix. This will be wrong when
+ // e.g. shearing is involved.
+ const double nXBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(0,0) );
+ const double nYBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(1,1) );
+
+ return ::basegfx::B2DSize( nXBorder,
+ nYBorder );
+ }
+
+ bool ViewShape::enterAnimationMode()
+ {
+ mbForceUpdate = true;
+ mbAnimationMode = true;
+
+ return true;
+ }
+
+ void ViewShape::leaveAnimationMode()
+ {
+ mpSprite.reset();
+ mbAnimationMode = false;
+ mbForceUpdate = true;
+ }
+
+ bool ViewShape::update( const GDIMetaFileSharedPtr& rMtf,
+ const RenderArgs& rArgs,
+ int nUpdateFlags,
+ bool bIsVisible ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::update()" );
+ ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(), "ViewShape::update(): Invalid layer canvas" );
+
+ // Shall we render to a sprite, or to a plain canvas?
+ if( isBackgroundDetached() )
+ return renderSprite( mpViewLayer,
+ rMtf,
+ rArgs.maOrigBounds,
+ rArgs.maBounds,
+ rArgs.maUnitBounds,
+ nUpdateFlags,
+ rArgs.mrAttr,
+ rArgs.mrSubsets,
+ rArgs.mnShapePriority,
+ bIsVisible );
+ else
+ return render( mpViewLayer->getCanvas(),
+ rMtf,
+ rArgs.maBounds,
+ rArgs.maUpdateBounds,
+ nUpdateFlags,
+ rArgs.mrAttr,
+ rArgs.mrSubsets,
+ bIsVisible );
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewshape.hxx b/slideshow/source/engine/shapes/viewshape.hxx
new file mode 100644
index 000000000000..b1808c2c96c2
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewshape.hxx
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWSHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWSHAPE_HXX
+
+#include <cppcanvas/renderer.hxx>
+#include <cppcanvas/bitmap.hxx>
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+#include "tools.hxx"
+#include "shapeattributelayer.hxx"
+#include "animatedsprite.hxx"
+#include "viewlayer.hxx"
+#include "doctreenode.hxx"
+
+#include <vector>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's XShape, associated to a specific View
+
+ The class is able to render the associated XShape on
+ View implementations.
+ */
+ class ViewShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewShape for the given View
+
+ @param rView
+ The associated View object.
+ */
+ explicit ViewShape( const ViewLayerSharedPtr& rViewLayer );
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ /** Query dimension of a safety border around the shape for AA
+
+ If the view performs antialiasing, this method
+ calculates a safety border around the shape, in the
+ shape coordinate system, which is guaranteed to
+ include every pixel touched when rendering the shape.
+ */
+ ::basegfx::B2DSize getAntialiasingBorder() const;
+
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ /** Notify the ViewShape that an animation starts now
+
+ This method enters animation mode on the associate
+ target view. The shape can be animated in parallel on
+ different views.
+
+ @return whether the mode change finished successfully.
+ */
+ bool enterAnimationMode();
+
+ /** Notify the ViewShape that it is no longer animated
+
+ This methods ends animation mode on the associate
+ target view
+ */
+ void leaveAnimationMode();
+
+ /** Query whether the ViewShape is currently animated
+
+ This method checks whether the ViewShape is currently in
+ animation mode.
+ */
+ bool isBackgroundDetached() const { return mbAnimationMode; }
+
+
+ // render methods
+ //------------------------------------------------------------------
+
+ enum UpdateFlags
+ {
+ NONE= 0,
+ TRANSFORMATION= 1,
+ CLIP= 2,
+ ALPHA= 4,
+ POSITION= 8,
+ CONTENT= 16,
+ FORCE= 32
+ };
+
+ struct RenderArgs
+ {
+ /** Create render argument struct
+
+ @param rOrigBounds
+ The initial shape bounds
+
+ @param rUpdateBounds
+ The area covered by the shape
+
+ @param rBounds
+ The current shape bounds
+
+ @param rAttr
+ The current shape attribute set. Can be NULL, for
+ default attributes. Attention: stored as a reference,
+ thus, parameter object must stay valid!
+
+ @param rSubsets
+ Vector of subset rendering ranges. Attention:
+ stored as a reference, thus, parameter object must
+ stay valid!
+
+ @param nPrio
+ Shape priority
+ */
+ RenderArgs( const ::basegfx::B2DRectangle& rOrigBounds,
+ const ::basegfx::B2DRectangle& rUpdateBounds,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUnitBounds,
+ const ShapeAttributeLayerSharedPtr& rAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ double nPrio ) :
+ maOrigBounds( rOrigBounds ),
+ maUpdateBounds( rUpdateBounds ),
+ maBounds( rBounds ),
+ maUnitBounds( rUnitBounds ),
+ mrAttr( rAttr ),
+ mrSubsets( rSubsets ),
+ mnShapePriority( nPrio )
+ {
+ }
+
+ const ::basegfx::B2DRectangle maOrigBounds;
+ const ::basegfx::B2DRectangle maUpdateBounds;
+ const ::basegfx::B2DRectangle maBounds;
+ const ::basegfx::B2DRectangle maUnitBounds;
+ const ShapeAttributeLayerSharedPtr& mrAttr;
+ const VectorOfDocTreeNodes& mrSubsets;
+ const double mnShapePriority;
+ };
+
+ /** Update the ViewShape
+
+ This method updates the ViewShape on the associated
+ view. If the shape is currently animated, the render
+ target is the sprite, otherwise the view's
+ canvas. This method does not render anything, if the
+ update flags are 0.
+
+ @param rMtf
+ The metafile representation of the shape
+
+ @param rArgs
+ Parameter structure, containing all necessary arguments
+
+ @param nUpdateFlags
+ Bitmask of things to update. Use FORCE to force a repaint.
+
+ @param bIsVisible
+ When false, the shape is fully invisible (and possibly
+ don't need to be painted)
+
+ @return whether the rendering finished successfully.
+ */
+ bool update( const GDIMetaFileSharedPtr& rMtf,
+ const RenderArgs& rArgs,
+ int nUpdateFlags,
+ bool bIsVisible ) const;
+
+ /** Retrieve renderer for given canvas and metafile.
+
+ If necessary, the renderer is created or updated for
+ the metafile and attribute layer.
+
+ @return a renderer that renders to the given
+ destination canvas
+ */
+ ::cppcanvas::RendererSharedPtr getRenderer( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const;
+
+
+ private:
+ struct RendererCacheEntry
+ {
+ RendererCacheEntry() :
+ mpDestinationCanvas(),
+ mpRenderer(),
+ mpMtf(),
+ mpLastBitmap(),
+ mpLastBitmapCanvas()
+ {
+ }
+
+ ::cppcanvas::CanvasSharedPtr getDestinationCanvas() const
+ {
+ return mpDestinationCanvas;
+ }
+
+ ::cppcanvas::CanvasSharedPtr mpDestinationCanvas;
+ ::cppcanvas::RendererSharedPtr mpRenderer;
+ GDIMetaFileSharedPtr mpMtf;
+ ::cppcanvas::BitmapSharedPtr mpLastBitmap;
+ ::cppcanvas::BitmapCanvasSharedPtr mpLastBitmapCanvas;
+ };
+
+ typedef ::std::vector< RendererCacheEntry > RendererCacheVector;
+
+
+ /** Prefetch Renderer for given canvas
+ */
+ bool prefetch( RendererCacheEntry& io_rCacheEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const;
+
+ /** Draw with prefetched Renderer to stored canvas
+
+ This method draws prefetched Renderer to its
+ associated canvas (which happens to be mpLastCanvas).
+ */
+ bool draw( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ const ::basegfx::B2DPolyPolygon* pClip,
+ const VectorOfDocTreeNodes& rSubsets ) const;
+
+ /** Render shape to an active sprite
+ */
+ bool renderSprite( const ViewLayerSharedPtr& rViewLayer,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rOrigBounds,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUnitBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ double nPrio,
+ bool bIsVisible ) const;
+
+ /** Render shape to given canvas
+ */
+ bool render( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUpdateBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ bool bIsVisible ) const;
+
+ /** Calc sprite size in pixel
+
+ Converts user coordinate system to device pixel, and
+ adds antialiasing border.
+
+ @param rUserSize
+ Size of the sprite in user coordinate system (doc coordinates)
+ */
+ ::basegfx::B2DSize calcSpriteSizePixel( const ::basegfx::B2DSize& rUserSize ) const;
+
+ enum{ MAX_RENDER_CACHE_ENTRIES=2 };
+
+ /** Retrieve a valid iterator to renderer cache entry
+
+ This method ensures that an internal limit of
+ MAX_RENDER_CACHE_ENTRIES is not exceeded.
+
+ @param rDestinationCanvas
+ Destination canvas to retrieve cache entry for
+
+ @return a valid iterator to a renderer cache entry for
+ the given canvas. The entry might be
+ default-constructed (if newly added)
+ */
+ RendererCacheVector::iterator getCacheEntry( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas ) const;
+
+ void invalidateRenderer() const;
+
+ /** The view layer this object is part of.
+
+ Needed for sprite creation
+ */
+ ViewLayerSharedPtr mpViewLayer;
+
+ /// A set of cached mtf/canvas combinations
+ mutable RendererCacheVector maRenderers;
+
+ /// The sprite object
+ mutable AnimatedSpriteSharedPtr mpSprite;
+
+ /// If true, render() calls go to the sprite
+ mutable bool mbAnimationMode;
+
+ /// If true, shape needs full repaint (and the sprite a setup, if any)
+ mutable bool mbForceUpdate;
+ };
+
+ typedef ::boost::shared_ptr< ViewShape > ViewShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapesubset.cxx b/slideshow/source/engine/shapesubset.cxx
new file mode 100644
index 000000000000..29e635b43404
--- /dev/null
+++ b/slideshow/source/engine/shapesubset.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include "shapesubset.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ShapeSubset::ShapeSubset( const AttributableShapeSharedPtr& rOriginalShape,
+ const DocTreeNode& rTreeNode,
+ const SubsettableShapeManagerSharedPtr& rShapeManager ) :
+ mpOriginalShape( rOriginalShape ),
+ mpSubsetShape(),
+ maTreeNode( rTreeNode ),
+ mpShapeManager( rShapeManager )
+ {
+ ENSURE_OR_THROW( mpShapeManager,
+ "ShapeSubset::ShapeSubset(): Invalid shape manager" );
+ }
+
+ ShapeSubset::ShapeSubset( const ShapeSubsetSharedPtr& rOriginalSubset,
+ const DocTreeNode& rTreeNode ) :
+ mpOriginalShape( rOriginalSubset->mpSubsetShape ?
+ rOriginalSubset->mpSubsetShape :
+ rOriginalSubset->mpOriginalShape ),
+ mpSubsetShape(),
+ maTreeNode( rTreeNode ),
+ mpShapeManager( rOriginalSubset->mpShapeManager )
+ {
+ ENSURE_OR_THROW( mpShapeManager,
+ "ShapeSubset::ShapeSubset(): Invalid shape manager" );
+ ENSURE_OR_THROW( rOriginalSubset->maTreeNode.isEmpty() ||
+ (rTreeNode.getStartIndex() >= rOriginalSubset->maTreeNode.getStartIndex() &&
+ rTreeNode.getEndIndex() <= rOriginalSubset->maTreeNode.getEndIndex()),
+ "ShapeSubset::ShapeSubset(): Subset is bigger than parent" );
+ }
+
+ ShapeSubset::ShapeSubset( const AttributableShapeSharedPtr& rOriginalShape,
+ const SubsettableShapeManagerSharedPtr& rShapeManager ) :
+ mpOriginalShape( rOriginalShape ),
+ mpSubsetShape(),
+ maTreeNode(),
+ mpShapeManager( rShapeManager )
+ {
+ ENSURE_OR_THROW( mpShapeManager,
+ "ShapeSubset::ShapeSubset(): Invalid shape manager" );
+ }
+
+ ShapeSubset::~ShapeSubset()
+ {
+ try
+ {
+ // if not done yet: revoke subset from original
+ disableSubsetShape();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ AttributableShapeSharedPtr ShapeSubset::getSubsetShape() const
+ {
+ return mpSubsetShape ? mpSubsetShape : mpOriginalShape;
+ }
+
+ bool ShapeSubset::enableSubsetShape()
+ {
+ if( !mpSubsetShape &&
+ !maTreeNode.isEmpty() )
+ {
+ mpSubsetShape = mpShapeManager->getSubsetShape(
+ mpOriginalShape,
+ maTreeNode );
+ }
+
+ return mpSubsetShape;
+ }
+
+ void ShapeSubset::disableSubsetShape()
+ {
+ if( mpSubsetShape )
+ {
+ mpShapeManager->revokeSubset( mpOriginalShape,
+ mpSubsetShape );
+ mpSubsetShape.reset();
+ }
+ }
+
+ bool ShapeSubset::isFullSet() const
+ {
+ return maTreeNode.isEmpty();
+ }
+
+ DocTreeNode ShapeSubset::getSubset() const
+ {
+ return maTreeNode;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/layer.cxx b/slideshow/source/engine/slide/layer.cxx
new file mode 100644
index 000000000000..c345e8012016
--- /dev/null
+++ b/slideshow/source/engine/slide/layer.cxx
@@ -0,0 +1,367 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b1drange.hxx>
+#include <basegfx/range/b2dpolyrange.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+
+#include "layer.hxx"
+
+#include <boost/bind.hpp>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ Layer::Layer( const basegfx::B2DRange& rMaxLayerBounds,
+ Dummy ) :
+ maViewEntries(),
+ maBounds(),
+ maNewBounds(),
+ maMaxBounds( rMaxLayerBounds ),
+ mbBoundsDirty(false),
+ mbBackgroundLayer(true),
+ mbClipSet(false)
+ {
+ }
+
+ Layer::Layer( const basegfx::B2DRange& rMaxLayerBounds ) :
+ maViewEntries(),
+ maBounds(),
+ maNewBounds(),
+ maMaxBounds( rMaxLayerBounds ),
+ mbBoundsDirty(false),
+ mbBackgroundLayer(false),
+ mbClipSet(false)
+ {
+ }
+
+ ViewLayerSharedPtr Layer::addView( const ViewSharedPtr& rNewView )
+ {
+ OSL_ASSERT( rNewView );
+
+ ViewEntryVector::iterator aIter;
+ const ViewEntryVector::iterator aEnd( maViewEntries.end() );
+ if( (aIter=std::find_if( maViewEntries.begin(),
+ aEnd,
+ boost::bind<bool>(
+ std::equal_to< ViewSharedPtr >(),
+ boost::bind( &ViewEntry::getView, _1 ),
+ boost::cref( rNewView )))) != aEnd )
+ {
+ // already added - just return existing layer
+ return aIter->mpViewLayer;
+
+ }
+
+ // not yet added - create new view layer
+ ViewLayerSharedPtr pNewLayer;
+ if( mbBackgroundLayer )
+ pNewLayer = rNewView;
+ else
+ pNewLayer = rNewView->createViewLayer(maBounds);
+
+ // add to local list
+ maViewEntries.push_back(
+ ViewEntry( rNewView,
+ pNewLayer ));
+
+ return maViewEntries.back().mpViewLayer;
+ }
+
+ ViewLayerSharedPtr Layer::removeView( const ViewSharedPtr& rView )
+ {
+ OSL_ASSERT( rView );
+
+ ViewEntryVector::iterator aIter;
+ const ViewEntryVector::iterator aEnd( maViewEntries.end() );
+ if( (aIter=std::find_if( maViewEntries.begin(),
+ aEnd,
+ boost::bind<bool>(
+ std::equal_to< ViewSharedPtr >(),
+ boost::bind( &ViewEntry::getView, _1 ),
+ boost::cref( rView )))) == aEnd )
+ {
+ // View was not added/is already removed
+ return ViewLayerSharedPtr();
+ }
+
+ OSL_ENSURE( std::count_if( maViewEntries.begin(),
+ aEnd,
+ boost::bind<bool>(
+ std::equal_to< ViewSharedPtr >(),
+ boost::bind( &ViewEntry::getView, _1 ),
+ boost::cref( rView ))) == 1,
+ "Layer::removeView(): view added multiple times" );
+
+ ViewLayerSharedPtr pRet( aIter->mpViewLayer );
+ maViewEntries.erase(aIter);
+
+ return pRet;
+ }
+
+ void Layer::viewChanged( const ViewSharedPtr& rChangedView )
+ {
+ ViewEntryVector::iterator aIter;
+ const ViewEntryVector::iterator aEnd( maViewEntries.end() );
+ if( (aIter=std::find_if( maViewEntries.begin(),
+ aEnd,
+ boost::bind<bool>(
+ std::equal_to< ViewSharedPtr >(),
+ boost::bind( &ViewEntry::getView, _1 ),
+ boost::cref( rChangedView )))) !=
+ aEnd )
+ {
+ // adapt size of given ViewLayer - background layer
+ // resizes with view.
+ if( !mbBackgroundLayer )
+ aIter->mpViewLayer->resize(maBounds);
+ }
+ }
+
+ void Layer::viewsChanged()
+ {
+ // adapt size of given ViewLayer - background layer
+ // resizes with view.
+ if( !mbBackgroundLayer )
+ {
+ std::for_each( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind( &ViewLayer::resize,
+ boost::bind( &ViewEntry::getViewLayer,
+ _1 ),
+ boost::cref(maBounds)));
+ }
+ }
+
+ void Layer::setShapeViews( ShapeSharedPtr const& rShape ) const
+ {
+ rShape->clearAllViewLayers();
+
+ std::for_each( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind(&Shape::addViewLayer,
+ boost::cref(rShape),
+ boost::bind(&ViewEntry::getViewLayer,
+ _1),
+ false ));
+ }
+
+ void Layer::setPriority( const ::basegfx::B1DRange& rPrioRange )
+ {
+ if( !mbBackgroundLayer )
+ {
+ std::for_each( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind( &ViewLayer::setPriority,
+ boost::bind( &ViewEntry::getViewLayer,
+ _1 ),
+ boost::cref(rPrioRange)));
+ }
+ }
+
+ void Layer::addUpdateRange( ::basegfx::B2DRange const& rUpdateRange )
+ {
+ // TODO(Q1): move this to B2DMultiRange
+ if( !rUpdateRange.isEmpty() )
+ maUpdateAreas.appendElement( rUpdateRange,
+ basegfx::ORIENTATION_POSITIVE );
+ }
+
+ void Layer::updateBounds( ShapeSharedPtr const& rShape )
+ {
+ if( !mbBackgroundLayer )
+ {
+ if( !mbBoundsDirty )
+ maNewBounds.reset();
+
+ maNewBounds.expand( rShape->getUpdateArea() );
+ }
+
+ mbBoundsDirty = true;
+ }
+
+ bool Layer::commitBounds()
+ {
+ mbBoundsDirty = false;
+
+ if( mbBackgroundLayer )
+ return false;
+
+ if( maNewBounds == maBounds )
+ return false;
+
+ maBounds = maNewBounds;
+ if( std::count_if( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind( &ViewLayer::resize,
+ boost::bind( &ViewEntry::getViewLayer,
+ _1 ),
+ boost::cref(maBounds)) ) == 0 )
+ {
+ return false;
+ }
+
+ // layer content invalid, update areas have wrong
+ // coordinates/not sensible anymore.
+ clearUpdateRanges();
+
+ return true;
+ }
+
+ void Layer::clearUpdateRanges()
+ {
+ maUpdateAreas.clear();
+ }
+
+ void Layer::clearContent()
+ {
+ // clear content on all view layers
+ std::for_each( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind(
+ &ViewLayer::clear,
+ boost::bind(
+ &ViewEntry::getViewLayer,
+ _1)));
+
+ // layer content cleared, update areas are not sensible
+ // anymore.
+ clearUpdateRanges();
+ }
+
+ class LayerEndUpdate : private boost::noncopyable
+ {
+ public:
+ LayerEndUpdate( LayerSharedPtr const& rLayer ) :
+ mpLayer( rLayer )
+ {}
+
+ ~LayerEndUpdate() { if(mpLayer) mpLayer->endUpdate(); }
+
+ void dismiss() { mpLayer.reset(); }
+
+ private:
+ LayerSharedPtr mpLayer;
+ };
+
+ Layer::EndUpdater Layer::beginUpdate()
+ {
+ if( maUpdateAreas.count() )
+ {
+ // perform proper layer update. That means, setup proper
+ // clipping, and render each shape that intersects with
+ // the calculated update area
+ ::basegfx::B2DPolyPolygon aClip( maUpdateAreas.solveCrossovers() );
+ aClip = ::basegfx::tools::stripNeutralPolygons(aClip);
+ aClip = ::basegfx::tools::stripDispensablePolygons(aClip, false);
+
+ // actually, if there happen to be shapes with zero
+ // update area in the maUpdateAreas vector, the
+ // resulting clip polygon will be empty.
+ if( aClip.count() )
+ {
+ // set clip to all view layers
+ std::for_each( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind(
+ &ViewLayer::setClip,
+ boost::bind(
+ &ViewEntry::getViewLayer,
+ _1),
+ boost::cref(aClip)));
+
+ // clear update area on all view layers
+ std::for_each( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind(
+ &ViewLayer::clear,
+ boost::bind(
+ &ViewEntry::getViewLayer,
+ _1)));
+
+ mbClipSet = true;
+ }
+ }
+
+ return EndUpdater(new LayerEndUpdate(shared_from_this()));
+ }
+
+ void Layer::endUpdate()
+ {
+ if( mbClipSet )
+ {
+ mbClipSet = false;
+
+ basegfx::B2DPolyPolygon aEmptyClip;
+ std::for_each( maViewEntries.begin(),
+ maViewEntries.end(),
+ boost::bind(
+ &ViewLayer::setClip,
+ boost::bind(
+ &ViewEntry::getViewLayer,
+ _1),
+ boost::cref(aEmptyClip)));
+ }
+
+ clearUpdateRanges();
+ }
+
+ bool Layer::isInsideUpdateArea( ShapeSharedPtr const& rShape ) const
+ {
+ return maUpdateAreas.overlaps( rShape->getUpdateArea() );
+ }
+
+ LayerSharedPtr Layer::createBackgroundLayer( const basegfx::B2DRange& rMaxLayerBounds )
+ {
+ return LayerSharedPtr(new Layer( rMaxLayerBounds,
+ BackgroundLayer ));
+ }
+
+ LayerSharedPtr Layer::createLayer( const basegfx::B2DRange& rMaxLayerBounds )
+ {
+ return LayerSharedPtr( new Layer( rMaxLayerBounds ) );
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/layer.hxx b/slideshow/source/engine/slide/layer.hxx
new file mode 100644
index 000000000000..6c257c21125c
--- /dev/null
+++ b/slideshow/source/engine/slide/layer.hxx
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_LAYER_HXX
+#define INCLUDED_SLIDESHOW_LAYER_HXX
+
+#include <basegfx/range/b2dpolyrange.hxx>
+#include <cppcanvas/spritecanvas.hxx>
+
+#include "view.hxx"
+#include "animatableshape.hxx"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include <vector>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class LayerEndUpdate;
+
+ /* Definition of Layer class */
+
+ /** This class represents one layer of output on a Slide.
+
+ Layers group shapes for a certain depth region of a slide.
+
+ Since slides have a notion of depth, i.e. shapes on it
+ have a certain order in which they lie upon each other,
+ this layering must be modeled. A prime example for this
+ necessity are animations of shapes lying behind other
+ shapes. Then, everything behind the animated shape will be
+ in a background layer, the shape itself will be in an
+ animation layer, and everything before it will be in a
+ foreground layer (these layers are most preferrably
+ modeled as XSprite objects internally).
+
+ @attention All methods of this class are only supposed to
+ be called from the LayerManager. Normally, it shouldn't be
+ possible to get hold of an instance of this class at all.
+ */
+ class Layer : public boost::enable_shared_from_this<Layer>,
+ private boost::noncopyable
+ {
+ public:
+ typedef boost::shared_ptr<LayerEndUpdate> EndUpdater;
+
+ /** Create background layer
+
+ This method will create a layer without a ViewLayer,
+ i.e. one that displays directly on the background.
+
+ @param rMaxLayerBounds
+ Maximal bounds of this layer, in user
+ coordinates. This layer will never be larger or extend
+ outside these bounds.
+ */
+ static ::boost::shared_ptr< Layer > createBackgroundLayer( const basegfx::B2DRange& rMaxLayerBounds );
+
+ /** Create non-background layer
+
+ This method will create a layer in front of the
+ background, to contain shapes that should appear in
+ front of animated objects.
+
+ @param rMaxLayerBounds
+ Maximal bounds of this layer, in user
+ coordinates. This layer will never be larger or extend
+ outside these bounds.
+ */
+ static ::boost::shared_ptr< Layer > createLayer( const basegfx::B2DRange& rMaxLayerBounds );
+
+
+ /////////////////////////////////////////////////////////////////////
+
+
+ /** Predicate, whether this layer is the special
+ background layer
+
+ This method is mostly useful for checking invariants.
+ */
+ bool isBackgroundLayer() const { return mbBackgroundLayer; }
+
+ /** Add a view to this layer.
+
+ If the view is already added, this method does not add
+ it a second time, just returning the existing ViewLayer.
+
+ @param rNewView
+ New view to add to this layer.
+
+ @return the newly generated ViewLayer for this View
+ */
+ ViewLayerSharedPtr addView( const ViewSharedPtr& rNewView );
+
+ /** Remove a view
+
+ This method removes the view from this Layer and all
+ shapes included herein.
+
+ @return the ViewLayer of the removed Layer, if
+ any. Otherwise, NULL is returned.
+ */
+ ViewLayerSharedPtr removeView( const ViewSharedPtr& rView );
+
+ /** Notify that given ViewLayer has changed
+
+ @param rChangedView
+ This view's layer will get resized. Afterwards, a
+ complete repaint might be necessary.
+ */
+ void viewChanged( const ViewSharedPtr& rChangedView );
+
+ /** Notify that all ViewLayer have changed
+
+ This resizes all view layers. Afterwards, a complete
+ repaint might be necessary.
+ */
+ void viewsChanged();
+
+ /** Init shape with this layer's views
+
+ @param rShape
+ The shape, that will subsequently display on this
+ layer's views
+ */
+ void setShapeViews( ShapeSharedPtr const& rShape ) const;
+
+
+ /////////////////////////////////////////////////////////////////////
+
+
+ /** Change layer priority range.
+
+ The layer priority affects the position of the layer
+ in the z direction (i.e. before/behind which other
+ layers this one appears). The higher the prio, the
+ further on top of the layer stack this one appears.
+
+ @param rPrioRange
+ The priority range of differing layers must not
+ intersect
+ */
+ void setPriority( const ::basegfx::B1DRange& rPrioRange );
+
+ /** Add an area that needs update
+
+ @param rUpdateRange
+ Area on this layer that needs update
+ */
+ void addUpdateRange( ::basegfx::B2DRange const& rUpdateRange );
+
+ /** Whether any update ranges have been added
+
+ @return true, if any non-empty addUpdateRange() calls
+ have been made since the last render()/update() call.
+ */
+ bool isUpdatePending() const { return maUpdateAreas.count()!=0; }
+
+ /** Update layer bound rect from shape bounds
+ */
+ void updateBounds( ShapeSharedPtr const& rShape );
+
+ /** Commit collected layer bounds to ViewLayer
+
+ Call this method when you're done adding new shapes to
+ the layer.
+
+ @return true, if layer needed a resize (which
+ invalidates its content - you have to repaint all
+ contained shapes!)
+ */
+ bool commitBounds();
+
+ /** Clear all registered update ranges
+
+ This method clears all update ranges that are
+ registered at this layer.
+ */
+ void clearUpdateRanges();
+
+ /** Clear whole layer content
+
+ This method clears the whole layer content. As a
+ byproduct, all update ranges are cleared as well. It
+ makes no sense to maintain them any further, since
+ they only serve for partial updates.
+ */
+ void clearContent();
+
+ /** Init layer update.
+
+ This method initializes a full layer update of the
+ update area. When the last copy of the returned
+ EndUpdater is destroyed, the Layer leaves update mode
+ again.
+
+ @return a update end RAII object.
+ */
+ EndUpdater beginUpdate();
+
+ /** Finish layer update
+
+ Resets clipping and transformation to normal values
+ */
+ void endUpdate();
+
+ /** Check whether given shape is inside current update area.
+
+ @return true, if the given shape is at least partially
+ inside the current update area.
+ */
+ bool isInsideUpdateArea( ShapeSharedPtr const& rShape ) const;
+
+ private:
+ enum Dummy{ BackgroundLayer };
+
+ /** Create background layer
+
+ This constructor will create a layer without a
+ ViewLayer, i.e. one that displays directly on the
+ background.
+
+ @param rMaxLayerBounds
+ Maximal bounds of this layer, in user
+ coordinates. This layer will never be larger or extend
+ outside these bounds.
+
+ @param eFlag
+ Dummy parameter, to disambiguate from normal layer
+ constructor
+ */
+ Layer( const basegfx::B2DRange& rMaxLayerBounds,
+ Dummy eFlag );
+
+ /** Create non-background layer
+
+ This constructor will create a layer in front of the
+ background, to contain shapes that should appear in
+ front of animated objects.
+
+ @param rMaxLayerBounds
+ Maximal bounds of this layer, in user
+ coordinates. This layer will never be larger or extend
+ outside these bounds.
+ */
+ explicit Layer( const basegfx::B2DRange& rMaxLayerBounds );
+
+ struct ViewEntry
+ {
+ ViewEntry( const ViewSharedPtr& rView,
+ const ViewLayerSharedPtr& rViewLayer ) :
+ mpView( rView ),
+ mpViewLayer( rViewLayer )
+ {}
+
+ ViewSharedPtr mpView;
+ ViewLayerSharedPtr mpViewLayer;
+
+ // for generic algo access (which needs actual functions)
+ const ViewSharedPtr& getView() const { return mpView; }
+ const ViewLayerSharedPtr& getViewLayer() const { return mpViewLayer; }
+ };
+
+ typedef ::std::vector< ViewEntry > ViewEntryVector;
+
+ ViewEntryVector maViewEntries;
+ basegfx::B2DPolyRange maUpdateAreas;
+ basegfx::B2DRange maBounds;
+ basegfx::B2DRange maNewBounds;
+ const basegfx::B2DRange maMaxBounds; // maBounds is clipped against this
+ bool mbBoundsDirty; // true, if view layers need resize
+ bool mbBackgroundLayer; // true, if this
+ // layer is the
+ // special
+ // background layer
+ bool mbClipSet; // true, if beginUpdate set a clip
+ };
+
+ typedef ::boost::shared_ptr< Layer > LayerSharedPtr;
+ typedef ::boost::weak_ptr< Layer > LayerWeakPtr;
+ typedef ::std::vector< LayerSharedPtr > LayerVector;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_LAYER_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/layermanager.cxx b/slideshow/source/engine/slide/layermanager.cxx
new file mode 100644
index 000000000000..e8d3a3aa23ab
--- /dev/null
+++ b/slideshow/source/engine/slide/layermanager.cxx
@@ -0,0 +1,923 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <basegfx/range/b1drange.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+#include <o3tl/compat_functional.hxx>
+
+#include "layermanager.hxx"
+
+using namespace ::com::sun::star;
+
+namespace boost
+{
+ // add operator!= for weak_ptr
+ inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
+ slideshow::internal::LayerWeakPtr const& rRHS )
+ {
+ return (rLHS<rRHS) || (rRHS<rLHS);
+ }
+}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ template<typename LayerFunc,
+ typename ShapeFunc> void LayerManager::manageViews(
+ LayerFunc layerFunc,
+ ShapeFunc shapeFunc )
+ {
+ LayerSharedPtr pCurrLayer;
+ ViewLayerSharedPtr pCurrViewLayer;
+ LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
+ const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
+ while( aIter != aEnd )
+ {
+ LayerSharedPtr pLayer = aIter->second.lock();
+ if( pLayer && pLayer != pCurrLayer )
+ {
+ pCurrLayer = pLayer;
+ pCurrViewLayer = layerFunc(pCurrLayer);
+ }
+
+ if( pCurrViewLayer )
+ shapeFunc(aIter->first,pCurrViewLayer);
+
+ ++aIter;
+ }
+ }
+
+ LayerManager::LayerManager( const UnoViewContainer& rViews,
+ const ::basegfx::B2DRange& rPageBounds,
+ bool bDisableAnimationZOrder ) :
+ mrViews(rViews),
+ maLayers(),
+ maXShapeHash( 101 ),
+ maAllShapes(),
+ maUpdateShapes(),
+ maPageBounds( rPageBounds ),
+ mnActiveSprites(0),
+ mbLayerAssociationDirty(false),
+ mbActive(false),
+ mbDisableAnimationZOrder(bDisableAnimationZOrder)
+ {
+ // prevent frequent resizes (won't have more than 4 layers
+ // for 99.9% of the cases)
+ maLayers.reserve(4);
+
+ // create initial background layer
+ maLayers.push_back(
+ Layer::createBackgroundLayer(
+ maPageBounds ));
+
+ // init views
+ std::for_each( mrViews.begin(),
+ mrViews.end(),
+ ::boost::bind(&LayerManager::viewAdded,
+ this,
+ _1) );
+ }
+
+ void LayerManager::activate( bool bSlideBackgoundPainted )
+ {
+ mbActive = true;
+ maUpdateShapes.clear(); // update gets forced via area, or
+ // has happend outside already
+
+ if( !bSlideBackgoundPainted )
+ {
+ std::for_each(mrViews.begin(),
+ mrViews.end(),
+ boost::mem_fn(&View::clearAll));
+
+ // force update of whole slide area
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::bind( &Layer::addUpdateRange,
+ _1,
+ boost::cref(maPageBounds) ));
+ }
+ else
+ {
+ // clear all possibly pending update areas - content
+ // is there, already
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::mem_fn( &Layer::clearUpdateRanges ));
+ }
+
+ updateShapeLayers( bSlideBackgoundPainted );
+ }
+
+ void LayerManager::deactivate()
+ {
+ // TODO(F3): This is mostly a hack. Problem is, there's
+ // currently no smart way of telling shapes "remove your
+ // sprites". Others, like MediaShapes, listen to
+ // start/stop animation events, which is too much overhead
+ // for all shapes, though.
+
+ const bool bMoreThanOneLayer(maLayers.size() > 1);
+ if( mnActiveSprites || bMoreThanOneLayer )
+ {
+ // clear all viewlayers, dump everything but the
+ // background layer - this will also remove all shape
+ // sprites
+ std::for_each(maAllShapes.begin(),
+ maAllShapes.end(),
+ boost::bind( &Shape::clearAllViewLayers,
+ boost::bind( o3tl::select1st<LayerShapeMap::value_type>(),
+ _1 )));
+
+ for (LayerShapeMap::iterator
+ iShape (maAllShapes.begin()),
+ iEnd (maAllShapes.end());
+ iShape!=iEnd;
+ ++iShape)
+ {
+ iShape->second.reset();
+ }
+
+ if( bMoreThanOneLayer )
+ maLayers.erase(maLayers.begin()+1,
+ maLayers.end());
+
+ mbLayerAssociationDirty = true;
+ }
+
+ mbActive = false;
+
+ // only background layer left
+ OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
+ }
+
+ void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
+ {
+ // view must be member of mrViews container
+ OSL_ASSERT( std::find(mrViews.begin(),
+ mrViews.end(),
+ rView) != mrViews.end() );
+
+ // init view content
+ if( mbActive )
+ rView->clearAll();
+
+ // add View to all registered shapes
+ manageViews(
+ boost::bind(&Layer::addView,
+ _1,
+ boost::cref(rView)),
+ // repaint on view add
+ boost::bind(&Shape::addViewLayer,
+ _1,
+ _2,
+ true) );
+
+ // in case we haven't reached all layers from the
+ // maAllShapes, issue addView again for good measure
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::bind( &Layer::addView,
+ _1,
+ boost::cref(rView) ));
+ }
+
+ void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
+ {
+ // view must not be member of mrViews container anymore
+ OSL_ASSERT( std::find(mrViews.begin(),
+ mrViews.end(),
+ rView) == mrViews.end() );
+
+ // remove View from all registered shapes
+ manageViews(
+ boost::bind(&Layer::removeView,
+ _1,
+ boost::cref(rView)),
+ boost::bind(&Shape::removeViewLayer,
+ _1,
+ _2) );
+
+ // in case we haven't reached all layers from the
+ // maAllShapes, issue removeView again for good measure
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::bind( &Layer::removeView,
+ _1,
+ boost::cref(rView) ));
+ }
+
+ void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
+ {
+ (void)rView;
+
+ // view must be member of mrViews container
+ OSL_ASSERT( std::find(mrViews.begin(),
+ mrViews.end(),
+ rView) != mrViews.end() );
+
+ // TODO(P2): selectively update only changed view
+ viewsChanged();
+ }
+
+ void LayerManager::viewsChanged()
+ {
+ if( !mbActive )
+ return;
+
+ // clear view area
+ ::std::for_each( mrViews.begin(),
+ mrViews.end(),
+ ::boost::mem_fn(&View::clearAll) );
+
+ // TODO(F3): resize and repaint all layers
+
+ // render all shapes
+ std::for_each( maAllShapes.begin(),
+ maAllShapes.end(),
+ boost::bind(&Shape::render,
+ boost::bind( ::o3tl::select1st<LayerShapeMap::value_type>(), _1)) );
+ }
+
+ void LayerManager::addShape( const ShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
+
+ // add shape to XShape hash map
+ if( !maXShapeHash.insert(
+ XShapeHash::value_type( rShape->getXShape(),
+ rShape) ).second )
+ {
+ // entry already present, nothing to do
+ return;
+ }
+
+ // add shape to appropriate layer
+ implAddShape( rShape );
+ }
+
+ void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
+ {
+ LayerSharedPtr& rBgLayer( maLayers.front() );
+ rBgLayer->setShapeViews(rShapeEntry.first);
+ rShapeEntry.second = rBgLayer;
+ }
+
+ void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
+
+ LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
+
+ OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
+ mbLayerAssociationDirty = true;
+
+ if( mbDisableAnimationZOrder )
+ putShape2BackgroundLayer(
+ *maAllShapes.insert(aValue).first );
+ else
+ maAllShapes.insert(aValue);
+
+ // update shape, it's just added and not yet painted
+ if( rShape->isVisible() )
+ notifyShapeUpdate( rShape );
+ }
+
+ bool LayerManager::removeShape( const ShapeSharedPtr& rShape )
+ {
+ // remove shape from XShape hash map
+ if( maXShapeHash.erase( rShape->getXShape() ) == 0 )
+ return false; // shape not in map
+
+ OSL_ASSERT( maAllShapes.find(rShape) != maAllShapes.end() );
+
+ implRemoveShape( rShape );
+
+ return true;
+ }
+
+ void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
+
+ const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
+
+ if( aShapeEntry == maAllShapes.end() )
+ return;
+
+ const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
+
+ // Enter shape area to the update area, but only if shape
+ // is visible and not in sprite mode (otherwise, updating
+ // the area doesn't do actual harm, but costs time)
+ // Actually, also add it if it was listed in
+ // maUpdateShapes (might have just gone invisible).
+ if( bShapeUpdateNotified ||
+ (rShape->isVisible() &&
+ !rShape->isBackgroundDetached()) )
+ {
+ LayerSharedPtr pLayer = aShapeEntry->second.lock();
+ if( pLayer )
+ {
+ // store area early, once the shape is removed from
+ // the layers, it no longer has any view references
+ pLayer->addUpdateRange( rShape->getUpdateArea() );
+ }
+ }
+
+ rShape->clearAllViewLayers();
+ maAllShapes.erase( aShapeEntry );
+
+ mbLayerAssociationDirty = true;
+ }
+
+ ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
+ {
+ ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
+
+ const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
+ if( aIter == maXShapeHash.end() )
+ return ShapeSharedPtr(); // not found
+
+ // found, return data part of entry pair.
+ return aIter->second;
+ }
+
+ AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
+ const DocTreeNode& rTreeNode )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+
+ AttributableShapeSharedPtr pSubset;
+
+ // shape already added?
+ if( rOrigShape->createSubset( pSubset,
+ rTreeNode ) )
+ {
+ OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
+
+ // don't add to shape hash, we're dupes to the
+ // original XShape anyway - all subset shapes return
+ // the same XShape as the original one.
+
+ // add shape to corresponding layer
+ implAddShape( pSubset );
+
+ // update original shape, it now shows less content
+ // (the subset is removed from its displayed
+ // output). Subset shape is updated within
+ // implAddShape().
+ if( rOrigShape->isVisible() )
+ notifyShapeUpdate( rOrigShape );
+ }
+
+ return pSubset;
+ }
+
+ void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
+ const AttributableShapeSharedPtr& rSubsetShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+
+ if( rOrigShape->revokeSubset( rSubsetShape ) )
+ {
+ OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
+
+ implRemoveShape( rSubsetShape );
+
+ // update original shape, it now shows more content
+ // (the subset is added back to its displayed output)
+ if( rOrigShape->isVisible() )
+ notifyShapeUpdate( rOrigShape );
+ }
+ }
+
+ void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
+
+ const bool bPrevAnimState( rShape->isBackgroundDetached() );
+
+ rShape->enterAnimationMode();
+
+ // if this call _really_ enabled the animation mode at
+ // rShape, insert it to our enter animation queue, to
+ // perform the necessary layer reorg lazily on
+ // LayerManager::update()/render().
+ if( bPrevAnimState != rShape->isBackgroundDetached() )
+ {
+ ++mnActiveSprites;
+ mbLayerAssociationDirty = true;
+
+ // area needs update (shape is removed from normal
+ // slide, and now rendered as an autonomous
+ // sprite). store in update set
+ if( rShape->isVisible() )
+ addUpdateArea( rShape );
+ }
+
+ // TODO(P1): this can lead to potential wasted effort, if
+ // a shape gets toggled animated/unanimated a few times
+ // between two frames, returning to the original state.
+ }
+
+ void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
+ {
+ ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
+ ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
+
+ const bool bPrevAnimState( rShape->isBackgroundDetached() );
+
+ rShape->leaveAnimationMode();
+
+ // if this call _really_ ended the animation mode at
+ // rShape, insert it to our leave animation queue, to
+ // perform the necessary layer reorg lazily on
+ // LayerManager::update()/render().
+ if( bPrevAnimState != rShape->isBackgroundDetached() )
+ {
+ --mnActiveSprites;
+ mbLayerAssociationDirty = true;
+
+ // shape needs update, no previous rendering, fast
+ // update possible.
+ if( rShape->isVisible() )
+ notifyShapeUpdate( rShape );
+ }
+
+ // TODO(P1): this can lead to potential wasted effort, if
+ // a shape gets toggled animated/unanimated a few times
+ // between two frames, returning to the original state.
+ }
+
+ void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
+ {
+ if( !mbActive || mrViews.empty() )
+ return;
+
+ // hidden sprite-shape needs render() call still, to hide sprite
+ if( rShape->isVisible() || rShape->isBackgroundDetached() )
+ maUpdateShapes.insert( rShape );
+ else
+ addUpdateArea( rShape );
+ }
+
+ bool LayerManager::isUpdatePending() const
+ {
+ if( !mbActive )
+ return false;
+
+ if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
+ return true;
+
+ const LayerVector::const_iterator aEnd( maLayers.end() );
+ if( std::find_if( maLayers.begin(),
+ aEnd,
+ boost::mem_fn(&Layer::isUpdatePending)) != aEnd )
+ return true;
+
+ return false;
+ }
+
+ bool LayerManager::updateSprites()
+ {
+ bool bRet(true);
+
+ // send update() calls to every shape in the
+ // maUpdateShapes set, which is _animated_ (i.e. a
+ // sprite).
+ const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
+ ShapeUpdateSet::const_iterator aCurrShape=maUpdateShapes.begin();
+ while( aCurrShape != aEnd )
+ {
+ if( (*aCurrShape)->isBackgroundDetached() )
+ {
+ // can update shape directly, without
+ // affecting layer content (shape is
+ // currently displayed in a sprite)
+ if( !(*aCurrShape)->update() )
+ bRet = false; // delay error exit
+ }
+ else
+ {
+ // TODO(P2): addUpdateArea() involves log(n)
+ // search for shape layer. Have a frequent
+ // shape/layer association cache, or ptr back to
+ // layer at the shape?
+
+ // cannot update shape directly, it's not
+ // animated and update() calls will prolly
+ // overwrite other page content.
+ addUpdateArea( *aCurrShape );
+ }
+
+ ++aCurrShape;
+ }
+
+ maUpdateShapes.clear();
+
+ return bRet;
+ }
+
+ bool LayerManager::update()
+ {
+ bool bRet = true;
+
+ if( !mbActive )
+ return bRet;
+
+ // going to render - better flush any pending layer reorg
+ // now
+ updateShapeLayers(false);
+
+ // all sprites
+ bRet = updateSprites();
+
+ // any non-sprite update areas left?
+ if( std::find_if( maLayers.begin(),
+ maLayers.end(),
+ boost::mem_fn( &Layer::isUpdatePending )) == maLayers.end() )
+ return bRet; // nope, done.
+
+ // update each shape on each layer, that has
+ // isUpdatePending()
+ bool bIsCurrLayerUpdating(false);
+ Layer::EndUpdater aEndUpdater;
+ LayerSharedPtr pCurrLayer;
+ LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
+ const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
+ while( aIter != aEnd )
+ {
+ LayerSharedPtr pLayer = aIter->second.lock();
+ if( pLayer != pCurrLayer )
+ {
+ pCurrLayer = pLayer;
+ bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
+
+ if( bIsCurrLayerUpdating )
+ aEndUpdater = pCurrLayer->beginUpdate();
+ }
+
+ if( bIsCurrLayerUpdating &&
+ !aIter->first->isBackgroundDetached() &&
+ pCurrLayer->isInsideUpdateArea(aIter->first) )
+ {
+ if( !aIter->first->render() )
+ bRet = false;
+ }
+
+ ++aIter;
+ }
+
+ return bRet;
+ }
+
+ namespace
+ {
+ /** Little wrapper around a Canvas, to render one-shot
+ into a canvas
+ */
+ class DummyLayer : public ViewLayer
+ {
+ public:
+ explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
+ mpCanvas( rCanvas )
+ {
+ }
+
+ virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const
+ {
+ return true; // visible on all views
+ }
+
+ virtual ::cppcanvas::CanvasSharedPtr getCanvas() const
+ {
+ return mpCanvas;
+ }
+
+ virtual void clear() const
+ {
+ // NOOP
+ }
+
+ virtual void clearAll() const
+ {
+ // NOOP
+ }
+
+ virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
+ double /*nSpritePrio*/ ) const
+ {
+ ENSURE_OR_THROW( false,
+ "DummyLayer::createSprite(): This method is not supposed to be called!" );
+ return ::cppcanvas::CustomSpriteSharedPtr();
+ }
+
+ virtual void setPriority( const basegfx::B1DRange& /*rRange*/ )
+ {
+ OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
+ }
+
+ virtual ::basegfx::B2DHomMatrix getTransformation() const
+ {
+ return mpCanvas->getTransformation();
+ }
+
+ virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const
+ {
+ OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
+ return ::basegfx::B2DHomMatrix();
+ }
+
+ virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ )
+ {
+ OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
+ }
+
+ virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ )
+ {
+ OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
+ return false;
+ }
+
+ private:
+ ::cppcanvas::CanvasSharedPtr mpCanvas;
+ };
+ }
+
+ bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
+ {
+ bool bRet( true );
+ ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
+
+ LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
+ const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
+ while( aIter != aEnd )
+ {
+ try
+ {
+ // forward to all shape's addViewLayer method (which
+ // we request to render the Shape on the new
+ // ViewLayer. Since we add the shapes in the
+ // maShapeSet order (which is also the render order),
+ // this is equivalent to a subsequent render() call)
+ aIter->first->addViewLayer( pTmpLayer,
+ true );
+
+ // and remove again, this is only temporary
+ aIter->first->removeViewLayer( pTmpLayer );
+ }
+ catch( uno::Exception& )
+ {
+ // TODO(E1): Might be superfluous. Nowadays,
+ // addViewLayer swallows all errors, anyway.
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ // at least one shape could not be rendered
+ bRet = false;
+ }
+
+ ++aIter;
+ }
+
+ return bRet;
+ }
+
+ void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
+
+ const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
+
+ if( aShapeEntry == maAllShapes.end() )
+ return;
+
+ LayerSharedPtr pLayer = aShapeEntry->second.lock();
+ if( pLayer )
+ pLayer->addUpdateRange( rShape->getUpdateArea() );
+ }
+
+ void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
+ LayerShapeMap::const_iterator aFirstLayerShape,
+ LayerShapeMap::const_iterator aEndLayerShapes )
+ {
+ const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
+ if( bLayerExists )
+ {
+ const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
+ const bool bLayerResized( rLayer->commitBounds() );
+ rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
+ nCurrLayerIndex+1) );
+
+ if( bLayerResized )
+ {
+ // need to re-render whole layer - start from
+ // clean state
+ rLayer->clearContent();
+
+ // render and remove from update set
+ while( aFirstLayerShape != aEndLayerShapes )
+ {
+ maUpdateShapes.erase(aFirstLayerShape->first);
+ aFirstLayerShape->first->render();
+ ++aFirstLayerShape;
+ }
+ }
+ }
+ }
+
+ LayerSharedPtr LayerManager::createForegroundLayer() const
+ {
+ OSL_ASSERT( mbActive );
+
+ LayerSharedPtr pLayer( Layer::createLayer(
+ maPageBounds ));
+
+ // create ViewLayers for all registered views, and add to
+ // newly created layer.
+ ::std::for_each( mrViews.begin(),
+ mrViews.end(),
+ boost::bind( &Layer::addView,
+ boost::cref(pLayer),
+ _1 ));
+
+ return pLayer;
+ }
+
+ void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ OSL_ASSERT( mbActive );
+
+ // do we need to process shapes?
+ if( !mbLayerAssociationDirty )
+ return;
+
+ if( mbDisableAnimationZOrder )
+ {
+ // layer setup happened elsewhere, is only bg layer
+ // anyway.
+ mbLayerAssociationDirty = false;
+ return;
+ }
+
+ // scan through maAllShapes, and determine shape animation
+ // discontinuities: when a shape that has
+ // isBackgroundDetached() return false follows a shape
+ // with isBackgroundDetached() true, the former and all
+ // following ones must be moved into an own layer.
+
+ // to avoid tons of temporaries, create weak_ptr to Layers
+ // beforehand
+ std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
+ std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
+
+ std::size_t nCurrLayerIndex(0);
+ bool bIsBackgroundLayer(true);
+ bool bLastWasBackgroundDetached(false); // last shape sprite state
+ LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
+ LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
+ const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
+ ShapeUpdateSet aUpdatedShapes; // shapes that need update
+ while( aCurrShapeEntry != aEndShapeEntry )
+ {
+ const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
+ const bool bThisIsBackgroundDetached(
+ pCurrShape->isBackgroundDetached() );
+
+ if( bLastWasBackgroundDetached == true &&
+ bThisIsBackgroundDetached == false )
+ {
+ // discontinuity found - current shape needs to
+ // get into a new layer
+ // --------------------------------------------
+
+ // commit changes to previous layer
+ commitLayerChanges(nCurrLayerIndex,
+ aCurrLayerFirstShapeEntry,
+ aCurrShapeEntry);
+ aCurrLayerFirstShapeEntry=aCurrShapeEntry;
+ ++nCurrLayerIndex;
+ bIsBackgroundLayer = false;
+
+ if( aWeakLayers.size() <= nCurrLayerIndex ||
+ aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
+ {
+ // no more layers left, or shape was not
+ // member of this layer - create a new one
+ maLayers.insert( maLayers.begin()+nCurrLayerIndex,
+ createForegroundLayer() );
+ aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
+ maLayers[nCurrLayerIndex] );
+ }
+ }
+
+ OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
+
+ // note: using indices here, since vector::insert
+ // above invalidates iterators
+ LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
+ LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
+ if( rCurrWeakLayer != aCurrShapeEntry->second )
+ {
+ // mismatch: shape is not contained in current
+ // layer - move shape to that layer, then.
+ maLayers.at(nCurrLayerIndex)->setShapeViews(
+ pCurrShape );
+
+ // layer got new shape(s), need full repaint, if
+ // non-sprite shape
+ if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
+ {
+ LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
+ if( pOldLayer )
+ {
+ // old layer still valid? then we need to
+ // repaint former shape area
+ pOldLayer->addUpdateRange(
+ pCurrShape->getUpdateArea() );
+ }
+
+ // render on new layer (only if not
+ // explicitely disabled)
+ if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
+ maUpdateShapes.insert( pCurrShape );
+ }
+
+ aCurrShapeEntry->second = rCurrWeakLayer;
+ }
+
+ // update layerbounds regardless of the fact that the
+ // shape might be contained in said layer
+ // already. updateBounds() is dumb and needs to
+ // collect all shape bounds.
+ // of course, no need to expand layer bounds for
+ // shapes that reside in sprites themselves.
+ if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
+ rCurrLayer->updateBounds( pCurrShape );
+
+ bLastWasBackgroundDetached = bThisIsBackgroundDetached;
+ ++aCurrShapeEntry;
+ }
+
+ // commit very last layer data
+ commitLayerChanges(nCurrLayerIndex,
+ aCurrLayerFirstShapeEntry,
+ aCurrShapeEntry);
+
+ // any layers left? Bin them!
+ if( maLayers.size() > nCurrLayerIndex+1 )
+ maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
+ maLayers.end());
+
+ mbLayerAssociationDirty = false;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/layermanager.hxx b/slideshow/source/engine/slide/layermanager.hxx
new file mode 100644
index 000000000000..74a643430192
--- /dev/null
+++ b/slideshow/source/engine/slide/layermanager.hxx
@@ -0,0 +1,388 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_LAYERMANAGER_HXX
+#define INCLUDED_SLIDESHOW_LAYERMANAGER_HXX
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <cppcanvas/spritecanvas.hxx>
+
+#include "unoview.hxx"
+#include "unoviewcontainer.hxx"
+#include "attributableshape.hxx"
+#include "layer.hxx"
+#include "tools.hxx"
+
+#include <vector>
+#include <map>
+#include <boost/unordered_map.hpp>
+#include <algorithm>
+#include <functional>
+
+namespace basegfx {
+ class B2DRange;
+}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /* Definition of Layermanager class */
+
+ /** This class manages all of a slide's layers (and shapes)
+
+ Since layer content changes when animations start or end,
+ the layer manager keeps track of this and also handles
+ starting/stopping of Shape animations. Note that none of
+ the methods actually perform a screen update, this is
+ always delayed until the ActivitiesQueue explicitely
+ performs it.
+
+ @see Layer
+ @see Shape
+ */
+ class LayerManager : private boost::noncopyable
+ {
+ public:
+ /** Create a new layer manager for the given page bounds
+
+ @param rViews
+ Views currently registered
+
+ @param rPageBounds
+ Overall page bounds, in user space coordinates
+
+ @param bDisableAnimationZOrder
+ When true, all sprite animations run in the
+ foreground. That is, no extra layers are created, and
+ the slideshow runs potentially faster.
+ */
+ LayerManager( const UnoViewContainer& rViews,
+ const ::basegfx::B2DRange& rPageBounds,
+ bool bDisableAnimationZOrder );
+
+ /** Activate the LayerManager
+
+ This method activates the LayerManager. Prior to
+ activation, this instance will be passive, i.e. won't
+ render anything to any view.
+
+ @param bSlideBackgoundPainted
+ When true, the initial slide content on the background
+ layer is already rendered (e.g. from a previous slide
+ transition). When false, LayerManager also renders
+ initial content of background layer on next update()
+ call.
+ */
+ void activate( bool bSlideBackgoundPainted );
+
+ /** Deactivate the LayerManager
+
+ This method deactivates the LayerManager. After
+ deactivation, this instance will be passive,
+ i.e. don't render anything to any view. Furthermore,
+ if there's currently more than one Layer active, this
+ method also removes all but one.
+ */
+ void deactivate();
+
+ // From ViewEventHandler, forwarded by SlideImpl
+ /// Notify new view added to UnoViewContainer
+ void viewAdded( const UnoViewSharedPtr& rView );
+ /// Notify view removed from UnoViewContainer
+ void viewRemoved( const UnoViewSharedPtr& rView );
+ void viewChanged( const UnoViewSharedPtr& rView );
+ void viewsChanged();
+
+ /** Add the shape to this object
+
+ This method adds a shape to the page.
+ */
+ void addShape( const ShapeSharedPtr& rShape );
+
+ /** Remove shape from this object
+
+ This method removes a shape from the shape.
+ */
+ bool removeShape( const ShapeSharedPtr& rShape );
+
+ /** Lookup a Shape from an XShape model object
+
+ This method looks up the internal shape map for one
+ representing the given XShape.
+
+ @param xShape
+ The XShape object, for which the representing Shape
+ should be looked up.
+ */
+ ShapeSharedPtr lookupShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape ) const;
+
+ /** Query a subset of the given original shape
+
+ This method queries a new (but not necessarily unique)
+ shape, which displays only the given subset of the
+ original one.
+ */
+ AttributableShapeSharedPtr getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
+ const DocTreeNode& rTreeNode );
+
+ /** Revoke a previously queried subset shape.
+
+ With this method, a previously requested subset shape
+ is revoked again. If the last client revokes a given
+ subset, it will cease to be displayed, and the
+ original shape will again show the subset data.
+
+ @param rOrigShape
+ The shape the subset was created from
+
+ @param rSubsetShape
+ The subset created from rOrigShape
+ */
+ void revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
+ const AttributableShapeSharedPtr& rSubsetShape );
+
+ /** Notify the LayerManager that the given Shape starts an
+ animation now.
+
+ This method enters animation mode for the Shape on all
+ registered views.
+ */
+ void enterAnimationMode( const AnimatableShapeSharedPtr& rShape );
+
+ /** Notify the LayerManager that the given Shape is no
+ longer animated.
+
+ This methods ends animation mode for the given Shape
+ on all registered views.
+ */
+ void leaveAnimationMode( const AnimatableShapeSharedPtr& rShape );
+
+ /** Notify that a shape needs an update
+
+ This method notifies the layer manager that a shape
+ update is necessary. This is useful if, during
+ animation playback, changes occur to shapes which make
+ an update necessary on an update() call. Otherwise,
+ update() will not render anything, which is not
+ triggered by calling one of the other LayerManager
+ methods.
+
+ @param rShape
+ Shape which needs an update
+ */
+ void notifyShapeUpdate( const ShapeSharedPtr& rShape);
+
+ /** Check whether any update operations are pending.
+
+ @return true, if this LayerManager has any updates
+ pending, i.e. needs to repaint something for the next
+ frame.
+ */
+ bool isUpdatePending() const;
+
+ /** Update the content
+
+ This method updates the content on all layers on all
+ registered views. It does not issues a
+ View::updateScreen() call on registered views. Please
+ note that this method only takes into account changes
+ to shapes induced directly by calling methods of the
+ LayerManager. If a shape needs an update, because of
+ some external event unknown to the LayerManager (most
+ notably running animations), you have to notify the
+ LayerManager via notifyShapeUpdate().
+
+ @see LayerManager::updateScreen()
+
+ @return whether the update finished successfully.
+ */
+ bool update();
+
+ /** Render the content to given canvas
+
+ This is a one-shot operation, which simply draws all
+ shapes onto the given canvas, without any caching or
+ other fuzz. Don't use that for repeated output onto
+ the same canvas, the View concept is more optimal
+ then.
+
+ @param rTargetCanvas
+ Target canvas to output onto.
+ */
+ bool renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const;
+
+ private:
+ /** A hash map which maps the XShape to the corresponding Shape object.
+
+ Provides quicker lookup than ShapeSet for simple mappings
+ */
+ typedef ::boost::unordered_map<
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >,
+ ShapeSharedPtr,
+ hash< ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > > > XShapeHash;
+
+ class ShapeComparator
+ {
+ public:
+ bool operator() (const ShapeSharedPtr& rpS1, const ShapeSharedPtr& rpS2 ) const
+ {
+ return Shape::lessThanShape::compare(rpS1.get(), rpS2.get());
+ }
+ };
+ /** Set of all shapes
+ */
+ private:
+ typedef ::std::map< ShapeSharedPtr, LayerWeakPtr, ShapeComparator > LayerShapeMap;
+ typedef ::std::set< ShapeSharedPtr > ShapeUpdateSet;
+
+
+ ////////////////////////////////////////////////////////////////////////
+
+
+ /// Adds shape area to containing layer's damage area
+ void addUpdateArea( ShapeSharedPtr const& rShape );
+
+ LayerSharedPtr createForegroundLayer() const;
+
+ /** Push changes from updateShapeLayerAssociations() to current layer
+
+ Factored-out method that resizes layer, if necessary,
+ assigns correct layer priority, and repaints contained shapes.
+
+ @param nCurrLayerIndex
+ Index of current layer in maLayers
+
+ @param aFirstLayerShape
+ Valid iterator out of maAllShapes, denoting the first
+ shape from nCurrLayerIndex
+
+ @param aEndLayerShapes
+ Valid iterator or end iterator out of maAllShapes,
+ denoting one-behind-the-last shape of nCurrLayerIndex
+ */
+ void commitLayerChanges( std::size_t nCurrLayerIndex,
+ LayerShapeMap::const_iterator aFirstLayerShape,
+ LayerShapeMap::const_iterator aEndLayerShapes );
+
+ /** Init Shape layers with background layer.
+ */
+ void putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry );
+
+ /** Commits any pending layer reorg, due to shapes either
+ entering or leaving animation mode
+
+ @param bBackgroundLayerPainted
+ When true, LayerManager does not render anything on
+ the background layer. Use this, if background has been
+ updated by other means (e.g. slide transition)
+ */
+ void updateShapeLayers( bool bBackgroundLayerPainted );
+
+ /** Common stuff when adding a shape
+ */
+ void implAddShape( const ShapeSharedPtr& rShape );
+
+ /** Common stuff when removing a shape
+ */
+ void implRemoveShape( const ShapeSharedPtr& rShape );
+
+ /** Add or remove views
+
+ Sharing duplicate code from viewAdded and viewRemoved
+ method. The only point of variation at those places
+ are removal vs. adding.
+ */
+ template<typename LayerFunc,
+ typename ShapeFunc> void manageViews( LayerFunc layerFunc,
+ ShapeFunc shapeFunc );
+
+ bool updateSprites();
+
+ /// Registered views
+ const UnoViewContainer& mrViews;
+
+ /// All layers of this object. Vector owns the layers
+ LayerVector maLayers;
+
+ /** Contains all shapes with their XShape reference as the key
+ */
+ XShapeHash maXShapeHash;
+
+ /** Set of shapes this LayerManager own
+
+ Contains the same set of shapes as XShapeHash, but is
+ sorted in z order, for painting and layer
+ association. Set entries are enriched with two flags
+ for buffering animation enable/disable changes, and
+ shape update requests.
+ */
+ LayerShapeMap maAllShapes;
+
+ /** Set of shapes that have requested an update
+
+ When a shape is member of this set, its maShapes entry
+ has bNeedsUpdate set to true. We maintain this
+ redundant information for faster update processing.
+ */
+ ShapeUpdateSet maUpdateShapes;
+
+ /** Overall slide bounds (in user coordinate
+ system). shapes that exceed this boundary are clipped,
+ thus, layers only need to be of this size.
+ */
+ const basegfx::B2DRange maPageBounds;
+
+ /// Number of shape sprites currenly active on this LayerManager
+ sal_Int32 mnActiveSprites;
+
+ /// sal_True, if shapes might need to move to different layer
+ bool mbLayerAssociationDirty;
+
+ /// sal_False when deactivated
+ bool mbActive;
+
+ /** When true, all sprite animations run in the foreground. That
+ is, no extra layers are created, and the slideshow runs
+ potentially faster.
+ */
+ bool mbDisableAnimationZOrder;
+ };
+
+ typedef ::boost::shared_ptr< LayerManager > LayerManagerSharedPtr;
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_LAYERMANAGER_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/makefile.mk b/slideshow/source/engine/slide/makefile.mk
new file mode 100644
index 000000000000..953307d621c1
--- /dev/null
+++ b/slideshow/source/engine/slide/makefile.mk
@@ -0,0 +1,51 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=slideshow
+TARGET=slide
+ENABLE_EXCEPTIONS=TRUE
+PRJINC=..$/..
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = $(SLO)$/layer.obj \
+ $(SLO)$/layermanager.obj \
+ $(SLO)$/shapemanagerimpl.obj \
+ $(SLO)$/slideanimations.obj \
+ $(SLO)$/slideimpl.obj \
+ $(SLO)$/userpaintoverlay.obj
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/slide/shapemanagerimpl.cxx b/slideshow/source/engine/slide/shapemanagerimpl.cxx
new file mode 100644
index 000000000000..7ad4f14c5e17
--- /dev/null
+++ b/slideshow/source/engine/slide/shapemanagerimpl.cxx
@@ -0,0 +1,466 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/presentation/XShapeEventListener.hpp>
+#include <com/sun/star/presentation/XSlideShowListener.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+
+#include "shapemanagerimpl.hxx"
+
+#include <boost/bind.hpp>
+
+#include <o3tl/compat_functional.hxx>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+ShapeManagerImpl::ShapeManagerImpl( EventMultiplexer& rMultiplexer,
+ LayerManagerSharedPtr const& rLayerManager,
+ CursorManager& rCursorManager,
+ const ShapeEventListenerMap& rGlobalListenersMap,
+ const ShapeCursorMap& rGlobalCursorMap ):
+ mrMultiplexer(rMultiplexer),
+ mpLayerManager(rLayerManager),
+ mrCursorManager(rCursorManager),
+ mrGlobalListenersMap(rGlobalListenersMap),
+ mrGlobalCursorMap(rGlobalCursorMap),
+ maShapeListenerMap(),
+ maShapeCursorMap(),
+ maHyperlinkShapes(),
+ mbEnabled(false)
+{
+}
+
+void ShapeManagerImpl::activate( bool bSlideBackgoundPainted )
+{
+ if( !mbEnabled )
+ {
+ mbEnabled = true;
+
+ // register this handler on EventMultiplexer.
+ // Higher prio (overrides other engine handlers)
+ mrMultiplexer.addMouseMoveHandler( shared_from_this(), 2.0 );
+ mrMultiplexer.addClickHandler( shared_from_this(), 2.0 );
+ mrMultiplexer.addShapeListenerHandler( shared_from_this() );
+
+ // clone listener map
+ uno::Reference<presentation::XShapeEventListener> xDummyListener;
+ std::for_each( mrGlobalListenersMap.begin(),
+ mrGlobalListenersMap.end(),
+ boost::bind( &ShapeManagerImpl::listenerAdded,
+ this,
+ boost::cref(xDummyListener),
+ boost::bind(
+ o3tl::select1st<ShapeEventListenerMap::value_type>(),
+ _1 )));
+
+ // clone cursor map
+ std::for_each( mrGlobalCursorMap.begin(),
+ mrGlobalCursorMap.end(),
+ boost::bind( &ShapeManagerImpl::cursorChanged,
+ this,
+ boost::bind(
+ o3tl::select1st<ShapeCursorMap::value_type>(),
+ _1 ),
+ boost::bind(
+ o3tl::select2nd<ShapeCursorMap::value_type>(),
+ _1 )));
+
+ if( mpLayerManager )
+ mpLayerManager->activate( bSlideBackgoundPainted );
+ }
+}
+
+void ShapeManagerImpl::deactivate()
+{
+ if( mbEnabled )
+ {
+ mbEnabled = false;
+
+ if( mpLayerManager )
+ mpLayerManager->deactivate();
+
+ maShapeListenerMap.clear();
+ maShapeCursorMap.clear();
+
+ mrMultiplexer.removeShapeListenerHandler( shared_from_this() );
+ mrMultiplexer.removeMouseMoveHandler( shared_from_this() );
+ mrMultiplexer.removeClickHandler( shared_from_this() );
+ }
+}
+
+void ShapeManagerImpl::dispose()
+{
+ // remove listeners (EventMultiplexer holds shared_ptr on us)
+ deactivate();
+
+ maHyperlinkShapes.clear();
+ maShapeCursorMap.clear();
+ maShapeListenerMap.clear();
+ mpLayerManager.reset();
+}
+
+bool ShapeManagerImpl::handleMousePressed( awt::MouseEvent const& )
+{
+ // not used here
+ return false; // did not handle the event
+}
+
+bool ShapeManagerImpl::handleMouseReleased( awt::MouseEvent const& e )
+{
+ if( !mbEnabled || e.Buttons != awt::MouseButton::LEFT)
+ return false;
+
+ basegfx::B2DPoint const aPosition( e.X, e.Y );
+
+ // first check for hyperlinks, because these have
+ // highest prio:
+ rtl::OUString const hyperlink( checkForHyperlink(aPosition) );
+ if( hyperlink.getLength() > 0 )
+ {
+ mrMultiplexer.notifyHyperlinkClicked(hyperlink);
+ return true; // event consumed
+ }
+
+ // find matching shape (scan reversely, to coarsely match
+ // paint order)
+ ShapeToListenersMap::reverse_iterator aCurrBroadcaster(
+ maShapeListenerMap.rbegin() );
+ ShapeToListenersMap::reverse_iterator const aEndBroadcasters(
+ maShapeListenerMap.rend() );
+ while( aCurrBroadcaster != aEndBroadcasters )
+ {
+ // TODO(F2): Get proper geometry polygon from the
+ // shape, to avoid having areas outside the shape
+ // react on the mouse
+ if( aCurrBroadcaster->first->getBounds().isInside( aPosition ) &&
+ aCurrBroadcaster->first->isVisible() )
+ {
+ // shape hit, and shape is visible. Raise
+ // event.
+
+ boost::shared_ptr<cppu::OInterfaceContainerHelper> const pCont(
+ aCurrBroadcaster->second );
+ uno::Reference<drawing::XShape> const xShape(
+ aCurrBroadcaster->first->getXShape() );
+
+ // DON'T do anything with /this/ after this point!
+ pCont->forEach<presentation::XShapeEventListener>(
+ boost::bind( &presentation::XShapeEventListener::click,
+ _1,
+ boost::cref(xShape),
+ boost::cref(e) ));
+
+ return true; // handled this event
+ }
+
+ ++aCurrBroadcaster;
+ }
+
+ return false; // did not handle this event
+}
+
+bool ShapeManagerImpl::handleMouseEntered( const awt::MouseEvent& )
+{
+ // not used here
+ return false; // did not handle the event
+}
+
+bool ShapeManagerImpl::handleMouseExited( const awt::MouseEvent& )
+{
+ // not used here
+ return false; // did not handle the event
+}
+
+bool ShapeManagerImpl::handleMouseDragged( const awt::MouseEvent& )
+{
+ // not used here
+ return false; // did not handle the event
+}
+
+bool ShapeManagerImpl::handleMouseMoved( const awt::MouseEvent& e )
+{
+ if( !mbEnabled )
+ return false;
+
+ // find hit shape in map
+ const ::basegfx::B2DPoint aPosition( e.X, e.Y );
+ sal_Int16 nNewCursor(-1);
+
+ if( checkForHyperlink(aPosition).getLength() > 0 )
+ {
+ nNewCursor = awt::SystemPointer::REFHAND;
+ }
+ else
+ {
+ // find matching shape (scan reversely, to coarsely match
+ // paint order)
+ ShapeToCursorMap::reverse_iterator aCurrCursor(
+ maShapeCursorMap.rbegin() );
+ ShapeToCursorMap::reverse_iterator const aEndCursors(
+ maShapeCursorMap.rend() );
+ while( aCurrCursor != aEndCursors )
+ {
+ // TODO(F2): Get proper geometry polygon from the
+ // shape, to avoid having areas outside the shape
+ // react on the mouse
+ if( aCurrCursor->first->getBounds().isInside( aPosition ) &&
+ aCurrCursor->first->isVisible() )
+ {
+ // shape found, and it's visible. set
+ // requested cursor to shape's
+ nNewCursor = aCurrCursor->second;
+ break;
+ }
+
+ ++aCurrCursor;
+ }
+ }
+
+ if( nNewCursor == -1 )
+ mrCursorManager.resetCursor();
+ else
+ mrCursorManager.requestCursor( nNewCursor );
+
+ return false; // we don't /eat/ this event. Lower prio
+ // handler should see it, too.
+}
+
+bool ShapeManagerImpl::update()
+{
+ if( mbEnabled && mpLayerManager )
+ return mpLayerManager->update();
+
+ return false;
+}
+
+bool ShapeManagerImpl::update( ViewSharedPtr const& /*rView*/ )
+{
+ // am not doing view-specific updates here.
+ return false;
+}
+
+bool ShapeManagerImpl::needsUpdate() const
+{
+ if( mbEnabled && mpLayerManager )
+ return mpLayerManager->isUpdatePending();
+
+ return false;
+}
+
+void ShapeManagerImpl::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
+{
+ if( mbEnabled && mpLayerManager )
+ mpLayerManager->enterAnimationMode(rShape);
+}
+
+void ShapeManagerImpl::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
+{
+ if( mbEnabled && mpLayerManager )
+ mpLayerManager->leaveAnimationMode(rShape);
+}
+
+void ShapeManagerImpl::notifyShapeUpdate( const ShapeSharedPtr& rShape )
+{
+ if( mbEnabled && mpLayerManager )
+ mpLayerManager->notifyShapeUpdate(rShape);
+}
+
+ShapeSharedPtr ShapeManagerImpl::lookupShape( uno::Reference< drawing::XShape > const & xShape ) const
+{
+ if( mpLayerManager )
+ return mpLayerManager->lookupShape(xShape);
+
+ return ShapeSharedPtr();
+}
+
+void ShapeManagerImpl::addHyperlinkArea( const HyperlinkAreaSharedPtr& rArea )
+{
+ maHyperlinkShapes.insert(rArea);
+}
+
+void ShapeManagerImpl::removeHyperlinkArea( const HyperlinkAreaSharedPtr& rArea )
+{
+ maHyperlinkShapes.erase(rArea);
+}
+
+AttributableShapeSharedPtr ShapeManagerImpl::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
+ const DocTreeNode& rTreeNode )
+{
+ if( mpLayerManager )
+ return mpLayerManager->getSubsetShape(rOrigShape,rTreeNode);
+
+ return AttributableShapeSharedPtr();
+}
+
+void ShapeManagerImpl::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
+ const AttributableShapeSharedPtr& rSubsetShape )
+{
+ if( mpLayerManager )
+ mpLayerManager->revokeSubset(rOrigShape,rSubsetShape);
+}
+
+bool ShapeManagerImpl::listenerAdded(
+ const uno::Reference<presentation::XShapeEventListener>& /*xListener*/,
+ const uno::Reference<drawing::XShape>& xShape )
+{
+ ShapeEventListenerMap::const_iterator aIter;
+ if( (aIter = mrGlobalListenersMap.find( xShape )) ==
+ mrGlobalListenersMap.end() )
+ {
+ ENSURE_OR_RETURN_FALSE(false,
+ "ShapeManagerImpl::listenerAdded(): global "
+ "shape listener map inconsistency!");
+ }
+
+ // is this one of our shapes? other shapes are ignored.
+ ShapeSharedPtr pShape( lookupShape(xShape) );
+ if( pShape )
+ {
+ maShapeListenerMap.insert(
+ ShapeToListenersMap::value_type(
+ pShape,
+ aIter->second));
+ }
+
+ return true;
+}
+
+bool ShapeManagerImpl::listenerRemoved(
+ const uno::Reference<presentation::XShapeEventListener>& /*xListener*/,
+ const uno::Reference<drawing::XShape>& xShape )
+{
+ // shape really erased from map? maybe there are other listeners
+ // for the same shape pending...
+ if( mrGlobalListenersMap.find(xShape) == mrGlobalListenersMap.end() )
+ {
+ // is this one of our shapes? other shapes are ignored.
+ ShapeSharedPtr pShape( lookupShape(xShape) );
+ if( pShape )
+ maShapeListenerMap.erase(pShape);
+ }
+
+ return true;
+}
+
+bool ShapeManagerImpl::cursorChanged( const uno::Reference<drawing::XShape>& xShape,
+ sal_Int16 nCursor )
+{
+ ShapeSharedPtr pShape( lookupShape(xShape) );
+
+ // is this one of our shapes? other shapes are ignored.
+ if( !pShape )
+ return false;
+
+ if( mrGlobalCursorMap.find(xShape) == mrGlobalCursorMap.end() )
+ {
+ // erased from global map - erase locally, too
+ maShapeCursorMap.erase(pShape);
+ }
+ else
+ {
+ // included in global map - update local one
+ ShapeToCursorMap::iterator aIter;
+ if( (aIter = maShapeCursorMap.find(pShape))
+ == maShapeCursorMap.end() )
+ {
+ maShapeCursorMap.insert(
+ ShapeToCursorMap::value_type(
+ pShape,
+ nCursor ));
+ }
+ else
+ {
+ aIter->second = nCursor;
+ }
+ }
+
+ return true;
+}
+
+rtl::OUString ShapeManagerImpl::checkForHyperlink( basegfx::B2DPoint const& hitPos ) const
+{
+ // find matching region (scan reversely, to coarsely match
+ // paint order): set is ordered by priority
+ AreaSet::const_reverse_iterator iPos( maHyperlinkShapes.rbegin() );
+ AreaSet::const_reverse_iterator const iEnd( maHyperlinkShapes.rend() );
+ for( ; iPos != iEnd; ++iPos )
+ {
+ HyperlinkAreaSharedPtr const& pArea = *iPos;
+
+ HyperlinkArea::HyperlinkRegions const linkRegions(
+ pArea->getHyperlinkRegions() );
+
+ for( std::size_t i = linkRegions.size(); i--; )
+ {
+ basegfx::B2DRange const& region = linkRegions[i].first;
+ if( region.isInside(hitPos) )
+ return linkRegions[i].second;
+ }
+ }
+
+ return rtl::OUString();
+}
+
+void ShapeManagerImpl::addIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler )
+{
+ maIntrinsicAnimationEventHandlers.add( rHandler );
+}
+
+void ShapeManagerImpl::removeIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler )
+{
+ maIntrinsicAnimationEventHandlers.remove( rHandler );
+}
+
+bool ShapeManagerImpl::notifyIntrinsicAnimationsEnabled()
+{
+ return maIntrinsicAnimationEventHandlers.applyAll(
+ boost::mem_fn(&IntrinsicAnimationEventHandler::enableAnimations));
+}
+
+bool ShapeManagerImpl::notifyIntrinsicAnimationsDisabled()
+{
+ return maIntrinsicAnimationEventHandlers.applyAll(
+ boost::mem_fn(&IntrinsicAnimationEventHandler::disableAnimations));
+}
+
+
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/shapemanagerimpl.hxx b/slideshow/source/engine/slide/shapemanagerimpl.hxx
new file mode 100644
index 000000000000..3a43e8c0a795
--- /dev/null
+++ b/slideshow/source/engine/slide/shapemanagerimpl.hxx
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_SLIDESHOW_SHAPEMANAGERIMPL_HXX
+#define INCLUDED_SLIDESHOW_SHAPEMANAGERIMPL_HXX
+
+#include <osl/mutex.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <com/sun/star/presentation/XShapeEventListener.hpp>
+
+#include "shape.hxx"
+#include "subsettableshapemanager.hxx"
+#include "eventmultiplexer.hxx"
+#include "layermanager.hxx"
+#include "viewupdate.hxx"
+#include "shapemaps.hxx"
+#include "cursormanager.hxx"
+#include "hyperlinkarea.hxx"
+#include "listenercontainer.hxx"
+#include "shapelistenereventhandler.hxx"
+#include "mouseeventhandler.hxx"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+#include <set>
+#include <map>
+
+namespace slideshow {
+namespace internal {
+
+/** Listener class for shape events
+
+ This helper class registers itself on each view, and
+ broadcasts the XShapeEventListener events. The mouse motion
+ events are needed for setting the shape cursor.
+*/
+class ShapeManagerImpl : public SubsettableShapeManager,
+ public ShapeListenerEventHandler,
+ public MouseEventHandler,
+ public ViewUpdate,
+ public boost::enable_shared_from_this<ShapeManagerImpl>,
+ private boost::noncopyable
+{
+public:
+ /** Create a shape event broadcaster
+
+ @param rEventMultiplexer
+ The slideshow-global event source, where this class
+ registeres its event handlers.
+ */
+ ShapeManagerImpl( EventMultiplexer& rMultiplexer,
+ LayerManagerSharedPtr const& rLayerManager,
+ CursorManager& rCursorManager,
+ const ShapeEventListenerMap& rGlobalListenersMap,
+ const ShapeCursorMap& rGlobalCursorMap );
+
+ /** Enables event listening.
+
+ @param bSlideBackgoundPainted
+ When true, the initial slide content on the background layer
+ is already rendered (e.g. from a previous slide
+ transition). When false, slide renders initial content of
+ slide.
+ */
+ void activate( bool bSlideBackgoundPainted );
+
+ /** Disables event listening.
+ */
+ void deactivate();
+
+ // Disposable interface
+ // ---------------------------------------------------------------
+
+ virtual void dispose();
+
+private:
+
+ // MouseEventHandler interface
+ // ---------------------------------------------------------------
+
+ virtual bool handleMousePressed(
+ ::com::sun::star::awt::MouseEvent const& evt );
+ virtual bool handleMouseReleased(
+ ::com::sun::star::awt::MouseEvent const& evt );
+ virtual bool handleMouseEntered(
+ ::com::sun::star::awt::MouseEvent const& evt );
+ virtual bool handleMouseExited(
+ ::com::sun::star::awt::MouseEvent const& evt );
+ virtual bool handleMouseDragged(
+ ::com::sun::star::awt::MouseEvent const& evt );
+ virtual bool handleMouseMoved(
+ ::com::sun::star::awt::MouseEvent const& evt );
+
+
+ // ViewUpdate interface
+ // -------------------------------------------------------------------
+
+ virtual bool update();
+ virtual bool update( ViewSharedPtr const& rView );
+ virtual bool needsUpdate() const;
+
+
+ // ShapeManager interface
+ // ---------------------------------------------------
+
+ virtual void enterAnimationMode( const AnimatableShapeSharedPtr& rShape );
+ virtual void leaveAnimationMode( const AnimatableShapeSharedPtr& rShape );
+ virtual void notifyShapeUpdate( const ShapeSharedPtr& rShape );
+ virtual ShapeSharedPtr lookupShape(
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > const & xShape ) const;
+ virtual void addHyperlinkArea( const boost::shared_ptr<HyperlinkArea>& rArea );
+ virtual void removeHyperlinkArea( const boost::shared_ptr<HyperlinkArea>& rArea );
+
+
+ // SubsettableShapeManager interface
+ // ---------------------------------------------------
+
+ virtual boost::shared_ptr<AttributableShape> getSubsetShape(
+ const boost::shared_ptr<AttributableShape>& rOrigShape,
+ const DocTreeNode& rTreeNode );
+ virtual void revokeSubset(
+ const boost::shared_ptr<AttributableShape>& rOrigShape,
+ const boost::shared_ptr<AttributableShape>& rSubsetShape );
+
+ virtual void addIntrinsicAnimationHandler(
+ const IntrinsicAnimationEventHandlerSharedPtr& rHandler );
+ virtual void removeIntrinsicAnimationHandler(
+ const IntrinsicAnimationEventHandlerSharedPtr& rHandler );
+ virtual bool notifyIntrinsicAnimationsEnabled();
+ virtual bool notifyIntrinsicAnimationsDisabled();
+
+
+ // ShapeListenerEventHandler
+ // ---------------------------------------------
+
+ virtual bool listenerAdded( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::presentation::XShapeEventListener>& xListener,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape>& xShape );
+
+ virtual bool listenerRemoved( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::presentation::XShapeEventListener>& xListener,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape>& xShape );
+
+ // ShapeCursorEventHandler interface
+ // ---------------------------------------------------------------
+
+ virtual bool cursorChanged( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape>& xShape,
+ sal_Int16 nCursor );
+
+
+ ::rtl::OUString checkForHyperlink( ::basegfx::B2DPoint const& hitPos )const;
+
+
+ typedef std::map<ShapeSharedPtr,
+ boost::shared_ptr< ::cppu::OInterfaceContainerHelper >,
+ Shape::lessThanShape> ShapeToListenersMap;
+ typedef std::map<ShapeSharedPtr, sal_Int16,
+ Shape::lessThanShape> ShapeToCursorMap;
+ typedef std::set<HyperlinkAreaSharedPtr,
+ HyperlinkArea::lessThanArea> AreaSet;
+
+ typedef ThreadUnsafeListenerContainer<
+ IntrinsicAnimationEventHandlerSharedPtr,
+ std::vector<IntrinsicAnimationEventHandlerSharedPtr> > ImplIntrinsicAnimationEventHandlers;
+
+ EventMultiplexer& mrMultiplexer;
+ LayerManagerSharedPtr mpLayerManager;
+ CursorManager& mrCursorManager;
+ const ShapeEventListenerMap& mrGlobalListenersMap;
+ const ShapeCursorMap& mrGlobalCursorMap;
+ ShapeToListenersMap maShapeListenerMap;
+ ShapeToCursorMap maShapeCursorMap;
+ AreaSet maHyperlinkShapes;
+ ImplIntrinsicAnimationEventHandlers maIntrinsicAnimationEventHandlers;
+ bool mbEnabled;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_SHAPEMANAGERIMPL_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/slideanimations.cxx b/slideshow/source/engine/slide/slideanimations.cxx
new file mode 100644
index 000000000000..b2b90cda722e
--- /dev/null
+++ b/slideshow/source/engine/slide/slideanimations.cxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/diagnose_ex.h>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include "slideanimations.hxx"
+#include "animationnodefactory.hxx"
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ SlideAnimations::SlideAnimations( const SlideShowContext& rContext,
+ const ::basegfx::B2DVector& rSlideSize ) :
+ maContext( rContext ),
+ maSlideSize( rSlideSize ),
+ mpRootNode()
+ {
+ ENSURE_OR_THROW( maContext.mpSubsettableShapeManager,
+ "SlideAnimations::SlideAnimations(): Invalid SlideShowContext" );
+ }
+
+ SlideAnimations::~SlideAnimations()
+ {
+ if( mpRootNode )
+ {
+ SHOW_NODE_TREE( mpRootNode );
+
+ try
+ {
+ mpRootNode->dispose();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ }
+
+ bool SlideAnimations::importAnimations( const uno::Reference< animations::XAnimationNode >& xRootAnimationNode )
+ {
+ mpRootNode = AnimationNodeFactory::createAnimationNode(
+ xRootAnimationNode,
+ maSlideSize,
+ maContext );
+
+ SHOW_NODE_TREE( mpRootNode );
+
+ return mpRootNode;
+ }
+
+ bool SlideAnimations::isAnimated() const
+ {
+ if( !mpRootNode )
+ return false; // no animations there
+
+ // query root node about pending animations
+ return mpRootNode->hasPendingAnimation();
+ }
+
+ bool SlideAnimations::start()
+ {
+ if( !mpRootNode )
+ return false; // no animations there
+
+ // init all nodes
+ if( !mpRootNode->init() )
+ return false;
+
+ // resolve root node
+ if( !mpRootNode->resolve() )
+ return false;
+
+ return true;
+ }
+
+ void SlideAnimations::end()
+ {
+ if( !mpRootNode )
+ return; // no animations there
+
+ // end root node
+ mpRootNode->deactivate();
+ mpRootNode->end();
+ }
+
+ void SlideAnimations::dispose()
+ {
+ mpRootNode.reset();
+ maContext.dispose();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/slideanimations.hxx b/slideshow/source/engine/slide/slideanimations.hxx
new file mode 100644
index 000000000000..698c8b6a6cfc
--- /dev/null
+++ b/slideshow/source/engine/slide/slideanimations.hxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_SLIDEANIMATIONS_HXX
+#define INCLUDED_SLIDESHOW_SLIDEANIMATIONS_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <basegfx/vector/b2dvector.hxx>
+
+#include "event.hxx"
+#include "slideshowcontext.hxx"
+#include "subsettableshapemanager.hxx"
+#include "animationnode.hxx"
+
+namespace com { namespace sun { namespace star { namespace animations
+{
+ class XAnimationNode;
+} } } }
+
+
+/* Definition of SlideAnimations class */
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class generates and manages all animations of a slide.
+
+ Provided with the root animation node, this class imports
+ the effect information and builds the event tree for all
+ of the slide's animations.
+ */
+ class SlideAnimations
+ {
+ public:
+ /** Create an animation generator.
+
+ @param rContext
+ Slide show context, passing on common parameters
+ */
+ SlideAnimations( const SlideShowContext& rContext,
+ const ::basegfx::B2DVector& rSlideSize );
+ ~SlideAnimations();
+
+ /** Import animations from a SMIL root animation node.
+
+ This method might take some time, depending on the
+ complexity of the SMIL animation network to be
+ imported.
+
+ @param xRootAnimationNode
+ Root animation node for the effects to be
+ generated. This is typically obtained from the
+ XDrawPage's XAnimationNodeSupplier.
+
+ */
+ bool importAnimations( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode >& xRootAnimationNode );
+
+ /** Check, whether imported animations actually contain
+ any effects.
+
+ @return true, if there are actual animations in the
+ imported node tree.
+ */
+ bool isAnimated() const;
+
+ /** Start the animations.
+
+ This method creates the network of events and
+ activities for all animations. The events and
+ activities are inserted into the constructor-provided
+ queues. These queues are not explicitely cleared, if
+ you rely on this object's effects to run without
+ interference, you should clear the queues by yourself.
+
+ @return true, if all events have been successfully
+ created.
+ */
+ bool start();
+
+ /** End all animations.
+
+ This method force-ends all animations. If a slide end
+ event has been registered, that is fired, too.
+ */
+ void end();
+
+ /// Release all references. Does not notify anything.
+ void dispose();
+
+ private:
+ SlideShowContext maContext;
+ const basegfx::B2DVector maSlideSize;
+ AnimationNodeSharedPtr mpRootNode;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_SLIDEANIMATIONS_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/slideimpl.cxx b/slideshow/source/engine/slide/slideimpl.cxx
new file mode 100644
index 000000000000..eb2ee6c1bc57
--- /dev/null
+++ b/slideshow/source/engine/slide/slideimpl.cxx
@@ -0,0 +1,1284 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <osl/diagnose.hxx>
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/canvastools.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/XTargetPropertiesCreator.hpp>
+#include <com/sun/star/drawing/TextAnimationKind.hpp>
+
+#include <animations/animationnodehelper.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/anytostring.hxx>
+
+#include "slide.hxx"
+#include "slideshowcontext.hxx"
+#include "slideanimations.hxx"
+#include "doctreenode.hxx"
+#include "screenupdater.hxx"
+#include "cursormanager.hxx"
+#include "shapeimporter.hxx"
+#include "slideshowexceptions.hxx"
+#include "eventqueue.hxx"
+#include "activitiesqueue.hxx"
+#include "layermanager.hxx"
+#include "shapemanagerimpl.hxx"
+#include "usereventqueue.hxx"
+#include "userpaintoverlay.hxx"
+#include "event.hxx"
+#include "tools.hxx"
+
+#include <o3tl/compat_functional.hxx>
+
+#include <boost/bind.hpp>
+#include <iterator>
+#include <algorithm>
+#include <functional>
+#include <iostream>
+
+using namespace ::com::sun::star;
+
+// -----------------------------------------------------------------------------
+
+namespace slideshow
+{
+namespace internal
+{
+namespace
+{
+
+class SlideImpl : public Slide,
+ public CursorManager,
+ public ViewEventHandler,
+ public ::osl::DebugBase<SlideImpl>
+{
+public:
+ SlideImpl( const uno::Reference<drawing::XDrawPage>& xDrawPage,
+ const uno::Reference<drawing::XDrawPagesSupplier>& xDrawPages,
+ const uno::Reference<animations::XAnimationNode>& xRootNode,
+ EventQueue& rEventQueue,
+ EventMultiplexer& rEventMultiplexer,
+ ScreenUpdater& rScreenUpdater,
+ ActivitiesQueue& rActivitiesQueue,
+ UserEventQueue& rUserEventQueue,
+ CursorManager& rCursorManager,
+ const UnoViewContainer& rViewContainer,
+ const uno::Reference<uno::XComponentContext>& xContext,
+ const ShapeEventListenerMap& rShapeListenerMap,
+ const ShapeCursorMap& rShapeCursorMap,
+ const PolyPolygonVector& rPolyPolygonVector,
+ RGBColor const& rUserPaintColor,
+ double dUserPaintStrokeWidth,
+ bool bUserPaintEnabled,
+ bool bIntrinsicAnimationsAllowed,
+ bool bDisableAnimationZOrder );
+
+ ~SlideImpl();
+
+
+ // Disposable interface
+ // -------------------------------------------------------------------
+
+ virtual void dispose();
+
+
+ // Slide interface
+ // -------------------------------------------------------------------
+
+ virtual bool prefetch();
+ virtual bool show( bool );
+ virtual void hide();
+
+ virtual basegfx::B2ISize getSlideSize() const;
+ virtual uno::Reference<drawing::XDrawPage > getXDrawPage() const;
+ virtual uno::Reference<animations::XAnimationNode> getXAnimationNode() const;
+ virtual PolyPolygonVector getPolygons();
+ virtual void drawPolygons() const;
+ virtual bool isPaintOverlayActive() const;
+ virtual void enablePaintOverlay();
+ virtual void disablePaintOverlay();
+ virtual void update_settings( bool bUserPaintEnabled, RGBColor const& aUserPaintColor, double dUserPaintStrokeWidth );
+
+
+ // TODO(F2): Rework SlideBitmap to no longer be based on XBitmap,
+ // but on canvas-independent basegfx bitmaps
+ virtual SlideBitmapSharedPtr getCurrentSlideBitmap( const UnoViewSharedPtr& rView ) const;
+
+
+private:
+ // ViewEventHandler
+ virtual void viewAdded( const UnoViewSharedPtr& rView );
+ virtual void viewRemoved( const UnoViewSharedPtr& rView );
+ virtual void viewChanged( const UnoViewSharedPtr& rView );
+ virtual void viewsChanged();
+
+ // CursorManager
+ virtual bool requestCursor( sal_Int16 nCursorShape );
+ virtual void resetCursor();
+
+ void activatePaintOverlay();
+ void deactivatePaintOverlay();
+
+ /** Query whether the slide has animations at all
+
+ If the slide doesn't have animations, show() displays
+ only static content. If an event is registered with
+ registerSlideEndEvent(), this event will be
+ immediately activated at the end of the show() method.
+
+ @return true, if this slide has animations, false
+ otherwise
+ */
+ bool isAnimated();
+
+ /// Set all Shapes to their initial attributes for slideshow
+ bool applyInitialShapeAttributes( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XAnimationNode >& xRootAnimationNode );
+
+ /// Renders current slide content to bitmap
+ SlideBitmapSharedPtr createCurrentSlideBitmap(
+ const UnoViewSharedPtr& rView,
+ ::basegfx::B2ISize const & rSlideSize ) const;
+
+ /// Prefetch all shapes (not the animations)
+ bool loadShapes();
+
+ /// Retrieve slide size from XDrawPage
+ basegfx::B2ISize getSlideSizeImpl() const;
+
+ /// Prefetch show, but don't call applyInitialShapeAttributes()
+ bool implPrefetchShow();
+
+ /// Query the rectangle covered by the slide
+ ::basegfx::B2DRectangle getSlideRect() const;
+
+ /// Start GIF and other intrinsic shape animations
+ void endIntrinsicAnimations();
+
+ /// End GIF and other intrinsic shape animations
+ void startIntrinsicAnimations();
+
+ /// Add Polygons to the member maPolygons
+ void addPolygons(PolyPolygonVector aPolygons);
+
+ // Types
+ // =====
+
+ enum SlideAnimationState
+ {
+ CONSTRUCTING_STATE=0,
+ INITIAL_STATE=1,
+ SHOWING_STATE=2,
+ FINAL_STATE=3,
+ SlideAnimationState_NUM_ENTRIES=4
+ };
+
+ typedef std::vector< SlideBitmapSharedPtr > VectorOfSlideBitmaps;
+ /** Vector of slide bitmaps.
+
+ Since the bitmap content is sensitive to animation
+ effects, we have an inner vector containing a distinct
+ bitmap for each of the SlideAnimationStates.
+ */
+ typedef ::std::vector< std::pair< UnoViewSharedPtr,
+ VectorOfSlideBitmaps > > VectorOfVectorOfSlideBitmaps;
+
+
+ // Member variables
+ // ================
+
+ /// The page model object
+ uno::Reference< drawing::XDrawPage > mxDrawPage;
+ uno::Reference< drawing::XDrawPagesSupplier > mxDrawPagesSupplier;
+ uno::Reference< animations::XAnimationNode > mxRootNode;
+
+ LayerManagerSharedPtr mpLayerManager;
+ boost::shared_ptr<ShapeManagerImpl> mpShapeManager;
+ boost::shared_ptr<SubsettableShapeManager> mpSubsettableShapeManager;
+
+ /// Contains common objects needed throughout the slideshow
+ SlideShowContext maContext;
+
+ /// parent cursor manager
+ CursorManager& mrCursorManager;
+
+ /// Handles the animation and event generation for us
+ SlideAnimations maAnimations;
+ PolyPolygonVector maPolygons;
+
+ RGBColor maUserPaintColor;
+ double mdUserPaintStrokeWidth;
+ UserPaintOverlaySharedPtr mpPaintOverlay;
+
+ /// Bitmaps with slide content at various states
+ mutable VectorOfVectorOfSlideBitmaps maSlideBitmaps;
+
+ SlideAnimationState meAnimationState;
+
+ const basegfx::B2ISize maSlideSize;
+
+ sal_Int16 mnCurrentCursor;
+
+ /// True, when intrinsic shape animations are allowed
+ bool mbIntrinsicAnimationsAllowed;
+
+ /// True, when user paint overlay is enabled
+ bool mbUserPaintOverlayEnabled;
+
+ /// True, if initial load of all page shapes succeeded
+ bool mbShapesLoaded;
+
+ /// True, if initial load of all animation info succeeded
+ bool mbShowLoaded;
+
+ /** True, if this slide is not static.
+
+ If this slide has animated content, this variable will
+ be true, and false otherwise.
+ */
+ bool mbHaveAnimations;
+
+ /** True, if this slide has a main animation sequence.
+
+ If this slide has animation content, which in turn has
+ a main animation sequence (which must be fully run
+ before EventMultiplexer::notifySlideAnimationsEnd() is
+ called), this member is true.
+ */
+ bool mbMainSequenceFound;
+
+ /// When true, show() was called. Slide hidden oherwise.
+ bool mbActive;
+
+ ///When true, enablePaintOverlay was called and mbUserPaintOverlay = true
+ bool mbPaintOverlayActive;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////
+
+
+class SlideRenderer
+{
+public:
+ explicit SlideRenderer( SlideImpl& rSlide ) :
+ mrSlide( rSlide )
+ {
+ }
+
+ void operator()( const UnoViewSharedPtr& rView )
+ {
+ // fully clear view content to background color
+ rView->clearAll();
+
+ SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( rView ) );
+ ::cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
+
+ const ::basegfx::B2DHomMatrix aViewTransform( rView->getTransformation() );
+ const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
+
+ // setup a canvas with device coordinate space, the slide
+ // bitmap already has the correct dimension.
+ ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
+ pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // render at given output position
+ pBitmap->move( aOutPosPixel );
+
+ // clear clip (might have been changed, e.g. from comb
+ // transition)
+ pBitmap->clip( ::basegfx::B2DPolyPolygon() );
+ pBitmap->draw( pDevicePixelCanvas );
+ }
+
+private:
+ SlideImpl& mrSlide;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////
+
+
+SlideImpl::SlideImpl( const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Reference<drawing::XDrawPagesSupplier>& xDrawPages,
+ const uno::Reference< animations::XAnimationNode >& xRootNode,
+ EventQueue& rEventQueue,
+ EventMultiplexer& rEventMultiplexer,
+ ScreenUpdater& rScreenUpdater,
+ ActivitiesQueue& rActivitiesQueue,
+ UserEventQueue& rUserEventQueue,
+ CursorManager& rCursorManager,
+ const UnoViewContainer& rViewContainer,
+ const uno::Reference< uno::XComponentContext >& xComponentContext,
+ const ShapeEventListenerMap& rShapeListenerMap,
+ const ShapeCursorMap& rShapeCursorMap,
+ const PolyPolygonVector& rPolyPolygonVector,
+ RGBColor const& aUserPaintColor,
+ double dUserPaintStrokeWidth,
+ bool bUserPaintEnabled,
+ bool bIntrinsicAnimationsAllowed,
+ bool bDisableAnimationZOrder ) :
+ mxDrawPage( xDrawPage ),
+ mxDrawPagesSupplier( xDrawPages ),
+ mxRootNode( xRootNode ),
+ mpLayerManager( new LayerManager(
+ rViewContainer,
+ getSlideRect(),
+ bDisableAnimationZOrder) ),
+ mpShapeManager( new ShapeManagerImpl(
+ rEventMultiplexer,
+ mpLayerManager,
+ rCursorManager,
+ rShapeListenerMap,
+ rShapeCursorMap)),
+ mpSubsettableShapeManager( mpShapeManager ),
+ maContext( mpSubsettableShapeManager,
+ rEventQueue,
+ rEventMultiplexer,
+ rScreenUpdater,
+ rActivitiesQueue,
+ rUserEventQueue,
+ *this,
+ rViewContainer,
+ xComponentContext ),
+ mrCursorManager( rCursorManager ),
+ maAnimations( maContext,
+ getSlideSizeImpl() ),
+ maPolygons(rPolyPolygonVector),
+ maUserPaintColor(aUserPaintColor),
+ mdUserPaintStrokeWidth(dUserPaintStrokeWidth),
+ mpPaintOverlay(),
+ maSlideBitmaps(),
+ meAnimationState( CONSTRUCTING_STATE ),
+ maSlideSize(getSlideSizeImpl()),
+ mnCurrentCursor( awt::SystemPointer::ARROW ),
+ mbIntrinsicAnimationsAllowed( bIntrinsicAnimationsAllowed ),
+ mbUserPaintOverlayEnabled(bUserPaintEnabled),
+ mbShapesLoaded( false ),
+ mbShowLoaded( false ),
+ mbHaveAnimations( false ),
+ mbMainSequenceFound( false ),
+ mbActive( false ),
+ mbPaintOverlayActive( false )
+{
+ // clone already existing views for slide bitmaps
+ std::for_each( rViewContainer.begin(),
+ rViewContainer.end(),
+ boost::bind( &SlideImpl::viewAdded,
+ this,
+ _1 ));
+
+ // register screen update (LayerManager needs to signal pending
+ // updates)
+ maContext.mrScreenUpdater.addViewUpdate(mpShapeManager);
+}
+
+void SlideImpl::update_settings( bool bUserPaintEnabled, RGBColor const& aUserPaintColor, double dUserPaintStrokeWidth )
+{
+ maUserPaintColor = aUserPaintColor;
+ mdUserPaintStrokeWidth = dUserPaintStrokeWidth;
+ mbUserPaintOverlayEnabled = bUserPaintEnabled;
+}
+
+SlideImpl::~SlideImpl()
+{
+ if( mpShapeManager )
+ {
+ maContext.mrScreenUpdater.removeViewUpdate(mpShapeManager);
+ mpShapeManager->dispose();
+
+ // TODO(Q3): Make sure LayerManager (and thus Shapes) dies
+ // first, because SlideShowContext has SubsettableShapeManager
+ // as reference member.
+ mpLayerManager.reset();
+ }
+}
+
+void SlideImpl::dispose()
+{
+ maSlideBitmaps.clear();
+ mpPaintOverlay.reset();
+ maAnimations.dispose();
+ maContext.dispose();
+
+ if( mpShapeManager )
+ {
+ maContext.mrScreenUpdater.removeViewUpdate(mpShapeManager);
+ mpShapeManager->dispose();
+ }
+
+ // TODO(Q3): Make sure LayerManager (and thus Shapes) dies first,
+ // because SlideShowContext has SubsettableShapeManager as
+ // reference member.
+ mpLayerManager.reset();
+ mpSubsettableShapeManager.reset();
+ mpShapeManager.reset();
+ mxRootNode.clear();
+ mxDrawPage.clear();
+ mxDrawPagesSupplier.clear();
+}
+
+bool SlideImpl::prefetch()
+{
+ if( !mxRootNode.is() )
+ return false;
+
+ return applyInitialShapeAttributes(mxRootNode);
+}
+
+bool SlideImpl::show( bool bSlideBackgoundPainted )
+{
+ // ---------------------------------------------------------------
+
+ if( mbActive )
+ return true; // already active
+
+ if( !mpShapeManager || !mpLayerManager )
+ return false; // disposed
+
+ // ---------------------------------------------------------------
+
+ // set initial shape attributes (e.g. hide shapes that have
+ // 'appear' effect set)
+ if( !applyInitialShapeAttributes(mxRootNode) )
+ return false;
+
+ // ---------------------------------------------------------------
+
+ // activate and take over view - clears view, if necessary
+ mbActive = true;
+ requestCursor( mnCurrentCursor );
+
+ // enable shape management & event broadcasting for shapes of this
+ // slide. Also enables LayerManager to record updates. Currently,
+ // never let LayerManager render initial slide content, use
+ // buffered slide bitmaps instead.
+ mpShapeManager->activate( true );
+
+ // ---------------------------------------------------------------
+
+ // render slide to screen, if requested
+ if( !bSlideBackgoundPainted )
+ {
+ std::for_each(maContext.mrViewContainer.begin(),
+ maContext.mrViewContainer.end(),
+ boost::mem_fn(&View::clearAll));
+
+ std::for_each( maContext.mrViewContainer.begin(),
+ maContext.mrViewContainer.end(),
+ SlideRenderer(*this) );
+ maContext.mrScreenUpdater.notifyUpdate();
+ }
+
+ // ---------------------------------------------------------------
+
+ // fire up animations
+ const bool bIsAnimated( isAnimated() );
+ if( bIsAnimated )
+ maAnimations.start(); // feeds initial events into queue
+
+ // NOTE: this looks slightly weird, but is indeed correct:
+ // as isAnimated() might return false, _although_ there is
+ // a main sequence (because the animation nodes don't
+ // contain any executable effects), we gotta check both
+ // conditions here.
+ if( !bIsAnimated || !mbMainSequenceFound )
+ {
+ // manually trigger a slide animation end event (we don't have
+ // animations at all, or we don't have a main animation
+ // sequence, but if we had, it'd end now). Note that having
+ // animations alone does not matter here, as only main
+ // sequence animations prevents showing the next slide on
+ // nextEvent().
+ maContext.mrEventMultiplexer.notifySlideAnimationsEnd();
+ }
+
+ // enable shape-intrinsic animations (drawing layer animations or
+ // GIF animations)
+ if( mbIntrinsicAnimationsAllowed )
+ startIntrinsicAnimations();
+
+ // ---------------------------------------------------------------
+
+ // enable paint overlay, if maUserPaintColor is valid
+ activatePaintOverlay();
+
+ // ---------------------------------------------------------------
+
+ // from now on, animations might be showing
+ meAnimationState = SHOWING_STATE;
+
+ return true;
+}
+
+void SlideImpl::hide()
+{
+ if( !mbActive || !mpShapeManager )
+ return; // already hidden/disposed
+
+ // ---------------------------------------------------------------
+
+ // from now on, all animations are stopped
+ meAnimationState = FINAL_STATE;
+
+ // ---------------------------------------------------------------
+
+ // disable user paint overlay under all circumstances,
+ // this slide now ceases to be active.
+ deactivatePaintOverlay();
+
+ // ---------------------------------------------------------------
+
+ // switch off all shape-intrinsic animations.
+ endIntrinsicAnimations();
+
+ // force-end all SMIL animations, too
+ maAnimations.end();
+
+ // ---------------------------------------------------------------
+
+ // disable shape management & event broadcasting for shapes of this
+ // slide. Also disables LayerManager.
+ mpShapeManager->deactivate();
+
+ // vanish from view
+ resetCursor();
+ mbActive = false;
+
+ // ---------------------------------------------------------------
+}
+
+basegfx::B2ISize SlideImpl::getSlideSize() const
+{
+ return maSlideSize;
+}
+
+uno::Reference<drawing::XDrawPage > SlideImpl::getXDrawPage() const
+{
+ return mxDrawPage;
+}
+
+uno::Reference<animations::XAnimationNode> SlideImpl::getXAnimationNode() const
+{
+ return mxRootNode;
+}
+
+PolyPolygonVector SlideImpl::getPolygons()
+{
+ if(mbPaintOverlayActive)
+ maPolygons = mpPaintOverlay->getPolygons();
+ return maPolygons;
+}
+
+SlideBitmapSharedPtr SlideImpl::getCurrentSlideBitmap( const UnoViewSharedPtr& rView ) const
+{
+ // search corresponding entry in maSlideBitmaps (which
+ // contains the views as the key)
+ VectorOfVectorOfSlideBitmaps::iterator aIter;
+ const VectorOfVectorOfSlideBitmaps::iterator aEnd( maSlideBitmaps.end() );
+ if( (aIter=std::find_if( maSlideBitmaps.begin(),
+ aEnd,
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind(
+ o3tl::select1st<VectorOfVectorOfSlideBitmaps::value_type>(),
+ _1 )))) == aEnd )
+ {
+ // corresponding view not found - maybe view was not
+ // added to Slide?
+ ENSURE_OR_THROW( false,
+ "SlideImpl::getInitialSlideBitmap(): view does not "
+ "match any of the added ones" );
+ }
+
+ // ensure that the show is loaded
+ if( !mbShowLoaded )
+ {
+ // only prefetch and init shapes when not done already
+ // (otherwise, at least applyInitialShapeAttributes() will be
+ // called twice for initial slide rendering). Furthermore,
+ // applyInitialShapeAttributes() _always_ performs
+ // initializations, which would be highly unwanted during a
+ // running show. OTOH, a slide whose mbShowLoaded is false is
+ // guaranteed not be running a show.
+
+ // set initial shape attributes (e.g. hide 'appear' effect
+ // shapes)
+ if( !const_cast<SlideImpl*>(this)->applyInitialShapeAttributes( mxRootNode ) )
+ ENSURE_OR_THROW(false,
+ "SlideImpl::getCurrentSlideBitmap(): Cannot "
+ "apply initial attributes");
+ }
+
+ SlideBitmapSharedPtr& rBitmap( aIter->second.at( meAnimationState ));
+ const ::basegfx::B2ISize& rSlideSize(
+ getSlideSizePixel( getSlideSize(),
+ rView ));
+
+ // is the bitmap valid (actually existent, and of correct
+ // size)?
+ if( !rBitmap || rBitmap->getSize() != rSlideSize )
+ {
+ // no bitmap there yet, or wrong size - create one
+ rBitmap = createCurrentSlideBitmap(rView, rSlideSize);
+ }
+
+ return rBitmap;
+}
+
+
+// private methods
+//--------------------------------------------------------------------------------------------------------------
+
+
+void SlideImpl::viewAdded( const UnoViewSharedPtr& rView )
+{
+ maSlideBitmaps.push_back(
+ std::make_pair( rView,
+ VectorOfSlideBitmaps(SlideAnimationState_NUM_ENTRIES) ));
+
+ if( mpLayerManager )
+ mpLayerManager->viewAdded( rView );
+}
+
+void SlideImpl::viewRemoved( const UnoViewSharedPtr& rView )
+{
+ if( mpLayerManager )
+ mpLayerManager->viewRemoved( rView );
+
+ const VectorOfVectorOfSlideBitmaps::iterator aEnd( maSlideBitmaps.end() );
+ maSlideBitmaps.erase(
+ std::remove_if( maSlideBitmaps.begin(),
+ aEnd,
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind(
+ o3tl::select1st<VectorOfVectorOfSlideBitmaps::value_type>(),
+ _1 ))),
+ aEnd );
+}
+
+void SlideImpl::viewChanged( const UnoViewSharedPtr& rView )
+{
+ // nothing to do for the Slide - getCurrentSlideBitmap() lazily
+ // handles bitmap resizes
+ if( mbActive && mpLayerManager )
+ mpLayerManager->viewChanged(rView);
+}
+
+void SlideImpl::viewsChanged()
+{
+ // nothing to do for the Slide - getCurrentSlideBitmap() lazily
+ // handles bitmap resizes
+ if( mbActive && mpLayerManager )
+ mpLayerManager->viewsChanged();
+}
+
+bool SlideImpl::requestCursor( sal_Int16 nCursorShape )
+{
+ mnCurrentCursor = nCursorShape;
+ return mrCursorManager.requestCursor(mnCurrentCursor);
+}
+
+void SlideImpl::resetCursor()
+{
+ mnCurrentCursor = awt::SystemPointer::ARROW;
+ mrCursorManager.resetCursor();
+}
+
+bool SlideImpl::isAnimated()
+{
+ // prefetch, but don't apply initial shape attributes
+ if( !implPrefetchShow() )
+ return false;
+
+ return mbHaveAnimations && maAnimations.isAnimated();
+}
+
+SlideBitmapSharedPtr SlideImpl::createCurrentSlideBitmap( const UnoViewSharedPtr& rView,
+ const ::basegfx::B2ISize& rBmpSize ) const
+{
+ ENSURE_OR_THROW( rView && rView->getCanvas(),
+ "SlideImpl::createCurrentSlideBitmap(): Invalid view" );
+ ENSURE_OR_THROW( mpLayerManager,
+ "SlideImpl::createCurrentSlideBitmap(): Invalid layer manager" );
+ ENSURE_OR_THROW( mbShowLoaded,
+ "SlideImpl::createCurrentSlideBitmap(): No show loaded" );
+
+ ::cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
+
+ // create a bitmap of appropriate size
+ ::cppcanvas::BitmapSharedPtr pBitmap(
+ ::cppcanvas::BaseGfxFactory::getInstance().createBitmap(
+ pCanvas,
+ rBmpSize ) );
+
+ ENSURE_OR_THROW( pBitmap,
+ "SlideImpl::createCurrentSlideBitmap(): Cannot create page bitmap" );
+
+ ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas( pBitmap->getBitmapCanvas() );
+
+ ENSURE_OR_THROW( pBitmapCanvas,
+ "SlideImpl::createCurrentSlideBitmap(): Cannot create page bitmap canvas" );
+
+ // apply linear part of destination canvas transformation (linear means in this context:
+ // transformation without any translational components)
+ ::basegfx::B2DHomMatrix aLinearTransform( rView->getTransformation() );
+ aLinearTransform.set( 0, 2, 0.0 );
+ aLinearTransform.set( 1, 2, 0.0 );
+ pBitmapCanvas->setTransformation( aLinearTransform );
+
+ // output all shapes to bitmap
+ initSlideBackground( pBitmapCanvas, rBmpSize );
+ mpLayerManager->renderTo( pBitmapCanvas );
+
+ return SlideBitmapSharedPtr( new SlideBitmap( pBitmap ) );
+}
+
+namespace
+{
+ class MainSequenceSearcher
+ {
+ public:
+ MainSequenceSearcher()
+ {
+ maSearchKey.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
+ maSearchKey.Value <<= presentation::EffectNodeType::MAIN_SEQUENCE;
+ }
+
+ void operator()( const uno::Reference< animations::XAnimationNode >& xChildNode )
+ {
+ uno::Sequence< beans::NamedValue > aUserData( xChildNode->getUserData() );
+
+ if( findNamedValue( aUserData, maSearchKey ) )
+ {
+ maMainSequence = xChildNode;
+ }
+ }
+
+ uno::Reference< animations::XAnimationNode > getMainSequence() const
+ {
+ return maMainSequence;
+ }
+
+ private:
+ beans::NamedValue maSearchKey;
+ uno::Reference< animations::XAnimationNode > maMainSequence;
+ };
+}
+
+bool SlideImpl::implPrefetchShow()
+{
+ if( mbShowLoaded )
+ return true;
+
+ ENSURE_OR_RETURN_FALSE( mxDrawPage.is(),
+ "SlideImpl::implPrefetchShow(): Invalid draw page" );
+ ENSURE_OR_RETURN_FALSE( mpLayerManager,
+ "SlideImpl::implPrefetchShow(): Invalid layer manager" );
+
+ // fetch desired page content
+ // ==========================
+
+ if( !loadShapes() )
+ return false;
+
+ // New animations framework: import the shape effect info
+ // ======================================================
+
+ try
+ {
+ if( mxRootNode.is() )
+ {
+ if( !maAnimations.importAnimations( mxRootNode ) )
+ {
+ OSL_FAIL( "SlideImpl::implPrefetchShow(): have animation nodes, "
+ "but import animations failed." );
+
+ // could not import animation framework,
+ // _although_ some animation nodes are there -
+ // this is an error (not finding animations at
+ // all is okay - might be a static slide)
+ return false;
+ }
+
+ // now check whether we've got a main sequence (if
+ // not, we must manually call
+ // EventMultiplexer::notifySlideAnimationsEnd()
+ // above, as e.g. interactive sequences alone
+ // don't block nextEvent() from issuing the next
+ // slide)
+ MainSequenceSearcher aSearcher;
+ if( ::anim::for_each_childNode( mxRootNode, aSearcher ) )
+ mbMainSequenceFound = aSearcher.getMainSequence().is();
+
+ // import successfully done
+ mbHaveAnimations = true;
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL(
+ rtl::OUStringToOString(
+ comphelper::anyToString(cppu::getCaughtException()),
+ RTL_TEXTENCODING_UTF8 ) );
+ // TODO(E2): Error handling. For now, bail out
+ }
+
+ mbShowLoaded = true;
+
+ return true;
+}
+
+void SlideImpl::enablePaintOverlay()
+{
+ if( !mbUserPaintOverlayEnabled || !mbPaintOverlayActive )
+ {
+ mbUserPaintOverlayEnabled = true;
+ activatePaintOverlay();
+ }
+}
+
+void SlideImpl::disablePaintOverlay()
+{
+}
+
+void SlideImpl::activatePaintOverlay()
+{
+ if( mbUserPaintOverlayEnabled || !maPolygons.empty() )
+ {
+ mpPaintOverlay = UserPaintOverlay::create( maUserPaintColor,
+ mdUserPaintStrokeWidth,
+ maContext,
+ maPolygons,
+ mbUserPaintOverlayEnabled );
+ mbPaintOverlayActive = true;
+ }
+}
+
+void SlideImpl::drawPolygons() const
+{
+ if( mpPaintOverlay )
+ mpPaintOverlay->drawPolygons();
+}
+
+void SlideImpl::addPolygons(PolyPolygonVector aPolygons)
+{
+ if(!aPolygons.empty())
+ {
+ for( PolyPolygonVector::iterator aIter=aPolygons.begin(),
+ aEnd=aPolygons.end();
+ aIter!=aEnd;
+ ++aIter )
+ {
+ maPolygons.push_back(*aIter);
+ }
+ }
+}
+
+bool SlideImpl::isPaintOverlayActive() const
+{
+ return mbPaintOverlayActive;
+}
+
+void SlideImpl::deactivatePaintOverlay()
+{
+ if(mbPaintOverlayActive)
+ maPolygons = mpPaintOverlay->getPolygons();
+
+ mpPaintOverlay.reset();
+ mbPaintOverlayActive = false;
+}
+
+::basegfx::B2DRectangle SlideImpl::getSlideRect() const
+{
+ const basegfx::B2ISize slideSize( getSlideSizeImpl() );
+ return ::basegfx::B2DRectangle(0.0,0.0,
+ slideSize.getX(),
+ slideSize.getY());
+}
+
+void SlideImpl::endIntrinsicAnimations()
+{
+ mpSubsettableShapeManager->notifyIntrinsicAnimationsDisabled();
+}
+
+void SlideImpl::startIntrinsicAnimations()
+{
+ mpSubsettableShapeManager->notifyIntrinsicAnimationsEnabled();
+}
+
+bool SlideImpl::applyInitialShapeAttributes(
+ const uno::Reference< animations::XAnimationNode >& xRootAnimationNode )
+{
+ if( !implPrefetchShow() )
+ return false;
+
+ if( !xRootAnimationNode.is() )
+ {
+ meAnimationState = INITIAL_STATE;
+
+ return true; // no animations - no attributes to apply -
+ // succeeded
+ }
+
+ uno::Reference< animations::XTargetPropertiesCreator > xPropsCreator;
+
+ try
+ {
+ ENSURE_OR_RETURN_FALSE( maContext.mxComponentContext.is(),
+ "SlideImpl::applyInitialShapeAttributes(): Invalid component context" );
+
+ uno::Reference<lang::XMultiComponentFactory> xFac(
+ maContext.mxComponentContext->getServiceManager() );
+
+ xPropsCreator.set(
+ xFac->createInstanceWithContext(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.animations.TargetPropertiesCreator") ),
+ maContext.mxComponentContext ),
+ uno::UNO_QUERY_THROW );
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL(
+ rtl::OUStringToOString(
+ comphelper::anyToString(cppu::getCaughtException()),
+ RTL_TEXTENCODING_UTF8 ) );
+
+ // could not determine initial shape attributes - this
+ // is an error, as some effects might then be plainly
+ // invisible
+ ENSURE_OR_RETURN_FALSE( false,
+ "SlideImpl::applyInitialShapeAttributes(): "
+ "couldn't create TargetPropertiesCreator." );
+ }
+
+ uno::Sequence< animations::TargetProperties > aProps(
+ xPropsCreator->createInitialTargetProperties( xRootAnimationNode ) );
+
+ // apply extracted values to our shapes
+ const ::std::size_t nSize( aProps.getLength() );
+ for( ::std::size_t i=0; i<nSize; ++i )
+ {
+ sal_Int16 nParaIndex( -1 );
+ uno::Reference< drawing::XShape > xShape( aProps[i].Target,
+ uno::UNO_QUERY );
+
+ if( !xShape.is() )
+ {
+ // not a shape target. Maybe a ParagraphTarget?
+ presentation::ParagraphTarget aParaTarget;
+
+ if( (aProps[i].Target >>= aParaTarget) )
+ {
+ // yep, ParagraphTarget found - extract shape
+ // and index
+ xShape = aParaTarget.Shape;
+ nParaIndex = aParaTarget.Paragraph;
+ }
+ }
+
+ if( xShape.is() )
+ {
+ ShapeSharedPtr pShape( mpLayerManager->lookupShape( xShape ) );
+
+ if( !pShape )
+ {
+ OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): no shape found for given target" );
+ continue;
+ }
+
+ AttributableShapeSharedPtr pAttrShape(
+ ::boost::dynamic_pointer_cast< AttributableShape >( pShape ) );
+
+ if( !pAttrShape )
+ {
+ OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): shape found does not "
+ "implement AttributableShape interface" );
+ continue;
+ }
+
+ if( nParaIndex != -1 )
+ {
+ // our target is a paragraph subset, thus look
+ // this up first.
+ const DocTreeNodeSupplier& rNodeSupplier( pAttrShape->getTreeNodeSupplier() );
+
+ pAttrShape = pAttrShape->getSubset(
+ rNodeSupplier.getTreeNode(
+ nParaIndex,
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ) );
+
+ if( !pAttrShape )
+ {
+ OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): shape found does not "
+ "provide a subset for requested paragraph index" );
+ continue;
+ }
+ }
+
+ const uno::Sequence< beans::NamedValue >& rShapeProps( aProps[i].Properties );
+ const ::std::size_t nShapePropSize( rShapeProps.getLength() );
+ for( ::std::size_t j=0; j<nShapePropSize; ++j )
+ {
+ bool bVisible=false;
+ if( rShapeProps[j].Name.equalsIgnoreAsciiCaseAscii("visibility") &&
+ extractValue( bVisible,
+ rShapeProps[j].Value,
+ pShape,
+ getSlideSize() ))
+ {
+ pAttrShape->setVisibility( bVisible );
+ }
+ else
+ {
+ OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): Unexpected "
+ "(and unimplemented) property encountered" );
+ }
+ }
+ }
+ }
+
+ meAnimationState = INITIAL_STATE;
+
+ return true;
+}
+
+bool SlideImpl::loadShapes()
+{
+ if( mbShapesLoaded )
+ return true;
+
+ ENSURE_OR_RETURN_FALSE( mxDrawPage.is(),
+ "SlideImpl::loadShapes(): Invalid draw page" );
+ ENSURE_OR_RETURN_FALSE( mpLayerManager,
+ "SlideImpl::loadShapes(): Invalid layer manager" );
+
+ // fetch desired page content
+ // ==========================
+
+ // also take master page content
+ uno::Reference< drawing::XDrawPage > xMasterPage;
+ uno::Reference< drawing::XShapes > xMasterPageShapes;
+ sal_Int32 nCurrCount(0);
+
+ uno::Reference< drawing::XMasterPageTarget > xMasterPageTarget( mxDrawPage,
+ uno::UNO_QUERY );
+ if( xMasterPageTarget.is() )
+ {
+ xMasterPage = xMasterPageTarget->getMasterPage();
+ xMasterPageShapes.set( xMasterPage,
+ uno::UNO_QUERY );
+
+ if( xMasterPage.is() && xMasterPageShapes.is() )
+ {
+ // TODO(P2): maybe cache master pages here (or treat the
+ // masterpage as a single metafile. At least currently,
+ // masterpages do not contain animation effects)
+ try
+ {
+ // load the masterpage shapes
+ // -------------------------------------------------------------------------
+ ShapeImporter aMPShapesFunctor( xMasterPage,
+ mxDrawPage,
+ mxDrawPagesSupplier,
+ maContext,
+ 0, /* shape num starts at 0 */
+ true );
+
+ mpLayerManager->addShape(
+ aMPShapesFunctor.importBackgroundShape() );
+
+ while( !aMPShapesFunctor.isImportDone() )
+ {
+ ShapeSharedPtr const& rShape(
+ aMPShapesFunctor.importShape() );
+ if( rShape )
+ mpLayerManager->addShape( rShape );
+ }
+ addPolygons(aMPShapesFunctor.getPolygons());
+
+ nCurrCount = aMPShapesFunctor.getImportedShapesCount();
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( ShapeLoadFailedException& )
+ {
+ // TODO(E2): Error handling. For now, bail out
+ OSL_FAIL( "SlideImpl::loadShapes(): caught ShapeLoadFailedException" );
+ return false;
+
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ return false;
+ }
+ }
+ }
+
+ try
+ {
+ // load the normal page shapes
+ // -------------------------------------------------------------------------
+
+ ShapeImporter aShapesFunctor( mxDrawPage,
+ mxDrawPage,
+ mxDrawPagesSupplier,
+ maContext,
+ nCurrCount,
+ false );
+
+ while( !aShapesFunctor.isImportDone() )
+ {
+ ShapeSharedPtr const& rShape(
+ aShapesFunctor.importShape() );
+ if( rShape )
+ mpLayerManager->addShape( rShape );
+ }
+ addPolygons(aShapesFunctor.getPolygons());
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( ShapeLoadFailedException& )
+ {
+ // TODO(E2): Error handling. For now, bail out
+ OSL_FAIL( "SlideImpl::loadShapes(): caught ShapeLoadFailedException" );
+ return false;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ return false;
+ }
+
+ mbShapesLoaded = true;
+
+ return true;
+}
+
+basegfx::B2ISize SlideImpl::getSlideSizeImpl() const
+{
+ uno::Reference< beans::XPropertySet > xPropSet(
+ mxDrawPage, uno::UNO_QUERY_THROW );
+
+ sal_Int32 nDocWidth = 0;
+ sal_Int32 nDocHeight = 0;
+ xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Width") ) ) >>= nDocWidth;
+ xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Height") ) ) >>= nDocHeight;
+
+ return basegfx::B2ISize( nDocWidth, nDocHeight );
+}
+
+} // namespace
+
+
+SlideSharedPtr createSlide( const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Reference<drawing::XDrawPagesSupplier>& xDrawPages,
+ const uno::Reference< animations::XAnimationNode >& xRootNode,
+ EventQueue& rEventQueue,
+ EventMultiplexer& rEventMultiplexer,
+ ScreenUpdater& rScreenUpdater,
+ ActivitiesQueue& rActivitiesQueue,
+ UserEventQueue& rUserEventQueue,
+ CursorManager& rCursorManager,
+ const UnoViewContainer& rViewContainer,
+ const uno::Reference< uno::XComponentContext >& xComponentContext,
+ const ShapeEventListenerMap& rShapeListenerMap,
+ const ShapeCursorMap& rShapeCursorMap,
+ const PolyPolygonVector& rPolyPolygonVector,
+ RGBColor const& rUserPaintColor,
+ double dUserPaintStrokeWidth,
+ bool bUserPaintEnabled,
+ bool bIntrinsicAnimationsAllowed,
+ bool bDisableAnimationZOrder )
+{
+ boost::shared_ptr<SlideImpl> pRet( new SlideImpl( xDrawPage, xDrawPages, xRootNode, rEventQueue,
+ rEventMultiplexer, rScreenUpdater,
+ rActivitiesQueue, rUserEventQueue,
+ rCursorManager, rViewContainer,
+ xComponentContext, rShapeListenerMap,
+ rShapeCursorMap, rPolyPolygonVector, rUserPaintColor,
+ dUserPaintStrokeWidth, bUserPaintEnabled,
+ bIntrinsicAnimationsAllowed,
+ bDisableAnimationZOrder ));
+
+ rEventMultiplexer.addViewHandler( pRet );
+
+ return pRet;
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/userpaintoverlay.cxx b/slideshow/source/engine/slide/userpaintoverlay.cxx
new file mode 100644
index 000000000000..d060f139f0d9
--- /dev/null
+++ b/slideshow/source/engine/slide/userpaintoverlay.cxx
@@ -0,0 +1,562 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/presentation/XSlideShowView.hpp>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include "activity.hxx"
+#include "activitiesqueue.hxx"
+#include "slideshowcontext.hxx"
+#include "userpaintoverlay.hxx"
+#include "mouseeventhandler.hxx"
+#include "eventmultiplexer.hxx"
+#include "screenupdater.hxx"
+#include "vieweventhandler.hxx"
+
+#include <boost/bind.hpp>
+#include <boost/noncopyable.hpp>
+#include "slide.hxx"
+#include "cursormanager.hxx"
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class PaintOverlayHandler : public MouseEventHandler,
+ public ViewEventHandler,
+ public UserPaintEventHandler
+ {
+ public:
+ PaintOverlayHandler( const RGBColor& rStrokeColor,
+ double nStrokeWidth,
+ ActivitiesQueue& rActivitiesQueue,
+ ScreenUpdater& rScreenUpdater,
+ const UnoViewContainer& rViews,
+ Slide& rSlide,
+ const PolyPolygonVector& rPolygons,
+ bool bActive ) :
+ mrActivitiesQueue( rActivitiesQueue ),
+ mrScreenUpdater( rScreenUpdater ),
+ maViews(),
+ maPolygons( rPolygons ),
+ maStrokeColor( rStrokeColor ),
+ mnStrokeWidth( nStrokeWidth ),
+ maLastPoint(),
+ maLastMouseDownPos(),
+ mbIsLastPointValid( false ),
+ mbIsLastMouseDownPosValid( false ),
+ //handle the "remove all ink from slide" mode of erasing
+ mbIsEraseAllModeActivated( false ),
+ //handle the "remove stroke by stroke" mode of erasing
+ mbIsEraseModeActivated( false ),
+ mrSlide(rSlide),
+ mnSize(100),
+ mbActive( bActive )
+ {
+ std::for_each( rViews.begin(),
+ rViews.end(),
+ boost::bind( &PaintOverlayHandler::viewAdded,
+ this,
+ _1 ));
+ drawPolygons();
+ }
+
+ virtual void dispose()
+ {
+ maViews.clear();
+ }
+
+ // ViewEventHandler methods
+ virtual void viewAdded( const UnoViewSharedPtr& rView )
+ {
+ maViews.push_back( rView );
+ }
+
+ virtual void viewRemoved( const UnoViewSharedPtr& rView )
+ {
+ maViews.erase( ::std::remove( maViews.begin(),
+ maViews.end(),
+ rView ) );
+ }
+
+ virtual void viewChanged( const UnoViewSharedPtr& /*rView*/ )
+ {
+ // TODO(F2): for persistent drawings, need to store
+ // polygon and repaint here.
+ }
+
+ virtual void viewsChanged()
+ {
+ // TODO(F2): for persistent drawings, need to store
+ // polygon and repaint here.
+ }
+
+ bool colorChanged( RGBColor const& rUserColor )
+ {
+ mbIsLastPointValid = false;
+ mbActive = true;
+ this->maStrokeColor = rUserColor;
+ this->mbIsEraseModeActivated = false;
+ return true;
+ }
+
+ bool widthChanged( double nUserStrokeWidth )
+ {
+ this->mnStrokeWidth = nUserStrokeWidth;
+ mbIsEraseModeActivated = false;
+ return true;
+ }
+
+ void repaintWithoutPolygons()
+ {
+ // must get access to the instance to erase all polygon
+ for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end();
+ aIter!=aEnd;
+ ++aIter )
+ {
+ // fully clear view content to background color
+ //(*aIter)->getCanvas()->clear();
+
+ //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
+ SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( (*aIter) ) );
+ ::cppcanvas::CanvasSharedPtr pCanvas( (*aIter)->getCanvas() );
+
+ const ::basegfx::B2DHomMatrix aViewTransform( (*aIter)->getTransformation() );
+ const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
+
+ // setup a canvas with device coordinate space, the slide
+ // bitmap already has the correct dimension.
+ ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
+
+ pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // render at given output position
+ pBitmap->move( aOutPosPixel );
+
+ // clear clip (might have been changed, e.g. from comb
+ // transition)
+ pBitmap->clip( ::basegfx::B2DPolyPolygon() );
+ pBitmap->draw( pDevicePixelCanvas );
+
+ mrScreenUpdater.notifyUpdate(*aIter,true);
+ }
+ }
+
+ bool eraseAllInkChanged( bool const& rEraseAllInk )
+ {
+ this->mbIsEraseAllModeActivated= rEraseAllInk;
+ // if the erase all mode is activated it will remove all ink from slide,
+ // therefor destroy all the polygons stored
+ if(mbIsEraseAllModeActivated)
+ {
+ // The Erase Mode should be desactivated
+ mbIsEraseModeActivated = false;
+ repaintWithoutPolygons();
+ maPolygons.clear();
+ }
+ mbIsEraseAllModeActivated=false;
+ return true;
+ }
+
+ bool eraseInkWidthChanged( sal_Int32 rEraseInkSize )
+ {
+ // Change the size
+ this->mnSize=rEraseInkSize;
+ // Changed to mode Erase
+ this->mbIsEraseModeActivated = true;
+ return true;
+ }
+
+ bool switchPenMode()
+ {
+ mbIsLastPointValid = false;
+ mbActive = true;
+ this->mbIsEraseModeActivated = false;
+ return true;
+ }
+
+ bool switchEraserMode()
+ {
+ mbIsLastPointValid = false;
+ mbActive = true;
+ this->mbIsEraseModeActivated = true;
+ return true;
+ }
+
+ bool disable()
+ {
+ mbIsLastPointValid = false;
+ mbIsLastMouseDownPosValid = false;
+ mbActive = false;
+ return true;
+ }
+
+ //Draw all registered polygons.
+ void drawPolygons()
+ {
+ for( PolyPolygonVector::iterator aIter=maPolygons.begin(), aEnd=maPolygons.end();
+ aIter!=aEnd;
+ ++aIter )
+ {
+ (*aIter)->draw();
+ }
+ // screen update necessary to show painting
+ mrScreenUpdater.notifyUpdate();
+ }
+
+ //Retrieve all registered polygons.
+ PolyPolygonVector getPolygons()
+ {
+ return maPolygons;
+ }
+
+ // MouseEventHandler methods
+ virtual bool handleMousePressed( const awt::MouseEvent& e )
+ {
+ if( !mbActive )
+ return false;
+
+ if (e.Buttons == awt::MouseButton::RIGHT)
+ {
+ mbIsLastPointValid = false;
+ return false;
+ }
+
+ if (e.Buttons != awt::MouseButton::LEFT)
+ return false;
+
+ maLastMouseDownPos.setX( e.X );
+ maLastMouseDownPos.setY( e.Y );
+ mbIsLastMouseDownPosValid = true;
+
+ // eat mouse click (though we don't process it
+ // _directly_, it enables the drag mode
+ return true;
+ }
+
+ virtual bool handleMouseReleased( const awt::MouseEvent& e )
+ {
+ if( !mbActive )
+ return false;
+
+ if (e.Buttons == awt::MouseButton::RIGHT)
+ {
+ mbIsLastPointValid = false;
+ return false;
+ }
+
+ if (e.Buttons != awt::MouseButton::LEFT)
+ return false;
+
+ // check, whether up- and down press are on exactly
+ // the same pixel. If that's the case, ignore the
+ // click, and pass on the event to low-prio
+ // handlers. This effectively permits effect
+ // advancements via clicks also when user paint is
+ // enabled.
+ if( mbIsLastMouseDownPosValid &&
+ ::basegfx::B2DPoint( e.X,
+ e.Y ) == maLastMouseDownPos )
+ {
+ mbIsLastMouseDownPosValid = false;
+ return false;
+ }
+
+ // invalidate, next downpress will have to start a new
+ // polygon.
+ mbIsLastPointValid = false;
+
+ // eat mouse click (though we don't process it
+ // _directly_, it enables the drag mode
+ return true;
+ }
+
+ virtual bool handleMouseEntered( const awt::MouseEvent& e )
+ {
+ if( !mbActive )
+ return false;
+
+ mbIsLastPointValid = true;
+ maLastPoint.setX( e.X );
+ maLastPoint.setY( e.Y );
+
+ return true;
+ }
+
+ virtual bool handleMouseExited( const awt::MouseEvent& )
+ {
+ if( !mbActive )
+ return false;
+
+ mbIsLastPointValid = false;
+ mbIsLastMouseDownPosValid = false;
+
+ return true;
+ }
+
+ virtual bool handleMouseDragged( const awt::MouseEvent& e )
+ {
+ if( !mbActive )
+ return false;
+
+ if (e.Buttons == awt::MouseButton::RIGHT)
+ {
+ mbIsLastPointValid = false;
+ return false;
+ }
+
+ if(mbIsEraseModeActivated)
+ {
+ //define the last point as an object
+ //we suppose that there's no way this point could be valid
+ ::basegfx::B2DPolygon aPoly;
+
+ maLastPoint.setX( e.X-mnSize );
+ maLastPoint.setY( e.Y-mnSize );
+
+ aPoly.append( maLastPoint );
+
+ maLastPoint.setX( e.X-mnSize );
+ maLastPoint.setY( e.Y+mnSize );
+
+ aPoly.append( maLastPoint );
+ maLastPoint.setX( e.X+mnSize );
+ maLastPoint.setY( e.Y+mnSize );
+
+ aPoly.append( maLastPoint );
+ maLastPoint.setX( e.X+mnSize );
+ maLastPoint.setY( e.Y-mnSize );
+
+ aPoly.append( maLastPoint );
+ maLastPoint.setX( e.X-mnSize );
+ maLastPoint.setY( e.Y-mnSize );
+
+ aPoly.append( maLastPoint );
+
+ //now we have defined a Polygon that is closed
+
+ //The point is to redraw the LastPoint the way it was originally on the bitmap,
+ //of the slide
+ for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end();
+ aIter!=aEnd;
+ ++aIter )
+ {
+
+ //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
+ SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( (*aIter) ) );
+ ::cppcanvas::CanvasSharedPtr pCanvas( (*aIter)->getCanvas() );
+
+ ::basegfx::B2DHomMatrix aViewTransform( (*aIter)->getTransformation() );
+ const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
+
+ // setup a canvas with device coordinate space, the slide
+ // bitmap already has the correct dimension.
+ ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
+
+ pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // render at given output position
+ pBitmap->move( aOutPosPixel );
+
+ ::basegfx::B2DPolyPolygon aPolyPoly=::basegfx::B2DPolyPolygon(aPoly);
+ aViewTransform.translate(-aOutPosPixel.getX(), -aOutPosPixel.getY());
+ aPolyPoly.transform(aViewTransform);
+ // set clip so that we just redraw a part of the canvas
+ pBitmap->clip(aPolyPoly);
+ pBitmap->draw( pDevicePixelCanvas );
+
+ mrScreenUpdater.notifyUpdate(*aIter,true);
+ }
+
+ }
+ else
+ {
+ if( !mbIsLastPointValid )
+ {
+ mbIsLastPointValid = true;
+ maLastPoint.setX( e.X );
+ maLastPoint.setY( e.Y );
+ }
+ else
+ {
+ ::basegfx::B2DPolygon aPoly;
+ aPoly.append( maLastPoint );
+
+ maLastPoint.setX( e.X );
+ maLastPoint.setY( e.Y );
+
+ aPoly.append( maLastPoint );
+
+ // paint to all views
+ for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end();
+ aIter!=aEnd;
+ ++aIter )
+ {
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
+ ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( (*aIter)->getCanvas(),
+ aPoly ) );
+
+ if( pPolyPoly )
+ {
+ pPolyPoly->setStrokeWidth(mnStrokeWidth);
+ pPolyPoly->setRGBALineColor( maStrokeColor.getIntegerColor() );
+ pPolyPoly->draw();
+ maPolygons.push_back(pPolyPoly);
+ }
+ }
+
+ // screen update necessary to show painting
+ mrScreenUpdater.notifyUpdate();
+ }
+ }
+ // mouse events captured
+ return true;
+ }
+
+ virtual bool handleMouseMoved( const awt::MouseEvent& /*e*/ )
+ {
+ // not used here
+ return false; // did not handle the event
+ }
+
+
+ void update_settings( bool bUserPaintEnabled, RGBColor const& aUserPaintColor, double dUserPaintStrokeWidth )
+ {
+ maStrokeColor = aUserPaintColor;
+ mnStrokeWidth = dUserPaintStrokeWidth;
+ mbActive = bUserPaintEnabled;
+ if( !mbActive )
+ disable();
+ }
+
+ private:
+ ActivitiesQueue& mrActivitiesQueue;
+ ScreenUpdater& mrScreenUpdater;
+ UnoViewVector maViews;
+ PolyPolygonVector maPolygons;
+ RGBColor maStrokeColor;
+ double mnStrokeWidth;
+ basegfx::B2DPoint maLastPoint;
+ basegfx::B2DPoint maLastMouseDownPos;
+ bool mbIsLastPointValid;
+ bool mbIsLastMouseDownPosValid;
+ // added bool for erasing purpose :
+ bool mbIsEraseAllModeActivated;
+ bool mbIsEraseModeActivated;
+ Slide& mrSlide;
+ sal_Int32 mnSize;
+ bool mbActive;
+ };
+
+ UserPaintOverlaySharedPtr UserPaintOverlay::create( const RGBColor& rStrokeColor,
+ double nStrokeWidth,
+ const SlideShowContext& rContext,
+ const PolyPolygonVector& rPolygons,
+ bool bActive )
+ {
+ UserPaintOverlaySharedPtr pRet( new UserPaintOverlay( rStrokeColor,
+ nStrokeWidth,
+ rContext,
+ rPolygons,
+ bActive));
+
+ return pRet;
+ }
+
+ UserPaintOverlay::UserPaintOverlay( const RGBColor& rStrokeColor,
+ double nStrokeWidth,
+ const SlideShowContext& rContext,
+ const PolyPolygonVector& rPolygons,
+ bool bActive ) :
+ mpHandler( new PaintOverlayHandler( rStrokeColor,
+ nStrokeWidth,
+ rContext.mrActivitiesQueue,
+ rContext.mrScreenUpdater,
+ rContext.mrViewContainer,
+ //adding a link to Slide
+ dynamic_cast<Slide&>(rContext.mrCursorManager),
+ rPolygons, bActive )),
+ mrMultiplexer( rContext.mrEventMultiplexer )
+ {
+ mrMultiplexer.addClickHandler( mpHandler, 3.0 );
+ mrMultiplexer.addMouseMoveHandler( mpHandler, 3.0 );
+ mrMultiplexer.addViewHandler( mpHandler );
+ mrMultiplexer.addUserPaintHandler(mpHandler);
+ }
+
+ PolyPolygonVector UserPaintOverlay::getPolygons()
+ {
+ return mpHandler->getPolygons();
+ }
+
+ void UserPaintOverlay::drawPolygons()
+ {
+ mpHandler->drawPolygons();
+ }
+
+ void UserPaintOverlay::update_settings( bool bUserPaintEnabled, RGBColor const& aUserPaintColor, double dUserPaintStrokeWidth )
+ {
+ mpHandler->update_settings( bUserPaintEnabled, aUserPaintColor, dUserPaintStrokeWidth );
+ }
+
+
+ UserPaintOverlay::~UserPaintOverlay()
+ {
+ try
+ {
+ mrMultiplexer.removeMouseMoveHandler( mpHandler );
+ mrMultiplexer.removeClickHandler( mpHandler );
+ mrMultiplexer.removeViewHandler( mpHandler );
+ mpHandler->dispose();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slide/userpaintoverlay.hxx b/slideshow/source/engine/slide/userpaintoverlay.hxx
new file mode 100644
index 000000000000..05abeaea2056
--- /dev/null
+++ b/slideshow/source/engine/slide/userpaintoverlay.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_USERPAINTOVERLAY_HXX
+#define INCLUDED_SLIDESHOW_USERPAINTOVERLAY_HXX
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+#include "unoview.hxx"
+#include "rgbcolor.hxx"
+
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+/* Definition of UserPaintOverlay class */
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class EventMultiplexer;
+ struct SlideShowContext;
+
+ class PaintOverlayHandler;
+ typedef ::boost::shared_ptr< class UserPaintOverlay > UserPaintOverlaySharedPtr;
+ typedef ::std::vector< ::cppcanvas::PolyPolygonSharedPtr> PolyPolygonVector;
+ /** Slide overlay, which can be painted into by the user.
+
+ This class registers itself at the EventMultiplexer,
+ listening for mouse clicks and moves. When the mouse is
+ dragged, a hand sketching in the selected color is shown.
+ */
+ class UserPaintOverlay : private boost::noncopyable
+ {
+ public:
+ /** Create a UserPaintOverlay
+
+ @param rStrokeColor
+ Color to use for drawing
+
+ @param nStrokeWidth
+ Width of the stroked path
+ */
+ static UserPaintOverlaySharedPtr create( const RGBColor& rStrokeColor,
+ double nStrokeWidth,
+ const SlideShowContext& rContext,
+ const PolyPolygonVector& rPolygons,
+ bool bActive);
+ ~UserPaintOverlay();
+ PolyPolygonVector getPolygons();
+ void drawPolygons();
+
+ void update_settings( bool bUserPaintEnabled, RGBColor const& aUserPaintColor, double dUserPaintStrokeWidth );
+
+
+ private:
+ UserPaintOverlay( const RGBColor& rStrokeColor,
+ double nStrokeWidth,
+ const SlideShowContext& rContext,
+ const PolyPolygonVector& rPolygons,
+ bool bActive );
+
+ ::boost::shared_ptr<PaintOverlayHandler> mpHandler;
+ EventMultiplexer& mrMultiplexer;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_USERPAINTOVERLAY_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slidebitmap.cxx b/slideshow/source/engine/slidebitmap.cxx
new file mode 100644
index 000000000000..2f73a3e9dfbc
--- /dev/null
+++ b/slideshow/source/engine/slidebitmap.cxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <slidebitmap.hxx>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/XBitmap.hpp>
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <canvas/canvastools.hxx>
+#include <basegfx/tools/canvastools.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ SlideBitmap::SlideBitmap( const ::cppcanvas::BitmapSharedPtr& rBitmap ) :
+ maOutputPos(),
+ maClipPoly(),
+ mxBitmap()
+ {
+ if( rBitmap )
+ mxBitmap = rBitmap->getUNOBitmap();
+
+ ENSURE_OR_THROW( mxBitmap.is(), "SlideBitmap::SlideBitmap(): Invalid bitmap" );
+ }
+
+ bool SlideBitmap::draw( const ::cppcanvas::CanvasSharedPtr& rCanvas ) const
+ {
+ ENSURE_OR_RETURN_FALSE( rCanvas && rCanvas->getUNOCanvas().is(),
+ "SlideBitmap::draw(): Invalid canvas" );
+
+ // selectively only copy the transformation from current viewstate,
+ // don't want no clipping here.
+ rendering::ViewState aViewState;
+ aViewState.AffineTransform = rCanvas->getViewState().AffineTransform;
+
+ rendering::RenderState aRenderState;
+ ::canvas::tools::initRenderState( aRenderState );
+
+ const basegfx::B2DHomMatrix aTranslation(basegfx::tools::createTranslateB2DHomMatrix(maOutputPos));
+ ::canvas::tools::setRenderStateTransform( aRenderState, aTranslation );
+
+ try
+ {
+ if( maClipPoly.count() )
+ {
+ // TODO(P1): Buffer the clip polygon
+ aRenderState.Clip =
+ ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ rCanvas->getUNOCanvas()->getDevice(),
+ maClipPoly );
+ }
+
+ rCanvas->getUNOCanvas()->drawBitmap( mxBitmap,
+ aViewState,
+ aRenderState );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ ::basegfx::B2ISize SlideBitmap::getSize() const
+ {
+ return ::basegfx::unotools::b2ISizeFromIntegerSize2D( mxBitmap->getSize() );
+ }
+
+ void SlideBitmap::move( const ::basegfx::B2DPoint& rNewPos )
+ {
+ maOutputPos = rNewPos;
+ }
+
+ void SlideBitmap::clip( const ::basegfx::B2DPolyPolygon& rClipPoly )
+ {
+ maClipPoly = rClipPoly;
+ }
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap > SlideBitmap::getXBitmap()
+ {
+ return mxBitmap;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slideshowcontext.cxx b/slideshow/source/engine/slideshowcontext.cxx
new file mode 100644
index 000000000000..ee2ef90c4619
--- /dev/null
+++ b/slideshow/source/engine/slideshowcontext.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#include "precompiled_slideshow.hxx"
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include "slideshowcontext.hxx"
+#include "subsettableshapemanager.hxx"
+#include "screenupdater.hxx"
+#include "eventqueue.hxx"
+#include "activitiesqueue.hxx"
+#include "usereventqueue.hxx"
+#include "eventmultiplexer.hxx"
+#include "unoviewcontainer.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+namespace internal
+{
+
+SlideShowContext::SlideShowContext( SubsettableShapeManagerSharedPtr& rSubsettableShapeManager,
+ EventQueue& rEventQueue,
+ EventMultiplexer& rEventMultiplexer,
+ ScreenUpdater& rScreenUpdater,
+ ActivitiesQueue& rActivitiesQueue,
+ UserEventQueue& rUserEventQueue,
+ CursorManager& rCursorManager,
+ const UnoViewContainer& rViewContainer,
+ const uno::Reference<
+ uno::XComponentContext>& rComponentContext ) :
+ mpSubsettableShapeManager( rSubsettableShapeManager ),
+ mrEventQueue( rEventQueue ),
+ mrEventMultiplexer( rEventMultiplexer ),
+ mrScreenUpdater( rScreenUpdater ),
+ mrActivitiesQueue( rActivitiesQueue ),
+ mrUserEventQueue( rUserEventQueue ),
+ mrCursorManager( rCursorManager ),
+ mrViewContainer( rViewContainer ),
+ mxComponentContext( rComponentContext )
+ {}
+
+void SlideShowContext::dispose()
+{
+ mxComponentContext.clear();
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slideshowimpl.cxx b/slideshow/source/engine/slideshowimpl.cxx
new file mode 100644
index 000000000000..7ede504abc20
--- /dev/null
+++ b/slideshow/source/engine/slideshowimpl.cxx
@@ -0,0 +1,2465 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <cppuhelper/compbase2.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <comphelper/make_shared_from_uno.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/optional.hxx>
+#include <comphelper/servicedecl.hxx>
+#include <comphelper/namecontainer.hxx>
+
+#include <cppcanvas/spritecanvas.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include <tools/debug.hxx>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/tools/canvastools.hxx>
+
+#include <vcl/font.hxx>
+#include "rtl/ref.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/util/XUpdatable.hpp>
+#include <com/sun/star/awt/XPaintListener.hpp>
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/presentation/XSlideShow.hpp>
+#include <com/sun/star/presentation/XSlideShowListener.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/drawing/XLayer.hpp>
+#include <com/sun/star/drawing/XLayerSupplier.hpp>
+#include <com/sun/star/drawing/XLayerManager.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+#include "com/sun/star/uno/Reference.hxx"
+#include <com/sun/star/loader/CannotActivateFactoryException.hpp>
+
+#include "unoviewcontainer.hxx"
+#include "transitionfactory.hxx"
+#include "eventmultiplexer.hxx"
+#include "usereventqueue.hxx"
+#include "eventqueue.hxx"
+#include "cursormanager.hxx"
+#include "slideshowcontext.hxx"
+#include "activitiesqueue.hxx"
+#include "activitiesfactory.hxx"
+#include "interruptabledelayevent.hxx"
+#include "slide.hxx"
+#include "shapemaps.hxx"
+#include "slideview.hxx"
+#include "tools.hxx"
+#include "unoview.hxx"
+#include "slidebitmap.hxx"
+#include "rehearsetimingsactivity.hxx"
+#include "waitsymbol.hxx"
+#include "effectrewinder.hxx"
+#include "framerate.hxx"
+
+#include <boost/noncopyable.hpp>
+#include <boost/bind.hpp>
+
+#include <map>
+#include <vector>
+#include <iterator>
+#include <string>
+#include <algorithm>
+#include <stdio.h>
+#include <iostream>
+
+using namespace com::sun::star;
+using namespace ::slideshow::internal;
+
+namespace {
+
+/** During animations the update() method tells its caller to call it as
+ soon as possible. This gives us more time to render the next frame and
+ still maintain a steady frame rate. This class is responsible for
+ synchronizing the display of new frames and thus keeping the frame rate
+ steady.
+*/
+class FrameSynchronization
+{
+public:
+ /** Create new object with a predefined duration between two frames.
+ @param nFrameDuration
+ The preferred duration between the display of two frames in
+ seconds.
+ */
+ FrameSynchronization (const double nFrameDuration);
+
+ /** Set the current time as the time at which the current frame is
+ displayed. From this the target time of the next frame is derived.
+ */
+ void MarkCurrentFrame (void);
+
+ /** When there is time left until the next frame is due then wait.
+ Otherwise return without delay.
+ */
+ void Synchronize (void);
+
+ /** Activate frame synchronization when an animation is active and
+ frames are to be displayed in a steady rate. While active
+ Synchronize() will wait until the frame duration time has passed.
+ */
+ void Activate (void);
+
+ /** Deactivate frame sychronization when no animation is active and the
+ time between frames depends on user actions and other external
+ sources. While deactivated Synchronize() will return without delay.
+ */
+ void Deactivate (void);
+
+private:
+ /** The timer that is used for synchronization is independent from the
+ one used by SlideShowImpl: it is not paused or modified by
+ animations.
+ */
+ canvas::tools::ElapsedTime maTimer;
+ /** Time between the display of frames. Enforced only when mbIsActive
+ is <TRUE/>.
+ */
+ const double mnFrameDuration;
+ /** Time (of maTimer) when the next frame shall be displayed.
+ Synchronize() will wait until this time.
+ */
+ double mnNextFrameTargetTime;
+ /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
+ it returns immediately.
+ */
+ bool mbIsActive;
+};
+
+/******************************************************************************
+
+ SlideShowImpl
+
+ This class encapsulates the slideshow presentation viewer.
+
+ With an instance of this class, it is possible to statically
+ and dynamically show a presentation, as defined by the
+ constructor-provided draw model (represented by a sequence
+ of ::com::sun::star::drawing::XDrawPage objects).
+
+ It is possible to show the presentation on multiple views
+ simultaneously (e.g. for a multi-monitor setup). Since this
+ class also relies on user interaction, the corresponding
+ XSlideShowView interface provides means to register some UI
+ event listeners (mostly borrowed from awt::XWindow interface).
+
+ Since currently (mid 2004), OOo isn't very well suited to
+ multi-threaded rendering, this class relies on <em>very
+ frequent</em> external update() calls, which will render the
+ next frame of animations. This works as follows: after the
+ displaySlide() has been successfully called (which setup and
+ starts an actual slide show), the update() method must be
+ called until it returns false.
+ Effectively, this puts the burden of providing
+ concurrency to the clients of this class, which, as noted
+ above, is currently unavoidable with the current state of
+ affairs (I've actually tried threading here, but failed
+ miserably when using the VCL canvas as the render backend -
+ deadlocked).
+
+ ******************************************************************************/
+
+typedef cppu::WeakComponentImplHelper1<presentation::XSlideShow> SlideShowImplBase;
+
+typedef ::std::vector< ::cppcanvas::PolyPolygonSharedPtr> PolyPolygonVector;
+
+/// Maps XDrawPage for annotations persistence
+typedef ::std::map< ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage>,
+ PolyPolygonVector> PolygonMap;
+
+class SlideShowImpl : private cppu::BaseMutex,
+ public CursorManager,
+ public SlideShowImplBase
+{
+public:
+ explicit SlideShowImpl(
+ uno::Reference<uno::XComponentContext> const& xContext );
+
+ /** Notify that the transition phase of the current slide
+ has ended.
+
+ The life of a slide has three phases: the transition
+ phase, when the previous slide vanishes, and the
+ current slide becomes visible, the shape animation
+ phase, when shape effects are running, and the phase
+ after the last shape animation has ended, but before
+ the next slide transition starts.
+
+ This method notifies the end of the first phase.
+
+ @param bPaintSlide
+ When true, Slide::show() is passed a true as well, denoting
+ explicit paint of slide content. Pass false here, if e.g. a
+ slide transition has already rendered the initial slide image.
+ */
+ void notifySlideTransitionEnded( bool bPaintSlide );
+
+ /** Notify that the shape animation phase of the current slide
+ has ended.
+
+ The life of a slide has three phases: the transition
+ phase, when the previous slide vanishes, and the
+ current slide becomes visible, the shape animation
+ phase, when shape effects are running, and the phase
+ after the last shape animation has ended, but before
+ the next slide transition starts.
+
+ This method notifies the end of the second phase.
+ */
+ void notifySlideAnimationsEnded();
+
+ /** Notify that the slide has ended.
+
+ The life of a slide has three phases: the transition
+ phase, when the previous slide vanishes, and the
+ current slide becomes visible, the shape animation
+ phase, when shape effects are running, and the phase
+ after the last shape animation has ended, but before
+ the next slide transition starts.
+
+ This method notifies the end of the third phase.
+ */
+ void notifySlideEnded (const bool bReverse);
+
+ /** Notification from eventmultiplexer that a hyperlink
+ has been clicked.
+ */
+ bool notifyHyperLinkClicked( rtl::OUString const& hyperLink );
+
+ /** Notification from eventmultiplexer that an animation event has occoured.
+ This will be forewarded to all registered XSlideShowListener
+ */
+ bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode );
+
+private:
+ // XSlideShow:
+ virtual sal_Bool SAL_CALL nextEffect() throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL previousEffect() throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL startShapeActivity(
+ uno::Reference<drawing::XShape> const& xShape )
+ throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL stopShapeActivity(
+ uno::Reference<drawing::XShape> const& xShape )
+ throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL pause( sal_Bool bPauseShow )
+ throw (uno::RuntimeException);
+ virtual uno::Reference<drawing::XDrawPage> SAL_CALL getCurrentSlide()
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL displaySlide(
+ uno::Reference<drawing::XDrawPage> const& xSlide,
+ uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
+ uno::Reference<animations::XAnimationNode> const& xRootNode,
+ uno::Sequence<beans::PropertyValue> const& rProperties )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL registerUserPaintPolygons( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xDocFactory ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL setProperty(
+ beans::PropertyValue const& rProperty ) throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL addView(
+ uno::Reference<presentation::XSlideShowView> const& xView )
+ throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL removeView(
+ uno::Reference<presentation::XSlideShowView> const& xView )
+ throw (uno::RuntimeException);
+ virtual sal_Bool SAL_CALL update( double & nNextTimeout )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL addSlideShowListener(
+ uno::Reference<presentation::XSlideShowListener> const& xListener )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL removeSlideShowListener(
+ uno::Reference<presentation::XSlideShowListener> const& xListener )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL addShapeEventListener(
+ uno::Reference<presentation::XShapeEventListener> const& xListener,
+ uno::Reference<drawing::XShape> const& xShape )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL removeShapeEventListener(
+ uno::Reference<presentation::XShapeEventListener> const& xListener,
+ uno::Reference<drawing::XShape> const& xShape )
+ throw (uno::RuntimeException);
+ virtual void SAL_CALL setShapeCursor(
+ uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
+ throw (uno::RuntimeException);
+
+ // CursorManager
+ // -----------------------------------------------------------
+
+ virtual bool requestCursor( sal_Int16 nCursorShape );
+ virtual void resetCursor();
+
+ /** This is somewhat similar to displaySlide when called for the current
+ slide. It has been simplified to take advantage of that no slide
+ change takes place. Furthermore it does not show the slide
+ transition.
+ */
+ void redisplayCurrentSlide (void);
+
+protected:
+ // WeakComponentImplHelperBase
+ virtual void SAL_CALL disposing();
+
+ bool isDisposed() const
+ {
+ return (rBHelper.bDisposed || rBHelper.bInDispose);
+ }
+
+private:
+ struct SeparateListenerImpl; friend struct SeparateListenerImpl;
+ struct PrefetchPropertiesFunc; friend struct PrefetchPropertiesFunc;
+
+ /// Stop currently running show.
+ void stopShow();
+
+ ///Find a polygons vector in maPolygons (map)
+ PolygonMap::iterator findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage);
+
+ /// Creates a new slide.
+ SlideSharedPtr makeSlide(
+ uno::Reference<drawing::XDrawPage> const& xDrawPage,
+ uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
+ uno::Reference<animations::XAnimationNode> const& xRootNode );
+
+ /// Checks whether the given slide/animation node matches mpPrefetchSlide
+ static bool matches(
+ SlideSharedPtr const& pSlide,
+ uno::Reference<drawing::XDrawPage> const& xSlide,
+ uno::Reference<animations::XAnimationNode> const& xNode )
+ {
+ if (pSlide)
+ return (pSlide->getXDrawPage() == xSlide &&
+ pSlide->getXAnimationNode() == xNode);
+ else
+ return (!xSlide.is() && !xNode.is());
+ }
+
+ /// Resets the current slide transition sound object with a new one:
+ SoundPlayerSharedPtr resetSlideTransitionSound(
+ uno::Any const& url = uno::Any(), bool bLoopSound = false );
+
+ /// stops the current slide transition sound
+ void stopSlideTransitionSound();
+
+ /** Prepare a slide transition
+
+ This method registers all necessary events and
+ activities for a slide transition.
+
+ @return the slide change activity, or NULL for no transition effect
+ */
+ ActivitySharedPtr createSlideTransition(
+ const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const SlideSharedPtr& rLeavingSlide,
+ const SlideSharedPtr& rEnteringSlide,
+ const EventSharedPtr& rTransitionEndEvent );
+
+ /** Request/release the wait symbol. The wait symbol is displayed when
+ there are more requests then releases. Locking the wait symbol
+ helps to avoid intermediate repaints.
+
+ Do not call this method directly. Use WaitSymbolLock instead.
+ */
+ void requestWaitSymbol (void);
+ void releaseWaitSymbol (void);
+
+ class WaitSymbolLock {public:
+ WaitSymbolLock(SlideShowImpl& rSlideShowImpl) : mrSlideShowImpl(rSlideShowImpl)
+ { mrSlideShowImpl.requestWaitSymbol(); }
+ ~WaitSymbolLock(void)
+ { mrSlideShowImpl.releaseWaitSymbol(); }
+ private: SlideShowImpl& mrSlideShowImpl;
+ };
+
+ /// Filter requested cursor shape against hard slideshow cursors (wait, etc.)
+ sal_Int16 calcActiveCursor( sal_Int16 nCursorShape ) const;
+
+ /** This method is called asynchronously to finish the rewinding of an
+ effect to the previous slide that was initiated earlier.
+ */
+ void rewindEffectToPreviousSlide (void);
+
+ /// all registered views
+ UnoViewContainer maViewContainer;
+
+ /// all registered slide show listeners
+ cppu::OInterfaceContainerHelper maListenerContainer;
+
+ /// map of vectors, containing all registered listeners for a shape
+ ShapeEventListenerMap maShapeEventListeners;
+ /// map of sal_Int16 values, specifying the mouse cursor for every shape
+ ShapeCursorMap maShapeCursors;
+
+ //map of vector of Polygons, containing polygons drawn on each slide.
+ PolygonMap maPolygons;
+
+ boost::optional<RGBColor> maUserPaintColor;
+
+ double maUserPaintStrokeWidth;
+
+ //changed for the eraser project
+ boost::optional<bool> maEraseAllInk;
+ boost::optional<bool> maSwitchPenMode;
+ boost::optional<bool> maSwitchEraserMode;
+ boost::optional<sal_Int32> maEraseInk;
+ //end changed
+
+ boost::shared_ptr<canvas::tools::ElapsedTime> mpPresTimer;
+ ScreenUpdater maScreenUpdater;
+ EventQueue maEventQueue;
+ EventMultiplexer maEventMultiplexer;
+ ActivitiesQueue maActivitiesQueue;
+ UserEventQueue maUserEventQueue;
+ SubsettableShapeManagerSharedPtr mpDummyPtr;
+
+ boost::shared_ptr<SeparateListenerImpl> mpListener;
+
+ boost::shared_ptr<RehearseTimingsActivity> mpRehearseTimingsActivity;
+ boost::shared_ptr<WaitSymbol> mpWaitSymbol;
+
+ /// the current slide transition sound object:
+ SoundPlayerSharedPtr mpCurrentSlideTransitionSound;
+
+ uno::Reference<uno::XComponentContext> mxComponentContext;
+ uno::Reference<
+ presentation::XTransitionFactory> mxOptionalTransitionFactory;
+
+ /// the previously running slide
+ SlideSharedPtr mpPreviousSlide;
+ /// the currently running slide
+ SlideSharedPtr mpCurrentSlide;
+ /// the already prefetched slide: best candidate for upcoming slide
+ SlideSharedPtr mpPrefetchSlide;
+ /// slide to be prefetched: best candidate for upcoming slide
+ uno::Reference<drawing::XDrawPage> mxPrefetchSlide;
+ /// save the XDrawPagesSupplier to retieve polygons
+ uno::Reference<drawing::XDrawPagesSupplier> mxDrawPagesSupplier;
+ /// slide animation to be prefetched:
+ uno::Reference<animations::XAnimationNode> mxPrefetchAnimationNode;
+
+ sal_Int16 mnCurrentCursor;
+
+ sal_Int32 mnWaitSymbolRequestCount;
+ bool mbAutomaticAdvancementMode;
+ bool mbImageAnimationsAllowed;
+ bool mbNoSlideTransitions;
+ bool mbMouseVisible;
+ bool mbForceManualAdvance;
+ bool mbShowPaused;
+ bool mbSlideShowIdle;
+ bool mbDisableAnimationZOrder;
+
+ EffectRewinder maEffectRewinder;
+ FrameSynchronization maFrameSynchronization;
+};
+
+/** Separate event listener for animation, view and hyperlink events.
+
+ This handler is registered for slide animation end, view and
+ hyperlink events at the global EventMultiplexer, and forwards
+ notifications to the SlideShowImpl
+*/
+struct SlideShowImpl::SeparateListenerImpl : public EventHandler,
+ public ViewRepaintHandler,
+ public HyperlinkHandler,
+ public AnimationEventHandler,
+ private boost::noncopyable
+{
+ SlideShowImpl& mrShow;
+ ScreenUpdater& mrScreenUpdater;
+ EventQueue& mrEventQueue;
+
+ SeparateListenerImpl( SlideShowImpl& rShow,
+ ScreenUpdater& rScreenUpdater,
+ EventQueue& rEventQueue ) :
+ mrShow( rShow ),
+ mrScreenUpdater( rScreenUpdater ),
+ mrEventQueue( rEventQueue )
+ {}
+
+ // EventHandler
+ virtual bool handleEvent()
+ {
+ // DON't call notifySlideAnimationsEnded()
+ // directly, but queue an event. handleEvent()
+ // might be called from e.g.
+ // showNext(), and notifySlideAnimationsEnded() must not be called
+ // in recursion. Note that the event is scheduled for the next
+ // frame so that its expensive execution does not come in between
+ // sprite hiding and shape redraw (at the end of the animation of a
+ // shape), which would cause a flicker.
+ mrEventQueue.addEventForNextRound(
+ makeEvent(
+ boost::bind( &SlideShowImpl::notifySlideAnimationsEnded, boost::ref(mrShow) ),
+ "SlideShowImpl::notifySlideAnimationsEnded"));
+ return true;
+ }
+
+ // ViewRepaintHandler
+ virtual void viewClobbered( const UnoViewSharedPtr& rView )
+ {
+ // given view needs repaint, request update
+ mrScreenUpdater.notifyUpdate(rView, true);
+ }
+
+ // HyperlinkHandler
+ virtual bool handleHyperlink( ::rtl::OUString const& rLink )
+ {
+ return mrShow.notifyHyperLinkClicked(rLink);
+ }
+
+ // AnimationEventHandler
+ virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
+ {
+ return mrShow.handleAnimationEvent(rNode);
+ }
+};
+
+SlideShowImpl::SlideShowImpl(
+ uno::Reference<uno::XComponentContext> const& xContext )
+ : SlideShowImplBase(m_aMutex),
+ maViewContainer(),
+ maListenerContainer( m_aMutex ),
+ maShapeEventListeners(),
+ maShapeCursors(),
+ maUserPaintColor(),
+ maUserPaintStrokeWidth(4.0),
+ mpPresTimer( new canvas::tools::ElapsedTime ),
+ maScreenUpdater(maViewContainer),
+ maEventQueue( mpPresTimer ),
+ maEventMultiplexer( maEventQueue,
+ maViewContainer ),
+ maActivitiesQueue( mpPresTimer ),
+ maUserEventQueue( maEventMultiplexer,
+ maEventQueue,
+ *this ),
+ mpDummyPtr(),
+ mpListener(),
+ mpRehearseTimingsActivity(),
+ mpWaitSymbol(),
+ mpCurrentSlideTransitionSound(),
+ mxComponentContext( xContext ),
+ mxOptionalTransitionFactory(),
+ mpCurrentSlide(),
+ mpPrefetchSlide(),
+ mxPrefetchSlide(),
+ mxDrawPagesSupplier(),
+ mxPrefetchAnimationNode(),
+ mnCurrentCursor(awt::SystemPointer::ARROW),
+ mnWaitSymbolRequestCount(0),
+ mbAutomaticAdvancementMode(false),
+ mbImageAnimationsAllowed( true ),
+ mbNoSlideTransitions( false ),
+ mbMouseVisible( true ),
+ mbForceManualAdvance( false ),
+ mbShowPaused( false ),
+ mbSlideShowIdle( true ),
+ mbDisableAnimationZOrder( false ),
+ maEffectRewinder(maEventMultiplexer, maEventQueue, maUserEventQueue),
+ maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond)
+
+{
+ // keep care not constructing any UNO references to this inside ctor,
+ // shift that code to create()!
+
+ uno::Reference<lang::XMultiComponentFactory> xFactory(
+ mxComponentContext->getServiceManager() );
+
+ if( xFactory.is() )
+ {
+ try
+ {
+ // #i82460# try to retrieve special transition factory
+ mxOptionalTransitionFactory.set(
+ xFactory->createInstanceWithContext(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.presentation.TransitionFactory" )),
+ mxComponentContext ),
+ uno::UNO_QUERY );
+ }
+ catch (loader::CannotActivateFactoryException const&)
+ {
+ }
+ }
+
+ mpListener.reset( new SeparateListenerImpl(
+ *this,
+ maScreenUpdater,
+ maEventQueue ));
+ maEventMultiplexer.addSlideAnimationsEndHandler( mpListener );
+ maEventMultiplexer.addViewRepaintHandler( mpListener );
+ maEventMultiplexer.addHyperlinkHandler( mpListener, 0.0 );
+ maEventMultiplexer.addAnimationStartHandler( mpListener );
+ maEventMultiplexer.addAnimationEndHandler( mpListener );
+}
+
+// we are about to be disposed (someone call dispose() on us)
+void SlideShowImpl::disposing()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ maEffectRewinder.dispose();
+
+ // stop slide transition sound, if any:
+ stopSlideTransitionSound();
+
+ mxComponentContext.clear();
+
+ if( mpCurrentSlideTransitionSound )
+ {
+ mpCurrentSlideTransitionSound->dispose();
+ mpCurrentSlideTransitionSound.reset();
+ }
+
+ mpWaitSymbol.reset();
+
+ if( mpRehearseTimingsActivity )
+ {
+ mpRehearseTimingsActivity->dispose();
+ mpRehearseTimingsActivity.reset();
+ }
+
+ if( mpListener )
+ {
+ maEventMultiplexer.removeSlideAnimationsEndHandler(mpListener);
+ maEventMultiplexer.removeViewRepaintHandler(mpListener);
+ maEventMultiplexer.removeHyperlinkHandler(mpListener);
+ maEventMultiplexer.removeAnimationStartHandler( mpListener );
+ maEventMultiplexer.removeAnimationEndHandler( mpListener );
+
+ mpListener.reset();
+ }
+
+ maUserEventQueue.clear();
+ maActivitiesQueue.clear();
+ maEventMultiplexer.clear();
+ maEventQueue.clear();
+ mpPresTimer.reset();
+ maShapeCursors.clear();
+ maShapeEventListeners.clear();
+
+ // send all listeners a disposing() that we are going down:
+ maListenerContainer.disposeAndClear(
+ lang::EventObject( static_cast<cppu::OWeakObject *>(this) ) );
+
+ maViewContainer.dispose();
+
+ // release slides:
+ mxPrefetchAnimationNode.clear();
+ mxPrefetchSlide.clear();
+ mpPrefetchSlide.reset();
+ mpCurrentSlide.reset();
+ mpPreviousSlide.reset();
+}
+
+/// stops the current slide transition sound
+void SlideShowImpl::stopSlideTransitionSound()
+{
+ if (mpCurrentSlideTransitionSound)
+ {
+ mpCurrentSlideTransitionSound->stopPlayback();
+ mpCurrentSlideTransitionSound->dispose();
+ mpCurrentSlideTransitionSound.reset();
+ }
+ }
+
+SoundPlayerSharedPtr SlideShowImpl::resetSlideTransitionSound( const uno::Any& rSound, bool bLoopSound )
+{
+ sal_Bool bStopSound = sal_False;
+ rtl::OUString url;
+
+ if( !(rSound >>= bStopSound) )
+ bStopSound = sal_False;
+ rSound >>= url;
+
+ if( !bStopSound && (url.getLength() == 0) )
+ return SoundPlayerSharedPtr();
+
+ stopSlideTransitionSound();
+
+ if (url.getLength() > 0)
+ {
+ try
+ {
+ mpCurrentSlideTransitionSound = SoundPlayer::create(
+ maEventMultiplexer, url, mxComponentContext );
+ mpCurrentSlideTransitionSound->setPlaybackLoop( bLoopSound );
+ }
+ catch (lang::NoSupportException const&)
+ {
+ // catch possible exceptions from SoundPlayer, since
+ // being not able to playback the sound is not a hard
+ // error here (still, the slide transition should be
+ // shown).
+ }
+ }
+ return mpCurrentSlideTransitionSound;
+}
+
+ActivitySharedPtr SlideShowImpl::createSlideTransition(
+ const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const SlideSharedPtr& rLeavingSlide,
+ const SlideSharedPtr& rEnteringSlide,
+ const EventSharedPtr& rTransitionEndEvent)
+{
+ ENSURE_OR_THROW( !maViewContainer.empty(),
+ "createSlideTransition(): No views" );
+ ENSURE_OR_THROW( rEnteringSlide,
+ "createSlideTransition(): No entering slide" );
+
+ // return empty transition, if slide transitions
+ // are disabled.
+ if (mbNoSlideTransitions)
+ return ActivitySharedPtr();
+
+ // retrieve slide change parameters from XDrawPage
+ uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
+ uno::UNO_QUERY );
+
+ if( !xPropSet.is() )
+ {
+ OSL_TRACE( "createSlideTransition(): "
+ "Slide has no PropertySet - assuming no transition\n" );
+ return ActivitySharedPtr();
+ }
+
+ sal_Int16 nTransitionType(0);
+ if( !getPropertyValue( nTransitionType,
+ xPropSet,
+ OUSTR("TransitionType" )) )
+ {
+ OSL_TRACE( "createSlideTransition(): "
+ "Could not extract slide transition type from XDrawPage - assuming no transition\n" );
+ return ActivitySharedPtr();
+ }
+
+ sal_Int16 nTransitionSubType(0);
+ if( !getPropertyValue( nTransitionSubType,
+ xPropSet,
+ OUSTR("TransitionSubtype" )) )
+ {
+ OSL_TRACE( "createSlideTransition(): "
+ "Could not extract slide transition subtype from XDrawPage - assuming no transition\n" );
+ return ActivitySharedPtr();
+ }
+
+ bool bTransitionDirection(false);
+ if( !getPropertyValue( bTransitionDirection,
+ xPropSet,
+ OUSTR("TransitionDirection")) )
+ {
+ OSL_TRACE( "createSlideTransition(): "
+ "Could not extract slide transition direction from XDrawPage - assuming default direction\n" );
+ }
+
+ sal_Int32 aUnoColor(0);
+ if( !getPropertyValue( aUnoColor,
+ xPropSet,
+ OUSTR("TransitionFadeColor")) )
+ {
+ OSL_TRACE( "createSlideTransition(): "
+ "Could not extract slide transition fade color from XDrawPage - assuming black\n" );
+ }
+
+ const RGBColor aTransitionFadeColor( unoColor2RGBColor( aUnoColor ));
+
+ uno::Any aSound;
+ sal_Bool bLoopSound = sal_False;
+
+ if( !getPropertyValue( aSound, xPropSet, OUSTR("Sound")) )
+ OSL_TRACE( "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound\n" );
+
+ if( !getPropertyValue( bLoopSound, xPropSet, OUSTR("LoopSound") ) )
+ OSL_TRACE( "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound\n" );
+
+ NumberAnimationSharedPtr pTransition(
+ TransitionFactory::createSlideTransition(
+ rLeavingSlide,
+ rEnteringSlide,
+ maViewContainer,
+ maScreenUpdater,
+ maEventMultiplexer,
+ mxOptionalTransitionFactory,
+ nTransitionType,
+ nTransitionSubType,
+ bTransitionDirection,
+ aTransitionFadeColor,
+ resetSlideTransitionSound( aSound, bLoopSound ) ));
+
+ if( !pTransition )
+ return ActivitySharedPtr(); // no transition effect has been
+ // generated. Normally, that means
+ // that simply no transition is
+ // set on this slide.
+
+ double nTransitionDuration(0.0);
+ if( !getPropertyValue( nTransitionDuration,
+ xPropSet,
+ OUSTR("TransitionDuration")) )
+ {
+ OSL_TRACE( "createSlideTransition(): "
+ "Could not extract slide transition duration from XDrawPage - assuming no transition\n" );
+ return ActivitySharedPtr();
+ }
+
+ sal_Int32 nMinFrames(5);
+ if( !getPropertyValue( nMinFrames,
+ xPropSet,
+ OUSTR("MinimalFrameNumber")) )
+ {
+ OSL_TRACE( "createSlideTransition(): "
+ "No minimal number of frames given - assuming 5\n" );
+ }
+
+ // prefetch slide transition bitmaps, but postpone it after
+ // displaySlide() has finished - sometimes, view size has not yet
+ // reached final size
+ maEventQueue.addEvent(
+ makeEvent(
+ boost::bind(
+ &::slideshow::internal::Animation::prefetch,
+ pTransition,
+ AnimatableShapeSharedPtr(),
+ ShapeAttributeLayerSharedPtr()),
+ "Animation::prefetch"));
+
+ return ActivitySharedPtr(
+ ActivitiesFactory::createSimpleActivity(
+ ActivitiesFactory::CommonParameters(
+ rTransitionEndEvent,
+ maEventQueue,
+ maActivitiesQueue,
+ nTransitionDuration,
+ nMinFrames,
+ false,
+ boost::optional<double>(1.0),
+ 0.0,
+ 0.0,
+ ShapeSharedPtr(),
+ rEnteringSlide->getSlideSize() ),
+ pTransition,
+ true ));
+}
+
+PolygonMap::iterator SlideShowImpl::findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage)
+{
+ // TODO(P2) : Optimze research in the map.
+ bool bFound = false;
+ PolygonMap::iterator aIter=maPolygons.begin();
+
+ while(aIter!=maPolygons.end() && !bFound)
+ {
+ if(aIter->first == xDrawPage)
+ bFound = true;
+ else
+ aIter++;
+ }
+
+ return aIter;
+}
+
+SlideSharedPtr SlideShowImpl::makeSlide(
+ uno::Reference<drawing::XDrawPage> const& xDrawPage,
+ uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
+ uno::Reference<animations::XAnimationNode> const& xRootNode )
+{
+ if( !xDrawPage.is() )
+ return SlideSharedPtr();
+
+ //Retrieve polygons for the current slide
+ PolygonMap::iterator aIter;
+ aIter = findPolygons(xDrawPage);
+
+ const SlideSharedPtr pSlide( createSlide(xDrawPage,
+ xDrawPages,
+ xRootNode,
+ maEventQueue,
+ maEventMultiplexer,
+ maScreenUpdater,
+ maActivitiesQueue,
+ maUserEventQueue,
+ *this,
+ maViewContainer,
+ mxComponentContext,
+ maShapeEventListeners,
+ maShapeCursors,
+ (aIter != maPolygons.end()) ? aIter->second : PolyPolygonVector(),
+ maUserPaintColor ? *maUserPaintColor : RGBColor(),
+ maUserPaintStrokeWidth,
+ !!maUserPaintColor,
+ mbImageAnimationsAllowed,
+ mbDisableAnimationZOrder) );
+
+ // prefetch show content (reducing latency for slide
+ // bitmap and effect start later on)
+ pSlide->prefetch();
+
+ return pSlide;
+}
+
+void SlideShowImpl::requestWaitSymbol (void)
+{
+ ++mnWaitSymbolRequestCount;
+ OSL_ASSERT(mnWaitSymbolRequestCount>0);
+
+ if (mnWaitSymbolRequestCount == 1)
+ {
+ if( !mpWaitSymbol )
+ {
+ // fall back to cursor
+ requestCursor(calcActiveCursor(mnCurrentCursor));
+ }
+ else
+ mpWaitSymbol->show();
+ }
+}
+
+void SlideShowImpl::releaseWaitSymbol (void)
+{
+ --mnWaitSymbolRequestCount;
+ OSL_ASSERT(mnWaitSymbolRequestCount>=0);
+
+ if (mnWaitSymbolRequestCount == 0)
+ {
+ if( !mpWaitSymbol )
+ {
+ // fall back to cursor
+ requestCursor(calcActiveCursor(mnCurrentCursor));
+ }
+ else
+ mpWaitSymbol->hide();
+ }
+}
+
+sal_Int16 SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape ) const
+{
+ if( mnWaitSymbolRequestCount>0 && !mpWaitSymbol ) // enforce wait cursor
+ nCursorShape = awt::SystemPointer::WAIT;
+ else if( !mbMouseVisible ) // enforce INVISIBLE
+ nCursorShape = awt::SystemPointer::INVISIBLE;
+ else if( maUserPaintColor &&
+ nCursorShape == awt::SystemPointer::ARROW )
+ nCursorShape = awt::SystemPointer::PEN;
+
+ return nCursorShape;
+}
+
+void SlideShowImpl::stopShow()
+{
+ // Force-end running animation
+ // ===========================
+ if (mpCurrentSlide)
+ {
+ mpCurrentSlide->hide();
+ //Register polygons in the map
+ if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
+ maPolygons.erase(mpCurrentSlide->getXDrawPage());
+
+ maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
+ }
+
+ // clear all queues
+ maEventQueue.clear();
+ maActivitiesQueue.clear();
+
+ // Attention: we MUST clear the user event queue here,
+ // this is because the current slide might have registered
+ // shape events (click or enter/leave), which might
+ // otherwise dangle forever in the queue (because of the
+ // shared ptr nature). If someone needs to change this:
+ // somehow unregister those shapes at the user event queue
+ // on notifySlideEnded().
+ maUserEventQueue.clear();
+
+ // re-enable automatic effect advancement
+ // (maEventQueue.clear() above might have killed
+ // maEventMultiplexer's tick events)
+ if (mbAutomaticAdvancementMode)
+ {
+ // toggle automatic mode (enabling just again is
+ // ignored by EventMultiplexer)
+ maEventMultiplexer.setAutomaticMode( false );
+ maEventMultiplexer.setAutomaticMode( true );
+ }
+}
+
+class SlideShowImpl::PrefetchPropertiesFunc
+{
+public:
+ PrefetchPropertiesFunc( SlideShowImpl * that_,
+ bool& rbSkipAllMainSequenceEffects,
+ bool& rbSkipSlideTransition)
+ : mpSlideShowImpl(that_),
+ mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects),
+ mrbSkipSlideTransition(rbSkipSlideTransition)
+ {}
+
+ void operator()( beans::PropertyValue const& rProperty ) const {
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("Prefetch") ))
+ {
+ uno::Sequence<uno::Any> seq;
+ if ((rProperty.Value >>= seq) && seq.getLength() == 2)
+ {
+ seq[0] >>= mpSlideShowImpl->mxPrefetchSlide;
+ seq[1] >>= mpSlideShowImpl->mxPrefetchAnimationNode;
+ }
+ }
+ else if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("SkipAllMainSequenceEffects") ))
+ {
+ rProperty.Value >>= mrbSkipAllMainSequenceEffects;
+ }
+ else if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("SkipSlideTransition") ))
+ {
+ rProperty.Value >>= mrbSkipSlideTransition;
+ }
+ else
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ rProperty.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+private:
+ SlideShowImpl *const mpSlideShowImpl;
+ bool& mrbSkipAllMainSequenceEffects;
+ bool& mrbSkipSlideTransition;
+};
+
+void SlideShowImpl::displaySlide(
+ uno::Reference<drawing::XDrawPage> const& xSlide,
+ uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
+ uno::Reference<animations::XAnimationNode> const& xRootNode,
+ uno::Sequence<beans::PropertyValue> const& rProperties )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ maEffectRewinder.setRootAnimationNode(xRootNode);
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ mxDrawPagesSupplier = xDrawPages;
+
+ stopShow(); // MUST call that: results in
+ // maUserEventQueue.clear(). What's more,
+ // stopShow()'s currSlide->hide() call is
+ // now also required, notifySlideEnded()
+ // relies on that
+ // unconditionally. Otherwise, genuine
+ // shape animations (drawing layer and
+ // GIF) will not be stopped.
+
+ bool bSkipAllMainSequenceEffects (false);
+ bool bSkipSlideTransition (false);
+ std::for_each( rProperties.getConstArray(),
+ rProperties.getConstArray() + rProperties.getLength(),
+ PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects, bSkipSlideTransition) );
+
+ OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
+ if (maViewContainer.empty())
+ return;
+
+ // this here might take some time
+ {
+ WaitSymbolLock aLock (*this);
+
+ mpPreviousSlide = mpCurrentSlide;
+ mpCurrentSlide.reset();
+
+ if (matches( mpPrefetchSlide, xSlide, xRootNode ))
+ {
+ // prefetched slide matches:
+ mpCurrentSlide = mpPrefetchSlide;
+ }
+ else
+ mpCurrentSlide = makeSlide( xSlide, xDrawPages, xRootNode );
+
+ OSL_ASSERT( mpCurrentSlide );
+ if (mpCurrentSlide)
+ {
+ basegfx::B2DSize oldSlideSize;
+ if( mpPreviousSlide )
+ oldSlideSize = mpPreviousSlide->getSlideSize();
+
+ basegfx::B2DSize const slideSize( mpCurrentSlide->getSlideSize() );
+
+ // push new transformation to all views, if size changed
+ if( !mpPreviousSlide || oldSlideSize != slideSize )
+ {
+ std::for_each( maViewContainer.begin(),
+ maViewContainer.end(),
+ boost::bind( &View::setViewSize, _1,
+ boost::cref(slideSize) ));
+
+ // explicitly notify view change here,
+ // because transformation might have changed:
+ // optimization, this->notifyViewChange() would
+ // repaint slide which is not necessary.
+ maEventMultiplexer.notifyViewsChanged();
+ }
+
+ // create slide transition, and add proper end event
+ // (which then starts the slide effects
+ // via CURRENT_SLIDE.show())
+ ActivitySharedPtr pSlideChangeActivity (
+ createSlideTransition(
+ mpCurrentSlide->getXDrawPage(),
+ mpPreviousSlide,
+ mpCurrentSlide,
+ makeEvent(
+ boost::bind(
+ &SlideShowImpl::notifySlideTransitionEnded,
+ this,
+ false ),
+ "SlideShowImpl::notifySlideTransitionEnded")));
+
+ if (bSkipSlideTransition)
+ {
+ // The transition activity was created for the side effects
+ // (like sound transitions). Because we want to skip the
+ // acutual transition animation we do not need the activity
+ // anymore.
+ pSlideChangeActivity.reset();
+ }
+
+ if (pSlideChangeActivity)
+ {
+ // factory generated a slide transition - activate it!
+ maActivitiesQueue.addActivity( pSlideChangeActivity );
+ }
+ else
+ {
+ // no transition effect on this slide - schedule slide
+ // effect start event right away.
+ maEventQueue.addEvent(
+ makeEvent(
+ boost::bind(
+ &SlideShowImpl::notifySlideTransitionEnded,
+ this,
+ true ),
+ "SlideShowImpl::notifySlideTransitionEnded"));
+ }
+ }
+ } // finally
+
+ maEventMultiplexer.notifySlideTransitionStarted();
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
+
+ // We are currently rewinding an effect. This lead us from the next
+ // slide to this one. To complete this we have to play back all main
+ // sequence effects on this slide.
+ if (bSkipAllMainSequenceEffects)
+ maEffectRewinder.skipAllMainSequenceEffects();
+}
+
+void SlideShowImpl::redisplayCurrentSlide (void)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+ stopShow();
+
+ OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
+ if (maViewContainer.empty())
+ return;
+
+ // No transition effect on this slide - schedule slide
+ // effect start event right away.
+ maEventQueue.addEvent(
+ makeEvent(
+ boost::bind(
+ &SlideShowImpl::notifySlideTransitionEnded,
+ this,
+ true ),
+ "SlideShowImpl::notifySlideTransitionEnded"));
+
+ maEventMultiplexer.notifySlideTransitionStarted();
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
+}
+
+sal_Bool SlideShowImpl::nextEffect() throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ if (mbShowPaused)
+ return true;
+ else
+ return maEventMultiplexer.notifyNextEffect();
+}
+
+sal_Bool SlideShowImpl::previousEffect() throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ if (mbShowPaused)
+ return true;
+ else
+ {
+ return maEffectRewinder.rewind(
+ maScreenUpdater.createLock(false),
+ ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::redisplayCurrentSlide), this),
+ ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::rewindEffectToPreviousSlide), this));
+ }
+}
+
+void SlideShowImpl::rewindEffectToPreviousSlide (void)
+{
+ // Show the wait symbol now and prevent it from showing temporary slide
+ // content while effects are played back.
+ WaitSymbolLock aLock (*this);
+
+ // A previous call to EffectRewinder::Rewind could not rewind the current
+ // effect because there are no effects on the current slide or none has
+ // yet been displayed. Go to the previous slide.
+ notifySlideEnded(true);
+
+ // Process pending events once more in order to have the following
+ // screen update show the last effect. Not sure whether this should be
+ // necessary.
+ maEventQueue.forceEmpty();
+
+ // We have to call the screen updater before the wait symbol is turned
+ // off. Otherwise the wait symbol would force the display of an
+ // intermediate state of the slide (before the effects are replayed.)
+ maScreenUpdater.commitUpdates();
+}
+
+sal_Bool SlideShowImpl::startShapeActivity(
+ uno::Reference<drawing::XShape> const& /*xShape*/ )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ // TODO(F3): NYI
+ OSL_FAIL( "not yet implemented!" );
+ return false;
+}
+
+sal_Bool SlideShowImpl::stopShapeActivity(
+ uno::Reference<drawing::XShape> const& /*xShape*/ )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ // TODO(F3): NYI
+ OSL_FAIL( "not yet implemented!" );
+ return false;
+}
+
+sal_Bool SlideShowImpl::pause( sal_Bool bPauseShow )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ if (bPauseShow)
+ mpPresTimer->pauseTimer();
+ else
+ mpPresTimer->continueTimer();
+
+ maEventMultiplexer.notifyPauseMode(bPauseShow);
+
+ mbShowPaused = bPauseShow;
+ return true;
+}
+
+uno::Reference<drawing::XDrawPage> SlideShowImpl::getCurrentSlide()
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return uno::Reference<drawing::XDrawPage>();
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ if (mpCurrentSlide)
+ return mpCurrentSlide->getXDrawPage();
+ else
+ return uno::Reference<drawing::XDrawPage>();
+}
+
+sal_Bool SlideShowImpl::addView(
+ uno::Reference<presentation::XSlideShowView> const& xView )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ // first of all, check if view has a valid canvas
+ ENSURE_OR_RETURN_FALSE( xView.is(), "addView(): Invalid view" );
+ ENSURE_OR_RETURN_FALSE( xView->getCanvas().is(),
+ "addView(): View does not provide a valid canvas" );
+
+ UnoViewSharedPtr const pView( createSlideView(
+ xView,
+ maEventQueue,
+ maEventMultiplexer ));
+ if (!maViewContainer.addView( pView ))
+ return false; // view already added
+
+ // initialize view content
+ // =======================
+
+ if (mpCurrentSlide)
+ {
+ // set view transformation
+ const basegfx::B2ISize slideSize = mpCurrentSlide->getSlideSize();
+ pView->setViewSize( basegfx::B2DSize( slideSize.getX(),
+ slideSize.getY() ) );
+ }
+
+ // clear view area (since its newly added,
+ // we need a clean slate)
+ pView->clearAll();
+
+ // broadcast newly added view
+ maEventMultiplexer.notifyViewAdded( pView );
+
+ // set current mouse ptr
+ pView->setCursorShape( calcActiveCursor(mnCurrentCursor) );
+
+ return true;
+}
+
+sal_Bool SlideShowImpl::removeView(
+ uno::Reference<presentation::XSlideShowView> const& xView )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ ENSURE_OR_RETURN_FALSE( xView.is(), "removeView(): Invalid view" );
+
+ UnoViewSharedPtr const pView( maViewContainer.removeView( xView ) );
+ if( !pView )
+ return false; // view was not added in the first place
+
+ // remove view from EventMultiplexer (mouse events etc.)
+ maEventMultiplexer.notifyViewRemoved( pView );
+
+ pView->_dispose();
+
+ return true;
+}
+
+void SlideShowImpl::registerUserPaintPolygons( const uno::Reference< lang::XMultiServiceFactory >& xDocFactory ) throw (uno::RuntimeException)
+{
+ //Retrieve Polygons if user ends presentation by context menu
+ if (mpCurrentSlide)
+ {
+ if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
+ maPolygons.erase(mpCurrentSlide->getXDrawPage());
+
+ maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
+ }
+
+ //Creating the layer for shapes
+ // query for the XLayerManager
+ uno::Reference< drawing::XLayerSupplier > xLayerSupplier(xDocFactory, uno::UNO_QUERY);
+ uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
+
+ uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
+ // create a layer and set its properties
+ uno::Reference< drawing::XLayer > xDrawnInSlideshow = xLayerManager->insertNewByIndex(xLayerManager->getCount());
+ uno::Reference< beans::XPropertySet > xLayerPropSet(xDrawnInSlideshow, uno::UNO_QUERY);
+
+ //Layer Name which enables to catch annotations
+ rtl::OUString layerName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DrawnInSlideshow"));
+ uno::Any aPropLayer;
+
+ aPropLayer <<= layerName;
+ xLayerPropSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Name")), aPropLayer);
+
+ aPropLayer <<= true;
+ xLayerPropSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsVisible")), aPropLayer);
+
+ aPropLayer <<= false;
+ xLayerPropSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsLocked")), aPropLayer);
+
+ PolygonMap::iterator aIter=maPolygons.begin();
+
+ PolyPolygonVector aPolygons;
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly;
+ ::basegfx::B2DPolyPolygon b2DPolyPoly;
+
+ //Register polygons for each slide
+ while(aIter!=maPolygons.end())
+ {
+ aPolygons = aIter->second;
+ //Get shapes for the slide
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > Shapes(aIter->first, ::com::sun::star::uno::UNO_QUERY);
+ //Retrieve polygons for one slide
+ for( PolyPolygonVector::iterator aIterPoly=aPolygons.begin(),
+ aEnd=aPolygons.end();
+ aIterPoly!=aEnd; ++aIterPoly )
+ {
+ pPolyPoly = (*aIterPoly);
+ b2DPolyPoly = ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly->getUNOPolyPolygon());
+
+ //Normally there is only one polygon
+ for(sal_uInt32 i=0; i< b2DPolyPoly.count();i++)
+ {
+ const ::basegfx::B2DPolygon& aPoly = b2DPolyPoly.getB2DPolygon(i);
+ sal_uInt32 nPoints = aPoly.count();
+
+ if( nPoints > 1)
+ {
+ //create the PolyLineShape
+ uno::Reference< uno::XInterface > polyshape(xDocFactory->createInstance(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.PolyLineShape")) ) );
+ uno::Reference< drawing::XShape > rPolyShape(polyshape, uno::UNO_QUERY);
+
+ //Add the shape to the slide
+ Shapes->add(rPolyShape);
+
+ //Retrieve shape properties
+ uno::Reference< beans::XPropertySet > aXPropSet = uno::Reference< beans::XPropertySet >( rPolyShape, uno::UNO_QUERY );
+ //Construct a sequence of points sequence
+ drawing::PointSequenceSequence aRetval;
+ //Create only one sequence for one polygon
+ aRetval.realloc( 1 );
+ // Retrieve the sequence of points from aRetval
+ drawing::PointSequence* pOuterSequence = aRetval.getArray();
+ // Create 2 points in this sequence
+ pOuterSequence->realloc(nPoints);
+ // Get these points which are in an array
+ awt::Point* pInnerSequence = pOuterSequence->getArray();
+ for( sal_uInt32 n = 0; n < nPoints; n++ )
+ {
+ //Create a point from the polygon
+ *pInnerSequence++ = awt::Point(
+ basegfx::fround(aPoly.getB2DPoint(n).getX()),
+ basegfx::fround(aPoly.getB2DPoint(n).getY()));
+ }
+
+ //Fill the properties
+ //Give the built PointSequenceSequence.
+ uno::Any aParam;
+ aParam <<= aRetval;
+ aXPropSet->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PolyPolygon")), aParam );
+
+ //LineStyle : SOLID by default
+ uno::Any aAny;
+ drawing::LineStyle eLS;
+ eLS = drawing::LineStyle_SOLID;
+ aAny <<= eLS;
+ aXPropSet->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LineStyle")), aAny );
+
+ //LineColor
+ sal_uInt32 nLineColor;
+ nLineColor = pPolyPoly->getRGBALineColor();
+ //Transform polygon color from RRGGBBAA to AARRGGBB
+ aAny <<= RGBAColor2UnoColor(nLineColor);
+ aXPropSet->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LineColor")), aAny );
+
+ //LineWidth
+ double fLineWidth;
+ fLineWidth = pPolyPoly->getStrokeWidth();
+ aAny <<= (sal_Int32)fLineWidth;
+ aXPropSet->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LineWidth")), aAny );
+
+ // make polygons special
+ xLayerManager->attachShapeToLayer(rPolyShape, xDrawnInSlideshow);
+ }
+ }
+ }
+ ++aIter;
+ }
+}
+
+sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("AutomaticAdvancement") ))
+ {
+ double nTimeout(0.0);
+ mbAutomaticAdvancementMode = (rProperty.Value >>= nTimeout);
+ if (mbAutomaticAdvancementMode)
+ {
+ maEventMultiplexer.setAutomaticTimeout( nTimeout );
+ }
+ maEventMultiplexer.setAutomaticMode( mbAutomaticAdvancementMode );
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("UserPaintColor") ))
+ {
+ sal_Int32 nColor(0);
+ if (rProperty.Value >>= nColor)
+ {
+ OSL_ENSURE( mbMouseVisible,
+ "setProperty(): User paint overrides invisible mouse" );
+
+ // enable user paint
+ maUserPaintColor.reset( unoColor2RGBColor( nColor ) );
+ if( mpCurrentSlide && !mpCurrentSlide->isPaintOverlayActive() )
+ mpCurrentSlide->enablePaintOverlay();
+
+ maEventMultiplexer.notifyUserPaintColor( *maUserPaintColor );
+ }
+ else
+ {
+ // disable user paint
+ maUserPaintColor.reset();
+ maEventMultiplexer.notifyUserPaintDisabled();
+ if( mpCurrentSlide )
+ mpCurrentSlide->disablePaintOverlay();
+ }
+
+ resetCursor();
+
+ return true;
+ }
+
+ //adding support for erasing features in UserPaintOverlay
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("EraseAllInk") ))
+ {
+ bool nEraseAllInk(false);
+ if (rProperty.Value >>= nEraseAllInk)
+ {
+ OSL_ENSURE( mbMouseVisible,
+ "setProperty(): User paint overrides invisible mouse" );
+
+ // enable user paint
+ maEraseAllInk.reset( nEraseAllInk );
+ maEventMultiplexer.notifyEraseAllInk( *maEraseAllInk );
+ }
+
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("SwitchPenMode") ))
+ {
+ bool nSwitchPenMode(false);
+ if (rProperty.Value >>= nSwitchPenMode)
+ {
+ OSL_ENSURE( mbMouseVisible,
+ "setProperty(): User paint overrides invisible mouse" );
+
+ if(nSwitchPenMode == true){
+ // Switch to Pen Mode
+ maSwitchPenMode.reset( nSwitchPenMode );
+ maEventMultiplexer.notifySwitchPenMode();
+ }
+ }
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("SwitchEraserMode") ))
+ {
+ bool nSwitchEraserMode(false);
+ if (rProperty.Value >>= nSwitchEraserMode)
+ {
+ OSL_ENSURE( mbMouseVisible,
+ "setProperty(): User paint overrides invisible mouse" );
+ if(nSwitchEraserMode == true){
+ // switch to Eraser mode
+ maSwitchEraserMode.reset( nSwitchEraserMode );
+ maEventMultiplexer.notifySwitchEraserMode();
+ }
+ }
+
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("EraseInk") ))
+ {
+ sal_Int32 nEraseInk(100);
+ if (rProperty.Value >>= nEraseInk)
+ {
+ OSL_ENSURE( mbMouseVisible,
+ "setProperty(): User paint overrides invisible mouse" );
+
+ // enable user paint
+ maEraseInk.reset( nEraseInk );
+ maEventMultiplexer.notifyEraseInkWidth( *maEraseInk );
+ }
+
+ return true;
+ }
+
+ // new Property for pen's width
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("UserPaintStrokeWidth") ))
+ {
+ double nWidth(4.0);
+ if (rProperty.Value >>= nWidth)
+ {
+ OSL_ENSURE( mbMouseVisible,"setProperty(): User paint overrides invisible mouse" );
+ // enable user paint stroke width
+ maUserPaintStrokeWidth = nWidth;
+ maEventMultiplexer.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth );
+ }
+
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("AdvanceOnClick") ))
+ {
+ sal_Bool bAdvanceOnClick = sal_False;
+ if (! (rProperty.Value >>= bAdvanceOnClick))
+ return false;
+ maUserEventQueue.setAdvanceOnClick( bAdvanceOnClick );
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("DisableAnimationZOrder") ))
+ {
+ sal_Bool bDisableAnimationZOrder = sal_False;
+ if (! (rProperty.Value >>= bDisableAnimationZOrder))
+ return false;
+ mbDisableAnimationZOrder = bDisableAnimationZOrder == sal_True;
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("ImageAnimationsAllowed") ) )
+ {
+ if (! (rProperty.Value >>= mbImageAnimationsAllowed))
+ return false;
+
+ // TODO(F3): Forward to slides!
+// if( bOldValue != mbImageAnimationsAllowed )
+// {
+// if( mbImageAnimationsAllowed )
+// maEventMultiplexer.notifyIntrinsicAnimationsEnabled();
+// else
+// maEventMultiplexer.notifyIntrinsicAnimationsDisabled();
+// }
+
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("MouseVisible") ))
+ {
+ if (! (rProperty.Value >>= mbMouseVisible))
+ return false;
+
+ requestCursor(mnCurrentCursor);
+
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("ForceManualAdvance") ))
+ {
+ return (rProperty.Value >>= mbForceManualAdvance);
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("RehearseTimings") ))
+ {
+ bool bRehearseTimings = false;
+ if (! (rProperty.Value >>= bRehearseTimings))
+ return false;
+
+ if (bRehearseTimings)
+ {
+ // TODO(Q3): Move to slide
+ mpRehearseTimingsActivity = RehearseTimingsActivity::create(
+ SlideShowContext(
+ mpDummyPtr,
+ maEventQueue,
+ maEventMultiplexer,
+ maScreenUpdater,
+ maActivitiesQueue,
+ maUserEventQueue,
+ *this,
+ maViewContainer,
+ mxComponentContext) );
+ }
+ else if (mpRehearseTimingsActivity)
+ {
+ // removes timer from all views:
+ mpRehearseTimingsActivity->dispose();
+ mpRehearseTimingsActivity.reset();
+ }
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("WaitSymbolBitmap") ))
+ {
+ uno::Reference<rendering::XBitmap> xBitmap;
+ if (! (rProperty.Value >>= xBitmap))
+ return false;
+
+ mpWaitSymbol = WaitSymbol::create( xBitmap,
+ maScreenUpdater,
+ maEventMultiplexer,
+ maViewContainer );
+
+ return true;
+ }
+
+ if (rProperty.Name.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("NoSlideTransitions") ))
+ {
+ return (rProperty.Value >>= mbNoSlideTransitions);
+ }
+
+ if (rProperty.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("IsSoundEnabled")))
+ {
+ uno::Sequence<uno::Any> aValues;
+ uno::Reference<presentation::XSlideShowView> xView;
+ sal_Bool bValue (false);
+ if ((rProperty.Value >>= aValues)
+ && aValues.getLength()==2
+ && (aValues[0] >>= xView)
+ && (aValues[1] >>= bValue))
+ {
+ // Look up the view.
+ for (UnoViewVector::const_iterator
+ iView (maViewContainer.begin()),
+ iEnd (maViewContainer.end());
+ iView!=iEnd;
+ ++iView)
+ {
+ if (*iView && (*iView)->getUnoView()==xView)
+ {
+ // Store the flag at the view so that media shapes have
+ // access to it.
+ (*iView)->setIsSoundEnabled(bValue);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void SlideShowImpl::addSlideShowListener(
+ uno::Reference<presentation::XSlideShowListener> const& xListener )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ // container syncs with passed mutex ref
+ maListenerContainer.addInterface(xListener);
+}
+
+void SlideShowImpl::removeSlideShowListener(
+ uno::Reference<presentation::XSlideShowListener> const& xListener )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // container syncs with passed mutex ref
+ maListenerContainer.removeInterface(xListener);
+}
+
+void SlideShowImpl::addShapeEventListener(
+ uno::Reference<presentation::XShapeEventListener> const& xListener,
+ uno::Reference<drawing::XShape> const& xShape )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ ShapeEventListenerMap::iterator aIter;
+ if( (aIter=maShapeEventListeners.find( xShape )) ==
+ maShapeEventListeners.end() )
+ {
+ // no entry for this shape -> create one
+ aIter = maShapeEventListeners.insert(
+ ShapeEventListenerMap::value_type(
+ xShape,
+ boost::shared_ptr<cppu::OInterfaceContainerHelper>(
+ new cppu::OInterfaceContainerHelper(m_aMutex)))).first;
+ }
+
+ // add new listener to broadcaster
+ if( aIter->second.get() )
+ aIter->second->addInterface( xListener );
+
+ maEventMultiplexer.notifyShapeListenerAdded(xListener,
+ xShape);
+}
+
+void SlideShowImpl::removeShapeEventListener(
+ uno::Reference<presentation::XShapeEventListener> const& xListener,
+ uno::Reference<drawing::XShape> const& xShape )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ ShapeEventListenerMap::iterator aIter;
+ if( (aIter = maShapeEventListeners.find( xShape )) !=
+ maShapeEventListeners.end() )
+ {
+ // entry for this shape found -> remove listener from
+ // helper object
+ ENSURE_OR_THROW(
+ aIter->second.get(),
+ "SlideShowImpl::removeShapeEventListener(): "
+ "listener map contains NULL broadcast helper" );
+
+ aIter->second->removeInterface( xListener );
+ }
+
+ maEventMultiplexer.notifyShapeListenerRemoved(xListener,
+ xShape);
+}
+
+void SlideShowImpl::setShapeCursor(
+ uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return;
+
+ // precondition: must only be called from the main thread!
+ DBG_TESTSOLARMUTEX();
+
+ ShapeCursorMap::iterator aIter;
+ if( (aIter=maShapeCursors.find( xShape )) == maShapeCursors.end() )
+ {
+ // no entry for this shape -> create one
+ if( nPointerShape != awt::SystemPointer::ARROW )
+ {
+ // add new entry, unless shape shall display
+ // normal pointer arrow -> no need to handle that
+ // case
+ maShapeCursors.insert(
+ ShapeCursorMap::value_type(xShape,
+ nPointerShape) );
+ }
+ }
+ else if( nPointerShape == awt::SystemPointer::ARROW )
+ {
+ // shape shall display normal cursor -> can disable
+ // the cursor and clear the entry
+ maShapeCursors.erase( xShape );
+ }
+ else
+ {
+ // existing entry found, update with new cursor ID
+ aIter->second = nPointerShape;
+ }
+
+ maEventMultiplexer.notifyShapeCursorChange(xShape,
+ nPointerShape);
+}
+
+bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape )
+{
+ mnCurrentCursor = nCursorShape;
+
+ const sal_Int16 nActualCursor = calcActiveCursor(mnCurrentCursor);
+
+ // change all views to the requested cursor ID
+ std::for_each( maViewContainer.begin(),
+ maViewContainer.end(),
+ boost::bind( &View::setCursorShape,
+ _1,
+ nActualCursor ));
+
+ return nActualCursor==nCursorShape;
+}
+
+void SlideShowImpl::resetCursor()
+{
+ mnCurrentCursor = awt::SystemPointer::ARROW;
+
+ // change all views to the default cursor ID
+ std::for_each( maViewContainer.begin(),
+ maViewContainer.end(),
+ boost::bind( &View::setCursorShape,
+ _1,
+ calcActiveCursor(mnCurrentCursor) ));
+}
+
+sal_Bool SlideShowImpl::update( double & nNextTimeout )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (isDisposed())
+ return false;
+
+ // precondition: update() must only be called from the
+ // main thread!
+ DBG_TESTSOLARMUTEX();
+
+ if( mbShowPaused )
+ {
+ // commit frame (might be repaints pending)
+ maScreenUpdater.commitUpdates();
+
+ return false;
+ }
+ else
+ {
+ // TODO(F2): re-evaluate whether that timer lagging makes
+ // sense.
+
+ // hold timer, while processing the queues:
+ // 1. when there is more than one active activity this ensures the
+ // same time for all activities and events
+ // 2. processing of events may lead to creation of further events
+ // that have zero delay. While the timer is stopped these events
+ // are processed in the same run.
+ {
+ comphelper::ScopeGuard scopeGuard(
+ boost::bind( &canvas::tools::ElapsedTime::releaseTimer,
+ boost::cref(mpPresTimer) ) );
+ mpPresTimer->holdTimer();
+
+ // process queues
+ maEventQueue.process();
+ maActivitiesQueue.process();
+
+ // commit frame to screen
+ maFrameSynchronization.Synchronize();
+ maScreenUpdater.commitUpdates();
+
+ // TODO(Q3): remove need to call dequeued() from
+ // activities. feels like a wart.
+ //
+ // Rationale for ActivitiesQueue::processDequeued(): when
+ // an activity ends, it usually pushed the end state to
+ // the animated shape in question, and ends the animation
+ // (which, in turn, will usually disable shape sprite
+ // mode). Disabling shape sprite mode causes shape
+ // repaint, which, depending on slide content, takes
+ // considerably more time than sprite updates. Thus, the
+ // last animation step tends to look delayed. To
+ // camouflage this, reaching end position and disabling
+ // sprite mode is split into two (normal Activity::end(),
+ // and Activity::dequeued()). Now, the reason to call
+ // commitUpdates() twice here is caused by the unrelated
+ // fact that during wait cursor display/hide, the screen
+ // is updated, and shows hidden sprites, but, in case of
+ // leaving the second commitUpdates() call out and punting
+ // that to the next round, no updated static slide
+ // content. In short, the last shape animation of a slide
+ // tends to blink at its end.
+
+ // process dequeued activities _after_ commit to screen
+ maActivitiesQueue.processDequeued();
+
+ // commit frame to screen
+ maScreenUpdater.commitUpdates();
+ }
+ // Time held until here
+
+ const bool bActivitiesLeft = (! maActivitiesQueue.isEmpty());
+ const bool bTimerEventsLeft = (! maEventQueue.isEmpty());
+ const bool bRet = (bActivitiesLeft || bTimerEventsLeft);
+
+ if (bRet)
+ {
+ // calc nNextTimeout value:
+ if (bActivitiesLeft)
+ {
+ // Activity queue is not empty. Tell caller that we would
+ // like to render another frame.
+
+ // Return a zero time-out to signal our caller to call us
+ // back as soon as possible. The actual timing, waiting the
+ // appropriate amount of time between frames, is then done
+ // by the maFrameSynchronization object.
+ nNextTimeout = 0;
+ maFrameSynchronization.Activate();
+ }
+ else
+ {
+ // timer events left:
+ // difference from current time (nota bene:
+ // time no longer held here!) to the next event in
+ // the event queue.
+
+ // #i61190# Retrieve next timeout only _after_
+ // processing activity queue
+
+ // ensure positive value:
+ nNextTimeout = std::max( 0.0, maEventQueue.nextTimeout() );
+
+ // There is no active animation so the frame rate does not
+ // need to be synchronized.
+ maFrameSynchronization.Deactivate();
+ }
+
+ mbSlideShowIdle = false;
+ }
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ // when slideshow is idle, issue an XUpdatable::update() call
+ // exactly once after a previous animation sequence finished -
+ // this might trigger screen dumps on some canvas
+ // implementations
+ if( !mbSlideShowIdle &&
+ (!bRet ||
+ nNextTimeout > 1.0) )
+ {
+ UnoViewVector::const_iterator aCurr(maViewContainer.begin());
+ const UnoViewVector::const_iterator aEnd(maViewContainer.end());
+ while( aCurr != aEnd )
+ {
+ try
+ {
+ uno::Reference< presentation::XSlideShowView > xView( (*aCurr)->getUnoView(),
+ uno::UNO_QUERY_THROW );
+ uno::Reference< util::XUpdatable > xUpdatable( xView->getCanvas(),
+ uno::UNO_QUERY_THROW );
+ xUpdatable->update();
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+
+ ++aCurr;
+ }
+
+ mbSlideShowIdle = true;
+ }
+#endif
+
+ return bRet;
+ }
+}
+
+void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ OSL_ENSURE( !isDisposed(), "### already disposed!" );
+ OSL_ENSURE( mpCurrentSlide,
+ "notifySlideTransitionEnded(): Invalid current slide" );
+ if (mpCurrentSlide)
+ {
+ mpCurrentSlide->update_settings( !!maUserPaintColor, maUserPaintColor ? *maUserPaintColor : RGBColor(), maUserPaintStrokeWidth );
+
+ // first init show, to give the animations
+ // the chance to register SlideStartEvents
+ const bool bBackgroundLayerRendered( !bPaintSlide );
+ mpCurrentSlide->show( bBackgroundLayerRendered );
+ maEventMultiplexer.notifySlideStartEvent();
+ }
+}
+
+void queryAutomaticSlideTransition( uno::Reference<drawing::XDrawPage> const& xDrawPage,
+ double& nAutomaticNextSlideTimeout,
+ bool& bHasAutomaticNextSlide )
+{
+ // retrieve slide change parameters from XDrawPage
+ // ===============================================
+
+ uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
+ uno::UNO_QUERY );
+
+ sal_Int32 nChange(0);
+ if( !xPropSet.is() ||
+ !getPropertyValue( nChange,
+ xPropSet,
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("Change"))) )
+ {
+ OSL_TRACE(
+ "queryAutomaticSlideTransition(): "
+ "Could not extract slide change mode from XDrawPage - assuming <none>\n" );
+ }
+
+ bHasAutomaticNextSlide = nChange == 1;
+
+ if( !xPropSet.is() ||
+ !getPropertyValue( nAutomaticNextSlideTimeout,
+ xPropSet,
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("Duration"))) )
+ {
+ OSL_TRACE(
+ "queryAutomaticSlideTransition(): "
+ "Could not extract slide transition timeout from "
+ "XDrawPage - assuming 1 sec\n" );
+ }
+}
+
+void SlideShowImpl::notifySlideAnimationsEnded()
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ //Draw polygons above animations
+ mpCurrentSlide->drawPolygons();
+
+ OSL_ENSURE( !isDisposed(), "### already disposed!" );
+
+ // This struct will receive the (interruptable) event,
+ // that triggers the notifySlideEnded() method.
+ InterruptableEventPair aNotificationEvents;
+
+ if( maEventMultiplexer.getAutomaticMode() )
+ {
+ OSL_ENSURE( ! mpRehearseTimingsActivity,
+ "unexpected: RehearseTimings mode!" );
+
+ // schedule a slide end event, with automatic mode's
+ // delay
+ aNotificationEvents = makeInterruptableDelay(
+ boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
+ maEventMultiplexer.getAutomaticTimeout() );
+ }
+ else
+ {
+ OSL_ENSURE( mpCurrentSlide,
+ "notifySlideAnimationsEnded(): Invalid current slide!" );
+
+ bool bHasAutomaticNextSlide=false;
+ double nAutomaticNextSlideTimeout=0.0;
+ queryAutomaticSlideTransition(mpCurrentSlide->getXDrawPage(),
+ nAutomaticNextSlideTimeout,
+ bHasAutomaticNextSlide);
+
+ // check whether slide transition should happen
+ // 'automatically'. If yes, simply schedule the
+ // specified timeout.
+ // NOTE: mbForceManualAdvance and mpRehearseTimingsActivity
+ // override any individual slide setting, to always
+ // step slides manually.
+ if( !mbForceManualAdvance &&
+ !mpRehearseTimingsActivity &&
+ bHasAutomaticNextSlide )
+ {
+ aNotificationEvents = makeInterruptableDelay(
+ boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
+ nAutomaticNextSlideTimeout);
+
+ // TODO(F2): Provide a mechanism to let the user override
+ // this automatic timeout via next()
+ }
+ else
+ {
+ if (mpRehearseTimingsActivity)
+ mpRehearseTimingsActivity->start();
+
+ // generate click event. Thus, the user must
+ // trigger the actual end of a slide. No need to
+ // generate interruptable event here, there's no
+ // timeout involved.
+ aNotificationEvents.mpImmediateEvent =
+ makeEvent( boost::bind<void>(
+ boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
+ "SlideShowImpl::notifySlideEnded");
+ }
+ }
+
+ // register events on the queues. To make automatic slide
+ // changes interruptable, register the interruption event
+ // as a nextEffectEvent target. Note that the timeout
+ // event is optional (e.g. manual slide changes don't
+ // generate a timeout)
+ maUserEventQueue.registerNextEffectEvent(
+ aNotificationEvents.mpImmediateEvent );
+
+ if( aNotificationEvents.mpTimeoutEvent )
+ maEventQueue.addEvent( aNotificationEvents.mpTimeoutEvent );
+
+ // current slide's main sequence is over. Now should be
+ // the time to prefetch the next slide (if any), and
+ // prepare the initial slide bitmap (speeds up slide
+ // change setup time a lot). Show the wait cursor, this
+ // indeed might take some seconds.
+ {
+ WaitSymbolLock aLock (*this);
+
+ if (! matches( mpPrefetchSlide,
+ mxPrefetchSlide, mxPrefetchAnimationNode ))
+ {
+ mpPrefetchSlide = makeSlide( mxPrefetchSlide, mxDrawPagesSupplier,
+ mxPrefetchAnimationNode );
+ }
+ if (mpPrefetchSlide)
+ {
+ // ignore return value, this is just to populate
+ // Slide's internal bitmap buffer, such that the time
+ // needed to generate the slide bitmap is not spent
+ // when the slide change is requested.
+ mpPrefetchSlide->getCurrentSlideBitmap( *maViewContainer.begin() );
+ }
+ } // finally
+
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded ) );
+}
+
+void SlideShowImpl::notifySlideEnded (const bool bReverse)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ OSL_ENSURE( !isDisposed(), "### already disposed!" );
+
+ if (mpRehearseTimingsActivity && !bReverse)
+ {
+ const double time = mpRehearseTimingsActivity->stop();
+ if (mpRehearseTimingsActivity->hasBeenClicked())
+ {
+ // save time at current drawpage:
+ uno::Reference<beans::XPropertySet> xPropSet(
+ mpCurrentSlide->getXDrawPage(), uno::UNO_QUERY );
+ OSL_ASSERT( xPropSet.is() );
+ if (xPropSet.is())
+ {
+ xPropSet->setPropertyValue(
+ OUSTR("Change"),
+ uno::Any( static_cast<sal_Int32>(1) ) );
+ xPropSet->setPropertyValue(
+ OUSTR("Duration"),
+ uno::Any( static_cast<sal_Int32>(time) ) );
+ }
+ }
+ }
+
+ if (bReverse)
+ maEventMultiplexer.notifySlideEndEvent();
+
+ stopShow(); // MUST call that: results in
+ // maUserEventQueue.clear(). What's more,
+ // stopShow()'s currSlide->hide() call is
+ // now also required, notifySlideEnded()
+ // relies on that
+ // unconditionally. Otherwise, genuine
+ // shape animations (drawing layer and
+ // GIF) will not be stopped.
+
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::bind<void>(
+ ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded),
+ _1,
+ sal_Bool(bReverse)));
+}
+
+bool SlideShowImpl::notifyHyperLinkClicked( rtl::OUString const& hyperLink )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::bind( &presentation::XSlideShowListener::hyperLinkClicked,
+ _1,
+ boost::cref(hyperLink) ));
+ return true;
+}
+
+/** Notification from eventmultiplexer that an animation event has occoured.
+ This will be forewarded to all registered XSlideShoeListener
+ */
+bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ uno::Reference<animations::XAnimationNode> xNode( rNode->getXAnimationNode() );
+
+ switch( rNode->getState() )
+ {
+ case AnimationNode::ACTIVE:
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::bind( &animations::XAnimationListener::beginEvent,
+ _1,
+ boost::cref(xNode) ));
+ break;
+
+ case AnimationNode::FROZEN:
+ case AnimationNode::ENDED:
+ maListenerContainer.forEach<presentation::XSlideShowListener>(
+ boost::bind( &animations::XAnimationListener::endEvent,
+ _1,
+ boost::cref(xNode) ));
+ if(mpCurrentSlide->isPaintOverlayActive())
+ mpCurrentSlide->drawPolygons();
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+//===== FrameSynchronization ==================================================
+
+FrameSynchronization::FrameSynchronization (const double nFrameDuration)
+ : maTimer(),
+ mnFrameDuration(nFrameDuration),
+ mnNextFrameTargetTime(0),
+ mbIsActive(false)
+{
+ MarkCurrentFrame();
+}
+
+void FrameSynchronization::MarkCurrentFrame (void)
+{
+ mnNextFrameTargetTime = maTimer.getElapsedTime() + mnFrameDuration;
+}
+
+void FrameSynchronization::Synchronize (void)
+{
+ if (mbIsActive)
+ {
+ // Do busy waiting for now.
+ while (maTimer.getElapsedTime() < mnNextFrameTargetTime)
+ ;
+ }
+
+ MarkCurrentFrame();
+}
+
+void FrameSynchronization::Activate (void)
+{
+ mbIsActive = true;
+}
+
+void FrameSynchronization::Deactivate (void)
+{
+ mbIsActive = false;
+}
+
+} // anon namespace
+
+namespace sdecl = comphelper::service_decl;
+#if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)
+ sdecl::class_<SlideShowImpl> serviceImpl;
+ const sdecl::ServiceDecl slideShowDecl(
+ serviceImpl,
+#else
+ const sdecl::ServiceDecl slideShowDecl(
+ sdecl::class_<SlideShowImpl>(),
+#endif
+ "com.sun.star.comp.presentation.SlideShow",
+ "com.sun.star.presentation.SlideShow" );
+
+// The C shared lib entry points
+COMPHELPER_SERVICEDECL_EXPORTS1(slideShowDecl)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/slideview.cxx b/slideshow/source/engine/slideview.cxx
new file mode 100644
index 000000000000..fc632afd3b13
--- /dev/null
+++ b/slideshow/source/engine/slideview.cxx
@@ -0,0 +1,1194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/canvastools.hxx>
+
+#include "eventqueue.hxx"
+#include "eventmultiplexer.hxx"
+#include "slideview.hxx"
+#include "delayevent.hxx"
+#include "unoview.hxx"
+
+#include <rtl/instance.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase2.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <comphelper/make_shared_from_uno.hxx>
+
+#include <cppcanvas/spritecanvas.hxx>
+#include <cppcanvas/customsprite.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include <tools/debug.hxx>
+
+#include <basegfx/range/b1drange.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+
+#include <com/sun/star/presentation/XSlideShow.hpp>
+
+#include <boost/noncopyable.hpp>
+#include <boost/bind.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <vector>
+#include <iterator>
+#include <algorithm>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+struct StaticUnitRectPoly : public rtl::StaticWithInit<basegfx::B2DPolygon, StaticUnitRectPoly>
+{
+ basegfx::B2DPolygon operator()()
+ {
+ return basegfx::tools::createUnitPolygon();
+ }
+};
+
+/** Sprite entry, to store sprite plus priority
+
+ The operator<() defines a strict weak ordering of sprites, sort
+ key is the sprite priority.
+ */
+struct SpriteEntry
+{
+ SpriteEntry( const cppcanvas::CustomSpriteSharedPtr& rSprite,
+ double nPrio ) :
+ mpSprite( rSprite ),
+ mnPriority( nPrio )
+ {
+ }
+
+ bool operator<(const SpriteEntry& rRHS) const
+ {
+ return mnPriority < rRHS.mnPriority;
+ }
+
+ boost::weak_ptr< cppcanvas::CustomSprite > mpSprite;
+ double mnPriority;
+};
+
+typedef std::vector< SpriteEntry > SpriteVector;
+
+
+/** Create a clip polygon for slide views
+
+ @param rClip
+ Clip to set (can be empty)
+
+ @param rCanvas
+ Canvas to create the clip polygon for
+
+ @param rUserSize
+ The size of the view. Note that the returned clip will
+ <em>always</em> clip to at least the rect defined herein.
+
+ @return the view clip polygon, in view coordinates, which is
+ guaranteed to at least clip to the view size.
+ */
+basegfx::B2DPolyPolygon createClipPolygon( const basegfx::B2DPolyPolygon& rClip,
+ const cppcanvas::CanvasSharedPtr& /*rCanvas*/,
+ const basegfx::B2DSize& rUserSize )
+{
+ // setup canvas clipping
+ // =====================
+
+ // AW: Simplified
+ const basegfx::B2DRange aClipRange(0, 0, rUserSize.getX(), rUserSize.getY());
+
+ if(rClip.count())
+ {
+ return basegfx::tools::clipPolyPolygonOnRange(rClip, aClipRange, true, false);
+ }
+ else
+ {
+ return basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aClipRange));
+ }
+}
+
+/** Prepare given clip polygon to be stored as the current clip
+
+ Note that this is separate from createClipPolygon(), to allow
+ SlideView implementations to store this intermediate result
+ (createClipPolygon() has to be called every time the view size
+ changes)
+ */
+basegfx::B2DPolyPolygon prepareClip( const basegfx::B2DPolyPolygon& rClip )
+{
+ basegfx::B2DPolyPolygon aClip( rClip );
+
+ // TODO(P2): unnecessary, once XCanvas is correctly handling this
+ // AW: Should be no longer necessary; tools are now bezier-safe
+ if( aClip.areControlPointsUsed() )
+ aClip = basegfx::tools::adaptiveSubdivideByAngle( aClip );
+
+ // normalize polygon, preparation for clipping
+ // in updateCanvas()
+ aClip = basegfx::tools::correctOrientations(aClip);
+ aClip = basegfx::tools::solveCrossovers(aClip);
+ aClip = basegfx::tools::stripNeutralPolygons(aClip);
+ aClip = basegfx::tools::stripDispensablePolygons(aClip, false);
+
+ return aClip;
+}
+
+
+void clearRect( ::cppcanvas::CanvasSharedPtr const& pCanvas,
+ basegfx::B2IRange const& rArea )
+{
+ // convert clip polygon to device coordinate system
+ ::basegfx::B2DPolyPolygon const* pClipPoly( pCanvas->getClip() );
+ if( pClipPoly )
+ {
+ ::basegfx::B2DPolyPolygon aClipPoly( *pClipPoly );
+ aClipPoly.transform( pCanvas->getTransformation() );
+ pCanvas->setClip( aClipPoly );
+ }
+
+ // set transformation to identitiy (->device pixel)
+ pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // #i42440# Fill the _full_ background in
+ // black. Since we had to extend the bitmap by one
+ // pixel, and the bitmap is initialized white,
+ // depending on the slide content a one pixel wide
+ // line will show to the bottom and the right.
+ const ::basegfx::B2DPolygon aPoly(
+ ::basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRange(rArea)));
+
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
+ ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( pCanvas,
+ aPoly ) );
+
+ if( pPolyPoly )
+ {
+ pPolyPoly->setCompositeOp( cppcanvas::CanvasGraphic::SOURCE );
+ pPolyPoly->setRGBAFillColor( 0x00000000U );
+ pPolyPoly->draw();
+ }
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ ::cppcanvas::CanvasSharedPtr pCliplessCanvas( pCanvas->clone() );
+ pCliplessCanvas->setClip();
+
+ if( pCanvas->getClip() )
+ {
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly2(
+ ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( pCliplessCanvas,
+ *(pCanvas->getClip()) ));
+ if( pPolyPoly2 )
+ {
+ pPolyPoly2->setRGBALineColor( 0x008000FFU );
+ pPolyPoly2->draw();
+ }
+ }
+#endif
+}
+
+/** Get bounds in pixel
+
+ @param rLayerBounds
+ Bound rect, in user space coordinates
+
+ @param rTransformation
+ User space to device pixel transformation
+
+ @return the layer bounds in pixel, extended by one pixel to the
+ right and bottom
+ */
+basegfx::B2IRange getLayerBoundsPixel( basegfx::B2DRange const& rLayerBounds,
+ basegfx::B2DHomMatrix const& rTransformation )
+{
+ ::basegfx::B2DRange aTmpRect;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRect,
+ rLayerBounds,
+ rTransformation );
+
+ if( aTmpRect.isEmpty() )
+ return ::basegfx::B2IRange();
+
+ // #i42440# Returned layer size is one pixel too small, as
+ // rendering happens one pixel to the right and below the
+ // actual bound rect.
+ return ::basegfx::B2IRange( ::basegfx::fround(aTmpRect.getMinX()),
+ ::basegfx::fround(aTmpRect.getMinY()),
+ ::basegfx::fround(aTmpRect.getMaxX()) + 1,
+ ::basegfx::fround(aTmpRect.getMaxY()) + 1 );
+}
+
+
+// ----------------------------------------------------------------
+
+/** Container class for sprites issued by a ViewLayer
+
+ This class handles the sprite prioritization issues, that are
+ needed for layer sprites (e.g. the need to re-prioritize sprites
+ when the layer changes prio).
+ */
+class LayerSpriteContainer
+{
+ /** Max fill level of maSprites, before we try to prune it from
+ deceased sprites
+ */
+ enum{ SPRITE_ULLAGE=256 };
+
+ /** All sprites that have been issued by this container (pruned
+ from time to time, for invalid references). This vector is
+ kept sorted with increasing sprite priority.
+ */
+ SpriteVector maSprites;
+
+ /// Priority of this layer, relative to other view layers
+ basegfx::B1DRange maLayerPrioRange;
+
+ double getSpritePriority( std::size_t nSpriteNum ) const
+ {
+ // divide the available layer range equally between all
+ // sprites, assign upper bound of individual sprite range as
+ // sprite prio (the layer itself gets assigned the lower bound
+ // of sprite 0's individual range):
+ //
+ // | layer 0 | layer 1 | ...
+ // | sprite 0 | sprite 1 | sprite 0 | sprite 1 | ...
+ return maLayerPrioRange.getMinimum() + maLayerPrioRange.getRange()*(nSpriteNum+1)/(maSprites.size()+1);
+ }
+
+ /** Rescan sprite vector, and remove deceased sprites (and reset
+ sprite prio)
+
+ @param aBegin
+ Iterator to the first entry to rescan
+ */
+ void updateSprites()
+ {
+ SpriteVector aValidSprites;
+
+ // check all sprites for validity and set new priority
+ SpriteVector::iterator aCurrSprite( maSprites.begin() );
+ const SpriteVector::iterator aEnd( maSprites.end() );
+ while( aCurrSprite != aEnd )
+ {
+ cppcanvas::CustomSpriteSharedPtr pCurrSprite( aCurrSprite->mpSprite.lock() );
+
+ if( pCurrSprite )
+ {
+ // only copy still valid sprites over to the refreshed
+ // sprite vector.
+ aValidSprites.push_back( *aCurrSprite );
+
+ pCurrSprite->setPriority(
+ getSpritePriority( aValidSprites.size()-1 ));
+ }
+
+ ++aCurrSprite;
+ }
+
+ // replace sprite list with pruned one
+ maSprites.swap( aValidSprites );
+ }
+
+public:
+ LayerSpriteContainer() :
+ maSprites(),
+ maLayerPrioRange()
+ {
+ }
+
+ basegfx::B1DRange getLayerPriority() const
+ {
+ return maLayerPrioRange;
+ }
+
+ void setLayerPriority( const basegfx::B1DRange& rRange )
+ {
+ if( rRange != maLayerPrioRange )
+ {
+ maLayerPrioRange = rRange;
+
+ // prune and recalc sprite prios
+ updateSprites();
+ }
+ }
+
+ void addSprite( const cppcanvas::CustomSpriteSharedPtr& pSprite,
+ double nPriority )
+ {
+ if( !pSprite )
+ return;
+
+ SpriteEntry aEntry( pSprite,nPriority );
+
+ // insert new sprite, such that vector stays sorted
+ SpriteVector::iterator aInsertPos(
+ maSprites.insert(
+ std::lower_bound( maSprites.begin(),
+ maSprites.end(),
+ aEntry ),
+ aEntry ));
+
+ const std::size_t nNumSprites( maSprites.size() );
+ if( nNumSprites > SPRITE_ULLAGE ||
+ maSprites.end() - aInsertPos > 1 )
+ {
+ // updateSprites() also updates all sprite prios
+ updateSprites();
+ }
+ else
+ {
+ // added sprite to the end, and not too many sprites in
+ // vector - perform optimized update (only need to set
+ // prio). This basically caters for the common case of
+ // iterated character animations, which generate lots of
+ // sprites, all added to the end.
+ pSprite->setPriority(
+ getSpritePriority( nNumSprites-1 ));
+ }
+ }
+
+ void clear()
+ {
+ maSprites.clear();
+ }
+};
+
+
+// ----------------------------------------------------------------
+
+
+/** This class provides layers for a slide view
+
+ Layers are used to render animations with the correct z order -
+ because sprites are always in front of the static canvas
+ background, shapes that must appear <em<before</em> an animation
+ must also be displayed as a sprite.
+
+ Each layer has a priority assigned to it (valid range [0,1]), which
+ also affects all sprites created for this specific layer - i.e. if
+ the layer priority changes, the sprites change z order together
+ with their parent.
+ */
+class SlideViewLayer : public ViewLayer,
+ private boost::noncopyable
+{
+ /// Smart container for all sprites issued by this layer
+ mutable LayerSpriteContainer maSpriteContainer;
+
+ /// Bounds of this layer in user space coordinates
+ basegfx::B2DRange maLayerBounds;
+
+ /// Bounds of this layer in device pixel
+ mutable basegfx::B2IRange maLayerBoundsPixel;
+
+ /// Current clip polygon in user coordinates
+ basegfx::B2DPolyPolygon maClip;
+
+ /// Current size of the view in user coordinates
+ basegfx::B2DSize maUserSize;
+
+ /// Current overall view transformation
+ basegfx::B2DHomMatrix maTransformation;
+
+ /// 'parent' canvas, this viewlayer is associated with
+ const cppcanvas::SpriteCanvasSharedPtr mpSpriteCanvas;
+
+ /** output surface (necessarily a sprite, won't otherwise be able
+ to display anything <em>before</em> other sprites)
+ */
+ mutable cppcanvas::CustomSpriteSharedPtr mpSprite;
+
+ /// actual output canvas retrieved from a sprite
+ mutable cppcanvas::CanvasSharedPtr mpOutputCanvas;
+
+ /// ptr back to owning view. needed for isOnView() method
+ View const* const mpParentView;
+
+public:
+ /** Create a new layer
+
+ @param pCanvas
+ Sprite canvas to create the layer on
+
+ @param rTransform
+ Initial overall canvas transformation
+
+ @param rLayerBounds
+ Initial layer bounds, in view coordinate system
+ */
+ SlideViewLayer( const cppcanvas::SpriteCanvasSharedPtr& pCanvas,
+ const basegfx::B2DHomMatrix& rTransform,
+ const basegfx::B2DRange& rLayerBounds,
+ const basegfx::B2DSize& rUserSize,
+ View const* const pParentView) :
+ maSpriteContainer(),
+ maLayerBounds(rLayerBounds),
+ maLayerBoundsPixel(),
+ maClip(),
+ maUserSize(rUserSize),
+ maTransformation(rTransform),
+ mpSpriteCanvas(pCanvas),
+ mpSprite(),
+ mpOutputCanvas(),
+ mpParentView(pParentView)
+ {
+ }
+
+ void updateView( const basegfx::B2DHomMatrix& rMatrix,
+ const basegfx::B2DSize& rUserSize )
+ {
+ maTransformation = rMatrix;
+ maUserSize = rUserSize;
+
+ // limit layer bounds to visible screen
+ maLayerBounds.intersect( basegfx::B2DRange(0.0,
+ 0.0,
+ maUserSize.getX(),
+ maUserSize.getY()) );
+
+ basegfx::B2IRange const& rNewLayerPixel(
+ getLayerBoundsPixel(maLayerBounds,
+ maTransformation) );
+ if( rNewLayerPixel != maLayerBoundsPixel )
+ {
+ // re-gen sprite with new size
+ mpOutputCanvas.reset();
+ mpSprite.reset();
+ }
+ }
+
+private:
+ // ViewLayer interface
+ // ----------------------------------------------
+
+ virtual cppcanvas::CustomSpriteSharedPtr createSprite(
+ const ::basegfx::B2DSize& rSpriteSizePixel,
+ double nPriority ) const
+ {
+ cppcanvas::CustomSpriteSharedPtr pSprite(
+ mpSpriteCanvas->createCustomSprite( rSpriteSizePixel ) );
+
+ maSpriteContainer.addSprite( pSprite,
+ nPriority );
+
+ return pSprite;
+ }
+
+ virtual void setPriority( const basegfx::B1DRange& rRange )
+ {
+ OSL_ENSURE( !rRange.isEmpty() &&
+ rRange.getMinimum() >= 1.0,
+ "SlideViewLayer::setPriority(): prio MUST be larger than 1.0 (because "
+ "the background layer already lies there)" );
+
+ maSpriteContainer.setLayerPriority( rRange );
+
+ if( mpSprite )
+ mpSprite->setPriority( rRange.getMinimum() );
+ }
+
+ virtual basegfx::B2DHomMatrix getTransformation() const
+ {
+ // Offset given transformation by left, top border of given
+ // range (after transformation through given transformation)
+ basegfx::B2DRectangle aTmpRect;
+ canvas::tools::calcTransformedRectBounds( aTmpRect,
+ maLayerBounds,
+ maTransformation );
+
+ basegfx::B2DHomMatrix aMatrix( maTransformation );
+
+ // Add translation according to the origin of aTmpRect. Ignore the
+ // translation when aTmpRect was not properly initialized.
+ if ( ! aTmpRect.isEmpty())
+ {
+ aMatrix.translate( -basegfx::fround(aTmpRect.getMinX()),
+ -basegfx::fround(aTmpRect.getMinY()) );
+ }
+
+ return aMatrix;
+ }
+
+ virtual basegfx::B2DHomMatrix getSpriteTransformation() const
+ {
+ return maTransformation;
+ }
+
+ virtual void clear() const
+ {
+ // keep layer clip
+ clearRect(getCanvas()->clone(),
+ maLayerBoundsPixel);
+ }
+
+ virtual void clearAll() const
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas( getCanvas()->clone() );
+
+ // clear layer clip, to clear whole area
+ pCanvas->setClip();
+
+ clearRect(pCanvas,
+ maLayerBoundsPixel);
+ }
+
+ virtual bool isOnView(boost::shared_ptr<View> const& rView) const
+ {
+ return rView.get() == mpParentView;
+ }
+
+ virtual cppcanvas::CanvasSharedPtr getCanvas() const
+ {
+ if( !mpOutputCanvas )
+ {
+ if( !mpSprite )
+ {
+ maLayerBoundsPixel = getLayerBoundsPixel(maLayerBounds,
+ maTransformation);
+
+ // HACK: ensure at least 1x1 pixel size. clients might
+ // need an actual canvas (e.g. for bound rect
+ // calculations) without rendering anything. Better
+ // solution: introduce something like a reference
+ // canvas for ViewLayers, which is always available.
+ if( maLayerBoundsPixel.isEmpty() )
+ maLayerBoundsPixel = basegfx::B2IRange(0,0,1,1);
+
+ const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
+ mpSprite = mpSpriteCanvas->createCustomSprite(
+ basegfx::B2DVector(sal::static_int_cast<sal_Int32>(rSpriteSize.getX()),
+ sal::static_int_cast<sal_Int32>(rSpriteSize.getY())) );
+
+ mpSprite->setPriority(
+ maSpriteContainer.getLayerPriority().getMinimum() );
+
+#if defined(VERBOSE) && defined(DBG_UTIL)
+ mpSprite->movePixel(
+ basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) +
+ basegfx::B2DPoint(10,10) );
+
+ mpSprite->setAlpha(0.5);
+#else
+ mpSprite->movePixel(
+ basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) );
+
+ mpSprite->setAlpha(1.0);
+#endif
+ mpSprite->show();
+ }
+
+ ENSURE_OR_THROW( mpSprite,
+ "SlideViewLayer::getCanvas(): no layer sprite" );
+
+ mpOutputCanvas = mpSprite->getContentCanvas();
+
+ ENSURE_OR_THROW( mpOutputCanvas,
+ "SlideViewLayer::getCanvas(): sprite doesn't yield a canvas" );
+
+ // new canvas retrieved - setup transformation and clip
+ mpOutputCanvas->setTransformation( getTransformation() );
+ mpOutputCanvas->setClip(
+ createClipPolygon( maClip,
+ mpOutputCanvas,
+ maUserSize ));
+ }
+
+ return mpOutputCanvas;
+ }
+
+ virtual void setClip( const basegfx::B2DPolyPolygon& rClip )
+ {
+ basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
+
+ if( aNewClip != maClip )
+ {
+ maClip = aNewClip;
+
+ if(mpOutputCanvas )
+ mpOutputCanvas->setClip(
+ createClipPolygon( maClip,
+ mpOutputCanvas,
+ maUserSize ));
+ }
+ }
+
+ virtual bool resize( const ::basegfx::B2DRange& rArea )
+ {
+ const bool bRet( maLayerBounds != rArea );
+ maLayerBounds = rArea;
+ updateView( maTransformation,
+ maUserSize );
+
+ return bRet;
+ }
+};
+
+
+// ---------------------------------------------------------
+
+typedef cppu::WeakComponentImplHelper2<
+ ::com::sun::star::util::XModifyListener,
+ ::com::sun::star::awt::XPaintListener> SlideViewBase;
+
+/** SlideView class
+
+ This class implements the View interface, encapsulating
+ <em>one</em> view a slideshow is displayed on.
+ */
+class SlideView : private cppu::BaseMutex,
+ public SlideViewBase,
+ public UnoView
+{
+public:
+ SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
+ EventQueue& rEventQueue,
+ EventMultiplexer& rEventMultiplexer );
+ void updateCanvas();
+
+private:
+ // View:
+ virtual ViewLayerSharedPtr createViewLayer( const basegfx::B2DRange& rLayerBounds ) const;
+ virtual bool updateScreen() const;
+ virtual bool paintScreen() const;
+ virtual void setViewSize( const ::basegfx::B2DSize& );
+ virtual void setCursorShape( sal_Int16 nPointerShape );
+
+ // ViewLayer interface
+ virtual bool isOnView(boost::shared_ptr<View> const& rView) const;
+ virtual void clear() const;
+ virtual void clearAll() const;
+ virtual cppcanvas::CanvasSharedPtr getCanvas() const;
+ virtual cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& rSpriteSizePixel,
+ double nPriority ) const;
+ virtual void setPriority( const basegfx::B1DRange& rRange );
+ virtual ::basegfx::B2DHomMatrix getTransformation() const;
+ virtual basegfx::B2DHomMatrix getSpriteTransformation() const;
+ virtual void setClip( const ::basegfx::B2DPolyPolygon& rClip );
+ virtual bool resize( const ::basegfx::B2DRange& rArea );
+
+ // UnoView:
+ virtual void _dispose();
+ virtual uno::Reference<presentation::XSlideShowView> getUnoView()const;
+ virtual void setIsSoundEnabled (const bool bValue);
+ virtual bool isSoundEnabled (void) const;
+
+ // XEventListener:
+ virtual void SAL_CALL disposing( lang::EventObject const& evt )
+ throw (uno::RuntimeException);
+ // XModifyListener:
+ virtual void SAL_CALL modified( const lang::EventObject& aEvent )
+ throw (uno::RuntimeException);
+ // XPaintListener:
+ virtual void SAL_CALL windowPaint( const awt::PaintEvent& e )
+ throw (uno::RuntimeException);
+
+ // WeakComponentImplHelperBase:
+ virtual void SAL_CALL disposing();
+
+ void updateClip();
+
+private:
+ typedef std::vector< boost::weak_ptr<SlideViewLayer> > ViewLayerVector;
+
+ /// Prune viewlayers from deceased ones, optionally update them
+ void pruneLayers( bool bWithViewLayerUpdate=false ) const;
+
+ /** Max fill level of maViewLayers, before we try to prune it from
+ deceased layers
+ */
+ enum{ LAYER_ULLAGE=8 };
+
+ uno::Reference<presentation::XSlideShowView> mxView;
+ cppcanvas::SpriteCanvasSharedPtr mpCanvas;
+
+ EventMultiplexer& mrEventMultiplexer;
+ EventQueue& mrEventQueue;
+
+ mutable LayerSpriteContainer maSprites;
+ mutable ViewLayerVector maViewLayers;
+
+ basegfx::B2DPolyPolygon maClip;
+
+ basegfx::B2DHomMatrix maViewTransform;
+ basegfx::B2DSize maUserSize;
+ bool mbIsSoundEnabled;
+};
+
+
+SlideView::SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
+ EventQueue& rEventQueue,
+ EventMultiplexer& rEventMultiplexer ) :
+ SlideViewBase( m_aMutex ),
+ mxView( xView ),
+ mpCanvas(),
+ mrEventMultiplexer( rEventMultiplexer ),
+ mrEventQueue( rEventQueue ),
+ maSprites(),
+ maViewLayers(),
+ maClip(),
+ maViewTransform(),
+ maUserSize( 1.0, 1.0 ), // default size: one-by-one rectangle
+ mbIsSoundEnabled(true)
+{
+ // take care not constructing any UNO references to this _inside_
+ // ctor, shift that code to createSlideView()!
+ ENSURE_OR_THROW( mxView.is(),
+ "SlideView::SlideView(): Invalid view" );
+
+ mpCanvas = cppcanvas::VCLFactory::getInstance().createSpriteCanvas(
+ xView->getCanvas() );
+ ENSURE_OR_THROW( mpCanvas,
+ "Could not create cppcanvas" );
+
+ geometry::AffineMatrix2D aViewTransform(
+ xView->getTransformation() );
+
+ if( basegfx::fTools::equalZero(
+ basegfx::B2DVector(aViewTransform.m00,
+ aViewTransform.m10).getLength()) ||
+ basegfx::fTools::equalZero(
+ basegfx::B2DVector(aViewTransform.m01,
+ aViewTransform.m11).getLength()) )
+ {
+ OSL_FAIL( "SlideView::SlideView(): Singular matrix!" );
+
+ canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
+ }
+
+ basegfx::unotools::homMatrixFromAffineMatrix(
+ maViewTransform, aViewTransform );
+
+ // once and forever: set fixed prio to this 'layer' (we're always
+ // the background layer)
+ maSprites.setLayerPriority( basegfx::B1DRange(0.0,1.0) );
+}
+
+void SlideView::disposing()
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ maViewLayers.clear();
+ maSprites.clear();
+ mpCanvas.reset();
+
+ // additionally, also de-register from XSlideShowView
+ if (mxView.is())
+ {
+ mxView->removeTransformationChangedListener( this );
+ mxView->removePaintListener( this );
+ mxView.clear();
+ }
+}
+
+ViewLayerSharedPtr SlideView::createViewLayer( const basegfx::B2DRange& rLayerBounds ) const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ ENSURE_OR_THROW( mpCanvas,
+ "SlideView::createViewLayer(): Disposed" );
+
+ const std::size_t nNumLayers( maViewLayers.size() );
+
+ // avoid filling up layer vector with lots of deceased layer weak
+ // ptrs
+ if( nNumLayers > LAYER_ULLAGE )
+ pruneLayers();
+
+ boost::shared_ptr<SlideViewLayer> pViewLayer( new SlideViewLayer(mpCanvas,
+ getTransformation(),
+ rLayerBounds,
+ maUserSize,
+ this) );
+ maViewLayers.push_back( pViewLayer );
+
+ return pViewLayer;
+}
+
+bool SlideView::updateScreen() const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ ENSURE_OR_RETURN_FALSE( mpCanvas.get(),
+ "SlideView::updateScreen(): Disposed" );
+
+ return mpCanvas->updateScreen( false );
+}
+
+bool SlideView::paintScreen() const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ ENSURE_OR_RETURN_FALSE( mpCanvas.get(),
+ "SlideView::paintScreen(): Disposed" );
+
+ return mpCanvas->updateScreen( true );
+}
+
+void SlideView::clear() const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ OSL_ENSURE( mxView.is() && mpCanvas,
+ "SlideView::clear(): Disposed" );
+ if( !mxView.is() || !mpCanvas )
+ return;
+
+ // keep layer clip
+ clearRect(getCanvas()->clone(),
+ getLayerBoundsPixel(
+ basegfx::B2DRange(0,0,
+ maUserSize.getX(),
+ maUserSize.getY()),
+ getTransformation()));
+}
+
+void SlideView::clearAll() const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ OSL_ENSURE( mxView.is() && mpCanvas,
+ "SlideView::clear(): Disposed" );
+ if( !mxView.is() || !mpCanvas )
+ return;
+
+ // clear whole view
+ mxView->clear();
+}
+
+void SlideView::setViewSize( const basegfx::B2DSize& rSize )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ maUserSize = rSize;
+ updateCanvas();
+}
+
+void SlideView::setCursorShape( sal_Int16 nPointerShape )
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (mxView.is())
+ mxView->setMouseCursor( nPointerShape );
+}
+
+bool SlideView::isOnView(boost::shared_ptr<View> const& rView) const
+{
+ return rView.get() == this;
+}
+
+cppcanvas::CanvasSharedPtr SlideView::getCanvas() const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ ENSURE_OR_THROW( mpCanvas,
+ "SlideView::getCanvas(): Disposed" );
+
+ return mpCanvas;
+}
+
+cppcanvas::CustomSpriteSharedPtr SlideView::createSprite(
+ const basegfx::B2DSize& rSpriteSizePixel,
+ double nPriority ) const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ ENSURE_OR_THROW( mpCanvas, "SlideView::createSprite(): Disposed" );
+
+ cppcanvas::CustomSpriteSharedPtr pSprite(
+ mpCanvas->createCustomSprite( rSpriteSizePixel ) );
+
+ maSprites.addSprite( pSprite,
+ nPriority );
+
+ return pSprite;
+}
+
+void SlideView::setPriority( const basegfx::B1DRange& /*rRange*/ )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ OSL_FAIL( "SlideView::setPriority() is a NOOP for slide view - "
+ "content will always be shown in the background" );
+}
+
+basegfx::B2DHomMatrix SlideView::getTransformation() const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ basegfx::B2DHomMatrix aMatrix;
+ aMatrix.scale( 1.0/maUserSize.getX(), 1.0/maUserSize.getY() );
+
+ return maViewTransform * aMatrix;
+}
+
+basegfx::B2DHomMatrix SlideView::getSpriteTransformation() const
+{
+ return getTransformation();
+}
+
+void SlideView::setClip( const basegfx::B2DPolyPolygon& rClip )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
+
+ if( aNewClip != maClip )
+ {
+ maClip = aNewClip;
+
+ updateClip();
+ }
+}
+
+bool SlideView::resize( const ::basegfx::B2DRange& /*rArea*/ )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ OSL_FAIL( "SlideView::resize(): ignored for the View, can't change size "
+ "effectively, anyway" );
+
+ return false;
+}
+
+uno::Reference<presentation::XSlideShowView> SlideView::getUnoView() const
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ return mxView;
+}
+
+void SlideView::setIsSoundEnabled (const bool bValue)
+{
+ mbIsSoundEnabled = bValue;
+}
+
+bool SlideView::isSoundEnabled (void) const
+{
+ return mbIsSoundEnabled;
+}
+
+void SlideView::_dispose()
+{
+ dispose();
+}
+
+// XEventListener
+void SlideView::disposing( lang::EventObject const& evt )
+ throw (uno::RuntimeException)
+{
+ (void)evt;
+
+ // no deregistration necessary anymore, XView has left:
+ osl::MutexGuard const guard( m_aMutex );
+
+ if (mxView.is())
+ {
+ OSL_ASSERT( evt.Source == mxView );
+ mxView.clear();
+ }
+
+ dispose();
+}
+
+// XModifyListener
+void SlideView::modified( const lang::EventObject& /*aEvent*/ )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard const guard( m_aMutex );
+
+ OSL_ENSURE( mxView.is(), "SlideView::modified(): "
+ "Disposed, but event received from XSlideShowView?!");
+
+ if( !mxView.is() )
+ return;
+
+ geometry::AffineMatrix2D aViewTransform(
+ mxView->getTransformation() );
+
+ if( basegfx::fTools::equalZero(
+ basegfx::B2DVector(aViewTransform.m00,
+ aViewTransform.m10).getLength()) ||
+ basegfx::fTools::equalZero(
+ basegfx::B2DVector(aViewTransform.m01,
+ aViewTransform.m11).getLength()) )
+ {
+ OSL_FAIL( "SlideView::modified(): Singular matrix!" );
+
+ canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
+ }
+
+ // view transformation really changed?
+ basegfx::B2DHomMatrix aNewTransform;
+ basegfx::unotools::homMatrixFromAffineMatrix(
+ aNewTransform,
+ aViewTransform );
+
+ if( aNewTransform == maViewTransform )
+ return; // No change, nothing to do
+
+ maViewTransform = aNewTransform;
+
+ updateCanvas();
+
+ // notify view change. Don't call EventMultiplexer directly, this
+ // might not be the main thread!
+ mrEventQueue.addEvent(
+ makeEvent( boost::bind( (bool (EventMultiplexer::*)(
+ const uno::Reference<presentation::XSlideShowView>&))
+ &EventMultiplexer::notifyViewChanged,
+ boost::ref(mrEventMultiplexer), mxView ),
+ "EventMultiplexer::notifyViewChanged"));
+}
+
+// XPaintListener
+void SlideView::windowPaint( const awt::PaintEvent& /*e*/ )
+ throw (uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ OSL_ENSURE( mxView.is() && mpCanvas, "Disposed, but event received?!" );
+
+ // notify view clobbering. Don't call EventMultiplexer directly,
+ // this might not be the main thread!
+ mrEventQueue.addEvent(
+ makeEvent( boost::bind( &EventMultiplexer::notifyViewClobbered,
+ boost::ref(mrEventMultiplexer), mxView ),
+ "EventMultiplexer::notifyViewClobbered") );
+}
+
+void SlideView::updateCanvas()
+{
+ OSL_ENSURE( mpCanvas,
+ "SlideView::updateCanvasTransform(): Disposed" );
+
+ if( !mpCanvas || !mxView.is())
+ return;
+
+ mpCanvas->clear(); // this is unnecessary, strictly speaking. but
+ // it makes the SlideView behave exactly like a
+ // sprite-based SlideViewLayer, because those
+ // are created from scratch after a resize
+ clearAll();
+ mpCanvas->setTransformation( getTransformation() );
+ mpCanvas->setClip(
+ createClipPolygon( maClip,
+ mpCanvas,
+ maUserSize ));
+
+ // forward update to viewlayers
+ pruneLayers( true );
+}
+
+void SlideView::updateClip()
+{
+ OSL_ENSURE( mpCanvas,
+ "SlideView::updateClip(): Disposed" );
+
+ if( !mpCanvas )
+ return;
+
+ mpCanvas->setClip(
+ createClipPolygon( maClip,
+ mpCanvas,
+ maUserSize ));
+
+ pruneLayers( false );
+}
+
+void SlideView::pruneLayers( bool bWithViewLayerUpdate ) const
+{
+ ViewLayerVector aValidLayers;
+
+ const basegfx::B2DHomMatrix& rCurrTransform(
+ getTransformation() );
+
+ // check all layers for validity, and retain only the live ones
+ ViewLayerVector::const_iterator aCurr( maViewLayers.begin() );
+ const ViewLayerVector::const_iterator aEnd( maViewLayers.end() );
+ while( aCurr != aEnd )
+ {
+ boost::shared_ptr< SlideViewLayer > pCurrLayer( aCurr->lock() );
+
+ if( pCurrLayer )
+ {
+ aValidLayers.push_back( pCurrLayer );
+
+ if( bWithViewLayerUpdate )
+ pCurrLayer->updateView( rCurrTransform,
+ maUserSize );
+ }
+
+ ++aCurr;
+ }
+
+ // replace layer list with pruned one
+ maViewLayers.swap( aValidLayers );
+}
+
+} // anonymous namespace
+
+UnoViewSharedPtr createSlideView( uno::Reference< presentation::XSlideShowView> const& xView,
+ EventQueue& rEventQueue,
+ EventMultiplexer& rEventMultiplexer )
+{
+ boost::shared_ptr<SlideView> const that(
+ comphelper::make_shared_from_UNO(
+ new SlideView(xView,
+ rEventQueue,
+ rEventMultiplexer)));
+
+ // register listeners with XSlideShowView
+ xView->addTransformationChangedListener( that.get() );
+ xView->addPaintListener( that.get() );
+
+ // set new transformation
+ that->updateCanvas();
+
+ return that;
+}
+
+} // namespace internal
+} // namespace slideshow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/smilfunctionparser.cxx b/slideshow/source/engine/smilfunctionparser.cxx
new file mode 100644
index 000000000000..a49f88d061ba
--- /dev/null
+++ b/slideshow/source/engine/smilfunctionparser.cxx
@@ -0,0 +1,640 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <rtl/math.hxx>
+
+#include <smilfunctionparser.hxx>
+#include <expressionnodefactory.hxx>
+
+#include <rtl/ustring.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+
+// Makes parser a static resource,
+// we're synchronized externally.
+// But watch out, the parser might have
+// state not visible to this code!
+#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
+#if defined(VERBOSE) && defined(DBG_UTIL)
+#include <typeinfo>
+#define BOOST_SPIRIT_DEBUG
+#endif
+#include <boost/spirit/include/classic_core.hpp>
+
+#if OSL_DEBUG_LEVEL > 0
+#include <iostream>
+#endif
+#include <functional>
+#include <algorithm>
+#include <stack>
+
+
+
+/* Implementation of SmilFunctionParser class */
+
+namespace slideshow
+{
+ namespace internal
+ {
+ namespace
+ {
+ typedef const sal_Char* StringIteratorT;
+
+ struct ParserContext
+ {
+ typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
+
+ // stores a stack of not-yet-evaluated operands. This is used
+ // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
+ // arguments from. If all arguments to an operator are constant,
+ // the operator pushes a precalculated result on the stack, and
+ // a composite ExpressionNode otherwise.
+ OperandStack maOperandStack;
+
+ // bounds of the shape this expression is associated with
+ ::basegfx::B2DRectangle maShapeBounds;
+
+ // when true, enable usage of time-dependent variable '$'
+ // in expressions
+ bool mbParseAnimationFunction;
+ };
+
+ typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
+
+
+ template< typename Generator > class ShapeBoundsFunctor
+ {
+ public:
+ ShapeBoundsFunctor( Generator aGenerator,
+ const ParserContextSharedPtr& rContext ) :
+ maGenerator( aGenerator ),
+ mpContext( rContext )
+ {
+ ENSURE_OR_THROW( mpContext,
+ "ShapeBoundsFunctor::ShapeBoundsFunctor(): Invalid context" );
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ mpContext->maOperandStack.push(
+ ExpressionNodeFactory::createConstantValueExpression(
+ maGenerator( mpContext->maShapeBounds ) ) );
+ }
+
+ private:
+ Generator maGenerator;
+ ParserContextSharedPtr mpContext;
+ };
+
+ template< typename Generator > ShapeBoundsFunctor< Generator >
+ makeShapeBoundsFunctor( const Generator& rGenerator,
+ const ParserContextSharedPtr& rContext )
+ {
+ return ShapeBoundsFunctor<Generator>(rGenerator, rContext);
+ }
+
+ /** Generate apriori constant value
+ */
+ class ConstantFunctor
+ {
+ public:
+ ConstantFunctor( double rValue,
+ const ParserContextSharedPtr& rContext ) :
+ mnValue( rValue ),
+ mpContext( rContext )
+ {
+ ENSURE_OR_THROW( mpContext,
+ "ConstantFunctor::ConstantFunctor(): Invalid context" );
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ mpContext->maOperandStack.push(
+ ExpressionNodeFactory::createConstantValueExpression( mnValue ) );
+ }
+
+ private:
+ const double mnValue;
+ ParserContextSharedPtr mpContext;
+ };
+
+ /** Generate parse-dependent-but-then-constant value
+ */
+ class DoubleConstantFunctor
+ {
+ public:
+ DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) :
+ mpContext( rContext )
+ {
+ ENSURE_OR_THROW( mpContext,
+ "DoubleConstantFunctor::DoubleConstantFunctor(): Invalid context" );
+ }
+
+ void operator()( double n ) const
+ {
+ // push constant value expression to the stack
+ mpContext->maOperandStack.push(
+ ExpressionNodeFactory::createConstantValueExpression( n ) );
+ }
+
+ private:
+ ParserContextSharedPtr mpContext;
+ };
+
+ /** Generate special t value expression node
+ */
+ class ValueTFunctor
+ {
+ public:
+ ValueTFunctor( const ParserContextSharedPtr& rContext ) :
+ mpContext( rContext )
+ {
+ ENSURE_OR_THROW( mpContext,
+ "ValueTFunctor::ValueTFunctor(): Invalid context" );
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ if( !mpContext->mbParseAnimationFunction )
+ {
+ OSL_FAIL( "ValueTFunctor::operator(): variable encountered, but we're not parsing a function here" );
+ throw ParseError();
+ }
+
+ // push special t value expression to the stack
+ mpContext->maOperandStack.push(
+ ExpressionNodeFactory::createValueTExpression() );
+ }
+
+ private:
+ ParserContextSharedPtr mpContext;
+ };
+
+ template< typename Functor > class UnaryFunctionFunctor
+ {
+ private:
+ /** ExpressionNode implementation for unary
+ function over one ExpressionNode
+ */
+ class UnaryFunctionExpression : public ExpressionNode
+ {
+ public:
+ UnaryFunctionExpression( const Functor& rFunctor,
+ const ExpressionNodeSharedPtr& rArg ) :
+ maFunctor( rFunctor ),
+ mpArg( rArg )
+ {
+ }
+
+ virtual double operator()( double t ) const
+ {
+ return maFunctor( (*mpArg)(t) );
+ }
+
+ virtual bool isConstant() const
+ {
+ return mpArg->isConstant();
+ }
+
+ private:
+ Functor maFunctor;
+ ExpressionNodeSharedPtr mpArg;
+ };
+
+ public:
+ UnaryFunctionFunctor( const Functor& rFunctor,
+ const ParserContextSharedPtr& rContext ) :
+ maFunctor( rFunctor ),
+ mpContext( rContext )
+ {
+ ENSURE_OR_THROW( mpContext,
+ "UnaryFunctionFunctor::UnaryFunctionFunctor(): Invalid context" );
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
+
+ if( rNodeStack.size() < 1 )
+ throw ParseError( "Not enough arguments for unary operator" );
+
+ // retrieve arguments
+ ExpressionNodeSharedPtr pArg( rNodeStack.top() );
+ rNodeStack.pop();
+
+ // check for constness
+ if( pArg->isConstant() )
+ {
+ rNodeStack.push(
+ ExpressionNodeFactory::createConstantValueExpression(
+ maFunctor( (*pArg)(0.0) ) ) );
+ }
+ else
+ {
+ // push complex node, that calcs the value on demand
+ rNodeStack.push(
+ ExpressionNodeSharedPtr(
+ new UnaryFunctionExpression(
+ maFunctor,
+ pArg ) ) );
+ }
+ }
+
+ private:
+ Functor maFunctor;
+ ParserContextSharedPtr mpContext;
+ };
+
+ // TODO(Q2): Refactor makeUnaryFunctionFunctor,
+ // makeBinaryFunctionFunctor and the whole
+ // ExpressionNodeFactory, to use a generic
+ // makeFunctionFunctor template, which is overloaded for
+ // unary, binary, ternary, etc. function pointers.
+ template< typename Functor > UnaryFunctionFunctor<Functor>
+ makeUnaryFunctionFunctor( const Functor& rFunctor,
+ const ParserContextSharedPtr& rContext )
+ {
+ return UnaryFunctionFunctor<Functor>( rFunctor, rContext );
+ }
+
+ // MSVC has problems instantiating above template function with plain function
+ // pointers (doesn't like the const reference there). Thus, provide it with
+ // a dedicated overload here.
+ UnaryFunctionFunctor< double (*)(double) >
+ makeUnaryFunctionFunctor( double (*pFunc)(double),
+ const ParserContextSharedPtr& rContext )
+ {
+ return UnaryFunctionFunctor< double (*)(double) >( pFunc, rContext );
+ }
+
+ /** Implements a binary function over two ExpressionNodes
+
+ @tpl Generator
+ Generator functor, to generate an ExpressionNode of
+ appropriate type
+
+ */
+ template< class Generator > class BinaryFunctionFunctor
+ {
+ public:
+ BinaryFunctionFunctor( const Generator& rGenerator,
+ const ParserContextSharedPtr& rContext ) :
+ maGenerator( rGenerator ),
+ mpContext( rContext )
+ {
+ ENSURE_OR_THROW( mpContext,
+ "BinaryFunctionFunctor::BinaryFunctionFunctor(): Invalid context" );
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
+
+ if( rNodeStack.size() < 2 )
+ throw ParseError( "Not enough arguments for binary operator" );
+
+ // retrieve arguments
+ ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
+ rNodeStack.pop();
+ ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
+ rNodeStack.pop();
+
+ // create combined ExpressionNode
+ ExpressionNodeSharedPtr pNode( maGenerator( pFirstArg,
+ pSecondArg ) );
+ // check for constness
+ if( pFirstArg->isConstant() &&
+ pSecondArg->isConstant() )
+ {
+ // call the operator() at pNode, store result
+ // in constant value ExpressionNode.
+ rNodeStack.push(
+ ExpressionNodeFactory::createConstantValueExpression(
+ (*pNode)( 0.0 ) ) );
+ }
+ else
+ {
+ // push complex node, that calcs the value on demand
+ rNodeStack.push( pNode );
+ }
+ }
+
+ private:
+ Generator maGenerator;
+ ParserContextSharedPtr mpContext;
+ };
+
+ template< typename Generator > BinaryFunctionFunctor<Generator>
+ makeBinaryFunctionFunctor( const Generator& rGenerator,
+ const ParserContextSharedPtr& rContext )
+ {
+ return BinaryFunctionFunctor<Generator>( rGenerator, rContext );
+ }
+
+
+ // Workaround for MSVC compiler anomaly (stack trashing)
+ //
+ // The default ureal_parser_policies implementation of parse_exp
+ // triggers a really weird error in MSVC7 (Version 13.00.9466), in
+ // that the real_parser_impl::parse_main() call of parse_exp()
+ // overwrites the frame pointer _on the stack_ (EBP of the calling
+ // function gets overwritten while lying on the stack).
+ //
+ // For the time being, our parser thus can only read the 1.0E10
+ // notation, not the 1.0e10 one.
+ //
+ // TODO(F1): Also handle the 1.0e10 case here.
+ template< typename T > struct custom_real_parser_policies : public ::boost::spirit::ureal_parser_policies<T>
+ {
+ template< typename ScannerT >
+ static typename ::boost::spirit::parser_result< ::boost::spirit::chlit<>, ScannerT >::type
+ parse_exp(ScannerT& scan)
+ {
+ // as_lower_d somehow breaks MSVC7
+ return ::boost::spirit::ch_p('E').parse(scan);
+ }
+ };
+
+ /* This class implements the following grammar (more or
+ less literally written down below, only slightly
+ obfuscated by the parser actions):
+
+ identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height'
+
+ function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log'
+
+ basic_expression =
+ number |
+ identifier |
+ function '(' additive_expression ')' |
+ '(' additive_expression ')'
+
+ unary_expression =
+ '-' basic_expression |
+ basic_expression
+
+ multiplicative_expression =
+ unary_expression ( ( '*' unary_expression )* |
+ ( '/' unary_expression )* )
+
+ additive_expression =
+ multiplicative_expression ( ( '+' multiplicative_expression )* |
+ ( '-' multiplicative_expression )* )
+
+ */
+ class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
+ {
+ public:
+ /** Create an arithmetic expression grammar
+
+ @param rParserContext
+ Contains context info for the parser
+ */
+ ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
+ mpParserContext( rParserContext )
+ {
+ }
+
+ template< typename ScannerT > class definition
+ {
+ public:
+ // grammar definition
+ definition( const ExpressionGrammar& self )
+ {
+ using ::boost::spirit::str_p;
+ using ::boost::spirit::real_parser;
+
+ identifier =
+ str_p( "$" )[ ValueTFunctor( self.getContext()) ]
+ | str_p( "pi" )[ ConstantFunctor(M_PI, self.getContext()) ]
+ | str_p( "e" )[ ConstantFunctor(M_E, self.getContext()) ]
+ | str_p( "x" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getCenterX),self.getContext()) ]
+ | str_p( "y" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getCenterY),self.getContext()) ]
+ | str_p( "width" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getWidth), self.getContext()) ]
+ | str_p( "height" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getHeight), self.getContext()) ]
+ ;
+
+ unaryFunction =
+ (str_p( "abs" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&fabs, self.getContext()) ]
+ | (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&sqrt, self.getContext()) ]
+ | (str_p( "sin" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&sin, self.getContext()) ]
+ | (str_p( "cos" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&cos, self.getContext()) ]
+ | (str_p( "tan" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&tan, self.getContext()) ]
+ | (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&atan, self.getContext()) ]
+ | (str_p( "acos" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&acos, self.getContext()) ]
+ | (str_p( "asin" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&asin, self.getContext()) ]
+ | (str_p( "exp" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&exp, self.getContext()) ]
+ | (str_p( "log" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&log, self.getContext()) ]
+ ;
+
+ binaryFunction =
+ (str_p( "min" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMinExpression, self.getContext()) ]
+ | (str_p( "max" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMaxExpression, self.getContext()) ]
+ ;
+
+ basicExpression =
+ real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ]
+ | identifier
+ | unaryFunction
+ | binaryFunction
+ | '(' >> additiveExpression >> ')'
+ ;
+
+ unaryExpression =
+ ('-' >> basicExpression)[ makeUnaryFunctionFunctor(::std::negate<double>(), self.getContext()) ]
+ | basicExpression
+ ;
+
+ multiplicativeExpression =
+ unaryExpression
+ >> *( ('*' >> unaryExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMultipliesExpression, self.getContext()) ]
+ | ('/' >> unaryExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createDividesExpression, self.getContext()) ]
+ )
+ ;
+
+ additiveExpression =
+ multiplicativeExpression
+ >> *( ('+' >> multiplicativeExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createPlusExpression, self.getContext()) ]
+ | ('-' >> multiplicativeExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMinusExpression, self.getContext()) ]
+ )
+ ;
+
+ BOOST_SPIRIT_DEBUG_RULE(additiveExpression);
+ BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression);
+ BOOST_SPIRIT_DEBUG_RULE(unaryExpression);
+ BOOST_SPIRIT_DEBUG_RULE(basicExpression);
+ BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
+ BOOST_SPIRIT_DEBUG_RULE(binaryFunction);
+ BOOST_SPIRIT_DEBUG_RULE(identifier);
+ }
+
+ const ::boost::spirit::rule< ScannerT >& start() const
+ {
+ return additiveExpression;
+ }
+
+ private:
+ // the constituents of the Spirit arithmetic expression grammar.
+ // For the sake of readability, without 'ma' prefix.
+ ::boost::spirit::rule< ScannerT > additiveExpression;
+ ::boost::spirit::rule< ScannerT > multiplicativeExpression;
+ ::boost::spirit::rule< ScannerT > unaryExpression;
+ ::boost::spirit::rule< ScannerT > basicExpression;
+ ::boost::spirit::rule< ScannerT > unaryFunction;
+ ::boost::spirit::rule< ScannerT > binaryFunction;
+ ::boost::spirit::rule< ScannerT > identifier;
+ };
+
+ const ParserContextSharedPtr& getContext() const
+ {
+ return mpParserContext;
+ }
+
+ private:
+ ParserContextSharedPtr mpParserContext; // might get modified during parsing
+ };
+
+#ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
+ const ParserContextSharedPtr& getParserContext()
+ {
+ static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
+
+ // clear node stack (since we reuse the static object, that's
+ // the whole point here)
+ while( !lcl_parserContext->maOperandStack.empty() )
+ lcl_parserContext->maOperandStack.pop();
+
+ return lcl_parserContext;
+ }
+#endif
+ }
+
+ ExpressionNodeSharedPtr SmilFunctionParser::parseSmilValue( const ::rtl::OUString& rSmilValue,
+ const ::basegfx::B2DRectangle& rRelativeShapeBounds )
+ {
+ // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
+ // gives better conversion robustness here (we might want to map space
+ // etc. to ASCII space here)
+ const ::rtl::OString& rAsciiSmilValue(
+ rtl::OUStringToOString( rSmilValue, RTL_TEXTENCODING_ASCII_US ) );
+
+ StringIteratorT aStart( rAsciiSmilValue.getStr() );
+ StringIteratorT aEnd( rAsciiSmilValue.getStr()+rAsciiSmilValue.getLength() );
+
+ ParserContextSharedPtr pContext;
+
+#ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
+ // static parser context, because the actual
+ // Spirit parser is also a static object
+ pContext = getParserContext();
+#else
+ pContext.reset( new ParserContext() );
+#endif
+
+ pContext->maShapeBounds = rRelativeShapeBounds;
+ pContext->mbParseAnimationFunction = false; // parse with '$' disabled
+
+
+ ExpressionGrammar aExpressionGrammer( pContext );
+ const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
+ ::boost::spirit::parse( aStart,
+ aEnd,
+ aExpressionGrammer,
+ ::boost::spirit::space_p ) );
+ OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
+
+ // input fully congested by the parser?
+ if( !aParseInfo.full )
+ throw ParseError( "SmilFunctionParser::parseSmilValue(): string not fully parseable" );
+
+ // parser's state stack now must contain exactly _one_ ExpressionNode,
+ // which represents our formula.
+ if( pContext->maOperandStack.size() != 1 )
+ throw ParseError( "SmilFunctionParser::parseSmilValue(): incomplete or empty expression" );
+
+ return pContext->maOperandStack.top();
+ }
+
+ ExpressionNodeSharedPtr SmilFunctionParser::parseSmilFunction( const ::rtl::OUString& rSmilFunction,
+ const ::basegfx::B2DRectangle& rRelativeShapeBounds )
+ {
+ // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
+ // gives better conversion robustness here (we might want to map space
+ // etc. to ASCII space here)
+ const ::rtl::OString& rAsciiSmilFunction(
+ rtl::OUStringToOString( rSmilFunction, RTL_TEXTENCODING_ASCII_US ) );
+
+ StringIteratorT aStart( rAsciiSmilFunction.getStr() );
+ StringIteratorT aEnd( rAsciiSmilFunction.getStr()+rAsciiSmilFunction.getLength() );
+
+ ParserContextSharedPtr pContext;
+
+#ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
+ // static parser context, because the actual
+ // Spirit parser is also a static object
+ pContext = getParserContext();
+#else
+ pContext.reset( new ParserContext() );
+#endif
+
+ pContext->maShapeBounds = rRelativeShapeBounds;
+ pContext->mbParseAnimationFunction = true; // parse with '$' enabled
+
+
+ ExpressionGrammar aExpressionGrammer( pContext );
+ const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
+ ::boost::spirit::parse( aStart,
+ aEnd,
+ aExpressionGrammer >> ::boost::spirit::end_p,
+ ::boost::spirit::space_p ) );
+ OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
+
+ // input fully congested by the parser?
+ if( !aParseInfo.full )
+ throw ParseError( "SmilFunctionParser::parseSmilFunction(): string not fully parseable" );
+
+ // parser's state stack now must contain exactly _one_ ExpressionNode,
+ // which represents our formula.
+ if( pContext->maOperandStack.size() != 1 )
+ throw ParseError( "SmilFunctionParser::parseSmilFunction(): incomplete or empty expression" );
+
+ return pContext->maOperandStack.top();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/soundplayer.cxx b/slideshow/source/engine/soundplayer.cxx
new file mode 100644
index 000000000000..fa68c1741528
--- /dev/null
+++ b/slideshow/source/engine/soundplayer.cxx
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/lang/XComponent.hdl>
+
+#include <tools/urlobj.hxx>
+
+#include <avmedia/mediawindow.hxx>
+
+#include "soundplayer.hxx"
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ // TODO(Q3): Move the whole SoundPlayer class to avmedia.
+
+ boost::shared_ptr<SoundPlayer> SoundPlayer::create(
+ EventMultiplexer & rEventMultiplexer,
+ const ::rtl::OUString& rSoundURL,
+ const uno::Reference< uno::XComponentContext>& rComponentContext )
+ {
+ boost::shared_ptr<SoundPlayer> pPlayer(
+ new SoundPlayer( rEventMultiplexer,
+ rSoundURL,
+ rComponentContext ) );
+ rEventMultiplexer.addPauseHandler( pPlayer );
+ pPlayer->mThis = pPlayer;
+ return pPlayer;
+ }
+
+ bool SoundPlayer::handlePause( bool bPauseShow )
+ {
+ return bPauseShow ? stopPlayback() : startPlayback();
+ }
+
+ void SoundPlayer::dispose()
+ {
+ if( mThis )
+ {
+ mrEventMultiplexer.removePauseHandler( mThis );
+ mThis.reset();
+ }
+
+ if( mxPlayer.is() )
+ {
+ mxPlayer->stop();
+ uno::Reference<lang::XComponent> xComponent(
+ mxPlayer, uno::UNO_QUERY );
+ if( xComponent.is() )
+ xComponent->dispose();
+ mxPlayer.clear();
+ }
+ }
+
+ SoundPlayer::SoundPlayer(
+ EventMultiplexer & rEventMultiplexer,
+ const ::rtl::OUString& rSoundURL,
+ const uno::Reference< uno::XComponentContext>& rComponentContext )
+ : mrEventMultiplexer(rEventMultiplexer),
+ mThis(),
+ mxPlayer()
+ {
+ ENSURE_OR_THROW( rComponentContext.is(),
+ "SoundPlayer::SoundPlayer(): Invalid component context" );
+
+ try
+ {
+ const INetURLObject aURL( rSoundURL );
+ mxPlayer.set( avmedia::MediaWindow::createPlayer(
+ aURL.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS ) ),
+ uno::UNO_QUERY);
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ if( !mxPlayer.is() )
+ throw lang::NoSupportException(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "No sound support for ") ) + rSoundURL,
+ uno::Reference<uno::XInterface>() );
+ }
+
+ SoundPlayer::~SoundPlayer()
+ {
+ try
+ {
+ dispose();
+ }
+ catch (uno::Exception &) {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ double SoundPlayer::getDuration() const
+ {
+ if( !mxPlayer.is() )
+ return 0.0;
+
+ const double nDuration( mxPlayer->getDuration() );
+ if( mxPlayer->isPlaying() )
+ return ::std::max( 0.0,
+ nDuration - mxPlayer->getMediaTime() );
+ else
+ return nDuration;
+ }
+
+ bool SoundPlayer::startPlayback()
+ {
+ if( !mxPlayer.is() )
+ return false;
+
+ if( mxPlayer->isPlaying() )
+ mxPlayer->stop();
+
+ mxPlayer->start();
+ return true;
+ }
+
+ bool SoundPlayer::stopPlayback()
+ {
+ if( mxPlayer.is() )
+ mxPlayer->stop();
+
+ return true;
+ }
+
+ void SoundPlayer::setPlaybackLoop( bool bLoop )
+ {
+ if( mxPlayer.is() )
+ mxPlayer->setPlaybackLoop( bLoop );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/sp_debug.cxx b/slideshow/source/engine/sp_debug.cxx
new file mode 100644
index 000000000000..c80a3634167d
--- /dev/null
+++ b/slideshow/source/engine/sp_debug.cxx
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+//
+// sp_collector.cpp
+//
+// Copyright (c) 2002, 2003 Peter Dimov
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+
+#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
+
+#include <boost/assert.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/detail/lightweight_mutex.hpp>
+#include <cstdlib>
+#include <map>
+#include <deque>
+#include <iostream>
+
+typedef std::map< void const *, std::pair<void *, size_t> > map_type;
+
+static map_type & get_map()
+{
+ static map_type m;
+ return m;
+}
+
+typedef boost::detail::lightweight_mutex mutex_type;
+
+static mutex_type & get_mutex()
+{
+ static mutex_type m;
+ return m;
+}
+
+static void * init_mutex_before_main = &get_mutex();
+
+namespace
+{
+ class X;
+
+ struct count_layout
+ {
+ boost::detail::sp_counted_base * pi;
+ int id;
+ };
+
+ struct shared_ptr_layout
+ {
+ X * px;
+ count_layout pn;
+ };
+}
+
+// assume 4 byte alignment for pointers when scanning
+size_t const pointer_align = 4;
+
+typedef std::map<void const *, long> map2_type;
+
+static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2)
+{
+ unsigned char const * p = static_cast<unsigned char const *>(area);
+
+ for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
+ {
+ shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
+
+ if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0)
+ {
+ ++m2[q->pn.pi];
+ }
+ }
+}
+
+typedef std::deque<void const *> open_type;
+
+static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open)
+{
+ unsigned char const * p = static_cast<unsigned char const *>(area);
+
+ for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
+ {
+ shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
+
+ if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0)
+ {
+ open.push_back(q->pn.pi);
+ m2.erase(q->pn.pi);
+ }
+ }
+}
+
+static void find_unreachable_objects_impl(map_type const & m, map2_type & m2)
+{
+ // scan objects for shared_ptr members, compute internal counts
+
+ {
+ std::cout << "... " << m.size() << " objects in m.\n";
+
+ for(map_type::const_iterator i = m.begin(); i != m.end(); ++i)
+ {
+ BOOST_ASSERT(static_cast<boost::detail::sp_counted_base const *>(i->first)->use_count() != 0); // there should be no inactive counts in the map
+
+ scan_and_count(i->second.first, i->second.second, m, m2);
+ }
+
+ std::cout << "... " << m2.size() << " objects in m2.\n";
+ }
+
+ // mark reachable objects
+
+ {
+ open_type open;
+
+ for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i)
+ {
+ boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
+ if(p->use_count() != i->second) open.push_back(p);
+ }
+
+ std::cout << "... " << m2.size() << " objects in open.\n";
+
+ for(open_type::iterator j = open.begin(); j != open.end(); ++j)
+ {
+ m2.erase(*j);
+ }
+
+ while(!open.empty())
+ {
+ void const * p = open.front();
+ open.pop_front();
+
+ map_type::const_iterator i = m.find(p);
+ BOOST_ASSERT(i != m.end());
+
+ scan_and_mark(i->second.first, i->second.second, m2, open);
+ }
+ }
+
+ // m2 now contains the unreachable objects
+}
+
+std::size_t find_unreachable_objects(bool report)
+{
+ map2_type m2;
+
+#ifdef BOOST_HAS_THREADS
+
+ // This will work without the #ifdef, but some compilers warn
+ // that lock is not referenced
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ map_type const & m = get_map();
+
+ find_unreachable_objects_impl(m, m2);
+
+ if(report)
+ {
+ for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
+ {
+ map_type::const_iterator i = m.find(j->first);
+ BOOST_ASSERT(i != m.end());
+ std::cout << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
+ }
+ }
+
+ return m2.size();
+}
+
+typedef std::deque< boost::shared_ptr<X> > free_list_type;
+
+static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free)
+{
+ unsigned char * p = static_cast<unsigned char *>(area);
+
+ for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
+ {
+ shared_ptr_layout * q = reinterpret_cast<shared_ptr_layout *>(p);
+
+ if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0)
+ {
+ boost::shared_ptr<X> * ppx = reinterpret_cast< boost::shared_ptr<X> * >(p);
+ free.push_back(*ppx);
+ ppx->reset();
+ }
+ }
+}
+
+void free_unreachable_objects()
+{
+ free_list_type free;
+
+ {
+ map2_type m2;
+
+#ifdef BOOST_HAS_THREADS
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ map_type const & m = get_map();
+
+ find_unreachable_objects_impl(m, m2);
+
+ for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
+ {
+ map_type::const_iterator i = m.find(j->first);
+ BOOST_ASSERT(i != m.end());
+ scan_and_free(i->second.first, i->second.second, m2, free);
+ }
+ }
+
+ std::cout << "... about to free " << free.size() << " objects.\n";
+}
+
+// debug hooks
+
+namespace boost
+{
+
+void sp_scalar_constructor_hook(void *)
+{
+}
+
+void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn)
+{
+#ifdef BOOST_HAS_THREADS
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ get_map()[pn] = std::make_pair(px, size);
+}
+
+void sp_scalar_destructor_hook(void *)
+{
+}
+
+void sp_scalar_destructor_hook(void *, std::size_t, void * pn)
+{
+#ifdef BOOST_HAS_THREADS
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ get_map().erase(pn);
+}
+
+void sp_array_constructor_hook(void *)
+{
+}
+
+void sp_array_destructor_hook(void *)
+{
+}
+
+} // namespace boost
+
+#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/tools.cxx b/slideshow/source/engine/tools.cxx
new file mode 100644
index 000000000000..f7417e19db29
--- /dev/null
+++ b/slideshow/source/engine/tools.cxx
@@ -0,0 +1,839 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/canvastools.hxx>
+
+#include <math.h>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/vector/b2ivector.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/tools/lerp.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include "unoview.hxx"
+#include "smilfunctionparser.hxx"
+#include "tools.hxx"
+
+#include <limits>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ namespace
+ {
+ class NamedValueStringComparator
+ {
+ public:
+ NamedValueStringComparator( const ::rtl::OUString& rSearchString ) :
+ mrSearchString( rSearchString )
+ {
+ }
+
+ bool operator()( const beans::NamedValue& rValue ) const
+ {
+ return rValue.Name == mrSearchString;
+ }
+
+ private:
+ const ::rtl::OUString& mrSearchString;
+ };
+
+ class NamedValueComparator
+ {
+ public:
+ NamedValueComparator( const beans::NamedValue& rKey ) :
+ mrKey( rKey )
+ {
+ }
+
+ bool operator()( const beans::NamedValue& rValue ) const
+ {
+ return rValue.Name == mrKey.Name && rValue.Value == mrKey.Value;
+ }
+
+ private:
+ const beans::NamedValue& mrKey;
+ };
+
+ ::basegfx::B2DHomMatrix getAttributedShapeTransformation( const ::basegfx::B2DRectangle& rShapeBounds,
+ const ShapeAttributeLayerSharedPtr& pAttr )
+ {
+ ::basegfx::B2DHomMatrix aTransform;
+ const ::basegfx::B2DSize& rSize( rShapeBounds.getRange() );
+
+ const double nShearX( pAttr->isShearXAngleValid() ?
+ pAttr->getShearXAngle() :
+ 0.0 );
+ const double nShearY( pAttr->isShearYAngleValid() ?
+ pAttr->getShearYAngle() :
+ 0.0 );
+ const double nRotation( pAttr->isRotationAngleValid() ?
+ pAttr->getRotationAngle()*M_PI/180.0 :
+ 0.0 );
+
+ // scale, shear and rotation pivot point is the shape
+ // center - adapt origin accordingly
+ aTransform.translate( -0.5, -0.5 );
+
+ // ensure valid size (zero size will inevitably lead
+ // to a singular transformation matrix)
+ aTransform.scale( ::basegfx::pruneScaleValue(
+ rSize.getX() ),
+ ::basegfx::pruneScaleValue(
+ rSize.getY() ) );
+
+ const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) );
+ const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) );
+ const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) );
+
+ if( bNeedRotation || bNeedShearX || bNeedShearY )
+ {
+ if( bNeedShearX )
+ aTransform.shearX( nShearX );
+
+ if( bNeedShearY )
+ aTransform.shearY( nShearY );
+
+ if( bNeedRotation )
+ aTransform.rotate( nRotation );
+ }
+
+ // move left, top corner back to position of the
+ // shape. Since we've already translated the
+ // center of the shape to the origin (the
+ // translate( -0.5, -0.5 ) above), translate to
+ // center of final shape position here.
+ aTransform.translate( rShapeBounds.getCenterX(),
+ rShapeBounds.getCenterY() );
+
+ return aTransform;
+ }
+ }
+
+ // Value extraction from Any
+ // =========================
+
+ /// extract unary double value from Any
+ bool extractValue( double& o_rValue,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& rShape,
+ const ::basegfx::B2DVector& rSlideBounds )
+ {
+ // try to extract numeric value (double, or smaller POD, like float or int)
+ if( (rSourceAny >>= o_rValue) )
+ {
+ // succeeded
+ return true;
+ }
+
+ // try to extract string
+ ::rtl::OUString aString;
+ if( !(rSourceAny >>= aString) )
+ return false; // nothing left to try
+
+ // parse the string into an ExpressionNode
+ try
+ {
+ // Parse string into ExpressionNode, eval node at time 0.0
+ o_rValue = (*SmilFunctionParser::parseSmilValue(
+ aString,
+ calcRelativeShapeBounds(rSlideBounds,
+ rShape->getBounds()) ))(0.0);
+ }
+ catch( ParseError& )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /// extract enum/constant group value from Any
+ bool extractValue( sal_Int32& o_rValue,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& /*rShape*/,
+ const ::basegfx::B2DVector& /*rSlideBounds*/ )
+ {
+ // try to extract numeric value (int, or smaller POD, like byte)
+ if( (rSourceAny >>= o_rValue) )
+ {
+ // succeeded
+ return true;
+ }
+
+ // okay, no plain int. Maybe one of the domain-specific enums?
+ drawing::FillStyle eFillStyle;
+ if( (rSourceAny >>= eFillStyle) )
+ {
+ o_rValue = sal::static_int_cast<sal_Int16>(eFillStyle);
+
+ // succeeded
+ return true;
+ }
+
+ drawing::LineStyle eLineStyle;
+ if( (rSourceAny >>= eLineStyle) )
+ {
+ o_rValue = sal::static_int_cast<sal_Int16>(eLineStyle);
+
+ // succeeded
+ return true;
+ }
+
+ awt::FontSlant eFontSlant;
+ if( (rSourceAny >>= eFontSlant) )
+ {
+ o_rValue = sal::static_int_cast<sal_Int16>(eFontSlant);
+
+ // succeeded
+ return true;
+ }
+
+ // nothing left to try. Failure
+ return false;
+ }
+
+ /// extract enum/constant group value from Any
+ bool extractValue( sal_Int16& o_rValue,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& rShape,
+ const ::basegfx::B2DVector& rSlideBounds )
+ {
+ sal_Int32 aValue;
+ if( !extractValue(aValue,rSourceAny,rShape,rSlideBounds) )
+ return false;
+
+ if( std::numeric_limits<sal_Int16>::max() < aValue ||
+ std::numeric_limits<sal_Int16>::min() > aValue )
+ {
+ return false;
+ }
+
+ o_rValue = static_cast<sal_Int16>(aValue);
+
+ return true;
+ }
+
+ /// extract color value from Any
+ bool extractValue( RGBColor& o_rValue,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& /*rShape*/,
+ const ::basegfx::B2DVector& /*rSlideBounds*/ )
+ {
+ // try to extract numeric value (double, or smaller POD, like float or int)
+ {
+ double nTmp = 0;
+ if( (rSourceAny >>= nTmp) )
+ {
+ sal_uInt32 aIntColor( static_cast< sal_uInt32 >(nTmp) );
+
+ // TODO(F2): Handle color values correctly, here
+ o_rValue = unoColor2RGBColor( aIntColor );
+
+ // succeeded
+ return true;
+ }
+ }
+
+ // try double sequence
+ {
+ uno::Sequence< double > aTmp;
+ if( (rSourceAny >>= aTmp) )
+ {
+ ENSURE_OR_THROW( aTmp.getLength() == 3,
+ "extractValue(): inappropriate length for RGB color value" );
+
+ o_rValue = RGBColor( aTmp[0], aTmp[1], aTmp[2] );
+
+ // succeeded
+ return true;
+ }
+ }
+
+ // try sal_Int32 sequence
+ {
+ uno::Sequence< sal_Int32 > aTmp;
+ if( (rSourceAny >>= aTmp) )
+ {
+ ENSURE_OR_THROW( aTmp.getLength() == 3,
+ "extractValue(): inappropriate length for RGB color value" );
+
+ // truncate to byte
+ o_rValue = RGBColor( ::cppcanvas::makeColor(
+ static_cast<sal_uInt8>(aTmp[0]),
+ static_cast<sal_uInt8>(aTmp[1]),
+ static_cast<sal_uInt8>(aTmp[2]),
+ 255 ) );
+
+ // succeeded
+ return true;
+ }
+ }
+
+ // try sal_Int8 sequence
+ {
+ uno::Sequence< sal_Int8 > aTmp;
+ if( (rSourceAny >>= aTmp) )
+ {
+ ENSURE_OR_THROW( aTmp.getLength() == 3,
+ "extractValue(): inappropriate length for RGB color value" );
+
+ o_rValue = RGBColor( ::cppcanvas::makeColor( aTmp[0], aTmp[1], aTmp[2], 255 ) );
+
+ // succeeded
+ return true;
+ }
+ }
+
+ // try to extract string
+ ::rtl::OUString aString;
+ if( !(rSourceAny >>= aString) )
+ return false; // nothing left to try
+
+ // TODO(F2): Provide symbolic color values here
+ o_rValue = RGBColor( 0.5, 0.5, 0.5 );
+
+ return true;
+ }
+
+ /// extract color value from Any
+ bool extractValue( HSLColor& o_rValue,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& /*rShape*/,
+ const ::basegfx::B2DVector& /*rSlideBounds*/ )
+ {
+ // try double sequence
+ {
+ uno::Sequence< double > aTmp;
+ if( (rSourceAny >>= aTmp) )
+ {
+ ENSURE_OR_THROW( aTmp.getLength() == 3,
+ "extractValue(): inappropriate length for HSL color value" );
+
+ o_rValue = HSLColor( aTmp[0], aTmp[1], aTmp[2] );
+
+ // succeeded
+ return true;
+ }
+ }
+
+ // try sal_Int8 sequence
+ {
+ uno::Sequence< sal_Int8 > aTmp;
+ if( (rSourceAny >>= aTmp) )
+ {
+ ENSURE_OR_THROW( aTmp.getLength() == 3,
+ "extractValue(): inappropriate length for HSL color value" );
+
+ o_rValue = HSLColor( aTmp[0]*360.0/255.0, aTmp[1]/255.0, aTmp[2]/255.0 );
+
+ // succeeded
+ return true;
+ }
+ }
+
+ return false; // nothing left to try
+ }
+
+ /// extract plain string from Any
+ bool extractValue( ::rtl::OUString& o_rValue,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& /*rShape*/,
+ const ::basegfx::B2DVector& /*rSlideBounds*/ )
+ {
+ // try to extract string
+ if( !(rSourceAny >>= o_rValue) )
+ return false; // nothing left to try
+
+ return true;
+ }
+
+ /// extract bool value from Any
+ bool extractValue( bool& o_rValue,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& /*rShape*/,
+ const ::basegfx::B2DVector& /*rSlideBounds*/ )
+ {
+ sal_Bool nTmp = sal_Bool();
+ // try to extract bool value
+ if( (rSourceAny >>= nTmp) )
+ {
+ o_rValue = nTmp;
+
+ // succeeded
+ return true;
+ }
+
+ // try to extract string
+ ::rtl::OUString aString;
+ if( !(rSourceAny >>= aString) )
+ return false; // nothing left to try
+
+ // we also take the strings "true" and "false",
+ // as well as "on" and "off" here
+ if( aString.equalsIgnoreAsciiCaseAscii("true") ||
+ aString.equalsIgnoreAsciiCaseAscii("on") )
+ {
+ o_rValue = true;
+ return true;
+ }
+ if( aString.equalsIgnoreAsciiCaseAscii("false") ||
+ aString.equalsIgnoreAsciiCaseAscii("off") )
+ {
+ o_rValue = false;
+ return true;
+ }
+
+ // ultimately failed.
+ return false;
+ }
+
+ /// extract double 2-tuple from Any
+ bool extractValue( ::basegfx::B2DTuple& o_rPair,
+ const uno::Any& rSourceAny,
+ const ShapeSharedPtr& rShape,
+ const ::basegfx::B2DVector& rSlideBounds )
+ {
+ animations::ValuePair aPair;
+
+ if( !(rSourceAny >>= aPair) )
+ return false;
+
+ double nFirst;
+ if( !extractValue( nFirst, aPair.First, rShape, rSlideBounds ) )
+ return false;
+
+ double nSecond;
+ if( !extractValue( nSecond, aPair.Second, rShape, rSlideBounds ) )
+ return false;
+
+ o_rPair.setX( nFirst );
+ o_rPair.setY( nSecond );
+
+ return true;
+ }
+
+ bool findNamedValue( uno::Sequence< beans::NamedValue > const& rSequence,
+ const beans::NamedValue& rSearchKey )
+ {
+ const beans::NamedValue* pArray = rSequence.getConstArray();
+ const size_t nLen( rSequence.getLength() );
+
+ if( nLen == 0 )
+ return false;
+
+ const beans::NamedValue* pFound = ::std::find_if( pArray,
+ pArray + nLen,
+ NamedValueComparator( rSearchKey ) );
+
+ if( pFound == pArray + nLen )
+ return false;
+
+ return true;
+ }
+
+ bool findNamedValue( beans::NamedValue* o_pRet,
+ const uno::Sequence< beans::NamedValue >& rSequence,
+ const ::rtl::OUString& rSearchString )
+ {
+ const beans::NamedValue* pArray = rSequence.getConstArray();
+ const size_t nLen( rSequence.getLength() );
+
+ if( nLen == 0 )
+ return false;
+
+ const beans::NamedValue* pFound = ::std::find_if( pArray,
+ pArray + nLen,
+ NamedValueStringComparator( rSearchString ) );
+ if( pFound == pArray + nLen )
+ return false;
+
+ if( o_pRet )
+ *o_pRet = *pFound;
+
+ return true;
+ }
+
+ basegfx::B2DRange calcRelativeShapeBounds( const basegfx::B2DVector& rPageSize,
+ const basegfx::B2DRange& rShapeBounds )
+ {
+ return basegfx::B2DRange( rShapeBounds.getMinX() / rPageSize.getX(),
+ rShapeBounds.getMinY() / rPageSize.getY(),
+ rShapeBounds.getMaxX() / rPageSize.getX(),
+ rShapeBounds.getMaxY() / rPageSize.getY() );
+ }
+
+ // TODO(F2): Currently, the positional attributes DO NOT mirror the XShape properties.
+ // First and foremost, this is because we must operate with the shape boundrect,
+ // not position and size (the conversion between logic rect, snap rect and boundrect
+ // are non-trivial for draw shapes, and I won't duplicate them here). Thus, shapes
+ // rotated on the page will still have 0.0 rotation angle, as the metafile
+ // representation fetched over the API is our default zero case.
+
+ ::basegfx::B2DHomMatrix getShapeTransformation( const ::basegfx::B2DRectangle& rShapeBounds,
+ const ShapeAttributeLayerSharedPtr& pAttr )
+ {
+ if( !pAttr )
+ {
+ const basegfx::B2DHomMatrix aTransform(basegfx::tools::createScaleTranslateB2DHomMatrix(
+ rShapeBounds.getWidth(), rShapeBounds.getHeight(),
+ rShapeBounds.getMinX(), rShapeBounds.getMinY()));
+
+ return aTransform;
+ }
+ else
+ {
+ return getAttributedShapeTransformation( rShapeBounds,
+ pAttr );
+ }
+ }
+
+ ::basegfx::B2DHomMatrix getSpriteTransformation( const ::basegfx::B2DVector& rPixelSize,
+ const ::basegfx::B2DVector& rOrigSize,
+ const ShapeAttributeLayerSharedPtr& pAttr )
+ {
+ ::basegfx::B2DHomMatrix aTransform;
+
+ if( pAttr )
+ {
+ const double nShearX( pAttr->isShearXAngleValid() ?
+ pAttr->getShearXAngle() :
+ 0.0 );
+ const double nShearY( pAttr->isShearYAngleValid() ?
+ pAttr->getShearYAngle() :
+ 0.0 );
+ const double nRotation( pAttr->isRotationAngleValid() ?
+ pAttr->getRotationAngle()*M_PI/180.0 :
+ 0.0 );
+
+ // scale, shear and rotation pivot point is the
+ // sprite's pixel center - adapt origin accordingly
+ aTransform.translate( -0.5*rPixelSize.getX(),
+ -0.5*rPixelSize.getY() );
+
+ const ::basegfx::B2DSize aSize(
+ pAttr->isWidthValid() ? pAttr->getWidth() : rOrigSize.getX(),
+ pAttr->isHeightValid() ? pAttr->getHeight() : rOrigSize.getY() );
+
+ // ensure valid size (zero size will inevitably lead
+ // to a singular transformation matrix).
+ aTransform.scale( ::basegfx::pruneScaleValue(
+ aSize.getX() /
+ ::basegfx::pruneScaleValue(
+ rOrigSize.getX() ) ),
+ ::basegfx::pruneScaleValue(
+ aSize.getY() /
+ ::basegfx::pruneScaleValue(
+ rOrigSize.getY() ) ) );
+
+ const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) );
+ const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) );
+ const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) );
+
+ if( bNeedRotation || bNeedShearX || bNeedShearY )
+ {
+ if( bNeedShearX )
+ aTransform.shearX( nShearX );
+
+ if( bNeedShearY )
+ aTransform.shearY( nShearY );
+
+ if( bNeedRotation )
+ aTransform.rotate( nRotation );
+ }
+
+ // move left, top corner back to original position of
+ // the sprite (we've translated the center of the
+ // sprite to the origin above).
+ aTransform.translate( 0.5*rPixelSize.getX(),
+ 0.5*rPixelSize.getY() );
+ }
+
+ // return identity transform for un-attributed
+ // shapes. This renders the sprite as-is, in it's
+ // document-supplied size.
+ return aTransform;
+ }
+
+ ::basegfx::B2DRectangle getShapeUpdateArea( const ::basegfx::B2DRectangle& rUnitBounds,
+ const ::basegfx::B2DHomMatrix& rShapeTransform,
+ const ShapeAttributeLayerSharedPtr& pAttr )
+ {
+ ::basegfx::B2DHomMatrix aTransform;
+
+ if( pAttr &&
+ pAttr->isCharScaleValid() &&
+ fabs(pAttr->getCharScale()) > 1.0 )
+ {
+ // enlarge shape bounds. Have to consider the worst
+ // case here (the text fully fills the shape)
+
+ const double nCharScale( pAttr->getCharScale() );
+
+ // center of scaling is the middle of the shape
+ aTransform.translate( -0.5, -0.5 );
+ aTransform.scale( nCharScale, nCharScale );
+ aTransform.translate( 0.5, 0.5 );
+ }
+
+ aTransform *= rShapeTransform;
+
+ ::basegfx::B2DRectangle aRes;
+
+ // apply shape transformation to unit rect
+ return ::canvas::tools::calcTransformedRectBounds(
+ aRes,
+ rUnitBounds,
+ aTransform );
+ }
+
+ ::basegfx::B2DRange getShapeUpdateArea( const ::basegfx::B2DRange& rUnitBounds,
+ const ::basegfx::B2DRange& rShapeBounds )
+ {
+ return ::basegfx::B2DRectangle(
+ basegfx::tools::lerp( rShapeBounds.getMinX(),
+ rShapeBounds.getMaxX(),
+ rUnitBounds.getMinX() ),
+ basegfx::tools::lerp( rShapeBounds.getMinY(),
+ rShapeBounds.getMaxY(),
+ rUnitBounds.getMinY() ),
+ basegfx::tools::lerp( rShapeBounds.getMinX(),
+ rShapeBounds.getMaxX(),
+ rUnitBounds.getMaxX() ),
+ basegfx::tools::lerp( rShapeBounds.getMinY(),
+ rShapeBounds.getMaxY(),
+ rUnitBounds.getMaxY() ) );
+ }
+
+ ::basegfx::B2DRectangle getShapePosSize( const ::basegfx::B2DRectangle& rOrigBounds,
+ const ShapeAttributeLayerSharedPtr& pAttr )
+ {
+ // an already empty shape bound need no further
+ // treatment. In fact, any changes applied below would
+ // actually remove the special empty state, thus, don't
+ // change!
+ if( !pAttr ||
+ rOrigBounds.isEmpty() )
+ {
+ return rOrigBounds;
+ }
+ else
+ {
+ // cannot use maBounds anymore, attributes might have been
+ // changed by now.
+ // Have to use absolute values here, as negative sizes
+ // (aka mirrored shapes) _still_ have the same bounds,
+ // only with mirrored content.
+ ::basegfx::B2DSize aSize;
+ aSize.setX( fabs( pAttr->isWidthValid() ?
+ pAttr->getWidth() :
+ rOrigBounds.getWidth() ) );
+ aSize.setY( fabs( pAttr->isHeightValid() ?
+ pAttr->getHeight() :
+ rOrigBounds.getHeight() ) );
+
+ ::basegfx::B2DPoint aPos;
+ aPos.setX( pAttr->isPosXValid() ?
+ pAttr->getPosX() :
+ rOrigBounds.getCenterX() );
+ aPos.setY( pAttr->isPosYValid() ?
+ pAttr->getPosY() :
+ rOrigBounds.getCenterY() );
+
+ // the positional attribute retrieved from the
+ // ShapeAttributeLayer actually denotes the _middle_
+ // of the shape (do it as the PPTs do...)
+ return ::basegfx::B2DRectangle( aPos - 0.5*aSize,
+ aPos + 0.5*aSize );
+ }
+ }
+
+ RGBColor unoColor2RGBColor( sal_Int32 nColor )
+ {
+ return RGBColor(
+ ::cppcanvas::makeColor(
+ // convert from API color to IntSRGBA color
+ // (0xAARRGGBB -> 0xRRGGBBAA)
+ static_cast< sal_uInt8 >( nColor >> 16U ),
+ static_cast< sal_uInt8 >( nColor >> 8U ),
+ static_cast< sal_uInt8 >( nColor ),
+ static_cast< sal_uInt8 >( nColor >> 24U ) ) );
+ }
+
+ sal_Int32 RGBAColor2UnoColor( ::cppcanvas::Color::IntSRGBA aColor )
+ {
+ return ::cppcanvas::makeColorARGB(
+ // convert from IntSRGBA color to API color
+ // (0xRRGGBBAA -> 0xAARRGGBB)
+ static_cast< sal_uInt8 >(0),
+ ::cppcanvas::getRed(aColor),
+ ::cppcanvas::getGreen(aColor),
+ ::cppcanvas::getBlue(aColor));
+ }
+
+ void fillRect( const ::cppcanvas::CanvasSharedPtr& rCanvas,
+ const ::basegfx::B2DRectangle& rRect,
+ ::cppcanvas::Color::IntSRGBA aFillColor )
+ {
+ const ::basegfx::B2DPolygon aPoly(
+ ::basegfx::tools::createPolygonFromRect( rRect ));
+
+ ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
+ ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( rCanvas,
+ aPoly ) );
+
+ if( pPolyPoly )
+ {
+ pPolyPoly->setRGBAFillColor( aFillColor );
+ pPolyPoly->draw();
+ }
+ }
+
+ void initSlideBackground( const ::cppcanvas::CanvasSharedPtr& rCanvas,
+ const ::basegfx::B2ISize& rSize )
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas( rCanvas->clone() );
+
+ // set transformation to identitiy (->device pixel)
+ pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // #i42440# Fill the _full_ background in
+ // black. Since we had to extend the bitmap by one
+ // pixel, and the bitmap is initialized white,
+ // depending on the slide content a one pixel wide
+ // line will show to the bottom and the right.
+ fillRect( pCanvas,
+ ::basegfx::B2DRectangle( 0.0, 0.0,
+ rSize.getX(),
+ rSize.getY() ),
+ 0x000000FFU );
+
+ // fill the bounds rectangle in white. Subtract one pixel
+ // from both width and height, because the slide size is
+ // chosen one pixel larger than given by the drawing
+ // layer. This is because shapes with line style, that
+ // have the size of the slide would otherwise be cut
+ // off. OTOH, every other slide background (solid fill,
+ // gradient, bitmap) render one pixel less, thus revealing
+ // ugly white pixel to the right and the bottom.
+ fillRect( pCanvas,
+ ::basegfx::B2DRectangle( 0.0, 0.0,
+ rSize.getX()-1,
+ rSize.getY()-1 ),
+ 0xFFFFFFFFU );
+ }
+
+ ::basegfx::B2DRectangle getAPIShapeBounds( const uno::Reference< drawing::XShape >& xShape )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xShape,
+ uno::UNO_QUERY_THROW );
+ // read bound rect
+ awt::Rectangle aTmpRect;
+ if( !(xPropSet->getPropertyValue(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("BoundRect") ) ) >>= aTmpRect) )
+ {
+ ENSURE_OR_THROW( false,
+ "getAPIShapeBounds(): Could not get \"BoundRect\" property from shape" );
+ }
+
+ return ::basegfx::B2DRectangle( aTmpRect.X,
+ aTmpRect.Y,
+ aTmpRect.X+aTmpRect.Width,
+ aTmpRect.Y+aTmpRect.Height );
+ }
+
+/*
+ TODO(F1): When ZOrder someday becomes usable enable this
+
+ double getAPIShapePrio( const uno::Reference< drawing::XShape >& xShape )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xShape,
+ uno::UNO_QUERY_THROW );
+ // read prio
+ sal_Int32 nPrio(0);
+ if( !(xPropSet->getPropertyValue(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZOrder") ) ) >>= nPrio) )
+ {
+ ENSURE_OR_THROW( false,
+ "getAPIShapePrio(): Could not get \"ZOrder\" property from shape" );
+ }
+
+ // TODO(F2): Check and adapt the range of possible values here.
+ // Maybe we can also take the total number of shapes here
+ return nPrio / 65535.0;
+ }
+*/
+
+ basegfx::B2IVector getSlideSizePixel( const basegfx::B2DVector& rSlideSize,
+ const UnoViewSharedPtr& pView )
+ {
+ ENSURE_OR_THROW(pView, "getSlideSizePixel(): invalid view");
+
+ // determine transformed page bounds
+ const basegfx::B2DRange aRect( 0,0,
+ rSlideSize.getX(),
+ rSlideSize.getY() );
+ basegfx::B2DRange aTmpRect;
+ canvas::tools::calcTransformedRectBounds( aTmpRect,
+ aRect,
+ pView->getTransformation() );
+
+ // #i42440# Returned slide size is one pixel too small, as
+ // rendering happens one pixel to the right and below the
+ // actual bound rect.
+ return basegfx::B2IVector(
+ basegfx::fround( aTmpRect.getRange().getX() ) + 1,
+ basegfx::fround( aTmpRect.getRange().getY() ) + 1 );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/barndoorwipe.cxx b/slideshow/source/engine/transitions/barndoorwipe.cxx
new file mode 100644
index 000000000000..e65e94344854
--- /dev/null
+++ b/slideshow/source/engine/transitions/barndoorwipe.cxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "barndoorwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon BarnDoorWipe::operator () ( double t )
+{
+ if (m_doubled)
+ t /= 2.0;
+
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5));
+ aTransform.scale( ::basegfx::pruneScaleValue(t), 1.0 );
+ aTransform.translate( 0.5, 0.5 );
+ ::basegfx::B2DPolygon poly( m_unitRect );
+ poly.transform( aTransform );
+ ::basegfx::B2DPolyPolygon res(poly);
+
+ if (m_doubled) {
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5);
+ aTransform.rotate( M_PI_2 );
+ aTransform.translate( 0.5, 0.5 );
+ poly.transform( aTransform );
+ res.append(poly);
+ }
+
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/barndoorwipe.hxx b/slideshow/source/engine/transitions/barndoorwipe.hxx
new file mode 100644
index 000000000000..e7c2d74e7b16
--- /dev/null
+++ b/slideshow/source/engine/transitions/barndoorwipe.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_BARNDOORWIPE_HXX
+#define INCLUDED_SLIDESHOW_BARNDOORWIPE_HXX
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generate a barn door wipe or double barn door wipe:
+class BarnDoorWipe : public ParametricPolyPolygon
+{
+public:
+ BarnDoorWipe( bool doubled = false )
+ : m_unitRect( createUnitRect() ), m_doubled(doubled) {}
+ virtual ::basegfx::B2DPolyPolygon operator()( double x );
+private:
+ const ::basegfx::B2DPolygon m_unitRect;
+ const bool m_doubled;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_BARNDOORWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/barwipepolypolygon.cxx b/slideshow/source/engine/transitions/barwipepolypolygon.cxx
new file mode 100644
index 000000000000..c9838530f323
--- /dev/null
+++ b/slideshow/source/engine/transitions/barwipepolypolygon.cxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include "barwipepolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon BarWipePolyPolygon::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res;
+ ::basegfx::B2DHomMatrix aTransform;
+ aTransform.scale( ::basegfx::pruneScaleValue( t / m_nBars ), 1.0 );
+ for ( sal_Int32 i = m_nBars; i--; )
+ {
+ ::basegfx::B2DHomMatrix transform( aTransform );
+ transform.translate( static_cast<double>(i) / m_nBars, 0.0 );
+ ::basegfx::B2DPolygon poly( m_unitRect );
+ poly.transform( transform );
+ res.append( poly );
+ }
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/barwipepolypolygon.hxx b/slideshow/source/engine/transitions/barwipepolypolygon.hxx
new file mode 100644
index 000000000000..001d1b940ae7
--- /dev/null
+++ b/slideshow/source/engine/transitions/barwipepolypolygon.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_BARWIPEPOLYPOLYGON_HXX
+#define INCLUDED_SLIDESHOW_BARWIPEPOLYPOLYGON_HXX
+
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a horizontal, left-to-right bar wipe:
+class BarWipePolyPolygon : public ParametricPolyPolygon
+{
+public:
+ BarWipePolyPolygon( sal_Int32 nBars = 1 /* nBars > 1: blinds effect */ )
+ : m_nBars(nBars),
+ m_unitRect( createUnitRect() )
+ {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ const sal_Int32 m_nBars;
+ const ::basegfx::B2DPolygon m_unitRect;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_BARWIPEPOLYPOLYGON_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/boxwipe.cxx b/slideshow/source/engine/transitions/boxwipe.cxx
new file mode 100644
index 000000000000..b4d479de7e43
--- /dev/null
+++ b/slideshow/source/engine/transitions/boxwipe.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include "boxwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon BoxWipe::operator () ( double t )
+{
+ ::basegfx::B2DHomMatrix aTransform;
+ double d = ::basegfx::pruneScaleValue(t);
+ if (m_topCentered) {
+ aTransform.translate( -0.5, 0.0 );
+ aTransform.scale( d, d );
+ aTransform.translate( 0.5, 0.0 );
+ } else {
+ aTransform.scale( d, d );
+ }
+
+ ::basegfx::B2DPolyPolygon res( m_unitRect );
+ res.transform( aTransform );
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/boxwipe.hxx b/slideshow/source/engine/transitions/boxwipe.hxx
new file mode 100644
index 000000000000..899d56755acc
--- /dev/null
+++ b/slideshow/source/engine/transitions/boxwipe.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_BOXWIPE_HXX
+#define INCLUDED_SLIDESHOW_BOXWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a default topleft to right bottom box wipe
+class BoxWipe : public ParametricPolyPolygon
+{
+public:
+ BoxWipe( bool topCentered ) : m_topCentered(topCentered),
+ m_unitRect( createUnitRect() )
+ {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ const bool m_topCentered;
+ const ::basegfx::B2DPolyPolygon m_unitRect;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_BOXWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/checkerboardwipe.cxx b/slideshow/source/engine/transitions/checkerboardwipe.cxx
new file mode 100644
index 000000000000..d8b2fbc8cadb
--- /dev/null
+++ b/slideshow/source/engine/transitions/checkerboardwipe.cxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include "checkerboardwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon CheckerBoardWipe::operator () ( double t )
+{
+ const double d = (1.0 / m_unitsPerEdge);
+ ::basegfx::B2DHomMatrix aTransform;
+ aTransform.scale( ::basegfx::pruneScaleValue( d * 2.0 * t ),
+ ::basegfx::pruneScaleValue( d ) );
+
+ ::basegfx::B2DPolyPolygon res;
+ for ( sal_Int32 i = m_unitsPerEdge; i--; )
+ {
+ ::basegfx::B2DHomMatrix transform( aTransform );
+ if ((i % 2) == 1) // odd line
+ transform.translate( -d, 0.0 );
+ for ( sal_Int32 j = (m_unitsPerEdge / 2) + 1; j--; )
+ {
+ ::basegfx::B2DPolyPolygon poly( m_unitRect );
+ poly.transform( transform );
+ res.append( poly );
+ transform.translate( d * 2.0, 0.0 );
+ }
+ aTransform.translate( 0.0, d ); // next line
+ }
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/checkerboardwipe.hxx b/slideshow/source/engine/transitions/checkerboardwipe.hxx
new file mode 100644
index 000000000000..06c7e28e240d
--- /dev/null
+++ b/slideshow/source/engine/transitions/checkerboardwipe.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_CHECKERBOARDWIPE_HXX
+#define INCLUDED_SLIDESHOW_CHECKERBOARDWIPE_HXX
+
+#include <osl/diagnose.h>
+
+#include "transitiontools.hxx"
+#include "parametricpolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generate a check board wipe (across)
+class CheckerBoardWipe : public ParametricPolyPolygon
+{
+public:
+ CheckerBoardWipe( sal_Int32 unitsPerEdge = 10 )
+ : m_unitsPerEdge(unitsPerEdge),
+ m_unitRect( createUnitRect() )
+ { OSL_ASSERT( (unitsPerEdge % 2) == 0 ); }
+ virtual ::basegfx::B2DPolyPolygon operator () ( double x );
+private:
+ const sal_Int32 m_unitsPerEdge;
+ const ::basegfx::B2DPolyPolygon m_unitRect;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_CHECKERBOARDWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/clippingfunctor.cxx b/slideshow/source/engine/transitions/clippingfunctor.cxx
new file mode 100644
index 000000000000..5aa03e75a42f
--- /dev/null
+++ b/slideshow/source/engine/transitions/clippingfunctor.cxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include "clippingfunctor.hxx"
+#include "transitiontools.hxx"
+
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ClippingFunctor::ClippingFunctor(const ParametricPolyPolygonSharedPtr& rPolygon,
+ const TransitionInfo& rTransitionInfo,
+ bool bDirectionForward,
+ bool bModeIn ) :
+ mpParametricPoly( rPolygon ),
+ maStaticTransformation(),
+ mbForwardParameterSweep( true ),
+ mbSubtractPolygon( false ),
+ mbScaleIsotrophically( rTransitionInfo.mbScaleIsotrophically ),
+ mbFlip(false)
+ {
+ ENSURE_OR_THROW( rPolygon,
+ "ClippingFunctor::ClippingFunctor(): Invalid parametric polygon" );
+
+ // maBackgroundRect serves as the minuent when
+ // subtracting a given clip polygon from the
+ // background. To speed up the clipper algo, avoid
+ // actual intersections of the generated
+ // poly-polygon with the minuent - i.e. choose the
+ // polygon to subtract from sufficiently large.
+
+ // blow up unit rect to (-1,-1),(2,2)
+ // AW: Not needed, just use range
+ // ::basegfx::B2DHomMatrix aMatrix;
+ // aMatrix.scale(3.0,3.0);
+ // aMatrix.translate(-1.0,-1.0);
+ // maBackgroundRect.transform( aMatrix );
+
+ // extract modification info from maTransitionInfo
+ // -----------------------------------------------
+
+ // perform general transformations _before_ the reverse
+ // mode changes. This allows the Transition table to be
+ // filled more constitently (otherwise, when e.g. rotating
+ // a clip 90 degrees, the REVERSEMETHOD_FLIP_X becomes
+ // REVERSEMETHOD_FLIP_Y instead)
+ if (rTransitionInfo.mnRotationAngle != 0.0 ||
+ rTransitionInfo.mnScaleX != 1.0 ||
+ rTransitionInfo.mnScaleY != 1.0)
+ {
+ maStaticTransformation.translate( -0.5, -0.5 );
+ // apply further transformations:
+ if (rTransitionInfo.mnRotationAngle != 0.0)
+ {
+ maStaticTransformation.rotate(
+ basegfx::deg2rad(rTransitionInfo.mnRotationAngle) );
+ }
+ if (rTransitionInfo.mnScaleX != 1.0 ||
+ rTransitionInfo.mnScaleY != 1.0)
+ {
+ maStaticTransformation.scale(
+ rTransitionInfo.mnScaleX,
+ rTransitionInfo.mnScaleY );
+ }
+ maStaticTransformation.translate( 0.5, 0.5 );
+ }
+
+ if( !bDirectionForward )
+ {
+ // Client has requested reversed
+ // direction. Apply TransitionInfo's choice
+ // for that
+ switch( rTransitionInfo.meReverseMethod )
+ {
+ default:
+ ENSURE_OR_THROW(
+ false,
+ "TransitionFactory::TransitionFactory(): Unexpected reverse method" );
+ break;
+
+ case TransitionInfo::REVERSEMETHOD_IGNORE:
+ break;
+
+ case TransitionInfo::REVERSEMETHOD_INVERT_SWEEP:
+ mbForwardParameterSweep = !mbForwardParameterSweep;
+ break;
+
+ case TransitionInfo::REVERSEMETHOD_SUBTRACT_POLYGON:
+ mbSubtractPolygon = !mbSubtractPolygon;
+ break;
+
+ case TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT:
+ mbForwardParameterSweep = !mbForwardParameterSweep;
+ mbSubtractPolygon = !mbSubtractPolygon;
+ break;
+
+ case TransitionInfo::REVERSEMETHOD_ROTATE_180:
+ maStaticTransformation = basegfx::tools::createRotateAroundPoint(0.5, 0.5, M_PI)
+ * maStaticTransformation;
+ break;
+
+ case TransitionInfo::REVERSEMETHOD_FLIP_X:
+ maStaticTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix(-1.0, 1.0, 1.0, 0.0)
+ * maStaticTransformation;
+ mbFlip = true;
+ break;
+
+ case TransitionInfo::REVERSEMETHOD_FLIP_Y:
+ maStaticTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix(1.0, -1.0, 0.0, 1.0)
+ * maStaticTransformation;
+ mbFlip = true;
+ break;
+ }
+ }
+
+ if( !bModeIn )
+ {
+ // client has requested 'out' mode. Apply
+ // TransitionInfo's method of choice
+ if( rTransitionInfo.mbOutInvertsSweep )
+ mbForwardParameterSweep = !mbForwardParameterSweep;
+ else
+ mbSubtractPolygon = !mbSubtractPolygon;
+ }
+ }
+
+ ::basegfx::B2DPolyPolygon ClippingFunctor::operator()( double nValue,
+ const ::basegfx::B2DSize& rTargetSize )
+ {
+ // modify clip polygon according to static
+ // transformation plus current shape size
+ ::basegfx::B2DHomMatrix aMatrix( maStaticTransformation );
+
+ // retrieve current clip polygon
+ ::basegfx::B2DPolyPolygon aClipPoly = (*mpParametricPoly)(
+ mbForwardParameterSweep ? nValue : 1.0 - nValue );
+
+ // TODO(Q4): workaround here, better be fixed in cppcanvas
+ if (aClipPoly.count() == 0)
+ aClipPoly.append( basegfx::B2DPolygon() );
+
+ if (mbFlip)
+ aClipPoly.flip();
+
+ // currently, clipper cannot cope with curves. Subdivide first
+ // AW: Should be no longer necessary; clipping tools are now bezier-safe
+ // if( aClipPoly.areControlPointsUsed() )
+ // aClipPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aClipPoly);
+
+ if( mbSubtractPolygon )
+ {
+ // subtract given polygon from background
+ // rect. Do that before any transformations.
+
+ // calc maBackgroundRect \ aClipPoly
+ // =================================
+
+ // AW: Simplified
+ // use a range with fixed size (-1,-1),(2,2)
+ const basegfx::B2DRange aBackgroundRange(-1, -1, 2, 2);
+ const basegfx::B2DRange aClipPolyRange(aClipPoly.getB2DRange());
+
+ if(aBackgroundRange.isInside(aClipPolyRange))
+ {
+ // combine polygons; make the clip polygon the hole
+ aClipPoly = ::basegfx::tools::correctOrientations(aClipPoly);
+ aClipPoly.flip();
+ aClipPoly.insert(0, basegfx::tools::createPolygonFromRect(aBackgroundRange));
+ }
+ else
+ {
+ // when not completely inside aBackgroundRange clipping is needed
+ // substract aClipPoly from aBackgroundRange
+ const basegfx::B2DPolyPolygon aBackgroundPolyPoly(basegfx::tools::createPolygonFromRect(aBackgroundRange));
+ aClipPoly = basegfx::tools::solvePolygonOperationDiff(aBackgroundPolyPoly, aClipPoly);
+ }
+ }
+
+ // scale polygon up to current shape size
+ if( mbScaleIsotrophically )
+ {
+ const double nScale( ::std::max( rTargetSize.getX(),
+ rTargetSize.getY() ) );
+ aMatrix.scale( nScale, nScale );
+ aMatrix.translate( -(nScale-rTargetSize.getX())/2.0,
+ -(nScale-rTargetSize.getY())/2.0 );
+ }
+ else
+ {
+ aMatrix.scale( rTargetSize.getX(),
+ rTargetSize.getY() );
+ }
+
+ // apply cumulative transformation to clip polygon
+ aClipPoly.transform( aMatrix );
+
+ return aClipPoly;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/clippingfunctor.hxx b/slideshow/source/engine/transitions/clippingfunctor.hxx
new file mode 100644
index 000000000000..97a6ee1b62dc
--- /dev/null
+++ b/slideshow/source/engine/transitions/clippingfunctor.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_CLIPPINGFUNCTOR_HXX
+#define INCLUDED_SLIDESHOW_CLIPPINGFUNCTOR_HXX
+
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <transitioninfo.hxx>
+#include <parametricpolypolygon.hxx>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Generates the final clipping polygon.
+
+ This class serves as the functor, which generates the
+ final clipping polygon from a given ParametricPolyPolygon
+ and a TransitionInfo.
+
+ The ParametricPolyPolygon can be obtained from the
+ ParametricPolyPolygonFactory, see there.
+
+ The TransitionInfo further parameterizes the polygon
+ generated by the ParametricPolyPolygon, with common
+ modifications such as rotation, flipping, or change of
+ direction. This allows the ParametricPolyPolygonFactory to
+ provide only prototypical shapes, with the ClippingFunctor
+ further customizing the output.
+ */
+ class ClippingFunctor
+ {
+ public:
+ ClippingFunctor(
+ const ParametricPolyPolygonSharedPtr& rPolygon,
+ const TransitionInfo& rTransitionInfo,
+ bool bDirectionForward,
+ bool bModeIn );
+
+ /** Generate clip polygon.
+
+ @param nValue
+ Value to generate the polygon for. Must be in the
+ range [0,1].
+
+ @param rTargetSize
+ Size the clip polygon should cover. This is typically
+ the size of the object the effect is applied on.
+ */
+ ::basegfx::B2DPolyPolygon operator()( double nValue,
+ const ::basegfx::B2DSize& rTargetSize );
+
+ private:
+ ParametricPolyPolygonSharedPtr mpParametricPoly;
+ ::basegfx::B2DHomMatrix maStaticTransformation;
+ // AW: Not needed
+ // ::basegfx::B2DPolyPolygon maBackgroundRect;
+ bool mbForwardParameterSweep;
+ bool mbSubtractPolygon;
+ const bool mbScaleIsotrophically;
+ bool mbFlip;
+ };
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_CLIPPINGFUNCTOR_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/clockwipe.cxx b/slideshow/source/engine/transitions/clockwipe.cxx
new file mode 100644
index 000000000000..dbcf59abb1f6
--- /dev/null
+++ b/slideshow/source/engine/transitions/clockwipe.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "clockwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolygon ClockWipe::calcCenteredClock( double t, double e )
+{
+ ::basegfx::B2DPolygon poly;
+ ::basegfx::B2DHomMatrix aTransform;
+ aTransform.rotate( t * 2.0 * M_PI );
+ const double MAX_EDGE = 2.0;
+ ::basegfx::B2DPoint p( 0.0, -MAX_EDGE );
+ p *= aTransform;
+ poly.append( p );
+ if (t >= 0.875)
+ poly.append( ::basegfx::B2DPoint( -e, -e ) );
+ if (t >= 0.625)
+ poly.append( ::basegfx::B2DPoint( -e, e ) );
+ if (t >= 0.375)
+ poly.append( ::basegfx::B2DPoint( e, e ) );
+ if (t >= 0.125)
+ poly.append( ::basegfx::B2DPoint( e, -e ) );
+ poly.append( ::basegfx::B2DPoint( 0.0, -e ) );
+ poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
+ poly.setClosed(true);
+ return poly;
+}
+
+::basegfx::B2DPolyPolygon ClockWipe::operator () ( double t )
+{
+ const basegfx::B2DHomMatrix aTransform(basegfx::tools::createScaleTranslateB2DHomMatrix(0.5, 0.5, 0.5, 0.5));
+ ::basegfx::B2DPolygon poly( calcCenteredClock(t) );
+ poly.transform( aTransform );
+ return ::basegfx::B2DPolyPolygon(poly);
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/clockwipe.hxx b/slideshow/source/engine/transitions/clockwipe.hxx
new file mode 100644
index 000000000000..28a5bd8ada10
--- /dev/null
+++ b/slideshow/source/engine/transitions/clockwipe.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_CLOCKWIPE_HXX
+#define INCLUDED_SLIDESHOW_CLOCKWIPE_HXX
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include "parametricpolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a clockWiseTwelve clock wipe:
+class ClockWipe : public ParametricPolyPolygon
+{
+public:
+ /// 0,1 to 1,1 to 1,0 to 0,-1 to -1,0 to 0,1:
+ static ::basegfx::B2DPolygon calcCenteredClock( double t, double e = 1.0 );
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_CLOCKWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/combtransition.cxx b/slideshow/source/engine/transitions/combtransition.cxx
new file mode 100644
index 000000000000..76d898538a82
--- /dev/null
+++ b/slideshow/source/engine/transitions/combtransition.cxx
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <cppcanvas/spritecanvas.hxx>
+
+#include "combtransition.hxx"
+
+#include <boost/bind.hpp>
+
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+basegfx::B2DPolyPolygon createClipPolygon(
+ const ::basegfx::B2DVector& rDirection,
+ const ::basegfx::B2DSize& rSlideSize,
+ int nNumStrips, int nOffset )
+{
+ // create clip polygon in standard orientation (will later
+ // be rotated to match direction vector)
+ ::basegfx::B2DPolyPolygon aClipPoly;
+
+ // create nNumStrips/2 vertical strips
+ for( int i=nOffset; i<nNumStrips; i+=2 )
+ {
+ aClipPoly.append(
+ ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRectangle( double(i)/nNumStrips, 0.0,
+ double(i+1)/nNumStrips, 1.0) ) );
+
+ }
+
+ // rotate polygons, such that the strips are parallel to
+ // the given direction vector
+ const ::basegfx::B2DVector aUpVec(0.0, 1.0);
+ basegfx::B2DHomMatrix aMatrix(basegfx::tools::createRotateAroundPoint(0.5, 0.5, aUpVec.angle( rDirection )));
+
+ // blow up clip polygon to slide size
+ aMatrix.scale( rSlideSize.getX(),
+ rSlideSize.getY() );
+
+ aClipPoly.transform( aMatrix );
+
+ return aClipPoly;
+}
+
+}
+
+CombTransition::CombTransition(
+ boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ const ::basegfx::B2DVector& rPushDirection,
+ sal_Int32 nNumStripes )
+ : SlideChangeBase( leavingSlide, pEnteringSlide, pSoundPlayer,
+ rViewContainer, rScreenUpdater, rEventMultiplexer,
+ false /* no leaving sprite */,
+ false /* no entering sprite */ ),
+ maPushDirectionUnit( rPushDirection ),
+ mnNumStripes( nNumStripes )
+{
+}
+
+void CombTransition::renderComb( double t,
+ const ViewEntry& rViewEntry ) const
+{
+ const SlideBitmapSharedPtr& pEnteringBitmap = getEnteringBitmap(rViewEntry);
+ const cppcanvas::CanvasSharedPtr pCanvas_ = rViewEntry.mpView->getCanvas();
+
+ if( !pEnteringBitmap || !pCanvas_ )
+ return;
+
+ // calc bitmap offsets. The enter/leaving bitmaps are only
+ // as large as the actual slides. For scaled-down
+ // presentations, we have to move the left, top edge of
+ // those bitmaps to the actual position, governed by the
+ // given view transform. The aBitmapPosPixel local
+ // variable is already in device coordinate space
+ // (i.e. pixel).
+
+ // TODO(F2): Properly respect clip here. Might have to be transformed, too.
+ const basegfx::B2DHomMatrix viewTransform( rViewEntry.mpView->getTransformation() );
+ const basegfx::B2DPoint pageOrigin( viewTransform * basegfx::B2DPoint() );
+
+ // change transformation on cloned canvas to be in
+ // device pixel
+ cppcanvas::CanvasSharedPtr pCanvas( pCanvas_->clone() );
+ basegfx::B2DPoint p;
+
+ // TODO(Q2): Use basegfx bitmaps here
+ // TODO(F1): SlideBitmap is not fully portable between different canvases!
+
+ const basegfx::B2DSize enteringSizePixel(
+ getEnteringSlideSizePixel( rViewEntry.mpView) );
+
+ const basegfx::B2DVector aPushDirection = basegfx::B2DVector(
+ enteringSizePixel * maPushDirectionUnit );
+ const basegfx::B2DPolyPolygon aClipPolygon1 = basegfx::B2DPolyPolygon(
+ createClipPolygon( maPushDirectionUnit,
+ enteringSizePixel,
+ mnNumStripes, 0 ) );
+ const basegfx::B2DPolyPolygon aClipPolygon2 = basegfx::B2DPolyPolygon(
+ createClipPolygon( maPushDirectionUnit,
+ enteringSizePixel,
+ mnNumStripes, 1 ) );
+
+ SlideBitmapSharedPtr const & pLeavingBitmap = getLeavingBitmap(rViewEntry);
+ if( pLeavingBitmap )
+ {
+ // render odd strips:
+ pLeavingBitmap->clip( aClipPolygon1 );
+ // don't modify bitmap object (no move!):
+ p = basegfx::B2DPoint( pageOrigin + (t * aPushDirection) );
+ pCanvas->setTransformation(basegfx::tools::createTranslateB2DHomMatrix(p.getX(), p.getY()));
+ pLeavingBitmap->draw( pCanvas );
+
+ // render even strips:
+ pLeavingBitmap->clip( aClipPolygon2 );
+ // don't modify bitmap object (no move!):
+ p = basegfx::B2DPoint( pageOrigin - (t * aPushDirection) );
+ pCanvas->setTransformation(basegfx::tools::createTranslateB2DHomMatrix(p.getX(), p.getY()));
+ pLeavingBitmap->draw( pCanvas );
+ }
+
+ // TODO(Q2): Use basegfx bitmaps here
+ // TODO(F1): SlideBitmap is not fully portable between different canvases!
+
+ // render odd strips:
+ pEnteringBitmap->clip( aClipPolygon1 );
+ // don't modify bitmap object (no move!):
+ p = basegfx::B2DPoint( pageOrigin + ((t - 1.0) * aPushDirection) );
+ pCanvas->setTransformation(basegfx::tools::createTranslateB2DHomMatrix(p.getX(), p.getY()));
+ pEnteringBitmap->draw( pCanvas );
+
+ // render even strips:
+ pEnteringBitmap->clip( aClipPolygon2 );
+ // don't modify bitmap object (no move!):
+ p = basegfx::B2DPoint( pageOrigin + ((1.0 - t) * aPushDirection) );
+ pCanvas->setTransformation(basegfx::tools::createTranslateB2DHomMatrix(p.getX(), p.getY()));
+ pEnteringBitmap->draw( pCanvas );
+}
+
+bool CombTransition::operator()( double t )
+{
+ std::for_each( beginViews(),
+ endViews(),
+ boost::bind( &CombTransition::renderComb,
+ this,
+ t,
+ _1 ));
+
+ getScreenUpdater().notifyUpdate();
+
+ return true;
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/combtransition.hxx b/slideshow/source/engine/transitions/combtransition.hxx
new file mode 100644
index 000000000000..9016824d84da
--- /dev/null
+++ b/slideshow/source/engine/transitions/combtransition.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_COMBTRANSITION_HXX
+#define INCLUDED_SLIDESHOW_COMBTRANSITION_HXX
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include "slidechangebase.hxx"
+
+namespace slideshow {
+namespace internal {
+
+/** Comb transition class.
+
+ This class provides a SlideChangeAnimation, showing a
+ comb-like effect (stripes of alternating push effects).
+*/
+class CombTransition : public SlideChangeBase
+{
+public:
+ /** Create the comb transition effect.
+
+ @param nNumStripes
+ Number of comb-like stripes to show in this effect
+ */
+ CombTransition( ::boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ const ::basegfx::B2DVector& rPushDirection,
+ sal_Int32 nNumStripes );
+
+ // NumberAnimation
+ virtual bool operator()( double x );
+
+private:
+ const ::basegfx::B2DVector maPushDirectionUnit;
+ sal_Int32 mnNumStripes;
+
+ void renderComb( double t, const ViewEntry& rViewEntry ) const;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_COMBTRANSITION_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/doublediamondwipe.cxx b/slideshow/source/engine/transitions/doublediamondwipe.cxx
new file mode 100644
index 000000000000..41b71493c2e3
--- /dev/null
+++ b/slideshow/source/engine/transitions/doublediamondwipe.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include "doublediamondwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon DoubleDiamondWipe::operator () ( double t )
+{
+ // outer:
+ const double a = ::basegfx::pruneScaleValue( 0.25 + (t * 0.75) );
+ ::basegfx::B2DPolygon poly;
+ poly.append( ::basegfx::B2DPoint( 0.5 + a, 0.5 ) );
+ poly.append( ::basegfx::B2DPoint( 0.5, 0.5 - a ) );
+ poly.append( ::basegfx::B2DPoint( 0.5 - a, 0.5 ) );
+ poly.append( ::basegfx::B2DPoint( 0.5, 0.5 + a ) );
+ poly.setClosed(true);
+ ::basegfx::B2DPolyPolygon res(poly);
+
+ // inner (reverse order to clip):
+ const double b = ::basegfx::pruneScaleValue( (1.0 - t) * 0.25 );
+ poly.clear();
+ poly.append( ::basegfx::B2DPoint( 0.5 + b, 0.5 ) );
+ poly.append( ::basegfx::B2DPoint( 0.5, 0.5 + b ) );
+ poly.append( ::basegfx::B2DPoint( 0.5 - b, 0.5 ) );
+ poly.append( ::basegfx::B2DPoint( 0.5, 0.5 - b ) );
+ poly.setClosed(true);
+ res.append(poly);
+
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/doublediamondwipe.hxx b/slideshow/source/engine/transitions/doublediamondwipe.hxx
new file mode 100644
index 000000000000..ca8475130eba
--- /dev/null
+++ b/slideshow/source/engine/transitions/doublediamondwipe.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_DOUBLEDIAMONDWIPE_HXX
+#define INCLUDED_SLIDESHOW_DOUBLEDIAMONDWIPE_HXX
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a double diamond wipe:
+class DoubleDiamondWipe : public ParametricPolyPolygon
+{
+public:
+ DoubleDiamondWipe() : m_unitRect( createUnitRect() ) {}
+ virtual ::basegfx::B2DPolyPolygon operator()( double x );
+private:
+ const ::basegfx::B2DPolyPolygon m_unitRect;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_DOUBLEDIAMONDWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/ellipsewipe.cxx b/slideshow/source/engine/transitions/ellipsewipe.cxx
new file mode 100644
index 000000000000..8d2a9f4c7885
--- /dev/null
+++ b/slideshow/source/engine/transitions/ellipsewipe.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include "ellipsewipe.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon EllipseWipe::operator () ( double t )
+{
+ // currently only circle:
+ ::basegfx::B2DPolygon poly(
+ ::basegfx::tools::createPolygonFromCircle(
+ ::basegfx::B2DPoint( 0.5, 0.5 ),
+ ::basegfx::pruneScaleValue( t * M_SQRT2 / 2.0 ) ) );
+ return ::basegfx::B2DPolyPolygon( poly );
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/ellipsewipe.hxx b/slideshow/source/engine/transitions/ellipsewipe.hxx
new file mode 100644
index 000000000000..d1dcd7f3ea20
--- /dev/null
+++ b/slideshow/source/engine/transitions/ellipsewipe.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_ELLIPSEWIPE_HXX
+#define INCLUDED_SLIDESHOW_ELLIPSEWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generate a iris wipe
+class EllipseWipe : public ParametricPolyPolygon
+{
+public:
+ EllipseWipe( sal_Int32 /*nTransitionSubType xxx todo */ ) {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double x );
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_ELLIPSEWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/fanwipe.cxx b/slideshow/source/engine/transitions/fanwipe.cxx
new file mode 100644
index 000000000000..3e884f918e33
--- /dev/null
+++ b/slideshow/source/engine/transitions/fanwipe.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "transitiontools.hxx"
+#include "clockwipe.hxx"
+#include "fanwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon FanWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res;
+ ::basegfx::B2DPolygon poly(
+ ClockWipe::calcCenteredClock(
+ t / ((m_center && m_single) ? 2.0 : 4.0) ) );
+
+ res.append( poly );
+ // flip on y-axis:
+ poly.transform(basegfx::tools::createScaleB2DHomMatrix(-1.0, 1.0));
+ poly.flip();
+ res.append( poly );
+
+ if (m_center)
+ {
+ res.transform(basegfx::tools::createScaleTranslateB2DHomMatrix(0.5, 0.5, 0.5, 0.5));
+
+ if (! m_single)
+ res.append( flipOnXAxis(res) );
+ }
+ else
+ {
+ OSL_ASSERT( ! m_fanIn );
+ res.transform(basegfx::tools::createScaleTranslateB2DHomMatrix(0.5, 1.0, 0.5, 1.0));
+ }
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/fanwipe.hxx b/slideshow/source/engine/transitions/fanwipe.hxx
new file mode 100644
index 000000000000..946bc5daab68
--- /dev/null
+++ b/slideshow/source/engine/transitions/fanwipe.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_FANWIPE_HXX
+#define INCLUDED_SLIDESHOW_FANWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a centerTop (center=true) or double fan wipe:
+class FanWipe : public ParametricPolyPolygon
+{
+public:
+ FanWipe( bool center, bool single = true, bool fanIn = false )
+ : m_center(center), m_single(single), m_fanIn(fanIn) {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ bool m_center, m_single, m_fanIn;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_FANWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/figurewipe.cxx b/slideshow/source/engine/transitions/figurewipe.cxx
new file mode 100644
index 000000000000..73ffbbda17fd
--- /dev/null
+++ b/slideshow/source/engine/transitions/figurewipe.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ * ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "transitiontools.hxx"
+#include "figurewipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon FigureWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res(m_figure);
+ res.transform(basegfx::tools::createScaleTranslateB2DHomMatrix(t, t, 0.5, 0.5));
+ return res;
+}
+
+FigureWipe * FigureWipe::createTriangleWipe()
+{
+ const double s60 = sin( basegfx::deg2rad(60.0) );
+ const double s30 = sin( basegfx::deg2rad(30.0) );
+ ::basegfx::B2DPolygon figure;
+ figure.append( ::basegfx::B2DPoint( 0.5 + s30, 0.5 ) );
+ figure.append( ::basegfx::B2DPoint( 0.0, -0.5 - s60 ) );
+ figure.append( ::basegfx::B2DPoint( -0.5 - s30, 0.5 ) );
+ figure.setClosed(true);
+ return new FigureWipe(figure);
+}
+
+FigureWipe * FigureWipe::createArrowHeadWipe()
+{
+ const double s60 = sin( basegfx::deg2rad(60.0) );
+ const double s30 = sin( basegfx::deg2rad(30.0) );
+ const double off = s30;
+ ::basegfx::B2DPolygon figure;
+ figure.append( ::basegfx::B2DPoint( 0.5 + s30 + off, 0.5 + off ) );
+ figure.append( ::basegfx::B2DPoint( 0.0, -0.5 - s60 ) );
+ figure.append( ::basegfx::B2DPoint( -0.5 - s30 - off, 0.5 + off ) );
+ figure.append( ::basegfx::B2DPoint( 0.0, 0.5 ) );
+ figure.setClosed(true);
+ return new FigureWipe(figure);
+}
+
+FigureWipe * FigureWipe::createPentagonWipe()
+{
+ const double s = sin( basegfx::deg2rad(18.0) );
+ const double c = cos( basegfx::deg2rad(18.0) );
+ ::basegfx::B2DPolygon figure;
+ figure.append( ::basegfx::B2DPoint( 0.5, 0.5 ) );
+ figure.append( ::basegfx::B2DPoint( 0.5 + s, 0.5 - c ) );
+ figure.append( ::basegfx::B2DPoint( 0.0, 0.5 - c - sin(basegfx::deg2rad(36.0)) ) );
+ figure.append( ::basegfx::B2DPoint( -0.5 - s, 0.5 - c ) );
+ figure.append( ::basegfx::B2DPoint( -0.5, 0.5 ) );
+ figure.setClosed(true);
+ return new FigureWipe(figure);
+}
+
+FigureWipe * FigureWipe::createHexagonWipe()
+{
+ const double s = sin( basegfx::deg2rad(30.0) );
+ const double c = cos( basegfx::deg2rad(30.0) );
+ ::basegfx::B2DPolygon figure;
+ figure.append( ::basegfx::B2DPoint( 0.5, c ) );
+ figure.append( ::basegfx::B2DPoint( 0.5 + s, 0.0 ) );
+ figure.append( ::basegfx::B2DPoint( 0.5, -c ) );
+ figure.append( ::basegfx::B2DPoint( -0.5, -c ) );
+ figure.append( ::basegfx::B2DPoint( -0.5 - s, 0.0 ) );
+ figure.append( ::basegfx::B2DPoint( -0.5, c ) );
+ figure.setClosed(true);
+ return new FigureWipe(figure);
+}
+
+FigureWipe * FigureWipe::createStarWipe( sal_Int32 nPoints )
+{
+ const double v = (M_PI / nPoints);
+ const ::basegfx::B2DPoint p_( 0.0, -M_SQRT2 );
+ ::basegfx::B2DPolygon figure;
+ for ( sal_Int32 pos = 0; pos < nPoints; ++pos ) {
+ const double w = (pos * 2.0 * M_PI / nPoints);
+ ::basegfx::B2DHomMatrix aTransform;
+ ::basegfx::B2DPoint p(p_);
+ aTransform.rotate( -w );
+ p *= aTransform;
+ figure.append(p);
+ p = p_;
+ aTransform.identity();
+ aTransform.scale( 0.5, 0.5 );
+ aTransform.rotate( -w - v );
+ p *= aTransform;
+ figure.append(p);
+ }
+ figure.setClosed(true);
+ return new FigureWipe(figure);
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/figurewipe.hxx b/slideshow/source/engine/transitions/figurewipe.hxx
new file mode 100644
index 000000000000..d9448e5a59c0
--- /dev/null
+++ b/slideshow/source/engine/transitions/figurewipe.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_FIGUREWIPE_HXX
+#define INCLUDED_SLIDESHOW_FIGUREWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+class FigureWipe : public ParametricPolyPolygon
+{
+public:
+ static FigureWipe * createTriangleWipe();
+ static FigureWipe * createArrowHeadWipe();
+ static FigureWipe * createStarWipe( sal_Int32 nPoints );
+ static FigureWipe * createPentagonWipe();
+ static FigureWipe * createHexagonWipe();
+
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ FigureWipe( ::basegfx::B2DPolygon const & figure ) : m_figure(figure) {}
+ const ::basegfx::B2DPolygon m_figure;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_FIGUREWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/fourboxwipe.cxx b/slideshow/source/engine/transitions/fourboxwipe.cxx
new file mode 100644
index 000000000000..aaa7b2823a85
--- /dev/null
+++ b/slideshow/source/engine/transitions/fourboxwipe.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "fourboxwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon FourBoxWipe::operator () ( double t )
+{
+ ::basegfx::B2DHomMatrix aTransform;
+ const double d = ::basegfx::pruneScaleValue( t / 2.0 );
+ if (m_cornersOut)
+ {
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5);
+ aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(d, d, -0.25, -0.25)
+ * aTransform;
+ }
+ else
+ {
+ aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(d, d, -0.5, -0.5);
+ }
+
+ // top left:
+ ::basegfx::B2DPolygon square( m_unitRect );
+ square.transform( aTransform );
+ ::basegfx::B2DPolyPolygon res( square );
+ // bottom left, flip on x-axis:
+ aTransform.scale( -1.0, 1.0 );
+ ::basegfx::B2DPolygon square2( m_unitRect );
+ square2.transform( aTransform );
+ square2.flip(); // flip direction
+ res.append( square2 );
+ // bottom right, flip on y-axis:
+ aTransform.scale( 1.0, -1.0 );
+ ::basegfx::B2DPolygon square3( m_unitRect );
+ square3.transform( aTransform );
+ res.append( square3 );
+ // top right, flip on x-axis:
+ aTransform.scale( -1.0, 1.0 );
+ ::basegfx::B2DPolygon square4( m_unitRect );
+ square4.transform( aTransform );
+ square4.flip(); // flip direction
+ res.append( square4 );
+
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.5);
+ res.transform( aTransform );
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/fourboxwipe.hxx b/slideshow/source/engine/transitions/fourboxwipe.hxx
new file mode 100644
index 000000000000..e4095c89ee27
--- /dev/null
+++ b/slideshow/source/engine/transitions/fourboxwipe.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_FOURBOXWIPE_HXX
+#define INCLUDED_SLIDESHOW_FOURBOXWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generate a 4-box wipe
+class FourBoxWipe : public ParametricPolyPolygon
+{
+public:
+ FourBoxWipe( bool cornersOut ) : m_cornersOut(cornersOut),
+ m_unitRect( createUnitRect() )
+ {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ const bool m_cornersOut;
+ const ::basegfx::B2DPolygon m_unitRect;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_FOURBOXWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/iriswipe.cxx b/slideshow/source/engine/transitions/iriswipe.cxx
new file mode 100644
index 000000000000..59aeff8df674
--- /dev/null
+++ b/slideshow/source/engine/transitions/iriswipe.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "iriswipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon IrisWipe::operator () ( double t )
+{
+ const double d = ::basegfx::pruneScaleValue(t);
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5));
+ aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(d, d, 0.5, 0.5) * aTransform;
+
+ ::basegfx::B2DPolyPolygon res( m_unitRect );
+ res.transform( aTransform );
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/iriswipe.hxx b/slideshow/source/engine/transitions/iriswipe.hxx
new file mode 100644
index 000000000000..c0d73a52ac16
--- /dev/null
+++ b/slideshow/source/engine/transitions/iriswipe.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_IRISWIPE_HXX
+#define INCLUDED_SLIDESHOW_IRISWIPE_HXX
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generate a iris wipe
+class IrisWipe : public ParametricPolyPolygon
+{
+public:
+ IrisWipe() : m_unitRect( createUnitRect() ) {}
+ virtual ::basegfx::B2DPolyPolygon operator()( double x );
+private:
+ const ::basegfx::B2DPolyPolygon m_unitRect;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_IRISWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/makefile.mk b/slideshow/source/engine/transitions/makefile.mk
new file mode 100644
index 000000000000..a5fbd567721c
--- /dev/null
+++ b/slideshow/source/engine/transitions/makefile.mk
@@ -0,0 +1,73 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=slideshow
+TARGET=transitions
+ENABLE_EXCEPTIONS=TRUE
+PRJINC=..$/..
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/barwipepolypolygon.obj \
+ $(SLO)$/boxwipe.obj \
+ $(SLO)$/clippingfunctor.obj \
+ $(SLO)$/combtransition.obj \
+ $(SLO)$/fourboxwipe.obj \
+ $(SLO)$/barndoorwipe.obj \
+ $(SLO)$/iriswipe.obj \
+ $(SLO)$/veewipe.obj \
+ $(SLO)$/ellipsewipe.obj \
+ $(SLO)$/checkerboardwipe.obj \
+ $(SLO)$/randomwipe.obj \
+ $(SLO)$/waterfallwipe.obj \
+ $(SLO)$/clockwipe.obj \
+ $(SLO)$/fanwipe.obj \
+ $(SLO)$/pinwheelwipe.obj \
+ $(SLO)$/snakewipe.obj \
+ $(SLO)$/spiralwipe.obj \
+ $(SLO)$/sweepwipe.obj \
+ $(SLO)$/figurewipe.obj \
+ $(SLO)$/doublediamondwipe.obj \
+ $(SLO)$/zigzagwipe.obj \
+ $(SLO)$/parametricpolypolygonfactory.obj \
+ $(SLO)$/shapetransitionfactory.obj \
+ $(SLO)$/slidetransitionfactory.obj \
+ $(SLO)$/transitionfactorytab.obj \
+ $(SLO)$/transitiontools.obj \
+ $(SLO)$/slidechangebase.obj
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/transitions/parametricpolypolygon.hxx b/slideshow/source/engine/transitions/parametricpolypolygon.hxx
new file mode 100644
index 000000000000..8f51de7c6440
--- /dev/null
+++ b/slideshow/source/engine/transitions/parametricpolypolygon.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_PARAMETRICPOLYPOLYGON_HXX
+#define INCLUDED_SLIDESHOW_PARAMETRICPOLYPOLYGON_HXX
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <boost/shared_ptr.hpp>
+
+
+/* Definition of ParametricPolyPolygon interface */
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Interface defining a parametric poly-polygon.
+
+ This interface defines a poly-polygon, whose actual shape
+ is parameterized by a floating point value. This is
+ e.g. used to generically access the various clip polygon
+ generators for transition effects.
+
+ Since for every parametric poly-polygon, there is a set of
+ variations, which can easily be generated by simple
+ transformations or change in parameter range sweep
+ direction, objects implementing this interface only
+ generate <em>one</em> prototypical instance of the
+ parametric poly-polygon. Generally speaking, the main
+ effect direction should be horizontal, it should make
+ increasingly more area visible (transition 'in'), and when
+ there is a designated direction given, that should be
+ left-to-right.
+ */
+ class ParametricPolyPolygon
+ {
+ public:
+ virtual ~ParametricPolyPolygon() {}
+
+ /** Retrieve the poly-polygon for value t.
+
+ @param t
+ Current parameter value to retrieve the corresponding
+ poly-polygon for. Permissible values for t must be in
+ the range [0,1].
+
+ @return a poly-polygon corresponding to the given
+ parameter value. The poly-polygon is interpreted as
+ living in the unit rectangle (i.e. [0,1]x[0,1]), but
+ is not necessarily constrained to completely lie in
+ this area (this very much depends on the actual effect
+ to be generated). Although, from a performance
+ perspective, it currently <em>is</em> advantageous to
+ try to keep the poly-polygon within these bounds (at
+ least if there are no hard reasons not to do so),
+ because then reversion or out transformations are
+ potentially faster to compute (see the
+ TransitionInfo::meReverseMethod member in
+ transitionfactory.cxx). Furthermore, if one of the
+ polygon modifications involve subtraction (also see
+ TransitionInfo::meReverseMethod), all generated
+ polygons should be oriented clock-wise
+ (i.e. traversing the polygon vertices with increasing
+ vertex index should generate a clock-wise movement).
+ */
+ virtual ::basegfx::B2DPolyPolygon operator()( double t ) = 0;
+ };
+
+ typedef ::boost::shared_ptr< ParametricPolyPolygon > ParametricPolyPolygonSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_PARAMETRICPOLYPOLYGON_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/parametricpolypolygonfactory.cxx b/slideshow/source/engine/transitions/parametricpolypolygonfactory.cxx
new file mode 100644
index 000000000000..e67ddb5b477f
--- /dev/null
+++ b/slideshow/source/engine/transitions/parametricpolypolygonfactory.cxx
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+
+#include "parametricpolypolygonfactory.hxx"
+#include "barwipepolypolygon.hxx"
+#include "boxwipe.hxx"
+#include "fourboxwipe.hxx"
+#include "barndoorwipe.hxx"
+#include "doublediamondwipe.hxx"
+#include "veewipe.hxx"
+#include "iriswipe.hxx"
+#include "ellipsewipe.hxx"
+#include "checkerboardwipe.hxx"
+#include "randomwipe.hxx"
+#include "waterfallwipe.hxx"
+#include "clockwipe.hxx"
+#include "fanwipe.hxx"
+#include "pinwheelwipe.hxx"
+#include "snakewipe.hxx"
+#include "spiralwipe.hxx"
+#include "sweepwipe.hxx"
+#include "figurewipe.hxx"
+#include "zigzagwipe.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ParametricPolyPolygonSharedPtr
+ ParametricPolyPolygonFactory::createClipPolyPolygon(
+ sal_Int16 nType, sal_Int16 nSubType )
+ {
+ using namespace ::com::sun::star::animations::TransitionType;
+ using namespace ::com::sun::star::animations::TransitionSubType;
+
+ switch (nType)
+ {
+ case BARWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new BarWipePolyPolygon );
+ case BLINDSWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new BarWipePolyPolygon( 6 ) );
+ case BOXWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new BoxWipe( nSubType == LEFTCENTER ||
+ nSubType == TOPCENTER ||
+ nSubType == RIGHTCENTER||
+ nSubType == BOTTOMCENTER ) );
+ case FOURBOXWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new FourBoxWipe( nSubType == CORNERSOUT ) );
+ case BARNDOORWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new BarnDoorWipe );
+ case DIAGONALWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new BarWipePolyPolygon );
+ case VEEWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new VeeWipe );
+ case IRISWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new IrisWipe );
+ case ELLIPSEWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new EllipseWipe(nSubType) );
+ case CHECKERBOARDWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new CheckerBoardWipe );
+ case RANDOMBARWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new RandomWipe( 128, true /* bars */ ) );
+ case DISSOLVE:
+ return ParametricPolyPolygonSharedPtr(
+ new RandomWipe( 16 * 16, // for now until dxcanvas is faster
+// 64 * 64 /* elements */,
+ false /* dissolve */ ) );
+ case WATERFALLWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new WaterfallWipe(
+ 128,
+ // flipOnYAxis:
+ nSubType == VERTICALRIGHT ||
+ nSubType == HORIZONTALLEFT ) );
+ case CLOCKWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new ClockWipe );
+ case FANWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new FanWipe( // center:
+ nSubType == CENTERTOP ||
+ nSubType == CENTERRIGHT ) );
+ case PINWHEELWIPE: {
+ sal_Int32 blades;
+ switch (nSubType) {
+ case ONEBLADE:
+ blades = 1;
+ break;
+ case THREEBLADE:
+ blades = 3;
+ break;
+ case FOURBLADE:
+ blades = 4;
+ break;
+ case EIGHTBLADE:
+ blades = 8;
+ break;
+ default:
+ blades = 2;
+ break;
+ }
+ return ParametricPolyPolygonSharedPtr(
+ new PinWheelWipe( blades ) );
+ }
+ case SNAKEWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new SnakeWipe(
+ // elements:
+ 64 * 64,
+ // diagonal:
+ nSubType == TOPLEFTDIAGONAL ||
+ nSubType == TOPRIGHTDIAGONAL ||
+ nSubType == BOTTOMRIGHTDIAGONAL ||
+ nSubType == BOTTOMLEFTDIAGONAL,
+ // flipOnYAxis:
+ nSubType == TOPLEFTVERTICAL ||
+ nSubType == TOPRIGHTDIAGONAL ||
+ nSubType == BOTTOMLEFTDIAGONAL
+ ) );
+ case PARALLELSNAKESWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new ParallelSnakesWipe(
+ // elements:
+ 64 * 64,
+ // diagonal:
+ nSubType == DIAGONALBOTTOMLEFTOPPOSITE ||
+ nSubType == DIAGONALTOPLEFTOPPOSITE,
+ // flipOnYAxis:
+ nSubType == VERTICALBOTTOMLEFTOPPOSITE ||
+ nSubType == HORIZONTALTOPLEFTOPPOSITE ||
+ nSubType == DIAGONALTOPLEFTOPPOSITE,
+ // opposite:
+ nSubType == VERTICALTOPLEFTOPPOSITE ||
+ nSubType == VERTICALBOTTOMLEFTOPPOSITE ||
+ nSubType == HORIZONTALTOPLEFTOPPOSITE ||
+ nSubType == HORIZONTALTOPRIGHTOPPOSITE ||
+ nSubType == DIAGONALBOTTOMLEFTOPPOSITE ||
+ nSubType == DIAGONALTOPLEFTOPPOSITE
+ ) );
+ case SPIRALWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new SpiralWipe(
+ // elements:
+ 64 * 64,
+ // flipOnYAxis:
+ nSubType == TOPLEFTCOUNTERCLOCKWISE ||
+ nSubType == TOPRIGHTCOUNTERCLOCKWISE ||
+ nSubType == BOTTOMRIGHTCOUNTERCLOCKWISE ||
+ nSubType == BOTTOMLEFTCOUNTERCLOCKWISE ) );
+ case BOXSNAKESWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new BoxSnakesWipe(
+ // elements:
+ 64 * 64,
+ // fourBox:
+ nSubType == FOURBOXVERTICAL ||
+ nSubType == FOURBOXHORIZONTAL ) );
+ case SINGLESWEEPWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new SweepWipe(
+ // center:
+ nSubType == CLOCKWISETOP ||
+ nSubType == CLOCKWISERIGHT ||
+ nSubType == CLOCKWISEBOTTOM ||
+ nSubType == CLOCKWISELEFT,
+ // single:
+ true,
+ // oppositeVertical:
+ false,
+ // flipOnYAxis:
+ nSubType == COUNTERCLOCKWISEBOTTOMLEFT ||
+ nSubType == COUNTERCLOCKWISETOPRIGHT
+ ) );
+ case DOUBLESWEEPWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new SweepWipe(
+ // center:
+ nSubType == PARALLELVERTICAL ||
+ nSubType == PARALLELDIAGONAL ||
+ nSubType == OPPOSITEVERTICAL ||
+ nSubType == OPPOSITEHORIZONTAL,
+ // single:
+ false,
+ // oppositeVertical:
+ nSubType == OPPOSITEVERTICAL ||
+ nSubType == OPPOSITEHORIZONTAL,
+ // flipOnYAxis:
+ false ) );
+ case DOUBLEFANWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ new FanWipe(
+ //center:
+ true,
+ // single:
+ false,
+ // fanIn:
+ nSubType == FANINVERTICAL ||
+ nSubType == FANINHORIZONTAL ) );
+ case TRIANGLEWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ FigureWipe::createTriangleWipe() );
+ case ARROWHEADWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ FigureWipe::createArrowHeadWipe() );
+ case PENTAGONWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ FigureWipe::createPentagonWipe() );
+ case HEXAGONWIPE:
+ return ParametricPolyPolygonSharedPtr(
+ FigureWipe::createHexagonWipe() );
+ case STARWIPE: {
+ sal_Int32 points;
+ switch (nSubType) {
+ case FIVEPOINT:
+ points = 5;
+ break;
+ case SIXPOINT:
+ points = 6;
+ break;
+ default:
+ points = 4;
+ break;
+ }
+ return ParametricPolyPolygonSharedPtr(
+ FigureWipe::createStarWipe(points) );
+ }
+ case MISCDIAGONALWIPE: {
+ switch (nSubType) {
+ case DOUBLEBARNDOOR:
+ return ParametricPolyPolygonSharedPtr(
+ new BarnDoorWipe( true /* doubled */ ) );
+ case DOUBLEDIAMOND:
+ return ParametricPolyPolygonSharedPtr(
+ new DoubleDiamondWipe );
+ }
+ break;
+ }
+ case ZIGZAGWIPE:
+ return ParametricPolyPolygonSharedPtr( new ZigZagWipe(5) );
+ case BARNZIGZAGWIPE:
+ return ParametricPolyPolygonSharedPtr( new BarnZigZagWipe(5) );
+
+ case BOWTIEWIPE:
+ case BARNVEEWIPE:
+ case EYEWIPE:
+ case ROUNDRECTWIPE:
+ case MISCSHAPEWIPE:
+ case SALOONDOORWIPE:
+ case WINDSHIELDWIPE:
+ // for now, map to barwipe transition
+ return ParametricPolyPolygonSharedPtr(
+ new BarWipePolyPolygon );
+
+ default:
+ case PUSHWIPE:
+ case SLIDEWIPE:
+ case FADE:
+ ENSURE_OR_THROW( false,
+ "createShapeClipPolyPolygonAnimation(): Transition type mismatch" );
+ }
+
+ return ParametricPolyPolygonSharedPtr();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/parametricpolypolygonfactory.hxx b/slideshow/source/engine/transitions/parametricpolypolygonfactory.hxx
new file mode 100644
index 000000000000..0b87b3d4e1e2
--- /dev/null
+++ b/slideshow/source/engine/transitions/parametricpolypolygonfactory.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_PARAMETRICPOLYPOLYGONFACTORY_HXX
+#define INCLUDED_SLIDESHOW_PARAMETRICPOLYPOLYGONFACTORY_HXX
+
+#include "parametricpolypolygon.hxx"
+#include <boost/noncopyable.hpp>
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /* Definition of Transitionfactory class */
+
+ class ParametricPolyPolygonFactory : private boost::noncopyable
+ {
+ public:
+ static ParametricPolyPolygonSharedPtr createClipPolyPolygon( sal_Int16 nTransitionType,
+ sal_Int16 nTransitionSubType );
+
+ private:
+ // static factory
+ ParametricPolyPolygonFactory();
+ ~ParametricPolyPolygonFactory();
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_PARAMETRICPOLYPOLYGONFACTORY_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/pinwheelwipe.cxx b/slideshow/source/engine/transitions/pinwheelwipe.cxx
new file mode 100644
index 000000000000..847189eb9004
--- /dev/null
+++ b/slideshow/source/engine/transitions/pinwheelwipe.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "clockwipe.hxx"
+#include "pinwheelwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon PinWheelWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolygon poly( ClockWipe::calcCenteredClock(
+ t / m_blades,
+ 2.0 /* max edge when rotating */ ) );
+ ::basegfx::B2DPolyPolygon res;
+ for ( sal_Int32 i = m_blades; i--; )
+ {
+ ::basegfx::B2DPolygon p(poly);
+ p.transform(basegfx::tools::createRotateB2DHomMatrix((i * 2.0 * M_PI) / m_blades));
+ res.append( p );
+ }
+ res.transform(basegfx::tools::createScaleTranslateB2DHomMatrix(0.5, 0.5, 0.5, 0.5));
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/pinwheelwipe.hxx b/slideshow/source/engine/transitions/pinwheelwipe.hxx
new file mode 100644
index 000000000000..e3347b5298ee
--- /dev/null
+++ b/slideshow/source/engine/transitions/pinwheelwipe.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_PINWHEELWIPE_HXX
+#define INCLUDED_SLIDESHOW_PINWHEELWIPE_HXX
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include "parametricpolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a n-blade pinWheel wipe:
+class PinWheelWipe : public ParametricPolyPolygon
+{
+public:
+ PinWheelWipe( sal_Int32 blades ) : m_blades(blades) {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ sal_Int32 m_blades;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_PINWHEELWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/randomwipe.cxx b/slideshow/source/engine/transitions/randomwipe.cxx
new file mode 100644
index 000000000000..424d53093d09
--- /dev/null
+++ b/slideshow/source/engine/transitions/randomwipe.cxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "randomwipe.hxx"
+#include "tools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+RandomWipe::RandomWipe( sal_Int32 nElements, bool randomBars )
+ : m_positions( new ::basegfx::B2DPoint[ nElements ] ),
+ m_nElements( nElements ),
+ m_rect( createUnitRect() )
+{
+ ::basegfx::B2DHomMatrix aTransform;
+ if (randomBars)
+ {
+ double edge = (1.0 / nElements);
+ for ( sal_Int32 pos = nElements; pos--; )
+ m_positions[ pos ].setY( ::basegfx::pruneScaleValue( pos * edge ) );
+ aTransform.scale( 1.0, ::basegfx::pruneScaleValue(edge) );
+ }
+ else // dissolve effect
+ {
+ sal_Int32 sqrtElements = static_cast<sal_Int32>(
+ sqrt( static_cast<double>(nElements) ) );
+ double edge = (1.0 / sqrtElements);
+ for ( sal_Int32 pos = nElements; pos--; ) {
+ m_positions[ pos ] = ::basegfx::B2DPoint(
+ ::basegfx::pruneScaleValue( (pos % sqrtElements) * edge ),
+ ::basegfx::pruneScaleValue( (pos / sqrtElements) * edge ) );
+ }
+ const double pedge = ::basegfx::pruneScaleValue(edge);
+ aTransform.scale( pedge, pedge );
+ }
+ m_rect.transform( aTransform );
+
+ // mix up:
+ for ( sal_Int32 pos1 = nElements ; pos1-- ; )
+ {
+ const sal_Int32 pos2 = getRandomOrdinal(pos1+1);
+ const ::basegfx::B2DPoint point( m_positions[ pos1 ] );
+ m_positions[ pos1 ] = m_positions[ pos2 ];
+ m_positions[ pos2 ] = point;
+ }
+}
+
+::basegfx::B2DPolyPolygon RandomWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res;
+ for ( sal_Int32 pos = static_cast<sal_Int32>(t * m_nElements); pos--; )
+ {
+ ::basegfx::B2DPoint const & point = m_positions[ pos ];
+ ::basegfx::B2DPolygon poly( m_rect );
+ poly.transform(basegfx::tools::createTranslateB2DHomMatrix(point.getX(), point.getY()));
+ res.append( poly );
+ }
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/randomwipe.hxx b/slideshow/source/engine/transitions/randomwipe.hxx
new file mode 100644
index 000000000000..bb8f11cc5da0
--- /dev/null
+++ b/slideshow/source/engine/transitions/randomwipe.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_RANDOMWIPE_HXX
+#define INCLUDED_SLIDESHOW_RANDOMWIPE_HXX
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <boost/scoped_array.hpp>
+
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+class RandomWipe : public ParametricPolyPolygon
+{
+public:
+ RandomWipe( sal_Int32 nElements,
+ bool randomBars /* true: generates a horizontal random bar wipe,
+ false: generates a dissolve wipe */ );
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ ::boost::scoped_array< ::basegfx::B2DPoint > m_positions;
+ sal_Int32 m_nElements;
+ ::basegfx::B2DPolygon m_rect;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_RANDOMWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/shapetransitionfactory.cxx b/slideshow/source/engine/transitions/shapetransitionfactory.cxx
new file mode 100644
index 000000000000..3f2ac271f7f7
--- /dev/null
+++ b/slideshow/source/engine/transitions/shapetransitionfactory.cxx
@@ -0,0 +1,409 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+
+#include "transitionfactory.hxx"
+#include "transitiontools.hxx"
+#include "parametricpolypolygonfactory.hxx"
+#include "animationfactory.hxx"
+#include "clippingfunctor.hxx"
+
+#include <boost/bind.hpp>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+/***************************************************
+ *** ***
+ *** Shape Transition Effects ***
+ *** ***
+ ***************************************************/
+
+namespace {
+
+class ClippingAnimation : public NumberAnimation
+{
+public:
+ ClippingAnimation(
+ const ParametricPolyPolygonSharedPtr& rPolygon,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const TransitionInfo& rTransitionInfo,
+ bool bDirectionForward,
+ bool bModeIn );
+
+ ~ClippingAnimation();
+
+ // Animation interface
+ // -------------------
+ virtual void prefetch( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer );
+ virtual void start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer );
+ virtual void end();
+
+ // NumberAnimation interface
+ // -----------------------
+ virtual bool operator()( double nValue );
+ virtual double getUnderlyingValue() const;
+
+private:
+ void end_();
+
+ AnimatableShapeSharedPtr mpShape;
+ ShapeAttributeLayerSharedPtr mpAttrLayer;
+ ShapeManagerSharedPtr mpShapeManager;
+ ClippingFunctor maClippingFunctor;
+ bool mbSpriteActive;
+};
+
+ClippingAnimation::ClippingAnimation(
+ const ParametricPolyPolygonSharedPtr& rPolygon,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const TransitionInfo& rTransitionInfo,
+ bool bDirectionForward,
+ bool bModeIn ) :
+ mpShape(),
+ mpAttrLayer(),
+ mpShapeManager( rShapeManager ),
+ maClippingFunctor( rPolygon,
+ rTransitionInfo,
+ bDirectionForward,
+ bModeIn ),
+ mbSpriteActive(false)
+{
+ ENSURE_OR_THROW(
+ rShapeManager,
+ "ClippingAnimation::ClippingAnimation(): Invalid ShapeManager" );
+}
+
+ClippingAnimation::~ClippingAnimation()
+{
+ try
+ {
+ end_();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+}
+
+void ClippingAnimation::prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& )
+{
+}
+
+void ClippingAnimation::start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rAttrLayer )
+{
+ OSL_ENSURE( !mpShape,
+ "ClippingAnimation::start(): Shape already set" );
+ OSL_ENSURE( !mpAttrLayer,
+ "ClippingAnimation::start(): Attribute layer already set" );
+
+ mpShape = rShape;
+ mpAttrLayer = rAttrLayer;
+
+ ENSURE_OR_THROW( rShape,
+ "ClippingAnimation::start(): Invalid shape" );
+ ENSURE_OR_THROW( rAttrLayer,
+ "ClippingAnimation::start(): Invalid attribute layer" );
+
+ mpShape = rShape;
+ mpAttrLayer = rAttrLayer;
+
+ if( !mbSpriteActive )
+ {
+ mpShapeManager->enterAnimationMode( mpShape );
+ mbSpriteActive = true;
+ }
+}
+
+void ClippingAnimation::end()
+{
+ end_();
+}
+
+void ClippingAnimation::end_()
+{
+ if( mbSpriteActive )
+ {
+ mbSpriteActive = false;
+ mpShapeManager->leaveAnimationMode( mpShape );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+ }
+}
+
+bool ClippingAnimation::operator()( double nValue )
+{
+ ENSURE_OR_RETURN_FALSE(
+ mpAttrLayer && mpShape,
+ "ClippingAnimation::operator(): Invalid ShapeAttributeLayer" );
+
+ // set new clip
+ mpAttrLayer->setClip( maClippingFunctor( nValue,
+ mpShape->getDomBounds().getRange() ) );
+
+ if( mpShape->isContentChanged() )
+ mpShapeManager->notifyShapeUpdate( mpShape );
+
+ return true;
+}
+
+double ClippingAnimation::getUnderlyingValue() const
+{
+ ENSURE_OR_THROW(
+ mpAttrLayer,
+ "ClippingAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" );
+
+ return 0.0; // though this should be used in concert with
+ // ActivitiesFactory::createSimpleActivity, better
+ // explicitely name our start value.
+ // Permissible range for operator() above is [0,1]
+}
+
+} // anon namespace
+
+
+AnimationActivitySharedPtr TransitionFactory::createShapeTransition(
+ const ActivitiesFactory::CommonParameters& rParms,
+ const AnimatableShapeSharedPtr& rShape,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& rSlideSize,
+ uno::Reference< animations::XTransitionFilter > const& xTransition )
+{
+ return createShapeTransition( rParms,
+ rShape,
+ rShapeManager,
+ rSlideSize,
+ xTransition,
+ xTransition->getTransition(),
+ xTransition->getSubtype() );
+}
+
+AnimationActivitySharedPtr TransitionFactory::createShapeTransition(
+ const ActivitiesFactory::CommonParameters& rParms,
+ const AnimatableShapeSharedPtr& rShape,
+ const ShapeManagerSharedPtr& rShapeManager,
+ const ::basegfx::B2DVector& rSlideSize,
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::animations::XTransitionFilter > const& xTransition,
+ sal_Int16 nType,
+ sal_Int16 nSubType )
+{
+ ENSURE_OR_THROW(
+ xTransition.is(),
+ "TransitionFactory::createShapeTransition(): Invalid XTransition" );
+
+ const TransitionInfo* pTransitionInfo(
+ getTransitionInfo( nType, nSubType ) );
+
+ AnimationActivitySharedPtr pGeneratedActivity;
+ if( pTransitionInfo != NULL )
+ {
+ switch( pTransitionInfo->meTransitionClass )
+ {
+ default:
+ case TransitionInfo::TRANSITION_INVALID:
+ OSL_FAIL( "TransitionFactory::createShapeTransition(): Invalid transition type. "
+ "Don't ask me for a 0 TransitionType, have no XTransitionFilter node instead!" );
+ return AnimationActivitySharedPtr();
+
+
+ case TransitionInfo::TRANSITION_CLIP_POLYPOLYGON:
+ {
+ // generate parametric poly-polygon
+ ParametricPolyPolygonSharedPtr pPoly(
+ ParametricPolyPolygonFactory::createClipPolyPolygon(
+ nType, nSubType ) );
+
+ // create a clip activity from that
+ pGeneratedActivity = ActivitiesFactory::createSimpleActivity(
+ rParms,
+ NumberAnimationSharedPtr(
+ new ClippingAnimation(
+ pPoly,
+ rShapeManager,
+ *pTransitionInfo,
+ xTransition->getDirection(),
+ xTransition->getMode() ) ),
+ true );
+ }
+ break;
+
+ case TransitionInfo::TRANSITION_SPECIAL:
+ {
+ switch( nType )
+ {
+ case animations::TransitionType::RANDOM:
+ {
+ // select randomly one of the effects from the
+ // TransitionFactoryTable
+
+ const TransitionInfo* pRandomTransitionInfo( getRandomTransitionInfo() );
+
+ ENSURE_OR_THROW( pRandomTransitionInfo != NULL,
+ "TransitionFactory::createShapeTransition(): Got invalid random transition info" );
+
+ ENSURE_OR_THROW( pRandomTransitionInfo->mnTransitionType != animations::TransitionType::RANDOM,
+ "TransitionFactory::createShapeTransition(): Got random again for random input!" );
+
+ // and recurse
+ pGeneratedActivity = createShapeTransition( rParms,
+ rShape,
+ rShapeManager,
+ rSlideSize,
+ xTransition,
+ pRandomTransitionInfo->mnTransitionType,
+ pRandomTransitionInfo->mnTransitionSubType );
+ }
+ break;
+
+ // TODO(F3): Implement slidewipe for shape
+ case animations::TransitionType::SLIDEWIPE:
+ {
+ sal_Int16 nBarWipeSubType(0);
+ bool bDirectionForward(true);
+
+ // map slidewipe to BARWIPE, for now
+ switch( nSubType )
+ {
+ case animations::TransitionSubType::FROMLEFT:
+ nBarWipeSubType = animations::TransitionSubType::LEFTTORIGHT;
+ bDirectionForward = true;
+ break;
+
+ case animations::TransitionSubType::FROMRIGHT:
+ nBarWipeSubType = animations::TransitionSubType::LEFTTORIGHT;
+ bDirectionForward = false;
+ break;
+
+ case animations::TransitionSubType::FROMTOP:
+ nBarWipeSubType = animations::TransitionSubType::TOPTOBOTTOM;
+ bDirectionForward = true;
+ break;
+
+ case animations::TransitionSubType::FROMBOTTOM:
+ nBarWipeSubType = animations::TransitionSubType::TOPTOBOTTOM;
+ bDirectionForward = false;
+ break;
+
+ default:
+ ENSURE_OR_THROW( false,
+ "TransitionFactory::createShapeTransition(): Unexpected subtype for SLIDEWIPE" );
+ break;
+ }
+
+ // generate parametric poly-polygon
+ ParametricPolyPolygonSharedPtr pPoly(
+ ParametricPolyPolygonFactory::createClipPolyPolygon(
+ animations::TransitionType::BARWIPE,
+ nBarWipeSubType ) );
+
+ // create a clip activity from that
+ pGeneratedActivity = ActivitiesFactory::createSimpleActivity(
+ rParms,
+ NumberAnimationSharedPtr(
+ new ClippingAnimation(
+ pPoly,
+ rShapeManager,
+ *getTransitionInfo( animations::TransitionType::BARWIPE,
+ nBarWipeSubType ),
+ bDirectionForward,
+ xTransition->getMode() ) ),
+ true );
+ }
+ break;
+
+ default:
+ {
+ // TODO(F1): Check whether there's anything left, anyway,
+ // for _shape_ transitions. AFAIK, there are no special
+ // effects for shapes...
+
+ // for now, map all to fade effect
+ pGeneratedActivity = ActivitiesFactory::createSimpleActivity(
+ rParms,
+ AnimationFactory::createNumberPropertyAnimation(
+ ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("Opacity") ),
+ rShape,
+ rShapeManager,
+ rSlideSize ),
+ xTransition->getMode() );
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if( !pGeneratedActivity )
+ {
+ // No animation generated, maybe no table entry for given
+ // transition?
+ OSL_TRACE(
+ "TransitionFactory::createShapeTransition(): Unknown type/subtype (%d/%d) "
+ "combination encountered",
+ xTransition->getTransition(),
+ xTransition->getSubtype() );
+ OSL_FAIL(
+ "TransitionFactory::createShapeTransition(): Unknown type/subtype "
+ "combination encountered" );
+ }
+
+ return pGeneratedActivity;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/slidechangebase.cxx b/slideshow/source/engine/transitions/slidechangebase.cxx
new file mode 100644
index 000000000000..44a2c73504c6
--- /dev/null
+++ b/slideshow/source/engine/transitions/slidechangebase.cxx
@@ -0,0 +1,538 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/canvastools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include "slidechangebase.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+SlideChangeBase::SlideChangeBase( boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ bool bCreateLeavingSprites,
+ bool bCreateEnteringSprites ) :
+ mpSoundPlayer( pSoundPlayer ),
+ mrEventMultiplexer(rEventMultiplexer),
+ mrScreenUpdater(rScreenUpdater),
+ maLeavingSlide( leavingSlide ),
+ mpEnteringSlide( pEnteringSlide ),
+ maViewData(),
+ mrViewContainer(rViewContainer),
+ mbCreateLeavingSprites(bCreateLeavingSprites),
+ mbCreateEnteringSprites(bCreateEnteringSprites),
+ mbSpritesVisible(false),
+ mbFinished(false),
+ mbPrefetched(false)
+{
+ ENSURE_OR_THROW(
+ pEnteringSlide,
+ "SlideChangeBase::SlideChangeBase(): Invalid entering slide!" );
+}
+
+SlideBitmapSharedPtr SlideChangeBase::getLeavingBitmap( const ViewEntry& rViewEntry ) const
+{
+ if( !rViewEntry.mpLeavingBitmap )
+ rViewEntry.mpLeavingBitmap = createBitmap(rViewEntry.mpView,
+ maLeavingSlide);
+
+ return rViewEntry.mpLeavingBitmap;
+}
+
+SlideBitmapSharedPtr SlideChangeBase::getEnteringBitmap( const ViewEntry& rViewEntry ) const
+{
+ if( !rViewEntry.mpEnteringBitmap )
+ rViewEntry.mpEnteringBitmap = createBitmap( rViewEntry.mpView,
+ boost::optional<SlideSharedPtr>(mpEnteringSlide) );
+
+ return rViewEntry.mpEnteringBitmap;
+}
+
+SlideBitmapSharedPtr SlideChangeBase::createBitmap( const UnoViewSharedPtr& rView,
+ const boost::optional<SlideSharedPtr>& rSlide ) const
+{
+ SlideBitmapSharedPtr pRet;
+ if( !rSlide )
+ return pRet;
+
+ SlideSharedPtr const & pSlide = *rSlide;
+ if( !pSlide )
+ {
+ // TODO(P3): No need to generate a bitmap here. This only made
+ // the code more uniform. Faster would be to simply clear the
+ // sprite to black.
+
+ // create empty, black-filled bitmap
+ const basegfx::B2ISize slideSizePixel(
+ getSlideSizePixel( mpEnteringSlide->getSlideSize(),
+ rView ));
+
+ cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
+
+ // create a bitmap of appropriate size
+ cppcanvas::BitmapSharedPtr pBitmap(
+ cppcanvas::BaseGfxFactory::getInstance().createBitmap(
+ pCanvas,
+ slideSizePixel ) );
+
+ ENSURE_OR_THROW(
+ pBitmap,
+ "SlideChangeBase::createBitmap(): Cannot create page bitmap" );
+
+ cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
+ pBitmap->getBitmapCanvas() );
+
+ ENSURE_OR_THROW( pBitmapCanvas,
+ "SlideChangeBase::createBitmap(): "
+ "Cannot create page bitmap canvas" );
+
+ // set transformation to identitiy (->device pixel)
+ pBitmapCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // clear bitmap to black
+ fillRect( pBitmapCanvas,
+ ::basegfx::B2DRectangle( 0.0, 0.0,
+ slideSizePixel.getX(),
+ slideSizePixel.getY() ),
+ 0x000000FFU );
+
+ pRet.reset( new SlideBitmap( pBitmap ));
+ }
+ else
+ {
+ pRet = pSlide->getCurrentSlideBitmap( rView );
+ }
+
+ return pRet;
+}
+
+::basegfx::B2ISize SlideChangeBase::getEnteringSlideSizePixel( const UnoViewSharedPtr& pView ) const
+{
+ return getSlideSizePixel( mpEnteringSlide->getSlideSize(),
+ pView );
+}
+
+::basegfx::B2ISize SlideChangeBase::getLeavingSlideSizePixel( const UnoViewSharedPtr& pView ) const
+{
+ return getSlideSizePixel( (*maLeavingSlide)->getSlideSize(),
+ pView );
+}
+
+
+void SlideChangeBase::renderBitmap(
+ SlideBitmapSharedPtr const & pSlideBitmap,
+ cppcanvas::CanvasSharedPtr const & pCanvas )
+{
+ if( pSlideBitmap && pCanvas )
+ {
+ // need to render without any transformation (we
+ // assume device units):
+ const basegfx::B2DHomMatrix viewTransform(
+ pCanvas->getTransformation() );
+ const basegfx::B2DPoint pageOrigin(
+ viewTransform * basegfx::B2DPoint() );
+ const cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
+ pCanvas->clone() );
+
+ // render at output position, don't modify bitmap object (no move!):
+ const basegfx::B2DHomMatrix transform(basegfx::tools::createTranslateB2DHomMatrix(
+ pageOrigin.getX(), pageOrigin.getY()));
+
+ pDevicePixelCanvas->setTransformation( transform );
+ pSlideBitmap->draw( pDevicePixelCanvas );
+ }
+}
+
+void SlideChangeBase::prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished || mbPrefetched )
+ return;
+
+ // register ourselves for view change events
+ mrEventMultiplexer.addViewHandler( shared_from_this() );
+
+ // init views and create slide bitmaps
+ std::for_each( mrViewContainer.begin(),
+ mrViewContainer.end(),
+ boost::bind( &SlideChangeBase::viewAdded,
+ this,
+ _1 ));
+
+ mbPrefetched = true;
+}
+
+void SlideChangeBase::start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rLayer )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ prefetch(rShape,rLayer); // no-op, if already done
+
+ // start accompanying sound effect, if any
+ if( mpSoundPlayer )
+ {
+ mpSoundPlayer->startPlayback();
+ // xxx todo: for now, presentation.cxx takes care about the slide
+ // #i50492# transition sound object, so just release it here
+ mpSoundPlayer.reset();
+ }
+}
+
+void SlideChangeBase::end()
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ try
+ {
+ // draw fully entered bitmap:
+ ViewsVecT::const_iterator aCurr( beginViews() );
+ const ViewsVecT::const_iterator aEnd( endViews() );
+ while( aCurr != aEnd )
+ {
+ // fully clear view content to background color
+ aCurr->mpView->clearAll();
+
+ const SlideBitmapSharedPtr pSlideBitmap( getEnteringBitmap( *aCurr ));
+ pSlideBitmap->clip( basegfx::B2DPolyPolygon() /* no clipping */ );
+ renderBitmap( pSlideBitmap,
+ aCurr->mpView->getCanvas() );
+
+ ++aCurr;
+ }
+ }
+ catch( uno::Exception& )
+ {
+ // make sure releasing below happens
+ }
+
+ // swap changes to screen
+ mrScreenUpdater.notifyUpdate();
+
+ // make object dysfunctional
+ mbFinished = true;
+ ViewsVecT().swap(maViewData);
+ maLeavingSlide.reset();
+ mpEnteringSlide.reset();
+
+ // sprites have been binned above
+ mbSpritesVisible = false;
+
+ // remove also from event multiplexer, we're dead anyway
+ mrEventMultiplexer.removeViewHandler( shared_from_this() );
+}
+
+bool SlideChangeBase::operator()( double nValue )
+{
+ if( mbFinished )
+ return false;
+
+ const std::size_t nEntries( maViewData.size() );
+ bool bSpritesVisible( mbSpritesVisible );
+
+ for( ::std::size_t i=0; i<nEntries; ++i )
+ {
+ // calc sprite offsets. The enter/leaving bitmaps are only
+ // as large as the actual slides. For scaled-down
+ // presentations, we have to move the left, top edge of
+ // those bitmaps to the actual position, governed by the
+ // given view transform. The aSpritePosPixel local
+ // variable is already in device coordinate space
+ // (i.e. pixel).
+
+ ViewEntry& rViewEntry( maViewData[i] );
+ const ::cppcanvas::CanvasSharedPtr& rCanvas( rViewEntry.mpView->getCanvas() );
+ ::cppcanvas::CustomSpriteSharedPtr& rInSprite( rViewEntry.mpInSprite );
+ ::cppcanvas::CustomSpriteSharedPtr& rOutSprite( rViewEntry.mpOutSprite );
+
+ // TODO(F2): Properly respect clip here.
+
+ // Might have to be transformed, too.
+ const ::basegfx::B2DHomMatrix aViewTransform(
+ rViewEntry.mpView->getTransformation() );
+ const ::basegfx::B2DPoint aSpritePosPixel(
+ aViewTransform * ::basegfx::B2DPoint() );
+
+ // move sprite to final output position, in
+ // device coordinates
+ if( rOutSprite )
+ rOutSprite->movePixel( aSpritePosPixel );
+ if( rInSprite )
+ rInSprite->movePixel( aSpritePosPixel );
+
+ if( !mbSpritesVisible )
+ {
+ if( rOutSprite )
+ {
+ // only render once: clipping is done
+ // exclusively with the sprite
+ const ::cppcanvas::CanvasSharedPtr pOutContentCanvas(
+ rOutSprite->getContentCanvas() );
+ if( pOutContentCanvas)
+ {
+ // TODO(Q2): Use basegfx bitmaps here
+
+ // TODO(F1): SlideBitmap is not fully portable
+ // between different canvases!
+
+ // render the content
+ OSL_ASSERT( getLeavingBitmap( rViewEntry ) );
+ if( getLeavingBitmap( rViewEntry ) )
+ getLeavingBitmap( rViewEntry )->draw( pOutContentCanvas );
+ }
+ }
+
+ if( rInSprite )
+ {
+ // only render once: clipping is done
+ // exclusively with the sprite
+ const ::cppcanvas::CanvasSharedPtr pInContentCanvas(
+ rInSprite->getContentCanvas() );
+ if( pInContentCanvas )
+ {
+ // TODO(Q2): Use basegfx bitmaps here
+
+ // TODO(F1): SlideBitmap is not fully portable
+ // between different canvases!
+
+ // render the content
+ getEnteringBitmap( rViewEntry )->draw( pInContentCanvas );
+ }
+ }
+ }
+
+ if( rOutSprite )
+ performOut( rOutSprite, rViewEntry, rCanvas, nValue );
+ if( rInSprite )
+ performIn( rInSprite, rViewEntry, rCanvas, nValue );
+
+ // finishing deeds for first run.
+ if( !mbSpritesVisible)
+ {
+ // enable sprites:
+ if( rOutSprite )
+ rOutSprite->show();
+ if( rInSprite )
+ rInSprite->show();
+ bSpritesVisible = true;
+ }
+ } // for_each( sprite )
+
+ mbSpritesVisible = bSpritesVisible;
+ mrScreenUpdater.notifyUpdate();
+
+ return true;
+}
+
+void SlideChangeBase::performIn(
+ const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
+ const ViewEntry& /*rViewEntry*/,
+ const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double /*t*/ )
+{
+}
+
+void SlideChangeBase::performOut(
+ const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
+ const ViewEntry& /*rViewEntry*/,
+ const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double /*t*/ )
+{
+}
+
+double SlideChangeBase::getUnderlyingValue() const
+{
+ return 0.0; // though this should be used in concert with
+ // ActivitiesFactory::createSimpleActivity, better
+ // explicitely name our start value.
+ // Permissible range for operator() above is [0,1]
+}
+
+void SlideChangeBase::viewAdded( const UnoViewSharedPtr& rView )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ maViewData.push_back( ViewEntry(rView) );
+
+ ViewEntry& rEntry( maViewData.back() );
+ getEnteringBitmap( rEntry );
+ getLeavingBitmap( rEntry );
+ addSprites( rEntry );
+}
+
+void SlideChangeBase::viewRemoved( const UnoViewSharedPtr& rView )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ // erase corresponding entry from maViewData
+ maViewData.erase(
+ std::remove_if(
+ maViewData.begin(),
+ maViewData.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( &ViewEntry::getView, _1 ))),
+ maViewData.end() );
+}
+
+void SlideChangeBase::viewChanged( const UnoViewSharedPtr& rView )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ // find entry corresponding to modified view
+ ViewsVecT::iterator aModifiedEntry(
+ std::find_if(
+ maViewData.begin(),
+ maViewData.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( &ViewEntry::getView, _1 ) )));
+
+ OSL_ASSERT( aModifiedEntry != maViewData.end() );
+ if( aModifiedEntry == maViewData.end() )
+ return;
+
+ // clear stale info (both bitmaps and sprites prolly need a
+ // resize)
+ clearViewEntry( *aModifiedEntry );
+ addSprites( *aModifiedEntry );
+}
+
+void SlideChangeBase::viewsChanged()
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ ViewsVecT::iterator aIter( maViewData.begin() );
+ ViewsVecT::iterator const aEnd ( maViewData.end() );
+ while( aIter != aEnd )
+ {
+ // clear stale info (both bitmaps and sprites prolly need a
+ // resize)
+ clearViewEntry( *aIter );
+ addSprites( *aIter );
+
+ ++aIter;
+ }
+}
+
+cppcanvas::CustomSpriteSharedPtr SlideChangeBase::createSprite(
+ UnoViewSharedPtr const & pView,
+ basegfx::B2DSize const & rSpriteSize,
+ double nPrio ) const
+{
+ // TODO(P2): change to bitmapsprite once that's working
+ const cppcanvas::CustomSpriteSharedPtr pSprite(
+ pView->createSprite( rSpriteSize,
+ nPrio ));
+
+ // alpha default is 0.0, which seems to be
+ // a bad idea when viewing content...
+ pSprite->setAlpha( 1.0 );
+ if (mbSpritesVisible)
+ pSprite->show();
+
+ return pSprite;
+}
+
+void SlideChangeBase::addSprites( ViewEntry& rEntry )
+{
+ if( mbCreateLeavingSprites && maLeavingSlide )
+ {
+ // create leaving sprite:
+ const basegfx::B2ISize leavingSlideSizePixel(
+ getLeavingBitmap( rEntry )->getSize() );
+
+ rEntry.mpOutSprite = createSprite( rEntry.mpView,
+ leavingSlideSizePixel,
+ 100 );
+ }
+
+ if( mbCreateEnteringSprites )
+ {
+ // create entering sprite:
+ const basegfx::B2ISize enteringSlideSizePixel(
+ getSlideSizePixel( mpEnteringSlide->getSlideSize(),
+ rEntry.mpView ));
+
+ rEntry.mpInSprite = createSprite( rEntry.mpView,
+ enteringSlideSizePixel,
+ 101 );
+ }
+}
+
+void SlideChangeBase::clearViewEntry( ViewEntry& rEntry )
+{
+ // clear stale info (both bitmaps and sprites prolly need a
+ // resize)
+ rEntry.mpEnteringBitmap.reset();
+ rEntry.mpLeavingBitmap.reset();
+ rEntry.mpInSprite.reset();
+ rEntry.mpOutSprite.reset();
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/slidechangebase.hxx b/slideshow/source/engine/transitions/slidechangebase.hxx
new file mode 100644
index 000000000000..98c437671722
--- /dev/null
+++ b/slideshow/source/engine/transitions/slidechangebase.hxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_TRANSITIONS_SLIDECHANGEBASE_HXX
+#define INCLUDED_SLIDESHOW_TRANSITIONS_SLIDECHANGEBASE_HXX
+
+#include <osl/mutex.hxx>
+
+#include "unoview.hxx"
+#include "vieweventhandler.hxx"
+#include "numberanimation.hxx"
+#include "slide.hxx"
+#include "screenupdater.hxx"
+#include "soundplayer.hxx"
+
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/optional.hpp>
+
+namespace cppcanvas
+{
+ class Canvas;
+ class CustomSprite;
+}
+
+namespace slideshow {
+namespace internal {
+
+/** Base class for all slide change effects.
+
+ This class provides the basic sprite and view handling
+ functionality. Derived classes should normally only need to
+ implement the perform() method.
+*/
+class SlideChangeBase : public ViewEventHandler,
+ public NumberAnimation,
+ public boost::enable_shared_from_this<SlideChangeBase>,
+ private ::boost::noncopyable
+{
+public:
+ // NumberAnimation
+ virtual bool operator()( double x );
+ virtual double getUnderlyingValue() const;
+
+ // Animation
+ virtual void prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& );
+ virtual void start( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& );
+ virtual void end();
+
+ // ViewEventHandler
+ virtual void viewAdded( const UnoViewSharedPtr& rView );
+ virtual void viewRemoved( const UnoViewSharedPtr& rView );
+ virtual void viewChanged( const UnoViewSharedPtr& rView );
+ virtual void viewsChanged();
+
+protected:
+ /** Create a new SlideChanger, for the given leaving and
+ entering slides.
+ */
+ SlideChangeBase(
+ ::boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ bool bCreateLeavingSprites = true,
+ bool bCreateEnteringSprites = true );
+
+ /// Info on a per-view basis
+ struct ViewEntry
+ {
+ ViewEntry() {}
+
+ explicit ViewEntry( const UnoViewSharedPtr& rView ) :
+ mpView( rView )
+ {
+ }
+
+ /// The view this entry is for
+ UnoViewSharedPtr mpView;
+ /// outgoing slide sprite
+ boost::shared_ptr<cppcanvas::CustomSprite> mpOutSprite;
+ /// incoming slide sprite
+ boost::shared_ptr<cppcanvas::CustomSprite> mpInSprite;
+ /// outgoing slide bitmap
+ mutable SlideBitmapSharedPtr mpLeavingBitmap;
+ /// incoming slide bitmap
+ mutable SlideBitmapSharedPtr mpEnteringBitmap;
+
+ // for algo access
+ const UnoViewSharedPtr& getView() const { return mpView; }
+ };
+
+ typedef ::std::vector<ViewEntry> ViewsVecT;
+
+ ViewsVecT::const_iterator beginViews() { return maViewData.begin(); }
+ ViewsVecT::const_iterator endViews() { return maViewData.end(); }
+
+ SlideBitmapSharedPtr getLeavingBitmap( const ViewEntry& rViewEntry ) const;
+ SlideBitmapSharedPtr getEnteringBitmap( const ViewEntry& rViewEntry ) const;
+
+ SlideBitmapSharedPtr createBitmap( const UnoViewSharedPtr& pView,
+ const boost::optional<SlideSharedPtr>& rSlide_ ) const;
+
+ ::basegfx::B2ISize getEnteringSlideSizePixel( const UnoViewSharedPtr& pView ) const;
+ ::basegfx::B2ISize getLeavingSlideSizePixel( const UnoViewSharedPtr& pView ) const;
+
+ void renderBitmap( SlideBitmapSharedPtr const& pSlideBitmap,
+ boost::shared_ptr<cppcanvas::Canvas> const& pCanvas );
+
+ /** Called on derived classes to implement actual slide change.
+
+ This method is called with the sprite of the slide coming 'in'
+
+ @param rSprite
+ Current sprite to operate on. This is the sprite of the
+ 'entering' slide
+
+ @param t
+ Current parameter value
+ */
+ virtual void performIn(
+ const boost::shared_ptr<cppcanvas::CustomSprite>& rSprite,
+ const ViewEntry& rViewEntry,
+ const boost::shared_ptr<cppcanvas::Canvas>& rDestinationCanvas,
+ double t );
+
+ /** Called on derived classes to implement actual slide change.
+
+ This method is called with the sprite of the slide moving 'out'
+
+ @param rSprite
+ Current sprite to operate on. This is the sprite of the
+ 'leaving' slide
+
+ @param t
+ Current parameter value
+ */
+ virtual void performOut(
+ const boost::shared_ptr<cppcanvas::CustomSprite>& rSprite,
+ const ViewEntry& rViewEntry,
+ const boost::shared_ptr<cppcanvas::Canvas>& rDestinationCanvas,
+ double t );
+
+ ScreenUpdater& getScreenUpdater() const { return mrScreenUpdater; }
+
+private:
+
+ boost::shared_ptr<cppcanvas::CustomSprite> createSprite(
+ UnoViewSharedPtr const & pView,
+ ::basegfx::B2DSize const & rSpriteSize,
+ double nPrio ) const;
+
+ void addSprites( ViewEntry& rEntry );
+ void clearViewEntry( ViewEntry& rEntry );
+
+ ViewsVecT::iterator lookupView( UnoViewSharedPtr const & pView );
+ ViewsVecT::const_iterator lookupView( UnoViewSharedPtr const & pView ) const;
+
+ SoundPlayerSharedPtr mpSoundPlayer;
+
+ EventMultiplexer& mrEventMultiplexer;
+ ScreenUpdater& mrScreenUpdater;
+
+ ::boost::optional<SlideSharedPtr> maLeavingSlide;
+ SlideSharedPtr mpEnteringSlide;
+
+ ViewsVecT maViewData;
+ const UnoViewContainer& mrViewContainer;
+
+ const bool mbCreateLeavingSprites;
+ const bool mbCreateEnteringSprites;
+ bool mbSpritesVisible;
+ bool mbFinished;
+ bool mbPrefetched;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif /* INCLUDED_SLIDESHOW_TRANSITIONS_SLIDECHANGEBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/slidetransitionfactory.cxx b/slideshow/source/engine/transitions/slidetransitionfactory.cxx
new file mode 100644
index 000000000000..42dc86ac8858
--- /dev/null
+++ b/slideshow/source/engine/transitions/slidetransitionfactory.cxx
@@ -0,0 +1,1168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include <comphelper/optional.hxx>
+#include <comphelper/make_shared_from_uno.hxx>
+
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include "slidechangebase.hxx"
+#include "transitionfactory.hxx"
+#include "transitiontools.hxx"
+#include "parametricpolypolygonfactory.hxx"
+#include "animationfactory.hxx"
+#include "clippingfunctor.hxx"
+#include "combtransition.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+
+
+/***************************************************
+ *** ***
+ *** Slide Transition Effects ***
+ *** ***
+ ***************************************************/
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+// helper methods
+// =============================================
+
+void fillPage( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const ::basegfx::B2DSize& rPageSizePixel,
+ const RGBColor& rFillColor )
+{
+ // need to render without any transformation (we
+ // assume rPageSizePixel to represent device units)
+ const ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
+ rDestinationCanvas->clone() );
+ pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // TODO(F2): Properly respect clip here.
+ // Might have to be transformed, too.
+ const ::basegfx::B2DHomMatrix aViewTransform(
+ rDestinationCanvas->getTransformation() );
+ const ::basegfx::B2DPoint aOutputPosPixel(
+ aViewTransform * ::basegfx::B2DPoint() );
+
+ fillRect( pDevicePixelCanvas,
+ ::basegfx::B2DRectangle(
+ aOutputPosPixel.getX(),
+ aOutputPosPixel.getY(),
+ aOutputPosPixel.getX() + rPageSizePixel.getX(),
+ aOutputPosPixel.getY() + rPageSizePixel.getY() ),
+ rFillColor.getIntegerColor() );
+}
+
+class PluginSlideChange: public SlideChangeBase
+{
+ struct TransitionViewPair {
+ uno::Reference<presentation::XTransition> mxTransition;
+ UnoViewSharedPtr mpView;
+
+ TransitionViewPair( uno::Reference<presentation::XTransition> xTransition, const UnoViewSharedPtr pView )
+ {
+ mxTransition = xTransition;
+ mpView = pView;
+ }
+
+ ~TransitionViewPair()
+ {
+ mxTransition.clear();
+ mpView.reset();;
+ }
+
+ void update( double t )
+ {
+ mxTransition->update( t );
+ }
+ };
+
+public:
+ /** Create a new SlideChanger, for the given leaving and
+ entering slide bitmaps, which uses super secret OpenGL
+ stuff.
+ */
+ PluginSlideChange( sal_Int16 nTransitionType,
+ sal_Int16 nTransitionSubType,
+ boost::optional<SlideSharedPtr> const& leavingSlide_,
+ const SlideSharedPtr& pEnteringSlide,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ const uno::Reference<
+ presentation::XTransitionFactory>& xFactory,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ EventMultiplexer& rEventMultiplexer) :
+ SlideChangeBase( leavingSlide_,
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer ),
+ maTransitions(),
+ mbSuccess( false ),
+ mnTransitionType( nTransitionType ),
+ mnTransitionSubType( nTransitionSubType ),
+ mxFactory( xFactory )
+ {
+ // create one transition per view
+ UnoViewVector::const_iterator aCurrView (rViewContainer.begin());
+ const UnoViewVector::const_iterator aEnd(rViewContainer.end());
+ while( aCurrView != aEnd )
+ {
+ if(! addTransition( *aCurrView ) )
+ return;
+
+ ENSURE_OR_THROW(maTransitions.back() && maTransitions.back()->mxTransition.is(),
+ "Failed to create plugin transition");
+ ++aCurrView;
+ }
+ mbSuccess = true;
+ }
+
+ ~PluginSlideChange()
+ {
+ mxFactory.clear();
+
+ ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
+ ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
+ while( aCurrView != aEnd )
+ {
+ delete (*aCurrView);
+ ++aCurrView;
+ }
+ maTransitions.clear();
+ }
+
+ bool addTransition( const UnoViewSharedPtr& rView )
+ {
+ uno::Reference<presentation::XTransition> rTransition = mxFactory->createTransition(
+ mnTransitionType,
+ mnTransitionSubType,
+ rView->getUnoView(),
+ getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
+ getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
+
+ if( rTransition.is() )
+ maTransitions.push_back( new TransitionViewPair( rTransition, rView ) );
+ else
+ return false;
+
+ return true;
+ }
+
+ virtual bool operator()( double t )
+ {
+ std::for_each(maTransitions.begin(),
+ maTransitions.end(),
+ boost::bind( &TransitionViewPair::update,
+ _1, t) );
+ return true;
+ }
+
+ bool Success()
+ {
+ return mbSuccess;
+ }
+
+ // ViewEventHandler
+ virtual void viewAdded( const UnoViewSharedPtr& rView )
+ {
+ OSL_TRACE("PluginSlideChange viewAdded");
+ SlideChangeBase::viewAdded( rView );
+
+ ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
+ ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
+ bool bKnown = false;
+ while( aCurrView != aEnd )
+ {
+ if( (*aCurrView)->mpView == rView ) {
+ bKnown = true;
+ break;
+ }
+ ++aCurrView;
+ }
+
+ if( !bKnown ) {
+ OSL_TRACE("need to be added");
+
+ addTransition( rView );
+ }
+ }
+
+ virtual void viewRemoved( const UnoViewSharedPtr& rView )
+ {
+ OSL_TRACE("PluginSlideChange viewRemoved");
+ SlideChangeBase::viewRemoved( rView );
+
+ ::std::vector< TransitionViewPair* >::iterator aCurrView (maTransitions.begin());
+ ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
+ while( aCurrView != aEnd )
+ {
+ if( (*aCurrView)->mpView == rView ) {
+ OSL_TRACE( "view removed" );
+ delete (*aCurrView);
+ maTransitions.erase( aCurrView );
+ break;
+ }
+ ++aCurrView;
+ }
+ }
+
+ virtual void viewChanged( const UnoViewSharedPtr& rView )
+ {
+ OSL_TRACE("PluginSlideChange viewChanged");
+ SlideChangeBase::viewChanged( rView );
+
+ ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
+ ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
+ while( aCurrView != aEnd )
+ {
+ if( (*aCurrView)->mpView == rView ) {
+ OSL_TRACE( "view changed" );
+ (*aCurrView)->mxTransition->viewChanged( rView->getUnoView(),
+ getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
+ getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
+ } else
+ OSL_TRACE( "view did not changed" );
+
+ ++aCurrView;
+ }
+ }
+
+ virtual void viewsChanged()
+ {
+ OSL_TRACE("PluginSlideChange viewsChanged");
+ SlideChangeBase::viewsChanged();
+
+ ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
+ ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
+ while( aCurrView != aEnd )
+ {
+ OSL_TRACE( "view changed" );
+ (*aCurrView)->mxTransition->viewChanged( (*aCurrView)->mpView->getUnoView(),
+ getLeavingBitmap(ViewEntry((*aCurrView)->mpView))->getXBitmap(),
+ getEnteringBitmap(ViewEntry((*aCurrView)->mpView))->getXBitmap() );
+ ++aCurrView;
+ }
+ }
+
+private:
+ // One transition object per view
+ std::vector< TransitionViewPair* > maTransitions;
+
+ // bool
+ bool mbSuccess;
+
+ sal_Int16 mnTransitionType;
+ sal_Int16 mnTransitionSubType;
+
+ uno::Reference<presentation::XTransitionFactory> mxFactory;
+};
+
+class ClippedSlideChange : public SlideChangeBase
+{
+public:
+ /** Create a new SlideChanger, for the given leaving and
+ entering slide bitmaps, which applies the given clip
+ polygon.
+ */
+ ClippedSlideChange(
+ const SlideSharedPtr& pEnteringSlide,
+ const ParametricPolyPolygonSharedPtr& rPolygon,
+ const TransitionInfo& rTransitionInfo,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ bool bDirectionForward,
+ const SoundPlayerSharedPtr& pSoundPlayer ) :
+ SlideChangeBase(
+ // leaving bitmap is empty, we're leveraging the fact that the
+ // old slide is still displayed in the background:
+ boost::optional<SlideSharedPtr>(),
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer ),
+ maClippingFunctor( rPolygon,
+ rTransitionInfo,
+ bDirectionForward,
+ true )
+ {}
+
+ virtual void performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+
+ virtual void performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+
+private:
+ ClippingFunctor maClippingFunctor;
+};
+
+void ClippedSlideChange::performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double t )
+{
+ // #i46602# Better work in device coordinate space here,
+ // otherwise, we too easily suffer from roundoffs. Apart from
+ // that, getEnteringSizePixel() _guarantees_ to cover the whole
+ // slide bitmap. There's a catch, though: this removes any effect
+ // of the view transformation (e.g. rotation) from the transition.
+ rSprite->setClipPixel(
+ maClippingFunctor( t,
+ getEnteringSlideSizePixel(rViewEntry.mpView) ) );
+}
+
+void ClippedSlideChange::performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
+ const ViewEntry& /*rViewEntry*/,
+ const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double /*t*/ )
+{
+ // not needed here
+}
+
+
+class FadingSlideChange : public SlideChangeBase
+{
+public:
+ /** Create a new SlideChanger, for the given leaving and
+ entering slides, which applies a fade effect.
+ */
+ FadingSlideChange(
+ boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ boost::optional<RGBColor> const& rFadeColor,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer )
+ : SlideChangeBase( leavingSlide,
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer ),
+ maFadeColor( rFadeColor ),
+ mbFirstTurn( true )
+ {}
+
+ virtual void performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+
+ virtual void performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+
+private:
+ const boost::optional< RGBColor > maFadeColor;
+ bool mbFirstTurn;
+};
+
+void FadingSlideChange::performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& /*rViewEntry*/,
+ const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double t )
+{
+ ENSURE_OR_THROW(
+ rSprite,
+ "FadingSlideChange::performIn(): Invalid sprite" );
+
+ if( maFadeColor )
+ // After half of the active time, fade in new slide
+ rSprite->setAlpha( t > 0.5 ? 2.0*(t-0.5) : 0.0 );
+ else
+ // Fade in new slide over full active time
+ rSprite->setAlpha( t );
+}
+
+void FadingSlideChange::performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t )
+{
+ ENSURE_OR_THROW(
+ rSprite,
+ "FadingSlideChange::performOut(): Invalid sprite" );
+ ENSURE_OR_THROW(
+ rDestinationCanvas,
+ "FadingSlideChange::performOut(): Invalid dest canvas" );
+
+ // only needed for color fades
+ if( maFadeColor )
+ {
+ if( mbFirstTurn )
+ {
+ mbFirstTurn = false;
+
+ // clear page to given fade color. 'Leaving' slide is
+ // painted atop of that, but slowly fading out.
+ fillPage( rDestinationCanvas,
+ getEnteringSlideSizePixel( rViewEntry.mpView ),
+ *maFadeColor );
+ }
+
+ // Until half of the active time, fade out old
+ // slide. After half of the active time, old slide
+ // will be invisible.
+ rSprite->setAlpha( t > 0.5 ? 0.0 : 2.0*(0.5-t) );
+ }
+}
+
+class CutSlideChange : public SlideChangeBase
+{
+public:
+ /** Create a new SlideChanger, for the given leaving and
+ entering slides, which applies a cut effect.
+ */
+ CutSlideChange(
+ boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const RGBColor& rFadeColor,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer )
+ : SlideChangeBase( leavingSlide,
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer ),
+ maFadeColor( rFadeColor ),
+ mbFirstTurn( true )
+ {}
+
+ virtual void performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+
+ virtual void performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+
+private:
+ RGBColor maFadeColor;
+ bool mbFirstTurn;
+};
+
+void CutSlideChange::performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& /*rViewEntry*/,
+ const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double t )
+{
+ ENSURE_OR_THROW(
+ rSprite,
+ "CutSlideChange::performIn(): Invalid sprite" );
+
+ // After 2/3rd of the active time, display new slide
+ rSprite->setAlpha( t > 2/3.0 ? 1.0 : 0.0 );
+}
+
+void CutSlideChange::performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t )
+{
+ ENSURE_OR_THROW(
+ rSprite,
+ "CutSlideChange::performOut(): Invalid sprite" );
+ ENSURE_OR_THROW(
+ rDestinationCanvas,
+ "FadingSlideChange::performOut(): Invalid dest canvas" );
+
+ if( mbFirstTurn )
+ {
+ mbFirstTurn = false;
+
+ // clear page to given fade color. 'Leaving' slide is
+ // painted atop of that
+ fillPage( rDestinationCanvas,
+ getEnteringSlideSizePixel( rViewEntry.mpView ),
+ maFadeColor );
+ }
+
+ // Until 1/3rd of the active time, display old slide.
+ rSprite->setAlpha( t > 1/3.0 ? 0.0 : 1.0 );
+}
+
+class MovingSlideChange : public SlideChangeBase
+{
+ /// Direction vector for leaving slide,
+ const ::basegfx::B2DVector maLeavingDirection;
+
+ /// Direction vector for entering slide,
+ const ::basegfx::B2DVector maEnteringDirection;
+
+ bool mbFirstPerformCall;
+
+public:
+ /** Create a new SlideChanger, for the given entering slide
+ bitmaps, which performes a moving slide change effect
+
+ @param rLeavingDirection
+ Direction vector. The move is performed along this
+ direction vector, starting at a position where the leaving
+ slide is fully visible, and ending at a position where the
+ leaving slide is just not visible. The vector must have
+ unit length.
+
+ @param rEnteringDirection
+ Direction vector. The move is performed along this
+ direction vector, starting at a position where the
+ entering slide is just not visible, and ending at the
+ final slide position. The vector must have unit length.
+ */
+ MovingSlideChange(
+ const boost::optional<SlideSharedPtr>& leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ const ::basegfx::B2DVector& rLeavingDirection,
+ const ::basegfx::B2DVector& rEnteringDirection )
+ : SlideChangeBase(
+ leavingSlide, pEnteringSlide, pSoundPlayer,
+ rViewContainer, rScreenUpdater, rEventMultiplexer,
+ // Optimization: when leaving bitmap is given,
+ // but it does not move, don't create sprites for it,
+ // we simply paint it once at startup:
+ !rLeavingDirection.equalZero() /* bCreateLeavingSprites */,
+ !rEnteringDirection.equalZero() /* bCreateEnteringSprites */ ),
+ // TODO(F1): calc correct length of direction
+ // vector. Directions not strictly horizontal or vertical
+ // must travel a longer distance.
+ maLeavingDirection( rLeavingDirection ),
+ // TODO(F1): calc correct length of direction
+ // vector. Directions not strictly horizontal or vertical
+ // must travel a longer distance.
+ maEnteringDirection( rEnteringDirection ),
+ mbFirstPerformCall( true )
+ {}
+
+ virtual void performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+
+ virtual void performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t );
+};
+
+void MovingSlideChange::performIn(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t )
+{
+ // intro sprite moves:
+
+ ENSURE_OR_THROW(
+ rSprite,
+ "MovingSlideChange::performIn(): Invalid sprite" );
+ ENSURE_OR_THROW(
+ rDestinationCanvas,
+ "MovingSlideChange::performIn(): Invalid dest canvas" );
+
+ if (mbFirstPerformCall && maLeavingDirection.equalZero())
+ {
+ mbFirstPerformCall = false;
+ renderBitmap( getLeavingBitmap(rViewEntry), rDestinationCanvas );
+ }
+
+ // TODO(F1): This does not account for non-translational
+ // transformations! If the canvas is rotated, we still
+ // move the sprite unrotated (which might or might not
+ // produce the intended effect).
+ const basegfx::B2DHomMatrix aViewTransform(
+ rDestinationCanvas->getTransformation() );
+ const basegfx::B2DPoint aPageOrigin(
+ aViewTransform * basegfx::B2DPoint() );
+
+ // move sprite
+ rSprite->movePixel(
+ aPageOrigin +
+ ((t - 1.0) *
+ ::basegfx::B2DSize( getEnteringSlideSizePixel(rViewEntry.mpView) ) *
+ maEnteringDirection) );
+}
+
+void MovingSlideChange::performOut(
+ const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
+ const ViewEntry& rViewEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ double t )
+{
+ // outro sprite moves:
+
+ ENSURE_OR_THROW(
+ rSprite,
+ "MovingSlideChange::performOut(): Invalid sprite" );
+ ENSURE_OR_THROW(
+ rDestinationCanvas,
+ "MovingSlideChange::performOut(): Invalid dest canvas" );
+
+ if (mbFirstPerformCall && maEnteringDirection.equalZero())
+ {
+ mbFirstPerformCall = false;
+ renderBitmap( getEnteringBitmap(rViewEntry), rDestinationCanvas );
+ }
+
+ // TODO(F1): This does not account for non-translational
+ // transformations! If the canvas is rotated, we still
+ // move the sprite unrotated (which might or might not
+ // produce the intended effect).
+ const basegfx::B2DHomMatrix aViewTransform(
+ rDestinationCanvas->getTransformation() );
+ const basegfx::B2DPoint aPageOrigin(
+ aViewTransform * basegfx::B2DPoint() );
+
+ // move sprite
+ rSprite->movePixel(
+ aPageOrigin + (t *
+ ::basegfx::B2DSize( getEnteringSlideSizePixel(rViewEntry.mpView) ) *
+ maLeavingDirection) );
+}
+
+
+NumberAnimationSharedPtr createPushWipeTransition(
+ boost::optional<SlideSharedPtr> const & leavingSlide_,
+ const SlideSharedPtr& pEnteringSlide,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ sal_Int16 /*nTransitionType*/,
+ sal_Int16 nTransitionSubType,
+ bool /*bTransitionDirection*/,
+ const SoundPlayerSharedPtr& pSoundPlayer )
+{
+ boost::optional<SlideSharedPtr> leavingSlide; // no bitmap
+ if (leavingSlide_ && (*leavingSlide_).get() != 0)
+ {
+ // opt: only page, if we've an
+ // actual slide to move out here. We
+ // _don't_ need a fake black background
+ // bitmap, neither for push nor for comb
+ // wipes.
+ leavingSlide = leavingSlide_;
+ }
+
+ // setup direction vector
+ bool bComb( false );
+ ::basegfx::B2DVector aDirection;
+ switch( nTransitionSubType )
+ {
+ default:
+ OSL_FAIL(
+ "createPushWipeTransition(): Unexpected transition "
+ "subtype for animations::TransitionType::PUSHWIPE "
+ "transitions" );
+ return NumberAnimationSharedPtr();
+
+ case animations::TransitionSubType::FROMTOP:
+ aDirection = ::basegfx::B2DVector( 0.0, 1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMBOTTOM:
+ aDirection = ::basegfx::B2DVector( 0.0, -1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMLEFT:
+ aDirection = ::basegfx::B2DVector( 1.0, 0.0 );
+ break;
+
+ case animations::TransitionSubType::FROMRIGHT:
+ aDirection = ::basegfx::B2DVector( -1.0, 0.0 );
+ break;
+
+ case animations::TransitionSubType::FROMBOTTOMRIGHT:
+ aDirection = ::basegfx::B2DVector( -1.0, -1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMBOTTOMLEFT:
+ aDirection = ::basegfx::B2DVector( 1.0, -1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMTOPRIGHT:
+ aDirection = ::basegfx::B2DVector( -1.0, 1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMTOPLEFT:
+ aDirection = ::basegfx::B2DVector( 1.0, 1.0 );
+ break;
+
+ case animations::TransitionSubType::COMBHORIZONTAL:
+ aDirection = ::basegfx::B2DVector( 1.0, 0.0 );
+ bComb = true;
+ break;
+
+ case animations::TransitionSubType::COMBVERTICAL:
+ aDirection = ::basegfx::B2DVector( 0.0, 1.0 );
+ bComb = true;
+ break;
+ }
+
+ if( bComb )
+ {
+ return NumberAnimationSharedPtr(
+ new CombTransition( leavingSlide,
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ aDirection,
+ 24 /* comb with 12 stripes */ ));
+ }
+ else
+ {
+ return NumberAnimationSharedPtr(
+ new MovingSlideChange( leavingSlide,
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ aDirection,
+ aDirection ));
+ }
+}
+
+NumberAnimationSharedPtr createSlideWipeTransition(
+ boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ sal_Int16 /*nTransitionType*/,
+ sal_Int16 nTransitionSubType,
+ bool bTransitionDirection,
+ const SoundPlayerSharedPtr& pSoundPlayer )
+{
+ // setup 'in' direction vector
+ ::basegfx::B2DVector aInDirection;
+ switch( nTransitionSubType )
+ {
+ default:
+ OSL_FAIL(
+ "createSlideWipeTransition(): Unexpected transition "
+ "subtype for animations::TransitionType::SLIDEWIPE "
+ "transitions" );
+ return NumberAnimationSharedPtr();
+
+ case animations::TransitionSubType::FROMTOP:
+ aInDirection = ::basegfx::B2DVector( 0.0, 1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMRIGHT:
+ aInDirection = ::basegfx::B2DVector( -1.0, 0.0 );
+ break;
+
+ case animations::TransitionSubType::FROMLEFT:
+ aInDirection = ::basegfx::B2DVector( 1.0, 0.0 );
+ break;
+
+ case animations::TransitionSubType::FROMBOTTOM:
+ aInDirection = ::basegfx::B2DVector( 0.0, -1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMBOTTOMRIGHT:
+ aInDirection = ::basegfx::B2DVector( -1.0, -1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMBOTTOMLEFT:
+ aInDirection = ::basegfx::B2DVector( 1.0, -1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMTOPRIGHT:
+ aInDirection = ::basegfx::B2DVector( -1.0, 1.0 );
+ break;
+
+ case animations::TransitionSubType::FROMTOPLEFT:
+ aInDirection = ::basegfx::B2DVector( 1.0, 1.0 );
+ break;
+ }
+
+ if( bTransitionDirection )
+ {
+ // normal, 'forward' slide wipe effect. Since the old
+ // content is still on screen (and does not move), we omit
+ // the 'leaving' slide.
+ // =======================================================
+
+ return NumberAnimationSharedPtr(
+ new MovingSlideChange(
+ boost::optional<SlideSharedPtr>() /* no slide */,
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ basegfx::B2DVector(),
+ aInDirection ));
+ }
+ else
+ {
+ // 'reversed' slide wipe effect. Reverse for slide wipes
+ // means, that the new slide is in the back, statically,
+ // and the old one is moving off in the foreground.
+ // =======================================================
+
+ return NumberAnimationSharedPtr(
+ new MovingSlideChange( leavingSlide,
+ pEnteringSlide,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ aInDirection,
+ basegfx::B2DVector() ));
+ }
+}
+
+NumberAnimationSharedPtr createPluginTransition(
+ sal_Int16 nTransitionType,
+ sal_Int16 nTransitionSubType,
+ boost::optional<SlideSharedPtr> const& pLeavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ const uno::Reference<
+ presentation::XTransitionFactory>& xFactory,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ EventMultiplexer& rEventMultiplexer)
+{
+ PluginSlideChange* pTransition =
+ new PluginSlideChange(
+ nTransitionType,
+ nTransitionSubType,
+ pLeavingSlide,
+ pEnteringSlide,
+ rViewContainer,
+ rScreenUpdater,
+ xFactory,
+ pSoundPlayer,
+ rEventMultiplexer );
+
+ if( pTransition->Success() )
+ return NumberAnimationSharedPtr( pTransition );
+ else {
+ delete pTransition;
+ return NumberAnimationSharedPtr();
+ }
+}
+
+} // anon namespace
+
+
+NumberAnimationSharedPtr TransitionFactory::createSlideTransition(
+ const SlideSharedPtr& pLeavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ const uno::Reference<presentation::XTransitionFactory>& xOptionalFactory,
+ sal_Int16 nTransitionType,
+ sal_Int16 nTransitionSubType,
+ bool bTransitionDirection,
+ const RGBColor& rTransitionFadeColor,
+ const SoundPlayerSharedPtr& pSoundPlayer )
+{
+ // xxx todo: change to TransitionType::NONE, TransitionSubType::NONE:
+ if (nTransitionType == 0 && nTransitionSubType == 0) {
+ // just play sound, no slide transition:
+ if (pSoundPlayer) {
+ pSoundPlayer->startPlayback();
+ // xxx todo: for now, presentation.cxx takes care about the slide
+ // #i50492# transition sound object, so just release it here
+ }
+ return NumberAnimationSharedPtr();
+ }
+
+ ENSURE_OR_THROW(
+ pEnteringSlide,
+ "TransitionFactory::createSlideTransition(): Invalid entering slide" );
+
+ if( xOptionalFactory.is() &&
+ xOptionalFactory->hasTransition(nTransitionType, nTransitionSubType) )
+ {
+ // #i82460# - optional plugin factory claims this transition. delegate.
+ NumberAnimationSharedPtr pTransition(
+ createPluginTransition(
+ nTransitionType,
+ nTransitionSubType,
+ comphelper::make_optional(pLeavingSlide),
+ pEnteringSlide,
+ rViewContainer,
+ rScreenUpdater,
+ xOptionalFactory,
+ pSoundPlayer,
+ rEventMultiplexer ));
+
+ if( pTransition.get() )
+ return pTransition;
+ }
+
+ const TransitionInfo* pTransitionInfo(
+ getTransitionInfo( nTransitionType, nTransitionSubType ) );
+
+ if( pTransitionInfo != NULL )
+ {
+ switch( pTransitionInfo->meTransitionClass )
+ {
+ default:
+ case TransitionInfo::TRANSITION_INVALID:
+ OSL_TRACE(
+ "TransitionFactory::createSlideTransition(): "
+ "Invalid type/subtype (%d/%d) combination encountered.",
+ nTransitionType,
+ nTransitionSubType );
+ return NumberAnimationSharedPtr();
+
+
+ case TransitionInfo::TRANSITION_CLIP_POLYPOLYGON:
+ {
+ // generate parametric poly-polygon
+ ParametricPolyPolygonSharedPtr pPoly(
+ ParametricPolyPolygonFactory::createClipPolyPolygon(
+ nTransitionType, nTransitionSubType ) );
+
+ // create a clip transition from that
+ return NumberAnimationSharedPtr(
+ new ClippedSlideChange( pEnteringSlide,
+ pPoly,
+ *pTransitionInfo,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ bTransitionDirection,
+ pSoundPlayer ));
+ }
+
+ case TransitionInfo::TRANSITION_SPECIAL:
+ {
+ switch( nTransitionType )
+ {
+ default:
+ OSL_FAIL(
+ "TransitionFactory::createSlideTransition(): "
+ "Unexpected transition type for "
+ "TRANSITION_SPECIAL transitions" );
+ return NumberAnimationSharedPtr();
+
+ case animations::TransitionType::RANDOM:
+ {
+ // select randomly one of the effects from the
+ // TransitionFactoryTable
+
+ const TransitionInfo* pRandomTransitionInfo(
+ getRandomTransitionInfo() );
+
+ ENSURE_OR_THROW(
+ pRandomTransitionInfo != NULL,
+ "TransitionFactory::createSlideTransition(): "
+ "Got invalid random transition info" );
+
+ ENSURE_OR_THROW(
+ pRandomTransitionInfo->mnTransitionType !=
+ animations::TransitionType::RANDOM,
+ "TransitionFactory::createSlideTransition(): "
+ "Got random again for random input!" );
+
+ // and recurse
+ return createSlideTransition(
+ pLeavingSlide,
+ pEnteringSlide,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ xOptionalFactory,
+ pRandomTransitionInfo->mnTransitionType,
+ pRandomTransitionInfo->mnTransitionSubType,
+ bTransitionDirection,
+ rTransitionFadeColor,
+ pSoundPlayer );
+ }
+
+ case animations::TransitionType::PUSHWIPE:
+ {
+ return createPushWipeTransition(
+ comphelper::make_optional(pLeavingSlide),
+ pEnteringSlide,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ nTransitionType,
+ nTransitionSubType,
+ bTransitionDirection,
+ pSoundPlayer );
+ }
+
+ case animations::TransitionType::SLIDEWIPE:
+ {
+ return createSlideWipeTransition(
+ comphelper::make_optional(pLeavingSlide),
+ pEnteringSlide,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer,
+ nTransitionType,
+ nTransitionSubType,
+ bTransitionDirection,
+ pSoundPlayer );
+ }
+
+ case animations::TransitionType::BARWIPE:
+ case animations::TransitionType::FADE:
+ {
+ // black page:
+ boost::optional<SlideSharedPtr> leavingSlide;
+
+ switch( nTransitionSubType )
+ {
+ case animations::TransitionSubType::CROSSFADE:
+ // crossfade needs no further setup,
+ // just blend new slide over existing
+ // background.
+ break;
+
+ // TODO(F1): Implement toColor/fromColor fades
+ case animations::TransitionSubType::FADETOCOLOR:
+ // FALLTHROUGH intended
+ case animations::TransitionSubType::FADEFROMCOLOR:
+ // FALLTHROUGH intended
+ case animations::TransitionSubType::FADEOVERCOLOR:
+ if (pLeavingSlide) {
+ // only generate, if fade
+ // effect really needs it.
+ leavingSlide.reset( pLeavingSlide );
+ }
+ break;
+
+ default:
+ ENSURE_OR_THROW( false,
+ "SlideTransitionFactory::createSlideTransition(): Unknown FADE subtype" );
+ }
+
+ if( nTransitionType == animations::TransitionType::FADE )
+ return NumberAnimationSharedPtr(
+ new FadingSlideChange(
+ leavingSlide,
+ pEnteringSlide,
+ comphelper::make_optional(
+ rTransitionFadeColor),
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer ));
+ else
+ return NumberAnimationSharedPtr(
+ new CutSlideChange(
+ leavingSlide,
+ pEnteringSlide,
+ rTransitionFadeColor,
+ pSoundPlayer,
+ rViewContainer,
+ rScreenUpdater,
+ rEventMultiplexer ));
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ // No animation generated, maybe no table entry for given
+ // transition?
+ OSL_TRACE(
+ "TransitionFactory::createSlideTransition(): "
+ "Unknown type/subtype (%d/%d) combination encountered",
+ nTransitionType,
+ nTransitionSubType );
+ OSL_FAIL(
+ "TransitionFactory::createSlideTransition(): "
+ "Unknown type/subtype combination encountered" );
+
+ return NumberAnimationSharedPtr();
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/snakewipe.cxx b/slideshow/source/engine/transitions/snakewipe.cxx
new file mode 100644
index 000000000000..a93e80430af8
--- /dev/null
+++ b/slideshow/source/engine/transitions/snakewipe.cxx
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "snakewipe.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+SnakeWipe::SnakeWipe( sal_Int32 nElements, bool diagonal, bool flipOnYAxis )
+ : m_sqrtElements( static_cast<sal_Int32>(
+ sqrt( static_cast<double>(nElements) ) ) ),
+ m_elementEdge( 1.0 / m_sqrtElements ),
+ m_diagonal(diagonal),
+ m_flipOnYAxis(flipOnYAxis)
+{
+}
+
+::basegfx::B2DPolyPolygon SnakeWipe::calcSnake( double t ) const
+{
+ ::basegfx::B2DPolyPolygon res;
+ const double area = (t * m_sqrtElements * m_sqrtElements);
+ const sal_Int32 line_ = (static_cast<sal_Int32>(area) / m_sqrtElements);
+ const double line = ::basegfx::pruneScaleValue(
+ static_cast<double>(line_) / m_sqrtElements );
+ const double col = ::basegfx::pruneScaleValue(
+ (area - (line_ * m_sqrtElements)) / m_sqrtElements );
+
+ if (! ::basegfx::fTools::equalZero( line )) {
+ ::basegfx::B2DPolygon poly;
+ poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
+ poly.append( ::basegfx::B2DPoint( 0.0, line ) );
+ poly.append( ::basegfx::B2DPoint( 1.0, line ) );
+ poly.append( ::basegfx::B2DPoint( 1.0, 0.0 ) );
+ poly.setClosed(true);
+ res.append(poly);
+ }
+ if (! ::basegfx::fTools::equalZero( col ))
+ {
+ double offset = 0.0;
+ if ((line_ & 1) == 1) {
+ // odd line: => right to left
+ offset = (1.0 - col);
+ }
+ ::basegfx::B2DPolygon poly;
+ poly.append( ::basegfx::B2DPoint( offset, line ) );
+ poly.append( ::basegfx::B2DPoint( offset,
+ line + m_elementEdge ) );
+ poly.append( ::basegfx::B2DPoint( offset + col,
+ line + m_elementEdge ) );
+ poly.append( ::basegfx::B2DPoint( offset + col, line ) );
+ poly.setClosed(true);
+ res.append(poly);
+ }
+
+ return res;
+}
+
+::basegfx::B2DPolyPolygon SnakeWipe::calcHalfDiagonalSnake(
+ double t, bool in ) const
+{
+ ::basegfx::B2DPolyPolygon res;
+
+ if (in) {
+ const double sqrtArea2 = sqrt( t * m_sqrtElements * m_sqrtElements );
+ const double edge = ::basegfx::pruneScaleValue(
+ static_cast<double>( static_cast<sal_Int32>(sqrtArea2) ) /
+ m_sqrtElements );
+
+ ::basegfx::B2DPolygon poly;
+ if (! ::basegfx::fTools::equalZero( edge )) {
+ poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
+ poly.append( ::basegfx::B2DPoint( 0.0, edge ) );
+ poly.append( ::basegfx::B2DPoint( edge, 0.0 ) );
+ poly.setClosed(true);
+ res.append(poly);
+ }
+ const double a = (M_SQRT1_2 / m_sqrtElements);
+ const double d = (sqrtArea2 - static_cast<sal_Int32>(sqrtArea2));
+ const double len = (t * M_SQRT2 * d);
+ const double height = ::basegfx::pruneScaleValue( M_SQRT1_2 / m_sqrtElements );
+ poly.clear();
+ poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
+ poly.append( ::basegfx::B2DPoint( 0.0, height ) );
+ poly.append( ::basegfx::B2DPoint( len + a, height ) );
+ poly.append( ::basegfx::B2DPoint( len + a, 0.0 ) );
+ poly.setClosed(true);
+ ::basegfx::B2DHomMatrix aTransform;
+
+ if ((static_cast<sal_Int32>(sqrtArea2) & 1) == 1)
+ {
+ // odd line
+ aTransform = basegfx::tools::createRotateB2DHomMatrix(M_PI_2 + M_PI_4);
+ aTransform.translate(edge + m_elementEdge, 0.0);
+ }
+ else
+ {
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(-a, 0.0);
+ aTransform.rotate( -M_PI_4 );
+ aTransform.translate( 0.0, edge );
+ }
+
+ poly.transform( aTransform );
+ res.append(poly);
+ }
+ else // out
+ {
+ const double sqrtArea2 = sqrt( t * m_sqrtElements * m_sqrtElements );
+ const double edge = ::basegfx::pruneScaleValue(
+ static_cast<double>( static_cast<sal_Int32>(sqrtArea2) ) /
+ m_sqrtElements );
+
+ ::basegfx::B2DPolygon poly;
+ if (! ::basegfx::fTools::equalZero( edge )) {
+ poly.append( ::basegfx::B2DPoint( 0.0, 1.0 ) );
+ poly.append( ::basegfx::B2DPoint( edge, 1.0 ) );
+ poly.append( ::basegfx::B2DPoint( 1.0, edge ) );
+ poly.append( ::basegfx::B2DPoint( 1.0, 0.0 ) );
+ poly.setClosed(true);
+ res.append(poly);
+ }
+ const double a = (M_SQRT1_2 / m_sqrtElements);
+ const double d = (sqrtArea2 - static_cast<sal_Int32>(sqrtArea2));
+ const double len = ((1.0 - t) * M_SQRT2 * d);
+ const double height = ::basegfx::pruneScaleValue( M_SQRT1_2 / m_sqrtElements );
+ poly.clear();
+ poly.append( ::basegfx::B2DPoint( 0.0, 0.0 ) );
+ poly.append( ::basegfx::B2DPoint( 0.0, height ) );
+ poly.append( ::basegfx::B2DPoint( len + a, height ) );
+ poly.append( ::basegfx::B2DPoint( len + a, 0.0 ) );
+ poly.setClosed(true);
+ ::basegfx::B2DHomMatrix aTransform;
+
+ if ((static_cast<sal_Int32>(sqrtArea2) & 1) == 1)
+ {
+ // odd line
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(0.0, -height);
+ aTransform.rotate( M_PI_2 + M_PI_4 );
+ aTransform.translate( 1.0, edge );
+ }
+ else
+ {
+ aTransform = basegfx::tools::createRotateB2DHomMatrix(-M_PI_4);
+ aTransform.translate( edge, 1.0 );
+ }
+ poly.transform( aTransform );
+ res.append(poly);
+ }
+
+ return res;
+}
+
+::basegfx::B2DPolyPolygon SnakeWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res;
+ if (m_diagonal)
+ {
+ if (t >= 0.5) {
+ res.append( calcHalfDiagonalSnake( 1.0, true ) );
+ res.append( calcHalfDiagonalSnake( 2.0 * (t - 0.5), false ) );
+ }
+ else
+ res.append( calcHalfDiagonalSnake( 2.0 * t, true ) );
+ }
+ else
+ res = calcSnake(t);
+
+ return m_flipOnYAxis ? flipOnYAxis(res) : res;
+}
+
+::basegfx::B2DPolyPolygon ParallelSnakesWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res;
+ if (m_diagonal)
+ {
+ OSL_ASSERT( m_opposite );
+ ::basegfx::B2DPolyPolygon half(
+ calcHalfDiagonalSnake( t, false /* out */ ) );
+ // flip on x axis and rotate 90 degrees:
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createScaleB2DHomMatrix(1.0, -1.0));
+ aTransform.translate( -0.5, 0.5 );
+ aTransform.rotate( M_PI_2 );
+ aTransform.translate( 0.5, 0.5 );
+ half.transform( aTransform );
+ half.flip();
+ res.append( half );
+
+ // rotate 180 degrees:
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5);
+ aTransform.rotate( M_PI );
+ aTransform.translate( 0.5, 0.5 );
+ half.transform( aTransform );
+ res.append( half );
+ }
+ else
+ {
+ ::basegfx::B2DPolyPolygon half( calcSnake( t / 2.0 ) );
+ // rotate 90 degrees:
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5));
+ aTransform.rotate( M_PI_2 );
+ aTransform.translate( 0.5, 0.5 );
+ half.transform( aTransform );
+ res.append( flipOnYAxis(half) );
+ res.append( m_opposite ? flipOnXAxis(half) : half );
+ }
+
+ return m_flipOnYAxis ? flipOnYAxis(res) : res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/snakewipe.hxx b/slideshow/source/engine/transitions/snakewipe.hxx
new file mode 100644
index 000000000000..7f282aa0557c
--- /dev/null
+++ b/slideshow/source/engine/transitions/snakewipe.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_SNAKEWIPE_HXX
+#define INCLUDED_SLIDESHOW_SNAKEWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a snake wipe:
+class SnakeWipe : public ParametricPolyPolygon
+{
+public:
+ SnakeWipe( sal_Int32 nElements, bool diagonal, bool flipOnYAxis );
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+
+protected:
+ // topLeftHorizontal:
+ ::basegfx::B2DPolyPolygon calcSnake( double t ) const;
+ // topLeftDiagonal:
+ ::basegfx::B2DPolyPolygon calcHalfDiagonalSnake( double t, bool in ) const;
+
+ const sal_Int32 m_sqrtElements;
+ const double m_elementEdge;
+ const bool m_diagonal;
+ const bool m_flipOnYAxis;
+};
+
+/// Generates a parallel snakes wipe:
+class ParallelSnakesWipe : public SnakeWipe
+{
+public:
+ ParallelSnakesWipe( sal_Int32 nElements,
+ bool diagonal, bool flipOnYAxis, bool opposite )
+ : SnakeWipe( nElements, diagonal, flipOnYAxis ),
+ m_opposite( opposite )
+ {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ const bool m_opposite;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_SNAKEWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/spiralwipe.cxx b/slideshow/source/engine/transitions/spiralwipe.cxx
new file mode 100644
index 000000000000..d7cbd6c7cf32
--- /dev/null
+++ b/slideshow/source/engine/transitions/spiralwipe.cxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include "spiralwipe.hxx"
+#include "transitiontools.hxx"
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+
+namespace slideshow {
+namespace internal {
+
+SpiralWipe::SpiralWipe( sal_Int32 nElements, bool flipOnYAxis )
+ : m_elements(nElements),
+ m_sqrtElements( static_cast<sal_Int32>(
+ sqrt( static_cast<double>(nElements) ) ) ),
+ m_flipOnYAxis(flipOnYAxis)
+{
+}
+
+::basegfx::B2DPolyPolygon SpiralWipe::calcNegSpiral( double t ) const
+{
+ const double area = (t * m_elements);
+ const double e = (sqrt(area) / 2.0);
+ const sal_Int32 edge = (static_cast<sal_Int32>(e) * 2);
+
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5));
+ const double edge_ = ::basegfx::pruneScaleValue(
+ static_cast<double>(edge) / m_sqrtElements );
+ aTransform.scale( edge_, edge_ );
+ aTransform.translate( 0.5, 0.5 );
+ ::basegfx::B2DPolygon poly( createUnitRect() );
+ poly.transform( aTransform );
+ ::basegfx::B2DPolyPolygon res(poly);
+
+ if (! ::basegfx::fTools::equalZero( 1.0 - t )) {
+ const sal_Int32 edge1 = (edge + 1);
+ sal_Int32 len = static_cast<sal_Int32>( (e - (edge /2)) * edge1 * 4 );
+ double w = M_PI_2;
+ while (len > 0) {
+ const sal_Int32 alen = (len > edge1 ? edge1 : len);
+ len -= alen;
+ poly = createUnitRect();
+ aTransform = basegfx::tools::createScaleB2DHomMatrix(
+ ::basegfx::pruneScaleValue( static_cast<double>(alen) / m_sqrtElements ),
+ ::basegfx::pruneScaleValue( 1.0 / m_sqrtElements ) );
+ aTransform.translate(
+ - ::basegfx::pruneScaleValue(
+ static_cast<double>(edge / 2) / m_sqrtElements ),
+ ::basegfx::pruneScaleValue(
+ static_cast<double>(edge / 2) / m_sqrtElements ) );
+ aTransform.rotate( w );
+ w -= M_PI_2;
+ aTransform.translate( 0.5, 0.5 );
+ poly.transform( aTransform );
+ res.append(poly);
+ }
+ }
+
+ return res;
+}
+
+::basegfx::B2DPolyPolygon SpiralWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res( createUnitRect() );
+ ::basegfx::B2DPolyPolygon innerSpiral( calcNegSpiral( 1.0 - t ) );
+ innerSpiral.flip();
+ res.append(innerSpiral);
+ return m_flipOnYAxis ? flipOnYAxis(res) : res;
+}
+
+::basegfx::B2DPolyPolygon BoxSnakesWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res( createUnitRect() );
+ ::basegfx::B2DPolyPolygon innerSpiral( calcNegSpiral( 1.0 - t ) );
+ innerSpiral.flip();
+
+ if (m_fourBox) {
+ ::basegfx::B2DHomMatrix aTransform;
+ aTransform.scale( 0.5, 0.5 );
+ innerSpiral.transform( aTransform );
+ res.append(innerSpiral);
+ res.append( flipOnXAxis(innerSpiral) );
+ innerSpiral = flipOnYAxis(innerSpiral);
+ res.append(innerSpiral);
+ res.append( flipOnXAxis(innerSpiral) );
+ }
+ else {
+ ::basegfx::B2DHomMatrix aTransform;
+ aTransform.scale( 1.0, 0.5 );
+ innerSpiral.transform( aTransform );
+ res.append(innerSpiral);
+ res.append( flipOnXAxis(innerSpiral) );
+ }
+
+ return m_flipOnYAxis ? flipOnYAxis(res) : res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/spiralwipe.hxx b/slideshow/source/engine/transitions/spiralwipe.hxx
new file mode 100644
index 000000000000..d515a28e5c79
--- /dev/null
+++ b/slideshow/source/engine/transitions/spiralwipe.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_SPIRALWIPE_HXX
+#define INCLUDED_SLIDESHOW_SPIRALWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a topLeftClockWise or
+/// bottomLeftCounterClockWise (flipOnYAxis=true) spiral wipe:
+class SpiralWipe : public ParametricPolyPolygon
+{
+public:
+ SpiralWipe( sal_Int32 nElements, bool flipOnYAxis = false );
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+protected:
+ ::basegfx::B2DPolyPolygon calcNegSpiral( double t ) const;
+
+ const sal_Int32 m_elements;
+ const sal_Int32 m_sqrtElements;
+ const bool m_flipOnYAxis;
+};
+
+/// Generates a twoBoxLeft or fourBoxHorizontal wipe:
+class BoxSnakesWipe : public SpiralWipe
+{
+public:
+ BoxSnakesWipe( sal_Int32 nElements, bool fourBox = false )
+ : SpiralWipe(nElements), m_fourBox(fourBox) {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ const bool m_fourBox;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_SPIRALWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/sweepwipe.cxx b/slideshow/source/engine/transitions/sweepwipe.cxx
new file mode 100644
index 000000000000..a5e25ac5a5e5
--- /dev/null
+++ b/slideshow/source/engine/transitions/sweepwipe.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "clockwipe.hxx"
+#include "sweepwipe.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon SweepWipe::operator () ( double t )
+{
+ t /= 2.0;
+ if (! m_center)
+ t /= 2.0;
+ if (!m_single && !m_oppositeVertical)
+ t /= 2.0;
+
+ ::basegfx::B2DPolygon poly( ClockWipe::calcCenteredClock( 0.25 + t ) );
+ ::basegfx::B2DHomMatrix aTransform;
+
+ if (m_center)
+ {
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.0);
+ poly.transform( aTransform );
+ }
+ ::basegfx::B2DPolyPolygon res(poly);
+
+ if (! m_single)
+ {
+ if (m_oppositeVertical)
+ {
+ aTransform = basegfx::tools::createScaleB2DHomMatrix(1.0, -1.0);
+ aTransform.translate( 0.0, 1.0 );
+ poly.transform( aTransform );
+ poly.flip();
+ }
+ else
+ {
+ aTransform = basegfx::tools::createTranslateB2DHomMatrix(-0.5, -0.5);
+ aTransform.rotate( M_PI );
+ aTransform.translate( 0.5, 0.5 );
+ poly.transform( aTransform );
+ }
+ res.append(poly);
+ }
+
+ return m_flipOnYAxis ? flipOnYAxis(res) : res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/sweepwipe.hxx b/slideshow/source/engine/transitions/sweepwipe.hxx
new file mode 100644
index 000000000000..953ed7b9e862
--- /dev/null
+++ b/slideshow/source/engine/transitions/sweepwipe.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_SWEEPWIPE_HXX
+#define INCLUDED_SLIDESHOW_SWEEPWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+class SweepWipe : public ParametricPolyPolygon
+{
+public:
+ SweepWipe( bool center, bool single,
+ bool oppositeVertical, bool flipOnYAxis )
+ : m_center(center), m_single(single),
+ m_oppositeVertical(oppositeVertical), m_flipOnYAxis(flipOnYAxis)
+ {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ const bool m_center, m_single, m_oppositeVertical, m_flipOnYAxis;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_SWEEPWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/transitionfactorytab.cxx b/slideshow/source/engine/transitions/transitionfactorytab.cxx
new file mode 100644
index 000000000000..a59c6051aa5e
--- /dev/null
+++ b/slideshow/source/engine/transitions/transitionfactorytab.cxx
@@ -0,0 +1,2149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <boost/current_function.hpp>
+#include <basegfx/numeric/ftools.hxx>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+
+#include "transitionfactory.hxx"
+#include "tools.hxx"
+
+#include <algorithm>
+
+using namespace ::com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+static const TransitionInfo lcl_transitionInfo[] =
+{
+ {
+ 0,
+ 0,
+ TransitionInfo::TRANSITION_INVALID,
+ 0.0,
+ 0.0,
+ 0.0,
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ false,
+ false
+ },
+ {
+ // mapped to BarWipePolyPolygon:
+ animations::TransitionType::BARWIPE,
+ animations::TransitionSubType::LEFTTORIGHT, // (1)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ false, // 'out' by subtraction
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarWipePolyPolygon:
+ animations::TransitionType::BARWIPE,
+ animations::TransitionSubType::TOPTOBOTTOM, // (2)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ false, // 'out' by subtraction
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to BarWipePolyPolygon(nBars=5):
+ animations::TransitionType::BLINDSWIPE,
+ animations::TransitionSubType::VERTICAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarWipePolyPolygon(nBars=5):
+ animations::TransitionType::BLINDSWIPE,
+ animations::TransitionSubType::HORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::TOPLEFT, // (3)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // possible via bottomRight
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::TOPRIGHT, // (4)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // possible via bottomLeft
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::BOTTOMRIGHT, // (5)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // possible via topLeft
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::BOTTOMLEFT, // (6)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // possible via topRight
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::TOPCENTER, // (23)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::RIGHTCENTER, // (24)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::BOTTOMCENTER, // (25)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxWipe:
+ animations::TransitionType::BOXWIPE,
+ animations::TransitionSubType::LEFTCENTER, // (26)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to FourBoxWipe:
+ animations::TransitionType::FOURBOXWIPE,
+ animations::TransitionSubType::CORNERSIN, // (7)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FourBoxWipe:
+ animations::TransitionType::FOURBOXWIPE,
+ animations::TransitionSubType::CORNERSOUT, // (8)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to BarnDoorWipe:
+ animations::TransitionType::BARNDOORWIPE,
+ animations::TransitionSubType::VERTICAL, // (21)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarnDoorWipe:
+ animations::TransitionType::BARNDOORWIPE,
+ animations::TransitionSubType::HORIZONTAL, // (22)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarnDoorWipe:
+ animations::TransitionType::BARNDOORWIPE,
+ animations::TransitionSubType::DIAGONALBOTTOMLEFT, // (45)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 45.0, // rotation
+ M_SQRT2, // scaling
+ M_SQRT2, // scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarnDoorWipe:
+ animations::TransitionType::BARNDOORWIPE,
+ animations::TransitionSubType::DIAGONALTOPLEFT, // (46)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -45.0, // rotation
+ M_SQRT2, // scaling
+ M_SQRT2, // scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to BarWipePolyPolygon:
+ animations::TransitionType::DIAGONALWIPE,
+ animations::TransitionSubType::TOPLEFT, // (41)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 45.0, // rotation
+ M_SQRT2, // scaling
+ M_SQRT2, // scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarWipePolyPolygon:
+ animations::TransitionType::DIAGONALWIPE,
+ animations::TransitionSubType::TOPRIGHT, // (42)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 135.0, // rotation
+ M_SQRT2, // scaling
+ M_SQRT2, // scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+
+ {
+ animations::TransitionType::BOWTIEWIPE,
+ animations::TransitionSubType::VERTICAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::BOWTIEWIPE,
+ animations::TransitionSubType::HORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to BarnDoorWipe (doubled=true):
+ animations::TransitionType::MISCDIAGONALWIPE,
+ animations::TransitionSubType::DOUBLEBARNDOOR, // (47)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 45.0, // rotation
+ M_SQRT2, // scaling
+ M_SQRT2, // scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to DoubleDiamondWipe:
+ animations::TransitionType::MISCDIAGONALWIPE,
+ animations::TransitionSubType::DOUBLEDIAMOND, // (48)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to VeeWipe:
+ animations::TransitionType::VEEWIPE,
+ animations::TransitionSubType::DOWN, // (61)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to VeeWipe:
+ animations::TransitionType::VEEWIPE,
+ animations::TransitionSubType::LEFT, // (62)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::VEEWIPE,
+ animations::TransitionSubType::UP, // (63)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::VEEWIPE,
+ animations::TransitionSubType::RIGHT,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+
+ {
+ animations::TransitionType::BARNVEEWIPE,
+ animations::TransitionSubType::TOP,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::BARNVEEWIPE,
+ animations::TransitionSubType::LEFT,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::BARNVEEWIPE,
+ animations::TransitionSubType::UP,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::BARNVEEWIPE,
+ animations::TransitionSubType::RIGHT,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to ZigZagWipe:
+ animations::TransitionType::ZIGZAGWIPE,
+ animations::TransitionSubType::LEFTTORIGHT, // (71)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ZigZagWipe:
+ animations::TransitionType::ZIGZAGWIPE,
+ animations::TransitionSubType::TOPTOBOTTOM, // (72)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarnZigZagWipe:
+ animations::TransitionType::BARNZIGZAGWIPE,
+ animations::TransitionSubType::VERTICAL, // (73)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BarnZigZagWipe:
+ animations::TransitionType::BARNZIGZAGWIPE,
+ animations::TransitionSubType::HORIZONTAL, // (74)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to IrisWipe:
+ animations::TransitionType::IRISWIPE,
+ animations::TransitionSubType::RECTANGLE, // (101)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to IrisWipe:
+ animations::TransitionType::IRISWIPE,
+ animations::TransitionSubType::DIAMOND, // (102)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 45.0, // rotation
+ M_SQRT2, // scaling
+ M_SQRT2, // scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+
+ {
+ // mapped to FigureWipe(triangle):
+ animations::TransitionType::TRIANGLEWIPE,
+ animations::TransitionSubType::UP, // (103)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(triangle):
+ animations::TransitionType::TRIANGLEWIPE,
+ animations::TransitionSubType::RIGHT, // (104)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(triangle):
+ animations::TransitionType::TRIANGLEWIPE,
+ animations::TransitionSubType::DOWN, // (105)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(triangle):
+ animations::TransitionType::TRIANGLEWIPE,
+ animations::TransitionSubType::LEFT, // (106)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 270.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to FigureWipe(arrowHead):
+ animations::TransitionType::ARROWHEADWIPE,
+ animations::TransitionSubType::UP, // (107)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(arrowHead):
+ animations::TransitionType::ARROWHEADWIPE,
+ animations::TransitionSubType::RIGHT, // (108)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(arrowHead):
+ animations::TransitionType::ARROWHEADWIPE,
+ animations::TransitionSubType::DOWN, // (109)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(arrowHead):
+ animations::TransitionType::ARROWHEADWIPE,
+ animations::TransitionSubType::LEFT, // (110)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 270.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to FigureWipe(pentagon):
+ animations::TransitionType::PENTAGONWIPE,
+ animations::TransitionSubType::UP, // (111)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(pentagon):
+ animations::TransitionType::PENTAGONWIPE,
+ animations::TransitionSubType::DOWN, // (112)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to FigureWipe(hexagon):
+ animations::TransitionType::HEXAGONWIPE,
+ animations::TransitionSubType::HORIZONTAL, // (113)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(hexagon):
+ animations::TransitionType::HEXAGONWIPE,
+ animations::TransitionSubType::VERTICAL, // (114)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to EllipseWipe:
+ animations::TransitionType::ELLIPSEWIPE,
+ animations::TransitionSubType::CIRCLE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size
+ },
+ {
+ // mapped to EllipseWipe:
+ animations::TransitionType::ELLIPSEWIPE,
+ animations::TransitionSubType::HORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to EllipseWipe:
+ animations::TransitionType::ELLIPSEWIPE,
+ animations::TransitionSubType::VERTICAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+
+ {
+ animations::TransitionType::EYEWIPE,
+ animations::TransitionSubType::HORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::EYEWIPE,
+ animations::TransitionSubType::VERTICAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::ROUNDRECTWIPE,
+ animations::TransitionSubType::HORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::ROUNDRECTWIPE,
+ animations::TransitionSubType::VERTICAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to FigureWipe(star, points=4):
+ animations::TransitionType::STARWIPE,
+ animations::TransitionSubType::FOURPOINT, // (127)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(star, points=5):
+ animations::TransitionType::STARWIPE,
+ animations::TransitionSubType::FIVEPOINT, // (128)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FigureWipe(star, points=6):
+ animations::TransitionType::STARWIPE,
+ animations::TransitionSubType::SIXPOINT, // (129)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ animations::TransitionType::MISCSHAPEWIPE,
+ animations::TransitionSubType::HEART,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::MISCSHAPEWIPE,
+ animations::TransitionSubType::KEYHOLE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to ClockWipe:
+ animations::TransitionType::CLOCKWIPE,
+ animations::TransitionSubType::CLOCKWISETWELVE, // (201)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ClockWipe:
+ animations::TransitionType::CLOCKWIPE,
+ animations::TransitionSubType::CLOCKWISETHREE, // (202)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ClockWipe:
+ animations::TransitionType::CLOCKWIPE,
+ animations::TransitionSubType::CLOCKWISESIX, // (203)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ClockWipe:
+ animations::TransitionType::CLOCKWIPE,
+ animations::TransitionSubType::CLOCKWISENINE, // (204)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 270.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to PinWheelWipe:
+ animations::TransitionType::PINWHEELWIPE,
+ animations::TransitionSubType::ONEBLADE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size, like ppt
+ },
+ {
+ // mapped to PinWheelWipe:
+ animations::TransitionType::PINWHEELWIPE,
+ animations::TransitionSubType::TWOBLADEVERTICAL, // (205)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size, like ppt
+ },
+ {
+ // mapped to PinWheelWipe:
+ animations::TransitionType::PINWHEELWIPE,
+ animations::TransitionSubType::TWOBLADEHORIZONTAL, // (206)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size, like ppt
+ },
+ {
+ // mapped to PinWheelWipe:
+ animations::TransitionType::PINWHEELWIPE,
+ animations::TransitionSubType::THREEBLADE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size, like ppt
+ },
+ {
+ // mapped to PinWheelWipe:
+ animations::TransitionType::PINWHEELWIPE,
+ animations::TransitionSubType::FOURBLADE, // (207)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size, like ppt
+ },
+ {
+ // mapped to PinWheelWipe:
+ animations::TransitionType::PINWHEELWIPE,
+ animations::TransitionSubType::EIGHTBLADE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size, like ppt
+ },
+
+ {
+ // mapped to SweepWipe (center=true, single=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::CLOCKWISETOP, // (221)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=true, single=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::CLOCKWISERIGHT, // (222)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=true, single=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::CLOCKWISEBOTTOM, // (223)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=true, single=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::CLOCKWISELEFT, // (224)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 270.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=false, single=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::CLOCKWISETOPLEFT, // (241)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=false, single=true, flipOnYAxis=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::COUNTERCLOCKWISEBOTTOMLEFT, // (242)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=false, single=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::CLOCKWISEBOTTOMRIGHT, // (243)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=false, single=true, flipOnYAxis=true):
+ animations::TransitionType::SINGLESWEEPWIPE,
+ animations::TransitionSubType::COUNTERCLOCKWISETOPRIGHT, // (244)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to FanWipe(center=true):
+ animations::TransitionType::FANWIPE,
+ animations::TransitionSubType::CENTERTOP, // (211)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe(center=true):
+ animations::TransitionType::FANWIPE,
+ animations::TransitionSubType::CENTERRIGHT, // (212)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe:
+ animations::TransitionType::FANWIPE,
+ animations::TransitionSubType::TOP, // (231)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe:
+ animations::TransitionType::FANWIPE,
+ animations::TransitionSubType::RIGHT, // (232)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe:
+ animations::TransitionType::FANWIPE,
+ animations::TransitionSubType::BOTTOM, // (233)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe:
+ animations::TransitionType::FANWIPE,
+ animations::TransitionSubType::LEFT, // (234)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to FanWipe(center=true, single=false, fanIn=false):
+ animations::TransitionType::DOUBLEFANWIPE,
+ animations::TransitionSubType::FANOUTVERTICAL, // (213)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe(center=true, single=false, fanIn=false):
+ animations::TransitionType::DOUBLEFANWIPE,
+ animations::TransitionSubType::FANOUTHORIZONTAL, // (214)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe(center=true, single=false, fanIn=true):
+ animations::TransitionType::DOUBLEFANWIPE,
+ animations::TransitionSubType::FANINVERTICAL, // (235)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to FanWipe(center=true, single=false, fanIn=true):
+ animations::TransitionType::DOUBLEFANWIPE,
+ animations::TransitionSubType::FANINHORIZONTAL, // (236)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to SweepWipe (center=true, single=false):
+ animations::TransitionType::DOUBLESWEEPWIPE,
+ animations::TransitionSubType::PARALLELVERTICAL, // (225)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=true, single=false):
+ animations::TransitionType::DOUBLESWEEPWIPE,
+ animations::TransitionSubType::PARALLELDIAGONAL, // (226)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=true, single=false,
+ // oppositeVertical=true):
+ animations::TransitionType::DOUBLESWEEPWIPE,
+ animations::TransitionSubType::OPPOSITEVERTICAL, // (227)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=true, single=false,
+ // oppositeVertical=true):
+ animations::TransitionType::DOUBLESWEEPWIPE,
+ animations::TransitionSubType::OPPOSITEHORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=false, single=false):
+ animations::TransitionType::DOUBLESWEEPWIPE,
+ animations::TransitionSubType::PARALLELDIAGONALTOPLEFT,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SweepWipe (center=false, single=false):
+ animations::TransitionType::DOUBLESWEEPWIPE,
+ animations::TransitionSubType::PARALLELDIAGONALBOTTOMLEFT,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ animations::TransitionType::SALOONDOORWIPE,
+ animations::TransitionSubType::TOP, // (251)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SALOONDOORWIPE,
+ animations::TransitionSubType::LEFT, // (252)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SALOONDOORWIPE,
+ animations::TransitionSubType::BOTTOM, // (253)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SALOONDOORWIPE,
+ animations::TransitionSubType::RIGHT, // (254)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::WINDSHIELDWIPE,
+ animations::TransitionSubType::RIGHT,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::WINDSHIELDWIPE,
+ animations::TransitionSubType::UP,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::WINDSHIELDWIPE,
+ animations::TransitionSubType::VERTICAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::WINDSHIELDWIPE,
+ animations::TransitionSubType::HORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to SnakeWipe:
+ animations::TransitionType::SNAKEWIPE,
+ animations::TransitionSubType::TOPLEFTHORIZONTAL, // (301)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SnakeWipe(flipOnYAxis=true):
+ animations::TransitionType::SNAKEWIPE,
+ animations::TransitionSubType::TOPLEFTVERTICAL, // (302)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SnakeWipe(diagonal=true):
+ animations::TransitionType::SNAKEWIPE,
+ animations::TransitionSubType::TOPLEFTDIAGONAL, // (303)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SnakeWipe(diagonal=true, flipOnYAxis=true):
+ animations::TransitionType::SNAKEWIPE,
+ animations::TransitionSubType::TOPRIGHTDIAGONAL, // (304)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SnakeWipe(diagonal=true):
+ animations::TransitionType::SNAKEWIPE,
+ animations::TransitionSubType::BOTTOMRIGHTDIAGONAL, // (305)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SnakeWipe(diagonal=true, flipOnYAxis=true):
+ animations::TransitionType::SNAKEWIPE,
+ animations::TransitionSubType::BOTTOMLEFTDIAGONAL, // (306)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to SpiralWipe:
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::TOPLEFTCLOCKWISE, // (310)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SpiralWipe:
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::TOPRIGHTCLOCKWISE, // (311)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SpiralWipe:
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::BOTTOMRIGHTCLOCKWISE, // (312)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SpiralWipe:
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::BOTTOMLEFTCLOCKWISE, // (313)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 270.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SpiralWipe(flipOnYAxis=true):
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::TOPLEFTCOUNTERCLOCKWISE, // (314)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SpiralWipe(flipOnYAxis=true):
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::TOPRIGHTCOUNTERCLOCKWISE, // (315)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SpiralWipe(flipOnYAxis=true):
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::BOTTOMRIGHTCOUNTERCLOCKWISE, // (316)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 270.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to SpiralWipe(flipOnYAxis=true):
+ animations::TransitionType::SPIRALWIPE,
+ animations::TransitionSubType::BOTTOMLEFTCOUNTERCLOCKWISE, // (317)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to ParallelSnakesWipe:
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::VERTICALTOPSAME,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe:
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::VERTICALBOTTOMSAME,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe (opposite=true):
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::VERTICALTOPLEFTOPPOSITE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe (flipOnYAxis=true, opposite=true):
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::VERTICALBOTTOMLEFTOPPOSITE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe:
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::HORIZONTALLEFTSAME,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe:
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::HORIZONTALRIGHTSAME,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe (flipOnYAxis=true, opposite=true):
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::HORIZONTALTOPLEFTOPPOSITE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe (opposite=true):
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::HORIZONTALTOPRIGHTOPPOSITE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe (diagonal=true, opposite=true):
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::DIAGONALBOTTOMLEFTOPPOSITE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to ParallelSnakesWipe (diagonal=true, opposite=true,
+ // flipOnYAxis=true):
+ animations::TransitionType::PARALLELSNAKESWIPE,
+ animations::TransitionSubType::DIAGONALTOPLEFTOPPOSITE,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to BoxSnakesWipe:
+ animations::TransitionType::BOXSNAKESWIPE,
+ animations::TransitionSubType::TWOBOXTOP, // (340)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxSnakesWipe:
+ animations::TransitionType::BOXSNAKESWIPE,
+ animations::TransitionSubType::TWOBOXBOTTOM, // (341)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxSnakesWipe:
+ animations::TransitionType::BOXSNAKESWIPE,
+ animations::TransitionSubType::TWOBOXLEFT, // (342)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxSnakesWipe:
+ animations::TransitionType::BOXSNAKESWIPE,
+ animations::TransitionSubType::TWOBOXRIGHT, // (343)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 180.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxSnakesWipe(fourBox=true):
+ animations::TransitionType::BOXSNAKESWIPE,
+ animations::TransitionSubType::FOURBOXVERTICAL, // (344)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to BoxSnakesWipe(fourBox=true):
+ animations::TransitionType::BOXSNAKESWIPE,
+ animations::TransitionSubType::FOURBOXHORIZONTAL, // (345)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to WaterfallWipe:
+ animations::TransitionType::WATERFALLWIPE,
+ animations::TransitionSubType::VERTICALLEFT, // (350)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to WaterfallWipe (flipOnYAxis=true):
+ animations::TransitionType::WATERFALLWIPE,
+ animations::TransitionSubType::VERTICALRIGHT, // (351)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to WaterfallWipe (flipOnYAxis=true):
+ animations::TransitionType::WATERFALLWIPE,
+ animations::TransitionSubType::HORIZONTALLEFT, // (352)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ -90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to WaterfallWipe, flipOnYAxis=false:
+ animations::TransitionType::WATERFALLWIPE,
+ animations::TransitionSubType::HORIZONTALRIGHT, // (353)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_ROTATE_180,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMLEFT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMTOP,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMRIGHT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMBOTTOM,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMBOTTOMRIGHT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMBOTTOMLEFT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMTOPRIGHT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::FROMTOPLEFT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::COMBHORIZONTAL,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::PUSHWIPE,
+ animations::TransitionSubType::COMBVERTICAL,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMLEFT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMTOP,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMRIGHT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMBOTTOM,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMBOTTOMRIGHT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMTOPRIGHT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMTOPLEFT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::SLIDEWIPE,
+ animations::TransitionSubType::FROMBOTTOMLEFT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE, // special code for this transition
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::FADE,
+ animations::TransitionSubType::CROSSFADE,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::FADE,
+ animations::TransitionSubType::FADETOCOLOR,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::FADE,
+ animations::TransitionSubType::FADEFROMCOLOR,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ animations::TransitionType::FADE,
+ animations::TransitionSubType::FADEOVERCOLOR,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ // this is the cut through black fade (does not fade, but does a
+ // hard cut)
+ {
+ animations::TransitionType::BARWIPE,
+ animations::TransitionSubType::FADEOVERCOLOR,
+ TransitionInfo::TRANSITION_SPECIAL,
+ // TODO(F2): Setup parameters
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to RandomWipe:
+ animations::TransitionType::RANDOMBARWIPE,
+ animations::TransitionSubType::VERTICAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to RandomWipe:
+ animations::TransitionType::RANDOMBARWIPE,
+ animations::TransitionSubType::HORIZONTAL,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to CheckerBoard:
+ animations::TransitionType::CHECKERBOARDWIPE,
+ animations::TransitionSubType::DOWN,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 90.0, // rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_Y,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+ {
+ // mapped to CheckerBoard:
+ animations::TransitionType::CHECKERBOARDWIPE,
+ animations::TransitionSubType::ACROSS, // (default)
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_FLIP_X,
+ true, // 'out' by parameter sweep inversion
+ false // scale isotrophically to target size
+ },
+
+ {
+ // mapped to RandomWipe:
+ animations::TransitionType::DISSOLVE,
+ animations::TransitionSubType::DEFAULT,
+ TransitionInfo::TRANSITION_CLIP_POLYPOLYGON,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size
+ },
+
+ /////////////////////////////////////////////////////////
+ // NOTE: This entry MUST be the last, to keep
+ // createSlideTransition() from infinite recursion. Because
+ // getRandomTransitionInfo() below will exclude the last entry of
+ // the table from the random number generation.
+ /////////////////////////////////////////////////////////
+ {
+ // specially handled
+ animations::TransitionType::RANDOM,
+ animations::TransitionSubType::DEFAULT,
+ TransitionInfo::TRANSITION_SPECIAL,
+ 0.0, // no rotation
+ 1.0, // no scaling
+ 1.0, // no scaling
+ TransitionInfo::REVERSEMETHOD_IGNORE,
+ true, // 'out' by parameter sweep inversion
+ true // scale isotrophically to target size
+ }
+ /////////////////////////////////////////////////////////
+ // NOTE: DON'T add after this entry! See comment above!
+ /////////////////////////////////////////////////////////
+};
+
+} // anon namespace
+
+const TransitionInfo* TransitionFactory::getTransitionInfo(
+ sal_Int16 nTransitionType, sal_Int16 nTransitionSubType )
+{
+ static const ::std::size_t lcl_tableSize(
+ sizeof(lcl_transitionInfo)/sizeof(TransitionInfo) );
+ static const TransitionInfo* pTableEnd = lcl_transitionInfo+lcl_tableSize;
+
+ const TransitionInfo* pRes = ::std::find_if(
+ lcl_transitionInfo, pTableEnd,
+ TransitionInfo::Comparator( nTransitionType,
+ nTransitionSubType ) );
+ if (pRes != pTableEnd)
+ return pRes;
+ else
+ return NULL;
+}
+
+const TransitionInfo* TransitionFactory::getRandomTransitionInfo()
+{
+ return lcl_transitionInfo + getRandomOrdinal(
+ sizeof(lcl_transitionInfo) / sizeof(TransitionInfo)
+ - 1 /* exclude random transition at end of table */ );
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/transitiontools.cxx b/slideshow/source/engine/transitions/transitiontools.cxx
new file mode 100644
index 000000000000..c497c91bee68
--- /dev/null
+++ b/slideshow/source/engine/transitions/transitiontools.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include "transitiontools.hxx"
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+
+namespace slideshow {
+namespace internal {
+
+// TODO(Q2): Move this to basegfx
+::basegfx::B2DPolygon createUnitRect()
+{
+ return ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRectangle(0.0,0.0,
+ 1.0,1.0 ) );
+}
+
+::basegfx::B2DPolyPolygon flipOnYAxis(
+ ::basegfx::B2DPolyPolygon const & polypoly )
+{
+ ::basegfx::B2DPolyPolygon res(polypoly);
+ res.transform(basegfx::tools::createScaleTranslateB2DHomMatrix(-1.0, 1.0, 1.0, 0.0));
+ res.flip();
+ return res;
+}
+
+::basegfx::B2DPolyPolygon flipOnXAxis(
+ ::basegfx::B2DPolyPolygon const & polypoly )
+{
+ ::basegfx::B2DPolyPolygon res(polypoly);
+ res.transform(basegfx::tools::createScaleTranslateB2DHomMatrix(1.0, -1.0, 0.0, 1.0));
+ res.flip();
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/transitiontools.hxx b/slideshow/source/engine/transitions/transitiontools.hxx
new file mode 100644
index 000000000000..6e1acaa525ee
--- /dev/null
+++ b/slideshow/source/engine/transitions/transitiontools.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_TRANSITIONTOOLS_HXX
+#define INCLUDED_SLIDESHOW_TRANSITIONTOOLS_HXX
+
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+#include <algorithm>
+
+
+namespace slideshow {
+namespace internal {
+
+/// Create a unit rect.
+::basegfx::B2DPolygon createUnitRect();
+
+/// Flips on X-axis:
+::basegfx::B2DPolyPolygon flipOnXAxis(
+ ::basegfx::B2DPolyPolygon const & polypoly );
+
+/// Flips on Y-axis:
+::basegfx::B2DPolyPolygon flipOnYAxis(
+ ::basegfx::B2DPolyPolygon const & polypoly );
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_TRANSITIONTOOLS_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/veewipe.cxx b/slideshow/source/engine/transitions/veewipe.cxx
new file mode 100644
index 000000000000..7e1484cd93b6
--- /dev/null
+++ b/slideshow/source/engine/transitions/veewipe.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include "veewipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+::basegfx::B2DPolyPolygon VeeWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolygon poly;
+ poly.append( ::basegfx::B2DPoint( 0.0, -1.0 ) );
+ const double d = ::basegfx::pruneScaleValue( 2.0 * t );
+ poly.append( ::basegfx::B2DPoint( 0.0, d - 1.0 ) );
+ poly.append( ::basegfx::B2DPoint( 0.5, d ) );
+ poly.append( ::basegfx::B2DPoint( 1.0, d - 1.0 ) );
+ poly.append( ::basegfx::B2DPoint( 1.0, -1.0 ) );
+ poly.setClosed(true);
+ return ::basegfx::B2DPolyPolygon( poly );
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/veewipe.hxx b/slideshow/source/engine/transitions/veewipe.hxx
new file mode 100644
index 000000000000..9106c4d625c6
--- /dev/null
+++ b/slideshow/source/engine/transitions/veewipe.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_VEEWIPE_HXX
+#define INCLUDED_SLIDESHOW_VEEWIPE_HXX
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+#include "parametricpolypolygon.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generate a vee wipe
+class VeeWipe : public ParametricPolyPolygon
+{
+public:
+ VeeWipe() {}
+ virtual ::basegfx::B2DPolyPolygon operator()( double x );
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_VEEWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/waterfallwipe.cxx b/slideshow/source/engine/transitions/waterfallwipe.cxx
new file mode 100644
index 000000000000..2e2349c48979
--- /dev/null
+++ b/slideshow/source/engine/transitions/waterfallwipe.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "waterfallwipe.hxx"
+#include "transitiontools.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+WaterfallWipe::WaterfallWipe( sal_Int32 nElements, bool flipOnYAxis )
+ : m_flipOnYAxis( flipOnYAxis )
+{
+ const sal_Int32 sqrtElements = static_cast<sal_Int32>(
+ sqrt( static_cast<double>(nElements) ) );
+ const double elementEdge = (1.0 / sqrtElements);
+ m_waterfall.append( ::basegfx::B2DPoint( 0.0, -1.0 ) );
+ for ( sal_Int32 pos = sqrtElements; pos--; )
+ {
+ const sal_Int32 xPos = (sqrtElements - pos - 1);
+ const double yPos = ::basegfx::pruneScaleValue( ((pos + 1) * elementEdge) - 1.0 );
+ m_waterfall.append( ::basegfx::B2DPoint(
+ ::basegfx::pruneScaleValue( xPos * elementEdge ),
+ yPos ) );
+ m_waterfall.append( ::basegfx::B2DPoint(
+ ::basegfx::pruneScaleValue( (xPos + 1) * elementEdge ),
+ yPos ) );
+ }
+ m_waterfall.append( ::basegfx::B2DPoint( 1.0, -1.0 ) );
+ m_waterfall.setClosed(true);
+}
+
+::basegfx::B2DPolyPolygon WaterfallWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolygon poly( m_waterfall );
+ poly.transform(basegfx::tools::createTranslateB2DHomMatrix(0.0, ::basegfx::pruneScaleValue(2.0 * t)));
+ poly.setB2DPoint( 0, ::basegfx::B2DPoint( 0.0, -1.0 ) );
+ poly.setB2DPoint( poly.count()-1, ::basegfx::B2DPoint( 1.0, -1.0 ) );
+
+ return m_flipOnYAxis ? flipOnYAxis( ::basegfx::B2DPolyPolygon(poly) )
+ : ::basegfx::B2DPolyPolygon(poly);
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/waterfallwipe.hxx b/slideshow/source/engine/transitions/waterfallwipe.hxx
new file mode 100644
index 000000000000..2f373bd3728e
--- /dev/null
+++ b/slideshow/source/engine/transitions/waterfallwipe.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_WATERFALLWIPE_HXX
+#define INCLUDED_SLIDESHOW_WATERFALLWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generate a vertical left waterfall wipe
+class WaterfallWipe : public ParametricPolyPolygon
+{
+public:
+ WaterfallWipe( sal_Int32 nElements, bool flipOnYAxis = false );
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+private:
+ bool m_flipOnYAxis;
+ ::basegfx::B2DPolygon m_waterfall;
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_WATERFALLWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/zigzagwipe.cxx b/slideshow/source/engine/transitions/zigzagwipe.cxx
new file mode 100644
index 000000000000..f884be30776b
--- /dev/null
+++ b/slideshow/source/engine/transitions/zigzagwipe.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include "transitiontools.hxx"
+#include "zigzagwipe.hxx"
+
+
+namespace slideshow {
+namespace internal {
+
+ZigZagWipe::ZigZagWipe( sal_Int32 nZigs ) : m_zigEdge( 1.0 / nZigs )
+{
+ const double d = m_zigEdge;
+ const double d2 = (d / 2.0);
+ m_stdZigZag.append( ::basegfx::B2DPoint( -1.0 - d, -d ) );
+ m_stdZigZag.append( ::basegfx::B2DPoint( -1.0 - d, 1.0 + d ) );
+ m_stdZigZag.append( ::basegfx::B2DPoint( -d, 1.0 + d ) );
+ for ( sal_Int32 pos = (nZigs + 2); pos--; ) {
+ m_stdZigZag.append( ::basegfx::B2DPoint( 0.0, ((pos - 1) * d) + d2 ) );
+ m_stdZigZag.append( ::basegfx::B2DPoint( -d, (pos - 1) * d ) );
+ }
+ m_stdZigZag.setClosed(true);
+}
+
+::basegfx::B2DPolyPolygon ZigZagWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res(m_stdZigZag);
+ res.transform(basegfx::tools::createTranslateB2DHomMatrix((1.0 + m_zigEdge) * t, 0.0));
+ return res;
+}
+
+::basegfx::B2DPolyPolygon BarnZigZagWipe::operator () ( double t )
+{
+ ::basegfx::B2DPolyPolygon res( createUnitRect() );
+ ::basegfx::B2DPolygon poly( m_stdZigZag );
+ poly.flip();
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ (1.0 + m_zigEdge) * (1.0 - t) / 2.0, 0.0));
+ poly.transform( aTransform );
+ res.append( poly );
+ aTransform.scale( -1.0, 1.0 );
+ aTransform.translate( 1.0, m_zigEdge / 2.0 );
+ poly = m_stdZigZag;
+ poly.transform( aTransform );
+ res.append( poly );
+ return res;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/transitions/zigzagwipe.hxx b/slideshow/source/engine/transitions/zigzagwipe.hxx
new file mode 100644
index 000000000000..f6a24fa127ce
--- /dev/null
+++ b/slideshow/source/engine/transitions/zigzagwipe.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined INCLUDED_SLIDESHOW_ZIGZAGWIPE_HXX
+#define INCLUDED_SLIDESHOW_ZIGZAGWIPE_HXX
+
+#include "parametricpolypolygon.hxx"
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+namespace slideshow {
+namespace internal {
+
+/// Generates a left to right zigZag wipe:
+class ZigZagWipe : public ParametricPolyPolygon
+{
+public:
+ ZigZagWipe( sal_Int32 nZigs );
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+protected:
+ const double m_zigEdge;
+ ::basegfx::B2DPolygon m_stdZigZag;
+};
+
+/// Generates a vertical barnZigZag wipe:
+class BarnZigZagWipe : public ZigZagWipe
+{
+public:
+ BarnZigZagWipe( sal_Int32 nZigs ) : ZigZagWipe(nZigs) {}
+ virtual ::basegfx::B2DPolyPolygon operator () ( double t );
+};
+
+}
+}
+
+#endif /* INCLUDED_SLIDESHOW_ZIGZAGWIPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/unoviewcontainer.cxx b/slideshow/source/engine/unoviewcontainer.cxx
new file mode 100644
index 000000000000..08bbc1d90ed9
--- /dev/null
+++ b/slideshow/source/engine/unoviewcontainer.cxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <unoviewcontainer.hxx>
+
+#include <boost/bind.hpp>
+
+#include <algorithm>
+
+
+using namespace ::com::sun::star;
+
+// -----------------------------------------------------------------------------
+
+namespace slideshow
+{
+ namespace internal
+ {
+ UnoViewContainer::UnoViewContainer() :
+ maViews()
+ {
+ }
+
+ bool UnoViewContainer::addView( const UnoViewSharedPtr& rView )
+ {
+ // check whether same view is already added
+ const UnoViewVector::iterator aEnd( maViews.end() );
+
+ // already added?
+ if( ::std::find_if( maViews.begin(),
+ aEnd,
+ ::boost::bind(
+ ::std::equal_to< uno::Reference< presentation::XSlideShowView > >(),
+ ::boost::cref( rView->getUnoView() ),
+ ::boost::bind(
+ &UnoView::getUnoView,
+ _1 ) ) ) != aEnd )
+ {
+ // yes, nothing to do
+ return false;
+ }
+
+ // add locally
+ maViews.push_back( rView );
+
+ return true;
+ }
+
+ UnoViewSharedPtr UnoViewContainer::removeView( const uno::Reference< presentation::XSlideShowView >& xView )
+ {
+ // check whether same view is already added
+ const UnoViewVector::iterator aEnd( maViews.end() );
+ UnoViewVector::iterator aIter;
+
+ // added in the first place?
+ if( (aIter=::std::find_if( maViews.begin(),
+ aEnd,
+ ::boost::bind(
+ ::std::equal_to< uno::Reference< presentation::XSlideShowView > >(),
+ ::boost::cref( xView ),
+ ::boost::bind(
+ &UnoView::getUnoView,
+ _1 ) ) ) ) == aEnd )
+ {
+ // nope, nothing to do
+ return UnoViewSharedPtr();
+ }
+
+ OSL_ENSURE(
+ ::std::count_if(
+ maViews.begin(),
+ aEnd,
+ ::boost::bind(
+ ::std::equal_to< uno::Reference< presentation::XSlideShowView > >(),
+ ::boost::cref( xView ),
+ ::boost::bind(
+ &UnoView::getUnoView,
+ _1 ))) == 1,
+ "UnoViewContainer::removeView(): View was added multiple times" );
+
+ UnoViewSharedPtr pView( *aIter );
+
+ // actually erase from container
+ maViews.erase( aIter );
+
+ return pView;
+ }
+
+ bool UnoViewContainer::removeView( const UnoViewSharedPtr& rView )
+ {
+ // remove locally
+ const UnoViewVector::iterator aEnd( maViews.end() );
+ UnoViewVector::iterator aIter;
+ if( (aIter=::std::find( maViews.begin(),
+ aEnd,
+ rView )) == aEnd )
+ {
+ // view seemingly was not added, failed
+ return false;
+ }
+
+ OSL_ENSURE( ::std::count( maViews.begin(),
+ aEnd,
+ rView ) == 1,
+ "UnoViewContainer::removeView(): View was added multiple times" );
+
+ // actually erase from container
+ maViews.erase( aIter );
+
+ return true;
+ }
+
+ void UnoViewContainer::dispose()
+ {
+ ::std::for_each( maViews.begin(),
+ maViews.end(),
+ ::boost::mem_fn(&UnoView::_dispose) );
+ maViews.clear();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/usereventqueue.cxx b/slideshow/source/engine/usereventqueue.cxx
new file mode 100644
index 000000000000..c550a982b300
--- /dev/null
+++ b/slideshow/source/engine/usereventqueue.cxx
@@ -0,0 +1,1009 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+
+#include <boost/bind.hpp>
+
+#include "delayevent.hxx"
+#include "usereventqueue.hxx"
+#include "cursormanager.hxx"
+#include "slideshowexceptions.hxx"
+
+#include <vector>
+#include <queue>
+#include <map>
+#include <functional>
+#include <algorithm>
+
+
+using namespace com::sun::star;
+
+/* Implementation of UserEventQueue class */
+
+namespace slideshow {
+namespace internal {
+
+namespace {
+
+typedef std::vector<EventSharedPtr> ImpEventVector;
+typedef std::queue<EventSharedPtr> ImpEventQueue;
+typedef std::map<uno::Reference<animations::XAnimationNode>,
+ ImpEventVector> ImpAnimationEventMap;
+typedef std::map<ShapeSharedPtr, ImpEventQueue,
+ Shape::lessThanShape> ImpShapeEventMap;
+
+// MouseEventHandler base class, not consuming any event:
+class MouseEventHandler_ : public MouseEventHandler
+{
+public:
+ virtual bool handleMousePressed( awt::MouseEvent const& /*e*/ ) { return false;}
+ virtual bool handleMouseReleased( awt::MouseEvent const& /*e*/) { return false;}
+ virtual bool handleMouseEntered( awt::MouseEvent const& /*e*/ ) { return false;}
+ virtual bool handleMouseExited( awt::MouseEvent const& /*e*/ ) { return false; }
+ virtual bool handleMouseDragged( awt::MouseEvent const& /*e*/ ) { return false;}
+ virtual bool handleMouseMoved( awt::MouseEvent const& /*e*/ ) { return false; }
+};
+
+/** @return one event has been posted
+ */
+template <typename ContainerT>
+bool fireSingleEvent( ContainerT & rQueue, EventQueue & rEventQueue )
+{
+ // post next event in given queue:
+ while (! rQueue.empty())
+ {
+ EventSharedPtr const pEvent(rQueue.front());
+ rQueue.pop();
+
+ // skip all inactive events (as the purpose of
+ // nextEventFromQueue() is to activate the next
+ // event, and events which return false on
+ // isCharged() will never be activated by the
+ // EventQueue)
+ if(pEvent->isCharged())
+ return rEventQueue.addEvent( pEvent );
+ }
+ return false; // no more (active) events in queue
+}
+
+/** @return at least one event has been posted
+ */
+template <typename ContainerT>
+bool fireAllEvents( ContainerT & rQueue, EventQueue & rEventQueue )
+{
+ bool bFiredAny = false;
+ while (fireSingleEvent( rQueue, rEventQueue ))
+ bFiredAny = true;
+ return bFiredAny;
+}
+
+class EventContainer
+{
+public:
+ EventContainer() :
+ maEvents()
+ {}
+
+ void clearContainer()
+ {
+ maEvents = ImpEventQueue();
+ }
+
+ void addEvent( const EventSharedPtr& rEvent )
+ {
+ maEvents.push( rEvent );
+ }
+
+ bool isEmpty()
+ {
+ return maEvents.empty();
+ }
+
+protected:
+ ImpEventQueue maEvents;
+};
+
+} // anon namespace
+
+class PlainEventHandler : public EventHandler,
+ public EventContainer
+{
+public:
+ PlainEventHandler( EventQueue & rEventQueue )
+ : EventContainer(), mrEventQueue(rEventQueue) {}
+
+ virtual void dispose()
+ {
+ clearContainer();
+ }
+
+ virtual bool handleEvent()
+ {
+ return fireAllEvents( maEvents, mrEventQueue );
+ }
+
+private:
+ EventQueue & mrEventQueue;
+};
+
+class AllAnimationEventHandler : public AnimationEventHandler
+{
+public:
+ AllAnimationEventHandler( EventQueue& rEventQueue ) :
+ mrEventQueue( rEventQueue ),
+ maAnimationEventMap()
+ {}
+
+ virtual void dispose()
+ {
+ maAnimationEventMap.clear();
+ }
+
+ virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
+ {
+ ENSURE_OR_RETURN_FALSE(
+ rNode,
+ "AllAnimationEventHandler::handleAnimationEvent(): Invalid node" );
+
+ bool bRet( false );
+
+ ImpAnimationEventMap::iterator aIter;
+ if( (aIter=maAnimationEventMap.find(
+ rNode->getXAnimationNode() )) != maAnimationEventMap.end() )
+ {
+ ImpEventVector& rVec( aIter->second );
+
+ bRet = !rVec.empty();
+
+ // registered node found -> fire all events in the vector
+ std::for_each( rVec.begin(), rVec.end(),
+ boost::bind( &EventQueue::addEvent,
+ boost::ref( mrEventQueue ), _1 ) );
+
+ rVec.clear();
+ }
+
+ return bRet;
+ }
+
+ void addEvent( const EventSharedPtr& rEvent,
+ const uno::Reference< animations::XAnimationNode >& xNode )
+ {
+ ImpAnimationEventMap::iterator aIter;
+ if( (aIter=maAnimationEventMap.find( xNode )) ==
+ maAnimationEventMap.end() )
+ {
+ // no entry for this animation -> create one
+ aIter = maAnimationEventMap.insert(
+ ImpAnimationEventMap::value_type( xNode,
+ ImpEventVector() ) ).first;
+ }
+
+ // add new event to queue
+ aIter->second.push_back( rEvent );
+ }
+
+ bool isEmpty()
+ {
+ // find at least one animation with a non-empty vector
+ ImpAnimationEventMap::const_iterator aCurr( maAnimationEventMap.begin() );
+ const ImpAnimationEventMap::const_iterator aEnd( maAnimationEventMap.end() );
+ while( aCurr != aEnd )
+ {
+ if( !aCurr->second.empty() )
+ return false; // at least one non-empty entry found
+
+ ++aCurr;
+ }
+
+ return true; // not a single non-empty entry found
+ }
+
+private:
+ EventQueue& mrEventQueue;
+ ImpAnimationEventMap maAnimationEventMap;
+};
+
+class ClickEventHandler : public MouseEventHandler_,
+ public EventHandler,
+ public EventContainer
+{
+public:
+ ClickEventHandler( EventQueue& rEventQueue ) :
+ EventContainer(),
+ mrEventQueue( rEventQueue ),
+ mbAdvanceOnClick( true )
+ {}
+
+ void setAdvanceOnClick( bool bAdvanceOnClick )
+ {
+ mbAdvanceOnClick = bAdvanceOnClick;
+ }
+
+private:
+ virtual void dispose()
+ {
+ clearContainer();
+ }
+
+ // triggered by API calls, e.g. space bar
+ virtual bool handleEvent()
+ {
+ return handleEvent_impl();
+ }
+
+ // triggered by mouse release:
+ virtual bool handleMouseReleased( const awt::MouseEvent& evt )
+ {
+ if(evt.Buttons != awt::MouseButton::LEFT)
+ return false;
+
+ if( mbAdvanceOnClick ) {
+ // fire next event
+ return handleEvent_impl();
+ }
+ else {
+ return false; // advance-on-click disabled
+ }
+ }
+
+ // triggered by both:
+ virtual bool handleEvent_impl()
+ {
+ // fire next event:
+ return fireSingleEvent( maEvents, mrEventQueue );
+ }
+
+private:
+ EventQueue& mrEventQueue;
+ bool mbAdvanceOnClick;
+};
+
+class SkipEffectEventHandler : public ClickEventHandler
+{
+public:
+ SkipEffectEventHandler( EventQueue & rEventQueue,
+ EventMultiplexer & rEventMultiplexer )
+ : ClickEventHandler(rEventQueue),
+ mrEventQueue(rEventQueue),
+ mrEventMultiplexer(rEventMultiplexer),
+ mbSkipTriggersNextEffect(true) {}
+
+ /** Remember to trigger (or not to trigger) the next effect after the
+ current effect is skiped.
+ */
+ void setSkipTriggersNextEffect (const bool bSkipTriggersNextEffect)
+ { mbSkipTriggersNextEffect = bSkipTriggersNextEffect; }
+
+ /// Skip the current effect but do not triggere the next effect.
+ void skipEffect (void) { handleEvent_impl(false); }
+
+private:
+ virtual bool handleEvent_impl()
+ {
+ return handleEvent_impl(true);
+ }
+
+ bool handleEvent_impl (bool bNotifyNextEffect)
+ {
+ // fire all events, so animation nodes can register their
+ // next effect listeners:
+ if(fireAllEvents( maEvents, mrEventQueue ))
+ {
+ if (mbSkipTriggersNextEffect && bNotifyNextEffect)
+ {
+ // then simulate a next effect event: this skip effect
+ // handler is triggered upon next effect events (multiplexer
+ // prio=-1)! Posting a notifyNextEffect() here is only safe
+ // (we don't run into busy loop), because we assume that
+ // someone has registerered above for next effects
+ // (multiplexer prio=0) at the user event queue.
+ return mrEventQueue.addEventWhenQueueIsEmpty(
+ makeEvent( boost::bind( &EventMultiplexer::notifyNextEffect,
+ boost::ref(mrEventMultiplexer) ),
+ "EventMultiplexer::notifyNextEffect") );
+ }
+ else
+ return true;
+ }
+ return false;
+ }
+
+private:
+ EventQueue & mrEventQueue;
+ EventMultiplexer & mrEventMultiplexer;
+ bool mbSkipTriggersNextEffect;
+};
+
+class RewindEffectEventHandler : public MouseEventHandler_,
+ public EventContainer
+{
+public:
+ RewindEffectEventHandler( EventQueue & rEventQueue )
+ : EventContainer(), mrEventQueue(rEventQueue) {}
+
+private:
+ virtual void dispose()
+ {
+ clearContainer();
+ }
+
+ virtual bool handleMouseReleased( awt::MouseEvent const& evt )
+ {
+ if(evt.Buttons != awt::MouseButton::RIGHT)
+ return false;
+
+ return fireAllEvents( maEvents, mrEventQueue );
+ }
+
+private:
+ EventQueue & mrEventQueue;
+};
+
+/** Base class to share some common code between
+ ShapeClickEventHandler and MouseMoveHandler
+
+ @derive override necessary MouseEventHandler interface methods,
+ call sendEvent() method to actually process the event.
+*/
+class MouseHandlerBase : public MouseEventHandler_
+{
+public:
+ MouseHandlerBase( EventQueue& rEventQueue ) :
+ mrEventQueue( rEventQueue ),
+ maShapeEventMap()
+ {}
+
+ virtual void dispose()
+ {
+ // TODO(Q1): Check whether plain vector with swap idiom is
+ // okay here
+ maShapeEventMap = ImpShapeEventMap();
+ }
+
+ void addEvent( const EventSharedPtr& rEvent,
+ const ShapeSharedPtr& rShape )
+ {
+ ImpShapeEventMap::iterator aIter;
+ if( (aIter=maShapeEventMap.find( rShape )) == maShapeEventMap.end() )
+ {
+ // no entry for this shape -> create one
+ aIter = maShapeEventMap.insert(
+ ImpShapeEventMap::value_type( rShape,
+ ImpEventQueue() ) ).first;
+ }
+
+ // add new event to queue
+ aIter->second.push( rEvent );
+ }
+
+ bool isEmpty()
+ {
+ // find at least one shape with a non-empty queue
+ ImpShapeEventMap::reverse_iterator aCurrShape( maShapeEventMap.begin());
+ ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.end() );
+ while( aCurrShape != aEndShape )
+ {
+ if( !aCurrShape->second.empty() )
+ return false; // at least one non-empty entry found
+
+ ++aCurrShape;
+ }
+
+ return true; // not a single non-empty entry found
+ }
+
+protected:
+ bool hitTest( const awt::MouseEvent& e,
+ ImpShapeEventMap::reverse_iterator& o_rHitShape )
+ {
+ // find hit shape in map
+ const basegfx::B2DPoint aPosition( e.X, e.Y );
+
+ // find matching shape (scan reversely, to coarsely match
+ // paint order)
+ ImpShapeEventMap::reverse_iterator aCurrShape(maShapeEventMap.rbegin());
+ const ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.rend() );
+ while( aCurrShape != aEndShape )
+ {
+ // TODO(F2): Get proper geometry polygon from the
+ // shape, to avoid having areas outside the shape
+ // react on the mouse
+ if( aCurrShape->first->getBounds().isInside( aPosition ) &&
+ aCurrShape->first->isVisible() )
+ {
+ // shape hit, and shape is visible - report a
+ // hit
+ o_rHitShape = aCurrShape;
+ return true;
+ }
+
+ ++aCurrShape;
+ }
+
+ return false; // nothing hit
+ }
+
+ bool sendEvent( ImpShapeEventMap::reverse_iterator& io_rHitShape )
+ {
+ // take next event from queue
+ const bool bRet( fireSingleEvent( io_rHitShape->second,
+ mrEventQueue ) );
+
+ // clear shape entry, if its queue is
+ // empty. This is important, since the shapes
+ // are held by shared ptr, and might otherwise
+ // not get released, even after their owning
+ // slide is long gone.
+ if( io_rHitShape->second.empty() )
+ {
+ // this looks funny, since ::std::map does
+ // provide an erase( iterator )
+ // method. Unfortunately, stlport does not
+ // declare the obvious erase(
+ // reverse_iterator ) needed here (missing
+ // orthogonality, eh?)
+ maShapeEventMap.erase( io_rHitShape->first );
+ }
+
+ return bRet;
+ }
+
+ bool processEvent( const awt::MouseEvent& e )
+ {
+ ImpShapeEventMap::reverse_iterator aCurrShape;
+
+ if( hitTest( e, aCurrShape ) )
+ return sendEvent( aCurrShape );
+
+ return false; // did not handle the event
+ }
+
+private:
+ EventQueue& mrEventQueue;
+ ImpShapeEventMap maShapeEventMap;
+};
+
+class ShapeClickEventHandler : public MouseHandlerBase
+{
+public:
+ ShapeClickEventHandler( CursorManager& rCursorManager,
+ EventQueue& rEventQueue ) :
+ MouseHandlerBase( rEventQueue ),
+ mrCursorManager( rCursorManager )
+ {}
+
+ virtual bool handleMouseReleased( const awt::MouseEvent& e )
+ {
+ if(e.Buttons != awt::MouseButton::LEFT)
+ return false;
+ return processEvent( e );
+ }
+
+ virtual bool handleMouseMoved( const awt::MouseEvent& e )
+ {
+ // TODO(P2): Maybe buffer last shape touched
+
+ // if we have a shape click event, and the mouse
+ // hovers over this shape, change cursor to hand
+ ImpShapeEventMap::reverse_iterator aDummy;
+ if( hitTest( e, aDummy ) )
+ mrCursorManager.requestCursor( awt::SystemPointer::REFHAND );
+
+ return false; // we don't /eat/ this event. Lower prio
+ // handler should see it, too.
+ }
+
+private:
+ CursorManager& mrCursorManager;
+};
+
+class MouseEnterHandler : public MouseHandlerBase
+{
+public:
+ MouseEnterHandler( EventQueue& rEventQueue )
+ : MouseHandlerBase( rEventQueue ),
+ mpLastShape() {}
+
+ virtual bool handleMouseMoved( const awt::MouseEvent& e )
+ {
+ // TODO(P2): Maybe buffer last shape touched, and
+ // check against that _first_
+
+ ImpShapeEventMap::reverse_iterator aCurr;
+ if( hitTest( e, aCurr ) )
+ {
+ if( aCurr->first != mpLastShape )
+ {
+ // we actually hit a shape, and it's different
+ // from the previous one - thus we just
+ // entered it, raise event
+ sendEvent( aCurr );
+ mpLastShape = aCurr->first;
+ }
+ }
+ else
+ {
+ // don't hit no shape - thus, last shape is NULL
+ mpLastShape.reset();
+ }
+
+ return false; // we don't /eat/ this event. Lower prio
+ // handler should see it, too.
+ }
+
+private:
+ ShapeSharedPtr mpLastShape;
+};
+
+class MouseLeaveHandler : public MouseHandlerBase
+{
+public:
+ MouseLeaveHandler( EventQueue& rEventQueue )
+ : MouseHandlerBase( rEventQueue ),
+ maLastIter() {}
+
+ virtual bool handleMouseMoved( const awt::MouseEvent& e )
+ {
+ // TODO(P2): Maybe buffer last shape touched, and
+ // check against that _first_
+
+ ImpShapeEventMap::reverse_iterator aCurr;
+ if( hitTest( e, aCurr ) )
+ {
+ maLastIter = aCurr;
+ }
+ else
+ {
+ if( maLastIter->first )
+ {
+ // last time, we were over a shape, now we're
+ // not - we thus just left that shape, raise
+ // event
+ sendEvent( maLastIter );
+ }
+
+ // in any case, when we hit this else-branch: no
+ // shape hit, thus have to clear maLastIter
+ maLastIter = ImpShapeEventMap::reverse_iterator();
+ }
+
+ return false; // we don't /eat/ this event. Lower prio
+ // handler should see it, too.
+ }
+
+private:
+ ImpShapeEventMap::reverse_iterator maLastIter;
+};
+
+template< typename Handler, typename Functor >
+void UserEventQueue::registerEvent(
+ boost::shared_ptr< Handler >& rHandler,
+ const EventSharedPtr& rEvent,
+ const Functor& rRegistrationFunctor )
+{
+ ENSURE_OR_THROW( rEvent,
+ "UserEventQueue::registerEvent(): Invalid event" );
+
+ if( !rHandler ) {
+ // create handler
+ rHandler.reset( new Handler( mrEventQueue ) );
+ // register handler on EventMultiplexer
+ rRegistrationFunctor( rHandler );
+ }
+
+ rHandler->addEvent( rEvent );
+}
+
+template< typename Handler, typename Arg, typename Functor >
+void UserEventQueue::registerEvent(
+ boost::shared_ptr< Handler >& rHandler,
+ const EventSharedPtr& rEvent,
+ const Arg& rArg,
+ const Functor& rRegistrationFunctor )
+{
+ ENSURE_OR_THROW( rEvent,
+ "UserEventQueue::registerEvent(): Invalid event" );
+
+ if( !rHandler ) {
+ // create handler
+ rHandler.reset( new Handler( mrEventQueue ) );
+
+ // register handler on EventMultiplexer
+ rRegistrationFunctor( rHandler );
+ }
+
+ rHandler->addEvent( rEvent, rArg );
+}
+
+
+// Public methods
+// =====================================================
+
+UserEventQueue::UserEventQueue( EventMultiplexer& rMultiplexer,
+ EventQueue& rEventQueue,
+ CursorManager& rCursorManager )
+ : mrMultiplexer( rMultiplexer ),
+ mrEventQueue( rEventQueue ),
+ mrCursorManager( rCursorManager ),
+ mpStartEventHandler(),
+ mpEndEventHandler(),
+ mpAnimationStartEventHandler(),
+ mpAnimationEndEventHandler(),
+ mpAudioStoppedEventHandler(),
+ mpClickEventHandler(),
+ mpSkipEffectEventHandler(),
+ mpRewindEffectEventHandler(),
+ mpDoubleClickEventHandler(),
+ mpMouseEnterHandler(),
+ mpMouseLeaveHandler(),
+ mbAdvanceOnClick( true )
+{
+}
+
+UserEventQueue::~UserEventQueue()
+{
+ try
+ {
+ // unregister all handlers
+ clear();
+ }
+ catch (uno::Exception &) {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+}
+
+bool UserEventQueue::isEmpty() const
+{
+ // TODO(T2): This is not thread safe, the handlers are all
+ // only separately synchronized. This poses the danger of
+ // generating false empty status on XSlideShow::update(), such
+ // that the last events of a slide are not triggered.
+
+ // we're empty iff all handler queues are empty
+ return
+ (mpStartEventHandler ? mpStartEventHandler->isEmpty() : true) &&
+ (mpEndEventHandler ? mpEndEventHandler->isEmpty() : true) &&
+ (mpAnimationStartEventHandler ? mpAnimationStartEventHandler->isEmpty() : true) &&
+ (mpAnimationEndEventHandler ? mpAnimationEndEventHandler->isEmpty() : true) &&
+ (mpAudioStoppedEventHandler ? mpAudioStoppedEventHandler->isEmpty() : true) &&
+ (mpShapeClickEventHandler ? mpShapeClickEventHandler->isEmpty() : true) &&
+ (mpClickEventHandler ? mpClickEventHandler->isEmpty() : true) &&
+ (mpSkipEffectEventHandler ? mpSkipEffectEventHandler->isEmpty() : true) &&
+ (mpRewindEffectEventHandler ? mpRewindEffectEventHandler->isEmpty() : true) &&
+ (mpShapeDoubleClickEventHandler ? mpShapeDoubleClickEventHandler->isEmpty() : true) &&
+ (mpDoubleClickEventHandler ? mpDoubleClickEventHandler->isEmpty() : true) &&
+ (mpMouseEnterHandler ? mpMouseEnterHandler->isEmpty() : true) &&
+ (mpMouseLeaveHandler ? mpMouseLeaveHandler->isEmpty() : true);
+}
+
+void UserEventQueue::clear()
+{
+ // unregister and delete all handlers
+ if( mpStartEventHandler ) {
+ mrMultiplexer.removeSlideStartHandler( mpStartEventHandler );
+ mpStartEventHandler.reset();
+ }
+ if( mpEndEventHandler ) {
+ mrMultiplexer.removeSlideEndHandler( mpEndEventHandler );
+ mpEndEventHandler.reset();
+ }
+ if( mpAnimationStartEventHandler ) {
+ mrMultiplexer.removeAnimationStartHandler(
+ mpAnimationStartEventHandler );
+ mpAnimationStartEventHandler.reset();
+ }
+ if( mpAnimationEndEventHandler ) {
+ mrMultiplexer.removeAnimationEndHandler( mpAnimationEndEventHandler );
+ mpAnimationEndEventHandler.reset();
+ }
+ if( mpAudioStoppedEventHandler ) {
+ mrMultiplexer.removeAudioStoppedHandler( mpAudioStoppedEventHandler );
+ mpAudioStoppedEventHandler.reset();
+ }
+ if( mpShapeClickEventHandler ) {
+ mrMultiplexer.removeClickHandler( mpShapeClickEventHandler );
+ mrMultiplexer.removeMouseMoveHandler( mpShapeClickEventHandler );
+ mpShapeClickEventHandler.reset();
+ }
+ if( mpClickEventHandler ) {
+ mrMultiplexer.removeClickHandler( mpClickEventHandler );
+ mrMultiplexer.removeNextEffectHandler( mpClickEventHandler );
+ mpClickEventHandler.reset();
+ }
+ if(mpSkipEffectEventHandler) {
+ mrMultiplexer.removeClickHandler( mpSkipEffectEventHandler );
+ mrMultiplexer.removeNextEffectHandler( mpSkipEffectEventHandler );
+ mpSkipEffectEventHandler.reset();
+ }
+ if(mpRewindEffectEventHandler) {
+ mrMultiplexer.removeClickHandler( mpRewindEffectEventHandler );
+ mpRewindEffectEventHandler.reset();
+ }
+ if( mpShapeDoubleClickEventHandler ) {
+ mrMultiplexer.removeDoubleClickHandler( mpShapeDoubleClickEventHandler );
+ mrMultiplexer.removeMouseMoveHandler( mpShapeDoubleClickEventHandler );
+ mpShapeDoubleClickEventHandler.reset();
+ }
+ if( mpDoubleClickEventHandler ) {
+ mrMultiplexer.removeDoubleClickHandler( mpDoubleClickEventHandler );
+ mpDoubleClickEventHandler.reset();
+ }
+ if( mpMouseEnterHandler ) {
+ mrMultiplexer.removeMouseMoveHandler( mpMouseEnterHandler );
+ mpMouseEnterHandler.reset();
+ }
+ if( mpMouseLeaveHandler ) {
+ mrMultiplexer.removeMouseMoveHandler( mpMouseLeaveHandler );
+ mpMouseLeaveHandler.reset();
+ }
+}
+
+void UserEventQueue::setAdvanceOnClick( bool bAdvanceOnClick )
+{
+ mbAdvanceOnClick = bAdvanceOnClick;
+
+ // forward to handler, if existing. Otherwise, the handler
+ // creation will do the forwarding.
+ if( mpClickEventHandler )
+ mpClickEventHandler->setAdvanceOnClick( bAdvanceOnClick );
+}
+
+
+void UserEventQueue::registerSlideStartEvent( const EventSharedPtr& rEvent )
+{
+ registerEvent( mpStartEventHandler,
+ rEvent,
+ boost::bind( &EventMultiplexer::addSlideStartHandler,
+ boost::ref( mrMultiplexer ), _1 ) );
+}
+
+void UserEventQueue::registerSlideEndEvent( const EventSharedPtr& rEvent )
+{
+ registerEvent( mpEndEventHandler,
+ rEvent,
+ boost::bind( &EventMultiplexer::addSlideEndHandler,
+ boost::ref( mrMultiplexer ), _1 ) );
+}
+
+void UserEventQueue::registerAnimationStartEvent(
+ const EventSharedPtr& rEvent,
+ const uno::Reference< animations::XAnimationNode>& xNode )
+{
+ registerEvent( mpAnimationStartEventHandler,
+ rEvent,
+ xNode,
+ boost::bind( &EventMultiplexer::addAnimationStartHandler,
+ boost::ref( mrMultiplexer ), _1 ) );
+}
+
+void UserEventQueue::registerAnimationEndEvent(
+ const EventSharedPtr& rEvent,
+ const uno::Reference<animations::XAnimationNode>& xNode )
+{
+ registerEvent( mpAnimationEndEventHandler,
+ rEvent,
+ xNode,
+ boost::bind( &EventMultiplexer::addAnimationEndHandler,
+ boost::ref( mrMultiplexer ), _1 ) );
+}
+
+void UserEventQueue::registerAudioStoppedEvent(
+ const EventSharedPtr& rEvent,
+ const uno::Reference<animations::XAnimationNode>& xNode )
+{
+ registerEvent( mpAudioStoppedEventHandler,
+ rEvent,
+ xNode,
+ boost::bind( &EventMultiplexer::addAudioStoppedHandler,
+ boost::ref( mrMultiplexer ), _1 ) );
+}
+
+void UserEventQueue::registerShapeClickEvent( const EventSharedPtr& rEvent,
+ const ShapeSharedPtr& rShape )
+{
+ ENSURE_OR_THROW(
+ rEvent,
+ "UserEventQueue::registerShapeClickEvent(): Invalid event" );
+
+ if( !mpShapeClickEventHandler )
+ {
+ // create handler
+ mpShapeClickEventHandler.reset(
+ new ShapeClickEventHandler(mrCursorManager,
+ mrEventQueue) );
+
+ // register handler on EventMultiplexer
+ mrMultiplexer.addClickHandler( mpShapeClickEventHandler, 1.0 );
+ mrMultiplexer.addMouseMoveHandler( mpShapeClickEventHandler, 1.0 );
+ }
+
+ mpShapeClickEventHandler->addEvent( rEvent, rShape );
+}
+
+namespace {
+class ClickEventRegistrationFunctor
+{
+public:
+ ClickEventRegistrationFunctor( EventMultiplexer& rMultiplexer,
+ double nPrio,
+ bool bAdvanceOnClick )
+ : mrMultiplexer( rMultiplexer ),
+ mnPrio(nPrio),
+ mbAdvanceOnClick( bAdvanceOnClick ) {}
+
+ void operator()( const boost::shared_ptr<ClickEventHandler>& rHandler )const
+ {
+ // register the handler on _two_ sources: we want the
+ // nextEffect events, e.g. space bar, to trigger clicks, as well!
+ mrMultiplexer.addClickHandler( rHandler, mnPrio );
+ mrMultiplexer.addNextEffectHandler( rHandler, mnPrio );
+
+ // forward advance-on-click state to newly
+ // generated handler (that's the only reason why
+ // we're called here)
+ rHandler->setAdvanceOnClick( mbAdvanceOnClick );
+ }
+
+private:
+ EventMultiplexer& mrMultiplexer;
+ double const mnPrio;
+ bool const mbAdvanceOnClick;
+};
+} // anon namespace
+
+void UserEventQueue::registerNextEffectEvent( const EventSharedPtr& rEvent )
+{
+ // TODO: better name may be mpNextEffectEventHandler? then we have
+ // next effect (=> waiting to be started)
+ // skip effect (skipping the currently running one)
+ // rewind effect (rewinding back running one and waiting (again)
+ // to be started)
+ registerEvent( mpClickEventHandler,
+ rEvent,
+ ClickEventRegistrationFunctor( mrMultiplexer,
+ 0.0 /* default prio */,
+ mbAdvanceOnClick ) );
+}
+
+void UserEventQueue::registerSkipEffectEvent(
+ EventSharedPtr const & pEvent,
+ const bool bSkipTriggersNextEffect)
+{
+ if(!mpSkipEffectEventHandler)
+ {
+ mpSkipEffectEventHandler.reset(
+ new SkipEffectEventHandler( mrEventQueue, mrMultiplexer ) );
+ // register the handler on _two_ sources: we want the
+ // nextEffect events, e.g. space bar, to trigger clicks, as well!
+ mrMultiplexer.addClickHandler( mpSkipEffectEventHandler,
+ -1.0 /* prio below default */ );
+ mrMultiplexer.addNextEffectHandler( mpSkipEffectEventHandler,
+ -1.0 /* prio below default */ );
+ // forward advance-on-click state to newly
+ // generated handler (that's the only reason why
+ // we're called here)
+ mpSkipEffectEventHandler->setAdvanceOnClick( mbAdvanceOnClick );
+ }
+ mpSkipEffectEventHandler->setSkipTriggersNextEffect(bSkipTriggersNextEffect);
+ mpSkipEffectEventHandler->addEvent( pEvent );
+}
+
+void UserEventQueue::registerRewindEffectEvent( EventSharedPtr const& pEvent )
+{
+ registerEvent( mpRewindEffectEventHandler,
+ pEvent,
+ boost::bind( &EventMultiplexer::addClickHandler,
+ boost::ref(mrMultiplexer), _1,
+ -1.0 /* prio below default */ ) );
+}
+
+void UserEventQueue::registerShapeDoubleClickEvent(
+ const EventSharedPtr& rEvent,
+ const ShapeSharedPtr& rShape )
+{
+ ENSURE_OR_THROW(
+ rEvent,
+ "UserEventQueue::registerShapeDoubleClickEvent(): Invalid event" );
+
+ if( !mpShapeDoubleClickEventHandler )
+ {
+ // create handler
+ mpShapeDoubleClickEventHandler.reset(
+ new ShapeClickEventHandler(mrCursorManager,
+ mrEventQueue) );
+
+ // register handler on EventMultiplexer
+ mrMultiplexer.addDoubleClickHandler( mpShapeDoubleClickEventHandler,
+ 1.0 );
+ mrMultiplexer.addMouseMoveHandler( mpShapeDoubleClickEventHandler,
+ 1.0 );
+ }
+
+ mpShapeDoubleClickEventHandler->addEvent( rEvent, rShape );
+}
+
+void UserEventQueue::registerDoubleClickEvent( const EventSharedPtr& rEvent )
+{
+ registerEvent( mpDoubleClickEventHandler,
+ rEvent,
+ boost::bind( &EventMultiplexer::addDoubleClickHandler,
+ boost::ref( mrMultiplexer ), _1,
+ 0.0 /* default prio */ ) );
+}
+
+void UserEventQueue::registerMouseEnterEvent( const EventSharedPtr& rEvent,
+ const ShapeSharedPtr& rShape )
+{
+ registerEvent( mpMouseEnterHandler,
+ rEvent,
+ rShape,
+ boost::bind( &EventMultiplexer::addMouseMoveHandler,
+ boost::ref( mrMultiplexer ), _1,
+ 0.0 /* default prio */ ) );
+}
+
+void UserEventQueue::registerMouseLeaveEvent( const EventSharedPtr& rEvent,
+ const ShapeSharedPtr& rShape )
+{
+ registerEvent( mpMouseLeaveHandler,
+ rEvent,
+ rShape,
+ boost::bind( &EventMultiplexer::addMouseMoveHandler,
+ boost::ref( mrMultiplexer ), _1,
+ 0.0 /* default prio */ ) );
+}
+
+void UserEventQueue::callSkipEffectEventHandler (void)
+{
+ ::boost::shared_ptr<SkipEffectEventHandler> pHandler (
+ ::boost::dynamic_pointer_cast<SkipEffectEventHandler>(mpSkipEffectEventHandler));
+ if (pHandler)
+ pHandler->skipEffect();
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/waitsymbol.cxx b/slideshow/source/engine/waitsymbol.cxx
new file mode 100644
index 000000000000..c96b11f6d4e9
--- /dev/null
+++ b/slideshow/source/engine/waitsymbol.cxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <boost/current_function.hpp>
+#include <canvas/canvastools.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+
+#include "waitsymbol.hxx"
+#include "eventmultiplexer.hxx"
+
+#include <o3tl/compat_functional.hxx>
+#include <algorithm>
+
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+const sal_Int32 LEFT_BORDER_SPACE = 10;
+const sal_Int32 LOWER_BORDER_SPACE = 10;
+
+WaitSymbolSharedPtr WaitSymbol::create( const uno::Reference<rendering::XBitmap>& xBitmap,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ const UnoViewContainer& rViewContainer )
+{
+ WaitSymbolSharedPtr pRet(
+ new WaitSymbol( xBitmap,
+ rScreenUpdater,
+ rViewContainer ));
+
+ rEventMultiplexer.addViewHandler( pRet );
+
+ return pRet;
+}
+
+WaitSymbol::WaitSymbol( uno::Reference<rendering::XBitmap> const & xBitmap,
+ ScreenUpdater& rScreenUpdater,
+ const UnoViewContainer& rViewContainer ) :
+ mxBitmap(xBitmap),
+ maViews(),
+ mrScreenUpdater( rScreenUpdater ),
+ mbVisible(false)
+{
+ std::for_each( rViewContainer.begin(),
+ rViewContainer.end(),
+ boost::bind( &WaitSymbol::viewAdded,
+ this,
+ _1 ));
+}
+
+void WaitSymbol::setVisible( const bool bVisible )
+{
+ if( mbVisible != bVisible )
+ {
+ mbVisible = bVisible;
+
+ ViewsVecT::const_iterator aIter( maViews.begin() );
+ ViewsVecT::const_iterator const aEnd ( maViews.end() );
+ while( aIter != aEnd )
+ {
+ if( aIter->second )
+ {
+ if( bVisible )
+ aIter->second->show();
+ else
+ aIter->second->hide();
+ }
+
+ ++aIter;
+ }
+
+ // sprites changed, need a screen update for this frame.
+ mrScreenUpdater.requestImmediateUpdate();
+ }
+}
+
+basegfx::B2DPoint WaitSymbol::calcSpritePos(
+ UnoViewSharedPtr const & rView ) const
+{
+ const uno::Reference<rendering::XBitmap> xBitmap( rView->getCanvas()->getUNOCanvas(),
+ uno::UNO_QUERY_THROW );
+ const geometry::IntegerSize2D realSize( xBitmap->getSize() );
+ return basegfx::B2DPoint(
+ std::min<sal_Int32>( realSize.Width, LEFT_BORDER_SPACE ),
+ std::max<sal_Int32>( 0, realSize.Height - mxBitmap->getSize().Height
+ - LOWER_BORDER_SPACE ) );
+}
+
+void WaitSymbol::viewAdded( const UnoViewSharedPtr& rView )
+{
+ cppcanvas::CustomSpriteSharedPtr sprite;
+
+ try
+ {
+ const geometry::IntegerSize2D spriteSize( mxBitmap->getSize() );
+ sprite = rView->createSprite( basegfx::B2DVector( spriteSize.Width,
+ spriteSize.Height ),
+ 1000.0 ); // sprite should be in front of all
+ // other sprites
+ rendering::ViewState viewState;
+ canvas::tools::initViewState( viewState );
+ rendering::RenderState renderState;
+ canvas::tools::initRenderState( renderState );
+ sprite->getContentCanvas()->getUNOCanvas()->drawBitmap(
+ mxBitmap, viewState, renderState );
+
+ sprite->setAlpha( 0.9 );
+ sprite->movePixel( calcSpritePos( rView ) );
+ if( mbVisible )
+ sprite->show();
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+
+ maViews.push_back( ViewsVecT::value_type( rView, sprite ) );
+}
+
+void WaitSymbol::viewRemoved( const UnoViewSharedPtr& rView )
+{
+ maViews.erase(
+ std::remove_if(
+ maViews.begin(), maViews.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( o3tl::select1st<ViewsVecT::value_type>(), _1 ) ) ),
+ maViews.end() );
+}
+
+void WaitSymbol::viewChanged( const UnoViewSharedPtr& rView )
+{
+ // find entry corresponding to modified view
+ ViewsVecT::iterator aModifiedEntry(
+ std::find_if(
+ maViews.begin(),
+ maViews.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( o3tl::select1st<ViewsVecT::value_type>(), _1 ))));
+
+ OSL_ASSERT( aModifiedEntry != maViews.end() );
+ if( aModifiedEntry == maViews.end() )
+ return;
+
+ if( aModifiedEntry->second )
+ aModifiedEntry->second->movePixel(
+ calcSpritePos(aModifiedEntry->first) );
+}
+
+void WaitSymbol::viewsChanged()
+{
+ // reposition sprites on all views
+ ViewsVecT::const_iterator aIter( maViews.begin() );
+ ViewsVecT::const_iterator const aEnd ( maViews.end() );
+ while( aIter != aEnd )
+ {
+ if( aIter->second )
+ aIter->second->movePixel(
+ calcSpritePos( aIter->first ));
+ ++aIter;
+ }
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/waitsymbol.hxx b/slideshow/source/engine/waitsymbol.hxx
new file mode 100644
index 000000000000..98d913500d11
--- /dev/null
+++ b/slideshow/source/engine/waitsymbol.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#if ! defined(WAITSYMBOL_HXX_INCLUDED)
+#define WAITSYMBOL_HXX_INCLUDED
+
+#include <com/sun/star/rendering/XBitmap.hpp>
+#include <cppcanvas/customsprite.hxx>
+
+#include "vieweventhandler.hxx"
+#include "screenupdater.hxx"
+#include "eventmultiplexer.hxx"
+#include "unoview.hxx"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/utility.hpp> // for noncopyable
+#include <vector>
+
+namespace slideshow {
+namespace internal {
+
+class EventMultiplexer;
+typedef boost::shared_ptr<class WaitSymbol> WaitSymbolSharedPtr;
+
+class WaitSymbol : public ViewEventHandler,
+ private ::boost::noncopyable
+{
+public:
+ static WaitSymbolSharedPtr create( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap>& xBitmap,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ const UnoViewContainer& rViewContainer );
+
+ /** Shows the wait symbol.
+ */
+ void show() { setVisible(true); }
+
+ /** Hides the wait symbol.
+ */
+ void hide() { setVisible(false); }
+
+private:
+ WaitSymbol( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap>& xBitmap,
+ ScreenUpdater& rScreenUpdater,
+ const UnoViewContainer& rViewContainer );
+
+ // ViewEventHandler
+ virtual void viewAdded( const UnoViewSharedPtr& rView );
+ virtual void viewRemoved( const UnoViewSharedPtr& rView );
+ virtual void viewChanged( const UnoViewSharedPtr& rView );
+ virtual void viewsChanged();
+
+ void setVisible( const bool bVisible );
+ ::basegfx::B2DPoint calcSpritePos( UnoViewSharedPtr const & rView ) const;
+
+ template <typename func_type>
+ void for_each_sprite( func_type const & func ) const
+ {
+ ViewsVecT::const_iterator iPos( maViews.begin() );
+ const ViewsVecT::const_iterator iEnd( maViews.end() );
+ for ( ; iPos != iEnd; ++iPos )
+ if( iPos->second )
+ func( iPos->second );
+ }
+
+ typedef ::std::vector<
+ ::std::pair<UnoViewSharedPtr,
+ cppcanvas::CustomSpriteSharedPtr> > ViewsVecT;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap> mxBitmap;
+
+ ViewsVecT maViews;
+ ScreenUpdater& mrScreenUpdater;
+ bool mbVisible;
+};
+
+} // namespace internal
+} // namespace presentation
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/wakeupevent.cxx b/slideshow/source/engine/wakeupevent.cxx
new file mode 100644
index 000000000000..6ab4b821cab8
--- /dev/null
+++ b/slideshow/source/engine/wakeupevent.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+
+#include <wakeupevent.hxx>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ WakeupEvent::WakeupEvent(
+ boost::shared_ptr<canvas::tools::ElapsedTime> const & pTimeBase,
+ ActivitiesQueue& rActivityQueue ) :
+#if OSL_DEBUG_LEVEL > 1
+ Event(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("WakeupEvent"))),
+#endif
+ maTimer(pTimeBase),
+ mnNextTime(0.0),
+ mpActivity(),
+ mrActivityQueue( rActivityQueue )
+ {
+ }
+
+ void WakeupEvent::dispose()
+ {
+ mpActivity.reset();
+ }
+
+ bool WakeupEvent::fire()
+ {
+ if( !mpActivity )
+ return false;
+
+ return mrActivityQueue.addActivity( mpActivity );
+ }
+
+ bool WakeupEvent::isCharged() const
+ {
+ // this event won't expire, we fire everytime we're
+ // re-inserted into the event queue.
+ return true;
+ }
+
+ double WakeupEvent::getActivationTime( double nCurrentTime ) const
+ {
+ const double nElapsedTime( maTimer.getElapsedTime() );
+
+ return ::std::max( nCurrentTime,
+ nCurrentTime - nElapsedTime + mnNextTime );
+ }
+
+ void WakeupEvent::start()
+ {
+ // start timer
+ maTimer.reset();
+ }
+
+ void WakeupEvent::setNextTimeout( double rNextTime )
+ {
+ mnNextTime = rNextTime;
+ }
+
+ void WakeupEvent::setActivity( const ActivitySharedPtr& rActivity )
+ {
+ mpActivity = rActivity;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */