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_drawinglayer.hxx"
26 
27 #include <drawinglayer/animation/animationtiming.hxx>
28 #include <basegfx/numeric/ftools.hxx>
29 
30 //////////////////////////////////////////////////////////////////////////////
31 
32 namespace drawinglayer
33 {
34 	namespace animation
35 	{
36 		//////////////////////////////////////////////////////////////////////////////
37 
AnimationEntry()38 		AnimationEntry::AnimationEntry()
39 		{
40 		}
41 
~AnimationEntry()42 		AnimationEntry::~AnimationEntry()
43 		{
44 		}
45 
46 		//////////////////////////////////////////////////////////////////////////////
47 
AnimationEntryFixed(double fDuration,double fState)48 		AnimationEntryFixed::AnimationEntryFixed(double fDuration, double fState)
49 		:	mfDuration(fDuration),
50 			mfState(fState)
51 		{
52 		}
53 
~AnimationEntryFixed()54 		AnimationEntryFixed::~AnimationEntryFixed()
55 		{
56 		}
57 
clone() const58 		AnimationEntry* AnimationEntryFixed::clone() const
59 		{
60 			return new AnimationEntryFixed(mfDuration, mfState);
61 		}
62 
operator ==(const AnimationEntry & rCandidate) const63 		bool AnimationEntryFixed::operator==(const AnimationEntry& rCandidate) const
64 		{
65 			const AnimationEntryFixed* pCompare = dynamic_cast< const AnimationEntryFixed* >(&rCandidate);
66 
67 			return (pCompare
68 				&& basegfx::fTools::equal(mfDuration, pCompare->mfDuration)
69 				&& basegfx::fTools::equal(mfState, pCompare->mfState));
70 		}
71 
getDuration() const72 		double AnimationEntryFixed::getDuration() const
73 		{
74 			return mfDuration;
75 		}
76 
getStateAtTime(double) const77 		double AnimationEntryFixed::getStateAtTime(double /*fTime*/) const
78 		{
79 			return mfState;
80 		}
81 
getNextEventTime(double fTime) const82 		double AnimationEntryFixed::getNextEventTime(double fTime) const
83 		{
84 			if(basegfx::fTools::less(fTime, mfDuration))
85 			{
86 				return mfDuration;
87 			}
88 			else
89 			{
90 				return 0.0;
91 			}
92 		}
93 
94 		//////////////////////////////////////////////////////////////////////////////
95 
AnimationEntryLinear(double fDuration,double fFrequency,double fStart,double fStop)96 		AnimationEntryLinear::AnimationEntryLinear(double fDuration, double fFrequency, double fStart, double fStop)
97 		:	mfDuration(fDuration),
98 			mfFrequency(fFrequency),
99 			mfStart(fStart),
100 			mfStop(fStop)
101 		{
102 		}
103 
~AnimationEntryLinear()104 		AnimationEntryLinear::~AnimationEntryLinear()
105 		{
106 		}
107 
clone() const108 		AnimationEntry* AnimationEntryLinear::clone() const
109 		{
110 			return new AnimationEntryLinear(mfDuration, mfFrequency, mfStart, mfStop);
111 		}
112 
operator ==(const AnimationEntry & rCandidate) const113 		bool AnimationEntryLinear::operator==(const AnimationEntry& rCandidate) const
114 		{
115 			const AnimationEntryLinear* pCompare = dynamic_cast< const AnimationEntryLinear* >(&rCandidate);
116 
117 			return (pCompare
118 				&& basegfx::fTools::equal(mfDuration, pCompare->mfDuration)
119 				&& basegfx::fTools::equal(mfStart, pCompare->mfStart)
120 				&& basegfx::fTools::equal(mfStop, pCompare->mfStop));
121 		}
122 
getDuration() const123 		double AnimationEntryLinear::getDuration() const
124 		{
125 			return mfDuration;
126 		}
127 
getStateAtTime(double fTime) const128 		double AnimationEntryLinear::getStateAtTime(double fTime) const
129 		{
130 			if(basegfx::fTools::more(mfDuration, 0.0))
131 			{
132 				const double fFactor(fTime / mfDuration);
133 
134 				if(fFactor > 1.0)
135 				{
136 					return mfStop;
137 				}
138 				else
139 				{
140 					return mfStart + ((mfStop - mfStart) * fFactor);
141 				}
142 			}
143 			else
144 			{
145 				return mfStart;
146 			}
147 		}
148 
getNextEventTime(double fTime) const149 		double AnimationEntryLinear::getNextEventTime(double fTime) const
150 		{
151 			if(basegfx::fTools::less(fTime, mfDuration))
152 			{
153 				// use the simple solution: just add the frequency. More correct (but also more
154 				// complicated) would be to calculate the slice of time we are in and when this
155 				// slice will end. For the animations, this makes no quality difference.
156 				fTime += mfFrequency;
157 
158 				if(basegfx::fTools::more(fTime, mfDuration))
159 				{
160 					fTime = mfDuration;
161 				}
162 
163 				return fTime;
164 			}
165 			else
166 			{
167 				return 0.0;
168 			}
169 		}
170 
171 		//////////////////////////////////////////////////////////////////////////////
172 
impGetIndexAtTime(double fTime,double & rfAddedTime) const173 		sal_uInt32 AnimationEntryList::impGetIndexAtTime(double fTime, double &rfAddedTime) const
174 		{
175 			sal_uInt32 nIndex(0L);
176 
177 			while(nIndex < maEntries.size() && basegfx::fTools::lessOrEqual(rfAddedTime + maEntries[nIndex]->getDuration(), fTime))
178 			{
179 				rfAddedTime += maEntries[nIndex++]->getDuration();
180 			}
181 
182 			return nIndex;
183 		}
184 
AnimationEntryList()185 		AnimationEntryList::AnimationEntryList()
186 		:	mfDuration(0.0)
187 		{
188 		}
189 
~AnimationEntryList()190 		AnimationEntryList::~AnimationEntryList()
191 		{
192 			for(sal_uInt32 a(0L); a < maEntries.size(); a++)
193 			{
194 				delete maEntries[a];
195 			}
196 		}
197 
clone() const198 		AnimationEntry* AnimationEntryList::clone() const
199 		{
200 			AnimationEntryList* pNew = new AnimationEntryList();
201 
202 			for(sal_uInt32 a(0L); a < maEntries.size(); a++)
203 			{
204 				pNew->append(*maEntries[a]);
205 			}
206 
207 			return pNew;
208 		}
209 
operator ==(const AnimationEntry & rCandidate) const210 		bool AnimationEntryList::operator==(const AnimationEntry& rCandidate) const
211 		{
212 			const AnimationEntryList* pCompare = dynamic_cast< const AnimationEntryList* >(&rCandidate);
213 
214 			if(pCompare && mfDuration == pCompare->mfDuration)
215 			{
216 				for(sal_uInt32 a(0L); a < maEntries.size(); a++)
217 				{
218 					if(!(*maEntries[a] == *pCompare->maEntries[a]))
219 					{
220 						return false;
221 					}
222 				}
223 
224 				return true;
225 			}
226 
227 			return false;
228 		}
229 
append(const AnimationEntry & rCandidate)230 		void AnimationEntryList::append(const AnimationEntry& rCandidate)
231 		{
232 			const double fDuration(rCandidate.getDuration());
233 
234 			if(!basegfx::fTools::equalZero(fDuration))
235 			{
236 				maEntries.push_back(rCandidate.clone());
237 				mfDuration += fDuration;
238 			}
239 		}
240 
getDuration() const241 		double AnimationEntryList::getDuration() const
242 		{
243 			return mfDuration;
244 		}
245 
getStateAtTime(double fTime) const246 		double AnimationEntryList::getStateAtTime(double fTime) const
247 		{
248 			if(!basegfx::fTools::equalZero(mfDuration))
249 			{
250 				double fAddedTime(0.0);
251 				const sal_uInt32 nIndex(impGetIndexAtTime(fTime, fAddedTime));
252 
253 				if(nIndex < maEntries.size())
254 				{
255 					return maEntries[nIndex]->getStateAtTime(fTime - fAddedTime);
256 				}
257 			}
258 
259 			return 0.0;
260 		}
261 
getNextEventTime(double fTime) const262 		double AnimationEntryList::getNextEventTime(double fTime) const
263 		{
264 			double fNewTime(0.0);
265 
266 			if(!basegfx::fTools::equalZero(mfDuration))
267 			{
268 				double fAddedTime(0.0);
269 				const sal_uInt32 nIndex(impGetIndexAtTime(fTime, fAddedTime));
270 
271 				if(nIndex < maEntries.size())
272 				{
273 					fNewTime = maEntries[nIndex]->getNextEventTime(fTime - fAddedTime) + fAddedTime;
274 				}
275 			}
276 
277 			return fNewTime;
278 		}
279 
280 		//////////////////////////////////////////////////////////////////////////////
281 
AnimationEntryLoop(sal_uInt32 nRepeat)282 		AnimationEntryLoop::AnimationEntryLoop(sal_uInt32 nRepeat)
283 		:	AnimationEntryList(),
284 			mnRepeat(nRepeat)
285 		{
286 		}
287 
~AnimationEntryLoop()288 		AnimationEntryLoop::~AnimationEntryLoop()
289 		{
290 		}
291 
clone() const292 		AnimationEntry* AnimationEntryLoop::clone() const
293 		{
294 			AnimationEntryLoop* pNew = new AnimationEntryLoop(mnRepeat);
295 
296 			for(sal_uInt32 a(0L); a < maEntries.size(); a++)
297 			{
298 				pNew->append(*maEntries[a]);
299 			}
300 
301 			return pNew;
302 		}
303 
operator ==(const AnimationEntry & rCandidate) const304 		bool AnimationEntryLoop::operator==(const AnimationEntry& rCandidate) const
305 		{
306 			const AnimationEntryLoop* pCompare = dynamic_cast< const AnimationEntryLoop* >(&rCandidate);
307 
308 			return (pCompare
309 				&& mnRepeat == pCompare->mnRepeat
310 				&& AnimationEntryList::operator==(rCandidate));
311 		}
312 
getDuration() const313 		double AnimationEntryLoop::getDuration() const
314 		{
315 			return (mfDuration * (double)mnRepeat);
316 		}
317 
getStateAtTime(double fTime) const318 		double AnimationEntryLoop::getStateAtTime(double fTime) const
319 		{
320 			if(mnRepeat && !basegfx::fTools::equalZero(mfDuration))
321 			{
322 				const sal_uInt32 nCurrentLoop((sal_uInt32)(fTime / mfDuration));
323 
324 				if(nCurrentLoop > mnRepeat)
325 				{
326 					return 1.0;
327 				}
328 				else
329 				{
330 					const double fTimeAtLoopStart((double)nCurrentLoop * mfDuration);
331 					const double fRelativeTime(fTime - fTimeAtLoopStart);
332 					return AnimationEntryList::getStateAtTime(fRelativeTime);
333 				}
334 			}
335 
336 			return 0.0;
337 		}
338 
getNextEventTime(double fTime) const339 		double AnimationEntryLoop::getNextEventTime(double fTime) const
340 		{
341 			double fNewTime(0.0);
342 
343 			if(mnRepeat && !basegfx::fTools::equalZero(mfDuration))
344 			{
345 				const sal_uInt32 nCurrentLoop((sal_uInt32)(fTime / mfDuration));
346 
347 				if(nCurrentLoop <= mnRepeat)
348 				{
349 					const double fTimeAtLoopStart((double)nCurrentLoop * mfDuration);
350 					const double fRelativeTime(fTime - fTimeAtLoopStart);
351 					const double fNextEventAtLoop(AnimationEntryList::getNextEventTime(fRelativeTime));
352 
353 					if(!basegfx::fTools::equalZero(fNextEventAtLoop))
354 					{
355 						fNewTime = fNextEventAtLoop + fTimeAtLoopStart;
356 					}
357 				}
358 			}
359 
360 			return fNewTime;
361 		}
362 	} // end of namespace animation
363 } // end of namespace drawinglayer
364 
365 //////////////////////////////////////////////////////////////////////////////
366 // eof
367