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