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