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