xref: /aoo42x/main/vcl/source/gdi/animate.cxx (revision cdf0e10c)
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_vcl.hxx"
30 
31 #define ENABLE_BYTESTRING_STREAM_OPERATORS
32 #include <vcl/animate.hxx>
33 #include <tools/debug.hxx>
34 #include <tools/stream.hxx>
35 #include <rtl/crc.h>
36 #include <vcl/virdev.hxx>
37 #include <vcl/window.hxx>
38 #include <impanmvw.hxx>
39 DBG_NAME( Animation )
40 
41 // -----------
42 // - Defines -
43 // -----------
44 
45 #define MIN_TIMEOUT 2L
46 #define INC_TIMEOUT 0L
47 
48 // -----------
49 // - statics -
50 // -----------
51 
52 sal_uLong Animation::mnAnimCount = 0UL;
53 
54 // -------------------
55 // - AnimationBitmap -
56 // -------------------
57 
58 sal_uLong AnimationBitmap::GetChecksum() const
59 {
60 	sal_uInt32	nCrc = aBmpEx.GetChecksum();
61 	SVBT32		aBT32;
62 
63 	UInt32ToSVBT32( aPosPix.X(), aBT32 );
64 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
65 
66 	UInt32ToSVBT32( aPosPix.Y(), aBT32 );
67 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
68 
69 	UInt32ToSVBT32( aSizePix.Width(), aBT32 );
70 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
71 
72 	UInt32ToSVBT32( aSizePix.Height(), aBT32 );
73 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
74 
75 	UInt32ToSVBT32( (long) nWait, aBT32 );
76 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
77 
78 	UInt32ToSVBT32( (long) eDisposal, aBT32 );
79 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
80 
81 	UInt32ToSVBT32( (long) bUserInput, aBT32 );
82 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
83 
84 	return nCrc;
85 }
86 
87 // -------------
88 // - Animation -
89 // -------------
90 
91 Animation::Animation() :
92 	mnLoopCount 		( 0 ),
93 	mnLoops 			( 0 ),
94 	mnPos				( 0 ),
95 	meCycleMode 		( CYCLE_NORMAL ),
96 	mbIsInAnimation 	( sal_False ),
97 	mbLoopTerminated	( sal_False ),
98 	mbIsWaiting 		( sal_False )
99 {
100 	DBG_CTOR( Animation, NULL );
101 	maTimer.SetTimeoutHdl( LINK( this, Animation, ImplTimeoutHdl ) );
102 	mpViewList = new List;
103 }
104 
105 // -----------------------------------------------------------------------
106 
107 Animation::Animation( const Animation& rAnimation ) :
108 	maBitmapEx			( rAnimation.maBitmapEx ),
109 	maGlobalSize		( rAnimation.maGlobalSize ),
110 	mnLoopCount 		( rAnimation.mnLoopCount ),
111 	mnPos				( rAnimation.mnPos ),
112 	meCycleMode 		( rAnimation.meCycleMode ),
113 	mbIsInAnimation 	( sal_False ),
114 	mbLoopTerminated	( rAnimation.mbLoopTerminated ),
115 	mbIsWaiting 		( rAnimation.mbIsWaiting )
116 {
117 	DBG_CTOR( Animation, NULL );
118 
119 	for( long i = 0, nCount = rAnimation.maList.Count(); i < nCount; i++ )
120 		maList.Insert( new AnimationBitmap( *(AnimationBitmap*) rAnimation.maList.GetObject( i ) ), LIST_APPEND );
121 
122 	maTimer.SetTimeoutHdl( LINK( this, Animation, ImplTimeoutHdl ) );
123 	mpViewList = new List;
124 	mnLoops = mbLoopTerminated ? 0 : mnLoopCount;
125 }
126 
127 // -----------------------------------------------------------------------
128 
129 Animation::~Animation()
130 {
131 	DBG_DTOR( Animation, NULL );
132 
133 	if( mbIsInAnimation )
134 		Stop();
135 
136 	for( void* pStepBmp = maList.First(); pStepBmp; pStepBmp = maList.Next() )
137 		delete (AnimationBitmap*) pStepBmp;
138 
139 	for( void* pView = mpViewList->First(); pView; pView = mpViewList->Next() )
140 		delete (ImplAnimView*) pView;
141 
142 	delete mpViewList;
143 }
144 
145 // -----------------------------------------------------------------------
146 
147 Animation& Animation::operator=( const Animation& rAnimation )
148 {
149 	Clear();
150 
151 	for( long i = 0, nCount = rAnimation.maList.Count(); i < nCount; i++ )
152 		maList.Insert( new AnimationBitmap( *(AnimationBitmap*) rAnimation.maList.GetObject( i ) ), LIST_APPEND );
153 
154 	maGlobalSize = rAnimation.maGlobalSize;
155 	maBitmapEx = rAnimation.maBitmapEx;
156 	meCycleMode = rAnimation.meCycleMode;
157 	mnLoopCount = rAnimation.mnLoopCount;
158 	mnPos = rAnimation.mnPos;
159 	mbLoopTerminated = rAnimation.mbLoopTerminated;
160 	mbIsWaiting = rAnimation.mbIsWaiting;
161 	mnLoops = mbLoopTerminated ? 0 : mnLoopCount;
162 
163 	return *this;
164 }
165 
166 // -----------------------------------------------------------------------
167 
168 sal_Bool Animation::operator==( const Animation& rAnimation ) const
169 {
170 	const sal_uLong nCount = maList.Count();
171 	sal_Bool		bRet = sal_False;
172 
173 	if( rAnimation.maList.Count() == nCount &&
174 		rAnimation.maBitmapEx == maBitmapEx &&
175 		rAnimation.maGlobalSize == maGlobalSize &&
176 		rAnimation.meCycleMode == meCycleMode )
177 	{
178 		bRet = sal_True;
179 
180 		for( sal_uLong n = 0; n < nCount; n++ )
181 		{
182 			if( ( *(AnimationBitmap*) maList.GetObject( n ) ) !=
183 				( *(AnimationBitmap*) rAnimation.maList.GetObject( n ) ) )
184 			{
185 				bRet = sal_False;
186 				break;
187 			}
188 		}
189 	}
190 
191 	return bRet;
192 }
193 
194 // ------------------------------------------------------------------
195 
196 sal_Bool Animation::IsEqual( const Animation& rAnimation ) const
197 {
198 	const sal_uLong nCount = maList.Count();
199 	sal_Bool		bRet = sal_False;
200 
201 	if( rAnimation.maList.Count() == nCount &&
202 		rAnimation.maBitmapEx.IsEqual( maBitmapEx ) &&
203 		rAnimation.maGlobalSize == maGlobalSize &&
204 		rAnimation.meCycleMode == meCycleMode )
205 	{
206 		for( sal_uLong n = 0; ( n < nCount ) && !bRet; n++ )
207 			if( ( (AnimationBitmap*) maList.GetObject( n ) )->IsEqual( *(AnimationBitmap*) rAnimation.maList.GetObject( n ) ) )
208 				bRet = sal_True;
209 	}
210 
211 	return bRet;
212 }
213 
214 // ------------------------------------------------------------------
215 
216 sal_Bool Animation::IsEmpty() const
217 {
218 	return( maBitmapEx.IsEmpty() && !maList.Count() );
219 }
220 
221 // ------------------------------------------------------------------
222 
223 void Animation::SetEmpty()
224 {
225 	maTimer.Stop();
226 	mbIsInAnimation = sal_False;
227 	maGlobalSize = Size();
228 	maBitmapEx.SetEmpty();
229 
230 	for( void* pStepBmp = maList.First(); pStepBmp; pStepBmp = maList.Next() )
231 		delete (AnimationBitmap*) pStepBmp;
232 	maList.Clear();
233 
234 	for( void* pView = mpViewList->First(); pView; pView = mpViewList->Next() )
235 		delete (ImplAnimView*) pView;
236 	mpViewList->Clear();
237 }
238 
239 // -----------------------------------------------------------------------
240 
241 void Animation::Clear()
242 {
243 	SetEmpty();
244 }
245 
246 // -----------------------------------------------------------------------
247 
248 sal_Bool Animation::IsTransparent() const
249 {
250 	Point		aPoint;
251 	Rectangle	aRect( aPoint, maGlobalSize );
252 	sal_Bool		bRet = sal_False;
253 
254 	// Falls irgendein 'kleines' Bildchen durch den Hintergrund
255 	// ersetzt werden soll, muessen wir 'transparent' sein, um
256 	// richtig dargestellt zu werden, da die Appl. aus Optimierungsgruenden
257 	// kein Invalidate auf nicht-transp. Grafiken ausfuehren
258 	for( long i = 0, nCount = maList.Count(); i < nCount; i++ )
259 	{
260 		const AnimationBitmap* pAnimBmp = (AnimationBitmap*) maList.GetObject( i );
261 
262 		if( DISPOSE_BACK == pAnimBmp->eDisposal && Rectangle( pAnimBmp->aPosPix, pAnimBmp->aSizePix ) != aRect )
263 		{
264 			bRet = sal_True;
265 			break;
266 		}
267 	}
268 
269 	if( !bRet )
270 		bRet = maBitmapEx.IsTransparent();
271 
272 	return bRet;
273 }
274 
275 // -----------------------------------------------------------------------
276 
277 sal_uLong Animation::GetSizeBytes() const
278 {
279 	sal_uLong nSizeBytes = GetBitmapEx().GetSizeBytes();
280 
281 	for( long i = 0, nCount = maList.Count(); i < nCount; i++ )
282 	{
283 		const AnimationBitmap* pAnimBmp = (AnimationBitmap*) maList.GetObject( i );
284 		nSizeBytes += pAnimBmp->aBmpEx.GetSizeBytes();
285 	}
286 
287 	return nSizeBytes;
288 }
289 
290 // -----------------------------------------------------------------------
291 
292 sal_uLong Animation::GetChecksum() const
293 {
294 	SVBT32		aBT32;
295 	sal_uInt32	nCrc = GetBitmapEx().GetChecksum();
296 
297 	UInt32ToSVBT32( maList.Count(), aBT32 );
298 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
299 
300 	UInt32ToSVBT32( maGlobalSize.Width(), aBT32 );
301 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
302 
303 	UInt32ToSVBT32( maGlobalSize.Height(), aBT32 );
304 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
305 
306 	UInt32ToSVBT32( (long) meCycleMode, aBT32 );
307 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
308 
309 	for( long i = 0, nCount = maList.Count(); i < nCount; i++ )
310 	{
311 		UInt32ToSVBT32( ( (AnimationBitmap*) maList.GetObject( i ) )->GetChecksum(), aBT32 );
312 		nCrc = rtl_crc32( nCrc, aBT32, 4 );
313 	}
314 
315 	return nCrc;
316 }
317 
318 // -----------------------------------------------------------------------
319 
320 sal_Bool Animation::Start( OutputDevice* pOut, const Point& rDestPt, long nExtraData,
321 					   OutputDevice* pFirstFrameOutDev )
322 {
323 	return Start( pOut, rDestPt, pOut->PixelToLogic( maGlobalSize ), nExtraData, pFirstFrameOutDev );
324 }
325 
326 // -----------------------------------------------------------------------
327 
328 sal_Bool Animation::Start( OutputDevice* pOut, const Point& rDestPt, const Size& rDestSz, long nExtraData,
329 					   OutputDevice* pFirstFrameOutDev )
330 {
331 	sal_Bool bRet = sal_False;
332 
333 	if( maList.Count() )
334 	{
335 		if( ( pOut->GetOutDevType() == OUTDEV_WINDOW ) && !mbLoopTerminated &&
336 			( ANIMATION_TIMEOUT_ON_CLICK != ( (AnimationBitmap*) maList.GetObject( mnPos ) )->nWait ) )
337 		{
338 			ImplAnimView*	pView;
339 			ImplAnimView*	pMatch = NULL;
340 
341 			for( pView = (ImplAnimView*) mpViewList->First(); pView; pView = (ImplAnimView*) mpViewList->Next() )
342 			{
343 				if( pView->ImplMatches( pOut, nExtraData ) )
344 				{
345 					if( pView->ImplGetOutPos() == rDestPt &&
346 						pView->ImplGetOutSizePix() == pOut->LogicToPixel( rDestSz ) )
347 					{
348 						pView->ImplRepaint();
349 						pMatch = pView;
350 					}
351 					else
352 					{
353 						delete (ImplAnimView*) mpViewList->Remove( pView );
354 						pView = NULL;
355 					}
356 
357 					break;
358 				}
359 			}
360 
361 			if( !mpViewList->Count() )
362 			{
363 				maTimer.Stop();
364 				mbIsInAnimation = sal_False;
365 				mnPos = 0UL;
366 			}
367 
368 			if( !pMatch )
369 				mpViewList->Insert( new ImplAnimView( this, pOut, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev ), LIST_APPEND );
370 
371 			if( !mbIsInAnimation )
372 			{
373 				ImplRestartTimer( ( (AnimationBitmap*) maList.GetObject( mnPos ) )->nWait );
374 				mbIsInAnimation = sal_True;
375 			}
376 		}
377 		else
378 			Draw( pOut, rDestPt, rDestSz );
379 
380 		bRet = sal_True;
381 	}
382 
383 	return bRet;
384 }
385 
386 // -----------------------------------------------------------------------
387 
388 void Animation::Stop( OutputDevice* pOut, long nExtraData )
389 {
390 	ImplAnimView* pView = (ImplAnimView*) mpViewList->First();
391 
392 	while( pView )
393 	{
394 		if( pView->ImplMatches( pOut, nExtraData ) )
395 		{
396 			delete (ImplAnimView*) mpViewList->Remove( pView );
397 			pView = (ImplAnimView*) mpViewList->GetCurObject();
398 		}
399 		else
400 			pView = (ImplAnimView*) mpViewList->Next();
401 	}
402 
403 	if( !mpViewList->Count() )
404 	{
405 		maTimer.Stop();
406 		mbIsInAnimation = sal_False;
407 	}
408 }
409 
410 // -----------------------------------------------------------------------
411 
412 void Animation::Draw( OutputDevice* pOut, const Point& rDestPt ) const
413 {
414 	Draw( pOut, rDestPt, pOut->PixelToLogic( maGlobalSize ) );
415 }
416 
417 // -----------------------------------------------------------------------
418 
419 void Animation::Draw( OutputDevice* pOut, const Point& rDestPt, const Size& rDestSz ) const
420 {
421 	const sal_uLong nCount = maList.Count();
422 
423 	if( nCount )
424 	{
425 		AnimationBitmap* pObj = (AnimationBitmap*) maList.GetObject( Min( mnPos, (long) nCount - 1L ) );
426 
427 		if( pOut->GetConnectMetaFile() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) )
428 			( (AnimationBitmap*) maList.GetObject( 0 ) )->aBmpEx.Draw( pOut, rDestPt, rDestSz );
429 		else if( ANIMATION_TIMEOUT_ON_CLICK == pObj->nWait )
430 			pObj->aBmpEx.Draw( pOut, rDestPt, rDestSz );
431 		else
432 		{
433 			const sal_uLong nOldPos = mnPos;
434 			( (Animation*) this )->mnPos = mbLoopTerminated ? ( nCount - 1UL ) : mnPos;
435 			delete new ImplAnimView( (Animation*) this, pOut, rDestPt, rDestSz, 0 );
436 			( (Animation*) this )->mnPos = nOldPos;
437 		}
438 	}
439 }
440 
441 // -----------------------------------------------------------------------
442 
443 void Animation::ImplRestartTimer( sal_uLong nTimeout )
444 {
445 	maTimer.SetTimeout( Max( nTimeout, (sal_uLong)(MIN_TIMEOUT + ( mnAnimCount - 1 ) * INC_TIMEOUT) ) * 10L );
446 	maTimer.Start();
447 }
448 
449 // -----------------------------------------------------------------------
450 
451 IMPL_LINK( Animation, ImplTimeoutHdl, Timer*, EMPTYARG )
452 {
453 	const sal_uLong nAnimCount = maList.Count();
454 
455 	if( nAnimCount )
456 	{
457 		ImplAnimView*	pView;
458 		sal_Bool			bGlobalPause = sal_True;
459 
460 		if( maNotifyLink.IsSet() )
461 		{
462 			AInfo* pAInfo;
463 
464 			// create AInfo-List
465 			for( pView = (ImplAnimView*) mpViewList->First(); pView; pView = (ImplAnimView*) mpViewList->Next() )
466 				maAInfoList.Insert( pView->ImplCreateAInfo() );
467 
468 			maNotifyLink.Call( this );
469 
470 			// set view state from AInfo structure
471 			for( pAInfo = (AInfo*) maAInfoList.First(); pAInfo; pAInfo = (AInfo*) maAInfoList.Next() )
472 			{
473 				if( !pAInfo->pViewData )
474 				{
475 					pView = new ImplAnimView( this, pAInfo->pOutDev,
476 											  pAInfo->aStartOrg, pAInfo->aStartSize, pAInfo->nExtraData );
477 
478 					mpViewList->Insert( pView, LIST_APPEND );
479 				}
480 				else
481 					pView = (ImplAnimView*) pAInfo->pViewData;
482 
483 				pView->ImplPause( pAInfo->bPause );
484 				pView->ImplSetMarked( sal_True );
485 			}
486 
487 			// delete AInfo structures
488 			for( pAInfo = (AInfo*) maAInfoList.First(); pAInfo; pAInfo = (AInfo*) maAInfoList.Next() )
489 				delete (AInfo*) pAInfo;
490 			maAInfoList.Clear();
491 
492 			// delete all unmarked views and reset marked state
493 			pView = (ImplAnimView*) mpViewList->First();
494 			while( pView )
495 			{
496 				if( !pView->ImplIsMarked() )
497 				{
498 					delete (ImplAnimView*) mpViewList->Remove( pView );
499 					pView = (ImplAnimView*) mpViewList->GetCurObject();
500 				}
501 				else
502 				{
503 					if( !pView->ImplIsPause() )
504 						bGlobalPause = sal_False;
505 
506 					pView->ImplSetMarked( sal_False );
507 					pView = (ImplAnimView*) mpViewList->Next();
508 				}
509 			}
510 		}
511 		else
512 			bGlobalPause = sal_False;
513 
514 		if( !mpViewList->Count() )
515 			Stop();
516 		else if( bGlobalPause )
517 			ImplRestartTimer( 10 );
518 		else
519 		{
520 			AnimationBitmap* pStepBmp = (AnimationBitmap*) maList.GetObject( ++mnPos );
521 
522 			if( !pStepBmp )
523 			{
524 				if( mnLoops == 1 )
525 				{
526 					Stop();
527 					mbLoopTerminated = sal_True;
528 					mnPos = nAnimCount - 1UL;
529 					maBitmapEx = ( (AnimationBitmap*) maList.GetObject( mnPos ) )->aBmpEx;
530 					return 0L;
531 				}
532 				else
533 				{
534 					if( mnLoops )
535 						mnLoops--;
536 
537 					mnPos = 0;
538 					pStepBmp = (AnimationBitmap*) maList.GetObject( mnPos );
539 				}
540 			}
541 
542 			// Paint all views; after painting check, if view is
543 			// marked; in this case remove view, because area of output
544 			// lies out of display area of window; mark state is
545 			// set from view itself
546 			pView = (ImplAnimView*) mpViewList->First();
547 			while( pView )
548 			{
549 				pView->ImplDraw( mnPos );
550 
551 				if( pView->ImplIsMarked() )
552 				{
553 					delete (ImplAnimView*) mpViewList->Remove( pView );
554 					pView = (ImplAnimView*) mpViewList->GetCurObject();
555 				}
556 				else
557 					pView = (ImplAnimView*) mpViewList->Next();
558 			}
559 
560 			// stop or restart timer
561 			if( !mpViewList->Count() )
562 				Stop();
563 			else
564 				ImplRestartTimer( pStepBmp->nWait );
565 		}
566 	}
567 	else
568 		Stop();
569 
570 	return 0L;
571 }
572 
573 // -----------------------------------------------------------------------
574 
575 sal_Bool Animation::Insert( const AnimationBitmap& rStepBmp )
576 {
577 	sal_Bool bRet = sal_False;
578 
579 	if( !IsInAnimation() )
580 	{
581 		Point		aPoint;
582 		Rectangle	aGlobalRect( aPoint, maGlobalSize );
583 
584 		maGlobalSize = aGlobalRect.Union( Rectangle( rStepBmp.aPosPix, rStepBmp.aSizePix ) ).GetSize();
585 		maList.Insert( new AnimationBitmap( rStepBmp ), LIST_APPEND );
586 
587 		// zunaechst nehmen wir die erste BitmapEx als Ersatz-BitmapEx
588 		if( maList.Count() == 1 )
589 			maBitmapEx = rStepBmp.aBmpEx;
590 
591 		bRet = sal_True;
592 	}
593 
594 	return bRet;
595 }
596 
597 // -----------------------------------------------------------------------
598 
599 const AnimationBitmap& Animation::Get( sal_uInt16 nAnimation ) const
600 {
601 	DBG_ASSERT( ( nAnimation < maList.Count() ), "No object at this position" );
602 	return *(AnimationBitmap*) maList.GetObject( nAnimation );
603 }
604 
605 // -----------------------------------------------------------------------
606 
607 void Animation::Replace( const AnimationBitmap& rNewAnimationBitmap, sal_uInt16 nAnimation )
608 {
609 	DBG_ASSERT( ( nAnimation < maList.Count() ), "No object at this position" );
610 
611 	delete (AnimationBitmap*) maList.Replace( new AnimationBitmap( rNewAnimationBitmap ), nAnimation );
612 
613 	// Falls wir an erster Stelle einfuegen,
614 	// muessen wir natuerlich auch,
615 	// auch die Ersatzdarstellungs-BitmapEx
616 	// aktualisieren;
617 	if ( ( !nAnimation && ( !mbLoopTerminated || ( maList.Count() == 1 ) ) ) ||
618 		 ( ( nAnimation == maList.Count() - 1 ) && mbLoopTerminated ) )
619 	{
620 		maBitmapEx = rNewAnimationBitmap.aBmpEx;
621 	}
622 }
623 
624 // -----------------------------------------------------------------------
625 
626 void Animation::SetLoopCount( const sal_uLong nLoopCount )
627 {
628 	mnLoopCount = nLoopCount;
629 	ResetLoopCount();
630 }
631 
632 // -----------------------------------------------------------------------
633 
634 void Animation::ResetLoopCount()
635 {
636 	mnLoops = mnLoopCount;
637 	mbLoopTerminated = sal_False;
638 }
639 
640 // -----------------------------------------------------------------------
641 
642 sal_Bool Animation::Convert( BmpConversion eConversion )
643 {
644 	DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
645 
646 	sal_Bool bRet;
647 
648 	if( !IsInAnimation() && maList.Count() )
649 	{
650 		bRet = sal_True;
651 
652 		for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
653 			bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Convert( eConversion );
654 
655 		maBitmapEx.Convert( eConversion );
656 	}
657 	else
658 		bRet = sal_False;
659 
660 	return bRet;
661 }
662 
663 // -----------------------------------------------------------------------
664 
665 sal_Bool Animation::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce )
666 {
667 	DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
668 
669 	sal_Bool bRet;
670 
671 	if( !IsInAnimation() && maList.Count() )
672 	{
673 		bRet = sal_True;
674 
675 		for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
676 			bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.ReduceColors( nNewColorCount, eReduce );
677 
678 		maBitmapEx.ReduceColors( nNewColorCount, eReduce );
679 	}
680 	else
681 		bRet = sal_False;
682 
683 	return bRet;
684 }
685 
686 // -----------------------------------------------------------------------
687 
688 sal_Bool Animation::Invert()
689 {
690 	DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
691 
692 	sal_Bool bRet;
693 
694 	if( !IsInAnimation() && maList.Count() )
695 	{
696 		bRet = sal_True;
697 
698 		for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
699 			bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Invert();
700 
701 		maBitmapEx.Invert();
702 	}
703 	else
704 		bRet = sal_False;
705 
706 	return bRet;
707 }
708 
709 // -----------------------------------------------------------------------
710 
711 sal_Bool Animation::Mirror( sal_uLong nMirrorFlags )
712 {
713 	DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
714 
715 	sal_Bool	bRet;
716 
717 	if( !IsInAnimation() && maList.Count() )
718 	{
719 		bRet = sal_True;
720 
721 		if( nMirrorFlags )
722 		{
723 			for( AnimationBitmap* pStepBmp = (AnimationBitmap*) maList.First();
724 				 pStepBmp && bRet;
725 				 pStepBmp = (AnimationBitmap*) maList.Next() )
726 			{
727 				if( ( bRet = pStepBmp->aBmpEx.Mirror( nMirrorFlags ) ) == sal_True )
728 				{
729 					if( nMirrorFlags & BMP_MIRROR_HORZ )
730 						pStepBmp->aPosPix.X() = maGlobalSize.Width() - pStepBmp->aPosPix.X() - pStepBmp->aSizePix.Width();
731 
732 					if( nMirrorFlags & BMP_MIRROR_VERT )
733 						pStepBmp->aPosPix.Y() = maGlobalSize.Height() - pStepBmp->aPosPix.Y() - pStepBmp->aSizePix.Height();
734 				}
735 			}
736 
737 			maBitmapEx.Mirror( nMirrorFlags );
738 		}
739 	}
740 	else
741 		bRet = sal_False;
742 
743 	return bRet;
744 }
745 
746 // -----------------------------------------------------------------------
747 
748 sal_Bool Animation::Dither( sal_uLong nDitherFlags )
749 {
750 	DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
751 
752 	sal_Bool bRet;
753 
754 	if( !IsInAnimation() && maList.Count() )
755 	{
756 		bRet = sal_True;
757 
758 		for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
759 			bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Dither( nDitherFlags );
760 
761 		maBitmapEx.Dither( nDitherFlags );
762 	}
763 	else
764 		bRet = sal_False;
765 
766 	return bRet;
767 }
768 
769 // -----------------------------------------------------------------------
770 
771 sal_Bool Animation::Adjust( short nLuminancePercent, short nContrastPercent,
772 			 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
773 			 double fGamma, sal_Bool bInvert )
774 {
775 	DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
776 
777 	sal_Bool bRet;
778 
779 	if( !IsInAnimation() && maList.Count() )
780 	{
781 		bRet = sal_True;
782 
783 		for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
784 		{
785 			bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Adjust( nLuminancePercent, nContrastPercent,
786 																	nChannelRPercent, nChannelGPercent, nChannelBPercent,
787 																	fGamma, bInvert );
788 		}
789 
790 		maBitmapEx.Adjust( nLuminancePercent, nContrastPercent,
791 						   nChannelRPercent, nChannelGPercent, nChannelBPercent,
792 						   fGamma, bInvert );
793 	}
794 	else
795 		bRet = sal_False;
796 
797 	return bRet;
798 }
799 
800 // -----------------------------------------------------------------------
801 
802 sal_Bool Animation::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
803 {
804 	DBG_ASSERT( !IsInAnimation(), "Animation modified while it is animated" );
805 
806 	sal_Bool bRet;
807 
808 	if( !IsInAnimation() && maList.Count() )
809 	{
810 		bRet = sal_True;
811 
812 		for( void* pStepBmp = maList.First(); pStepBmp && bRet; pStepBmp = maList.Next() )
813 			bRet = ( ( AnimationBitmap*) pStepBmp )->aBmpEx.Filter( eFilter, pFilterParam, pProgress );
814 
815 		maBitmapEx.Filter( eFilter, pFilterParam, pProgress );
816 	}
817 	else
818 		bRet = sal_False;
819 
820 	return bRet;
821 }
822 
823 // -----------------------------------------------------------------------
824 
825 SvStream& operator<<( SvStream& rOStm, const Animation& rAnimation )
826 {
827 	const sal_uInt16 nCount = rAnimation.Count();
828 
829 	if( nCount )
830 	{
831 		const ByteString	aDummyStr;
832 		const sal_uInt32		nDummy32 = 0UL;
833 
834 		// Falls keine BitmapEx gesetzt wurde, schreiben wir
835 		// einfach die erste Bitmap der Animation
836 		if( !rAnimation.GetBitmapEx().GetBitmap() )
837 			rOStm << rAnimation.Get( 0 ).aBmpEx;
838 		else
839 			rOStm << rAnimation.GetBitmapEx();
840 
841 		// Kennung schreiben ( SDANIMA1 )
842 		rOStm << (sal_uInt32) 0x5344414e << (sal_uInt32) 0x494d4931;
843 
844 		for( sal_uInt16 i = 0; i < nCount; i++ )
845 		{
846 			const AnimationBitmap&	rAnimBmp = rAnimation.Get( i );
847 			const sal_uInt16			nRest = nCount - i - 1;
848 
849 			// AnimationBitmap schreiben
850 			rOStm << rAnimBmp.aBmpEx;
851 			rOStm << rAnimBmp.aPosPix;
852 			rOStm << rAnimBmp.aSizePix;
853 			rOStm << rAnimation.maGlobalSize;
854 			rOStm << (sal_uInt16) ( ( ANIMATION_TIMEOUT_ON_CLICK == rAnimBmp.nWait ) ? 65535 : rAnimBmp.nWait );
855 			rOStm << (sal_uInt16) rAnimBmp.eDisposal;
856 			rOStm << (sal_uInt8) rAnimBmp.bUserInput;
857 			rOStm << (sal_uInt32) rAnimation.mnLoopCount;
858 			rOStm << nDummy32;	// unbenutzt
859 			rOStm << nDummy32;	// unbenutzt
860 			rOStm << nDummy32;	// unbenutzt
861 			rOStm << aDummyStr; // unbenutzt
862 			rOStm << nRest; 	// Anzahl der Strukturen, die noch _folgen_
863 		}
864 	}
865 
866 	return rOStm;
867 }
868 
869 // -----------------------------------------------------------------------
870 
871 SvStream& operator>>( SvStream& rIStm, Animation& rAnimation )
872 {
873 	Bitmap	aBmp;
874 	sal_uLong	nStmPos = rIStm.Tell();
875 	sal_uInt32	nAnimMagic1, nAnimMagic2;
876 	sal_uInt16	nOldFormat = rIStm.GetNumberFormatInt();
877 	sal_Bool	bReadAnimations = sal_False;
878 
879 	rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
880 	nStmPos = rIStm.Tell();
881 	rIStm >> nAnimMagic1 >> nAnimMagic2;
882 
883 	rAnimation.Clear();
884 
885 	// Wenn die BitmapEx am Anfang schon gelesen
886 	// wurde ( von Graphic ), koennen wir direkt die Animationsbitmaps einlesen
887 	if( ( nAnimMagic1 == 0x5344414e ) && ( nAnimMagic2 == 0x494d4931 ) && !rIStm.GetError() )
888 		bReadAnimations = sal_True;
889 	// ansonsten versuchen wir erstmal die Bitmap(-Ex) zu lesen
890 	else
891 	{
892 		rIStm.Seek( nStmPos );
893 		rIStm >> rAnimation.maBitmapEx;
894 		nStmPos = rIStm.Tell();
895 		rIStm >> nAnimMagic1 >> nAnimMagic2;
896 
897 		if( ( nAnimMagic1 == 0x5344414e ) && ( nAnimMagic2 == 0x494d4931 ) && !rIStm.GetError() )
898 			bReadAnimations = sal_True;
899 		else
900 			rIStm.Seek( nStmPos );
901 	}
902 
903 	// ggf. Animationsbitmaps lesen
904 	if( bReadAnimations )
905 	{
906 		AnimationBitmap aAnimBmp;
907 		BitmapEx		aBmpEx;
908 		ByteString		aDummyStr;
909 		sal_uInt32			nTmp32;
910 		sal_uInt16			nTmp16;
911 		sal_uInt8			cTmp;
912 
913 		do
914 		{
915 			rIStm >> aAnimBmp.aBmpEx;
916 			rIStm >> aAnimBmp.aPosPix;
917 			rIStm >> aAnimBmp.aSizePix;
918 			rIStm >> rAnimation.maGlobalSize;
919 			rIStm >> nTmp16; aAnimBmp.nWait = ( ( 65535 == nTmp16 ) ? ANIMATION_TIMEOUT_ON_CLICK : nTmp16 );
920 			rIStm >> nTmp16; aAnimBmp.eDisposal = ( Disposal) nTmp16;
921 			rIStm >> cTmp; aAnimBmp.bUserInput = (sal_Bool) cTmp;
922 			rIStm >> nTmp32; rAnimation.mnLoopCount = (sal_uInt16) nTmp32;
923 			rIStm >> nTmp32;	// unbenutzt
924 			rIStm >> nTmp32;	// unbenutzt
925 			rIStm >> nTmp32;	// unbenutzt
926 			rIStm >> aDummyStr; // unbenutzt
927 			rIStm >> nTmp16;	// Rest zu lesen
928 
929 			rAnimation.Insert( aAnimBmp );
930 		}
931 		while( nTmp16 && !rIStm.GetError() );
932 
933 		rAnimation.ResetLoopCount();
934 	}
935 
936 	rIStm.SetNumberFormatInt( nOldFormat );
937 
938 	return rIStm;
939 }
940