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