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