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