xref: /trunk/main/vcl/source/gdi/animate.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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