xref: /AOO41X/main/vcl/source/gdi/gdimtf.cxx (revision e6f63103da479d1a7dee04420ba89525dac05278)
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 
ImpLabelImpLabel126             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 
ImpLabelList()139                 ImpLabelList() : List( 8, 4, 4 ) {}
140                 ImpLabelList( const ImpLabelList& rList );
141                 ~ImpLabelList();
142 
ImplInsert(ImpLabel * p)143     void        ImplInsert( ImpLabel* p ) { Insert( p, LIST_APPEND ); }
ImplRemove(sal_uLong nPos)144     ImpLabel*   ImplRemove( sal_uLong nPos ) { return (ImpLabel*) Remove( nPos ); }
ImplReplace(ImpLabel * p)145     void        ImplReplace( ImpLabel* p ) { Replace( (void*)p ); }
ImplFirst()146     ImpLabel*   ImplFirst() { return (ImpLabel*) First(); }
ImplNext()147     ImpLabel*   ImplNext() { return (ImpLabel*) Next(); }
ImplGetLabel(sal_uLong nPos) const148     ImpLabel*   ImplGetLabel( sal_uLong nPos ) const { return (ImpLabel*) GetObject( nPos ); }
149     sal_uLong       ImplGetLabelPos( const String& rLabelName );
ImplCount() const150     sal_uLong       ImplCount() const { return Count(); }
151 };
152 
153 // ------------------------------------------------------------------------
154 
ImpLabelList(const ImpLabelList & rList)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 
~ImpLabelList()164 ImpLabelList::~ImpLabelList()
165 {
166     for( ImpLabel* pLabel = ImplFirst(); pLabel; pLabel = ImplNext() )
167         delete pLabel;
168 }
169 
170 // ------------------------------------------------------------------------
171 
ImplGetLabelPos(const String & rLabelName)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 
GDIMetaFile()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 
GDIMetaFile(const GDIMetaFile & rMtf)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 
~GDIMetaFile()237 GDIMetaFile::~GDIMetaFile()
238 {
239     Clear();
240 }
241 
242 // ------------------------------------------------------------------------
243 
operator =(const GDIMetaFile & rMtf)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 
operator ==(const GDIMetaFile & rMtf) const284 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 
IsEqual(const GDIMetaFile & rMtf) const312 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 
Clear()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 
Linker(OutputDevice * pOut,sal_Bool bLink)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 
Hook()391 long GDIMetaFile::Hook()
392 {
393     return aHookHdlLink.Call( this );
394 }
395 
396 // ------------------------------------------------------------------------
397 
Record(OutputDevice * pOut)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 
Play(GDIMetaFile & rMtf,sal_uLong nPos)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 
Play(OutputDevice * pOut,sal_uLong nPos)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 
Play(OutputDevice * pOut,const Point & rPos,const Size & rSize,sal_uLong nPos)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 
Pause(sal_Bool _bPause)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 
Stop()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 
WindStart()573 void GDIMetaFile::WindStart()
574 {
575     if( !bRecord )
576         First();
577 }
578 
579 // ------------------------------------------------------------------------
580 
WindEnd()581 void GDIMetaFile::WindEnd()
582 {
583     if( !bRecord )
584         Last();
585 }
586 
587 // ------------------------------------------------------------------------
588 
Wind(sal_uLong nActionPos)589 void GDIMetaFile::Wind( sal_uLong nActionPos )
590 {
591     if( !bRecord )
592         Seek( nActionPos );
593 }
594 
595 // ------------------------------------------------------------------------
596 
WindPrev()597 void GDIMetaFile::WindPrev()
598 {
599     if( !bRecord )
600         Prev();
601 }
602 
603 // ------------------------------------------------------------------------
604 
WindNext()605 void GDIMetaFile::WindNext()
606 {
607     if( !bRecord )
608         Next();
609 }
610 
611 // ------------------------------------------------------------------------
612 
AddAction(MetaAction * pAction)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 
AddAction(MetaAction * pAction,sal_uLong nPos)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#
RemoveAction(sal_uLong nPos)640 void GDIMetaFile::RemoveAction( sal_uLong nPos )
641 {
642     Remove( nPos );
643 
644     if( pPrev )
645         pPrev->RemoveAction( nPos );
646 }
647 
648 // ------------------------------------------------------------------------
649 
CopyAction(sal_uLong nPos) const650 MetaAction* GDIMetaFile::CopyAction( sal_uLong nPos ) const
651 {
652     return ( (MetaAction*) GetObject( nPos ) )->Clone();
653 }
654 
655 // ------------------------------------------------------------------------
656 
GetActionPos(const String & rLabel)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 
InsertLabel(const String & rLabel,sal_uLong nActionPos)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 
RemoveLabel(const String & rLabel)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 
RenameLabel(const String & rLabel,const String & rNewLabel)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 
GetLabelCount() const715 sal_uLong GDIMetaFile::GetLabelCount() const
716 {
717     return( pLabelList ? pLabelList->ImplCount() : 0UL );
718 }
719 
720 // ------------------------------------------------------------------------
721 
GetLabel(sal_uLong nLabel)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 
SaveStatus()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 
Mirror(sal_uLong nMirrorFlags)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 
Move(long nX,long nY)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 
Move(long nX,long nY,long nDPIX,long nDPIY)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 
Scale(double fScaleX,double fScaleY)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 
Scale(const Fraction & rScaleX,const Fraction & rScaleY)909 void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY )
910 {
911     Scale( (double) rScaleX, (double) rScaleY );
912 }
913 
914 // ------------------------------------------------------------------------
915 
Clip(const Rectangle & i_rClipRect)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 
ImplGetRotatedPoint(const Point & rPt,const Point & rRotatePt,const Size & rOffset,double fSin,double fCos)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 
ImplGetRotatedPolygon(const Polygon & rPoly,const Point & rRotatePt,const Size & rOffset,double fSin,double fCos)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 
ImplGetRotatedPolyPolygon(const PolyPolygon & rPolyPoly,const Point & rRotatePt,const Size & rOffset,double fSin,double fCos)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 
ImplAddGradientEx(GDIMetaFile & rMtf,const OutputDevice & rMapDev,const PolyPolygon & rPolyPoly,const Gradient & rGrad)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 
Rotate(long nAngle10)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().HasPolyPolygonOrB2DPolyPolygon() )
1388                         aMtf.AddAction( new MetaClipRegionAction( Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetAsPolyPolygon(), 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.HasPolyPolygonOrB2DPolyPolygon() )
1410                         aMtf.AddAction( new MetaISectRegionClipRegionAction( Region( ImplGetRotatedPolyPolygon( rRegion.GetAsPolyPolygon(), 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 
ImplActionBounds(Rectangle & o_rOutBounds,const Rectangle & i_rInBounds,const std::vector<Rectangle> & i_rClipStack,Rectangle * o_pHairline)1477 static void ImplActionBounds( Rectangle& o_rOutBounds,
1478                               const Rectangle& i_rInBounds,
1479                               const std::vector<Rectangle>& i_rClipStack,
1480                               Rectangle* o_pHairline )
1481 {
1482     Rectangle aBounds( i_rInBounds );
1483     if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() )
1484         aBounds.Intersection( i_rClipStack.back() );
1485     if( ! aBounds.IsEmpty() )
1486     {
1487         if( ! o_rOutBounds.IsEmpty() )
1488             o_rOutBounds.Union( aBounds );
1489         else
1490             o_rOutBounds = aBounds;
1491 
1492         if(o_pHairline)
1493         {
1494             if( ! o_pHairline->IsEmpty() )
1495                 o_pHairline->Union( aBounds );
1496             else
1497                 *o_pHairline = aBounds;
1498         }
1499     }
1500 }
1501 
GetBoundRect(OutputDevice & i_rReference,Rectangle * pHairline) const1502 Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference, Rectangle* pHairline ) const
1503 {
1504     GDIMetaFile     aMtf;
1505     VirtualDevice   aMapVDev( i_rReference );
1506 
1507     aMapVDev.EnableOutput( sal_False );
1508     aMapVDev.SetMapMode( GetPrefMapMode() );
1509 
1510     std::vector<Rectangle> aClipStack( 1, Rectangle() );
1511     std::vector<sal_uInt16> aPushFlagStack;
1512 
1513     Rectangle aBound;
1514 
1515     if(pHairline)
1516     {
1517         *pHairline = Rectangle();
1518     }
1519 
1520     const sal_uLong nActionCount(GetActionCount());
1521 
1522     for(sal_uLong a(0); a < nActionCount; a++)
1523     {
1524         MetaAction* pAction = GetAction(a);
1525         const sal_uInt16 nActionType = pAction->GetType();
1526         Rectangle* pUseHairline = (pHairline && aMapVDev.IsLineColor()) ? pHairline : 0;
1527 
1528         switch( nActionType )
1529         {
1530         case( META_PIXEL_ACTION ):
1531         {
1532             MetaPixelAction* pAct = (MetaPixelAction*) pAction;
1533             ImplActionBounds( aBound,
1534                              Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
1535                                        aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1536                              aClipStack, pUseHairline );
1537         }
1538         break;
1539 
1540         case( META_POINT_ACTION ):
1541         {
1542             MetaPointAction* pAct = (MetaPointAction*) pAction;
1543             ImplActionBounds( aBound,
1544                              Rectangle( aMapVDev.LogicToLogic( pAct->GetPoint(), aMapVDev.GetMapMode(), GetPrefMapMode() ),
1545                                        aMapVDev.PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1546                              aClipStack, pUseHairline );
1547         }
1548         break;
1549 
1550         case( META_LINE_ACTION ):
1551         {
1552             MetaLineAction* pAct = (MetaLineAction*) pAction;
1553             Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() );
1554             Rectangle aRect( aP1, aP2 );
1555             aRect.Justify();
1556 
1557             if(pUseHairline)
1558             {
1559                 const LineInfo& rLineInfo = pAct->GetLineInfo();
1560 
1561                 if(0 != rLineInfo.GetWidth())
1562                 {
1563                     pUseHairline = 0;
1564                 }
1565             }
1566 
1567             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1568         }
1569         break;
1570 
1571         case( META_RECT_ACTION ):
1572         {
1573             MetaRectAction* pAct = (MetaRectAction*) pAction;
1574             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1575         }
1576         break;
1577 
1578         case( META_ROUNDRECT_ACTION ):
1579         {
1580             MetaRoundRectAction*    pAct = (MetaRoundRectAction*) pAction;
1581             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1582         }
1583         break;
1584 
1585         case( META_ELLIPSE_ACTION ):
1586         {
1587             MetaEllipseAction*      pAct = (MetaEllipseAction*) pAction;
1588             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1589         }
1590         break;
1591 
1592         case( META_ARC_ACTION ):
1593         {
1594             MetaArcAction*  pAct = (MetaArcAction*) pAction;
1595             // FIXME: this is imprecise
1596             // e.g. for small arcs the whole rectangle is WAY too large
1597             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1598         }
1599         break;
1600 
1601         case( META_PIE_ACTION ):
1602         {
1603             MetaPieAction*  pAct = (MetaPieAction*) pAction;
1604             // FIXME: this is imprecise
1605             // e.g. for small arcs the whole rectangle is WAY too large
1606             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1607         }
1608         break;
1609 
1610         case( META_CHORD_ACTION ):
1611         {
1612             MetaChordAction*    pAct = (MetaChordAction*) pAction;
1613             // FIXME: this is imprecise
1614             // e.g. for small arcs the whole rectangle is WAY too large
1615             ImplActionBounds( aBound, aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1616         }
1617         break;
1618 
1619         case( META_POLYLINE_ACTION ):
1620         {
1621             MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction;
1622             Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1623 
1624             if(pUseHairline)
1625             {
1626                 const LineInfo& rLineInfo = pAct->GetLineInfo();
1627 
1628                 if(0 != rLineInfo.GetWidth())
1629                 {
1630                     pUseHairline = 0;
1631                 }
1632             }
1633 
1634             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1635         }
1636         break;
1637 
1638         case( META_POLYGON_ACTION ):
1639         {
1640             MetaPolygonAction* pAct = (MetaPolygonAction*) pAction;
1641             Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1642             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1643         }
1644         break;
1645 
1646         case( META_POLYPOLYGON_ACTION ):
1647         {
1648             MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction;
1649             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1650             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1651         }
1652         break;
1653 
1654         case( META_TEXT_ACTION ):
1655         {
1656             MetaTextAction* pAct = (MetaTextAction*) pAction;
1657             Rectangle aRect;
1658             // hdu said base = index
1659             aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() );
1660             Point aPt( pAct->GetPoint() );
1661             aRect.Move( aPt.X(), aPt.Y() );
1662             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1663         }
1664         break;
1665 
1666         case( META_TEXTARRAY_ACTION ):
1667         {
1668             MetaTextArrayAction* pAct = (MetaTextArrayAction*) pAction;
1669             Rectangle aRect;
1670             // hdu said base = index
1671             aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1672                                        0, pAct->GetDXArray() );
1673             Point aPt( pAct->GetPoint() );
1674             aRect.Move( aPt.X(), aPt.Y() );
1675             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1676         }
1677         break;
1678 
1679         case( META_STRETCHTEXT_ACTION ):
1680         {
1681             MetaStretchTextAction* pAct = (MetaStretchTextAction*) pAction;
1682             Rectangle aRect;
1683             // hdu said base = index
1684             aMapVDev.GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1685                                        pAct->GetWidth(), NULL );
1686             Point aPt( pAct->GetPoint() );
1687             aRect.Move( aPt.X(), aPt.Y() );
1688             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1689         }
1690         break;
1691 
1692         case( META_TEXTLINE_ACTION ):
1693         {
1694             MetaTextLineAction* pAct = (MetaTextLineAction*) pAction;
1695             // measure a test string to get ascend and descent right
1696             static const sal_Unicode pStr[] = { 0xc4, 0x67, 0 };
1697             String aStr( pStr );
1698 
1699             Rectangle aRect;
1700             aMapVDev.GetTextBoundRect( aRect, aStr, 0, 0, aStr.Len(), 0, NULL );
1701             Point aPt( pAct->GetStartPoint() );
1702             aRect.Move( aPt.X(), aPt.Y() );
1703             aRect.Right() = aRect.Left() + pAct->GetWidth();
1704             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1705         }
1706         break;
1707 
1708         case( META_BMPSCALE_ACTION ):
1709         {
1710             MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
1711             Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1712             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1713         }
1714         break;
1715 
1716         case( META_BMPSCALEPART_ACTION ):
1717         {
1718             MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
1719             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1720             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1721         }
1722         break;
1723 
1724         case( META_BMPEXSCALE_ACTION ):
1725         {
1726             MetaBmpExScaleAction*   pAct = (MetaBmpExScaleAction*) pAction;
1727             Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1728             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1729         }
1730         break;
1731 
1732         case( META_BMPEXSCALEPART_ACTION ):
1733         {
1734             MetaBmpExScalePartAction*   pAct = (MetaBmpExScalePartAction*) pAction;
1735             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1736             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1737         }
1738         break;
1739 
1740         case( META_GRADIENT_ACTION ):
1741         {
1742             MetaGradientAction* pAct = (MetaGradientAction*) pAction;
1743             Rectangle aRect( pAct->GetRect() );
1744             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1745         }
1746         break;
1747 
1748         case( META_GRADIENTEX_ACTION ):
1749         {
1750             MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
1751             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1752             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1753         }
1754         break;
1755 
1756         case( META_COMMENT_ACTION ):
1757         {
1758             // nothing to do
1759         };
1760         break;
1761 
1762         case( META_HATCH_ACTION ):
1763         {
1764             MetaHatchAction*    pAct = (MetaHatchAction*) pAction;
1765             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1766             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1767         }
1768         break;
1769 
1770         case( META_TRANSPARENT_ACTION ):
1771         {
1772             MetaTransparentAction* pAct = (MetaTransparentAction*) pAction;
1773             Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1774             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1775         }
1776         break;
1777 
1778         case( META_FLOATTRANSPARENT_ACTION ):
1779         {
1780             MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
1781             // MetaFloatTransparentAction is defined limiting it's content Metafile
1782             // to it's geometry definition(Point, Size), so use these directly
1783             const Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1784             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1785         }
1786         break;
1787 
1788         case( META_EPS_ACTION ):
1789         {
1790             MetaEPSAction*  pAct = (MetaEPSAction*) pAction;
1791             Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1792             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1793         }
1794         break;
1795 
1796         case( META_CLIPREGION_ACTION ):
1797         {
1798             MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction;
1799             if( pAct->IsClipping() )
1800                 aClipStack.back() = aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() );
1801             else
1802                 aClipStack.back() = Rectangle();
1803         }
1804         break;
1805 
1806         case( META_ISECTRECTCLIPREGION_ACTION ):
1807         {
1808             MetaISectRectClipRegionAction* pAct = (MetaISectRectClipRegionAction*) pAction;
1809             Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
1810             if( aClipStack.back().IsEmpty() )
1811                 aClipStack.back() = aRect;
1812             else
1813                 aClipStack.back().Intersection( aRect );
1814         }
1815         break;
1816 
1817         case( META_ISECTREGIONCLIPREGION_ACTION ):
1818         {
1819             MetaISectRegionClipRegionAction*    pAct = (MetaISectRegionClipRegionAction*) pAction;
1820             Rectangle aRect( aMapVDev.LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev.GetMapMode(), GetPrefMapMode() ) );
1821             if( aClipStack.back().IsEmpty() )
1822                 aClipStack.back() = aRect;
1823             else
1824                 aClipStack.back().Intersection( aRect );
1825         }
1826         break;
1827 
1828         case( META_BMP_ACTION ):
1829         {
1830             MetaBmpAction* pAct = (MetaBmpAction*) pAction;
1831             Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1832             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1833         }
1834         break;
1835 
1836         case( META_BMPEX_ACTION ):
1837         {
1838             MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
1839             Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmapEx().GetSizePixel() ) );
1840             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1841         }
1842         break;
1843 
1844         case( META_MASK_ACTION ):
1845         {
1846             MetaMaskAction* pAct = (MetaMaskAction*) pAction;
1847             Rectangle aRect( pAct->GetPoint(), aMapVDev.PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1848             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1849         }
1850         break;
1851 
1852         case( META_MASKSCALE_ACTION ):
1853         {
1854             MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
1855             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1856             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1857         }
1858         break;
1859 
1860         case( META_MASKSCALEPART_ACTION ):
1861         {
1862             MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
1863             Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1864             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1865         }
1866         break;
1867 
1868         case( META_WALLPAPER_ACTION ):
1869         {
1870             MetaWallpaperAction* pAct = (MetaWallpaperAction*) pAction;
1871             Rectangle aRect( pAct->GetRect() );
1872             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1873         }
1874         break;
1875 
1876         case( META_TEXTRECT_ACTION ):
1877         {
1878             MetaTextRectAction* pAct = (MetaTextRectAction*) pAction;
1879             Rectangle aRect( pAct->GetRect() );
1880             ImplActionBounds( aBound, aMapVDev.LogicToLogic( aRect, aMapVDev.GetMapMode(), GetPrefMapMode() ), aClipStack, 0 );
1881         }
1882         break;
1883 
1884         case( META_MOVECLIPREGION_ACTION ):
1885         {
1886             MetaMoveClipRegionAction* pAct = (MetaMoveClipRegionAction*) pAction;
1887             if( ! aClipStack.back().IsEmpty() )
1888             {
1889                 Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() );
1890                 aDelta = aMapVDev.LogicToLogic( aDelta, aMapVDev.GetMapMode(), GetPrefMapMode() );
1891                 aClipStack.back().Move( aDelta.Width(), aDelta.Width() );
1892             }
1893         }
1894         break;
1895 
1896         default:
1897             {
1898                 pAction->Execute( &aMapVDev );
1899 
1900                 if( nActionType == META_PUSH_ACTION )
1901                 {
1902                     MetaPushAction* pAct = (MetaPushAction*) pAction;
1903                     aPushFlagStack.push_back( pAct->GetFlags() );
1904                     if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
1905                     {
1906                         Rectangle aRect( aClipStack.back() );
1907                         aClipStack.push_back( aRect );
1908                     }
1909                 }
1910                 else if( nActionType == META_POP_ACTION )
1911                 {
1912                     // sanity check
1913                     if( ! aPushFlagStack.empty() )
1914                     {
1915                         if( (aPushFlagStack.back() & PUSH_CLIPREGION) != 0 )
1916                         {
1917                             if( aClipStack.size() > 1 )
1918                                 aClipStack.pop_back();
1919                         }
1920                         aPushFlagStack.pop_back();
1921                     }
1922                 }
1923             }
1924             break;
1925         }
1926     }
1927     return aBound;
1928 }
1929 
1930 // ------------------------------------------------------------------------
1931 
ImplColAdjustFnc(const Color & rColor,const void * pColParam)1932 Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam )
1933 {
1934     return Color( rColor.GetTransparency(),
1935                   ( (const ImplColAdjustParam*) pColParam )->pMapR[ rColor.GetRed() ],
1936                   ( (const ImplColAdjustParam*) pColParam )->pMapG[ rColor.GetGreen() ],
1937                   ( (const ImplColAdjustParam*) pColParam )->pMapB[ rColor.GetBlue() ] );
1938 
1939 }
1940 
1941 // ------------------------------------------------------------------------
1942 
ImplBmpAdjustFnc(const BitmapEx & rBmpEx,const void * pBmpParam)1943 BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1944 {
1945     const ImplBmpAdjustParam*   p = (const ImplBmpAdjustParam*) pBmpParam;
1946     BitmapEx                    aRet( rBmpEx );
1947 
1948     aRet.Adjust( p->nLuminancePercent, p->nContrastPercent,
1949                  p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent,
1950                  p->fGamma, p->bInvert );
1951 
1952     return aRet;
1953 }
1954 
1955 // ------------------------------------------------------------------------
1956 
ImplColConvertFnc(const Color & rColor,const void * pColParam)1957 Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam )
1958 {
1959     sal_uInt8 cLum = rColor.GetLuminance();
1960 
1961     if( MTF_CONVERSION_1BIT_THRESHOLD == ( (const ImplColConvertParam*) pColParam )->eConversion )
1962         cLum = ( cLum < 128 ) ? 0 : 255;
1963 
1964     return Color( rColor.GetTransparency(), cLum, cLum, cLum );
1965 }
1966 
1967 // ------------------------------------------------------------------------
1968 
ImplBmpConvertFnc(const BitmapEx & rBmpEx,const void * pBmpParam)1969 BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1970 {
1971     BitmapEx aRet( rBmpEx );
1972 
1973     aRet.Convert( ( (const ImplBmpConvertParam*) pBmpParam )->eConversion );
1974 
1975     return aRet;
1976 }
1977 
1978 // ------------------------------------------------------------------------
1979 
ImplColMonoFnc(const Color &,const void * pColParam)1980 Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam )
1981 {
1982     return( ( (const ImplColMonoParam*) pColParam )->aColor );
1983 }
1984 
1985 // ------------------------------------------------------------------------
1986 
ImplBmpMonoFnc(const BitmapEx & rBmpEx,const void * pBmpParam)1987 BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1988 {
1989     BitmapPalette aPal( 3 );
1990 
1991     aPal[ 0 ] = Color( COL_BLACK );
1992     aPal[ 1 ] = Color( COL_WHITE );
1993     aPal[ 2 ] = ( (const ImplBmpMonoParam*) pBmpParam )->aColor;
1994 
1995     Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal );
1996     aBmp.Erase( ( (const ImplBmpMonoParam*) pBmpParam )->aColor );
1997 
1998     if( rBmpEx.IsAlpha() )
1999         return BitmapEx( aBmp, rBmpEx.GetAlpha() );
2000     else if( rBmpEx.IsTransparent() )
2001         return BitmapEx( aBmp, rBmpEx.GetMask() );
2002     else
2003         return aBmp;
2004 }
2005 
2006 // ------------------------------------------------------------------------
2007 
ImplColReplaceFnc(const Color & rColor,const void * pColParam)2008 Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam )
2009 {
2010     const sal_uLong nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue();
2011 
2012     for( sal_uLong i = 0; i < ( (const ImplColReplaceParam*) pColParam )->nCount; i++ )
2013     {
2014         if( ( ( (const ImplColReplaceParam*) pColParam )->pMinR[ i ] <= nR ) &&
2015             ( ( (const ImplColReplaceParam*) pColParam )->pMaxR[ i ] >= nR ) &&
2016             ( ( (const ImplColReplaceParam*) pColParam )->pMinG[ i ] <= nG ) &&
2017             ( ( (const ImplColReplaceParam*) pColParam )->pMaxG[ i ] >= nG ) &&
2018             ( ( (const ImplColReplaceParam*) pColParam )->pMinB[ i ] <= nB ) &&
2019             ( ( (const ImplColReplaceParam*) pColParam )->pMaxB[ i ] >= nB ) )
2020         {
2021             return( ( (const ImplColReplaceParam*) pColParam )->pDstCols[ i ] );
2022         }
2023     }
2024 
2025     return rColor;
2026 }
2027 
2028 // ------------------------------------------------------------------------
2029 
ImplBmpReplaceFnc(const BitmapEx & rBmpEx,const void * pBmpParam)2030 BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
2031 {
2032     const ImplBmpReplaceParam*  p = (const ImplBmpReplaceParam*) pBmpParam;
2033     BitmapEx                    aRet( rBmpEx );
2034 
2035     aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount, p->pTols );
2036 
2037     return aRet;
2038 }
2039 
2040 // ------------------------------------------------------------------------
2041 
ImplExchangeColors(ColorExchangeFnc pFncCol,const void * pColParam,BmpExchangeFnc pFncBmp,const void * pBmpParam)2042 void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam,
2043                                       BmpExchangeFnc pFncBmp, const void* pBmpParam )
2044 {
2045     GDIMetaFile aMtf;
2046 
2047     aMtf.aPrefSize = aPrefSize;
2048     aMtf.aPrefMapMode = aPrefMapMode;
2049 
2050     for( MetaAction* pAction = (MetaAction*) First(); pAction; pAction = (MetaAction*) Next() )
2051     {
2052         const sal_uInt16 nType = pAction->GetType();
2053 
2054         switch( nType )
2055         {
2056             case( META_PIXEL_ACTION ):
2057             {
2058                 MetaPixelAction* pAct = (MetaPixelAction*) pAction;
2059                 aMtf.Insert( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
2060             }
2061             break;
2062 
2063             case( META_LINECOLOR_ACTION ):
2064             {
2065                 MetaLineColorAction* pAct = (MetaLineColorAction*) pAction;
2066 
2067                 if( !pAct->IsSetting() )
2068                     pAct->Duplicate();
2069                 else
2070                     pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2071 
2072                 aMtf.Insert( pAct, LIST_APPEND );
2073             }
2074             break;
2075 
2076             case( META_FILLCOLOR_ACTION ):
2077             {
2078                 MetaFillColorAction* pAct = (MetaFillColorAction*) pAction;
2079 
2080                 if( !pAct->IsSetting() )
2081                     pAct->Duplicate();
2082                 else
2083                     pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2084 
2085                 aMtf.Insert( pAct, LIST_APPEND );
2086             }
2087             break;
2088 
2089             case( META_TEXTCOLOR_ACTION ):
2090             {
2091                 MetaTextColorAction* pAct = (MetaTextColorAction*) pAction;
2092                 aMtf.Insert( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ), LIST_APPEND );
2093             }
2094             break;
2095 
2096             case( META_TEXTFILLCOLOR_ACTION ):
2097             {
2098                 MetaTextFillColorAction* pAct = (MetaTextFillColorAction*) pAction;
2099 
2100                 if( !pAct->IsSetting() )
2101                     pAct->Duplicate();
2102                 else
2103                     pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2104 
2105                 aMtf.Insert( pAct, LIST_APPEND );
2106             }
2107             break;
2108 
2109             case( META_TEXTLINECOLOR_ACTION ):
2110             {
2111                 MetaTextLineColorAction* pAct = (MetaTextLineColorAction*) pAction;
2112 
2113                 if( !pAct->IsSetting() )
2114                     pAct->Duplicate();
2115                 else
2116                     pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2117 
2118                 aMtf.Insert( pAct, LIST_APPEND );
2119             }
2120             break;
2121 
2122             case( META_OVERLINECOLOR_ACTION ):
2123             {
2124                 MetaOverlineColorAction* pAct = (MetaOverlineColorAction*) pAction;
2125 
2126                 if( !pAct->IsSetting() )
2127                     pAct->Duplicate();
2128                 else
2129                     pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), sal_True );
2130 
2131                 aMtf.Insert( pAct, LIST_APPEND );
2132             }
2133             break;
2134 
2135             case( META_FONT_ACTION ):
2136             {
2137                 MetaFontAction* pAct = (MetaFontAction*) pAction;
2138                 Font            aFont( pAct->GetFont() );
2139 
2140                 aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) );
2141                 aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) );
2142                 aMtf.Insert( new MetaFontAction( aFont ), LIST_APPEND );
2143             }
2144             break;
2145 
2146             case( META_WALLPAPER_ACTION ):
2147             {
2148                 MetaWallpaperAction*    pAct = (MetaWallpaperAction*) pAction;
2149                 Wallpaper               aWall( pAct->GetWallpaper() );
2150                 const Rectangle&        rRect = pAct->GetRect();
2151 
2152                 aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) );
2153 
2154                 if( aWall.IsBitmap() )
2155                     aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) );
2156 
2157                 if( aWall.IsGradient() )
2158                 {
2159                     Gradient aGradient( aWall.GetGradient() );
2160 
2161                     aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2162                     aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2163                     aWall.SetGradient( aGradient );
2164                 }
2165 
2166                 aMtf.Insert( new MetaWallpaperAction( rRect, aWall ), LIST_APPEND );
2167             }
2168             break;
2169 
2170             case( META_BMP_ACTION ):
2171             case( META_BMPEX_ACTION ):
2172             case( META_MASK_ACTION ):
2173             {
2174                 DBG_ERROR( "Don't use bitmap actions of this type in metafiles!" );
2175             }
2176             break;
2177 
2178             case( META_BMPSCALE_ACTION ):
2179             {
2180                 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
2181                 aMtf.Insert( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(),
2182                                                      pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
2183                                                      LIST_APPEND );
2184             }
2185             break;
2186 
2187             case( META_BMPSCALEPART_ACTION ):
2188             {
2189                 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
2190                 aMtf.Insert( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2191                                                          pAct->GetSrcPoint(), pAct->GetSrcSize(),
2192                                                          pFncBmp( pAct->GetBitmap(), pBmpParam ).GetBitmap() ),
2193                                                          LIST_APPEND );
2194             }
2195             break;
2196 
2197             case( META_BMPEXSCALE_ACTION ):
2198             {
2199                 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
2200                 aMtf.Insert( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(),
2201                                                        pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
2202                                                        LIST_APPEND );
2203             }
2204             break;
2205 
2206             case( META_BMPEXSCALEPART_ACTION ):
2207             {
2208                 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
2209                 aMtf.Insert( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2210                                                            pAct->GetSrcPoint(), pAct->GetSrcSize(),
2211                                                            pFncBmp( pAct->GetBitmapEx(), pBmpParam ) ),
2212                                                            LIST_APPEND );
2213             }
2214             break;
2215 
2216             case( META_MASKSCALE_ACTION ):
2217             {
2218                 MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
2219                 aMtf.Insert( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(),
2220                                                       pAct->GetBitmap(),
2221                                                       pFncCol( pAct->GetColor(), pColParam ) ),
2222                                                       LIST_APPEND );
2223             }
2224             break;
2225 
2226             case( META_MASKSCALEPART_ACTION ):
2227             {
2228                 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
2229                 aMtf.Insert( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2230                                                           pAct->GetSrcPoint(), pAct->GetSrcSize(),
2231                                                           pAct->GetBitmap(),
2232                                                           pFncCol( pAct->GetColor(), pColParam ) ),
2233                                                           LIST_APPEND );
2234             }
2235             break;
2236 
2237             case( META_GRADIENT_ACTION ):
2238             {
2239                 MetaGradientAction* pAct = (MetaGradientAction*) pAction;
2240                 Gradient            aGradient( pAct->GetGradient() );
2241 
2242                 aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2243                 aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2244                 aMtf.Insert( new MetaGradientAction( pAct->GetRect(), aGradient ), LIST_APPEND );
2245             }
2246             break;
2247 
2248             case( META_GRADIENTEX_ACTION ):
2249             {
2250                 MetaGradientExAction* pAct = (MetaGradientExAction*) pAction;
2251                 Gradient              aGradient( pAct->GetGradient() );
2252 
2253                 aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2254                 aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2255                 aMtf.Insert( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ), LIST_APPEND );
2256             }
2257             break;
2258 
2259             case( META_HATCH_ACTION ):
2260             {
2261                 MetaHatchAction*    pAct = (MetaHatchAction*) pAction;
2262                 Hatch               aHatch( pAct->GetHatch() );
2263 
2264                 aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) );
2265                 aMtf.Insert( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ), LIST_APPEND );
2266             }
2267             break;
2268 
2269             case( META_FLOATTRANSPARENT_ACTION ):
2270             {
2271                 MetaFloatTransparentAction* pAct = (MetaFloatTransparentAction*) pAction;
2272                 GDIMetaFile                 aTransMtf( pAct->GetGDIMetaFile() );
2273 
2274                 aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2275                 aMtf.Insert( new MetaFloatTransparentAction( aTransMtf,
2276                                                              pAct->GetPoint(), pAct->GetSize(),
2277                                                              pAct->GetGradient() ),
2278                                                              LIST_APPEND );
2279             }
2280             break;
2281 
2282             case( META_EPS_ACTION ):
2283             {
2284                 MetaEPSAction*  pAct = (MetaEPSAction*) pAction;
2285                 GDIMetaFile     aSubst( pAct->GetSubstitute() );
2286 
2287                 aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2288                 aMtf.Insert( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(),
2289                                                 pAct->GetLink(), aSubst ),
2290                                                 LIST_APPEND );
2291             }
2292             break;
2293 
2294             default:
2295             {
2296                 pAction->Duplicate();
2297                 aMtf.Insert( pAction, LIST_APPEND );
2298             }
2299             break;
2300         }
2301     }
2302 
2303     *this = aMtf;
2304 }
2305 
2306 // ------------------------------------------------------------------------
2307 
Adjust(short nLuminancePercent,short nContrastPercent,short nChannelRPercent,short nChannelGPercent,short nChannelBPercent,double fGamma,sal_Bool bInvert)2308 void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent,
2309                           short nChannelRPercent, short nChannelGPercent,
2310                           short nChannelBPercent, double fGamma, sal_Bool bInvert )
2311 {
2312     // nothing to do? => return quickly
2313     if( nLuminancePercent || nContrastPercent ||
2314         nChannelRPercent || nChannelGPercent || nChannelBPercent ||
2315         ( fGamma != 1.0 ) || bInvert )
2316     {
2317         double              fM, fROff, fGOff, fBOff, fOff;
2318         ImplColAdjustParam  aColParam;
2319         ImplBmpAdjustParam  aBmpParam;
2320 
2321         aColParam.pMapR = new sal_uInt8[ 256 ];
2322         aColParam.pMapG = new sal_uInt8[ 256 ];
2323         aColParam.pMapB = new sal_uInt8[ 256 ];
2324 
2325         // calculate slope
2326         if( nContrastPercent >= 0 )
2327             fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2328         else
2329             fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2330 
2331         // total offset = luminance offset + contrast offset
2332         fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2333 
2334         // channel offset = channel offset  + total offset
2335         fROff = nChannelRPercent * 2.55 + fOff;
2336         fGOff = nChannelGPercent * 2.55 + fOff;
2337         fBOff = nChannelBPercent * 2.55 + fOff;
2338 
2339         // calculate gamma value
2340         fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2341         const sal_Bool bGamma = ( fGamma != 1.0 );
2342 
2343         // create mapping table
2344         for( long nX = 0L; nX < 256L; nX++ )
2345         {
2346             aColParam.pMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2347             aColParam.pMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2348             aColParam.pMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2349 
2350             if( bGamma )
2351             {
2352                 aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma );
2353                 aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma );
2354                 aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma );
2355             }
2356 
2357             if( bInvert )
2358             {
2359                 aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ];
2360                 aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ];
2361                 aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ];
2362             }
2363         }
2364 
2365         aBmpParam.nLuminancePercent = nLuminancePercent;
2366         aBmpParam.nContrastPercent = nContrastPercent;
2367         aBmpParam.nChannelRPercent = nChannelRPercent;
2368         aBmpParam.nChannelGPercent = nChannelGPercent;
2369         aBmpParam.nChannelBPercent = nChannelBPercent;
2370         aBmpParam.fGamma = fGamma;
2371         aBmpParam.bInvert = bInvert;
2372 
2373         // do color adjustment
2374         ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam );
2375 
2376         delete[] aColParam.pMapR;
2377         delete[] aColParam.pMapG;
2378         delete[] aColParam.pMapB;
2379     }
2380 }
2381 
2382 // ------------------------------------------------------------------------
2383 
Convert(MtfConversion eConversion)2384 void GDIMetaFile::Convert( MtfConversion eConversion )
2385 {
2386     // nothing to do? => return quickly
2387     if( eConversion != MTF_CONVERSION_NONE )
2388     {
2389         ImplColConvertParam aColParam;
2390         ImplBmpConvertParam aBmpParam;
2391 
2392         aColParam.eConversion = eConversion;
2393         aBmpParam.eConversion = ( MTF_CONVERSION_1BIT_THRESHOLD == eConversion ) ? BMP_CONVERSION_1BIT_THRESHOLD : BMP_CONVERSION_8BIT_GREYS;
2394 
2395         ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam );
2396     }
2397 }
2398 
2399 // ------------------------------------------------------------------------
2400 
ReplaceColors(const Color & rSearchColor,const Color & rReplaceColor,sal_uLong nTol)2401 void GDIMetaFile::ReplaceColors( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
2402 {
2403     ReplaceColors( &rSearchColor, &rReplaceColor, 1, &nTol );
2404 }
2405 
2406 // ------------------------------------------------------------------------
2407 
ReplaceColors(const Color * pSearchColors,const Color * pReplaceColors,sal_uLong nColorCount,sal_uLong * pTols)2408 void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, sal_uLong* pTols )
2409 {
2410     ImplColReplaceParam aColParam;
2411     ImplBmpReplaceParam aBmpParam;
2412 
2413     aColParam.pMinR = new sal_uLong[ nColorCount ];
2414     aColParam.pMaxR = new sal_uLong[ nColorCount ];
2415     aColParam.pMinG = new sal_uLong[ nColorCount ];
2416     aColParam.pMaxG = new sal_uLong[ nColorCount ];
2417     aColParam.pMinB = new sal_uLong[ nColorCount ];
2418     aColParam.pMaxB = new sal_uLong[ nColorCount ];
2419 
2420     for( sal_uLong i = 0; i < nColorCount; i++ )
2421     {
2422         const long  nTol = pTols ? ( pTols[ i ] * 255 ) / 100 : 0;
2423         long        nVal;
2424 
2425         nVal = pSearchColors[ i ].GetRed();
2426         aColParam.pMinR[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2427         aColParam.pMaxR[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2428 
2429         nVal = pSearchColors[ i ].GetGreen();
2430         aColParam.pMinG[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2431         aColParam.pMaxG[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2432 
2433         nVal = pSearchColors[ i ].GetBlue();
2434         aColParam.pMinB[ i ] = (sal_uLong) Max( nVal - nTol, 0L );
2435         aColParam.pMaxB[ i ] = (sal_uLong) Min( nVal + nTol, 255L );
2436     }
2437 
2438     aColParam.pDstCols = pReplaceColors;
2439     aColParam.nCount = nColorCount;
2440 
2441     aBmpParam.pSrcCols = pSearchColors;
2442     aBmpParam.pDstCols = pReplaceColors;
2443     aBmpParam.nCount = nColorCount;
2444     aBmpParam.pTols = pTols;
2445 
2446     ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam );
2447 
2448     delete[] aColParam.pMinR;
2449     delete[] aColParam.pMaxR;
2450     delete[] aColParam.pMinG;
2451     delete[] aColParam.pMaxG;
2452     delete[] aColParam.pMinB;
2453     delete[] aColParam.pMaxB;
2454 };
2455 
2456 // ------------------------------------------------------------------------
2457 
GetMonochromeMtf(const Color & rColor) const2458 GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const
2459 {
2460     GDIMetaFile aRet( *this );
2461 
2462     ImplColMonoParam    aColParam;
2463     ImplBmpMonoParam    aBmpParam;
2464 
2465     aColParam.aColor = rColor;
2466     aBmpParam.aColor = rColor;
2467 
2468     aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam );
2469 
2470     return aRet;
2471 }
2472 
2473 // ------------------------------------------------------------------------
2474 
GetChecksum() const2475 sal_uLong GDIMetaFile::GetChecksum() const
2476 {
2477     GDIMetaFile         aMtf;
2478     SvMemoryStream      aMemStm( 65535, 65535 );
2479     ImplMetaWriteData   aWriteData;
2480     SVBT16              aBT16;
2481     SVBT32              aBT32;
2482     sal_uLong               nCrc = 0;
2483 
2484     aWriteData.meActualCharSet = aMemStm.GetStreamCharSet();
2485 
2486     for( sal_uLong i = 0, nObjCount = GetActionCount(); i < nObjCount; i++ )
2487     {
2488         MetaAction* pAction = GetAction( i );
2489 
2490         switch( pAction->GetType() )
2491         {
2492             case( META_BMP_ACTION ):
2493             {
2494                 MetaBmpAction* pAct = (MetaBmpAction*) pAction;
2495 
2496                 ShortToSVBT16( pAct->GetType(), aBT16 );
2497                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2498 
2499                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2500                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2501 
2502                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2503                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2504 
2505                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2506                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2507             }
2508             break;
2509 
2510             case( META_BMPSCALE_ACTION ):
2511             {
2512                 MetaBmpScaleAction* pAct = (MetaBmpScaleAction*) pAction;
2513 
2514                 ShortToSVBT16( pAct->GetType(), aBT16 );
2515                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2516 
2517                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2518                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2519 
2520                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2521                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2522 
2523                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2524                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2525 
2526                 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2527                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2528 
2529                 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2530                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2531             }
2532             break;
2533 
2534             case( META_BMPSCALEPART_ACTION ):
2535             {
2536                 MetaBmpScalePartAction* pAct = (MetaBmpScalePartAction*) pAction;
2537 
2538                 ShortToSVBT16( pAct->GetType(), aBT16 );
2539                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2540 
2541                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2542                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2543 
2544                 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2545                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2546 
2547                 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2548                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2549 
2550                 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2551                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2552 
2553                 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2554                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2555 
2556                 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2557                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2558 
2559                 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2560                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2561 
2562                 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2563                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2564 
2565                 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2566                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2567             }
2568             break;
2569 
2570             case( META_BMPEX_ACTION ):
2571             {
2572                 MetaBmpExAction* pAct = (MetaBmpExAction*) pAction;
2573 
2574                 ShortToSVBT16( pAct->GetType(), aBT16 );
2575                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2576 
2577                 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2578                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2579 
2580                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2581                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2582 
2583                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2584                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2585             }
2586             break;
2587 
2588             case( META_BMPEXSCALE_ACTION ):
2589             {
2590                 MetaBmpExScaleAction* pAct = (MetaBmpExScaleAction*) pAction;
2591 
2592                 ShortToSVBT16( pAct->GetType(), aBT16 );
2593                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2594 
2595                 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2596                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2597 
2598                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2599                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2600 
2601                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2602                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2603 
2604                 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2605                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2606 
2607                 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2608                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2609             }
2610             break;
2611 
2612             case( META_BMPEXSCALEPART_ACTION ):
2613             {
2614                 MetaBmpExScalePartAction* pAct = (MetaBmpExScalePartAction*) pAction;
2615 
2616                 ShortToSVBT16( pAct->GetType(), aBT16 );
2617                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2618 
2619                 UInt32ToSVBT32( pAct->GetBitmapEx().GetChecksum(), aBT32 );
2620                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2621 
2622                 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2623                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2624 
2625                 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2626                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2627 
2628                 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2629                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2630 
2631                 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2632                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2633 
2634                 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2635                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2636 
2637                 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2638                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2639 
2640                 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2641                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2642 
2643                 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2644                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2645             }
2646             break;
2647 
2648             case( META_MASK_ACTION ):
2649             {
2650                 MetaMaskAction* pAct = (MetaMaskAction*) pAction;
2651 
2652                 ShortToSVBT16( pAct->GetType(), aBT16 );
2653                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2654 
2655                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2656                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2657 
2658                 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2659                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2660 
2661                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2662                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2663 
2664                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2665                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2666             }
2667             break;
2668 
2669             case( META_MASKSCALE_ACTION ):
2670             {
2671                 MetaMaskScaleAction* pAct = (MetaMaskScaleAction*) pAction;
2672 
2673                 ShortToSVBT16( pAct->GetType(), aBT16 );
2674                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2675 
2676                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2677                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2678 
2679                 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2680                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2681 
2682                 UInt32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2683                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2684 
2685                 UInt32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2686                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2687 
2688                 UInt32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2689                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2690 
2691                 UInt32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2692                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2693             }
2694             break;
2695 
2696             case( META_MASKSCALEPART_ACTION ):
2697             {
2698                 MetaMaskScalePartAction* pAct = (MetaMaskScalePartAction*) pAction;
2699 
2700                 ShortToSVBT16( pAct->GetType(), aBT16 );
2701                 nCrc = rtl_crc32( nCrc, aBT16, 2 );
2702 
2703                 UInt32ToSVBT32( pAct->GetBitmap().GetChecksum(), aBT32 );
2704                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2705 
2706                 UInt32ToSVBT32( pAct->GetColor().GetColor(), aBT32 );
2707                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2708 
2709                 UInt32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2710                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2711 
2712                 UInt32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2713                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2714 
2715                 UInt32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2716                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2717 
2718                 UInt32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2719                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2720 
2721                 UInt32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2722                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2723 
2724                 UInt32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2725                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2726 
2727                 UInt32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2728                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2729 
2730                 UInt32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2731                 nCrc = rtl_crc32( nCrc, aBT32, 4 );
2732             }
2733             break;
2734 
2735             case META_EPS_ACTION :
2736             {
2737                 MetaEPSAction* pAct = (MetaEPSAction*) pAction;
2738                 nCrc = rtl_crc32( nCrc, pAct->GetLink().GetData(), pAct->GetLink().GetDataSize() );
2739             }
2740             break;
2741 
2742             case META_CLIPREGION_ACTION :
2743             {
2744                 MetaClipRegionAction* pAct = dynamic_cast< MetaClipRegionAction* >(pAction);
2745                 const Region& rRegion = pAct->GetRegion();
2746 
2747                 if(rRegion.HasPolyPolygonOrB2DPolyPolygon())
2748                 {
2749                     // It has shown that this is a possible bottleneck for checksum calculation.
2750                     // In worst case a very expensive RegionHandle representation gets created.
2751                     // In this case it's cheaper to use the PolyPolygon
2752                     const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetAsB2DPolyPolygon());
2753                     const sal_uInt32 nPolyCount(aPolyPolygon.count());
2754                     SVBT64 aSVBT64;
2755 
2756                     for(sal_uInt32 a(0); a < nPolyCount; a++)
2757                     {
2758                         const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(a));
2759                         const sal_uInt32 nPointCount(aPolygon.count());
2760                         const bool bControl(aPolygon.areControlPointsUsed());
2761 
2762                         for(sal_uInt32 b(0); b < nPointCount; b++)
2763                         {
2764                             const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(b));
2765 
2766                             DoubleToSVBT64(aPoint.getX(), aSVBT64);
2767                             nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2768                             DoubleToSVBT64(aPoint.getY(), aSVBT64);
2769                             nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2770 
2771                             if(bControl)
2772                             {
2773                                 if(aPolygon.isPrevControlPointUsed(b))
2774                                 {
2775                                     const basegfx::B2DPoint aCtrl(aPolygon.getPrevControlPoint(b));
2776 
2777                                     DoubleToSVBT64(aCtrl.getX(), aSVBT64);
2778                                     nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2779                                     DoubleToSVBT64(aCtrl.getY(), aSVBT64);
2780                                     nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2781                                 }
2782 
2783                                 if(aPolygon.isNextControlPointUsed(b))
2784                                 {
2785                                     const basegfx::B2DPoint aCtrl(aPolygon.getNextControlPoint(b));
2786 
2787                                     DoubleToSVBT64(aCtrl.getX(), aSVBT64);
2788                                     nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2789                                     DoubleToSVBT64(aCtrl.getY(), aSVBT64);
2790                                     nCrc = rtl_crc32(nCrc, aSVBT64, 8);
2791                                 }
2792                             }
2793                         }
2794                     }
2795 
2796                     SVBT8 aSVBT8;
2797                     ByteToSVBT8((sal_uInt8)pAct->IsClipping(), aSVBT8);
2798                     nCrc = rtl_crc32(nCrc, aSVBT8, 1);
2799                 }
2800                 else
2801                 {
2802                     pAction->Write( aMemStm, &aWriteData );
2803                     nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() );
2804                     aMemStm.Seek( 0 );
2805                 }
2806             }
2807             break;
2808 
2809             default:
2810             {
2811                 pAction->Write( aMemStm, &aWriteData );
2812                 nCrc = rtl_crc32( nCrc, aMemStm.GetData(), aMemStm.Tell() );
2813                 aMemStm.Seek( 0 );
2814             }
2815             break;
2816         }
2817     }
2818 
2819     return nCrc;
2820 }
2821 
2822 // ------------------------------------------------------------------------
2823 
GetSizeBytes() const2824 sal_uLong GDIMetaFile::GetSizeBytes() const
2825 {
2826     sal_uLong nSizeBytes = 0;
2827 
2828     for( sal_uLong i = 0, nObjCount = GetActionCount(); i < nObjCount; ++i )
2829     {
2830         MetaAction* pAction = GetAction( i );
2831 
2832         // default action size is set to 32 (=> not the exact value)
2833         nSizeBytes += 32;
2834 
2835         // add sizes for large action content
2836         switch( pAction->GetType() )
2837         {
2838             case( META_BMP_ACTION ): nSizeBytes += ( (MetaBmpAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2839             case( META_BMPSCALE_ACTION ): nSizeBytes += ( (MetaBmpScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2840             case( META_BMPSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2841 
2842             case( META_BMPEX_ACTION ): nSizeBytes += ( (MetaBmpExAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2843             case( META_BMPEXSCALE_ACTION ): nSizeBytes += ( (MetaBmpExScaleAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2844             case( META_BMPEXSCALEPART_ACTION ): nSizeBytes += ( (MetaBmpExScalePartAction*) pAction )->GetBitmapEx().GetSizeBytes(); break;
2845 
2846             case( META_MASK_ACTION ): nSizeBytes += ( (MetaMaskAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2847             case( META_MASKSCALE_ACTION ): nSizeBytes += ( (MetaMaskScaleAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2848             case( META_MASKSCALEPART_ACTION ): nSizeBytes += ( (MetaMaskScalePartAction*) pAction )->GetBitmap().GetSizeBytes(); break;
2849 
2850             case( META_POLYLINE_ACTION ): nSizeBytes += ( ( (MetaPolyLineAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
2851             case( META_POLYGON_ACTION ): nSizeBytes += ( ( (MetaPolygonAction*) pAction )->GetPolygon().GetSize() * sizeof( Point ) ); break;
2852             case( META_POLYPOLYGON_ACTION ):
2853             {
2854                 const PolyPolygon& rPolyPoly = ( (MetaPolyPolygonAction*) pAction )->GetPolyPolygon();
2855 
2856                 for( sal_uInt16 n = 0; n < rPolyPoly.Count(); ++n )
2857                     nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) );
2858             }
2859             break;
2860 
2861             case( META_TEXT_ACTION ): nSizeBytes += ( ( (MetaTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2862             case( META_STRETCHTEXT_ACTION ): nSizeBytes += ( ( (MetaStretchTextAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2863             case( META_TEXTRECT_ACTION ): nSizeBytes += ( ( (MetaTextRectAction*) pAction )->GetText().Len() * sizeof( sal_Unicode ) ); break;
2864             case( META_TEXTARRAY_ACTION ):
2865             {
2866                 MetaTextArrayAction* pTextArrayAction = (MetaTextArrayAction*) pAction;
2867 
2868                 nSizeBytes += ( pTextArrayAction->GetText().Len() * sizeof( sal_Unicode ) );
2869 
2870                 if( pTextArrayAction->GetDXArray() )
2871                     nSizeBytes += ( pTextArrayAction->GetLen() << 2 );
2872             }
2873             break;
2874         }
2875     }
2876 
2877     return( nSizeBytes );
2878 }
2879 
2880 // ------------------------------------------------------------------------
2881 
operator >>(SvStream & rIStm,GDIMetaFile & rGDIMetaFile)2882 SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile )
2883 {
2884     if( !rIStm.GetError() )
2885     {
2886         char    aId[ 7 ];
2887         sal_uLong   nStmPos = rIStm.Tell();
2888         sal_uInt16  nOldFormat = rIStm.GetNumberFormatInt();
2889 
2890         rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
2891 
2892         aId[ 0 ] = 0;
2893         aId[ 6 ] = 0;
2894         rIStm.Read( aId, 6 );
2895 
2896         if ( !strcmp( aId, "VCLMTF" ) )
2897         {
2898             // new format
2899             VersionCompat*  pCompat;
2900             MetaAction*     pAction;
2901             sal_uInt32          nStmCompressMode = 0;
2902             sal_uInt32          nCount = 0;
2903 
2904             pCompat = new VersionCompat( rIStm, STREAM_READ );
2905 
2906             rIStm >> nStmCompressMode;
2907             rIStm >> rGDIMetaFile.aPrefMapMode;
2908             rIStm >> rGDIMetaFile.aPrefSize;
2909             rIStm >> nCount;
2910 
2911             delete pCompat;
2912 
2913             ImplMetaReadData aReadData;
2914             aReadData.meActualCharSet = rIStm.GetStreamCharSet();
2915 
2916             for( sal_uInt32 nAction = 0UL; ( nAction < nCount ) && !rIStm.IsEof(); nAction++ )
2917             {
2918                 pAction = MetaAction::ReadMetaAction( rIStm, &aReadData );
2919 
2920                 if( pAction )
2921                     rGDIMetaFile.AddAction( pAction );
2922             }
2923         }
2924         else
2925         {
2926             // to avoid possible compiler optimizations => new/delete
2927             rIStm.Seek( nStmPos );
2928             delete( new SVMConverter( rIStm, rGDIMetaFile, CONVERT_FROM_SVM1 ) );
2929         }
2930 
2931         // check for errors
2932         if( rIStm.GetError() )
2933         {
2934             rGDIMetaFile.Clear();
2935             rIStm.Seek( nStmPos );
2936         }
2937 
2938         rIStm.SetNumberFormatInt( nOldFormat );
2939     }
2940 
2941     return rIStm;
2942 }
2943 
2944 // ------------------------------------------------------------------------
2945 
operator <<(SvStream & rOStm,const GDIMetaFile & rGDIMetaFile)2946 SvStream& operator<<( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile )
2947 {
2948     if( !rOStm.GetError() )
2949     {
2950         static const char*  pEnableSVM1 = getenv( "SAL_ENABLE_SVM1" );
2951         static const bool   bNoSVM1 = (NULL == pEnableSVM1 ) || ( '0' == *pEnableSVM1 );
2952 
2953         if( bNoSVM1 || rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50  )
2954         {
2955             const_cast< GDIMetaFile& >( rGDIMetaFile ).Write( rOStm );
2956         }
2957         else
2958         {
2959             delete( new SVMConverter( rOStm, const_cast< GDIMetaFile& >( rGDIMetaFile ), CONVERT_TO_SVM1 ) );
2960         }
2961 
2962 #ifdef DEBUG
2963         if( !bNoSVM1 && rOStm.GetVersion() < SOFFICE_FILEFORMAT_50 )
2964         {
2965 OSL_TRACE( \
2966 "GDIMetaFile would normally be written in old SVM1 format by this call. \
2967 The current implementation always writes in VCLMTF format. \
2968 Please set environment variable SAL_ENABLE_SVM1 to '1' to reenable old behavior" );
2969         }
2970 #endif // DEBUG
2971     }
2972 
2973     return rOStm;
2974 }
2975 
2976 // ------------------------------------------------------------------------
2977 
Read(SvStream & rIStm)2978 SvStream& GDIMetaFile::Read( SvStream& rIStm )
2979 {
2980     Clear();
2981     rIStm >> *this;
2982 
2983     return rIStm;
2984 }
2985 
2986 // ------------------------------------------------------------------------
2987 
Write(SvStream & rOStm)2988 SvStream& GDIMetaFile::Write( SvStream& rOStm )
2989 {
2990     VersionCompat*  pCompat;
2991     const sal_uInt32    nStmCompressMode = rOStm.GetCompressMode();
2992     sal_uInt16          nOldFormat = rOStm.GetNumberFormatInt();
2993 
2994     rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
2995     rOStm.Write( "VCLMTF", 6 );
2996 
2997     pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 );
2998 
2999     rOStm << nStmCompressMode;
3000     rOStm << aPrefMapMode;
3001     rOStm << aPrefSize;
3002     rOStm << (sal_uInt32) GetActionCount();
3003 
3004     delete pCompat;
3005 
3006     ImplMetaWriteData aWriteData;
3007     aWriteData.meActualCharSet = rOStm.GetStreamCharSet();
3008 
3009     MetaAction* pAct = (MetaAction*)First();
3010     while ( pAct )
3011     {
3012         pAct->Write( rOStm, &aWriteData );
3013         pAct = (MetaAction*)Next();
3014     }
3015 
3016     rOStm.SetNumberFormatInt( nOldFormat );
3017 
3018     return rOStm;
3019 }
3020 
3021 // ------------------------------------------------------------------------
3022 
CreateThumbnail(sal_uInt32 nMaximumExtent,BitmapEx & rBmpEx,const BitmapEx * pOverlay,const Rectangle * pOverlayRect) const3023 sal_Bool GDIMetaFile::CreateThumbnail( sal_uInt32 nMaximumExtent,
3024                                     BitmapEx& rBmpEx,
3025                                     const BitmapEx* pOverlay,
3026                                     const Rectangle* pOverlayRect ) const
3027 {
3028     // the implementation is provided by KA
3029 
3030     // initialization seems to be complicated but is used to avoid rounding errors
3031     VirtualDevice   aVDev;
3032     const Point     aNullPt;
3033     const Point     aTLPix( aVDev.LogicToPixel( aNullPt, GetPrefMapMode() ) );
3034     const Point     aBRPix( aVDev.LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) );
3035     Size            aDrawSize( aVDev.LogicToPixel( GetPrefSize(), GetPrefMapMode() ) );
3036     Size            aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
3037     Point           aPosPix;
3038 
3039     if ( !rBmpEx.IsEmpty() )
3040         rBmpEx.SetEmpty();
3041 
3042     // determine size that has the same aspect ratio as image size and
3043     // fits into the rectangle determined by nMaximumExtent
3044     if ( aSizePix.Width() && aSizePix.Height()
3045       && ( sal::static_int_cast< unsigned long >(aSizePix.Width()) >
3046                nMaximumExtent ||
3047            sal::static_int_cast< unsigned long >(aSizePix.Height()) >
3048                nMaximumExtent ) )
3049     {
3050         const Size  aOldSizePix( aSizePix );
3051         double      fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height();
3052 
3053         if ( fWH <= 1.0 )
3054         {
3055             aSizePix.Width() = FRound( nMaximumExtent * fWH );
3056             aSizePix.Height() = nMaximumExtent;
3057         }
3058         else
3059         {
3060             aSizePix.Width() = nMaximumExtent;
3061             aSizePix.Height() = FRound(  nMaximumExtent / fWH );
3062         }
3063 
3064         aDrawSize.Width() = FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() );
3065         aDrawSize.Height() = FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() );
3066     }
3067 
3068     Size        aFullSize;
3069     Point       aBackPosPix;
3070     Rectangle   aOverlayRect;
3071 
3072     // calculate addigtional positions and sizes if an overlay image is used
3073     if (  pOverlay )
3074     {
3075         aFullSize = Size( nMaximumExtent, nMaximumExtent );
3076         aOverlayRect = Rectangle( aNullPt, aFullSize  );
3077 
3078         aOverlayRect.Intersection( pOverlayRect ? *pOverlayRect : Rectangle( aNullPt, pOverlay->GetSizePixel() ) );
3079 
3080         if ( !aOverlayRect.IsEmpty() )
3081             aBackPosPix = Point( ( nMaximumExtent - aSizePix.Width() ) >> 1, ( nMaximumExtent - aSizePix.Height() ) >> 1 );
3082         else
3083             pOverlay = NULL;
3084     }
3085     else
3086     {
3087         aFullSize = aSizePix;
3088         pOverlay = NULL;
3089     }
3090 
3091     // draw image(s) into VDev and get resulting image
3092     if ( aVDev.SetOutputSizePixel( aFullSize ) )
3093     {
3094         // draw metafile into VDev
3095         const_cast<GDIMetaFile *>(this)->WindStart();
3096         const_cast<GDIMetaFile *>(this)->Play( &aVDev, aBackPosPix, aDrawSize );
3097 
3098         // draw overlay if neccessary
3099         if ( pOverlay )
3100             aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), *pOverlay );
3101 
3102         // get paint bitmap
3103         Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
3104 
3105         // assure that we have a true color image
3106         if ( aBmp.GetBitCount() != 24 )
3107             aBmp.Convert( BMP_CONVERSION_24BIT );
3108 
3109         // create resulting mask bitmap with metafile output set to black
3110         GDIMetaFile aMonchromeMtf( GetMonochromeMtf( COL_BLACK ) );
3111         aVDev.DrawWallpaper( Rectangle( aNullPt, aSizePix ), Wallpaper( Color( COL_WHITE ) ) );
3112         aMonchromeMtf.WindStart();
3113         aMonchromeMtf.Play( &aVDev, aBackPosPix, aDrawSize );
3114 
3115         // watch for overlay mask
3116         if ( pOverlay  )
3117         {
3118             Bitmap aOverlayMergeBmp( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ) );
3119 
3120             // create ANDed resulting mask at overlay area
3121             if ( pOverlay->IsTransparent() )
3122                 aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), pOverlay->GetMask() );
3123             else
3124             {
3125                 aVDev.SetLineColor( COL_BLACK );
3126                 aVDev.SetFillColor( COL_BLACK );
3127                 aVDev.DrawRect( aOverlayRect);
3128             }
3129 
3130             aOverlayMergeBmp.CombineSimple( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ), BMP_COMBINE_AND );
3131             aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), aOverlayMergeBmp );
3132         }
3133 
3134         rBmpEx = BitmapEx( aBmp, aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
3135     }
3136 
3137     return !rBmpEx.IsEmpty();
3138 }
3139