xref: /trunk/main/vcl/source/gdi/gdimtf.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 #include <vos/macros.hxx>
31 #include <rtl/crc.h>
32 #include <tools/stream.hxx>
33 #include <tools/vcompat.hxx>
34 #include <vcl/metaact.hxx>
35 #include <vcl/salbtype.hxx>
36 #include <vcl/outdev.hxx>
37 #include <vcl/window.hxx>
38 #ifndef _SV_CVTSVM_HXX
39 #include <vcl/cvtsvm.hxx>
40 #endif
41 #include <vcl/virdev.hxx>
42 #include <vcl/gdimtf.hxx>
43 #include <vcl/graphictools.hxx>
44 
45 // -----------
46 // - Defines -
47 // -----------
48 
49 #define GAMMA( _def_cVal, _def_InvGamma )   ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
50 
51 // --------------------------
52 // - Color exchange structs -
53 // --------------------------
54 
55 struct ImplColAdjustParam
56 {
57     sal_uInt8*  pMapR;
58     sal_uInt8*  pMapG;
59     sal_uInt8*  pMapB;
60 };
61 
62 struct ImplBmpAdjustParam
63 {
64     short   nLuminancePercent;
65     short   nContrastPercent;
66     short   nChannelRPercent;
67     short   nChannelGPercent;
68     short   nChannelBPercent;
69     double  fGamma;
70     sal_Bool    bInvert;
71 };
72 
73 // -----------------------------------------------------------------------------
74 
75 struct ImplColConvertParam
76 {
77     MtfConversion   eConversion;
78 };
79 
80 struct ImplBmpConvertParam
81 {
82     BmpConversion   eConversion;
83 };
84 
85 // -----------------------------------------------------------------------------
86 
87 struct ImplColMonoParam
88 {
89     Color aColor;
90 };
91 
92 struct ImplBmpMonoParam
93 {
94     Color aColor;
95 };
96 
97 // -----------------------------------------------------------------------------
98 
99 struct ImplColReplaceParam
100 {
101     sal_uLong*          pMinR;
102     sal_uLong*          pMaxR;
103     sal_uLong*          pMinG;
104     sal_uLong*          pMaxG;
105     sal_uLong*          pMinB;
106     sal_uLong*          pMaxB;
107     const Color*    pDstCols;
108     sal_uLong           nCount;
109 };
110 
111 struct ImplBmpReplaceParam
112 {
113     const Color*    pSrcCols;
114     const Color*    pDstCols;
115     sal_uLong           nCount;
116     const sal_uLong*    pTols;
117 };
118 
119 
120 // ---------
121 // - Label -
122 // ---------
123 
124 struct ImpLabel
125 {
126     String  aLabelName;
127     sal_uLong   nActionPos;
128 
129             ImpLabel( const String& rLabelName, sal_uLong _nActionPos ) :
130                 aLabelName( rLabelName ),
131                 nActionPos( _nActionPos ) {}
132 };
133 
134 // -------------
135 // - LabelList -
136 // -------------
137 
138 class ImpLabelList : private List
139 {
140 public:
141 
142                 ImpLabelList() : List( 8, 4, 4 ) {}
143                 ImpLabelList( const ImpLabelList& rList );
144                 ~ImpLabelList();
145 
146     void        ImplInsert( ImpLabel* p ) { Insert( p, LIST_APPEND ); }
147     ImpLabel*   ImplRemove( sal_uLong nPos ) { return (ImpLabel*) Remove( nPos ); }
148     void        ImplReplace( ImpLabel* p ) { Replace( (void*)p ); }
149     ImpLabel*   ImplFirst() { return (ImpLabel*) First(); }
150     ImpLabel*   ImplNext() { return (ImpLabel*) Next(); }
151     ImpLabel*   ImplGetLabel( sal_uLong nPos ) const { return (ImpLabel*) GetObject( nPos ); }
152     sal_uLong       ImplGetLabelPos( const String& rLabelName );
153     sal_uLong       ImplCount() const { return Count(); }
154 };
155 
156 // ------------------------------------------------------------------------
157 
158 ImpLabelList::ImpLabelList( const ImpLabelList& rList ) :
159         List( rList )
160 {
161     for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
162         ImplReplace( new ImpLabel( *pLabel ) );
163 }
164 
165 // ------------------------------------------------------------------------
166 
167 ImpLabelList::~ImpLabelList()
168 {
169     for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
170         delete pLabel;
171 }
172 
173 // ------------------------------------------------------------------------
174 
175 sal_uLong ImpLabelList::ImplGetLabelPos( const String& rLabelName )
176 {
177     sal_uLong nLabelPos = METAFILE_LABEL_NOTFOUND;
178 
179     for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
180     {
181         if ( rLabelName == pLabel->aLabelName )
182         {
183             nLabelPos = GetCurPos();
184             break;
185         }
186     }
187 
188     return nLabelPos;
189 }
190 
191 // ---------------
192 // - GDIMetaFile -
193 // ---------------
194 
195 GDIMetaFile::GDIMetaFile() :
196     List        ( 0x3EFF, 64, 64 ),
197     aPrefSize   ( 1, 1 ),
198     pPrev       ( NULL ),
199     pNext       ( NULL ),
200     pOutDev     ( NULL ),
201     pLabelList  ( NULL ),
202     bPause      ( sal_False ),
203     bRecord     ( sal_False )
204 {
205 }
206 
207 // ------------------------------------------------------------------------
208 
209 GDIMetaFile::GDIMetaFile( const GDIMetaFile& rMtf ) :
210     List            ( rMtf ),
211     aPrefMapMode    ( rMtf.aPrefMapMode ),
212     aPrefSize       ( rMtf.aPrefSize ),
213     aHookHdlLink    ( rMtf.aHookHdlLink ),
214     pPrev           ( rMtf.pPrev ),
215     pNext           ( rMtf.pNext ),
216     pOutDev         ( NULL ),
217     bPause          ( sal_False ),
218     bRecord         ( sal_False )
219 {
220     // RefCount der MetaActions erhoehen
221     for( void* pAct = First(); pAct; pAct = Next() )
222         ( (MetaAction*) pAct )->Duplicate();
223 
224     if( rMtf.pLabelList )
225         pLabelList = new ImpLabelList( *rMtf.pLabelList );
226     else
227         pLabelList = NULL;
228 
229     if( rMtf.bRecord )
230     {
231         Record( rMtf.pOutDev );
232 
233         if ( rMtf.bPause )
234             Pause( sal_True );
235     }
236 }
237 
238 // ------------------------------------------------------------------------
239 
240 GDIMetaFile::~GDIMetaFile()
241 {
242     Clear();
243 }
244 
245 // ------------------------------------------------------------------------
246 
247 GDIMetaFile& GDIMetaFile::operator=( const GDIMetaFile& rMtf )
248 {
249     if( this != &rMtf )
250     {
251         Clear();
252 
253         List::operator=( rMtf );
254 
255         // RefCount der MetaActions erhoehen
256         for( void* pAct = First(); pAct; pAct = Next() )
257             ( (MetaAction*) pAct )->Duplicate();
258 
259         if( rMtf.pLabelList )
260             pLabelList = new ImpLabelList( *rMtf.pLabelList );
261         else
262            pLabelList = NULL;
263 
264         aPrefMapMode = rMtf.aPrefMapMode;
265         aPrefSize = rMtf.aPrefSize;
266         aHookHdlLink = rMtf.aHookHdlLink;
267         pPrev = rMtf.pPrev;
268         pNext = rMtf.pNext;
269         pOutDev = NULL;
270         bPause = sal_False;
271         bRecord = sal_False;
272 
273         if( rMtf.bRecord )
274         {
275             Record( rMtf.pOutDev );
276 
277             if( rMtf.bPause )
278                 Pause( sal_True );
279         }
280     }
281 
282     return *this;
283 }
284 
285 // ------------------------------------------------------------------------
286 
287 sal_Bool GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const
288 {
289     const sal_uLong nObjCount = Count();
290     sal_Bool        bRet = sal_False;
291 
292     if( this == &rMtf )
293         bRet = sal_True;
294     else if( rMtf.GetActionCount() == nObjCount &&
295              rMtf.GetPrefSize() == aPrefSize &&
296              rMtf.GetPrefMapMode() == aPrefMapMode )
297     {
298         bRet = sal_True;
299 
300         for( sal_uLong n = 0UL; n < nObjCount; n++ )
301         {
302             if( GetObject( n ) != rMtf.GetObject( n ) )
303             {
304                 bRet = sal_False;
305                 break;
306             }
307         }
308     }
309 
310     return bRet;
311 }
312 
313 // ------------------------------------------------------------------------
314 
315 sal_Bool GDIMetaFile::IsEqual( const GDIMetaFile& rMtf ) const
316 {
317     const sal_uLong nObjCount = Count();
318     sal_Bool        bRet = sal_False;
319 
320     if( this == &rMtf )
321         bRet = sal_True;
322     else if( rMtf.GetActionCount() == nObjCount &&
323              rMtf.GetPrefSize() == aPrefSize &&
324              rMtf.GetPrefMapMode() == aPrefMapMode )
325     {
326         bRet = sal_True;
327 
328         for( sal_uLong n = 0UL; n < nObjCount; n++ )
329         {
330             if(!((MetaAction*)GetObject( n ))->IsEqual(*((MetaAction*)rMtf.GetObject( n ))))
331             {
332                 bRet = sal_False;
333                 break;
334             }
335         }
336     }
337 
338     return bRet;
339 }
340 
341 // ------------------------------------------------------------------------
342 
343 void GDIMetaFile::Clear()
344 {
345     if( bRecord )
346         Stop();
347 
348     for( void* pAct = First(); pAct; pAct = Next() )
349         ( (MetaAction*) pAct )->Delete();
350 
351     List::Clear();
352 
353     delete pLabelList;
354     pLabelList = NULL;
355 }
356 
357 // ------------------------------------------------------------------------
358 
359 void GDIMetaFile::Linker( OutputDevice* pOut, sal_Bool bLink )
360 {
361     if( bLink )
362     {
363         pNext = NULL;
364         pPrev = pOut->GetConnectMetaFile();
365         pOut->SetConnectMetaFile( this );
366 
367         if( pPrev )
368             pPrev->pNext = this;
369     }
370     else
371     {
372         if( pNext )
373         {
374             pNext->pPrev = pPrev;
375 
376             if( pPrev )
377                 pPrev->pNext = pNext;
378         }
379         else
380         {
381             if( pPrev )
382                 pPrev->pNext = NULL;
383 
384             pOut->SetConnectMetaFile( pPrev );
385         }
386 
387         pPrev = NULL;
388         pNext = NULL;
389     }
390 }
391 
392 // ------------------------------------------------------------------------
393 
394 long GDIMetaFile::Hook()
395 {
396     return aHookHdlLink.Call( this );
397 }
398 
399 // ------------------------------------------------------------------------
400 
401 void GDIMetaFile::Record( OutputDevice* pOut )
402 {
403     if( bRecord )
404         Stop();
405 
406     Last();
407     pOutDev = pOut;
408     bRecord = sal_True;
409     Linker( pOut, sal_True );
410 }
411 
412 // ------------------------------------------------------------------------
413 
414 void GDIMetaFile::Play( GDIMetaFile& rMtf, sal_uLong nPos )
415 {
416     if ( !bRecord && !rMtf.bRecord )
417     {
418         MetaAction* pAction = GetCurAction();
419         const sal_uLong nObjCount = Count();
420 
421         if( nPos > nObjCount )
422             nPos = nObjCount;
423 
424         for( sal_uLong nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ )
425         {
426             if( !Hook() )
427             {
428                 pAction->Duplicate();
429                 rMtf.AddAction( pAction );
430             }
431 
432             pAction = (MetaAction*) Next();
433         }
434     }
435 }
436 
437 // ------------------------------------------------------------------------
438 
439 void GDIMetaFile::Play( OutputDevice* pOut, sal_uLong nPos )
440 {
441     if( !bRecord )
442     {
443         MetaAction* pAction = GetCurAction();
444         const sal_uLong nObjCount = Count();
445         sal_uLong       i  = 0, nSyncCount = ( pOut->GetOutDevType() == OUTDEV_WINDOW ) ? 0x000000ff : 0xffffffff;
446 
447         if( nPos > nObjCount )
448             nPos = nObjCount;
449 
450         // #i23407# Set backwards-compatible text language and layout mode
451         // This is necessary, since old metafiles don't even know of these
452         // recent add-ons. Newer metafiles must of course explicitely set
453         // those states.
454         pOut->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE );
455         pOut->SetLayoutMode( 0 );
456         pOut->SetDigitLanguage( 0 );
457 
458         for( sal_uLong nCurPos = GetCurPos(); nCurPos < nPos; nCurPos++ )
459         {
460             if( !Hook() )
461             {
462                 pAction->Execute( pOut );
463 
464                 // flush output from time to time
465                 if( i++ > nSyncCount )
466                     ( (Window*) pOut )->Flush(), i = 0;
467             }
468 
469             pAction = (MetaAction*) Next();
470         }
471 
472         pOut->Pop();
473     }
474 }
475 
476 // ------------------------------------------------------------------------
477 
478 void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos,
479                         const Size& rSize, sal_uLong nPos )
480 {
481     Region  aDrawClipRegion;
482     MapMode aDrawMap( GetPrefMapMode() );
483     Size    aDestSize( pOut->LogicToPixel( rSize ) );
484 
485     if( aDestSize.Width() && aDestSize.Height() )
486     {
487         Size            aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) );
488         GDIMetaFile*    pMtf = pOut->GetConnectMetaFile();
489 
490         if( !aTmpPrefSize.Width() )
491             aTmpPrefSize.Width() = aDestSize.Width();
492 
493         if( !aTmpPrefSize.Height() )
494             aTmpPrefSize.Height() = aDestSize.Height();
495 
496         Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() );
497         Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() );
498 
499         aScaleX *= aDrawMap.GetScaleX(); aDrawMap.SetScaleX( aScaleX );
500         aScaleY *= aDrawMap.GetScaleY(); aDrawMap.SetScaleY( aScaleY );
501 
502         // #i47260# Convert logical output position to offset within
503         // the metafile's mapmode. Therefore, disable pixel offset on
504         // outdev, it's inverse mnOutOffLogicX/Y is calculated for a
505         // different mapmode (the one currently set on pOut, that is)
506         // - thus, aDrawMap's origin would generally be wrong. And
507         // even _if_ aDrawMap is similar to pOutDev's current mapmode,
508         // it's _still_ undesirable to have pixel offset unequal zero,
509         // because one would still get round-off errors (the
510         // round-trip error for LogicToPixel( PixelToLogic() ) was the
511         // reason for having pixel offset in the first place).
512         const Size& rOldOffset( pOut->GetPixelOffset() );
513         const Size  aEmptySize;
514         pOut->SetPixelOffset( aEmptySize );
515         aDrawMap.SetOrigin( pOut->PixelToLogic( pOut->LogicToPixel( rPos ), aDrawMap ) );
516         pOut->SetPixelOffset( rOldOffset );
517 
518         pOut->Push();
519 
520         if ( pMtf && pMtf->IsRecord() && ( pOut->GetOutDevType() != OUTDEV_PRINTER ) )
521             pOut->SetRelativeMapMode( aDrawMap );
522         else
523             pOut->SetMapMode( aDrawMap );
524 
525         // #i23407# Set backwards-compatible text language and layout mode
526         // This is necessary, since old metafiles don't even know of these
527         // recent add-ons. Newer metafiles must of course explicitely set
528         // those states.
529         pOut->SetLayoutMode( 0 );
530         pOut->SetDigitLanguage( 0 );
531 
532         Play( pOut, nPos );
533 
534         pOut->Pop();
535     }
536 }
537 
538 // ------------------------------------------------------------------------
539 
540 void GDIMetaFile::Pause( sal_Bool _bPause )
541 {
542     if( bRecord )
543     {
544         if( _bPause )
545         {
546             if( !bPause )
547                 Linker( pOutDev, sal_False );
548         }
549         else
550         {
551             if( bPause )
552                 Linker( pOutDev, sal_True );
553         }
554 
555         bPause = _bPause;
556     }
557 }
558 
559 // ------------------------------------------------------------------------
560 
561 void GDIMetaFile::Stop()
562 {
563     if( bRecord )
564     {
565         bRecord = sal_False;
566 
567         if( !bPause )
568             Linker( pOutDev, sal_False );
569         else
570             bPause = sal_False;
571     }
572 }
573 
574 // ------------------------------------------------------------------------
575 
576 void GDIMetaFile::WindStart()
577 {
578     if( !bRecord )
579         First();
580 }
581 
582 // ------------------------------------------------------------------------
583 
584 void GDIMetaFile::WindEnd()
585 {
586     if( !bRecord )
587         Last();
588 }
589 
590 // ------------------------------------------------------------------------
591 
592 void GDIMetaFile::Wind( sal_uLong nActionPos )
593 {
594     if( !bRecord )
595         Seek( nActionPos );
596 }
597 
598 // ------------------------------------------------------------------------
599 
600 void GDIMetaFile::WindPrev()
601 {
602     if( !bRecord )
603         Prev();
604 }
605 
606 // ------------------------------------------------------------------------
607 
608 void GDIMetaFile::WindNext()
609 {
610     if( !bRecord )
611         Next();
612 }
613 
614 // ------------------------------------------------------------------------
615 
616 void GDIMetaFile::AddAction( MetaAction* pAction )
617 {
618     Insert( pAction, LIST_APPEND );
619 
620     if( pPrev )
621     {
622         pAction->Duplicate();
623         pPrev->AddAction( pAction );
624     }
625 }
626 
627 // ------------------------------------------------------------------------
628 
629 void GDIMetaFile::AddAction( MetaAction* pAction, sal_uLong nPos )
630 {
631     Insert( pAction, nPos );
632 
633     if( pPrev )
634     {
635         pAction->Duplicate();
636         pPrev->AddAction( pAction, nPos );
637     }
638 }
639 
640 // ------------------------------------------------------------------------
641 
642 // @since #110496#
643 void GDIMetaFile::RemoveAction( sal_uLong nPos )
644 {
645     Remove( nPos );
646 
647     if( pPrev )
648         pPrev->RemoveAction( nPos );
649 }
650 
651 // ------------------------------------------------------------------------
652 
653 MetaAction* GDIMetaFile::CopyAction( sal_uLong nPos ) const
654 {
655     return ( (MetaAction*) GetObject( nPos ) )->Clone();
656 }
657 
658 // ------------------------------------------------------------------------
659 
660 sal_uLong GDIMetaFile::GetActionPos( const String& rLabel )
661 {
662     ImpLabel* pLabel = NULL;
663 
664     if( pLabelList )
665         pLabel = pLabelList->ImplGetLabel( pLabelList->ImplGetLabelPos( rLabel ) );
666     else
667         pLabel = NULL;
668 
669     return( pLabel ? pLabel->nActionPos : METAFILE_LABEL_NOTFOUND );
670 }
671 
672 // ------------------------------------------------------------------------
673 
674 sal_Bool GDIMetaFile::InsertLabel( const String& rLabel, sal_uLong nActionPos )
675 {
676     sal_Bool bRet = sal_False;
677 
678     if( !pLabelList )
679         pLabelList = new ImpLabelList;
680 
681     if( pLabelList->ImplGetLabelPos( rLabel ) == METAFILE_LABEL_NOTFOUND )
682     {
683         pLabelList->ImplInsert( new ImpLabel( rLabel, nActionPos ) );
684         bRet = sal_True;
685     }
686 
687     return bRet;
688 }
689 
690 // ------------------------------------------------------------------------
691 
692 void GDIMetaFile::RemoveLabel( const String& rLabel )
693 {
694     if( pLabelList )
695     {
696         const sal_uLong nLabelPos = pLabelList->ImplGetLabelPos( rLabel );
697 
698         if( nLabelPos != METAFILE_LABEL_NOTFOUND )
699             delete pLabelList->ImplRemove( nLabelPos );
700     }
701 }
702 
703 // ------------------------------------------------------------------------
704 
705 void GDIMetaFile::RenameLabel( const String& rLabel, const String& rNewLabel )
706 {
707     if( pLabelList )
708     {
709         const sal_uLong nLabelPos = pLabelList->ImplGetLabelPos( rLabel );
710 
711         if ( nLabelPos != METAFILE_LABEL_NOTFOUND )
712             pLabelList->ImplGetLabel( nLabelPos )->aLabelName = rNewLabel;
713     }
714 }
715 
716 // ------------------------------------------------------------------------
717 
718 sal_uLong GDIMetaFile::GetLabelCount() const
719 {
720     return( pLabelList ? pLabelList->ImplCount() : 0UL );
721 }
722 
723 // ------------------------------------------------------------------------
724 
725 String GDIMetaFile::GetLabel( sal_uLong nLabel )
726 {
727     String aString;
728 
729     if( pLabelList )
730     {
731         const ImpLabel* pLabel = pLabelList->ImplGetLabel( nLabel );
732 
733         if( pLabel )
734             aString = pLabel->aLabelName;
735     }
736 
737     return aString;
738 }
739 
740 // ------------------------------------------------------------------------
741 
742 sal_Bool GDIMetaFile::SaveStatus()
743 {
744     if ( bRecord )
745     {
746         if ( bPause )
747             Linker( pOutDev, sal_True );
748 
749         AddAction( new MetaLineColorAction( pOutDev->GetLineColor(),
750                                             pOutDev->IsLineColor() ) );
751         AddAction( new MetaFillColorAction( pOutDev->GetFillColor(),
752                                             pOutDev->IsFillColor() ) );
753         AddAction( new MetaFontAction( pOutDev->GetFont() ) );
754         AddAction( new MetaTextColorAction( pOutDev->GetTextColor() ) );
755         AddAction( new MetaTextFillColorAction( pOutDev->GetTextFillColor(),
756                                                 pOutDev->IsTextFillColor() ) );
757         AddAction( new MetaTextLineColorAction( pOutDev->GetTextLineColor(),
758                                                 pOutDev->IsTextLineColor() ) );
759         AddAction( new MetaOverlineColorAction( pOutDev->GetOverlineColor(),
760                                                 pOutDev->IsOverlineColor() ) );
761         AddAction( new MetaTextAlignAction( pOutDev->GetTextAlign() ) );
762         AddAction( new MetaRasterOpAction( pOutDev->GetRasterOp() ) );
763         AddAction( new MetaMapModeAction( pOutDev->GetMapMode() ) );
764         AddAction( new MetaClipRegionAction( pOutDev->GetClipRegion(),
765                                              pOutDev->IsClipRegion() ) );
766 
767         if ( bPause )
768             Linker( pOutDev, sal_False );
769 
770         return sal_True;
771     }
772     else
773         return sal_False;
774 }
775 
776 // ------------------------------------------------------------------------
777 
778 sal_Bool GDIMetaFile::Mirror( sal_uLong nMirrorFlags )
779 {
780     const Size  aOldPrefSize( GetPrefSize() );
781     long        nMoveX, nMoveY;
782     double      fScaleX, fScaleY;
783     sal_Bool        bRet;
784 
785     if( nMirrorFlags & MTF_MIRROR_HORZ )
786         nMoveX = VOS_ABS( aOldPrefSize.Width() ) - 1, fScaleX = -1.0;
787     else
788         nMoveX = 0, fScaleX = 1.0;
789 
790     if( nMirrorFlags & MTF_MIRROR_VERT )
791         nMoveY = VOS_ABS( aOldPrefSize.Height() ) - 1, fScaleY = -1.0;
792     else
793         nMoveY = 0, fScaleY = 1.0;
794 
795     if( ( fScaleX != 1.0 ) || ( fScaleY != 1.0 ) )
796     {
797         Scale( fScaleX, fScaleY );
798         Move( nMoveX, nMoveY );
799         SetPrefSize( aOldPrefSize );
800         bRet = sal_True;
801     }
802     else
803         bRet = sal_False;
804 
805     return bRet;
806 }
807 
808 // ------------------------------------------------------------------------
809 
810 void GDIMetaFile::Move( long nX, long nY )
811 {
812     const Size      aBaseOffset( nX, nY );
813     Size            aOffset( aBaseOffset );
814     VirtualDevice   aMapVDev;
815 
816     aMapVDev.EnableOutput( sal_False );
817     aMapVDev.SetMapMode( GetPrefMapMode() );
818 
819     for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
820     {
821         const long  nType = pAct->GetType();
822         MetaAction* pModAct;
823 
824         if( pAct->GetRefCount() > 1 )
825         {
826             Replace( pModAct = pAct->Clone(), GetCurPos() );
827             pAct->Delete();
828         }
829         else
830             pModAct = pAct;
831 
832         if( ( META_MAPMODE_ACTION == nType ) ||
833             ( META_PUSH_ACTION == nType ) ||
834             ( META_POP_ACTION == nType ) )
835         {
836             pModAct->Execute( &aMapVDev );
837             aOffset = aMapVDev.LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev.GetMapMode() );
838         }
839 
840         pModAct->Move( aOffset.Width(), aOffset.Height() );
841     }
842 }
843 
844 void GDIMetaFile::Move( long nX, long nY, long nDPIX, long nDPIY )
845 {
846     const Size      aBaseOffset( nX, nY );
847     Size            aOffset( aBaseOffset );
848     VirtualDevice   aMapVDev;
849 
850     aMapVDev.EnableOutput( sal_False );
851     aMapVDev.SetReferenceDevice( nDPIX, nDPIY );
852     aMapVDev.SetMapMode( GetPrefMapMode() );
853 
854     for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
855     {
856         const long  nType = pAct->GetType();
857         MetaAction* pModAct;
858 
859         if( pAct->GetRefCount() > 1 )
860         {
861             Replace( pModAct = pAct->Clone(), GetCurPos() );
862             pAct->Delete();
863         }
864         else
865             pModAct = pAct;
866 
867         if( ( META_MAPMODE_ACTION == nType ) ||
868             ( META_PUSH_ACTION == nType ) ||
869             ( META_POP_ACTION == nType ) )
870         {
871             pModAct->Execute( &aMapVDev );
872             if( aMapVDev.GetMapMode().GetMapUnit() == MAP_PIXEL )
873             {
874                 aOffset = aMapVDev.LogicToPixel( aBaseOffset, GetPrefMapMode() );
875                 MapMode aMap( aMapVDev.GetMapMode() );
876                 aOffset.Width() = static_cast<long>(aOffset.Width() * (double)aMap.GetScaleX());
877                 aOffset.Height() = static_cast<long>(aOffset.Height() * (double)aMap.GetScaleY());
878             }
879             else
880                 aOffset = aMapVDev.LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev.GetMapMode() );
881         }
882 
883         pModAct->Move( aOffset.Width(), aOffset.Height() );
884     }
885 }
886 
887 // ------------------------------------------------------------------------
888 
889 void GDIMetaFile::Scale( double fScaleX, double fScaleY )
890 {
891     for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
892     {
893         MetaAction* pModAct;
894 
895         if( pAct->GetRefCount() > 1 )
896         {
897             Replace( pModAct = pAct->Clone(), GetCurPos() );
898             pAct->Delete();
899         }
900         else
901             pModAct = pAct;
902 
903         pModAct->Scale( fScaleX, fScaleY );
904     }
905 
906     aPrefSize.Width() = FRound( aPrefSize.Width() * fScaleX );
907     aPrefSize.Height() = FRound( aPrefSize.Height() * fScaleY );
908 }
909 
910 // ------------------------------------------------------------------------
911 
912 void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY )
913 {
914     Scale( (double) rScaleX, (double) rScaleY );
915 }
916 
917 // ------------------------------------------------------------------------
918 
919 void GDIMetaFile::Clip( const Rectangle& i_rClipRect )
920 {
921     Rectangle aCurRect( i_rClipRect );
922     VirtualDevice   aMapVDev;
923 
924     aMapVDev.EnableOutput( sal_False );
925     aMapVDev.SetMapMode( GetPrefMapMode() );
926 
927     for( MetaAction* pAct = (MetaAction*) First(); pAct; pAct = (MetaAction*) Next() )
928     {
929         const long  nType = pAct->GetType();
930 
931         if( ( META_MAPMODE_ACTION == nType ) ||
932             ( META_PUSH_ACTION == nType ) ||
933             ( META_POP_ACTION == nType ) )
934         {
935             pAct->Execute( &aMapVDev );
936             aCurRect = aMapVDev.LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev.GetMapMode() );
937         }
938         else if( nType == META_CLIPREGION_ACTION )
939         {
940             MetaClipRegionAction* pOldAct = (MetaClipRegionAction*)pAct;
941             Region aNewReg( aCurRect );
942             if( pOldAct->IsClipping() )
943                 aNewReg.Intersect( pOldAct->GetRegion() );
944             MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, sal_True );
945             Replace( pNewAct, GetCurPos() );
946             pOldAct->Delete();
947         }
948     }
949 }
950 
951 // ------------------------------------------------------------------------
952 
953 Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt,
954                                         const Size& rOffset, double fSin, double fCos )
955 {
956     const long nX = rPt.X() - rRotatePt.X();
957     const long nY = rPt.Y() - rRotatePt.Y();
958 
959     return Point( FRound( fCos * nX + fSin * nY ) + rRotatePt.X() + rOffset.Width(),
960                   -FRound( fSin * nX - fCos * nY ) + rRotatePt.Y() + rOffset.Height() );
961 }
962 
963 // ------------------------------------------------------------------------
964 
965 Polygon GDIMetaFile::ImplGetRotatedPolygon( const Polygon& rPoly, const Point& rRotatePt,
966                                             const Size& rOffset, double fSin, double fCos )
967 {
968     Polygon aRet( rPoly );
969 
970     aRet.Rotate( rRotatePt, fSin, fCos );
971     aRet.Move( rOffset.Width(), rOffset.Height() );
972 
973     return aRet;
974 }
975 
976 // ------------------------------------------------------------------------
977 
978 PolyPolygon GDIMetaFile::ImplGetRotatedPolyPolygon( const PolyPolygon& rPolyPoly, const Point& rRotatePt,
979                                                     const Size& rOffset, double fSin, double fCos )
980 {
981     PolyPolygon aRet( rPolyPoly );
982 
983     aRet.Rotate( rRotatePt, fSin, fCos );
984     aRet.Move( rOffset.Width(), rOffset.Height() );
985 
986     return aRet;
987 }
988 
989 // ------------------------------------------------------------------------
990 
991 void GDIMetaFile::ImplAddGradientEx( GDIMetaFile&         rMtf,
992                                      const OutputDevice&  rMapDev,
993                                      const PolyPolygon&   rPolyPoly,
994                                      const Gradient&      rGrad     )
995 {
996     // #105055# Generate comment, GradientEx and Gradient actions
997     // (within DrawGradient)
998     VirtualDevice aVDev( rMapDev, 0 );
999     aVDev.EnableOutput( sal_False );
1000     GDIMetaFile aGradMtf;
1001 
1002     aGradMtf.Record( &aVDev );
1003     aVDev.DrawGradient( rPolyPoly, rGrad );
1004     aGradMtf.Stop();
1005 
1006     int i, nAct( aGradMtf.GetActionCount() );
1007     for( i=0; i<nAct; ++i )
1008     {
1009         MetaAction* pMetaAct = aGradMtf.GetAction(i);
1010         pMetaAct->Duplicate();
1011         rMtf.AddAction( pMetaAct );
1012     }
1013 }
1014 
1015 // ------------------------------------------------------------------------
1016 
1017 void GDIMetaFile::Rotate( long nAngle10 )
1018 {
1019     nAngle10 %= 3600L;
1020     nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10;
1021 
1022     if( nAngle10 )
1023     {
1024         GDIMetaFile     aMtf;
1025         VirtualDevice   aMapVDev;
1026         const double    fAngle = F_PI1800 * nAngle10;
1027         const double    fSin = sin( fAngle );
1028         const double    fCos = cos( fAngle );
1029         Rectangle       aRect=Rectangle( Point(), GetPrefSize() );
1030         Polygon         aPoly( aRect );
1031 
1032         aPoly.Rotate( Point(), fSin, fCos );
1033 
1034         aMapVDev.EnableOutput( sal_False );
1035         aMapVDev.SetMapMode( GetPrefMapMode() );
1036 
1037         const Rectangle aNewBound( aPoly.GetBoundRect() );
1038 
1039         const Point aOrigin( GetPrefMapMode().GetOrigin().X(), GetPrefMapMode().GetOrigin().Y() );
1040         const Size  aOffset( -aNewBound.Left(), -aNewBound.Top() );
1041 
1042         Point     aRotAnchor( aOrigin );
1043         Size      aRotOffset( aOffset );
1044 
1045         for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
1046         {
1047             const sal_uInt16 nActionType = pAction->GetType();
1048 
1049             switch( nActionType )
1050             {
1051                 case( META_PIXEL_ACTION ):
1052                 {
1053                     MetaPixelAction* pAct = (MetaPixelAction*) pAction;
1054                     aMtf.AddAction( new MetaPixelAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1055                                                                               pAct->GetColor() ) );
1056                 }
1057                 break;
1058 
1059                 case( META_POINT_ACTION ):
1060                 {
1061                     MetaPointAction* pAct = (MetaPointAction*) pAction;
1062                     aMtf.AddAction( new MetaPointAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1063                 }
1064                 break;
1065 
1066                 case( META_LINE_ACTION ):
1067                 {
1068                     MetaLineAction* pAct = (MetaLineAction*) pAction;
1069                     aMtf.AddAction( new MetaLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1070                                                         ImplGetRotatedPoint( pAct->GetEndPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1071                                                         pAct->GetLineInfo() ) );
1072                 }
1073                 break;
1074 
1075                 case( META_RECT_ACTION ):
1076                 {
1077                     MetaRectAction* pAct = (MetaRectAction*) pAction;
1078                     aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1079                 }
1080                 break;
1081 
1082                 case( META_ROUNDRECT_ACTION ):
1083                 {
1084                     MetaRoundRectAction*    pAct = (MetaRoundRectAction*) pAction;
1085                     const Polygon           aRoundRectPoly( pAct->GetRect(), pAct->GetHorzRound(), pAct->GetVertRound() );
1086 
1087                     aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aRoundRectPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1088                 }
1089                 break;
1090 
1091                 case( META_ELLIPSE_ACTION ):
1092                 {
1093                     MetaEllipseAction*      pAct = (MetaEllipseAction*) pAction;
1094                     const Polygon           aEllipsePoly( pAct->GetRect().Center(), pAct->GetRect().GetWidth() >> 1, pAct->GetRect().GetHeight() >> 1 );
1095 
1096                     aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aEllipsePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1097                 }
1098                 break;
1099 
1100                 case( META_ARC_ACTION ):
1101                 {
1102                     MetaArcAction*  pAct = (MetaArcAction*) pAction;
1103                     const Polygon   aArcPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_ARC );
1104 
1105                     aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aArcPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1106                 }
1107                 break;
1108 
1109                 case( META_PIE_ACTION ):
1110                 {
1111                     MetaPieAction*  pAct = (MetaPieAction*) pAction;
1112                     const Polygon   aPiePoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_PIE );
1113 
1114                     aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aPiePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1115                 }
1116                 break;
1117 
1118                 case( META_CHORD_ACTION ):
1119                 {
1120                     MetaChordAction*    pAct = (MetaChordAction*) pAction;
1121                     const Polygon       aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), POLY_CHORD );
1122 
1123                     aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aChordPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
1124                 }
1125                 break;
1126 
1127                 case( META_POLYLINE_ACTION ):
1128                 {
1129                     MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
1130                     aMtf.AddAction( new MetaPolyLineAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->GetLineInfo() ) );
1131                 }
1132                 break;
1133 
1134                 case( META_POLYGON_ACTION ):
1135                 {
1136                     MetaPolygonAction* pAct = (MetaPolygonAction*) pAction;
1137                     aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1138                 }
1139                 break;
1140 
1141                 case( META_POLYPOLYGON_ACTION ):
1142                 {
1143                     MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
1144                     aMtf.AddAction( new MetaPolyPolygonAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1145                 }
1146                 break;
1147 
1148                 case( META_TEXT_ACTION ):
1149                 {
1150                     MetaTextAction* pAct = (MetaTextAction*) pAction;
1151                     aMtf.AddAction( new MetaTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1152                                                                              pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
1153                 }
1154                 break;
1155 
1156                 case( META_TEXTARRAY_ACTION ):
1157                 {
1158                     MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction;
1159                     aMtf.AddAction( new MetaTextArrayAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1160                                                                                   pAct->GetText(), pAct->GetDXArray(), pAct->GetIndex(), pAct->GetLen() ) );
1161                 }
1162                 break;
1163 
1164                 case( META_STRETCHTEXT_ACTION ):
1165                 {
1166                     MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
1167                     aMtf.AddAction( new MetaStretchTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1168                                                                                     pAct->GetWidth(), pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
1169                 }
1170                 break;
1171 
1172                 case( META_TEXTLINE_ACTION ):
1173                 {
1174                     MetaTextLineAction* pAct = (MetaTextLineAction*) pAction;
1175                     aMtf.AddAction( new MetaTextLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
1176                                                                                  pAct->GetWidth(), pAct->GetStrikeout(), pAct->GetUnderline(), pAct->GetOverline() ) );
1177                 }
1178                 break;
1179 
1180                 case( META_BMPSCALE_ACTION ):
1181                 {
1182                     MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
1183                     Polygon             aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1184                     Rectangle           aBmpRect( aBmpPoly.GetBoundRect() );
1185                     BitmapEx            aBmpEx( pAct->GetBitmap() );
1186 
1187                     aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1188                     aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(),
1189                                                               aBmpEx ) );
1190                 }
1191                 break;
1192 
1193                 case( META_BMPSCALEPART_ACTION ):
1194                 {
1195                     MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
1196                     Polygon                 aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1197                     Rectangle               aBmpRect( aBmpPoly.GetBoundRect() );
1198                     BitmapEx                aBmpEx( pAct->GetBitmap() );
1199 
1200                     aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
1201                     aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1202 
1203                     aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1204                 }
1205                 break;
1206 
1207                 case( META_BMPEXSCALE_ACTION ):
1208                 {
1209                     MetaBmpExScaleAction*   pAct = (MetaBmpExScaleAction*) pAction;
1210                     Polygon                 aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1211                     Rectangle               aBmpRect( aBmpPoly.GetBoundRect() );
1212                     BitmapEx                aBmpEx( pAct->GetBitmapEx() );
1213 
1214                     aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1215 
1216                     aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1217                 }
1218                 break;
1219 
1220                 case( META_BMPEXSCALEPART_ACTION ):
1221                 {
1222                     MetaBmpExScalePartAction*   pAct = (MetaBmpExScalePartAction*) pAction;
1223                     Polygon                     aBmpPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1224                     Rectangle                   aBmpRect( aBmpPoly.GetBoundRect() );
1225                     BitmapEx                    aBmpEx( pAct->GetBitmapEx() );
1226 
1227                     aBmpEx.Crop( Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
1228                     aBmpEx.Rotate( nAngle10, Color( COL_TRANSPARENT ) );
1229 
1230                     aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1231                 }
1232                 break;
1233 
1234                 case( META_GRADIENT_ACTION ):
1235                 {
1236                     MetaGradientAction* pAct = (MetaGradientAction*) pAction;
1237 
1238                     ImplAddGradientEx( aMtf, aMapVDev,
1239                                        ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ),
1240                                        pAct->GetGradient() );
1241                 }
1242                 break;
1243 
1244                 case( META_GRADIENTEX_ACTION ):
1245                 {
1246                     MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
1247                     aMtf.AddAction( new MetaGradientExAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1248                                                               pAct->GetGradient() ) );
1249                 }
1250                 break;
1251 
1252                 // #105055# Handle gradientex comment block correctly
1253                 case( META_COMMENT_ACTION ):
1254                 {
1255                     MetaCommentAction* pCommentAct = (MetaCommentAction*) pAction;
1256                     if( pCommentAct->GetComment().Equals( "XGRAD_SEQ_BEGIN" ) )
1257                     {
1258                         int nBeginComments( 1 );
1259                         pAction = (MetaAction*) Next();
1260 
1261                         // skip everything, except gradientex action
1262                         while( pAction )
1263                         {
1264                             const sal_uInt16 nType = pAction->GetType();
1265 
1266                             if( META_GRADIENTEX_ACTION == nType )
1267                             {
1268                                 // Add rotated gradientex
1269                                 MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
1270                                 ImplAddGradientEx( aMtf, aMapVDev,
1271                                                    ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1272                                                    pAct->GetGradient() );
1273                             }
1274                             else if( META_COMMENT_ACTION == nType)
1275                             {
1276                                 MetaCommentAction* pAct = (MetaCommentAction*) pAction;
1277                                 if( pAct->GetComment().Equals( "XGRAD_SEQ_END" ) )
1278                                 {
1279                                     // handle nested blocks
1280                                     --nBeginComments;
1281 
1282                                     // gradientex comment block: end reached, done.
1283                                     if( !nBeginComments )
1284                                         break;
1285                                 }
1286                                 else if( pAct->GetComment().Equals( "XGRAD_SEQ_BEGIN" ) )
1287                                 {
1288                                     // handle nested blocks
1289                                     ++nBeginComments;
1290                                 }
1291 
1292                             }
1293 
1294                             pAction = (MetaAction*) Next();
1295                         }
1296                     }
1297                     else
1298                     {
1299                         sal_Bool bPathStroke = pCommentAct->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" );
1300                         if ( bPathStroke || pCommentAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
1301                         {
1302                             if ( pCommentAct->GetDataSize() )
1303                             {
1304                                 SvMemoryStream aMemStm( (void*)pCommentAct->GetData(), pCommentAct->GetDataSize(), STREAM_READ );
1305                                 SvMemoryStream aDest;
1306                                 if ( bPathStroke )
1307                                 {
1308                                     SvtGraphicStroke aStroke;
1309                                     aMemStm >> aStroke;
1310                                     Polygon aPath;
1311                                     aStroke.getPath( aPath );
1312                                     aStroke.setPath( ImplGetRotatedPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
1313                                     aDest << aStroke;
1314                                     aMtf.AddAction( new MetaCommentAction( "XPATHSTROKE_SEQ_BEGIN", 0,
1315                                                         static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
1316                                 }
1317                                 else
1318                                 {
1319                                     SvtGraphicFill aFill;
1320                                     aMemStm >> aFill;
1321                                     PolyPolygon aPath;
1322                                     aFill.getPath( aPath );
1323                                     aFill.setPath( ImplGetRotatedPolyPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
1324                                     aDest << aFill;
1325                                     aMtf.AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1326                                                         static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
1327                                 }
1328                             }
1329                         }
1330                         else if ( pCommentAct->GetComment().Equals( "XPATHSTROKE_SEQ_END" )
1331                                || pCommentAct->GetComment().Equals( "XPATHFILL_SEQ_END" ) )
1332                         {
1333                             pAction->Execute( &aMapVDev );
1334                             pAction->Duplicate();
1335                             aMtf.AddAction( pAction );
1336                         }
1337                     }
1338                 }
1339                 break;
1340 
1341                 case( META_HATCH_ACTION ):
1342                 {
1343                     MetaHatchAction*    pAct = (MetaHatchAction*) pAction;
1344                     Hatch               aHatch( pAct->GetHatch() );
1345 
1346                     aHatch.SetAngle( aHatch.GetAngle() + (sal_uInt16) nAngle10 );
1347                     aMtf.AddAction( new MetaHatchAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1348                                                                                     aHatch ) );
1349                 }
1350                 break;
1351 
1352                 case( META_TRANSPARENT_ACTION ):
1353                 {
1354                     MetaTransparentAction* pAct = (MetaTransparentAction*) pAction;
1355                     aMtf.AddAction( new MetaTransparentAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1356                                                                                           pAct->GetTransparence() ) );
1357                 }
1358                 break;
1359 
1360                 case( META_FLOATTRANSPARENT_ACTION ):
1361                 {
1362                     MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
1363                     GDIMetaFile                 aTransMtf( pAct->GetGDIMetaFile() );
1364                     Polygon                     aMtfPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1365                     Rectangle                   aMtfRect( aMtfPoly.GetBoundRect() );
1366 
1367                     aTransMtf.Rotate( nAngle10 );
1368                     aMtf.AddAction( new MetaFloatTransparentAction( aTransMtf, aMtfRect.TopLeft(), aMtfRect.GetSize(),
1369                                                                     pAct->GetGradient() ) );
1370                 }
1371                 break;
1372 
1373                 case( META_EPS_ACTION ):
1374                 {
1375                     MetaEPSAction*  pAct = (MetaEPSAction*) pAction;
1376                     GDIMetaFile     aEPSMtf( pAct->GetSubstitute() );
1377                     Polygon         aEPSPoly( ImplGetRotatedPolygon( Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1378                     Rectangle       aEPSRect( aEPSPoly.GetBoundRect() );
1379 
1380                     aEPSMtf.Rotate( nAngle10 );
1381                     aMtf.AddAction( new MetaEPSAction( aEPSRect.TopLeft(), aEPSRect.GetSize(),
1382                                                        pAct->GetLink(), aEPSMtf ) );
1383                 }
1384                 break;
1385 
1386                 case( META_CLIPREGION_ACTION ):
1387                 {
1388                     MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
1389 
1390                     if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygon() )
1391                         aMtf.AddAction( new MetaClipRegionAction( Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), sal_True ) );
1392                     else
1393                     {
1394                         pAction->Duplicate();
1395                         aMtf.AddAction( pAction );
1396                     }
1397                 }
1398                 break;
1399 
1400                 case( META_ISECTRECTCLIPREGION_ACTION ):
1401                 {
1402                     MetaISectRectClipRegionAction*  pAct = (MetaISectRectClipRegionAction*) pAction;
1403                     aMtf.AddAction( new MetaISectRegionClipRegionAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
1404                 }
1405                 break;
1406 
1407                 case( META_ISECTREGIONCLIPREGION_ACTION ):
1408                 {
1409                     MetaISectRegionClipRegionAction*    pAct = (MetaISectRegionClipRegionAction*) pAction;
1410                     const Region&                       rRegion = pAct->GetRegion();
1411 
1412                     if( rRegion.HasPolyPolygon() )
1413                         aMtf.AddAction( new MetaISectRegionClipRegionAction( Region( ImplGetRotatedPolyPolygon( rRegion.GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) );
1414                     else
1415                     {
1416                         pAction->Duplicate();
1417                         aMtf.AddAction( pAction );
1418                     }
1419                 }
1420                 break;
1421 
1422                 case( META_REFPOINT_ACTION ):
1423                 {
1424                     MetaRefPointAction* pAct = (MetaRefPointAction*) pAction;
1425                     aMtf.AddAction( new MetaRefPointAction( ImplGetRotatedPoint( pAct->GetRefPoint(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->IsSetting() ) );
1426                 }
1427                 break;
1428 
1429                 case( META_FONT_ACTION ):
1430                 {
1431                     MetaFontAction* pAct = (MetaFontAction*) pAction;
1432                     Font            aFont( pAct->GetFont() );
1433 
1434                     aFont.SetOrientation( aFont.GetOrientation() + (sal_uInt16) nAngle10 );
1435                     aMtf.AddAction( new MetaFontAction( aFont ) );
1436                 }
1437                 break;
1438 
1439                 case( META_BMP_ACTION ):
1440                 case( META_BMPEX_ACTION ):
1441                 case( META_MASK_ACTION ):
1442                 case( META_MASKSCALE_ACTION ):
1443                 case( META_MASKSCALEPART_ACTION ):
1444                 case( META_WALLPAPER_ACTION ):
1445                 case( META_TEXTRECT_ACTION ):
1446                 case( META_MOVECLIPREGION_ACTION ):
1447                 {
1448                     DBG_ERROR( "GDIMetaFile::Rotate(): unsupported action" );
1449                 }
1450                 break;
1451 
1452                 case( META_RENDERGRAPHIC_ACTION ):
1453                 {
1454                     OSL_TRACE( "Rotate not supported for RenderGraphic MetaActions yet" );
1455 
1456                     pAction->Duplicate();
1457                     aMtf.AddAction( pAction );
1458                 }
1459                 break;
1460 
1461                 default:
1462                 {
1463                     pAction->Execute( &aMapVDev );
1464                     pAction->Duplicate();
1465                     aMtf.AddAction( pAction );
1466 
1467                     // update rotation point and offset, if necessary
1468                     if( ( META_MAPMODE_ACTION == nActionType ) ||
1469                         ( META_PUSH_ACTION == nActionType ) ||
1470                         ( META_POP_ACTION == nActionType ) )
1471                     {
1472                         aRotAnchor = aMapVDev.LogicToLogic( aOrigin, aPrefMapMode, aMapVDev.GetMapMode() );
1473                         aRotOffset = aMapVDev.LogicToLogic( aOffset, aPrefMapMode, aMapVDev.GetMapMode() );
1474                     }
1475                 }
1476                 break;
1477             }
1478         }
1479 
1480         aMtf.aPrefMapMode = aPrefMapMode;
1481         aMtf.aPrefSize = aNewBound.GetSize();
1482 
1483         *this = aMtf;
1484     }
1485 }
1486 
1487 // ------------------------------------------------------------------------
1488 
1489 static void ImplActionBounds( Rectangle& o_rOutBounds,
1490                               const Rectangle& i_rInBounds,
1491                               const std::vector<Rectangle>& i_rClipStack )
1492 {
1493     Rectangle aBounds( i_rInBounds );
1494     if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() )
1495         aBounds.Intersection( i_rClipStack.back() );
1496     if( ! aBounds.IsEmpty() )
1497     {
1498         if( ! o_rOutBounds.IsEmpty() )
1499             o_rOutBounds.Union( aBounds );
1500         else
1501             o_rOutBounds = aBounds;
1502     }
1503 }
1504 
1505 Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference )
1506 {
1507     GDIMetaFile     aMtf;
1508     VirtualDevice   aMapVDev( i_rReference );
1509 
1510     aMapVDev.EnableOutput( sal_False );
1511     aMapVDev.SetMapMode( GetPrefMapMode() );
1512 
1513     std::vector<Rectangle> aClipStack( 1, Rectangle() );
1514     std::vector<sal_uInt16> aPushFlagStack;
1515 
1516     Rectangle aBound;
1517 
1518     for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
1519     {
1520         const sal_uInt16 nActionType = pAction->GetType();
1521 
1522         switch( nActionType )
1523         {
1524         case( META_PIXEL_ACTION ):
1525         {
1526             MetaPixelAction* pAct = (MetaPixelAction*) pAction;
1527             ImplActionBounds( aBound,
1528                              Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
1529                                        aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1530                              aClipStack );
1531         }
1532         break;
1533 
1534         case( META_POINT_ACTION ):
1535         {
1536             MetaPointAction* pAct = (MetaPointAction*) pAction;
1537             ImplActionBounds( aBound,
1538                              Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
1539                                        aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1540                              aClipStack );
1541         }
1542         break;
1543 
1544         case( META_LINE_ACTION ):
1545         {
1546             MetaLineAction* pAct = (MetaLineAction*) pAction;
1547             Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() );
1548             Rectangle aRect( aP1, aP2 );
1549             aRect.Justify();
1550             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1551         }
1552         break;
1553 
1554         case( META_RECT_ACTION ):
1555         {
1556             MetaRectAction* pAct = (MetaRectAction*) pAction;
1557             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1558         }
1559         break;
1560 
1561         case( META_ROUNDRECT_ACTION ):
1562         {
1563             MetaRoundRectAction*    pAct = (MetaRoundRectAction*) pAction;
1564             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1565         }
1566         break;
1567 
1568         case( META_ELLIPSE_ACTION ):
1569         {
1570             MetaEllipseAction*      pAct = (MetaEllipseAction*) pAction;
1571             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1572         }
1573         break;
1574 
1575         case( META_ARC_ACTION ):
1576         {
1577             MetaArcAction*  pAct = (MetaArcAction*) pAction;
1578             // FIXME: this is imprecise
1579             // e.g. for small arcs the whole rectangle is WAY too large
1580             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1581         }
1582         break;
1583 
1584         case( META_PIE_ACTION ):
1585         {
1586             MetaPieAction*  pAct = (MetaPieAction*) pAction;
1587             // FIXME: this is imprecise
1588             // e.g. for small arcs the whole rectangle is WAY too large
1589             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1590         }
1591         break;
1592 
1593         case( META_CHORD_ACTION ):
1594         {
1595             MetaChordAction*    pAct = (MetaChordAction*) pAction;
1596             // FIXME: this is imprecise
1597             // e.g. for small arcs the whole rectangle is WAY too large
1598             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1599         }
1600         break;
1601 
1602         case( META_POLYLINE_ACTION ):
1603         {
1604             MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
1605             Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1606             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1607         }
1608         break;
1609 
1610         case( META_POLYGON_ACTION ):
1611         {
1612             MetaPolygonAction* pAct = (MetaPolygonAction*) pAction;
1613             Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1614             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1615         }
1616         break;
1617 
1618         case( META_POLYPOLYGON_ACTION ):
1619         {
1620             MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
1621             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1622             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1623         }
1624         break;
1625 
1626         case( META_TEXT_ACTION ):
1627         {
1628             MetaTextAction* pAct = (MetaTextAction*) pAction;
1629             Rectangle aRect;
1630             // hdu said base = index
1631             aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() );
1632             Point aPt( pAct->GetPoint() );
1633             aRect.Move( aPt.X(), aPt.Y() );
1634             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1635         }
1636         break;
1637 
1638         case( META_TEXTARRAY_ACTION ):
1639         {
1640             MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction;
1641             Rectangle aRect;
1642             // hdu said base = index
1643             aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1644                                        0, pAct->GetDXArray() );
1645             Point aPt( pAct->GetPoint() );
1646             aRect.Move( aPt.X(), aPt.Y() );
1647             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1648         }
1649         break;
1650 
1651         case( META_STRETCHTEXT_ACTION ):
1652         {
1653             MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
1654             Rectangle aRect;
1655             // hdu said base = index
1656             aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1657                                        pAct->GetWidth(), NULL );
1658             Point aPt( pAct->GetPoint() );
1659             aRect.Move( aPt.X(), aPt.Y() );
1660             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1661         }
1662         break;
1663 
1664         case( META_TEXTLINE_ACTION ):
1665         {
1666             MetaTextLineAction* pAct = (MetaTextLineAction*) pAction;
1667             // measure a test string to get ascend and descent right
1668             static const sal_Unicode pStr[] = { 0xc4, 0x67, 0 };
1669             String aStr( pStr );
1670 
1671             Rectangle aRect;
1672             aMapVDev.GetTextBoundRect( aRect, aStr, 0, 0, aStr.Len(), 0, NULL );
1673             Point aPt( pAct->GetStartPoint() );
1674             aRect.Move( aPt.X(), aPt.Y() );
1675             aRect.Right() = aRect.Left() + pAct->GetWidth();
1676             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1677         }
1678         break;
1679 
1680         case( META_BMPSCALE_ACTION ):
1681         {
1682             MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
1683             Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1684             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1685         }
1686         break;
1687 
1688         case( META_BMPSCALEPART_ACTION ):
1689         {
1690             MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
1691             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1692             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1693         }
1694         break;
1695 
1696         case( META_BMPEXSCALE_ACTION ):
1697         {
1698             MetaBmpExScaleAction*   pAct = (MetaBmpExScaleAction*) pAction;
1699             Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1700             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1701         }
1702         break;
1703 
1704         case( META_BMPEXSCALEPART_ACTION ):
1705         {
1706             MetaBmpExScalePartAction*   pAct = (MetaBmpExScalePartAction*) pAction;
1707             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1708             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1709         }
1710         break;
1711 
1712         case( META_GRADIENT_ACTION ):
1713         {
1714             MetaGradientAction* pAct = (MetaGradientAction*) pAction;
1715             Rectangle aRect( pAct->GetRect() );
1716             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1717         }
1718         break;
1719 
1720         case( META_GRADIENTEX_ACTION ):
1721         {
1722             MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
1723             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1724             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1725         }
1726         break;
1727 
1728         case( META_COMMENT_ACTION ):
1729         {
1730             // nothing to do
1731         };
1732         break;
1733 
1734         case( META_HATCH_ACTION ):
1735         {
1736             MetaHatchAction*    pAct = (MetaHatchAction*) pAction;
1737             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1738             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1739         }
1740         break;
1741 
1742         case( META_TRANSPARENT_ACTION ):
1743         {
1744             MetaTransparentAction* pAct = (MetaTransparentAction*) pAction;
1745             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1746             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1747         }
1748         break;
1749 
1750         case( META_FLOATTRANSPARENT_ACTION ):
1751         {
1752             MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
1753             GDIMetaFile                 aTransMtf( pAct->GetGDIMetaFile() );
1754             // get the bound rect of the contained metafile
1755             Rectangle aRect( aTransMtf.GetBoundRect( i_rReference ) );
1756             // scale the rect now on the assumption that the correct top left of the metafile
1757             // (not its bounds !) is (0,0)
1758             Size aPSize( aTransMtf.GetPrefSize() );
1759             aPSize = aMapVDev.LogicToLogic( aPSize, aTransMtf.GetPrefMapMode(), aMapVDev.GetMapMode() );
1760             Size aActSize( pAct->GetSize() );
1761             double fX = double(aActSize.Width())/double(aPSize.Width());
1762             double fY = double(aActSize.Height())/double(aPSize.Height());
1763             aRect.Left()   = long(double(aRect.Left())*fX);
1764             aRect.Right()  = long(double(aRect.Right())*fX);
1765             aRect.Top()    = long(double(aRect.Top())*fY);
1766             aRect.Bottom() = long(double(aRect.Bottom())*fY);
1767 
1768             // transform the rect to current VDev state
1769             aRect = aMapVDev.LogicToLogic( aRect, aTransMtf.GetPrefMapMode(), aMapVDev.GetMapMode() );
1770 
1771             ImplActionBounds( aBound, aRect, aClipStack );
1772         }
1773         break;
1774 
1775         case( META_EPS_ACTION ):
1776         {
1777             MetaEPSAction*  pAct = (MetaEPSAction*) pAction;
1778             Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1779             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1780         }
1781         break;
1782 
1783         case( META_CLIPREGION_ACTION ):
1784         {
1785             MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
1786             if( pAct->IsClipping() )
1787                 aClipStack.back() = aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() );
1788             else
1789                 aClipStack.back() = Rectangle();
1790         }
1791         break;
1792 
1793         case( META_ISECTRECTCLIPREGION_ACTION ):
1794         {
1795             MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction;
1796             Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
1797             if( aClipStack.back().IsEmpty() )
1798                 aClipStack.back() = aRect;
1799             else
1800                 aClipStack.back().Intersection( aRect );
1801         }
1802         break;
1803 
1804         case( META_ISECTREGIONCLIPREGION_ACTION ):
1805         {
1806             MetaISectRegionClipRegionAction*    pAct = (MetaISectRegionClipRegionAction*) pAction;
1807             Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
1808             if( aClipStack.back().IsEmpty() )
1809                 aClipStack.back() = aRect;
1810             else
1811                 aClipStack.back().Intersection( aRect );
1812         }
1813         break;
1814 
1815         case( META_BMP_ACTION ):
1816         {
1817             MetaBmpAction* pAct = (MetaBmpAction*) pAction;
1818             Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1819             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1820         }
1821         break;
1822 
1823         case( META_BMPEX_ACTION ):
1824         {
1825             MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
1826             Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmapEx().GetSizePixel() ) );
1827             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1828         }
1829         break;
1830 
1831         case( META_MASK_ACTION ):
1832         {
1833             MetaMaskAction* pAct = (MetaMaskAction*) pAction;
1834             Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1835             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1836         }
1837         break;
1838 
1839         case( META_MASKSCALE_ACTION ):
1840         {
1841             MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
1842             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1843             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1844         }
1845         break;
1846 
1847         case( META_MASKSCALEPART_ACTION ):
1848         {
1849             MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
1850             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1851             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1852         }
1853         break;
1854 
1855         case( META_WALLPAPER_ACTION ):
1856         {
1857             MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction;
1858             Rectangle aRect( pAct->GetRect() );
1859             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1860         }
1861         break;
1862 
1863         case( META_TEXTRECT_ACTION ):
1864         {
1865             MetaTextRectAction* pAct = (MetaTextRectAction*) pAction;
1866             Rectangle aRect( pAct->GetRect() );
1867             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1868         }
1869         break;
1870 
1871         case( META_MOVECLIPREGION_ACTION ):
1872         {
1873             MetaMoveClipRegionAction* pAct = (MetaMoveClipRegionAction*) pAction;
1874             if( ! aClipStack.back().IsEmpty() )
1875             {
1876                 Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() );
1877                 aDelta = aMapVDev.LogicToLogic( aDelta, aMapVDev.GetMapMode(), GetPrefMapMode() );
1878                 aClipStack.back().Move( aDelta.Width(), aDelta.Width() );
1879             }
1880         }
1881         break;
1882 
1883         case( META_RENDERGRAPHIC_ACTION ):
1884         {
1885             MetaRenderGraphicAction* pAct = (MetaRenderGraphicAction*) pAction;
1886             Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1887             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack );
1888         }
1889         break;
1890 
1891         default:
1892             {
1893                 pAction->Execute( &aMapVDev );
1894 
1895                 if( nActionType == META_PUSH_ACTION )
1896                 {
1897                     MetaPushAction* pAct = (MetaPushAction*) pAction;
1898                     aPushFlagStack.push_back( pAct->GetFlags() );
1899                     if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
1900                     {
1901                         Rectangle aRect( aClipStack.back() );
1902                         aClipStack.push_back( aRect );
1903                     }
1904                 }
1905                 else if( nActionType == META_POP_ACTION )
1906                 {
1907                     // sanity check
1908                     if( ! aPushFlagStack.empty() )
1909                     {
1910                         if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
1911                         {
1912                             if( aClipStack.size() > 1 )
1913                                 aClipStack.pop_back();
1914                         }
1915                         aPushFlagStack.pop_back();
1916                     }
1917                 }
1918             }
1919             break;
1920         }
1921     }
1922     return aBound;
1923 }
1924 
1925 // ------------------------------------------------------------------------
1926 
1927 Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam )
1928 {
1929     return Color( rColor.GetTransparency(),
1930                   ( (const ImplColAdjustParam*) pColParam )->pMapR[ rColor.GetRed() ],
1931                   ( (const ImplColAdjustParam*) pColParam )->pMapG[ rColor.GetGreen() ],
1932                   ( (const ImplColAdjustParam*) pColParam )->pMapB[ rColor.GetBlue() ] );
1933 
1934 }
1935 
1936 // ------------------------------------------------------------------------
1937 
1938 BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1939 {
1940     const ImplBmpAdjustParam*   p = (const ImplBmpAdjustParam*) pBmpParam;
1941     BitmapEx                    aRet( rBmpEx );
1942 
1943     aRet.Adjust( p->nLuminancePercent, p->nContrastPercent,
1944                  p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent,
1945                  p->fGamma, p->bInvert );
1946 
1947     return aRet;
1948 }
1949 
1950 // ------------------------------------------------------------------------
1951 
1952 Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam )
1953 {
1954     sal_uInt8 cLum = rColor.GetLuminance();
1955 
1956     if( MTF_CONVERSION_1BIT_THRESHOLD == ( (const ImplColConvertParam*) pColParam )->eConversion )
1957         cLum = ( cLum < 128 ) ? 0 : 255;
1958 
1959     return Color( rColor.GetTransparency(), cLum, cLum, cLum );
1960 }
1961 
1962 // ------------------------------------------------------------------------
1963 
1964 BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1965 {
1966     BitmapEx aRet( rBmpEx );
1967 
1968     aRet.Convert( ( (const ImplBmpConvertParam*) pBmpParam )->eConversion );
1969 
1970     return aRet;
1971 }
1972 
1973 // ------------------------------------------------------------------------
1974 
1975 Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam )
1976 {
1977     return( ( (const ImplColMonoParam*) pColParam )->aColor );
1978 }
1979 
1980 // ------------------------------------------------------------------------
1981 
1982 BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1983 {
1984     BitmapPalette aPal( 3 );
1985 
1986     aPal[ 0 ] = Color( COL_BLACK );
1987     aPal[ 1 ] = Color( COL_WHITE );
1988     aPal[ 2 ] = ( (const ImplBmpMonoParam*) pBmpParam )->aColor;
1989 
1990     Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal );
1991     aBmp.Erase( ( (const ImplBmpMonoParam*) pBmpParam )->aColor );
1992 
1993     if( rBmpEx.IsAlpha() )
1994         return BitmapEx( aBmp, rBmpEx.GetAlpha() );
1995     else if( rBmpEx.IsTransparent() )
1996         return BitmapEx( aBmp, rBmpEx.GetMask() );
1997     else
1998         return aBmp;
1999 }
2000 
2001 // ------------------------------------------------------------------------
2002 
2003 Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam )
2004 {
2005     const sal_uLong nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue();
2006 
2007     for( sal_uLong i = 0; i < ( (const ImplColReplaceParam*) pColParam )->nCount; i++ )
2008     {
2009         if( ( ( (const ImplColReplaceParam*) pColParam )->pMinR[ i ] <= nR ) &&
2010             ( ( (const ImplColReplaceParam*) pColParam )->pMaxR[ i ] >= nR ) &&
2011             ( ( (const ImplColReplaceParam*) pColParam )->pMinG[ i ] <= nG ) &&
2012             ( ( (const ImplColReplaceParam*) pColParam )->pMaxG[ i ] >= nG ) &&
2013             ( ( (const ImplColReplaceParam*) pColParam )->pMinB[ i ] <= nB ) &&
2014             ( ( (const ImplColReplaceParam*) pColParam )->pMaxB[ i ] >= nB ) )
2015         {
2016             return( ( (const ImplColReplaceParam*) pColParam )->pDstCols[ i ] );
2017         }
2018     }
2019 
2020     return rColor;
2021 }
2022 
2023 // ------------------------------------------------------------------------
2024 
2025 BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
2026 {
2027     const ImplBmpReplaceParam*  p = (const ImplBmpReplaceParam*) pBmpParam;
2028     BitmapEx                    aRet( rBmpEx );
2029 
2030     aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount, p->pTols );
2031 
2032     return aRet;
2033 }
2034 
2035 // ------------------------------------------------------------------------
2036 
2037 void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam,
2038                                       BmpExchangeFnc pFncBmp, const void* pBmpParam )
2039 {
2040     GDIMetaFile aMtf;
2041 
2042     aMtf.aPrefSize = aPrefSize;
2043     aMtf.aPrefMapMode = aPrefMapMode;
2044 
2045     for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
2046     {
2047         const sal_uInt16 nType = pAction->GetType();
2048 
2049         switch( nType )
2050         {
2051             case( META_PIXEL_ACTION ):
2052             {
2053                 MetaPixelAction* pAct = (MetaPixelAction*) pAction;
2054                 aMtf.Insert( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
2055             }
2056             break;
2057 
2058             case( META_LINECOLOR_ACTION ):
2059             {
2060                 MetaLineColorAction* pAct = (MetaLineColorAction*) pAction;
2061 
2062                 if( !pAct->IsSetting() )
2063                     pAct->Duplicate();
2064                 else
2065                     pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2066 
2067                 aMtf.Insert( pAct, LIST_APPEND );
2068             }
2069             break;
2070 
2071             case( META_FILLCOLOR_ACTION ):
2072             {
2073                 MetaFillColorAction* pAct = (MetaFillColorAction*) pAction;
2074 
2075                 if( !pAct->IsSetting() )
2076                     pAct->Duplicate();
2077                 else
2078                     pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2079 
2080                 aMtf.Insert( pAct, LIST_APPEND );
2081             }
2082             break;
2083 
2084             case( META_TEXTCOLOR_ACTION ):
2085             {
2086                 MetaTextColorAction* pAct = (MetaTextColorAction*) pAction;
2087                 aMtf.Insert( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
2088             }
2089             break;
2090 
2091             case( META_TEXTFILLCOLOR_ACTION ):
2092             {
2093                 MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction;
2094 
2095                 if( !pAct->IsSetting() )
2096                     pAct->Duplicate();
2097                 else
2098                     pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2099 
2100                 aMtf.Insert( pAct, LIST_APPEND );
2101             }
2102             break;
2103 
2104             case( META_TEXTLINECOLOR_ACTION ):
2105             {
2106                 MetaTextLineColorAction* pAct = (MetaTextLineColorAction*) pAction;
2107 
2108                 if( !pAct->IsSetting() )
2109                     pAct->Duplicate();
2110                 else
2111                     pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2112 
2113                 aMtf.Insert( pAct, LIST_APPEND );
2114             }
2115             break;
2116 
2117             case( META_OVERLINECOLOR_ACTION ):
2118             {
2119                 MetaOverlineColorAction* pAct = (MetaOverlineColorAction*) pAction;
2120 
2121                 if( !pAct->IsSetting() )
2122                     pAct->Duplicate();
2123                 else
2124                     pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2125 
2126                 aMtf.Insert( pAct, LIST_APPEND );
2127             }
2128             break;
2129 
2130             case( META_FONT_ACTION ):
2131             {
2132                 MetaFontAction* pAct = (MetaFontAction*) pAction;
2133                 Font            aFont( pAct->GetFont() );
2134 
2135                 aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) );
2136                 aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) );
2137                 aMtf.Insert( new MetaFontAction( aFont ), LIST_APPEND );
2138             }
2139             break;
2140 
2141             case( META_WALLPAPER_ACTION ):
2142             {
2143                 MetaWallpaperAction*    pAct = (MetaWallpaperAction*) pAction;
2144                 Wallpaper               aWall( pAct->GetWallpaper() );
2145                 const Rectangle&        rRect = pAct->GetRect();
2146 
2147                 aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) );
2148 
2149                 if( aWall.IsBitmap() )
2150                     aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) );
2151 
2152                 if( aWall.IsGradient() )
2153                 {
2154                     Gradient aGradient( aWall.GetGradient() );
2155 
2156                     aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2157                     aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2158                     aWall.SetGradient( aGradient );
2159                 }
2160 
2161                 aMtf.Insert( new MetaWallpaperAction( rRect, aWall ), LIST_APPEND );
2162             }
2163             break;
2164 
2165             case( META_BMP_ACTION ):
2166             case( META_BMPEX_ACTION ):
2167             case( META_MASK_ACTION ):
2168             {
2169                 DBG_ERROR( "Don't use bitmap actions of this type in metafiles!" );
2170             }
2171             break;
2172 
2173             case( META_BMPSCALE_ACTION ):
2174             {
2175                 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
2176                 aMtf.Insert( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(),
2177                                                      pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
2178                                                      LIST_APPEND );
2179             }
2180             break;
2181 
2182             case( META_BMPSCALEPART_ACTION ):
2183             {
2184                 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
2185                 aMtf.Insert( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2186                                                          pAct->GetSrcPoint(), pAct->GetSrcSize(),
2187                                                          pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
2188                                                          LIST_APPEND );
2189             }
2190             break;
2191 
2192             case( META_BMPEXSCALE_ACTION ):
2193             {
2194                 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
2195                 aMtf.Insert( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(),
2196                                                        pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
2197                                                        LIST_APPEND );
2198             }
2199             break;
2200 
2201             case( META_BMPEXSCALEPART_ACTION ):
2202             {
2203                 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
2204                 aMtf.Insert( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2205                                                            pAct->GetSrcPoint(), pAct->GetSrcSize(),
2206                                                            pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
2207                                                            LIST_APPEND );
2208             }
2209             break;
2210 
2211             case( META_MASKSCALE_ACTION ):
2212             {
2213                 MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
2214                 aMtf.Insert( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(),
2215                                                       pAct->GetBitmap(),
2216                                                       pFncCol( pAct->GetColor(), pColParam ) ),
2217                                                       LIST_APPEND );
2218             }
2219             break;
2220 
2221             case( META_MASKSCALEPART_ACTION ):
2222             {
2223                 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
2224                 aMtf.Insert( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2225                                                           pAct->GetSrcPoint(), pAct->GetSrcSize(),
2226                                                           pAct->GetBitmap(),
2227                                                           pFncCol( pAct->GetColor(), pColParam ) ),
2228                                                           LIST_APPEND );
2229             }
2230             break;
2231 
2232             case( META_GRADIENT_ACTION ):
2233             {
2234                 MetaGradientAction* pAct = (MetaGradientAction*) pAction;
2235                 Gradient            aGradient( pAct->GetGradient() );
2236 
2237                 aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2238                 aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2239                 aMtf.Insert( new MetaGradientAction( pAct->GetRect(), aGradient ), LIST_APPEND );
2240             }
2241             break;
2242 
2243             case( META_GRADIENTEX_ACTION ):
2244             {
2245                 MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
2246                 Gradient              aGradient( pAct->GetGradient() );
2247 
2248                 aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2249                 aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2250                 aMtf.Insert( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ), LIST_APPEND );
2251             }
2252             break;
2253 
2254             case( META_HATCH_ACTION ):
2255             {
2256                 MetaHatchAction*    pAct = (MetaHatchAction*) pAction;
2257                 Hatch               aHatch( pAct->GetHatch() );
2258 
2259                 aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) );
2260                 aMtf.Insert( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ), LIST_APPEND );
2261             }
2262             break;
2263 
2264             case( META_FLOATTRANSPARENT_ACTION ):
2265             {
2266                 MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
2267                 GDIMetaFile                 aTransMtf( pAct->GetGDIMetaFile() );
2268 
2269                 aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2270                 aMtf.Insert( new MetaFloatTransparentAction( aTransMtf,
2271                                                              pAct->GetPoint(), pAct->GetSize(),
2272                                                              pAct->GetGradient() ),
2273                                                              LIST_APPEND );
2274             }
2275             break;
2276 
2277             case( META_EPS_ACTION ):
2278             {
2279                 MetaEPSAction*  pAct = (MetaEPSAction*) pAction;
2280                 GDIMetaFile     aSubst( pAct->GetSubstitute() );
2281 
2282                 aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2283                 aMtf.Insert( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(),
2284                                                 pAct->GetLink(), aSubst ),
2285                                                 LIST_APPEND );
2286             }
2287             break;
2288 
2289             case( META_RENDERGRAPHIC_ACTION ):
2290             {
2291                 OSL_TRACE( "ExchangeColors not supported for RenderGraphic MetaActions yet" );
2292 
2293                 pAction->Duplicate();
2294                 aMtf.Insert( pAction, LIST_APPEND );
2295             }
2296             break;
2297 
2298             default:
2299             {
2300                 pAction->Duplicate();
2301                 aMtf.Insert( pAction, LIST_APPEND );
2302             }
2303             break;
2304         }
2305     }
2306 
2307     *this = aMtf;
2308 }
2309 
2310 // ------------------------------------------------------------------------
2311 
2312 void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent,
2313                           short nChannelRPercent, short nChannelGPercent,
2314                           short nChannelBPercent, double fGamma, sal_Bool bInvert )
2315 {
2316     // nothing to do? => return quickly
2317     if( nLuminancePercent || nContrastPercent ||
2318         nChannelRPercent || nChannelGPercent || nChannelBPercent ||
2319         ( fGamma != 1.0 ) || bInvert )
2320     {
2321         double              fM, fROff, fGOff, fBOff, fOff;
2322         ImplColAdjustParam  aColParam;
2323         ImplBmpAdjustParam  aBmpParam;
2324 
2325         aColParam.pMapR = new sal_uInt8[ 256 ];
2326         aColParam.pMapG = new sal_uInt8[ 256 ];
2327         aColParam.pMapB = new sal_uInt8[ 256 ];
2328 
2329         // calculate slope
2330         if( nContrastPercent >= 0 )
2331             fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2332         else
2333             fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2334 
2335         // total offset = luminance offset + contrast offset
2336         fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2337 
2338         // channel offset = channel offset  + total offset
2339         fROff = nChannelRPercent * 2.55 + fOff;
2340         fGOff = nChannelGPercent * 2.55 + fOff;
2341         fBOff = nChannelBPercent * 2.55 + fOff;
2342 
2343         // calculate gamma value
2344         fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2345         const sal_Bool bGamma = ( fGamma != 1.0 );
2346 
2347         // create mapping table
2348         for( long nX = 0L; nX < 256L; nX++ )
2349         {
2350             aColParam.pMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2351             aColParam.pMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2352             aColParam.pMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2353 
2354             if( bGamma )
2355             {
2356                 aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma );
2357                 aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma );
2358                 aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma );
2359             }
2360 
2361             if( bInvert )
2362             {
2363                 aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ];
2364                 aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ];
2365                 aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ];
2366             }
2367         }
2368 
2369         aBmpParam.nLuminancePercent = nLuminancePercent;
2370         aBmpParam.nContrastPercent = nContrastPercent;
2371         aBmpParam.nChannelRPercent = nChannelRPercent;
2372         aBmpParam.nChannelGPercent = nChannelGPercent;
2373         aBmpParam.nChannelBPercent = nChannelBPercent;
2374         aBmpParam.fGamma = fGamma;
2375         aBmpParam.bInvert = bInvert;
2376 
2377         // do color adjustment
2378         ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam );
2379 
2380         delete[] aColParam.pMapR;
2381         delete[] aColParam.pMapG;
2382         delete[] aColParam.pMapB;
2383     }
2384 }
2385 
2386 // ------------------------------------------------------------------------
2387 
2388 void GDIMetaFile::Convert( MtfConversion eConversion )
2389 {
2390     // nothing to do? => return quickly
2391     if( eConversion != MTF_CONVERSION_NONE )
2392     {
2393         ImplColConvertParam aColParam;
2394         ImplBmpConvertParam aBmpParam;
2395 
2396         aColParam.eConversion = eConversion;
2397         aBmpParam.eConversion = ( MTF_CONVERSION_1BIT_THRESHOLD == eConversion ) ? BMP_CONVERSION_1BIT_THRESHOLD : BMP_CONVERSION_8BIT_GREYS;
2398 
2399         ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam );
2400     }
2401 }
2402 
2403 // ------------------------------------------------------------------------
2404 
2405 void GDIMetaFile::ReplaceColors( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
2406 {
2407     ReplaceColors( &rSearchColor, &rReplaceColor, 1, &nTol );
2408 }
2409 
2410 // ------------------------------------------------------------------------
2411 
2412 void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, sal_uLong* pTols )
2413 {
2414     ImplColReplaceParam aColParam;
2415     ImplBmpReplaceParam aBmpParam;
2416 
2417     aColParam.pMinR = new sal_uLong[ nColorCount ];
2418     aColParam.pMaxR = new sal_uLong[ nColorCount ];
2419     aColParam.pMinG = new sal_uLong[ nColorCount ];
2420     aColParam.pMaxG = new sal_uLong[ nColorCount ];
2421     aColParam.pMinB = new sal_uLong[ nColorCount ];
2422     aColParam.pMaxB = new sal_uLong[ nColorCount ];
2423 
2424     for( sal_uLong i = 0; i < nColorCount; i++ )
2425     {
2426         const long  nTol = pTols ? ( pTols[ i ] * 255 ) / 100 : 0;
2427         long        nVal;
2428 
2429         nVal = pSearchColors[ i ].GetRed();
2430         aColParam.pMinR[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2431         aColParam.pMaxR[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2432 
2433         nVal = pSearchColors[ i ].GetGreen();
2434         aColParam.pMinG[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2435         aColParam.pMaxG[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2436 
2437         nVal = pSearchColors[ i ].GetBlue();
2438         aColParam.pMinB[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2439         aColParam.pMaxB[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2440     }
2441 
2442     aColParam.pDstCols = pReplaceColors;
2443     aColParam.nCount = nColorCount;
2444 
2445     aBmpParam.pSrcCols = pSearchColors;
2446     aBmpParam.pDstCols = pReplaceColors;
2447     aBmpParam.nCount = nColorCount;
2448     aBmpParam.pTols = pTols;
2449 
2450     ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam );
2451 
2452     delete[] aColParam.pMinR;
2453     delete[] aColParam.pMaxR;
2454     delete[] aColParam.pMinG;
2455     delete[] aColParam.pMaxG;
2456     delete[] aColParam.pMinB;
2457     delete[] aColParam.pMaxB;
2458 };
2459 
2460 // ------------------------------------------------------------------------
2461 
2462 GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const
2463 {
2464     GDIMetaFile aRet( *this );
2465 
2466     ImplColMonoParam    aColParam;
2467     ImplBmpMonoParam    aBmpParam;
2468 
2469     aColParam.aColor = rColor;
2470     aBmpParam.aColor = rColor;
2471 
2472     aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam );
2473 
2474     return aRet;
2475 }
2476 
2477 // ------------------------------------------------------------------------
2478 
2479 sal_uLong GDIMetaFile::GetChecksum() const
2480 {
2481     GDIMetaFile         aMtf;
2482     SvMemoryStream      aMemStm( 65535, 65535 );
2483     ImplMetaWriteData   aWriteData;
2484     SVBT16              aBT16;
2485     SVBT32              aBT32;
2486     sal_uLong               nCrc = 0;
2487 
2488     aWriteData.meActualCharSet = aMemStm.GetStreamCharSet();
2489 
2490     for( sal_uLong i = 0, nObjCount = GetActionCount(); i < nObjCount; i++ )
2491     {
2492         MetaAction* pAction = GetAction( i );
2493 
2494         switch( pAction->GetType() )
2495         {
2496             case( META_BMP_ACTION ):
2497             {
2498                 MetaBmpAction* pAct = (MetaBmpAction*) pAction;
2499 
2500                 ShortToSVBT16( pAct->GetType(), aBT16 );
2501                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2502 
2503                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2504                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2505 
2506                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2507                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2508 
2509                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2510                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2511             }
2512             break;
2513 
2514             case( META_BMPSCALE_ACTION ):
2515             {
2516                 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
2517 
2518                 ShortToSVBT16( pAct->GetType(), aBT16 );
2519                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2520 
2521                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2522                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2523 
2524                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2525                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2526 
2527                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2528                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2529 
2530                 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2531                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2532 
2533                 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2534                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2535             }
2536             break;
2537 
2538             case( META_BMPSCALEPART_ACTION ):
2539             {
2540                 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
2541 
2542                 ShortToSVBT16( pAct->GetType(), aBT16 );
2543                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2544 
2545                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2546                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2547 
2548                 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2549                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2550 
2551                 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2552                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2553 
2554                 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2555                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2556 
2557                 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2558                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2559 
2560                 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2561                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2562 
2563                 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2564                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2565 
2566                 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2567                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2568 
2569                 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2570                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2571             }
2572             break;
2573 
2574             case( META_BMPEX_ACTION ):
2575             {
2576                 MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
2577 
2578                 ShortToSVBT16( pAct->GetType(), aBT16 );
2579                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2580 
2581                 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2582                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2583 
2584                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2585                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2586 
2587                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2588                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2589             }
2590             break;
2591 
2592             case( META_BMPEXSCALE_ACTION ):
2593             {
2594                 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
2595 
2596                 ShortToSVBT16( pAct->GetType(), aBT16 );
2597                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2598 
2599                 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2600                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2601 
2602                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2603                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2604 
2605                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2606                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2607 
2608                 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2609                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2610 
2611                 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2612                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2613             }
2614             break;
2615 
2616             case( META_BMPEXSCALEPART_ACTION ):
2617             {
2618                 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
2619 
2620                 ShortToSVBT16( pAct->GetType(), aBT16 );
2621                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2622 
2623                 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2624                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2625 
2626                 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2627                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2628 
2629                 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2630                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2631 
2632                 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2633                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2634 
2635                 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2636                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2637 
2638                 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2639                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2640 
2641                 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2642                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2643 
2644                 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2645                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2646 
2647                 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2648                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2649             }
2650             break;
2651 
2652             case( META_MASK_ACTION ):
2653             {
2654                 MetaMaskAction* pAct = (MetaMaskAction*) pAction;
2655 
2656                 ShortToSVBT16( pAct->GetType(), aBT16 );
2657                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2658 
2659                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2660                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2661 
2662                 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2663                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2664 
2665                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2666                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2667 
2668                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2669                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2670             }
2671             break;
2672 
2673             case( META_MASKSCALE_ACTION ):
2674             {
2675                 MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
2676 
2677                 ShortToSVBT16( pAct->GetType(), aBT16 );
2678                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2679 
2680                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2681                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2682 
2683                 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2684                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2685 
2686                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2687                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2688 
2689                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2690                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2691 
2692                 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2693                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2694 
2695                 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2696                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2697             }
2698             break;
2699 
2700             case( META_MASKSCALEPART_ACTION ):
2701             {
2702                 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
2703 
2704                 ShortToSVBT16( pAct->GetType(), aBT16 );
2705                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2706 
2707                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2708                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2709 
2710                 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2711                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2712 
2713                 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2714                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2715 
2716                 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2717                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2718 
2719                 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2720                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2721 
2722                 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2723                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2724 
2725                 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2726                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2727 
2728                 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2729                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2730 
2731                 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2732                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2733 
2734                 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2735                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2736             }
2737             break;
2738 
2739             case META_EPS_ACTION :
2740             {
2741                 MetaEPSAction* pAct = (MetaEPSAction*) pAction;
2742                 nCrc = rtl_crc32( nCrc, pAct->GetLink().GetData(), pAct->GetLink().GetDataSize() );
2743             }
2744             break;
2745 
2746             case( META_RENDERGRAPHIC_ACTION ):
2747             {
2748                 MetaRenderGraphicAction*    pAct = (MetaRenderGraphicAction*) pAction;
2749                 const ::vcl::RenderGraphic& rRenderGraphic = pAct->GetRenderGraphic();
2750 
2751                 ShortToSVBT16( pAct->GetType(), aBT16 );
2752                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2753 
2754                 nCrc = rtl_crc32( nCrc, rRenderGraphic.GetGraphicData().get(), rRenderGraphic.GetGraphicDataLength() );
2755 
2756                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2757                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2758 
2759                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2760                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2761 
2762                 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2763                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2764 
2765                 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2766                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2767             }
2768             break;
2769 
2770             default:
2771             {
2772                 pAction->Write( aMemStm, &aWriteData );
2773                 nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() );
2774                 aMemStm.Seek( 0 );
2775             }
2776             break;
2777         }
2778     }
2779 
2780     return nCrc;
2781 }
2782 
2783 // ------------------------------------------------------------------------
2784 
2785 sal_uLong GDIMetaFile::GetSizeBytes() const
2786 {
2787     sal_uLong nSizeBytes = 0;
2788 
2789     for( sal_uLong i = 0, nObjCount = GetActionCount(); i < nObjCount; ++i )
2790     {
2791         MetaAction* pAction = GetAction( i );
2792 
2793         // default action size is set to 32 (=> not the exact value)
2794         nSizeBytes += 32;
2795 
2796         // add sizes for large action content
2797         switch( pAction->GetType() )
2798         {
2799             case( META_BMP_ACTION ): nSizeBytes += ( (MetaBmpAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2800             case( META_BMPSCALE_ACTION ): nSizeBytes += ( (MetaBmpScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2801             case( META_BMPSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2802 
2803             case( META_BMPEX_ACTION ): nSizeBytes += ( (MetaBmpExAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2804             case( META_BMPEXSCALE_ACTION ): nSizeBytes += ( (MetaBmpExScaleAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2805             case( META_BMPEXSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpExScalePartAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2806 
2807             case( META_MASK_ACTION ): nSizeBytes += ( (MetaMaskAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2808             case( META_MASKSCALE_ACTION ): nSizeBytes += ( (MetaMaskScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2809             case( META_MASKSCALEPART_ACTION ): nSizeBytes += ( (MetaMaskScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2810 
2811             case( META_POLYLINE_ACTION ): nSizeBytes += ( ( (MetaPolyLineAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
2812             case( META_POLYGON_ACTION ): nSizeBytes += ( ( (MetaPolygonAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
2813             case( META_POLYPOLYGON_ACTION ):
2814             {
2815                 const PolyPolygon& rPolyPoly = ( (MetaPolyPolygonAction*) pAction )->GetPolyPolygon();
2816 
2817                 for( sal_uInt16 n = 0; n < rPolyPoly.Count(); ++n )
2818                     nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) );
2819             }
2820             break;
2821 
2822             case( META_TEXT_ACTION ): nSizeBytes += ( ( (MetaTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2823             case( META_STRETCHTEXT_ACTION ): nSizeBytes += ( ( (MetaStretchTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2824             case( META_TEXTRECT_ACTION ): nSizeBytes += ( ( (MetaTextRectAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2825             case( META_TEXTARRAY_ACTION ):
2826             {
2827                 MetaTextArrayAction* pTextArrayAction = (MetaTextArrayAction*) pAction;
2828 
2829                 nSizeBytes += ( pTextArrayAction->GetText().Len() * sizeof( sal_Unicode ) );
2830 
2831                 if( pTextArrayAction->GetDXArray() )
2832                     nSizeBytes += ( pTextArrayAction->GetLen() << 2 );
2833             }
2834             break;
2835 
2836             case( META_RENDERGRAPHIC_ACTION ): nSizeBytes += ( ( (MetaRenderGraphicAction*) pAction )->GetRenderGraphic() ).GetGraphicDataLength(); break;
2837         }
2838     }
2839 
2840     return( nSizeBytes );
2841 }
2842 
2843 // ------------------------------------------------------------------------
2844 
2845 SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile )
2846 {
2847     if( !rIStm.GetError() )
2848     {
2849         char    aId[ 7 ];
2850         sal_uLong   nStmPos = rIStm.Tell();
2851         sal_uInt16  nOldFormat = rIStm.GetNumberFormatInt();
2852 
2853         rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
2854 
2855         aId[ 0 ] = 0;
2856         aId[ 6 ] = 0;
2857         rIStm.Read( aId, 6 );
2858 
2859         if ( !strcmp( aId, "VCLMTF" ) )
2860         {
2861             // new format
2862             VersionCompat*  pCompat;
2863             MetaAction*     pAction;
2864             sal_uInt32      nStmCompressMode = 0;
2865             sal_uInt32      nCount = 0;
2866             sal_uInt8       bRenderGraphicReplacements = 0;
2867 
2868             pCompat = new VersionCompat( rIStm, STREAM_READ );
2869             {
2870                 // version 1
2871                 rIStm >> nStmCompressMode;
2872                 rIStm >> rGDIMetaFile.aPrefMapMode;
2873                 rIStm >> rGDIMetaFile.aPrefSize;
2874                 rIStm >> nCount;
2875 
2876                 if( pCompat->GetVersion() >= 2 )
2877                 {
2878                     // version 2
2879                     // =========
2880                     // contains an additional flag to indicate that RenderGraphic
2881                     // actions are immediately followed by a replacement image, that
2882                     // needs to be skipped in case the flag is set (KA 01/2011)
2883 
2884                     rIStm >> bRenderGraphicReplacements;
2885                 }
2886             }
2887             delete pCompat;
2888 
2889             ImplMetaReadData aReadData;
2890             aReadData.meActualCharSet = rIStm.GetStreamCharSet();
2891 
2892             for( sal_uInt32 nAction = 0UL; ( nAction < nCount ) && !rIStm.IsEof(); ++nAction )
2893             {
2894                 pAction = MetaAction::ReadMetaAction( rIStm, &aReadData );
2895 
2896                 if( pAction )
2897                 {
2898                     rGDIMetaFile.AddAction( pAction );
2899 
2900                     // if the MetaFile was written in RenderGraphics replacement mode
2901                     // and we just read a RenderGraphic action, skip the following
2902                     // META_BMPEXSCALE_ACTION, since this is the replacement image,
2903                     // just needed for old implementations; don't forget to increment
2904                     // the action read counter! (KA 01/2011)
2905                     if( bRenderGraphicReplacements &&
2906                         ( META_RENDERGRAPHIC_ACTION == pAction->GetType() ) &&
2907                         ( ++nAction < nCount ) && !rIStm.IsEof() )
2908                     {
2909                         sal_uInt16 nFollowingType;
2910 
2911                         // dummy read of the next following META_BMPEXSCALE_ACTION
2912                         // RenderGraphic replacement action (KA 01/2011)
2913                         rIStm >> nFollowingType;
2914                         delete ( new VersionCompat( rIStm, STREAM_READ ) );
2915 
2916                         OSL_ENSURE( META_BMPEXSCALE_ACTION == nFollowingType, \
2917 "META_RENDERGRAPHIC_ACTION read in RenderGraphic replacement mode \
2918 without following META_BMPEXSCALE_ACTION replacement" );
2919                     }
2920                 }
2921             }
2922         }
2923         else
2924         {
2925             // to avoid possible compiler optimizations => new/delete
2926             rIStm.Seek( nStmPos );
2927             delete( new SVMConverter( rIStm, rGDIMetaFile, CONVERT_FROM_SVM1 ) );
2928         }
2929 
2930         // check for errors
2931         if( rIStm.GetError() )
2932         {
2933             rGDIMetaFile.Clear();
2934             rIStm.Seek( nStmPos );
2935         }
2936 
2937         rIStm.SetNumberFormatInt( nOldFormat );
2938     }
2939 
2940     return rIStm;
2941 }
2942 
2943 // ------------------------------------------------------------------------
2944 
2945 SvStream& operator<<( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile )
2946 {
2947     if( !rOStm.GetError() )
2948     {
2949         static const char*  pEnableSVM1 = getenv( "SAL_ENABLE_SVM1" );
2950         static const bool   bNoSVM1 = (NULL == pEnableSVM1 ) || ( '0' == *pEnableSVM1 );
2951 
2952         if( bNoSVM1 || rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50  )
2953         {
2954             const_cast< GDIMetaFile& >( rGDIMetaFile ).Write( rOStm );
2955         }
2956         else
2957         {
2958             delete( new SVMConverter( rOStm, const_cast< GDIMetaFile& >( rGDIMetaFile ), CONVERT_TO_SVM1 ) );
2959         }
2960 
2961 #ifdef DEBUG
2962         if( !bNoSVM1 && rOStm.GetVersion() < SOFFICE_FILEFORMAT_50 )
2963         {
2964 OSL_TRACE( \
2965 "GDIMetaFile would normally be written in old SVM1 format by this call. \
2966 The current implementation always writes in VCLMTF format. \
2967 Please set environment variable SAL_ENABLE_SVM1 to '1' to reenable old behavior" );
2968         }
2969 #endif // DEBUG
2970     }
2971 
2972     return rOStm;
2973 }
2974 
2975 // ------------------------------------------------------------------------
2976 
2977 SvStream& GDIMetaFile::Read( SvStream& rIStm )
2978 {
2979     Clear();
2980     rIStm >> *this;
2981 
2982     return rIStm;
2983 }
2984 
2985 // ------------------------------------------------------------------------
2986 
2987 SvStream& GDIMetaFile::Write( SvStream& rOStm, GDIMetaFileWriteFlags nWriteFlags )
2988 {
2989     VersionCompat*  pCompat;
2990     const sal_uInt32    nStmCompressMode = rOStm.GetCompressMode();
2991     sal_uInt16          nOldFormat = rOStm.GetNumberFormatInt();
2992     const               sal_uInt8 bRenderGraphicReplacements =
2993                                 ( ( ( GDIMETAFILE_WRITE_REPLACEMENT_RENDERGRAPHIC & nWriteFlags ) != 0 ) ? 1 : 0 );
2994 
2995     // With the introduction of the META_RENDERGRAPHIC_ACTION, it is neccessary
2996     // to provide some kind of document backward compatibility:
2997     //
2998     //  If the flag GDIMETAFILE_WRITE_REPLACEMENT_RENDERGRAPHIC is set in
2999     //  parameter nWriteFlags, each META_RENDERGRAPHIC_ACTION is followed by
3000     //  an additional META_BMPEXSCALE_ACTION, that contains a replacement
3001     //  image for the new RenderGraphic action.
3002     //
3003     //  Old implementations, not knowing anything about META_RENDERGRAPHIC_ACTION,
3004     //  will skip this new action and read the META_BMPEXSCALE_ACTION instead
3005     //
3006     //  Since the current implementation is able to handle the new action, the
3007     //  then following image replacement action needs to be skipped by this
3008     //  implementation, if the metafile was written in the RenderGraphic
3009     //  replacement mode.
3010     //
3011     //  To be able to detect this compatibility mode, the header needs to
3012     //  be extended by a corresponding flag, resulting in version 2 of
3013     //  the header. The surrounding VersionCompat of the header
3014     //  allows to add such new data without any problems (KA 01/2011)
3015 
3016     rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
3017     rOStm.Write( "VCLMTF", 6 );
3018 
3019     pCompat = new VersionCompat( rOStm, STREAM_WRITE, 2 );
3020 
3021     {
3022         // version 1
3023         sal_uInt32 nActionCount = 0;
3024 
3025         // calculate correct action count and watch for
3026         // additional RenderGraphic replacement actions, if the
3027         // GDIMETAFILE_WRITE_REPLACEMENT_RENDERGRAPHIC is set
3028         // and META_RENDERGRAPHIC_ACTION are encountered (KA 01/2011)
3029         for( MetaAction* pAct = static_cast< MetaAction* >( First() ); pAct; pAct = static_cast< MetaAction* >( Next() ) )
3030         {
3031             nActionCount += ( bRenderGraphicReplacements && ( META_RENDERGRAPHIC_ACTION == pAct->GetType() ) ? 2 : 1 );
3032         }
3033 
3034         rOStm << nStmCompressMode << aPrefMapMode << aPrefSize << nActionCount;
3035 
3036         {
3037             // version 2
3038             // =========
3039             // since version 2, a GDIMETAFILE_WRITE_REPLACEMENT_RENDERGRAPHIC flag
3040             // is written, to indicate that each META_BMPEXSCALE_ACTION following
3041             // a META_RENDERGRAPHIC_ACTION needs to be skipped, in case the flag is
3042             // set (KA 01/2011)
3043             rOStm << bRenderGraphicReplacements;
3044         }
3045     }
3046 
3047     delete pCompat;
3048 
3049     ImplMetaWriteData aWriteData;
3050 
3051     aWriteData.meActualCharSet = rOStm.GetStreamCharSet();
3052     aWriteData.mnWriteFlags = nWriteFlags;
3053 
3054     for( MetaAction* pAct = static_cast< MetaAction* >( First() ); pAct; pAct = static_cast< MetaAction* >( Next() ) )
3055     {
3056         pAct->Write( rOStm, &aWriteData );
3057 
3058         // write the RenderGraphic replacement image, if the
3059         // GDIMETAFILE_WRITE_REPLACEMENT_RENDERGRAPHIC flag is set
3060         // and if a META_RENDERGRAPHIC_ACTION is encountered (KA 01/2011)
3061         if( bRenderGraphicReplacements && ( META_RENDERGRAPHIC_ACTION == pAct->GetType() ) )
3062         {
3063             MetaRenderGraphicAction*    pRenderAction = static_cast< MetaRenderGraphicAction* >( pAct );
3064             MetaBmpExScaleAction*       pBmpExScaleAction = new MetaBmpExScaleAction(
3065                                             pRenderAction->GetPoint(), pRenderAction->GetSize(),
3066                                             pRenderAction->GetRenderGraphic().GetReplacement() );
3067 
3068             pBmpExScaleAction->Write( rOStm, &aWriteData );
3069             pBmpExScaleAction->Delete();
3070         }
3071     }
3072 
3073     rOStm.SetNumberFormatInt( nOldFormat );
3074 
3075     return rOStm;
3076 }
3077 
3078 // ------------------------------------------------------------------------
3079 
3080 sal_Bool GDIMetaFile::CreateThumbnail( sal_uInt32 nMaximumExtent,
3081                                     BitmapEx& rBmpEx,
3082                                     const BitmapEx* pOverlay,
3083                                     const Rectangle* pOverlayRect ) const
3084 {
3085     // the implementation is provided by KA
3086 
3087     // initialization seems to be complicated but is used to avoid rounding errors
3088     VirtualDevice   aVDev;
3089     const Point     aNullPt;
3090     const Point     aTLPix( aVDev.LogicToPixel( aNullPt, GetPrefMapMode() ) );
3091     const Point     aBRPix( aVDev.LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) );
3092     Size            aDrawSize( aVDev.LogicToPixel( GetPrefSize(), GetPrefMapMode() ) );
3093     Size            aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
3094     Point           aPosPix;
3095 
3096     if ( !rBmpEx.IsEmpty() )
3097         rBmpEx.SetEmpty();
3098 
3099     // determine size that has the same aspect ratio as image size and
3100     // fits into the rectangle determined by nMaximumExtent
3101     if ( aSizePix.Width() && aSizePix.Height()
3102       && ( sal::static_int_cast< unsigned long >(aSizePix.Width()) >
3103                nMaximumExtent ||
3104            sal::static_int_cast< unsigned long >(aSizePix.Height()) >
3105                nMaximumExtent ) )
3106     {
3107         const Size  aOldSizePix( aSizePix );
3108         double      fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height();
3109 
3110         if ( fWH <= 1.0 )
3111         {
3112             aSizePix.Width() = FRound( nMaximumExtent * fWH );
3113             aSizePix.Height() = nMaximumExtent;
3114         }
3115         else
3116         {
3117             aSizePix.Width() = nMaximumExtent;
3118             aSizePix.Height() = FRound(  nMaximumExtent / fWH );
3119         }
3120 
3121         aDrawSize.Width() = FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() );
3122         aDrawSize.Height() = FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() );
3123     }
3124 
3125     Size        aFullSize;
3126     Point       aBackPosPix;
3127     Rectangle   aOverlayRect;
3128 
3129     // calculate addigtional positions and sizes if an overlay image is used
3130     if (  pOverlay )
3131     {
3132         aFullSize = Size( nMaximumExtent, nMaximumExtent );
3133         aOverlayRect = Rectangle( aNullPt, aFullSize  );
3134 
3135         aOverlayRect.Intersection( pOverlayRect ? *pOverlayRect : Rectangle( aNullPt, pOverlay->GetSizePixel() ) );
3136 
3137         if ( !aOverlayRect.IsEmpty() )
3138             aBackPosPix = Point( ( nMaximumExtent - aSizePix.Width() ) >> 1, ( nMaximumExtent - aSizePix.Height() ) >> 1 );
3139         else
3140             pOverlay = NULL;
3141     }
3142     else
3143     {
3144         aFullSize = aSizePix;
3145         pOverlay = NULL;
3146     }
3147 
3148     // draw image(s) into VDev and get resulting image
3149     if ( aVDev.SetOutputSizePixel( aFullSize ) )
3150     {
3151         // draw metafile into VDev
3152         const_cast<GDIMetaFile *>(this)->WindStart();
3153         const_cast<GDIMetaFile *>(this)->Play( &aVDev, aBackPosPix, aDrawSize );
3154 
3155         // draw overlay if neccessary
3156         if ( pOverlay )
3157             aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), *pOverlay );
3158 
3159         // get paint bitmap
3160         Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
3161 
3162         // assure that we have a true color image
3163         if ( aBmp.GetBitCount() != 24 )
3164             aBmp.Convert( BMP_CONVERSION_24BIT );
3165 
3166         // create resulting mask bitmap with metafile output set to black
3167         GDIMetaFile aMonchromeMtf( GetMonochromeMtf( COL_BLACK ) );
3168         aVDev.DrawWallpaper( Rectangle( aNullPt, aSizePix ), Wallpaper( Color( COL_WHITE ) ) );
3169         aMonchromeMtf.WindStart();
3170         aMonchromeMtf.Play( &aVDev, aBackPosPix, aDrawSize );
3171 
3172         // watch for overlay mask
3173         if ( pOverlay  )
3174         {
3175             Bitmap aOverlayMergeBmp( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ) );
3176 
3177             // create ANDed resulting mask at overlay area
3178             if ( pOverlay->IsTransparent() )
3179                 aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), pOverlay->GetMask() );
3180             else
3181             {
3182                 aVDev.SetLineColor( COL_BLACK );
3183                 aVDev.SetFillColor( COL_BLACK );
3184                 aVDev.DrawRect( aOverlayRect);
3185             }
3186 
3187             aOverlayMergeBmp.CombineSimple( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ), BMP_COMBINE_AND );
3188             aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), aOverlayMergeBmp );
3189         }
3190 
3191         rBmpEx = BitmapEx( aBmp, aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
3192     }
3193 
3194     return !rBmpEx.IsEmpty();
3195 }
3196