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