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