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 <canvas/verbosetrace.hxx> 30 31 #include <simplecontinuousactivitybase.hxx> 32 33 34 namespace slideshow 35 { 36 namespace internal 37 { SimpleContinuousActivityBase(const ActivityParameters & rParms)38 SimpleContinuousActivityBase::SimpleContinuousActivityBase( 39 const ActivityParameters& rParms ) : 40 ActivityBase( rParms ), 41 maTimer( rParms.mrActivitiesQueue.getTimer() ), 42 mnMinSimpleDuration( rParms.mnMinDuration ), 43 mnMinNumberOfFrames( rParms.mnMinNumberOfFrames ), 44 mnCurrPerformCalls( 0 ) 45 { 46 } 47 startAnimation()48 void SimpleContinuousActivityBase::startAnimation() 49 { 50 // init timer. We measure animation time only when we're 51 // actually started. 52 maTimer.reset(); 53 } 54 calcTimeLag() const55 double SimpleContinuousActivityBase::calcTimeLag() const 56 { 57 ActivityBase::calcTimeLag(); 58 if (! isActive()) 59 return 0.0; 60 61 // retrieve locally elapsed time 62 const double nCurrElapsedTime( maTimer.getElapsedTime() ); 63 64 // log time 65 VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): " 66 "next step is based on time: %f", nCurrElapsedTime ); 67 68 // go to great length to ensure a proper animation 69 // run. Since we don't know how often we will be called 70 // here, try to spread the animator calls uniquely over 71 // the [0,1] parameter range. Be aware of the fact that 72 // perform will be called at least mnMinNumberOfTurns 73 // times. 74 75 // fraction of time elapsed 76 const double nFractionElapsedTime( 77 nCurrElapsedTime / mnMinSimpleDuration ); 78 79 // fraction of minimum calls performed 80 const double nFractionRequiredCalls( 81 double(mnCurrPerformCalls) / mnMinNumberOfFrames ); 82 83 // okay, so now, the decision is easy: 84 // 85 // If the fraction of time elapsed is smaller than the 86 // number of calls required to be performed, then we calc 87 // the position on the animation range according to 88 // elapsed time. That is, we're so to say ahead of time. 89 // 90 // In contrary, if the fraction of time elapsed is larger, 91 // then we're lagging, and we thus calc the position on 92 // the animation time line according to the fraction of 93 // calls performed. Thus, the animation is forced to slow 94 // down, and take the required minimal number of steps, 95 // sufficiently equally distributed across the animation 96 // time line. 97 if( nFractionElapsedTime < nFractionRequiredCalls ) 98 { 99 VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): " 100 "t=%f is based on time", nFractionElapsedTime ); 101 return 0.0; 102 } 103 else 104 { 105 VERBOSE_TRACE( "SimpleContinuousActivityBase::perform(): " 106 "t=%f is based on number of calls", 107 nFractionRequiredCalls ); 108 109 // lag global time, so all other animations lag, too: 110 return ((nFractionElapsedTime - nFractionRequiredCalls) 111 * mnMinSimpleDuration); 112 } 113 } 114 perform()115 bool SimpleContinuousActivityBase::perform() 116 { 117 // call base class, for start() calls and end handling 118 if( !ActivityBase::perform() ) 119 return false; // done, we're ended 120 121 122 // get relative animation position 123 // =============================== 124 125 const double nCurrElapsedTime( maTimer.getElapsedTime() ); 126 double nT( nCurrElapsedTime / mnMinSimpleDuration ); 127 128 129 // one of the stop criteria reached? 130 // ================================= 131 132 // will be set to true below, if one of the termination criteria 133 // matched. 134 bool bActivityEnding( false ); 135 136 if( isRepeatCountValid() ) 137 { 138 // Finite duration 139 // =============== 140 141 // When we've autoreverse on, the repeat count 142 // doubles 143 const double nRepeatCount( getRepeatCount() ); 144 const double nEffectiveRepeat( isAutoReverse() ? 145 2.0*nRepeatCount : 146 nRepeatCount ); 147 148 // time (or frame count) elapsed? 149 if( nEffectiveRepeat <= nT ) 150 { 151 // okee. done for now. Will not exit right here, 152 // to give animation the chance to render the last 153 // frame below 154 bActivityEnding = true; 155 156 // clamp animation to max permissible value 157 nT = nEffectiveRepeat; 158 } 159 } 160 161 162 // need to do auto-reverse? 163 // ======================== 164 165 double nRepeats; 166 double nRelativeSimpleTime; 167 168 // TODO(Q3): Refactor this mess 169 if( isAutoReverse() ) 170 { 171 // divert active duration into repeat and 172 // fractional part. 173 const double nFractionalActiveDuration( modf(nT, &nRepeats) ); 174 175 // for auto-reverse, map ranges [1,2), [3,4), ... 176 // to ranges [0,1), [1,2), etc. 177 if( ((int)nRepeats) % 2 ) 178 { 179 // we're in an odd range, reverse sweep 180 nRelativeSimpleTime = 1.0 - nFractionalActiveDuration; 181 } 182 else 183 { 184 // we're in an even range, pass on as is 185 nRelativeSimpleTime = nFractionalActiveDuration; 186 } 187 188 // effective repeat count for autoreverse is half of 189 // the input time's value (each run of an autoreverse 190 // cycle is half of a repeat) 191 nRepeats /= 2; 192 } 193 else 194 { 195 // determine repeat 196 // ================ 197 198 // calc simple time and number of repeats from nT 199 // Now, that's easy, since the fractional part of 200 // nT gives the relative simple time, and the 201 // integer part the number of full repeats: 202 nRelativeSimpleTime = modf(nT, &nRepeats); 203 204 // clamp repeats to max permissible value (maRepeats.getValue() - 1.0) 205 if( isRepeatCountValid() && 206 nRepeats >= getRepeatCount() ) 207 { 208 // Note that this code here only gets 209 // triggered if maRepeats.getValue() is an 210 // _integer_. Otherwise, nRepeats will never 211 // reach nor exceed 212 // maRepeats.getValue(). Thus, the code below 213 // does not need to handle cases of fractional 214 // repeats, and can always assume that a full 215 // animation run has ended (with 216 // nRelativeSimpleTime=1.0 for 217 // non-autoreversed activities). 218 219 // with modf, nRelativeSimpleTime will never 220 // become 1.0, since nRepeats is incremented and 221 // nRelativeSimpleTime set to 0.0 then. 222 // 223 // For the animation to reach its final value, 224 // nRepeats must although become 225 // maRepeats.getValue()-1.0, and 226 // nRelativeSimpleTime=1.0. 227 nRelativeSimpleTime = 1.0; 228 nRepeats -= 1.0; 229 } 230 } 231 232 // actually perform something 233 // ========================== 234 235 simplePerform( nRelativeSimpleTime, 236 // nRepeats is already integer-valued 237 static_cast<sal_uInt32>( nRepeats ) ); 238 239 240 // delayed endActivity() call from end condition check 241 // below. Issued after the simplePerform() call above, to 242 // give animations the chance to correctly reach the 243 // animation end value, without spurious bail-outs because 244 // of isActive() returning false. 245 if( bActivityEnding ) 246 endActivity(); 247 248 // one more frame successfully performed 249 ++mnCurrPerformCalls; 250 251 return isActive(); 252 } 253 } 254 } 255