1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir // must be first
32*cdf0e10cSrcweir #include <canvas/debug.hxx>
33*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx>
34*cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx>
35*cdf0e10cSrcweir #include <comphelper/anytostring.hxx>
36*cdf0e10cSrcweir #include <com/sun/star/presentation/ParagraphTarget.hpp>
37*cdf0e10cSrcweir #include <com/sun/star/animations/Timing.hpp>
38*cdf0e10cSrcweir #include <com/sun/star/animations/AnimationAdditiveMode.hpp>
39*cdf0e10cSrcweir #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir #include "nodetools.hxx"
42*cdf0e10cSrcweir #include "doctreenode.hxx"
43*cdf0e10cSrcweir #include "animationbasenode.hxx"
44*cdf0e10cSrcweir #include "delayevent.hxx"
45*cdf0e10cSrcweir #include "framerate.hxx"
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir #include <boost/bind.hpp>
48*cdf0e10cSrcweir #include <boost/optional.hpp>
49*cdf0e10cSrcweir #include <algorithm>
50*cdf0e10cSrcweir 
51*cdf0e10cSrcweir using namespace com::sun::star;
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir namespace slideshow {
54*cdf0e10cSrcweir namespace internal {
55*cdf0e10cSrcweir 
56*cdf0e10cSrcweir AnimationBaseNode::AnimationBaseNode(
57*cdf0e10cSrcweir     const uno::Reference< animations::XAnimationNode >&   xNode,
58*cdf0e10cSrcweir     const BaseContainerNodeSharedPtr&                     rParent,
59*cdf0e10cSrcweir     const NodeContext&                                    rContext )
60*cdf0e10cSrcweir     : BaseNode( xNode, rParent, rContext ),
61*cdf0e10cSrcweir       mxAnimateNode( xNode, uno::UNO_QUERY_THROW ),
62*cdf0e10cSrcweir       maAttributeLayerHolder(),
63*cdf0e10cSrcweir       maSlideSize( rContext.maSlideSize ),
64*cdf0e10cSrcweir       mpActivity(),
65*cdf0e10cSrcweir       mpShape(),
66*cdf0e10cSrcweir       mpShapeSubset(),
67*cdf0e10cSrcweir       mpSubsetManager(rContext.maContext.mpSubsettableShapeManager),
68*cdf0e10cSrcweir       mbIsIndependentSubset( rContext.mbIsIndependentSubset )
69*cdf0e10cSrcweir {
70*cdf0e10cSrcweir     // extract native node targets
71*cdf0e10cSrcweir     // ===========================
72*cdf0e10cSrcweir 
73*cdf0e10cSrcweir     // plain shape target
74*cdf0e10cSrcweir     uno::Reference< drawing::XShape > xShape( mxAnimateNode->getTarget(),
75*cdf0e10cSrcweir                                               uno::UNO_QUERY );
76*cdf0e10cSrcweir 
77*cdf0e10cSrcweir     // distinguish 5 cases:
78*cdf0e10cSrcweir     //
79*cdf0e10cSrcweir     //  - plain shape target
80*cdf0e10cSrcweir     //  (NodeContext.mpMasterShapeSubset full set)
81*cdf0e10cSrcweir     //
82*cdf0e10cSrcweir     //  - parent-generated subset (generate an
83*cdf0e10cSrcweir     //  independent subset)
84*cdf0e10cSrcweir     //
85*cdf0e10cSrcweir     //  - parent-generated subset from iteration
86*cdf0e10cSrcweir     //  (generate a dependent subset)
87*cdf0e10cSrcweir     //
88*cdf0e10cSrcweir     //  - XShape target at the XAnimatioNode (generate
89*cdf0e10cSrcweir     //  a plain shape target)
90*cdf0e10cSrcweir     //
91*cdf0e10cSrcweir     //  - ParagraphTarget target at the XAnimationNode
92*cdf0e10cSrcweir     //  (generate an independent shape subset)
93*cdf0e10cSrcweir     if( rContext.mpMasterShapeSubset )
94*cdf0e10cSrcweir     {
95*cdf0e10cSrcweir         if( rContext.mpMasterShapeSubset->isFullSet() )
96*cdf0e10cSrcweir         {
97*cdf0e10cSrcweir             // case 1: plain shape target from parent
98*cdf0e10cSrcweir             mpShape = rContext.mpMasterShapeSubset->getSubsetShape();
99*cdf0e10cSrcweir         }
100*cdf0e10cSrcweir         else
101*cdf0e10cSrcweir         {
102*cdf0e10cSrcweir             // cases 2 & 3: subset shape
103*cdf0e10cSrcweir             mpShapeSubset = rContext.mpMasterShapeSubset;
104*cdf0e10cSrcweir         }
105*cdf0e10cSrcweir     }
106*cdf0e10cSrcweir     else
107*cdf0e10cSrcweir     {
108*cdf0e10cSrcweir         // no parent-provided shape, try to extract
109*cdf0e10cSrcweir         // from XAnimationNode - cases 4 and 5
110*cdf0e10cSrcweir 
111*cdf0e10cSrcweir         if( xShape.is() )
112*cdf0e10cSrcweir         {
113*cdf0e10cSrcweir             mpShape = lookupAttributableShape( getContext().mpSubsettableShapeManager,
114*cdf0e10cSrcweir                                                xShape );
115*cdf0e10cSrcweir         }
116*cdf0e10cSrcweir         else
117*cdf0e10cSrcweir         {
118*cdf0e10cSrcweir             // no shape provided. Maybe a ParagraphTarget?
119*cdf0e10cSrcweir             presentation::ParagraphTarget aTarget;
120*cdf0e10cSrcweir 
121*cdf0e10cSrcweir             if( !(mxAnimateNode->getTarget() >>= aTarget) )
122*cdf0e10cSrcweir                 ENSURE_OR_THROW(
123*cdf0e10cSrcweir                     false, "could not extract any target information" );
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir             xShape = aTarget.Shape;
126*cdf0e10cSrcweir 
127*cdf0e10cSrcweir             ENSURE_OR_THROW( xShape.is(), "invalid shape in ParagraphTarget" );
128*cdf0e10cSrcweir 
129*cdf0e10cSrcweir             mpShape = lookupAttributableShape( getContext().mpSubsettableShapeManager,
130*cdf0e10cSrcweir                                                xShape );
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir             // NOTE: For shapes with ParagraphTarget, we ignore
133*cdf0e10cSrcweir             // the SubItem property. We implicitely assume that it
134*cdf0e10cSrcweir             // is set to ONLY_TEXT.
135*cdf0e10cSrcweir             OSL_ENSURE(
136*cdf0e10cSrcweir                 mxAnimateNode->getSubItem() ==
137*cdf0e10cSrcweir                 presentation::ShapeAnimationSubType::ONLY_TEXT ||
138*cdf0e10cSrcweir                 mxAnimateNode->getSubItem() ==
139*cdf0e10cSrcweir                 presentation::ShapeAnimationSubType::AS_WHOLE,
140*cdf0e10cSrcweir                 "ParagraphTarget given, but subitem not AS_TEXT or AS_WHOLE? "
141*cdf0e10cSrcweir                 "Make up your mind, I'll ignore the subitem." );
142*cdf0e10cSrcweir 
143*cdf0e10cSrcweir             // okay, found a ParagraphTarget with a valid XShape. Does the shape
144*cdf0e10cSrcweir             // provide the given paragraph?
145*cdf0e10cSrcweir             const DocTreeNode& rTreeNode(
146*cdf0e10cSrcweir                 mpShape->getTreeNodeSupplier().getTreeNode(
147*cdf0e10cSrcweir                     aTarget.Paragraph,
148*cdf0e10cSrcweir                     DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ) );
149*cdf0e10cSrcweir 
150*cdf0e10cSrcweir             // CAUTION: the creation of the subset shape
151*cdf0e10cSrcweir             // _must_ stay in the node constructor, since
152*cdf0e10cSrcweir             // Slide::prefetchShow() initializes shape
153*cdf0e10cSrcweir             // attributes right after animation import (or
154*cdf0e10cSrcweir             // the Slide class must be changed).
155*cdf0e10cSrcweir             mpShapeSubset.reset(
156*cdf0e10cSrcweir                 new ShapeSubset( mpShape,
157*cdf0e10cSrcweir                                  rTreeNode,
158*cdf0e10cSrcweir                                  mpSubsetManager ));
159*cdf0e10cSrcweir 
160*cdf0e10cSrcweir             // Override NodeContext, and flag this node as
161*cdf0e10cSrcweir             // a special independent subset one. This is
162*cdf0e10cSrcweir             // important when applying initial attributes:
163*cdf0e10cSrcweir             // independent shape subsets must be setup
164*cdf0e10cSrcweir             // when the slide starts, since they, as their
165*cdf0e10cSrcweir             // name suggest, can have state independent to
166*cdf0e10cSrcweir             // the master shape. The following example
167*cdf0e10cSrcweir             // might illustrate that: a master shape has
168*cdf0e10cSrcweir             // no effect, one of the text paragraphs
169*cdf0e10cSrcweir             // within it has an appear effect. Now, the
170*cdf0e10cSrcweir             // respective paragraph must be invisible when
171*cdf0e10cSrcweir             // the slide is initially shown, and become
172*cdf0e10cSrcweir             // visible only when the effect starts.
173*cdf0e10cSrcweir             mbIsIndependentSubset = true;
174*cdf0e10cSrcweir 
175*cdf0e10cSrcweir             // already enable subset right here, the
176*cdf0e10cSrcweir             // setup of initial shape attributes of
177*cdf0e10cSrcweir             // course needs the subset shape
178*cdf0e10cSrcweir             // generated, to apply e.g. visibility
179*cdf0e10cSrcweir             // changes.
180*cdf0e10cSrcweir             mpShapeSubset->enableSubsetShape();
181*cdf0e10cSrcweir         }
182*cdf0e10cSrcweir     }
183*cdf0e10cSrcweir }
184*cdf0e10cSrcweir 
185*cdf0e10cSrcweir void AnimationBaseNode::dispose()
186*cdf0e10cSrcweir {
187*cdf0e10cSrcweir     if (mpActivity) {
188*cdf0e10cSrcweir         mpActivity->dispose();
189*cdf0e10cSrcweir         mpActivity.reset();
190*cdf0e10cSrcweir     }
191*cdf0e10cSrcweir 
192*cdf0e10cSrcweir     maAttributeLayerHolder.reset();
193*cdf0e10cSrcweir     mxAnimateNode.clear();
194*cdf0e10cSrcweir     mpShape.reset();
195*cdf0e10cSrcweir     mpShapeSubset.reset();
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir     BaseNode::dispose();
198*cdf0e10cSrcweir }
199*cdf0e10cSrcweir 
200*cdf0e10cSrcweir bool AnimationBaseNode::init_st()
201*cdf0e10cSrcweir {
202*cdf0e10cSrcweir     // if we've still got an old activity lying around, dispose it:
203*cdf0e10cSrcweir     if (mpActivity) {
204*cdf0e10cSrcweir         mpActivity->dispose();
205*cdf0e10cSrcweir         mpActivity.reset();
206*cdf0e10cSrcweir     }
207*cdf0e10cSrcweir 
208*cdf0e10cSrcweir     // note: actually disposing the activity too early might cause problems,
209*cdf0e10cSrcweir     // because on dequeued() it calls endAnimation(pAnim->end()), thus ending
210*cdf0e10cSrcweir     // animation _after_ last screen update.
211*cdf0e10cSrcweir     // review that end() is properly called (which calls endAnimation(), too).
212*cdf0e10cSrcweir 
213*cdf0e10cSrcweir     try {
214*cdf0e10cSrcweir         // TODO(F2): For restart functionality, we must regenerate activities,
215*cdf0e10cSrcweir         // since they are not able to reset their state (or implement _that_)
216*cdf0e10cSrcweir         mpActivity = createActivity();
217*cdf0e10cSrcweir     }
218*cdf0e10cSrcweir     catch (uno::Exception const&) {
219*cdf0e10cSrcweir         OSL_ENSURE( false, rtl::OUStringToOString(
220*cdf0e10cSrcweir                         comphelper::anyToString(cppu::getCaughtException()),
221*cdf0e10cSrcweir                         RTL_TEXTENCODING_UTF8 ) );
222*cdf0e10cSrcweir         // catch and ignore. We later handle empty activities, but for
223*cdf0e10cSrcweir         // other nodes to function properly, the core functionality of
224*cdf0e10cSrcweir         // this node must remain up and running.
225*cdf0e10cSrcweir     }
226*cdf0e10cSrcweir     return true;
227*cdf0e10cSrcweir }
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir bool AnimationBaseNode::resolve_st()
230*cdf0e10cSrcweir {
231*cdf0e10cSrcweir     // enable shape subset for automatically generated
232*cdf0e10cSrcweir     // subsets. Independent subsets are already setup
233*cdf0e10cSrcweir     // during construction time. Doing it only here
234*cdf0e10cSrcweir     // saves us a lot of sprites and shapes lying
235*cdf0e10cSrcweir     // around. This is especially important for
236*cdf0e10cSrcweir     // character-wise iterations, since the shape
237*cdf0e10cSrcweir     // content (e.g. thousands of characters) would
238*cdf0e10cSrcweir     // otherwise be painted character-by-character.
239*cdf0e10cSrcweir     if (isDependentSubsettedShape() && mpShapeSubset) {
240*cdf0e10cSrcweir         mpShapeSubset->enableSubsetShape();
241*cdf0e10cSrcweir     }
242*cdf0e10cSrcweir     return true;
243*cdf0e10cSrcweir }
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir void AnimationBaseNode::activate_st()
246*cdf0e10cSrcweir {
247*cdf0e10cSrcweir     // create new attribute layer
248*cdf0e10cSrcweir     maAttributeLayerHolder.createAttributeLayer( getShape() );
249*cdf0e10cSrcweir 
250*cdf0e10cSrcweir     ENSURE_OR_THROW( maAttributeLayerHolder.get(),
251*cdf0e10cSrcweir                       "Could not generate shape attribute layer" );
252*cdf0e10cSrcweir 
253*cdf0e10cSrcweir     // TODO(Q2): This affects the way mpActivity
254*cdf0e10cSrcweir     // works, but is performed here because of
255*cdf0e10cSrcweir     // locality (we're fiddling with the additive mode
256*cdf0e10cSrcweir     // here, anyway, and it's the only place where we
257*cdf0e10cSrcweir     // do). OTOH, maybe the complete additive mode
258*cdf0e10cSrcweir     // setup should be moved to the activities.
259*cdf0e10cSrcweir 
260*cdf0e10cSrcweir     // for simple by-animations, the SMIL spec
261*cdf0e10cSrcweir     // requires us to emulate "0,by-value" value list
262*cdf0e10cSrcweir     // behaviour, with additive mode forced to "sum",
263*cdf0e10cSrcweir     // no matter what the input is
264*cdf0e10cSrcweir     // (http://www.w3.org/TR/smil20/animation.html#adef-by).
265*cdf0e10cSrcweir     if( mxAnimateNode->getBy().hasValue() &&
266*cdf0e10cSrcweir         !mxAnimateNode->getTo().hasValue() &&
267*cdf0e10cSrcweir         !mxAnimateNode->getFrom().hasValue() )
268*cdf0e10cSrcweir     {
269*cdf0e10cSrcweir         // force attribute mode to REPLACE (note the
270*cdf0e10cSrcweir         // subtle discrepancy to the paragraph above,
271*cdf0e10cSrcweir         // where SMIL requires SUM. This is internally
272*cdf0e10cSrcweir         // handled by the FromToByActivity, and is
273*cdf0e10cSrcweir         // because otherwise DOM values would not be
274*cdf0e10cSrcweir         // handled correctly: the activity cannot
275*cdf0e10cSrcweir         // determine whether an
276*cdf0e10cSrcweir         // Activity::getUnderlyingValue() yields the
277*cdf0e10cSrcweir         // DOM value, or already a summed-up conglomerate)
278*cdf0e10cSrcweir         //
279*cdf0e10cSrcweir         // Note that this poses problems with our
280*cdf0e10cSrcweir         // hybrid activity duration (time or min number of frames),
281*cdf0e10cSrcweir         // since if activities
282*cdf0e10cSrcweir         // exceed their duration, wrong 'by' start
283*cdf0e10cSrcweir         // values might arise ('Laser effect')
284*cdf0e10cSrcweir         maAttributeLayerHolder.get()->setAdditiveMode(
285*cdf0e10cSrcweir             animations::AnimationAdditiveMode::REPLACE );
286*cdf0e10cSrcweir     }
287*cdf0e10cSrcweir     else
288*cdf0e10cSrcweir     {
289*cdf0e10cSrcweir         // apply additive mode to newly created Attribute layer
290*cdf0e10cSrcweir         maAttributeLayerHolder.get()->setAdditiveMode(
291*cdf0e10cSrcweir             mxAnimateNode->getAdditive() );
292*cdf0e10cSrcweir     }
293*cdf0e10cSrcweir 
294*cdf0e10cSrcweir     // fake normal animation behaviour, even if we
295*cdf0e10cSrcweir     // show nothing.  This is the appropriate way to
296*cdf0e10cSrcweir     // handle errors on Activity generation, because
297*cdf0e10cSrcweir     // maybe all other effects on the slide are
298*cdf0e10cSrcweir     // correctly initialized (but won't run, if we
299*cdf0e10cSrcweir     // signal an error here)
300*cdf0e10cSrcweir     if (mpActivity) {
301*cdf0e10cSrcweir         // supply Activity (and the underlying Animation) with
302*cdf0e10cSrcweir         // it's AttributeLayer, to perform the animation on
303*cdf0e10cSrcweir         mpActivity->setTargets( getShape(), maAttributeLayerHolder.get() );
304*cdf0e10cSrcweir 
305*cdf0e10cSrcweir         // add to activities queue
306*cdf0e10cSrcweir         getContext().mrActivitiesQueue.addActivity( mpActivity );
307*cdf0e10cSrcweir     }
308*cdf0e10cSrcweir     else {
309*cdf0e10cSrcweir         // Actually, DO generate the event for empty activity,
310*cdf0e10cSrcweir         // to keep the chain of animations running
311*cdf0e10cSrcweir         BaseNode::scheduleDeactivationEvent();
312*cdf0e10cSrcweir     }
313*cdf0e10cSrcweir }
314*cdf0e10cSrcweir 
315*cdf0e10cSrcweir void AnimationBaseNode::deactivate_st( NodeState eDestState )
316*cdf0e10cSrcweir {
317*cdf0e10cSrcweir     if (eDestState == FROZEN) {
318*cdf0e10cSrcweir         if (mpActivity)
319*cdf0e10cSrcweir             mpActivity->end();
320*cdf0e10cSrcweir     }
321*cdf0e10cSrcweir 
322*cdf0e10cSrcweir     if (isDependentSubsettedShape()) {
323*cdf0e10cSrcweir         // for dependent subsets, remove subset shape
324*cdf0e10cSrcweir         // from layer, re-integrate subsetted part
325*cdf0e10cSrcweir         // back into original shape. For independent
326*cdf0e10cSrcweir         // subsets, we cannot make any assumptions
327*cdf0e10cSrcweir         // about subset attribute state relative to
328*cdf0e10cSrcweir         // master shape, thus, have to keep it. This
329*cdf0e10cSrcweir         // will effectively re-integrate the subsetted
330*cdf0e10cSrcweir         // part into the original shape (whose
331*cdf0e10cSrcweir         // animation will hopefully have ended, too)
332*cdf0e10cSrcweir 
333*cdf0e10cSrcweir         // this statement will save a whole lot of
334*cdf0e10cSrcweir         // sprites for iterated text effects, since
335*cdf0e10cSrcweir         // those sprites will only exist during the
336*cdf0e10cSrcweir         // actual lifetime of the effects
337*cdf0e10cSrcweir         if (mpShapeSubset) {
338*cdf0e10cSrcweir             mpShapeSubset->disableSubsetShape();
339*cdf0e10cSrcweir         }
340*cdf0e10cSrcweir     }
341*cdf0e10cSrcweir 
342*cdf0e10cSrcweir     if (eDestState == ENDED) {
343*cdf0e10cSrcweir 
344*cdf0e10cSrcweir         // no shape anymore, no layer needed:
345*cdf0e10cSrcweir         maAttributeLayerHolder.reset();
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir         if (! isDependentSubsettedShape()) {
348*cdf0e10cSrcweir 
349*cdf0e10cSrcweir             // for all other shapes, removing the
350*cdf0e10cSrcweir             // attribute layer quite possibly changes
351*cdf0e10cSrcweir             // shape display. Thus, force update
352*cdf0e10cSrcweir             AttributableShapeSharedPtr const pShape( getShape() );
353*cdf0e10cSrcweir 
354*cdf0e10cSrcweir             // don't anybody dare to check against
355*cdf0e10cSrcweir             // pShape->isVisible() here, removing the
356*cdf0e10cSrcweir             // attribute layer might actually make the
357*cdf0e10cSrcweir             // shape invisible!
358*cdf0e10cSrcweir             getContext().mpSubsettableShapeManager->notifyShapeUpdate( pShape );
359*cdf0e10cSrcweir         }
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir         if (mpActivity) {
362*cdf0e10cSrcweir             // kill activity, if still running
363*cdf0e10cSrcweir             mpActivity->dispose();
364*cdf0e10cSrcweir             mpActivity.reset();
365*cdf0e10cSrcweir         }
366*cdf0e10cSrcweir     }
367*cdf0e10cSrcweir }
368*cdf0e10cSrcweir 
369*cdf0e10cSrcweir bool AnimationBaseNode::hasPendingAnimation() const
370*cdf0e10cSrcweir {
371*cdf0e10cSrcweir     // TODO(F1): This might not always be true. Are there 'inactive'
372*cdf0e10cSrcweir     // animation nodes?
373*cdf0e10cSrcweir     return true;
374*cdf0e10cSrcweir }
375*cdf0e10cSrcweir 
376*cdf0e10cSrcweir #if defined(VERBOSE) && defined(DBG_UTIL)
377*cdf0e10cSrcweir void AnimationBaseNode::showState() const
378*cdf0e10cSrcweir {
379*cdf0e10cSrcweir     BaseNode::showState();
380*cdf0e10cSrcweir 
381*cdf0e10cSrcweir     VERBOSE_TRACE( "AnimationBaseNode info: independent subset=%s",
382*cdf0e10cSrcweir                    mbIsIndependentSubset ? "y" : "n" );
383*cdf0e10cSrcweir }
384*cdf0e10cSrcweir #endif
385*cdf0e10cSrcweir 
386*cdf0e10cSrcweir ActivitiesFactory::CommonParameters
387*cdf0e10cSrcweir AnimationBaseNode::fillCommonParameters() const
388*cdf0e10cSrcweir {
389*cdf0e10cSrcweir     double nDuration = 0.0;
390*cdf0e10cSrcweir 
391*cdf0e10cSrcweir     // TODO(F3): Duration/End handling is barely there
392*cdf0e10cSrcweir     if( !(mxAnimateNode->getDuration() >>= nDuration) ) {
393*cdf0e10cSrcweir         mxAnimateNode->getEnd() >>= nDuration; // Wah.
394*cdf0e10cSrcweir     }
395*cdf0e10cSrcweir 
396*cdf0e10cSrcweir     // minimal duration we fallback to (avoid 0 here!)
397*cdf0e10cSrcweir     nDuration = ::std::max( 0.001, nDuration );
398*cdf0e10cSrcweir 
399*cdf0e10cSrcweir     const bool bAutoReverse( mxAnimateNode->getAutoReverse() );
400*cdf0e10cSrcweir 
401*cdf0e10cSrcweir     boost::optional<double> aRepeats;
402*cdf0e10cSrcweir     double nRepeats = 0;
403*cdf0e10cSrcweir     if( (mxAnimateNode->getRepeatCount() >>= nRepeats) ) {
404*cdf0e10cSrcweir         aRepeats.reset( nRepeats );
405*cdf0e10cSrcweir     }
406*cdf0e10cSrcweir     else {
407*cdf0e10cSrcweir         if( (mxAnimateNode->getRepeatDuration() >>= nRepeats) ) {
408*cdf0e10cSrcweir             // when repeatDuration is given,
409*cdf0e10cSrcweir             // autoreverse does _not_ modify the
410*cdf0e10cSrcweir             // active duration. Thus, calc repeat
411*cdf0e10cSrcweir             // count with already adapted simple
412*cdf0e10cSrcweir             // duration (twice the specified duration)
413*cdf0e10cSrcweir 
414*cdf0e10cSrcweir             // convert duration back to repeat counts
415*cdf0e10cSrcweir             if( bAutoReverse )
416*cdf0e10cSrcweir                 aRepeats.reset( nRepeats / (2.0 * nDuration) );
417*cdf0e10cSrcweir             else
418*cdf0e10cSrcweir                 aRepeats.reset( nRepeats / nDuration );
419*cdf0e10cSrcweir         }
420*cdf0e10cSrcweir         else {
421*cdf0e10cSrcweir             // no double value for both values - Timing::INDEFINITE?
422*cdf0e10cSrcweir             animations::Timing eTiming;
423*cdf0e10cSrcweir 
424*cdf0e10cSrcweir             if( !(mxAnimateNode->getRepeatDuration() >>= eTiming) ||
425*cdf0e10cSrcweir                 eTiming != animations::Timing_INDEFINITE )
426*cdf0e10cSrcweir             {
427*cdf0e10cSrcweir                 if( !(mxAnimateNode->getRepeatCount() >>= eTiming) ||
428*cdf0e10cSrcweir                     eTiming != animations::Timing_INDEFINITE )
429*cdf0e10cSrcweir                 {
430*cdf0e10cSrcweir                     // no indefinite timing, no other values given -
431*cdf0e10cSrcweir                     // use simple run, i.e. repeat of 1.0
432*cdf0e10cSrcweir                     aRepeats.reset( 1.0 );
433*cdf0e10cSrcweir                 }
434*cdf0e10cSrcweir             }
435*cdf0e10cSrcweir         }
436*cdf0e10cSrcweir     }
437*cdf0e10cSrcweir 
438*cdf0e10cSrcweir     // calc accel/decel:
439*cdf0e10cSrcweir     double nAcceleration = 0.0;
440*cdf0e10cSrcweir     double nDeceleration = 0.0;
441*cdf0e10cSrcweir     BaseNodeSharedPtr const pSelf( getSelf() );
442*cdf0e10cSrcweir     for ( boost::shared_ptr<BaseNode> pNode( pSelf );
443*cdf0e10cSrcweir           pNode; pNode = pNode->getParentNode() )
444*cdf0e10cSrcweir     {
445*cdf0e10cSrcweir         uno::Reference<animations::XAnimationNode> const xAnimationNode(
446*cdf0e10cSrcweir             pNode->getXAnimationNode() );
447*cdf0e10cSrcweir         nAcceleration = std::max( nAcceleration,
448*cdf0e10cSrcweir                                   xAnimationNode->getAcceleration() );
449*cdf0e10cSrcweir         nDeceleration = std::max( nDeceleration,
450*cdf0e10cSrcweir                                   xAnimationNode->getDecelerate() );
451*cdf0e10cSrcweir     }
452*cdf0e10cSrcweir 
453*cdf0e10cSrcweir     EventSharedPtr pEndEvent;
454*cdf0e10cSrcweir     if (pSelf) {
455*cdf0e10cSrcweir         pEndEvent = makeEvent(
456*cdf0e10cSrcweir             boost::bind( &AnimationNode::deactivate, pSelf ),
457*cdf0e10cSrcweir             "AnimationBaseNode::deactivate");
458*cdf0e10cSrcweir     }
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir     // Calculate the minimum frame count that depends on the duration and
461*cdf0e10cSrcweir     // the minimum frame count.
462*cdf0e10cSrcweir     const sal_Int32 nMinFrameCount (basegfx::clamp<sal_Int32>(
463*cdf0e10cSrcweir         basegfx::fround(nDuration * FrameRate::MinimumFramesPerSecond), 1, 10));
464*cdf0e10cSrcweir 
465*cdf0e10cSrcweir     return ActivitiesFactory::CommonParameters(
466*cdf0e10cSrcweir         pEndEvent,
467*cdf0e10cSrcweir         getContext().mrEventQueue,
468*cdf0e10cSrcweir         getContext().mrActivitiesQueue,
469*cdf0e10cSrcweir         nDuration,
470*cdf0e10cSrcweir         nMinFrameCount,
471*cdf0e10cSrcweir         bAutoReverse,
472*cdf0e10cSrcweir         aRepeats,
473*cdf0e10cSrcweir         nAcceleration,
474*cdf0e10cSrcweir         nDeceleration,
475*cdf0e10cSrcweir         getShape(),
476*cdf0e10cSrcweir         getSlideSize());
477*cdf0e10cSrcweir }
478*cdf0e10cSrcweir 
479*cdf0e10cSrcweir AttributableShapeSharedPtr AnimationBaseNode::getShape() const
480*cdf0e10cSrcweir {
481*cdf0e10cSrcweir     // any subsetting at all?
482*cdf0e10cSrcweir     if (mpShapeSubset)
483*cdf0e10cSrcweir         return mpShapeSubset->getSubsetShape();
484*cdf0e10cSrcweir     else
485*cdf0e10cSrcweir         return mpShape; // nope, plain shape always
486*cdf0e10cSrcweir }
487*cdf0e10cSrcweir 
488*cdf0e10cSrcweir } // namespace internal
489*cdf0e10cSrcweir } // namespace slideshow
490*cdf0e10cSrcweir 
491