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