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