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