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