Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : :
20 : :
21 : : // must be first
22 : : #include <canvas/debug.hxx>
23 : : #include <tools/diagnose_ex.h>
24 : : #include <canvas/verbosetrace.hxx>
25 : :
26 : : #include <com/sun/star/animations/AnimationCalcMode.hpp>
27 : : #include <comphelper/sequence.hxx>
28 : :
29 : : #include "activitiesfactory.hxx"
30 : : #include "smilfunctionparser.hxx"
31 : : #include "accumulation.hxx"
32 : : #include "activityparameters.hxx"
33 : : #include "interpolation.hxx"
34 : : #include "tools.hxx"
35 : : #include "simplecontinuousactivitybase.hxx"
36 : : #include "discreteactivitybase.hxx"
37 : : #include "continuousactivitybase.hxx"
38 : : #include "continuouskeytimeactivitybase.hxx"
39 : :
40 : : #include <boost/optional.hpp>
41 : : #include <boost/shared_ptr.hpp>
42 : :
43 : : #include <cmath> // for modf
44 : : #include <vector>
45 : : #include <algorithm>
46 : :
47 : : using namespace com::sun::star;
48 : :
49 : : namespace slideshow {
50 : : namespace internal {
51 : :
52 : : namespace {
53 : :
54 : : /** Traits template, to take formula application only for ValueType = double
55 : : */
56 : : template<typename ValueType> struct FormulaTraits
57 : : {
58 : 0 : static ValueType getPresentationValue(
59 : : const ValueType& rVal, const ExpressionNodeSharedPtr& )
60 : : {
61 : 0 : return rVal;
62 : : }
63 : : };
64 : :
65 : : /// Specialization for ValueType = double
66 : : template<> struct FormulaTraits<double>
67 : : {
68 : 0 : static double getPresentationValue(
69 : : double const& rVal, ExpressionNodeSharedPtr const& rFormula )
70 : : {
71 : 0 : return rFormula ? (*rFormula)(rVal) : rVal;
72 : : }
73 : : };
74 : :
75 : : // Various ActivityBase specializations for different animator types
76 : : // =================================================================
77 : :
78 : : /** FromToBy handler
79 : :
80 : : Provides the Activity specializations for FromToBy
81 : : animations (e.g. those without a values list).
82 : :
83 : : This template makes heavy use of SFINAE, only one of
84 : : the perform*() methods will compile for each of the
85 : : base classes.
86 : :
87 : : Note that we omit the virtual keyword on the perform()
88 : : overrides on purpose; those that actually do override
89 : : baseclass virtual methods inherit the property, and
90 : : the others won't increase our vtable. What's more,
91 : : having all perform() method in the vtable actually
92 : : creates POIs for them, which breaks the whole SFINAE
93 : : concept (IOW, this template won't compile any longer).
94 : :
95 : : @tpl BaseType
96 : : Base class to use for this activity. Only
97 : : ContinuousActivityBase and DiscreteActivityBase are
98 : : supported here.
99 : :
100 : : @tpl AnimationType
101 : : Type of the Animation to call.
102 : : */
103 : : template<class BaseType, typename AnimationType>
104 : 0 : class FromToByActivity : public BaseType
105 : : {
106 : : public:
107 : : typedef typename AnimationType::ValueType ValueType;
108 : : typedef boost::optional<ValueType> OptionalValueType;
109 : :
110 : : private:
111 : : // some compilers don't inline whose definition they haven't
112 : : // seen before the call site...
113 : 0 : ValueType getPresentationValue( const ValueType& rVal ) const
114 : : {
115 : 0 : return FormulaTraits<ValueType>::getPresentationValue( rVal, mpFormula);
116 : : }
117 : :
118 : : public:
119 : : /** Create FromToByActivity.
120 : :
121 : : @param rFrom
122 : : From this value, the animation starts
123 : :
124 : : @param rTo
125 : : With this value, the animation ends
126 : :
127 : : @param rBy
128 : : With this value, the animation increments the start value
129 : :
130 : : @param rParms
131 : : Standard Activity parameter struct
132 : :
133 : : @param rAnim
134 : : Shared ptr to AnimationType
135 : :
136 : : @param rInterpolator
137 : : Interpolator object to be used for lerping between
138 : : start and end value (need to be passed, since it
139 : : might contain state, e.g. interpolation direction
140 : : for HSL color space).
141 : :
142 : : @param bCumulative
143 : : Whether repeated animations should cumulate the
144 : : value, or start fresh each time.
145 : : */
146 : 0 : FromToByActivity(
147 : : const OptionalValueType& rFrom,
148 : : const OptionalValueType& rTo,
149 : : const OptionalValueType& rBy,
150 : : const ActivityParameters& rParms,
151 : : const ::boost::shared_ptr< AnimationType >& rAnim,
152 : : const Interpolator< ValueType >& rInterpolator,
153 : : bool bCumulative )
154 : : : BaseType( rParms ),
155 : : maFrom( rFrom ),
156 : : maTo( rTo ),
157 : : maBy( rBy ),
158 : : mpFormula( rParms.mpFormula ),
159 : : maStartValue(),
160 : : maEndValue(),
161 : : maPreviousValue(),
162 : : maStartInterpolationValue(),
163 : : mnIteration( 0 ),
164 : : mpAnim( rAnim ),
165 : : maInterpolator( rInterpolator ),
166 : : mbDynamicStartValue( false ),
167 : 0 : mbCumulative( bCumulative )
168 : : {
169 : 0 : ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
170 : :
171 : 0 : ENSURE_OR_THROW(
172 : : rTo || rBy,
173 : : "From and one of To or By, or To or By alone must be valid" );
174 : 0 : }
175 : :
176 : 0 : virtual void startAnimation()
177 : : {
178 : 0 : if (this->isDisposed() || !mpAnim)
179 : 0 : return;
180 : 0 : BaseType::startAnimation();
181 : :
182 : : // start animation
183 : 0 : mpAnim->start( BaseType::getShape(),
184 : : BaseType::getShapeAttributeLayer() );
185 : :
186 : : // setup start and end value. Determine animation
187 : : // start value only when animation actually
188 : : // started up (this order is part of the Animation
189 : : // interface contract)
190 : 0 : const ValueType aAnimationStartValue( mpAnim->getUnderlyingValue() );
191 : :
192 : : // first of all, determine general type of
193 : : // animation, by inspecting which of the FromToBy values
194 : : // are actually valid.
195 : : // See http://www.w3.org/TR/smil20/animation.html#AnimationNS-FromToBy
196 : : // for a definition
197 : 0 : if( maFrom )
198 : : {
199 : : // From-to or From-by animation. According to
200 : : // SMIL spec, the To value takes precedence
201 : : // over the By value, if both are specified
202 : 0 : if( maTo )
203 : : {
204 : : // From-To animation
205 : 0 : maStartValue = *maFrom;
206 : 0 : maEndValue = *maTo;
207 : : }
208 : 0 : else if( maBy )
209 : : {
210 : : // From-By animation
211 : 0 : maStartValue = *maFrom;
212 : 0 : maEndValue = maStartValue + *maBy;
213 : : }
214 : : }
215 : : else
216 : : {
217 : 0 : maStartValue = aAnimationStartValue;
218 : 0 : maStartInterpolationValue = maStartValue;
219 : :
220 : : // By or To animation. According to SMIL spec,
221 : : // the To value takes precedence over the By
222 : : // value, if both are specified
223 : 0 : if( maTo )
224 : : {
225 : : // To animation
226 : :
227 : : // According to the SMIL spec
228 : : // (http://www.w3.org/TR/smil20/animation.html#animationNS-ToAnimation),
229 : : // the to animation interpolates between
230 : : // the _running_ underlying value and the to value (as the end value)
231 : 0 : mbDynamicStartValue = true;
232 : 0 : maPreviousValue = maStartValue;
233 : 0 : maEndValue = *maTo;
234 : : }
235 : 0 : else if( maBy )
236 : : {
237 : : // By animation
238 : 0 : maStartValue = aAnimationStartValue;
239 : 0 : maEndValue = maStartValue + *maBy;
240 : : }
241 : : }
242 : : }
243 : :
244 : 0 : virtual void endAnimation()
245 : : {
246 : : // end animation
247 : 0 : if (mpAnim)
248 : 0 : mpAnim->end();
249 : 0 : }
250 : :
251 : : /// perform override for ContinuousActivityBase
252 : 0 : void perform( double nModifiedTime, sal_uInt32 nRepeatCount ) const
253 : : {
254 : 0 : if (this->isDisposed() || !mpAnim)
255 : 0 : return;
256 : :
257 : : // According to SMIL 3.0 spec 'to' animation if no other (lower priority)
258 : : // animations are active or frozen then a simple interpolation is performed.
259 : : // That is, the start interpolation value is constant while the animation
260 : : // is running, and is equal to the underlying value retrieved when
261 : : // the animation start.
262 : : // However if another animation is manipulating the underlying value,
263 : : // the 'to' animation will initially add to the effect of the lower priority
264 : : // animation, and increasingly dominate it as it nears the end of the
265 : : // simple duration, eventually overriding it completely.
266 : : // That is, each time the underlying value is changed between two
267 : : // computations of the animation function the new underlying value is used
268 : : // as start value for the interpolation.
269 : : // See:
270 : : // http://www.w3.org/TR/SMIL3/smil-animation.html#animationNS-ToAnimation
271 : : // (Figure 6 - Effect of Additive to animation example)
272 : : // Moreover when a 'to' animation is repeated, at each new iteration
273 : : // the start interpolation value is reset to the underlying value
274 : : // of the animated property when the animation started,
275 : : // as it is shown in the example provided by the SMIL 3.0 spec.
276 : : // This is exactly as Firefox performs SVG 'to' animations.
277 : 0 : if( mbDynamicStartValue )
278 : : {
279 : 0 : if( mnIteration != nRepeatCount )
280 : : {
281 : 0 : mnIteration = nRepeatCount;
282 : 0 : maStartInterpolationValue = maStartValue;
283 : : }
284 : : else
285 : : {
286 : 0 : ValueType aActualValue = mpAnim->getUnderlyingValue();
287 : 0 : if( aActualValue != maPreviousValue )
288 : 0 : maStartInterpolationValue = aActualValue;
289 : : }
290 : : }
291 : :
292 : : ValueType aValue = maInterpolator( maStartInterpolationValue,
293 : 0 : maEndValue, nModifiedTime );
294 : :
295 : : // According to the SMIL spec:
296 : : // Because 'to' animation is defined in terms of absolute values of
297 : : // the target attribute, cumulative animation is not defined.
298 : 0 : if( mbCumulative && !mbDynamicStartValue )
299 : : {
300 : : // aValue = this.aEndValue * nRepeatCount + aValue;
301 : 0 : aValue = accumulate( maEndValue, nRepeatCount, aValue );
302 : : }
303 : :
304 : 0 : (*mpAnim)( getPresentationValue( aValue ) );
305 : :
306 : 0 : if( mbDynamicStartValue )
307 : : {
308 : 0 : maPreviousValue = mpAnim->getUnderlyingValue();
309 : : }
310 : :
311 : : }
312 : :
313 : : using BaseType::perform;
314 : :
315 : : /// perform override for DiscreteActivityBase base
316 : 0 : void perform( sal_uInt32 nFrame, sal_uInt32 nRepeatCount ) const
317 : : {
318 : 0 : if (this->isDisposed() || !mpAnim)
319 : 0 : return;
320 : 0 : (*mpAnim)(
321 : : getPresentationValue(
322 : : accumulate( maEndValue, mbCumulative ? nRepeatCount : 0,
323 : : lerp( maInterpolator,
324 : : (mbDynamicStartValue
325 : : ? mpAnim->getUnderlyingValue()
326 : : : maStartValue),
327 : : maEndValue,
328 : : nFrame,
329 : : BaseType::getNumberOfKeyTimes() ) ) ) );
330 : : }
331 : :
332 : : using BaseType::isAutoReverse;
333 : :
334 : 0 : virtual void performEnd()
335 : : {
336 : : // xxx todo: good guess
337 : 0 : if (mpAnim)
338 : : {
339 : 0 : if (isAutoReverse())
340 : 0 : (*mpAnim)( getPresentationValue( maStartValue ) );
341 : : else
342 : 0 : (*mpAnim)( getPresentationValue( maEndValue ) );
343 : : }
344 : 0 : }
345 : :
346 : : /// Disposable:
347 : 0 : virtual void dispose()
348 : : {
349 : 0 : mpAnim.reset();
350 : 0 : BaseType::dispose();
351 : 0 : }
352 : :
353 : : private:
354 : : const OptionalValueType maFrom;
355 : : const OptionalValueType maTo;
356 : : const OptionalValueType maBy;
357 : :
358 : : ExpressionNodeSharedPtr mpFormula;
359 : :
360 : : ValueType maStartValue;
361 : : ValueType maEndValue;
362 : :
363 : : mutable ValueType maPreviousValue;
364 : : mutable ValueType maStartInterpolationValue;
365 : : mutable sal_uInt32 mnIteration;
366 : :
367 : : ::boost::shared_ptr< AnimationType > mpAnim;
368 : : Interpolator< ValueType > maInterpolator;
369 : : bool mbDynamicStartValue;
370 : : bool mbCumulative;
371 : : };
372 : :
373 : :
374 : : /** Generate Activity corresponding to given FromToBy values
375 : :
376 : : @tpl BaseType
377 : : BaseType to use for deriving the Activity from
378 : :
379 : : @tpl AnimationType
380 : : Subtype of the Animation object (e.g. NumberAnimation)
381 : : */
382 : : template<class BaseType, typename AnimationType>
383 : 0 : AnimationActivitySharedPtr createFromToByActivity(
384 : : const uno::Any& rFromAny,
385 : : const uno::Any& rToAny,
386 : : const uno::Any& rByAny,
387 : : const ActivityParameters& rParms,
388 : : const ::boost::shared_ptr< AnimationType >& rAnim,
389 : : const Interpolator< typename AnimationType::ValueType >& rInterpolator,
390 : : bool bCumulative,
391 : : const ShapeSharedPtr& rShape,
392 : : const ::basegfx::B2DVector& rSlideBounds )
393 : : {
394 : : typedef typename AnimationType::ValueType ValueType;
395 : : typedef boost::optional<ValueType> OptionalValueType;
396 : :
397 : 0 : OptionalValueType aFrom;
398 : 0 : OptionalValueType aTo;
399 : 0 : OptionalValueType aBy;
400 : :
401 : 0 : ValueType aTmpValue;
402 : :
403 : 0 : if( rFromAny.hasValue() )
404 : : {
405 : 0 : ENSURE_OR_THROW(
406 : : extractValue( aTmpValue, rFromAny, rShape, rSlideBounds ),
407 : : "createFromToByActivity(): Could not extract from value" );
408 : 0 : aFrom.reset(aTmpValue);
409 : : }
410 : 0 : if( rToAny.hasValue() )
411 : : {
412 : 0 : ENSURE_OR_THROW(
413 : : extractValue( aTmpValue, rToAny, rShape, rSlideBounds ),
414 : : "createFromToByActivity(): Could not extract to value" );
415 : 0 : aTo.reset(aTmpValue);
416 : : }
417 : 0 : if( rByAny.hasValue() )
418 : : {
419 : 0 : ENSURE_OR_THROW(
420 : : extractValue( aTmpValue, rByAny, rShape, rSlideBounds ),
421 : : "createFromToByActivity(): Could not extract by value" );
422 : 0 : aBy.reset(aTmpValue);
423 : : }
424 : :
425 : : return AnimationActivitySharedPtr(
426 : : new FromToByActivity<BaseType, AnimationType>(
427 : : aFrom,
428 : : aTo,
429 : : aBy,
430 : : rParms,
431 : : rAnim,
432 : : rInterpolator,
433 : 0 : bCumulative ) );
434 : : }
435 : :
436 : : /* The following table shows which animator combines with
437 : : which Activity type:
438 : :
439 : : NumberAnimator: all
440 : : PairAnimation: all
441 : : ColorAnimation: all
442 : : StringAnimation: DiscreteActivityBase
443 : : BoolAnimation: DiscreteActivityBase
444 : : */
445 : :
446 : : /** Values handler
447 : :
448 : : Provides the Activity specializations for value lists
449 : : animations.
450 : :
451 : : This template makes heavy use of SFINAE, only one of
452 : : the perform*() methods will compile for each of the
453 : : base classes.
454 : :
455 : : Note that we omit the virtual keyword on the perform()
456 : : overrides on purpose; those that actually do override
457 : : baseclass virtual methods inherit the property, and
458 : : the others won't increase our vtable. What's more,
459 : : having all perform() method in the vtable actually
460 : : creates POIs for them, which breaks the whole SFINAE
461 : : concept (IOW, this template won't compile any longer).
462 : :
463 : : @tpl BaseType
464 : : Base class to use for this activity. Only
465 : : ContinuousKeyTimeActivityBase and DiscreteActivityBase
466 : : are supported here. For values animation without key
467 : : times, the client must emulate key times by providing
468 : : a vector of equally spaced values between 0 and 1,
469 : : with the same number of entries as the values vector.
470 : :
471 : : @tpl AnimationType
472 : : Type of the Animation to call.
473 : : */
474 : : template<class BaseType, typename AnimationType>
475 : 0 : class ValuesActivity : public BaseType
476 : : {
477 : : public:
478 : : typedef typename AnimationType::ValueType ValueType;
479 : : typedef std::vector<ValueType> ValueVectorType;
480 : :
481 : : private:
482 : : // some compilers don't inline methods whose definition they haven't
483 : : // seen before the call site...
484 : 0 : ValueType getPresentationValue( const ValueType& rVal ) const
485 : : {
486 : : return FormulaTraits<ValueType>::getPresentationValue(
487 : 0 : rVal, mpFormula );
488 : : }
489 : :
490 : : public:
491 : : /** Create ValuesActivity.
492 : :
493 : : @param rValues
494 : : Value vector to cycle animation through
495 : :
496 : : @param rParms
497 : : Standard Activity parameter struct
498 : :
499 : : @param rAnim
500 : : Shared ptr to AnimationType
501 : :
502 : : @param rInterpolator
503 : : Interpolator object to be used for lerping between
504 : : start and end value (need to be passed, since it
505 : : might contain state, e.g. interpolation direction
506 : : for HSL color space).
507 : :
508 : : @param bCumulative
509 : : Whether repeated animations should cumulate the
510 : : value, or start afresh each time.
511 : : */
512 : 0 : ValuesActivity(
513 : : const ValueVectorType& rValues,
514 : : const ActivityParameters& rParms,
515 : : const boost::shared_ptr<AnimationType>& rAnim,
516 : : const Interpolator< ValueType >& rInterpolator,
517 : : bool bCumulative )
518 : : : BaseType( rParms ),
519 : : maValues( rValues ),
520 : : mpFormula( rParms.mpFormula ),
521 : : mpAnim( rAnim ),
522 : : maInterpolator( rInterpolator ),
523 : 0 : mbCumulative( bCumulative )
524 : : {
525 : 0 : ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
526 : 0 : ENSURE_OR_THROW( !rValues.empty(), "Empty value vector" );
527 : 0 : }
528 : :
529 : 0 : virtual void startAnimation()
530 : : {
531 : 0 : if (this->isDisposed() || !mpAnim)
532 : 0 : return;
533 : 0 : BaseType::startAnimation();
534 : :
535 : : // start animation
536 : 0 : mpAnim->start( BaseType::getShape(),
537 : : BaseType::getShapeAttributeLayer() );
538 : : }
539 : :
540 : 0 : virtual void endAnimation()
541 : : {
542 : : // end animation
543 : 0 : if (mpAnim)
544 : 0 : mpAnim->end();
545 : 0 : }
546 : :
547 : : /// perform override for ContinuousKeyTimeActivityBase base
548 : 0 : void perform( sal_uInt32 nIndex,
549 : : double nFractionalIndex,
550 : : sal_uInt32 nRepeatCount ) const
551 : : {
552 : 0 : if (this->isDisposed() || !mpAnim)
553 : 0 : return;
554 : 0 : ENSURE_OR_THROW( nIndex+1 < maValues.size(),
555 : : "ValuesActivity::perform(): index out of range" );
556 : :
557 : : // interpolate between nIndex and nIndex+1 values
558 : 0 : (*mpAnim)(
559 : : getPresentationValue(
560 : : accumulate( maValues.back(),
561 : : mbCumulative ? nRepeatCount : 0,
562 : : maInterpolator( maValues[ nIndex ],
563 : : maValues[ nIndex+1 ],
564 : : nFractionalIndex ) ) ) );
565 : : }
566 : :
567 : : using BaseType::perform;
568 : :
569 : : /// perform override for DiscreteActivityBase base
570 : 0 : void perform( sal_uInt32 nFrame, sal_uInt32 nRepeatCount ) const
571 : : {
572 : 0 : if (this->isDisposed() || !mpAnim)
573 : 0 : return;
574 : 0 : ENSURE_OR_THROW( nFrame < maValues.size(),
575 : : "ValuesActivity::perform(): index out of range" );
576 : :
577 : : // this is discrete, thus no lerp here.
578 : 0 : (*mpAnim)(
579 : : getPresentationValue(
580 : : accumulate( maValues.back(),
581 : : mbCumulative ? nRepeatCount : 0,
582 : : maValues[ nFrame ] ) ) );
583 : : }
584 : :
585 : 0 : virtual void performEnd()
586 : : {
587 : : // xxx todo: good guess
588 : 0 : if (mpAnim)
589 : 0 : (*mpAnim)( getPresentationValue( maValues.back() ) );
590 : 0 : }
591 : :
592 : : /// Disposable:
593 : 0 : virtual void dispose()
594 : : {
595 : 0 : mpAnim.reset();
596 : 0 : BaseType::dispose();
597 : 0 : }
598 : :
599 : : private:
600 : : ValueVectorType maValues;
601 : :
602 : : ExpressionNodeSharedPtr mpFormula;
603 : :
604 : : boost::shared_ptr<AnimationType> mpAnim;
605 : : Interpolator< ValueType > maInterpolator;
606 : : bool mbCumulative;
607 : : };
608 : :
609 : : /** Generate Activity corresponding to given Value vector
610 : :
611 : : @tpl BaseType
612 : : BaseType to use for deriving the Activity from
613 : :
614 : : @tpl AnimationType
615 : : Subtype of the Animation object (e.g. NumberAnimation)
616 : : */
617 : : template<class BaseType, typename AnimationType>
618 : 0 : AnimationActivitySharedPtr createValueListActivity(
619 : : const uno::Sequence<uno::Any>& rValues,
620 : : const ActivityParameters& rParms,
621 : : const boost::shared_ptr<AnimationType>& rAnim,
622 : : const Interpolator<typename AnimationType::ValueType>& rInterpolator,
623 : : bool bCumulative,
624 : : const ShapeSharedPtr& rShape,
625 : : const ::basegfx::B2DVector& rSlideBounds )
626 : : {
627 : : typedef typename AnimationType::ValueType ValueType;
628 : : typedef std::vector<ValueType> ValueVectorType;
629 : :
630 : 0 : ValueVectorType aValueVector;
631 : 0 : aValueVector.reserve( rValues.getLength() );
632 : :
633 : 0 : for( ::std::size_t i=0, nLen=rValues.getLength(); i<nLen; ++i )
634 : : {
635 : 0 : ValueType aValue;
636 : 0 : ENSURE_OR_THROW(
637 : : extractValue( aValue, rValues[i], rShape, rSlideBounds ),
638 : : "createValueListActivity(): Could not extract values" );
639 : 0 : aValueVector.push_back( aValue );
640 : : }
641 : :
642 : : return AnimationActivitySharedPtr(
643 : : new ValuesActivity<BaseType, AnimationType>(
644 : : aValueVector,
645 : : rParms,
646 : : rAnim,
647 : : rInterpolator,
648 : 0 : bCumulative ) );
649 : : }
650 : :
651 : : /** Generate Activity for given XAnimate, corresponding to given Value vector
652 : :
653 : : @tpl AnimationType
654 : : Subtype of the Animation object (e.g. NumberAnimation)
655 : :
656 : : @param rParms
657 : : Common activity parameters
658 : :
659 : : @param xNode
660 : : XAnimate node, to retrieve animation values from
661 : :
662 : : @param rAnim
663 : : Actual animation to operate with (gets called with the
664 : : time-dependent values)
665 : :
666 : : @param rInterpolator
667 : : Interpolator object to be used for lerping between
668 : : start and end values (need to be passed, since it
669 : : might contain state, e.g. interpolation direction
670 : : for HSL color space).
671 : : */
672 : : template<typename AnimationType>
673 : 0 : AnimationActivitySharedPtr createActivity(
674 : : const ActivitiesFactory::CommonParameters& rParms,
675 : : const uno::Reference< animations::XAnimate >& xNode,
676 : : const ::boost::shared_ptr< AnimationType >& rAnim,
677 : : const Interpolator< typename AnimationType::ValueType >& rInterpolator
678 : : = Interpolator< typename AnimationType::ValueType >() )
679 : : {
680 : : // setup common parameters
681 : : // =======================
682 : :
683 : : ActivityParameters aActivityParms( rParms.mpEndEvent,
684 : : rParms.mrEventQueue,
685 : : rParms.mrActivitiesQueue,
686 : : rParms.mnMinDuration,
687 : : rParms.maRepeats,
688 : : rParms.mnAcceleration,
689 : : rParms.mnDeceleration,
690 : : rParms.mnMinNumberOfFrames,
691 : 0 : rParms.mbAutoReverse );
692 : :
693 : : // is a formula given?
694 : 0 : const ::rtl::OUString& rFormulaString( xNode->getFormula() );
695 : 0 : if( !rFormulaString.isEmpty() )
696 : : {
697 : : // yep, parse and pass to ActivityParameters
698 : : try
699 : : {
700 : 0 : aActivityParms.mpFormula =
701 : : SmilFunctionParser::parseSmilFunction(
702 : : rFormulaString,
703 : : calcRelativeShapeBounds(
704 : : rParms.maSlideBounds,
705 : : rParms.mpShape->getBounds() ) );
706 : : }
707 : 0 : catch( ParseError& )
708 : : {
709 : : // parse error, thus no formula
710 : : OSL_FAIL( "createActivity(): Error parsing formula string" );
711 : : }
712 : : }
713 : :
714 : : // are key times given?
715 : 0 : const uno::Sequence< double >& aKeyTimes( xNode->getKeyTimes() );
716 : 0 : if( aKeyTimes.hasElements() )
717 : : {
718 : : // yes, convert them from Sequence< double >
719 : 0 : aActivityParms.maDiscreteTimes.resize( aKeyTimes.getLength() );
720 : : comphelper::sequenceToArray(
721 : : &aActivityParms.maDiscreteTimes[0],
722 : 0 : aKeyTimes ); // saves us some temporary vectors
723 : : }
724 : :
725 : : // values sequence given?
726 : 0 : const sal_Int32 nValueLen( xNode->getValues().getLength() );
727 : 0 : if( nValueLen )
728 : : {
729 : : // Value list activity
730 : : // ===================
731 : :
732 : : // fake keytimes, if necessary
733 : 0 : if( !aKeyTimes.hasElements() )
734 : : {
735 : : // create a dummy vector of key times,
736 : : // with aValues.getLength equally spaced entries.
737 : 0 : for( sal_Int32 i=0; i<nValueLen; ++i )
738 : 0 : aActivityParms.maDiscreteTimes.push_back( double(i)/nValueLen );
739 : : }
740 : :
741 : : // determine type of animation needed here:
742 : : // Value list activities are possible with
743 : : // ContinuousKeyTimeActivityBase and DiscreteActivityBase
744 : : // specializations
745 : 0 : const sal_Int16 nCalcMode( xNode->getCalcMode() );
746 : :
747 : 0 : switch( nCalcMode )
748 : : {
749 : : case animations::AnimationCalcMode::DISCRETE:
750 : : {
751 : : // since DiscreteActivityBase suspends itself
752 : : // between the frames, create a WakeupEvent for it.
753 : 0 : aActivityParms.mpWakeupEvent.reset(
754 : : new WakeupEvent(
755 : : rParms.mrEventQueue.getTimer(),
756 : : rParms.mrActivitiesQueue ) );
757 : :
758 : : AnimationActivitySharedPtr pActivity(
759 : : createValueListActivity< DiscreteActivityBase >(
760 : : xNode->getValues(),
761 : : aActivityParms,
762 : : rAnim,
763 : : rInterpolator,
764 : : xNode->getAccumulate(),
765 : : rParms.mpShape,
766 : 0 : rParms.maSlideBounds ) );
767 : :
768 : : // WakeupEvent and DiscreteActivityBase need circular
769 : : // references to the corresponding other object.
770 : 0 : aActivityParms.mpWakeupEvent->setActivity( pActivity );
771 : :
772 : 0 : return pActivity;
773 : : }
774 : :
775 : : default:
776 : : OSL_FAIL( "createActivity(): unexpected case" );
777 : : // FALLTHROUGH intended
778 : : case animations::AnimationCalcMode::PACED:
779 : : // FALLTHROUGH intended
780 : : case animations::AnimationCalcMode::SPLINE:
781 : : // FALLTHROUGH intended
782 : : case animations::AnimationCalcMode::LINEAR:
783 : : return createValueListActivity< ContinuousKeyTimeActivityBase >(
784 : : xNode->getValues(),
785 : : aActivityParms,
786 : : rAnim,
787 : : rInterpolator,
788 : : xNode->getAccumulate(),
789 : : rParms.mpShape,
790 : 0 : rParms.maSlideBounds );
791 : : }
792 : : }
793 : : else
794 : : {
795 : : // FromToBy activity
796 : : // =================
797 : :
798 : : // determine type of animation needed here:
799 : : // FromToBy activities are possible with
800 : : // ContinuousActivityBase and DiscreteActivityBase
801 : : // specializations
802 : 0 : const sal_Int16 nCalcMode( xNode->getCalcMode() );
803 : :
804 : 0 : switch( nCalcMode )
805 : : {
806 : : case animations::AnimationCalcMode::DISCRETE:
807 : : {
808 : : // fake keytimes, if necessary
809 : 0 : if( !aKeyTimes.hasElements() )
810 : : {
811 : : // create a dummy vector of 2 key times
812 : 0 : const ::std::size_t nLen( 2 );
813 : 0 : for( ::std::size_t i=0; i<nLen; ++i )
814 : 0 : aActivityParms.maDiscreteTimes.push_back( double(i)/nLen );
815 : : }
816 : :
817 : : // since DiscreteActivityBase suspends itself
818 : : // between the frames, create a WakeupEvent for it.
819 : 0 : aActivityParms.mpWakeupEvent.reset(
820 : : new WakeupEvent(
821 : : rParms.mrEventQueue.getTimer(),
822 : : rParms.mrActivitiesQueue ) );
823 : :
824 : : AnimationActivitySharedPtr pActivity(
825 : : createFromToByActivity< DiscreteActivityBase >(
826 : : xNode->getFrom(),
827 : : xNode->getTo(),
828 : : xNode->getBy(),
829 : : aActivityParms,
830 : : rAnim,
831 : : rInterpolator,
832 : : xNode->getAccumulate(),
833 : : rParms.mpShape,
834 : 0 : rParms.maSlideBounds ) );
835 : :
836 : : // WakeupEvent and DiscreteActivityBase need circular
837 : : // references to the corresponding other object.
838 : 0 : aActivityParms.mpWakeupEvent->setActivity( pActivity );
839 : :
840 : 0 : return pActivity;
841 : : }
842 : :
843 : : default:
844 : : OSL_FAIL( "createActivity(): unexpected case" );
845 : : // FALLTHROUGH intended
846 : : case animations::AnimationCalcMode::PACED:
847 : : // FALLTHROUGH intended
848 : : case animations::AnimationCalcMode::SPLINE:
849 : : // FALLTHROUGH intended
850 : : case animations::AnimationCalcMode::LINEAR:
851 : : return createFromToByActivity< ContinuousActivityBase >(
852 : : xNode->getFrom(),
853 : : xNode->getTo(),
854 : : xNode->getBy(),
855 : : aActivityParms,
856 : : rAnim,
857 : : rInterpolator,
858 : : xNode->getAccumulate(),
859 : : rParms.mpShape,
860 : 0 : rParms.maSlideBounds );
861 : : }
862 : : }
863 : : }
864 : :
865 : : /** Simple activity for ActivitiesFactory::createSimpleActivity
866 : :
867 : : @tpl Direction
868 : : Determines direction of value generator. A 1 yields a
869 : : forward direction, starting with 0.0 and ending with
870 : : 1.0. A 0 yields a backward direction, starting with
871 : : 1.0 and ending with 0.0
872 : : */
873 : : template<int Direction>
874 : 0 : class SimpleActivity : public ContinuousActivityBase
875 : : {
876 : : public:
877 : : /** Create SimpleActivity.
878 : :
879 : : @param rParms
880 : : Standard Activity parameter struct
881 : : */
882 : 0 : SimpleActivity( const ActivityParameters& rParms,
883 : : const NumberAnimationSharedPtr& rAnim ) :
884 : : ContinuousActivityBase( rParms ),
885 : 0 : mpAnim( rAnim )
886 : : {
887 : 0 : ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
888 : 0 : }
889 : :
890 : 0 : virtual void startAnimation()
891 : : {
892 : 0 : if (this->isDisposed() || !mpAnim)
893 : 0 : return;
894 : 0 : ContinuousActivityBase::startAnimation();
895 : :
896 : : // start animation
897 : 0 : mpAnim->start( getShape(),
898 : : getShapeAttributeLayer() );
899 : : }
900 : :
901 : 0 : virtual void endAnimation()
902 : : {
903 : : // end animation
904 : 0 : if (mpAnim)
905 : 0 : mpAnim->end();
906 : 0 : }
907 : :
908 : : using SimpleContinuousActivityBase::perform;
909 : :
910 : : /// perform override for ContinuousActivityBase
911 : 0 : virtual void perform( double nModifiedTime, sal_uInt32 ) const
912 : : {
913 : 0 : if (this->isDisposed() || !mpAnim)
914 : 0 : return;
915 : : // no cumulation, simple [0,1] range
916 : 0 : (*mpAnim)( 1.0 - Direction + nModifiedTime*(2.0*Direction - 1.0) );
917 : : }
918 : :
919 : 0 : virtual void performEnd()
920 : : {
921 : : // xxx todo: review
922 : 0 : if (mpAnim)
923 : 0 : (*mpAnim)( 1.0*Direction );
924 : 0 : }
925 : :
926 : : /// Disposable:
927 : 0 : virtual void dispose()
928 : : {
929 : 0 : mpAnim.reset();
930 : 0 : ContinuousActivityBase::dispose();
931 : 0 : }
932 : :
933 : : private:
934 : : NumberAnimationSharedPtr mpAnim;
935 : : };
936 : :
937 : : } // anon namespace
938 : :
939 : :
940 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
941 : : const CommonParameters& rParms,
942 : : const NumberAnimationSharedPtr& rAnim,
943 : : const uno::Reference< animations::XAnimate >& xNode )
944 : : {
945 : : // forward to appropriate template instantiation
946 : 0 : return createActivity( rParms, xNode, rAnim );
947 : : }
948 : :
949 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
950 : : const CommonParameters& rParms,
951 : : const EnumAnimationSharedPtr& rAnim,
952 : : const uno::Reference< animations::XAnimate >& xNode )
953 : : {
954 : : // forward to appropriate template instantiation
955 : 0 : return createActivity( rParms, xNode, rAnim );
956 : : }
957 : :
958 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
959 : : const CommonParameters& rParms,
960 : : const ColorAnimationSharedPtr& rAnim,
961 : : const uno::Reference< animations::XAnimate >& xNode )
962 : : {
963 : : // forward to appropriate template instantiation
964 : 0 : return createActivity( rParms, xNode, rAnim );
965 : : }
966 : :
967 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
968 : : const CommonParameters& rParms,
969 : : const HSLColorAnimationSharedPtr& rAnim,
970 : : const uno::Reference< animations::XAnimateColor >& xNode )
971 : : {
972 : : // forward to appropriate template instantiation
973 : : return createActivity( rParms,
974 : : uno::Reference< animations::XAnimate >(
975 : : xNode, uno::UNO_QUERY_THROW ),
976 : : rAnim,
977 : : // Direction==true means clockwise in SMIL API
978 : 0 : Interpolator< HSLColor >( !xNode->getDirection() ) );
979 : : }
980 : :
981 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
982 : : const CommonParameters& rParms,
983 : : const PairAnimationSharedPtr& rAnim,
984 : : const uno::Reference< animations::XAnimate >& xNode )
985 : : {
986 : : // forward to appropriate template instantiation
987 : 0 : return createActivity( rParms, xNode, rAnim );
988 : : }
989 : :
990 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
991 : : const CommonParameters& rParms,
992 : : const StringAnimationSharedPtr& rAnim,
993 : : const uno::Reference< animations::XAnimate >& xNode )
994 : : {
995 : : // forward to appropriate template instantiation
996 : 0 : return createActivity( rParms, xNode, rAnim );
997 : : }
998 : :
999 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
1000 : : const CommonParameters& rParms,
1001 : : const BoolAnimationSharedPtr& rAnim,
1002 : : const uno::Reference< animations::XAnimate >& xNode )
1003 : : {
1004 : : // forward to appropriate template instantiation
1005 : 0 : return createActivity( rParms, xNode, rAnim );
1006 : : }
1007 : :
1008 : 0 : AnimationActivitySharedPtr ActivitiesFactory::createSimpleActivity(
1009 : : const CommonParameters& rParms,
1010 : : const NumberAnimationSharedPtr& rAnim,
1011 : : bool bDirectionForward )
1012 : : {
1013 : : ActivityParameters aActivityParms( rParms.mpEndEvent,
1014 : : rParms.mrEventQueue,
1015 : : rParms.mrActivitiesQueue,
1016 : : rParms.mnMinDuration,
1017 : : rParms.maRepeats,
1018 : : rParms.mnAcceleration,
1019 : : rParms.mnDeceleration,
1020 : : rParms.mnMinNumberOfFrames,
1021 : 0 : rParms.mbAutoReverse );
1022 : :
1023 : 0 : if( bDirectionForward )
1024 : : return AnimationActivitySharedPtr(
1025 : 0 : new SimpleActivity<1>( aActivityParms, rAnim ) );
1026 : : else
1027 : : return AnimationActivitySharedPtr(
1028 : 0 : new SimpleActivity<0>( aActivityParms, rAnim ) );
1029 : : }
1030 : :
1031 : : } // namespace internal
1032 : 0 : } // namespace presentation
1033 : :
1034 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|