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