summaryrefslogtreecommitdiffstats
path: root/slideshow/source/engine/activities/activitiesfactory.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--slideshow/source/engine/activities/activitiesfactory.cxx1015
1 files changed, 1015 insertions, 0 deletions
diff --git a/slideshow/source/engine/activities/activitiesfactory.cxx b/slideshow/source/engine/activities/activitiesfactory.cxx
new file mode 100644
index 000000000..2dadfea49
--- /dev/null
+++ b/slideshow/source/engine/activities/activitiesfactory.cxx
@@ -0,0 +1,1015 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <comphelper/sequence.hxx>
+
+#include <activitiesfactory.hxx>
+#include <slideshowexceptions.hxx>
+#include <smilfunctionparser.hxx>
+#include "accumulation.hxx"
+#include "activityparameters.hxx"
+#include "interpolation.hxx"
+#include <tools.hxx>
+#include "simplecontinuousactivitybase.hxx"
+#include "discreteactivitybase.hxx"
+#include "continuousactivitybase.hxx"
+#include "continuouskeytimeactivitybase.hxx"
+
+#include <optional>
+
+#include <memory>
+#include <vector>
+#include <algorithm>
+
+using namespace com::sun::star;
+
+namespace slideshow::internal {
+
+namespace {
+
+/** Traits template, to take formula application only for ValueType = double
+ */
+template<typename ValueType> struct FormulaTraits
+{
+ static ValueType getPresentationValue(
+ const ValueType& rVal, const std::shared_ptr<ExpressionNode>& )
+ {
+ return rVal;
+ }
+};
+
+/// Specialization for ValueType = double
+template<> struct FormulaTraits<double>
+{
+ static double getPresentationValue(
+ double const& rVal, std::shared_ptr<ExpressionNode> const& rFormula )
+ {
+ return rFormula ? (*rFormula)(rVal) : rVal;
+ }
+};
+
+// Various ActivityBase specializations for different animator types
+// =================================================================
+
+/** FromToBy handler
+
+ Provides the Activity specializations for FromToBy
+ animations (e.g. those without a values list).
+
+ This template makes heavy use of SFINAE, only one of
+ the perform*() methods will compile for each of the
+ base classes.
+
+ Note that we omit the virtual keyword on the perform()
+ overrides on purpose; those that actually do override
+ baseclass virtual methods inherit the property, and
+ the others won't increase our vtable. What's more,
+ having all perform() method in the vtable actually
+ creates POIs for them, which breaks the whole SFINAE
+ concept (IOW, this template won't compile any longer).
+
+ @tpl BaseType
+ Base class to use for this activity. Only
+ ContinuousActivityBase and DiscreteActivityBase are
+ supported here.
+
+ @tpl AnimationType
+ Type of the Animation to call.
+*/
+template<class BaseType, typename AnimationType>
+class FromToByActivity : public BaseType
+{
+public:
+ typedef typename AnimationType::ValueType ValueType;
+ typedef std::optional<ValueType> OptionalValueType;
+
+private:
+ // some compilers don't inline whose definition they haven't
+ // seen before the call site...
+ ValueType getPresentationValue( const ValueType& rVal ) const
+ {
+ return FormulaTraits<ValueType>::getPresentationValue( rVal, mpFormula);
+ }
+
+public:
+ /** Create FromToByActivity.
+
+ @param rFrom
+ From this value, the animation starts
+
+ @param rTo
+ With this value, the animation ends
+
+ @param rBy
+ With this value, the animation increments the start value
+
+ @param rParms
+ Standard Activity parameter struct
+
+ @param rAnim
+ Shared ptr to AnimationType
+
+ @param rInterpolator
+ Interpolator object to be used for lerping between
+ start and end value (need to be passed, since it
+ might contain state, e.g. interpolation direction
+ for HSL color space).
+
+ @param bCumulative
+ Whether repeated animations should cumulate the
+ value, or start fresh each time.
+ */
+ FromToByActivity(
+ const OptionalValueType& rFrom,
+ const OptionalValueType& rTo,
+ const OptionalValueType& rBy,
+ const ActivityParameters& rParms,
+ const ::std::shared_ptr< AnimationType >& rAnim,
+ const Interpolator< ValueType >& rInterpolator,
+ bool bCumulative )
+ : BaseType( rParms ),
+ maFrom( rFrom ),
+ maTo( rTo ),
+ maBy( rBy ),
+ mpFormula( rParms.mpFormula ),
+ maStartValue(),
+ maEndValue(),
+ maPreviousValue(),
+ maStartInterpolationValue(),
+ mnIteration( 0 ),
+ mpAnim( rAnim ),
+ maInterpolator( rInterpolator ),
+ mbDynamicStartValue( false ),
+ mbCumulative( bCumulative )
+ {
+ ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
+
+ ENSURE_OR_THROW(
+ rTo || rBy,
+ "From and one of To or By, or To or By alone must be valid" );
+ }
+
+ virtual void startAnimation()
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ BaseType::startAnimation();
+
+ // start animation
+ mpAnim->start( BaseType::getShape(),
+ BaseType::getShapeAttributeLayer() );
+
+ // setup start and end value. Determine animation
+ // start value only when animation actually
+ // started up (this order is part of the Animation
+ // interface contract)
+ const ValueType aAnimationStartValue( mpAnim->getUnderlyingValue() );
+
+ // first of all, determine general type of
+ // animation, by inspecting which of the FromToBy values
+ // are actually valid.
+ // See http://www.w3.org/TR/smil20/animation.html#AnimationNS-FromToBy
+ // for a definition
+ if( maFrom )
+ {
+ // From-to or From-by animation. According to
+ // SMIL spec, the To value takes precedence
+ // over the By value, if both are specified
+ if( maTo )
+ {
+ // From-To animation
+ maStartValue = *maFrom;
+ maEndValue = *maTo;
+ }
+ else if( maBy )
+ {
+ // From-By animation
+ maStartValue = *maFrom;
+ maEndValue = maStartValue + *maBy;
+ }
+ maStartInterpolationValue = maStartValue;
+ }
+ else
+ {
+ maStartValue = aAnimationStartValue;
+ maStartInterpolationValue = maStartValue;
+
+ // By or To animation. According to SMIL spec,
+ // the To value takes precedence over the By
+ // value, if both are specified
+ if( maTo )
+ {
+ // To animation
+
+ // According to the SMIL spec
+ // (http://www.w3.org/TR/smil20/animation.html#animationNS-ToAnimation),
+ // the to animation interpolates between
+ // the _running_ underlying value and the to value (as the end value)
+ mbDynamicStartValue = true;
+ maPreviousValue = maStartValue;
+ maEndValue = *maTo;
+ }
+ else if( maBy )
+ {
+ // By animation
+ maStartValue = aAnimationStartValue;
+ maEndValue = maStartValue + *maBy;
+ }
+ }
+ }
+
+ virtual void endAnimation()
+ {
+ // end animation
+ if (mpAnim)
+ mpAnim->end();
+ }
+
+ /// perform override for ContinuousActivityBase
+ void perform( double nModifiedTime, sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+
+ // According to SMIL 3.0 spec 'to' animation if no other (lower priority)
+ // animations are active or frozen then a simple interpolation is performed.
+ // That is, the start interpolation value is constant while the animation
+ // is running, and is equal to the underlying value retrieved when
+ // the animation start.
+ // However if another animation is manipulating the underlying value,
+ // the 'to' animation will initially add to the effect of the lower priority
+ // animation, and increasingly dominate it as it nears the end of the
+ // simple duration, eventually overriding it completely.
+ // That is, each time the underlying value is changed between two
+ // computations of the animation function the new underlying value is used
+ // as start value for the interpolation.
+ // See:
+ // http://www.w3.org/TR/SMIL3/smil-animation.html#animationNS-ToAnimation
+ // (Figure 6 - Effect of Additive to animation example)
+ // Moreover when a 'to' animation is repeated, at each new iteration
+ // the start interpolation value is reset to the underlying value
+ // of the animated property when the animation started,
+ // as it is shown in the example provided by the SMIL 3.0 spec.
+ // This is exactly as Firefox performs SVG 'to' animations.
+ if( mbDynamicStartValue )
+ {
+ if( mnIteration != nRepeatCount )
+ {
+ mnIteration = nRepeatCount;
+ maStartInterpolationValue = maStartValue;
+ }
+ else
+ {
+ ValueType aActualValue = mpAnim->getUnderlyingValue();
+ if( aActualValue != maPreviousValue )
+ maStartInterpolationValue = aActualValue;
+ }
+ }
+
+ ValueType aValue = maInterpolator( maStartInterpolationValue,
+ maEndValue, nModifiedTime );
+
+ // According to the SMIL spec:
+ // Because 'to' animation is defined in terms of absolute values of
+ // the target attribute, cumulative animation is not defined.
+ if( mbCumulative && !mbDynamicStartValue )
+ {
+ // aValue = this.aEndValue * nRepeatCount + aValue;
+ aValue = accumulate( maEndValue, nRepeatCount, aValue );
+ }
+
+ (*mpAnim)( getPresentationValue( aValue ) );
+
+ if( mbDynamicStartValue )
+ {
+ maPreviousValue = mpAnim->getUnderlyingValue();
+ }
+
+ }
+
+ using BaseType::perform;
+
+ /// perform override for DiscreteActivityBase base
+ void perform( sal_uInt32 nFrame, sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ (*mpAnim)(
+ getPresentationValue(
+ accumulate( maEndValue, mbCumulative ? nRepeatCount : 0,
+ lerp( maInterpolator,
+ (mbDynamicStartValue
+ ? mpAnim->getUnderlyingValue()
+ : maStartValue),
+ maEndValue,
+ nFrame,
+ BaseType::getNumberOfKeyTimes() ) ) ) );
+ }
+
+ using BaseType::isAutoReverse;
+
+ virtual void performEnd()
+ {
+ // xxx todo: good guess
+ if (mpAnim)
+ {
+ if (isAutoReverse())
+ (*mpAnim)( getPresentationValue( maStartValue ) );
+ else
+ (*mpAnim)( getPresentationValue( maEndValue ) );
+ }
+ }
+
+ /// Disposable:
+ virtual void dispose()
+ {
+ mpAnim.reset();
+ BaseType::dispose();
+ }
+
+private:
+ const OptionalValueType maFrom;
+ const OptionalValueType maTo;
+ const OptionalValueType maBy;
+
+ std::shared_ptr<ExpressionNode> mpFormula;
+
+ ValueType maStartValue;
+ ValueType maEndValue;
+
+ mutable ValueType maPreviousValue;
+ mutable ValueType maStartInterpolationValue;
+ mutable sal_uInt32 mnIteration;
+
+ ::std::shared_ptr< AnimationType > mpAnim;
+ Interpolator< ValueType > maInterpolator;
+ bool mbDynamicStartValue;
+ bool mbCumulative;
+};
+
+
+/** Generate Activity corresponding to given FromToBy values
+
+ @tpl BaseType
+ BaseType to use for deriving the Activity from
+
+ @tpl AnimationType
+ Subtype of the Animation object (e.g. NumberAnimation)
+*/
+template<class BaseType, typename AnimationType>
+AnimationActivitySharedPtr createFromToByActivity(
+ const uno::Any& rFromAny,
+ const uno::Any& rToAny,
+ const uno::Any& rByAny,
+ const ActivityParameters& rParms,
+ const ::std::shared_ptr< AnimationType >& rAnim,
+ const Interpolator< typename AnimationType::ValueType >& rInterpolator,
+ bool bCumulative,
+ const ShapeSharedPtr& rShape,
+ const ::basegfx::B2DVector& rSlideBounds )
+{
+ typedef typename AnimationType::ValueType ValueType;
+ typedef std::optional<ValueType> OptionalValueType;
+
+ OptionalValueType aFrom;
+ OptionalValueType aTo;
+ OptionalValueType aBy;
+
+ ValueType aTmpValue;
+
+ if( rFromAny.hasValue() )
+ {
+ ENSURE_OR_THROW(
+ extractValue( aTmpValue, rFromAny, rShape, rSlideBounds ),
+ "createFromToByActivity(): Could not extract from value" );
+ aFrom = aTmpValue;
+ }
+ if( rToAny.hasValue() )
+ {
+ ENSURE_OR_THROW(
+ extractValue( aTmpValue, rToAny, rShape, rSlideBounds ),
+ "createFromToByActivity(): Could not extract to value" );
+ aTo = aTmpValue;
+ }
+ if( rByAny.hasValue() )
+ {
+ ENSURE_OR_THROW(
+ extractValue( aTmpValue, rByAny, rShape, rSlideBounds ),
+ "createFromToByActivity(): Could not extract by value" );
+ aBy = aTmpValue;
+ }
+
+ return std::make_shared<FromToByActivity<BaseType, AnimationType>>(
+ aFrom,
+ aTo,
+ aBy,
+ rParms,
+ rAnim,
+ rInterpolator,
+ bCumulative );
+}
+
+/* The following table shows which animator combines with
+ which Activity type:
+
+ NumberAnimator: all
+ PairAnimation: all
+ ColorAnimation: all
+ StringAnimation: DiscreteActivityBase
+ BoolAnimation: DiscreteActivityBase
+*/
+
+/** Values handler
+
+ Provides the Activity specializations for value lists
+ animations.
+
+ This template makes heavy use of SFINAE, only one of
+ the perform*() methods will compile for each of the
+ base classes.
+
+ Note that we omit the virtual keyword on the perform()
+ overrides on purpose; those that actually do override
+ baseclass virtual methods inherit the property, and
+ the others won't increase our vtable. What's more,
+ having all perform() method in the vtable actually
+ creates POIs for them, which breaks the whole SFINAE
+ concept (IOW, this template won't compile any longer).
+
+ @tpl BaseType
+ Base class to use for this activity. Only
+ ContinuousKeyTimeActivityBase and DiscreteActivityBase
+ are supported here. For values animation without key
+ times, the client must emulate key times by providing
+ a vector of equally spaced values between 0 and 1,
+ with the same number of entries as the values vector.
+
+ @tpl AnimationType
+ Type of the Animation to call.
+*/
+template<class BaseType, typename AnimationType>
+class ValuesActivity : public BaseType
+{
+public:
+ typedef typename AnimationType::ValueType ValueType;
+ typedef std::vector<ValueType> ValueVectorType;
+
+private:
+ // some compilers don't inline methods whose definition they haven't
+ // seen before the call site...
+ ValueType getPresentationValue( const ValueType& rVal ) const
+ {
+ return FormulaTraits<ValueType>::getPresentationValue(
+ rVal, mpFormula );
+ }
+
+public:
+ /** Create ValuesActivity.
+
+ @param rValues
+ Value vector to cycle animation through
+
+ @param rParms
+ Standard Activity parameter struct
+
+ @param rAnim
+ Shared ptr to AnimationType
+
+ @param rInterpolator
+ Interpolator object to be used for lerping between
+ start and end value (need to be passed, since it
+ might contain state, e.g. interpolation direction
+ for HSL color space).
+
+ @param bCumulative
+ Whether repeated animations should cumulate the
+ value, or start afresh each time.
+ */
+ ValuesActivity(
+ const ValueVectorType& rValues,
+ const ActivityParameters& rParms,
+ const std::shared_ptr<AnimationType>& rAnim,
+ const Interpolator< ValueType >& rInterpolator,
+ bool bCumulative )
+ : BaseType( rParms ),
+ maValues( rValues ),
+ mpFormula( rParms.mpFormula ),
+ mpAnim( rAnim ),
+ maInterpolator( rInterpolator ),
+ mbCumulative( bCumulative )
+ {
+ ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
+ ENSURE_OR_THROW( !rValues.empty(), "Empty value vector" );
+ }
+
+ virtual void startAnimation()
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ BaseType::startAnimation();
+
+ // start animation
+ mpAnim->start( BaseType::getShape(),
+ BaseType::getShapeAttributeLayer() );
+ }
+
+ virtual void endAnimation()
+ {
+ // end animation
+ if (mpAnim)
+ mpAnim->end();
+ }
+
+ /// perform override for ContinuousKeyTimeActivityBase base
+ void perform( sal_uInt32 nIndex,
+ double nFractionalIndex,
+ sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ ENSURE_OR_THROW( nIndex+1 < maValues.size(),
+ "ValuesActivity::perform(): index out of range" );
+
+ // interpolate between nIndex and nIndex+1 values
+ (*mpAnim)(
+ getPresentationValue(
+ accumulate<ValueType>( maValues.back(),
+ mbCumulative ? nRepeatCount : 0,
+ maInterpolator( maValues[ nIndex ],
+ maValues[ nIndex+1 ],
+ nFractionalIndex ) ) ) );
+ }
+
+ using BaseType::perform;
+
+ /// perform override for DiscreteActivityBase base
+ void perform( sal_uInt32 nFrame, sal_uInt32 nRepeatCount ) const
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ ENSURE_OR_THROW( nFrame < maValues.size(),
+ "ValuesActivity::perform(): index out of range" );
+
+ // this is discrete, thus no lerp here.
+ (*mpAnim)(
+ getPresentationValue(
+ slideshow::internal::accumulate<ValueType>( maValues.back(),
+ mbCumulative ? nRepeatCount : 0,
+ maValues[ nFrame ] ) ) );
+ }
+
+ virtual void performEnd()
+ {
+ // xxx todo: good guess
+ if (mpAnim)
+ (*mpAnim)( getPresentationValue( maValues.back() ) );
+ }
+
+private:
+ ValueVectorType maValues;
+
+ std::shared_ptr<ExpressionNode> mpFormula;
+
+ std::shared_ptr<AnimationType> mpAnim;
+ Interpolator< ValueType > maInterpolator;
+ bool mbCumulative;
+};
+
+/** Generate Activity corresponding to given Value vector
+
+ @tpl BaseType
+ BaseType to use for deriving the Activity from
+
+ @tpl AnimationType
+ Subtype of the Animation object (e.g. NumberAnimation)
+*/
+template<class BaseType, typename AnimationType>
+AnimationActivitySharedPtr createValueListActivity(
+ const uno::Sequence<uno::Any>& rValues,
+ const ActivityParameters& rParms,
+ const std::shared_ptr<AnimationType>& rAnim,
+ const Interpolator<typename AnimationType::ValueType>& rInterpolator,
+ bool bCumulative,
+ const ShapeSharedPtr& rShape,
+ const ::basegfx::B2DVector& rSlideBounds )
+{
+ typedef typename AnimationType::ValueType ValueType;
+ typedef std::vector<ValueType> ValueVectorType;
+
+ ValueVectorType aValueVector;
+ aValueVector.reserve( rValues.getLength() );
+
+ for( const auto& rValue : rValues )
+ {
+ ValueType aValue;
+ ENSURE_OR_THROW(
+ extractValue( aValue, rValue, rShape, rSlideBounds ),
+ "createValueListActivity(): Could not extract values" );
+ aValueVector.push_back( aValue );
+ }
+
+ return std::make_shared<ValuesActivity<BaseType, AnimationType>>(
+ aValueVector,
+ rParms,
+ rAnim,
+ rInterpolator,
+ bCumulative );
+}
+
+/** Generate Activity for given XAnimate, corresponding to given Value vector
+
+ @tpl AnimationType
+ Subtype of the Animation object (e.g. NumberAnimation)
+
+ @param rParms
+ Common activity parameters
+
+ @param xNode
+ XAnimate node, to retrieve animation values from
+
+ @param rAnim
+ Actual animation to operate with (gets called with the
+ time-dependent values)
+
+ @param rInterpolator
+ Interpolator object to be used for lerping between
+ start and end values (need to be passed, since it
+ might contain state, e.g. interpolation direction
+ for HSL color space).
+*/
+template<typename AnimationType>
+AnimationActivitySharedPtr createActivity(
+ const ActivitiesFactory::CommonParameters& rParms,
+ const uno::Reference< animations::XAnimate >& xNode,
+ const ::std::shared_ptr< AnimationType >& rAnim,
+ const Interpolator< typename AnimationType::ValueType >& rInterpolator
+ = Interpolator< typename AnimationType::ValueType >() )
+{
+ // setup common parameters
+ // =======================
+
+ ActivityParameters aActivityParms( rParms.mpEndEvent,
+ rParms.mrEventQueue,
+ rParms.mrActivitiesQueue,
+ rParms.mnMinDuration,
+ rParms.maRepeats,
+ rParms.mnAcceleration,
+ rParms.mnDeceleration,
+ rParms.mnMinNumberOfFrames,
+ rParms.mbAutoReverse );
+
+ // is a formula given?
+ const OUString& rFormulaString( xNode->getFormula() );
+ if( !rFormulaString.isEmpty() )
+ {
+ // yep, parse and pass to ActivityParameters
+ try
+ {
+ aActivityParms.mpFormula =
+ SmilFunctionParser::parseSmilFunction(
+ rFormulaString,
+ calcRelativeShapeBounds(
+ rParms.maSlideBounds,
+ rParms.mpShape->getBounds() ) );
+ }
+ catch( ParseError& )
+ {
+ // parse error, thus no formula
+ OSL_FAIL( "createActivity(): Error parsing formula string" );
+ }
+ }
+
+ // are key times given?
+ const uno::Sequence< double >& aKeyTimes( xNode->getKeyTimes() );
+ if( aKeyTimes.hasElements() )
+ {
+ // yes, convert them from Sequence< double >
+ aActivityParms.maDiscreteTimes.resize( aKeyTimes.getLength() );
+ comphelper::sequenceToArray(
+ aActivityParms.maDiscreteTimes.data(),
+ aKeyTimes ); // saves us some temporary vectors
+ }
+
+ // values sequence given?
+ const sal_Int32 nValueLen( xNode->getValues().getLength() );
+ if( nValueLen )
+ {
+ // Value list activity
+ // ===================
+
+ // fake keytimes, if necessary
+ if( !aKeyTimes.hasElements() )
+ {
+ // create a dummy vector of key times,
+ // with aValues.getLength equally spaced entries.
+ for( sal_Int32 i=0; i<nValueLen; ++i )
+ aActivityParms.maDiscreteTimes.push_back( double(i)/nValueLen );
+ }
+
+ // determine type of animation needed here:
+ // Value list activities are possible with
+ // ContinuousKeyTimeActivityBase and DiscreteActivityBase
+ // specializations
+ const sal_Int16 nCalcMode( xNode->getCalcMode() );
+
+ switch( nCalcMode )
+ {
+ case animations::AnimationCalcMode::DISCRETE:
+ {
+ // since DiscreteActivityBase suspends itself
+ // between the frames, create a WakeupEvent for it.
+ aActivityParms.mpWakeupEvent =
+ std::make_shared<WakeupEvent>(
+ rParms.mrEventQueue.getTimer(),
+ rParms.mrActivitiesQueue );
+
+ AnimationActivitySharedPtr pActivity(
+ createValueListActivity< DiscreteActivityBase >(
+ xNode->getValues(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds ) );
+
+ // WakeupEvent and DiscreteActivityBase need circular
+ // references to the corresponding other object.
+ aActivityParms.mpWakeupEvent->setActivity( pActivity );
+
+ return pActivity;
+ }
+
+ default:
+ OSL_FAIL( "createActivity(): unexpected case" );
+ [[fallthrough]];
+ case animations::AnimationCalcMode::PACED:
+ case animations::AnimationCalcMode::SPLINE:
+ case animations::AnimationCalcMode::LINEAR:
+ return createValueListActivity< ContinuousKeyTimeActivityBase >(
+ xNode->getValues(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds );
+ }
+ }
+ else
+ {
+ // FromToBy activity
+ // =================
+
+ // determine type of animation needed here:
+ // FromToBy activities are possible with
+ // ContinuousActivityBase and DiscreteActivityBase
+ // specializations
+ const sal_Int16 nCalcMode( xNode->getCalcMode() );
+
+ switch( nCalcMode )
+ {
+ case animations::AnimationCalcMode::DISCRETE:
+ {
+ // fake keytimes, if necessary
+ if( !aKeyTimes.hasElements() )
+ {
+ // create a dummy vector of 2 key times
+ const ::std::size_t nLen( 2 );
+ for( ::std::size_t i=0; i<nLen; ++i )
+ aActivityParms.maDiscreteTimes.push_back( double(i)/nLen );
+ }
+
+ // since DiscreteActivityBase suspends itself
+ // between the frames, create a WakeupEvent for it.
+ aActivityParms.mpWakeupEvent =
+ std::make_shared<WakeupEvent>(
+ rParms.mrEventQueue.getTimer(),
+ rParms.mrActivitiesQueue );
+
+ AnimationActivitySharedPtr pActivity(
+ createFromToByActivity< DiscreteActivityBase >(
+ xNode->getFrom(),
+ xNode->getTo(),
+ xNode->getBy(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds ) );
+
+ // WakeupEvent and DiscreteActivityBase need circular
+ // references to the corresponding other object.
+ aActivityParms.mpWakeupEvent->setActivity( pActivity );
+
+ return pActivity;
+ }
+
+ default:
+ OSL_FAIL( "createActivity(): unexpected case" );
+ [[fallthrough]];
+ case animations::AnimationCalcMode::PACED:
+ case animations::AnimationCalcMode::SPLINE:
+ case animations::AnimationCalcMode::LINEAR:
+ return createFromToByActivity< ContinuousActivityBase >(
+ xNode->getFrom(),
+ xNode->getTo(),
+ xNode->getBy(),
+ aActivityParms,
+ rAnim,
+ rInterpolator,
+ xNode->getAccumulate(),
+ rParms.mpShape,
+ rParms.maSlideBounds );
+ }
+ }
+}
+
+/** Simple activity for ActivitiesFactory::createSimpleActivity
+
+ @tpl Direction
+ Determines direction of value generator. A 1 yields a
+ forward direction, starting with 0.0 and ending with
+ 1.0. A 0 yields a backward direction, starting with
+ 1.0 and ending with 0.0
+*/
+template<int Direction>
+class SimpleActivity : public ContinuousActivityBase
+{
+public:
+ /** Create SimpleActivity.
+
+ @param rParms
+ Standard Activity parameter struct
+ */
+ SimpleActivity( const ActivityParameters& rParms,
+ const NumberAnimationSharedPtr& rAnim ) :
+ ContinuousActivityBase( rParms ),
+ mpAnim( rAnim )
+ {
+ ENSURE_OR_THROW( mpAnim, "Invalid animation object" );
+ }
+
+ virtual void startAnimation() override
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ ContinuousActivityBase::startAnimation();
+
+ // start animation
+ mpAnim->start( getShape(),
+ getShapeAttributeLayer() );
+ }
+
+ virtual void endAnimation() override
+ {
+ // end animation
+ if (mpAnim)
+ mpAnim->end();
+ }
+
+ using SimpleContinuousActivityBase::perform;
+
+ /// perform override for ContinuousActivityBase
+ virtual void perform( double nModifiedTime, sal_uInt32 ) const override
+ {
+ if (this->isDisposed() || !mpAnim)
+ return;
+ // no cumulation, simple [0,1] range
+ (*mpAnim)( 1.0 - Direction + nModifiedTime*(2.0*Direction - 1.0) );
+ }
+
+ virtual void performEnd() override
+ {
+ // xxx todo: review
+ if (mpAnim)
+ (*mpAnim)( 1.0*Direction );
+ }
+
+ /// Disposable:
+ virtual void dispose() override
+ {
+ mpAnim.reset();
+ ContinuousActivityBase::dispose();
+ }
+
+private:
+ NumberAnimationSharedPtr mpAnim;
+};
+
+} // anon namespace
+
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const NumberAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const EnumAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const ColorAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const HSLColorAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimateColor >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms,
+ uno::Reference< animations::XAnimate >(
+ xNode, uno::UNO_QUERY_THROW ),
+ rAnim,
+ // Direction==true means clockwise in SMIL API
+ Interpolator< HSLColor >( !xNode->getDirection() ) );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const PairAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const StringAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createAnimateActivity(
+ const CommonParameters& rParms,
+ const BoolAnimationSharedPtr& rAnim,
+ const uno::Reference< animations::XAnimate >& xNode )
+{
+ // forward to appropriate template instantiation
+ return createActivity( rParms, xNode, rAnim );
+}
+
+AnimationActivitySharedPtr ActivitiesFactory::createSimpleActivity(
+ const CommonParameters& rParms,
+ const NumberAnimationSharedPtr& rAnim,
+ bool bDirectionForward )
+{
+ ActivityParameters aActivityParms( rParms.mpEndEvent,
+ rParms.mrEventQueue,
+ rParms.mrActivitiesQueue,
+ rParms.mnMinDuration,
+ rParms.maRepeats,
+ rParms.mnAcceleration,
+ rParms.mnDeceleration,
+ rParms.mnMinNumberOfFrames,
+ rParms.mbAutoReverse );
+
+ if( bDirectionForward )
+ return std::make_shared<SimpleActivity<1>>( aActivityParms, rAnim );
+ else
+ return std::make_shared<SimpleActivity<0>>( aActivityParms, rAnim );
+}
+
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */