diff options
Diffstat (limited to '')
-rw-r--r-- | slideshow/source/engine/activities/activitiesfactory.cxx | 1015 |
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: */ |