| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_slideshow.hxx" |
| |
| // must be first |
| #include <canvas/debug.hxx> |
| #include <canvas/verbosetrace.hxx> |
| |
| #include <simplecontinuousactivitybase.hxx> |
| |
| |
| namespace slideshow |
| { |
| namespace internal |
| { |
| SimpleContinuousActivityBase::SimpleContinuousActivityBase( |
| const ActivityParameters& rParms ) : |
| ActivityBase( rParms ), |
| maTimer( rParms.mrActivitiesQueue.getTimer() ), |
| mnMinSimpleDuration( rParms.mnMinDuration ), |
| mnMinNumberOfFrames( rParms.mnMinNumberOfFrames ), |
| mnCurrPerformCalls( 0 ) |
| { |
| } |
| |
| void SimpleContinuousActivityBase::startAnimation() |
| { |
| // init timer. We measure animation time only when we're |
| // actually started. |
| maTimer.reset(); |
| } |
| |
| double SimpleContinuousActivityBase::calcTimeLag() const |
| { |
| ActivityBase::calcTimeLag(); |
| if (! isActive()) |
| return 0.0; |
| |
| // retrieve locally elapsed time |
| const double nCurrElapsedTime( maTimer.getElapsedTime() ); |
| |
| // log time |
| VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): " |
| "next step is based on time: %f", nCurrElapsedTime ); |
| |
| // go to great length to ensure a proper animation |
| // run. Since we don't know how often we will be called |
| // here, try to spread the animator calls uniquely over |
| // the [0,1] parameter range. Be aware of the fact that |
| // perform will be called at least mnMinNumberOfTurns |
| // times. |
| |
| // fraction of time elapsed |
| const double nFractionElapsedTime( |
| nCurrElapsedTime / mnMinSimpleDuration ); |
| |
| // fraction of minimum calls performed |
| const double nFractionRequiredCalls( |
| double(mnCurrPerformCalls) / mnMinNumberOfFrames ); |
| |
| // okay, so now, the decision is easy: |
| // |
| // If the fraction of time elapsed is smaller than the |
| // number of calls required to be performed, then we calc |
| // the position on the animation range according to |
| // elapsed time. That is, we're so to say ahead of time. |
| // |
| // In contrary, if the fraction of time elapsed is larger, |
| // then we're lagging, and we thus calc the position on |
| // the animation time line according to the fraction of |
| // calls performed. Thus, the animation is forced to slow |
| // down, and take the required minimal number of steps, |
| // sufficiently equally distributed across the animation |
| // time line. |
| if( nFractionElapsedTime < nFractionRequiredCalls ) |
| { |
| VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): " |
| "t=%f is based on time", nFractionElapsedTime ); |
| return 0.0; |
| } |
| else |
| { |
| VERBOSE_TRACE( "SimpleContinuousActivityBase::perform(): " |
| "t=%f is based on number of calls", |
| nFractionRequiredCalls ); |
| |
| // lag global time, so all other animations lag, too: |
| return ((nFractionElapsedTime - nFractionRequiredCalls) |
| * mnMinSimpleDuration); |
| } |
| } |
| |
| bool SimpleContinuousActivityBase::perform() |
| { |
| // call base class, for start() calls and end handling |
| if( !ActivityBase::perform() ) |
| return false; // done, we're ended |
| |
| |
| // get relative animation position |
| // =============================== |
| |
| const double nCurrElapsedTime( maTimer.getElapsedTime() ); |
| double nT( nCurrElapsedTime / mnMinSimpleDuration ); |
| |
| |
| // one of the stop criteria reached? |
| // ================================= |
| |
| // will be set to true below, if one of the termination criteria |
| // matched. |
| bool bActivityEnding( false ); |
| |
| if( isRepeatCountValid() ) |
| { |
| // Finite duration |
| // =============== |
| |
| // When we've autoreverse on, the repeat count |
| // doubles |
| const double nRepeatCount( getRepeatCount() ); |
| const double nEffectiveRepeat( isAutoReverse() ? |
| 2.0*nRepeatCount : |
| nRepeatCount ); |
| |
| // time (or frame count) elapsed? |
| if( nEffectiveRepeat <= nT ) |
| { |
| // okee. done for now. Will not exit right here, |
| // to give animation the chance to render the last |
| // frame below |
| bActivityEnding = true; |
| |
| // clamp animation to max permissible value |
| nT = nEffectiveRepeat; |
| } |
| } |
| |
| |
| // need to do auto-reverse? |
| // ======================== |
| |
| double nRepeats; |
| double nRelativeSimpleTime; |
| |
| // TODO(Q3): Refactor this mess |
| if( isAutoReverse() ) |
| { |
| // divert active duration into repeat and |
| // fractional part. |
| const double nFractionalActiveDuration( modf(nT, &nRepeats) ); |
| |
| // for auto-reverse, map ranges [1,2), [3,4), ... |
| // to ranges [0,1), [1,2), etc. |
| if( ((int)nRepeats) % 2 ) |
| { |
| // we're in an odd range, reverse sweep |
| nRelativeSimpleTime = 1.0 - nFractionalActiveDuration; |
| } |
| else |
| { |
| // we're in an even range, pass on as is |
| nRelativeSimpleTime = nFractionalActiveDuration; |
| } |
| |
| // effective repeat count for autoreverse is half of |
| // the input time's value (each run of an autoreverse |
| // cycle is half of a repeat) |
| nRepeats /= 2; |
| } |
| else |
| { |
| // determine repeat |
| // ================ |
| |
| // calc simple time and number of repeats from nT |
| // Now, that's easy, since the fractional part of |
| // nT gives the relative simple time, and the |
| // integer part the number of full repeats: |
| nRelativeSimpleTime = modf(nT, &nRepeats); |
| |
| // clamp repeats to max permissible value (maRepeats.getValue() - 1.0) |
| if( isRepeatCountValid() && |
| nRepeats >= getRepeatCount() ) |
| { |
| // Note that this code here only gets |
| // triggered if maRepeats.getValue() is an |
| // _integer_. Otherwise, nRepeats will never |
| // reach nor exceed |
| // maRepeats.getValue(). Thus, the code below |
| // does not need to handle cases of fractional |
| // repeats, and can always assume that a full |
| // animation run has ended (with |
| // nRelativeSimpleTime=1.0 for |
| // non-autoreversed activities). |
| |
| // with modf, nRelativeSimpleTime will never |
| // become 1.0, since nRepeats is incremented and |
| // nRelativeSimpleTime set to 0.0 then. |
| // |
| // For the animation to reach its final value, |
| // nRepeats must although become |
| // maRepeats.getValue()-1.0, and |
| // nRelativeSimpleTime=1.0. |
| nRelativeSimpleTime = 1.0; |
| nRepeats -= 1.0; |
| } |
| } |
| |
| // actually perform something |
| // ========================== |
| |
| simplePerform( nRelativeSimpleTime, |
| // nRepeats is already integer-valued |
| static_cast<sal_uInt32>( nRepeats ) ); |
| |
| |
| // delayed endActivity() call from end condition check |
| // below. Issued after the simplePerform() call above, to |
| // give animations the chance to correctly reach the |
| // animation end value, without spurious bail-outs because |
| // of isActive() returning false. |
| if( bActivityEnding ) |
| endActivity(); |
| |
| // one more frame successfully performed |
| ++mnCurrPerformCalls; |
| |
| return isActive(); |
| } |
| } |
| } |