xref: /trunk/main/svtools/source/filter/wmf/winmtf.cxx (revision 2925bb56)
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_svtools.hxx"
26 
27 
28 #include "winmtf.hxx"
29 #include <vcl/metaact.hxx>
30 #include <vcl/metric.hxx>
31 #include <rtl/tencinfo.h>
32 #include <vcl/svapp.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vos/mutex.hxx>
35 
36 // ------------------------------------------------------------------------
37 
38 #define WIN_MTF_MAX_CLIP_DEPTH 16
39 
ImpUpdateType()40 void WinMtfClipPath::ImpUpdateType()
41 {
42 	if ( !aPolyPoly.Count() )
43 		eType = EMPTY;
44 	else if ( aPolyPoly.IsRect() )
45 		eType = RECTANGLE;
46 	else
47 		eType = COMPLEX;
48 
49 	bNeedsUpdate = sal_True;
50 }
51 
IntersectClipRect(const Rectangle & rRect)52 void WinMtfClipPath::IntersectClipRect( const Rectangle& rRect )
53 {
54 	if ( !aPolyPoly.Count() )
55 		aPolyPoly = Polygon( rRect );
56 	else if ( nDepth < WIN_MTF_MAX_CLIP_DEPTH )
57 	{
58 		Polygon aPolygon( rRect );
59 		PolyPolygon aIntersection;
60 		PolyPolygon aPolyPolyRect( aPolygon );
61 		aPolyPoly.GetIntersection( aPolyPolyRect, aIntersection );
62 		aPolyPoly = aIntersection;
63 		nDepth++;
64 	}
65 	ImpUpdateType();
66 }
67 
ExcludeClipRect(const Rectangle & rRect)68 void WinMtfClipPath::ExcludeClipRect( const Rectangle& rRect )
69 {
70 	if ( aPolyPoly.Count() && ( nDepth < WIN_MTF_MAX_CLIP_DEPTH ) )
71 	{
72 		Polygon aPolygon( rRect );
73 		PolyPolygon aPolyPolyRect( aPolygon );
74 		PolyPolygon aDifference;
75 		aPolyPoly.GetDifference( aPolyPolyRect, aDifference );
76 		aPolyPoly = aDifference;
77 		nDepth++;
78 	}
79 	ImpUpdateType();
80 }
81 
SetClipPath(const PolyPolygon & rPolyPolygon,sal_Int32 nClippingMode)82 void WinMtfClipPath::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode )
83 {
84 	PolyPolygon aSimplePoly;
85 	if ( rPolyPolygon.Count() && rPolyPolygon[ 0 ].HasFlags() )
86 		rPolyPolygon.AdaptiveSubdivide( aSimplePoly, 100 );
87 	if ( !aSimplePoly.Count() )
88         aPolyPoly = aSimplePoly;
89 	else if ( nDepth < WIN_MTF_MAX_CLIP_DEPTH )
90 	{
91 		nDepth++;
92 
93 		PolyPolygon aNewClipPath;
94 
95         // #115345# Watch out for empty aPolyPoly here - conceptually,
96         // an empty clip path is a rectangle of infinite size, but it
97         // is represented by an empty aPolyPoly. When intersecting
98         // rPolyPolygon with this _empty_ aPolyPoly, set algebra
99         // guarantees wrong results.
100 		switch ( nClippingMode )
101 		{
102 			case RGN_OR :
103                 // #115345# clip stays empty, when ORing an arbitrary
104                 // rPolyPolygon. Thus, we can save us the unnecessary
105                 // clipper call.
106                 if( aPolyPoly.Count() )
107                     aPolyPoly.GetUnion( aSimplePoly, aNewClipPath );
108 			break;
109 			case RGN_XOR :
110                 // TODO:
111                 // #115345# Cannot handle this case, for the time being
112 				aPolyPoly.GetXOR( aSimplePoly, aNewClipPath );
113 			break;
114 			case RGN_DIFF :
115                 // TODO:
116                 // #115345# Cannot handle this case, for the time being
117 				aPolyPoly.GetDifference( aSimplePoly, aNewClipPath );
118 			break;
119 			case RGN_AND :
120                 // #115345# Clip becomes rPolyPolygon, when ANDing
121                 // with an arbitrary rPolyPolygon
122                 if( aPolyPoly.Count() )
123                     aPolyPoly.GetIntersection( aSimplePoly, aNewClipPath );
124                 else
125                     aNewClipPath = aSimplePoly;
126 			break;
127 			case RGN_COPY :
128 				aNewClipPath = aSimplePoly;
129 			break;
130 		}
131 		aPolyPoly = aNewClipPath;
132 	}
133 	ImpUpdateType();
134 }
135 
MoveClipRegion(const Size & rSize)136 void WinMtfClipPath::MoveClipRegion( const Size& rSize )
137 {
138 	aPolyPoly.Move( rSize.Width(), rSize.Height() );
139 	bNeedsUpdate = sal_True;
140 }
141 
142 // ------------------------------------------------------------------------
143 
AddPoint(const Point & rPoint)144 void WinMtfPathObj::AddPoint( const Point& rPoint )
145 {
146 	if ( bClosed )
147 		Insert( Polygon(), POLYPOLY_APPEND );
148 	Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ];
149 	rPoly.Insert( rPoly.GetSize(), rPoint, POLY_NORMAL );
150 	bClosed = sal_False;
151 }
152 
AddPolyLine(const Polygon & rPolyLine)153 void WinMtfPathObj::AddPolyLine( const Polygon& rPolyLine )
154 {
155 	if ( bClosed )
156 		Insert( Polygon(), POLYPOLY_APPEND );
157 	Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ];
158 	rPoly.Insert( rPoly.GetSize(), rPolyLine );
159 	bClosed = sal_False;
160 }
161 
AddPolygon(const Polygon & rPoly)162 void WinMtfPathObj::AddPolygon( const Polygon& rPoly )
163 {
164 	Insert( rPoly, POLYPOLY_APPEND );
165 	bClosed = sal_True;
166 }
167 
AddPolyPolygon(const PolyPolygon & rPolyPoly)168 void WinMtfPathObj::AddPolyPolygon( const PolyPolygon& rPolyPoly )
169 {
170 	sal_uInt16 i, nCount = rPolyPoly.Count();
171 	for ( i = 0; i < nCount; i++ )
172 		Insert( rPolyPoly[ i ], POLYPOLY_APPEND );
173 	bClosed = sal_True;
174 }
175 
ClosePath()176 void WinMtfPathObj::ClosePath()
177 {
178 	if ( Count() )
179 	{
180 		Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ];
181 		if ( rPoly.GetSize() > 2 )
182 		{
183 			Point aFirst( rPoly[ 0 ] );
184 			if ( aFirst != rPoly[ rPoly.GetSize() - 1 ] )
185 				rPoly.Insert( rPoly.GetSize(), aFirst, POLY_NORMAL );
186 		}
187 	}
188 	bClosed = sal_True;
189 }
190 
191 // ------------------------------------------------------------------------
192 
WinMtfFontStyle(LOGFONTW & rFont)193 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW& rFont )
194 {
195 	CharSet eCharSet;
196 	if ( ( rFont.lfCharSet == OEM_CHARSET ) || ( rFont.lfCharSet == DEFAULT_CHARSET ) )
197 		eCharSet = gsl_getSystemTextEncoding();
198 	else
199 		eCharSet = rtl_getTextEncodingFromWindowsCharset( rFont.lfCharSet );
200 	if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
201 		eCharSet = gsl_getSystemTextEncoding();
202 	aFont.SetCharSet( eCharSet );
203 	aFont.SetName( rFont.alfFaceName );
204 	FontFamily eFamily;
205 	switch ( rFont.lfPitchAndFamily & 0xf0 )
206 	{
207 		case FF_ROMAN:
208 			eFamily = FAMILY_ROMAN;
209 		break;
210 
211 		case FF_SWISS:
212 			eFamily = FAMILY_SWISS;
213 		break;
214 
215 		case FF_MODERN:
216 			eFamily = FAMILY_MODERN;
217 		break;
218 
219 		case FF_SCRIPT:
220 			eFamily = FAMILY_SCRIPT;
221 		break;
222 
223 		case FF_DECORATIVE:
224 			 eFamily = FAMILY_DECORATIVE;
225 		break;
226 
227 		default:
228 			eFamily = FAMILY_DONTKNOW;
229 		break;
230 	}
231 	aFont.SetFamily( eFamily );
232 
233 	FontPitch ePitch;
234 	switch ( rFont.lfPitchAndFamily & 0x0f )
235 	{
236 		case FIXED_PITCH:
237 			ePitch = PITCH_FIXED;
238 		break;
239 
240 		case DEFAULT_PITCH:
241 		case VARIABLE_PITCH:
242 		default:
243 			ePitch = PITCH_VARIABLE;
244 		break;
245 	}
246 	aFont.SetPitch( ePitch );
247 
248 	FontWeight eWeight;
249 	if( rFont.lfWeight <= FW_THIN )
250 		eWeight = WEIGHT_THIN;
251 	else if( rFont.lfWeight <= FW_ULTRALIGHT )
252 		eWeight = WEIGHT_ULTRALIGHT;
253 	else if( rFont.lfWeight <= FW_LIGHT )
254 		eWeight = WEIGHT_LIGHT;
255 	else if( rFont.lfWeight <  FW_MEDIUM )
256 		eWeight = WEIGHT_NORMAL;
257 	else if( rFont.lfWeight == FW_MEDIUM )
258 		eWeight = WEIGHT_MEDIUM;
259 	else if( rFont.lfWeight <= FW_SEMIBOLD )
260 		eWeight = WEIGHT_SEMIBOLD;
261 	else if( rFont.lfWeight <= FW_BOLD )
262 		eWeight = WEIGHT_BOLD;
263 	else if( rFont.lfWeight <= FW_ULTRABOLD )
264 		eWeight = WEIGHT_ULTRABOLD;
265 	else
266 		eWeight = WEIGHT_BLACK;
267 	aFont.SetWeight( eWeight );
268 
269 	if( rFont.lfItalic )
270 		aFont.SetItalic( ITALIC_NORMAL );
271 
272 	if( rFont.lfUnderline )
273 		aFont.SetUnderline( UNDERLINE_SINGLE );
274 
275 	if( rFont.lfStrikeOut )
276 		aFont.SetStrikeout( STRIKEOUT_SINGLE );
277 
278 	if ( rFont.lfOrientation )
279 		aFont.SetOrientation( (short)rFont.lfOrientation );
280 	else
281 		aFont.SetOrientation( (short)rFont.lfEscapement );
282 
283 	Size  aFontSize( Size( rFont.lfWidth, rFont.lfHeight ) );
284 	if ( rFont.lfHeight > 0 )
285 	{
286         // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
287         vos::OGuard aGuard( Application::GetSolarMutex() );
288 		VirtualDevice aVDev;
289 
290         // converting the cell height into a font height
291 		aFont.SetSize( aFontSize );
292 		aVDev.SetFont( aFont );
293 		FontMetric aMetric( aVDev.GetFontMetric() );
294 		long nHeight = aMetric.GetAscent() + aMetric.GetDescent();
295 		if ( nHeight )
296 		{
297 			double fHeight = ((double)aFontSize.Height() * rFont.lfHeight ) / nHeight;
298 			aFontSize.Height() = (sal_Int32)( fHeight + 0.5 );
299 		}
300 	}
301 	else if ( aFontSize.Height() < 0 )
302 		aFontSize.Height() *= -1;
303 
304 	if ( !rFont.lfWidth )
305 	{
306         // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
307         vos::OGuard aGuard( Application::GetSolarMutex() );
308 		VirtualDevice aVDev;
309 
310         aFont.SetSize( aFontSize );
311 		aVDev.SetFont( aFont );
312 		FontMetric aMetric( aVDev.GetFontMetric() );
313 		aFontSize.Width() = aMetric.GetWidth();
314 	}
315 
316 	aFont.SetSize( aFontSize );
317 };
318 
319 // ------------------------------------------------------------------------
320 
321 #ifdef WIN_MTF_ASSERT
WinMtfAssertHandler(const sal_Char * pAction,sal_uInt32 nFlags)322 void WinMtfAssertHandler( const sal_Char* pAction, sal_uInt32 nFlags )
323 {
324     static sal_Bool     bOnlyOnce;
325     static sal_Int32    nAssertCount;
326 
327     if ( nFlags & WIN_MTF_ASSERT_INIT )
328         nAssertCount = 0;
329     if ( nFlags & WIN_MTF_ASSERT_ONCE )
330        bOnlyOnce = sal_True;
331     if ( nFlags & WIN_MTF_ASSERT_MIFE )
332     {
333         if ( ( nAssertCount == 0 ) || ( bOnlyOnce == sal_False ) )
334         {
335             ByteString aText( "WMF/EMF Import: " );
336             if ( pAction )
337             {
338                 ByteString aAction( pAction );
339                 aText.Append( aAction );
340             }
341             aText.Append( " needs to be implemented (SJ)" );
342 	        DBG_ASSERT( 0, aText.GetBuffer() );
343         }
344         nAssertCount++;
345     }
346 }
347 #endif
348 
349 // ------------------------------------------------------------------------
350 
WinMtf(WinMtfOutput * pWinMtfOutput,SvStream & rStreamWMF,FilterConfigItem * pConfigItem)351 WinMtf::WinMtf( WinMtfOutput* pWinMtfOutput, SvStream& rStreamWMF, FilterConfigItem* pConfigItem ) :
352 	pOut				( pWinMtfOutput ),
353 	pWMF				( &rStreamWMF ),
354 	pFilterConfigItem	( pConfigItem )
355 {
356 #ifdef WIN_MTF_ASSERT
357     // we want to assert not implemented features, but we do this
358     // only once, so that nobody is handicaped by getting too much assertions
359     // I hope this will bring more testdocuments, without support of these
360     // testdocuments the implementation of missing features won't be possible. (SJ)
361     WinMtfAssertHandler( NULL, WIN_MTF_ASSERT_INIT | WIN_MTF_ASSERT_ONCE );
362 #endif
363 
364 	SvLockBytes *pLB = pWMF->GetLockBytes();
365 	if ( pLB )
366 		pLB->SetSynchronMode( sal_True );
367 
368 	nStartPos = pWMF->Tell();
369 
370 	pOut->SetDevOrg( Point() );
371 	if ( pFilterConfigItem )
372 	{
373 		xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
374 		if ( xStatusIndicator.is() )
375 		{
376 			rtl::OUString aMsg;
377 			xStatusIndicator->start( aMsg, 100 );
378 		}
379 	}
380 }
381 
382 // ------------------------------------------------------------------------
383 
~WinMtf()384 WinMtf::~WinMtf()
385 {
386 	delete pOut;
387 
388 	if ( xStatusIndicator.is() )
389 		xStatusIndicator->end();
390 }
391 
392 // ------------------------------------------------------------------------
393 
Callback(sal_uInt16 nPercent)394 void WinMtf::Callback( sal_uInt16 nPercent )
395 {
396 	if ( xStatusIndicator.is() )
397 		xStatusIndicator->setValue( nPercent );
398 }
399 
400 // ------------------------------------------------------------------------
401 
ReadColor()402 Color WinMtf::ReadColor()
403 {
404 	sal_uInt32 nColor;
405 	*pWMF >> nColor;
406 	return Color( (sal_uInt8)nColor, (sal_uInt8)( nColor >> 8 ), (sal_uInt8)( nColor >> 16 ) );
407 };
408 
409 //-----------------------------------------------------------------------------------
410 //-----------------------------------------------------------------------------------
411 //-----------------------------------------------------------------------------------
412 
ImplMap(const Point & rPt)413 Point WinMtfOutput::ImplMap( const Point& rPt )
414 {
415 	if ( mnWinExtX && mnWinExtY )
416 	{
417 		double fX2, fX = rPt.X();
418 		double fY2, fY = rPt.Y();
419 
420 		fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx;
421 		fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy;
422 
423 		if ( mnGfxMode == GM_COMPATIBLE )
424 		{
425 			switch( mnMapMode )
426 			{
427 				case MM_LOENGLISH :
428 				{
429 					fX2 -= mnWinOrgX;
430 					fY2  = mnWinOrgY-fY2;
431 					fX2 *= 25.40;
432 					fY2 *= 25.40;
433 					fX2 += mnDevOrgX;
434 					fY2 += mnDevOrgY;
435 				}
436 				break;
437 				case MM_HIENGLISH :
438 				{
439 					fX2 -= mnWinOrgX;
440 					fY2  = mnWinOrgY-fY2;
441 					fX2 *= 2.540;
442 					fY2 *= 2.540;
443 					fX2 += mnDevOrgX;
444 					fY2 += mnDevOrgY;
445 				}
446 				break;
447 				case MM_LOMETRIC :
448 				{
449 					fX2 -= mnWinOrgX;
450 					fY2  = mnWinOrgY-fY2;
451 					fX2 *= 10;
452 					fY2 *= 10;
453 					fX2 += mnDevOrgX;
454 					fY2 += mnDevOrgY;
455 				}
456 				break;
457 				case MM_HIMETRIC :
458 				{
459 					fX2 -= mnWinOrgX;
460 					fY2  = mnWinOrgY-fY2;
461 					fX2 += mnDevOrgX;
462 					fY2 += mnDevOrgY;
463 				}
464 				break;
465 				default :
466 				{
467 					fX2 -= mnWinOrgX;
468 					fY2 -= mnWinOrgY;
469 					fX2 /= mnWinExtX;
470 					fY2 /= mnWinExtY;
471 					fX2 *= mnDevWidth;
472 					fY2 *= mnDevHeight;
473 					fX2 += mnDevOrgX;
474 					fY2 += mnDevOrgY;	// fX2, fY2 now in device units
475 					fX2 *= (double)mnMillX * 100.0 / (double)mnPixX;
476 					fY2 *= (double)mnMillY * 100.0 / (double)mnPixY;
477 				}
478 				break;
479 			}
480 			fX2 -= mrclFrame.Left();
481 			fY2 -= mrclFrame.Top();
482 		}
483 		return Point( FRound( fX2 ), FRound( fY2 ) );
484 	}
485 	else
486 		return Point();
487 };
488 
489 // ------------------------------------------------------------------------
490 
ImplMap(const Size & rSz)491 Size WinMtfOutput::ImplMap( const Size& rSz )
492 {
493 	if ( mnWinExtX && mnWinExtY )
494 	{
495         // #121382# apply the whole WorldTransform, else a rotation will be misinterpreted
496 		double fWidth = rSz.Width() * maXForm.eM11 + rSz.Height() * maXForm.eM21;
497 		double fHeight = rSz.Width() * maXForm.eM12 + rSz.Height() * maXForm.eM22;
498 
499 		if ( mnGfxMode == GM_COMPATIBLE )
500 		{
501 			switch( mnMapMode )
502 			{
503 				case MM_LOENGLISH :
504 				{
505 					fWidth *= 25.40;
506 					fHeight*=-25.40;
507 				}
508 				break;
509 				case MM_HIENGLISH :
510 				{
511 					fWidth *= 2.540;
512 					fHeight*=-2.540;
513 				}
514 				break;
515 				case MM_LOMETRIC :
516 				{
517 					fWidth *= 10;
518 					fHeight*=-10;
519 				}
520 				break;
521 				case MM_HIMETRIC :
522 				{
523 					fHeight *= -1;
524 				}
525 				break;
526 				default :
527 				{
528 					fWidth /= mnWinExtX;
529 					fHeight /= mnWinExtY;
530 					fWidth *= mnDevWidth;
531 					fHeight *= mnDevHeight;
532 					fWidth *= (double)mnMillX * 100 / (double)mnPixX;
533 					fHeight *= (double)mnMillY * 100 / (double)mnPixY;
534 				}
535 				break;
536 			}
537 		}
538 		return Size( FRound( fWidth ), FRound( fHeight ) );
539 	}
540 	else
541 		return Size();
542 }
543 
544 //-----------------------------------------------------------------------------------
545 
ImplMap(const Rectangle & rRect)546 Rectangle WinMtfOutput::ImplMap( const Rectangle& rRect )
547 {
548 	return Rectangle( ImplMap( rRect.TopLeft() ), ImplMap( rRect.GetSize() ) );
549 }
550 
551 //-----------------------------------------------------------------------------------
552 
ImplMap(Font & rFont)553 void WinMtfOutput::ImplMap( Font& rFont )
554 {
555 	// !!! HACK: Wir setzen die Breite jetzt immer auf Null,
556 	// da OS die Breite unterschiedlich interpretieren;
557 	// muss spaeter in SV portabel gemacht werden ( KA 08.02.96 )
558 	Size  aFontSize = ImplMap ( rFont.GetSize() );
559 
560 	if( aFontSize.Height() < 0 )
561 		aFontSize.Height() *= -1;
562 
563 	rFont.SetSize( aFontSize );
564 
565 	if( ( mnWinExtX * mnWinExtY ) < 0 )
566 		rFont.SetOrientation( 3600 - rFont.GetOrientation() );
567 }
568 
569 //-----------------------------------------------------------------------------------
570 
ImplMap(Polygon & rPolygon)571 Polygon& WinMtfOutput::ImplMap( Polygon& rPolygon )
572 {
573 	sal_uInt16 nPoints = rPolygon.GetSize();
574 	for ( sal_uInt16 i = 0; i < nPoints; i++ )
575 	{
576 		rPolygon[ i ] = ImplMap( rPolygon[ i ] );
577 	}
578 	return rPolygon;
579 }
580 
581 //-----------------------------------------------------------------------------------
582 
ImplMap(PolyPolygon & rPolyPolygon)583 PolyPolygon& WinMtfOutput::ImplMap( PolyPolygon& rPolyPolygon )
584 {
585 	sal_uInt16 nPolys = rPolyPolygon.Count();
586 	for ( sal_uInt16 i = 0; i < nPolys; ImplMap( rPolyPolygon[ i++ ] ) ) ;
587 	return rPolyPolygon;
588 }
589 
590 //-----------------------------------------------------------------------------------
591 
SelectObject(sal_Int32 nIndex)592 void WinMtfOutput::SelectObject( sal_Int32 nIndex )
593 {
594 	GDIObj* pGDIObj = NULL;
595 
596 	if ( nIndex & ENHMETA_STOCK_OBJECT )
597 		pGDIObj = new GDIObj();
598 	else
599 	{
600 		nIndex &= 0xffff;		// zur Sicherheit: mehr als 65535 nicht zulassen
601 
602 		if ( (sal_uInt32)nIndex < vGDIObj.size() )
603 			pGDIObj = vGDIObj[ nIndex ];
604 	}
605 
606 	if( pGDIObj == NULL )
607 		return;
608 
609 	if ( nIndex & ENHMETA_STOCK_OBJECT )
610 	{
611 		sal_uInt16 nStockId = (sal_uInt8)nIndex;
612 		switch( nStockId )
613 		{
614 			case WHITE_BRUSH :
615 			{
616 				pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ) ) );
617 			}
618 			break;
619 			case LTGRAY_BRUSH :
620 			{
621 				pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_LIGHTGRAY ) ) );
622 			}
623 			break;
624 			case GRAY_BRUSH :
625 			case DKGRAY_BRUSH :
626 			{
627 				pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_GRAY ) ) );
628 			}
629 			break;
630 			case BLACK_BRUSH :
631 			{
632 				pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_BLACK ) ) );
633 			}
634 			break;
635 			case NULL_BRUSH :
636 			{
637 				pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_TRANSPARENT ), sal_True ) );
638 			}
639 			break;
640 			case WHITE_PEN :
641 			{
642 				pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_WHITE ) ) );
643 			}
644 			break;
645 			case BLACK_PEN :
646 			{
647 				pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_BLACK ) ) );
648 			}
649 			break;
650 			case NULL_PEN :
651 			{
652 				pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_TRANSPARENT ), sal_True ) );
653 			}
654 			break;
655 			default:
656 			break;
657 		}
658 	}
659 	if ( pGDIObj->pStyle )
660 	{
661 		switch( pGDIObj->eType )
662 		{
663 			case GDI_PEN :
664 				maLineStyle = (WinMtfLineStyle*)pGDIObj->pStyle;
665 			break;
666 			case GDI_BRUSH :
667 			{
668 				maFillStyle = (WinMtfFillStyle*)pGDIObj->pStyle;
669 				mbFillStyleSelected = sal_True;
670 			}
671 			break;
672 			case GDI_FONT :
673 				maFont = ((WinMtfFontStyle*)pGDIObj->pStyle)->aFont;
674 			break;
675 			default:
676 			break;  //  -Wall many options not handled.
677 		}
678 	}
679 	if ( nIndex & ENHMETA_STOCK_OBJECT )
680 		delete pGDIObj;
681 }
682 
683 //-----------------------------------------------------------------------------------
684 
SetFont(const Font & rFont)685 void WinMtfOutput::SetFont( const Font& rFont )
686 {
687 	maFont = rFont;
688 }
689 
690 //-----------------------------------------------------------------------------------
691 
GetFont() const692 const Font& WinMtfOutput::GetFont() const
693 {
694 	return maFont;
695 }
696 
697 //-----------------------------------------------------------------------------------
698 
SetTextLayoutMode(const sal_uInt32 nTextLayoutMode)699 void WinMtfOutput::SetTextLayoutMode( const sal_uInt32 nTextLayoutMode )
700 {
701 	mnTextLayoutMode = nTextLayoutMode;
702 }
703 
704 //-----------------------------------------------------------------------------------
705 
GetTextLayoutMode() const706 sal_uInt32 WinMtfOutput::GetTextLayoutMode() const
707 {
708 	return mnTextLayoutMode;
709 }
710 
711 //-----------------------------------------------------------------------------------
712 
SetBkMode(sal_uInt32 nMode)713 void WinMtfOutput::SetBkMode( sal_uInt32 nMode )
714 {
715 	mnBkMode = nMode;
716 }
717 
718 //-----------------------------------------------------------------------------------
719 
SetBkColor(const Color & rColor)720 void WinMtfOutput::SetBkColor( const Color& rColor )
721 {
722 	maBkColor = rColor;
723 }
724 
725 //-----------------------------------------------------------------------------------
726 
SetTextColor(const Color & rColor)727 void WinMtfOutput::SetTextColor( const Color& rColor )
728 {
729 	maTextColor = rColor;
730 }
731 
732 //-----------------------------------------------------------------------------------
733 
SetTextAlign(sal_uInt32 nAlign)734 void WinMtfOutput::SetTextAlign( sal_uInt32 nAlign )
735 {
736 	mnTextAlign = nAlign;
737 }
738 
739 //-----------------------------------------------------------------------------------
740 
ImplResizeObjectArry(sal_uInt32 nNewEntrys)741 void WinMtfOutput::ImplResizeObjectArry( sal_uInt32 nNewEntrys )
742 {
743 	sal_uInt32 i = vGDIObj.size();
744 	vGDIObj.resize( nNewEntrys );
745 	for ( ; i < nNewEntrys ; i++ )
746 		vGDIObj[ i ] = NULL;
747 }
748 
749 //-----------------------------------------------------------------------------------
750 
ImplDrawClippedPolyPolygon(const PolyPolygon & rPolyPoly)751 void WinMtfOutput::ImplDrawClippedPolyPolygon( const PolyPolygon& rPolyPoly )
752 {
753 	if ( rPolyPoly.Count() )
754 	{
755 		ImplSetNonPersistentLineColorTransparenz();
756 		if ( rPolyPoly.Count() == 1 )
757 		{
758 			if ( rPolyPoly.IsRect() )
759 				mpGDIMetaFile->AddAction( new MetaRectAction( rPolyPoly.GetBoundRect() ) );
760 			else
761 			{
762 				Polygon	aPoly( rPolyPoly[ 0 ] );
763 				sal_uInt16 nCount = aPoly.GetSize();
764 				if ( nCount )
765 				{
766 					if ( aPoly[ nCount - 1 ] != aPoly[ 0 ] )
767 					{
768 						Point aPoint( aPoly[ 0 ] );
769 						aPoly.Insert( nCount, aPoint );
770 					}
771 					mpGDIMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
772 				}
773 			}
774 		}
775 		else
776 			mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
777 	}
778 }
779 
780 
781 //-----------------------------------------------------------------------------------
782 
CreateObject(GDIObjectType eType,void * pStyle)783 void WinMtfOutput::CreateObject( GDIObjectType eType, void* pStyle )
784 {
785 	if ( pStyle )
786 	{
787 		if ( eType == GDI_FONT )
788 		{
789 			ImplMap( ((WinMtfFontStyle*)pStyle)->aFont );
790 			if (!((WinMtfFontStyle*)pStyle)->aFont.GetHeight() )
791 				((WinMtfFontStyle*)pStyle)->aFont.SetHeight( 423 );		// defaulting to 12pt
792 		}
793 		else if ( eType == GDI_PEN )
794 		{
795 			Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 );
796 			((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() );
797 			if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH )
798 			{
799 				aSize.Width() += 1;
800 				long nDotLen = ImplMap( aSize ).Width();
801 				((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen );
802 				((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen );
803 				((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 );
804 			}
805 		}
806 	}
807 	sal_uInt32 nIndex;
808 	for ( nIndex = 0; nIndex < vGDIObj.size(); nIndex++ )
809 	{
810 		if ( vGDIObj[ nIndex ] == NULL )
811 			break;
812 	}
813 	if ( nIndex == vGDIObj.size() )
814 		ImplResizeObjectArry( vGDIObj.size() + 16 );
815 
816 	vGDIObj[ nIndex ] = new GDIObj( eType, pStyle );
817 }
818 
819 //-----------------------------------------------------------------------------------
820 
CreateObject(sal_Int32 nIndex,GDIObjectType eType,void * pStyle)821 void WinMtfOutput::CreateObject( sal_Int32 nIndex, GDIObjectType eType, void* pStyle )
822 {
823 	if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
824 	{
825 		nIndex &= 0xffff;		// zur Sicherheit: mehr als 65535 nicht zulassen
826 		if ( pStyle )
827 		{
828 			if ( eType == GDI_FONT )
829 				ImplMap( ((WinMtfFontStyle*)pStyle)->aFont );
830 			else if ( eType == GDI_PEN )
831 			{
832 				Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 );
833 				((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() );
834 				if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH )
835 				{
836 					aSize.Width() += 1;
837 					long nDotLen = ImplMap( aSize ).Width();
838 					((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen );
839 					((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen );
840 					((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 );
841 				}
842 			}
843 		}
844 		if ( (sal_uInt32)nIndex >= vGDIObj.size() )
845 			ImplResizeObjectArry( nIndex + 16 );
846 
847 		if ( vGDIObj[ nIndex ] != NULL )
848 			delete vGDIObj[ nIndex ];
849 
850 		vGDIObj[ nIndex ] = new GDIObj( eType, pStyle );
851 	}
852 	else
853     {
854         switch ( eType )
855         {
856             case GDI_PEN :
857                 delete (WinMtfLineStyle*)pStyle;
858             break;
859             case GDI_BRUSH :
860                 delete (WinMtfFillStyle*)pStyle;
861             break;
862             case GDI_FONT :
863                 delete (WinMtfFontStyle*)pStyle;
864             break;
865 
866             default:
867                 DBG_ERROR( "unsupported style not deleted" );
868                 break;
869         }
870     }
871 }
872 
873 //-----------------------------------------------------------------------------------
874 
DeleteObject(sal_Int32 nIndex)875 void WinMtfOutput::DeleteObject( sal_Int32 nIndex )
876 {
877 	if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
878 	{
879         if ( (sal_uInt32)nIndex < vGDIObj.size() )
880         {
881 		    delete vGDIObj[ nIndex ];
882             vGDIObj[ nIndex ] = NULL;
883         }
884 	}
885 }
886 
887 //-----------------------------------------------------------------------------------
888 
IntersectClipRect(const Rectangle & rRect)889 void WinMtfOutput::IntersectClipRect( const Rectangle& rRect )
890 {
891 	aClipPath.IntersectClipRect( ImplMap( rRect ) );
892 }
893 
894 //-----------------------------------------------------------------------------------
895 
ExcludeClipRect(const Rectangle & rRect)896 void WinMtfOutput::ExcludeClipRect( const Rectangle& rRect )
897 {
898 	aClipPath.ExcludeClipRect( ImplMap( rRect ) );
899 }
900 
901 //-----------------------------------------------------------------------------------
902 
MoveClipRegion(const Size & rSize)903 void WinMtfOutput::MoveClipRegion( const Size& rSize )
904 {
905 	aClipPath.MoveClipRegion( ImplMap( rSize ) );
906 }
907 
SetClipPath(const PolyPolygon & rPolyPolygon,sal_Int32 nClippingMode,sal_Bool bIsMapped)908 void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, sal_Bool bIsMapped )
909 {
910 	if ( bIsMapped )
911 		aClipPath.SetClipPath( rPolyPolygon, nClippingMode );
912 	else
913 	{
914 		PolyPolygon aPP( rPolyPolygon );
915 		aClipPath.SetClipPath( ImplMap( aPP ), nClippingMode );
916 	}
917 }
918 
919 //-----------------------------------------------------------------------------------
920 //-----------------------------------------------------------------------------------
921 //-----------------------------------------------------------------------------------
922 
WinMtfOutput(GDIMetaFile & rGDIMetaFile)923 WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) :
924     mnLatestTextAlign   ( 0 ),
925 	mnTextAlign		    ( TA_LEFT | TA_TOP | TA_NOUPDATECP ),
926 	maLatestBkColor     ( 0x12345678 ),
927 	maBkColor			( COL_WHITE ),
928 	mnLatestTextLayoutMode( TEXT_LAYOUT_DEFAULT ),
929 	mnTextLayoutMode	( TEXT_LAYOUT_DEFAULT ),
930     mnLatestBkMode      ( 0 ),
931 	mnBkMode			( OPAQUE ),
932     meLatestRasterOp    ( ROP_INVERT ),
933 	meRasterOp			( ROP_OVERPAINT ),
934 	maActPos			( Point() ),
935 	mbNopMode			( sal_False ),
936 	mbFillStyleSelected	( sal_False ),
937 	mnGfxMode			( GM_COMPATIBLE ),
938     mnMapMode           ( MM_TEXT ),
939 	mnDevOrgX			( 0 ),
940 	mnDevOrgY			( 0 ),
941 	mnDevWidth			( 1 ),
942 	mnDevHeight			( 1 ),
943 	mnWinOrgX			( 0 ),
944 	mnWinOrgY			( 0 ),
945 	mnWinExtX			( 1 ),
946 	mnWinExtY			( 1 ),
947 	mnPixX				( 100 ),
948 	mnPixY				( 100 ),
949 	mnMillX				( 1 ),
950 	mnMillY				( 1 ),
951 	mpGDIMetaFile       ( &rGDIMetaFile )
952 {
953 	mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) );		// The original clipregion has to be on top
954 																			// of the stack so it can always be restored
955 																			// this is necessary to be able to support
956 																			// SetClipRgn( NULL ) and similar ClipRgn actions (SJ)
957 
958 	maFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Arial" )) );	// sj: #i57205#, we do have some scaling problems if using
959 	maFont.SetCharSet( gsl_getSystemTextEncoding() );						// the default font then most times a x11 font is used, we
960 	maFont.SetHeight( 423 );												// will prevent this defining a font
961 
962 	maLatestLineStyle.aLineColor = Color( 0x12, 0x34, 0x56 );
963 	maLatestFillStyle.aFillColor = Color( 0x12, 0x34, 0x56 );
964 
965 	mnRop = R2_BLACK + 1;
966 	SetRasterOp( R2_BLACK );
967 };
968 
969 //-----------------------------------------------------------------------------------
970 
~WinMtfOutput()971 WinMtfOutput::~WinMtfOutput()
972 {
973 	mpGDIMetaFile->AddAction( new MetaPopAction() );
974 	mpGDIMetaFile->SetPrefMapMode( MAP_100TH_MM );
975 	if ( mrclFrame.IsEmpty() )
976 		mpGDIMetaFile->SetPrefSize( Size( mnDevWidth, mnDevHeight ) );
977 	else
978 		mpGDIMetaFile->SetPrefSize( mrclFrame.GetSize() );
979 
980 	for ( sal_uInt32 i = 0; i < vGDIObj.size(); i++ )
981 		delete vGDIObj[ i ];
982 };
983 
984 //-----------------------------------------------------------------------------------
985 
UpdateClipRegion()986 void WinMtfOutput::UpdateClipRegion()
987 {
988 	if ( aClipPath.bNeedsUpdate )
989 	{
990 		aClipPath.bNeedsUpdate = sal_False;
991 
992 		mpGDIMetaFile->AddAction( new MetaPopAction() );                    // taking the orignal clipregion
993 		mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) );  //
994 
995 		switch ( aClipPath.GetType() )
996 		{
997 			case RECTANGLE :
998 			case COMPLEX :
999 			{
1000 //				we will not generate a RegionClipRegion Action, because this action
1001 //				cannot be saved to the wmf format - saving to wmf always happens
1002 //				if the placeholder graphic for ole objects is generated. (SJ)
1003 
1004 //				Region aClipRegion( aClipPath.GetClipPath() );
1005 //				mpGDIMetaFile->AddAction( new MetaISectRegionClipRegionAction( aClipRegion ) );
1006 
1007 				Rectangle aClipRect( aClipPath.GetClipPath().GetBoundRect() );
1008 				mpGDIMetaFile->AddAction( new MetaISectRectClipRegionAction( aClipRect ) );
1009 			}
1010 			break;
1011 			case EMPTY:
1012 			break;  // -Wall not handled.
1013 		}
1014 	}
1015 }
1016 
1017 //-----------------------------------------------------------------------------------
1018 
ImplSetNonPersistentLineColorTransparenz()1019 void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz()
1020 {
1021 	Color aColor(  COL_TRANSPARENT);
1022 	WinMtfLineStyle aTransparentLine( aColor, sal_True );
1023 	if ( ! ( maLatestLineStyle == aTransparentLine ) )
1024 	{
1025 		maLatestLineStyle = aTransparentLine;
1026 		mpGDIMetaFile->AddAction( new MetaLineColorAction( aTransparentLine.aLineColor, !aTransparentLine.bTransparent ) );
1027 	}
1028 }
1029 
1030 //-----------------------------------------------------------------------------------
1031 
UpdateLineStyle()1032 void WinMtfOutput::UpdateLineStyle()
1033 {
1034 	if (!( maLatestLineStyle == maLineStyle ) )
1035 	{
1036 		maLatestLineStyle = maLineStyle;
1037 		mpGDIMetaFile->AddAction( new MetaLineColorAction( maLineStyle.aLineColor, !maLineStyle.bTransparent ) );
1038 	}
1039 }
1040 
1041 //-----------------------------------------------------------------------------------
1042 
UpdateFillStyle()1043 void WinMtfOutput::UpdateFillStyle()
1044 {
1045 	if ( !mbFillStyleSelected )		// SJ: #i57205# taking care of bkcolor if no brush is selected
1046 		maFillStyle = WinMtfFillStyle( maBkColor, mnBkMode == TRANSPARENT );
1047 	if (!( maLatestFillStyle == maFillStyle ) )
1048 	{
1049 		maLatestFillStyle = maFillStyle;
1050 		mpGDIMetaFile->AddAction( new MetaFillColorAction( maFillStyle.aFillColor, !maFillStyle.bTransparent ) );
1051 	}
1052 }
1053 
1054 //-----------------------------------------------------------------------------------
1055 
SetRasterOp(sal_uInt32 nRasterOp)1056 sal_uInt32 WinMtfOutput::SetRasterOp( sal_uInt32 nRasterOp )
1057 {
1058 	sal_uInt32 nRetROP = mnRop;
1059 	if ( nRasterOp != mnRop )
1060 	{
1061 		mnRop = nRasterOp;
1062 		static WinMtfFillStyle aNopFillStyle;
1063 		static WinMtfLineStyle aNopLineStyle;
1064 
1065 		if ( mbNopMode && ( nRasterOp != R2_NOP ) )
1066 		{	// beim uebergang von R2_NOP auf anderen Modus
1067 			// gesetzten Pen und Brush aktivieren
1068 			maFillStyle = aNopFillStyle;
1069 			maLineStyle = aNopLineStyle;
1070 			mbNopMode = sal_False;
1071 		}
1072 		switch( nRasterOp )
1073 		{
1074 			case R2_NOT:
1075 				meRasterOp = ROP_INVERT;
1076 			break;
1077 
1078 			case R2_XORPEN:
1079 				meRasterOp = ROP_XOR;
1080 			break;
1081 
1082 			case R2_NOP:
1083 			{
1084 				meRasterOp = ROP_OVERPAINT;
1085 				if( mbNopMode == sal_False )
1086 				{
1087 					aNopFillStyle = maFillStyle;
1088 					aNopLineStyle = maLineStyle;
1089 					maFillStyle = WinMtfFillStyle( Color( COL_TRANSPARENT ), sal_True );
1090 					maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), sal_True );
1091 					mbNopMode = sal_True;
1092 				}
1093 			}
1094 			break;
1095 
1096 			default:
1097 				meRasterOp = ROP_OVERPAINT;
1098 			break;
1099 		}
1100 	}
1101 	if ( nRetROP != nRasterOp )
1102 		mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
1103 	return nRetROP;
1104 };
1105 
1106 //-----------------------------------------------------------------------------------
1107 
StrokeAndFillPath(sal_Bool bStroke,sal_Bool bFill)1108 void WinMtfOutput::StrokeAndFillPath( sal_Bool bStroke, sal_Bool bFill )
1109 {
1110 	if ( aPathObj.Count() )
1111 	{
1112 		UpdateClipRegion();
1113 		UpdateLineStyle();
1114 		UpdateFillStyle();
1115 		if ( bFill )
1116 		{
1117 			if ( !bStroke )
1118 			{
1119 				mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_LINECOLOR ) );
1120 				mpGDIMetaFile->AddAction( new MetaLineColorAction( Color(), sal_False ) );
1121 			}
1122 			if ( aPathObj.Count() == 1 )
1123 				mpGDIMetaFile->AddAction( new MetaPolygonAction( aPathObj.GetObject( 0 ) ) );
1124 			else
1125 				mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( aPathObj ) );
1126 
1127 			if ( !bStroke )
1128 				mpGDIMetaFile->AddAction( new MetaPopAction() );
1129 		}
1130 		else
1131 		{
1132 			sal_uInt16 i, nCount = aPathObj.Count();
1133 			for ( i = 0; i < nCount; i++ )
1134 				mpGDIMetaFile->AddAction( new MetaPolyLineAction( aPathObj[ i ], maLineStyle.aLineInfo ) );
1135 		}
1136 		ClearPath();
1137 	}
1138 }
1139 
1140 //-----------------------------------------------------------------------------------
1141 
DrawPixel(const Point & rSource,const Color & rColor)1142 void WinMtfOutput::DrawPixel( const Point& rSource, const Color& rColor )
1143 {
1144 	mpGDIMetaFile->AddAction( new MetaPixelAction( ImplMap( rSource), rColor ) );
1145 }
1146 
1147 //-----------------------------------------------------------------------------------
1148 
MoveTo(const Point & rPoint,sal_Bool bRecordPath)1149 void WinMtfOutput::MoveTo( const Point& rPoint, sal_Bool bRecordPath )
1150 {
1151     Point aDest( ImplMap( rPoint ) );
1152     if ( bRecordPath )
1153         aPathObj.AddPoint( aDest );
1154     maActPos = aDest;
1155 }
1156 
1157 //-----------------------------------------------------------------------------------
1158 
LineTo(const Point & rPoint,sal_Bool bRecordPath)1159 void WinMtfOutput::LineTo( const Point& rPoint, sal_Bool bRecordPath )
1160 {
1161 	UpdateClipRegion();
1162 
1163 	Point aDest( ImplMap( rPoint ) );
1164 	if ( bRecordPath )
1165 		aPathObj.AddPoint( aDest );
1166 	else
1167 	{
1168 		UpdateLineStyle();
1169 		mpGDIMetaFile->AddAction( new MetaLineAction( maActPos, aDest, maLineStyle.aLineInfo ) );
1170 	}
1171 	maActPos = aDest;
1172 }
1173 
1174 //-----------------------------------------------------------------------------------
1175 
DrawLine(const Point & rSource,const Point & rDest)1176 void WinMtfOutput::DrawLine( const Point& rSource, const Point& rDest )
1177 {
1178 	UpdateClipRegion();
1179 	UpdateLineStyle();
1180 	mpGDIMetaFile->AddAction( new MetaLineAction( ImplMap( rSource), ImplMap( rDest ), maLineStyle.aLineInfo ) );
1181 }
1182 
1183 //-----------------------------------------------------------------------------------
1184 
DrawRect(const Rectangle & rRect,sal_Bool bEdge)1185 void WinMtfOutput::DrawRect( const Rectangle& rRect, sal_Bool bEdge )
1186 {
1187 	UpdateClipRegion();
1188 	UpdateFillStyle();
1189 
1190 	if ( aClipPath.GetType() == COMPLEX )
1191 	{
1192 		Polygon aPoly( ImplMap( rRect ) );
1193 		PolyPolygon aPolyPolyRect( aPoly );
1194 		PolyPolygon aDest;
1195 		aClipPath.GetClipPath().GetIntersection( aPolyPolyRect, aDest );
1196 		ImplDrawClippedPolyPolygon( aDest );
1197 	}
1198 	else
1199 	{
1200 		if ( bEdge )
1201 		{
1202 			if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1203 			{
1204 				ImplSetNonPersistentLineColorTransparenz();
1205 				mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1206 				UpdateLineStyle();
1207 				mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( ImplMap( rRect ) ),maLineStyle.aLineInfo ) );
1208 			}
1209 			else
1210 			{
1211 				UpdateLineStyle();
1212 				mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1213 			}
1214 		}
1215 		else
1216 		{
1217 			ImplSetNonPersistentLineColorTransparenz();
1218 			mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1219 		}
1220 	}
1221 }
1222 
1223 //-----------------------------------------------------------------------------------
1224 
DrawRoundRect(const Rectangle & rRect,const Size & rSize)1225 void WinMtfOutput::DrawRoundRect( const Rectangle& rRect, const Size& rSize )
1226 {
1227 	UpdateClipRegion();
1228 	UpdateLineStyle();
1229 	UpdateFillStyle();
1230 	mpGDIMetaFile->AddAction( new MetaRoundRectAction( ImplMap( rRect ), labs( ImplMap( rSize ).Width() ), labs( ImplMap( rSize ).Height() ) ) );
1231 }
1232 
1233 //-----------------------------------------------------------------------------------
1234 
DrawEllipse(const Rectangle & rRect)1235 void WinMtfOutput::DrawEllipse( const Rectangle& rRect )
1236 {
1237 	UpdateClipRegion();
1238 	UpdateFillStyle();
1239 
1240 	if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1241 	{
1242 		Point aCenter( ImplMap( rRect.Center() ) );
1243 		Size  aRad( ImplMap( Size( rRect.GetWidth() / 2, rRect.GetHeight() / 2 ) ) );
1244 
1245 		ImplSetNonPersistentLineColorTransparenz();
1246 		mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) );
1247 		UpdateLineStyle();
1248 		mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) );
1249 	}
1250 	else
1251 	{
1252 		UpdateLineStyle();
1253 		mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) );
1254 	}
1255 }
1256 
1257 //-----------------------------------------------------------------------------------
1258 
DrawArc(const Rectangle & rRect,const Point & rStart,const Point & rEnd,sal_Bool bTo)1259 void WinMtfOutput::DrawArc( const Rectangle& rRect, const Point& rStart, const Point& rEnd, sal_Bool bTo )
1260 {
1261 	UpdateClipRegion();
1262 	UpdateLineStyle();
1263 	UpdateFillStyle();
1264 
1265 	Rectangle	aRect( ImplMap( rRect ) );
1266 	Point		aStart( ImplMap( rStart ) );
1267 	Point		aEnd( ImplMap( rEnd ) );
1268 
1269 	if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1270 	{
1271 		if ( aStart == aEnd )
1272 		{	// SJ: #i53768# if start & end is identical, then we have to draw a full ellipse
1273 			Point aCenter( aRect.Center() );
1274 			Size  aRad( aRect.GetWidth() / 2, aRect.GetHeight() / 2 );
1275 
1276 			mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) );
1277 		}
1278 		else
1279 			mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_ARC ), maLineStyle.aLineInfo ) );
1280 	}
1281 	else
1282 		mpGDIMetaFile->AddAction( new MetaArcAction( aRect, aStart, aEnd ) );
1283 
1284 	if ( bTo )
1285 		maActPos = aEnd;
1286 }
1287 
1288 //-----------------------------------------------------------------------------------
1289 
DrawPie(const Rectangle & rRect,const Point & rStart,const Point & rEnd)1290 void WinMtfOutput::DrawPie( const Rectangle& rRect, const Point& rStart, const Point& rEnd )
1291 {
1292 	UpdateClipRegion();
1293 	UpdateFillStyle();
1294 
1295 	Rectangle	aRect( ImplMap( rRect ) );
1296 	Point		aStart( ImplMap( rStart ) );
1297 	Point		aEnd( ImplMap( rEnd ) );
1298 
1299 	if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1300 	{
1301 		ImplSetNonPersistentLineColorTransparenz();
1302 		mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) );
1303 		UpdateLineStyle();
1304 		mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_PIE ), maLineStyle.aLineInfo ) );
1305 	}
1306 	else
1307 	{
1308 		UpdateLineStyle();
1309 		mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) );
1310 	}
1311 }
1312 
1313 //-----------------------------------------------------------------------------------
1314 
DrawChord(const Rectangle & rRect,const Point & rStart,const Point & rEnd)1315 void WinMtfOutput::DrawChord( const Rectangle& rRect, const Point& rStart, const Point& rEnd )
1316 {
1317 	UpdateClipRegion();
1318 	UpdateFillStyle();
1319 
1320 	Rectangle	aRect( ImplMap( rRect ) );
1321 	Point		aStart( ImplMap( rStart ) );
1322 	Point		aEnd( ImplMap( rEnd ) );
1323 
1324 	if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1325 	{
1326 		ImplSetNonPersistentLineColorTransparenz();
1327 		mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) );
1328 		UpdateLineStyle();
1329 		mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_CHORD ), maLineStyle.aLineInfo ) );
1330 	}
1331 	else
1332 	{
1333 		UpdateLineStyle();
1334 		mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) );
1335 	}
1336 }
1337 
1338 //-----------------------------------------------------------------------------------
1339 
DrawPolygon(Polygon & rPolygon,sal_Bool bRecordPath)1340 void WinMtfOutput::DrawPolygon( Polygon& rPolygon, sal_Bool bRecordPath )
1341 {
1342 	UpdateClipRegion();
1343 	ImplMap( rPolygon );
1344 	if ( bRecordPath )
1345 		aPathObj.AddPolygon( rPolygon );
1346 	else
1347 	{
1348 		UpdateFillStyle();
1349 
1350 		if ( aClipPath.GetType() == COMPLEX )
1351 		{
1352 			PolyPolygon aPolyPoly( rPolygon );
1353 			PolyPolygon aDest;
1354 			aClipPath.GetClipPath().GetIntersection( aPolyPoly, aDest );
1355 			ImplDrawClippedPolyPolygon( aDest );
1356 		}
1357 		else
1358 		{
1359 			if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1360 			{
1361 				sal_uInt16 nCount = rPolygon.GetSize();
1362 				if ( nCount )
1363 				{
1364 					if ( rPolygon[ nCount - 1 ] != rPolygon[ 0 ] )
1365 					{
1366 						Point aPoint( rPolygon[ 0 ] );
1367 						rPolygon.Insert( nCount, aPoint );
1368 					}
1369 				}
1370 				ImplSetNonPersistentLineColorTransparenz();
1371 				mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) );
1372 				UpdateLineStyle();
1373 				mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1374 			}
1375 			else
1376 			{
1377 				UpdateLineStyle();
1378 				mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) );
1379 			}
1380 		}
1381 	}
1382 }
1383 
1384 //-----------------------------------------------------------------------------------
1385 
DrawPolyPolygon(PolyPolygon & rPolyPolygon,sal_Bool bRecordPath)1386 void WinMtfOutput::DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordPath )
1387 {
1388 	UpdateClipRegion();
1389 
1390 	ImplMap( rPolyPolygon );
1391 
1392 	if ( bRecordPath )
1393 		aPathObj.AddPolyPolygon( rPolyPolygon );
1394 	else
1395 	{
1396 		UpdateFillStyle();
1397 
1398 		if ( aClipPath.GetType() == COMPLEX )
1399 		{
1400 			PolyPolygon aDest;
1401 			aClipPath.GetClipPath().GetIntersection( rPolyPolygon, aDest );
1402 			ImplDrawClippedPolyPolygon( aDest );
1403 		}
1404 		else
1405 		{
1406 			UpdateLineStyle();
1407 			mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPolygon ) );
1408 		}
1409 	}
1410 }
1411 
1412 //-----------------------------------------------------------------------------------
1413 
DrawPolyLine(Polygon & rPolygon,sal_Bool bTo,sal_Bool bRecordPath)1414 void WinMtfOutput::DrawPolyLine( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath )
1415 {
1416 	UpdateClipRegion();
1417 
1418 	ImplMap( rPolygon );
1419 	if ( bTo )
1420 	{
1421 		rPolygon[ 0 ] = maActPos;
1422 		maActPos = rPolygon[ rPolygon.GetSize() - 1 ];
1423 	}
1424 	if ( bRecordPath )
1425 		aPathObj.AddPolyLine( rPolygon );
1426 	else
1427 	{
1428 		UpdateLineStyle();
1429 		mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1430 	}
1431 }
1432 
1433 //-----------------------------------------------------------------------------------
1434 
DrawPolyBezier(Polygon & rPolygon,sal_Bool bTo,sal_Bool bRecordPath)1435 void WinMtfOutput::DrawPolyBezier( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath )
1436 {
1437 	UpdateClipRegion();
1438 
1439 	sal_uInt16 nPoints = rPolygon.GetSize();
1440 	if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) )
1441 	{
1442 		ImplMap( rPolygon );
1443 		if ( bTo )
1444 		{
1445 			rPolygon[ 0 ] = maActPos;
1446 			maActPos = rPolygon[ nPoints - 1 ];
1447 		}
1448 		sal_uInt16 i;
1449 		for ( i = 0; ( i + 2 ) < nPoints; )
1450 		{
1451 			rPolygon.SetFlags( i++, POLY_NORMAL );
1452 			rPolygon.SetFlags( i++, POLY_CONTROL );
1453 			rPolygon.SetFlags( i++, POLY_CONTROL );
1454 		}
1455 		if ( bRecordPath )
1456 			aPathObj.AddPolyLine( rPolygon );
1457 		else
1458 		{
1459 			UpdateLineStyle();
1460 			mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1461 		}
1462 	}
1463 }
1464 
1465 //-----------------------------------------------------------------------------------
1466 
DrawText(Point & rPosition,String & rText,sal_Int32 * pDXArry,sal_Bool bRecordPath,sal_Int32 nGfxMode)1467 void WinMtfOutput::DrawText( Point& rPosition, String& rText, sal_Int32* pDXArry, sal_Bool bRecordPath, sal_Int32 nGfxMode )
1468 {
1469     UpdateClipRegion();
1470 	rPosition = ImplMap( rPosition );
1471 	sal_Int32 nOldGfxMode = GetGfxMode();
1472 	SetGfxMode( GM_COMPATIBLE );
1473 
1474     if ( pDXArry )
1475 	{
1476 		sal_Int32 i, nSum, nLen = rText.Len();
1477 
1478 		for( i = 0, nSum = 0; i < nLen; i++ )
1479 		{
1480             // #121382# Map DXArray using WorldTransform
1481             const Size aSize(ImplMap(Size( pDXArry[i], 0)));
1482             const basegfx::B2DVector aVector(aSize.Width(), aSize.Height());
1483             const sal_Int32 nTemp(basegfx::fround(aVector.getLength()));
1484 			nSum += nTemp;
1485 			pDXArry[ i ] = nSum;
1486 		}
1487 	}
1488 	if ( mnLatestTextLayoutMode != mnTextLayoutMode )
1489 	{
1490 		mnLatestTextLayoutMode = mnTextLayoutMode;
1491 		mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) );
1492 	}
1493 	SetGfxMode( nGfxMode );
1494     sal_Bool bChangeFont = sal_False;
1495     if ( mnLatestTextAlign != mnTextAlign )
1496     {
1497         bChangeFont = sal_True;
1498         mnLatestTextAlign = mnTextAlign;
1499         TextAlign eTextAlign;
1500 		if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
1501 			eTextAlign = ALIGN_BASELINE;
1502 		else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
1503 			eTextAlign = ALIGN_BOTTOM;
1504 		else
1505 			eTextAlign = ALIGN_TOP;
1506 		mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) );
1507     }
1508     if ( maLatestTextColor != maTextColor )
1509     {
1510         bChangeFont = sal_True;
1511         maLatestTextColor = maTextColor;
1512 		mpGDIMetaFile->AddAction( new MetaTextColorAction( maTextColor ) );
1513     }
1514     sal_Bool bChangeFillColor = sal_False;
1515     if ( maLatestBkColor != maBkColor )
1516     {
1517         bChangeFillColor = sal_True;
1518         maLatestBkColor = maBkColor;
1519     }
1520     if ( mnLatestBkMode != mnBkMode )
1521     {
1522         bChangeFillColor = sal_True;
1523         mnLatestBkMode = mnBkMode;
1524     }
1525     if ( bChangeFillColor )
1526     {
1527         bChangeFont = sal_True;
1528 		mpGDIMetaFile->AddAction( new MetaTextFillColorAction( maFont.GetFillColor(), !maFont.IsTransparent() ) );
1529     }
1530     Font aTmp( maFont );
1531     aTmp.SetColor( maTextColor );
1532     aTmp.SetFillColor( maBkColor );
1533 
1534     if( mnBkMode == TRANSPARENT )
1535 		aTmp.SetTransparent( sal_True );
1536 	else
1537 		aTmp.SetTransparent( sal_False );
1538 
1539 	if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
1540 		aTmp.SetAlign( ALIGN_BASELINE );
1541 	else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
1542 		aTmp.SetAlign( ALIGN_BOTTOM );
1543 	else
1544 		aTmp.SetAlign( ALIGN_TOP );
1545 
1546 	if ( nGfxMode == GM_ADVANCED )
1547 	{
1548 		// check whether there is a font rotation applied via transformation
1549 		Point aP1( ImplMap( Point() ) );
1550 		Point aP2( ImplMap( Point( 0, 100 ) ) );
1551 		aP2.X() -= aP1.X();
1552 		aP2.Y() -= aP1.Y();
1553 		double fX = aP2.X();
1554 		double fY = aP2.Y();
1555 		if ( fX )
1556 		{
1557 			double fOrientation = acos( fX / sqrt( fX * fX + fY * fY ) ) * 57.29577951308;
1558 			if ( fY > 0 )
1559 				fOrientation = 360 - fOrientation;
1560 			fOrientation += 90;
1561 			fOrientation *= 10;
1562 			fOrientation += aTmp.GetOrientation();
1563 			aTmp.SetOrientation( sal_Int16( fOrientation ) );
1564 		}
1565 	}
1566 
1567 	if( mnTextAlign & ( TA_UPDATECP | TA_RIGHT_CENTER ) )
1568 	{
1569         // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
1570         vos::OGuard aGuard( Application::GetSolarMutex() );
1571 	    VirtualDevice aVDev;
1572 		sal_Int32 nTextWidth;
1573 
1574         aVDev.SetMapMode( MapMode( MAP_100TH_MM ) );
1575 		aVDev.SetFont( maFont );
1576 
1577         if( pDXArry )
1578 		{
1579 			sal_uInt32 nLen = rText.Len();
1580 			nTextWidth = aVDev.GetTextWidth( rText.GetChar( (sal_uInt16)( nLen - 1 ) ) );
1581 			if( nLen > 1 )
1582 				nTextWidth += pDXArry[ nLen - 2 ];
1583 		}
1584 		else
1585 			nTextWidth = aVDev.GetTextWidth( rText );
1586 
1587 		if( mnTextAlign & TA_UPDATECP )
1588 			rPosition = maActPos;
1589 
1590 		if ( mnTextAlign & TA_RIGHT_CENTER )
1591 		{
1592 			double fLenght = ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1;
1593 			rPosition.X() -= (sal_Int32)( fLenght * cos( maFont.GetOrientation() * F_PI1800 ) );
1594 			rPosition.Y() -= (sal_Int32)(-( fLenght * sin( maFont.GetOrientation() * F_PI1800 ) ) );
1595 		}
1596 
1597 		if( mnTextAlign & TA_UPDATECP )
1598 			maActPos.X() = rPosition.X() + nTextWidth;
1599 	}
1600 	if ( bChangeFont || ( maLatestFont != aTmp ) )
1601     {
1602 		maLatestFont = aTmp;
1603         mpGDIMetaFile->AddAction( new MetaFontAction( aTmp ) );
1604         mpGDIMetaFile->AddAction( new MetaTextAlignAction( aTmp.GetAlign() ) );
1605         mpGDIMetaFile->AddAction( new MetaTextColorAction( aTmp.GetColor() ) );
1606         mpGDIMetaFile->AddAction( new MetaTextFillColorAction( aTmp.GetFillColor(), !aTmp.IsTransparent() ) );
1607     }
1608 	if ( bRecordPath )
1609 	{
1610 		// ToDo
1611 	}
1612 	else
1613 	{
1614 		/* because text without dx array is badly scaled, we
1615 		   will create such an array if necessary */
1616 		sal_Int32* pDX = pDXArry;
1617 		if ( !pDXArry )
1618 		{
1619             // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
1620             vos::OGuard aGuard( Application::GetSolarMutex() );
1621 	        VirtualDevice aVDev;
1622 
1623             pDX = new sal_Int32[ rText.Len() ];
1624 			aVDev.SetMapMode( MAP_100TH_MM );
1625 			aVDev.SetFont( maLatestFont );
1626 			aVDev.GetTextArray( rText, pDX, 0, STRING_LEN );
1627 		}
1628 		mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, STRING_LEN ) );
1629 		if ( !pDXArry )		// this means we have created our own array
1630 			delete[] pDX;	// which must be deleted
1631 	}
1632 	SetGfxMode( nOldGfxMode );
1633 }
1634 
1635 //-----------------------------------------------------------------------------------
1636 
ImplDrawBitmap(const Point & rPos,const Size & rSize,const BitmapEx rBitmap)1637 void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx rBitmap )
1638 {
1639 	BitmapEx aBmpEx( rBitmap );
1640 	if ( aClipPath.GetType() == COMPLEX )
1641 	{
1642         VirtualDevice aVDev;
1643 		MapMode aMapMode( MAP_100TH_MM );
1644 		aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) );
1645 		const Size aOutputSizePixel( aVDev.LogicToPixel( rSize, aMapMode ) );
1646 		const Size aSizePixel( rBitmap.GetSizePixel() );
1647 		if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() )
1648 		{
1649 			aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) );
1650 			aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) );
1651 		}
1652 		aVDev.SetMapMode( aMapMode );
1653 		aVDev.SetOutputSizePixel( aSizePixel );
1654 		aVDev.SetFillColor( Color( COL_BLACK ) );
1655 		const PolyPolygon aClip( aClipPath.GetClipPath() );
1656 		aVDev.DrawPolyPolygon( aClip );
1657         const Point aEmptyPoint;
1658 
1659         // #i50672# Extract whole VDev content (to match size of rBitmap)
1660         aVDev.EnableMapMode( sal_False );
1661 		Bitmap aMask( aVDev.GetBitmap( aEmptyPoint, aSizePixel ).CreateMask( Color( COL_WHITE ) ) );
1662 
1663 		if ( aBmpEx.IsTransparent() )
1664 		{
1665 			if ( rBitmap.GetTransparentColor() == Color( COL_WHITE ) )
1666 				aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_OR );
1667 			else
1668 				aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_AND );
1669 			aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask );
1670 		}
1671 		else
1672 			aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask );
1673 	}
1674 	if ( aBmpEx.IsTransparent() )
1675 		mpGDIMetaFile->AddAction( new MetaBmpExScaleAction( rPos, rSize, aBmpEx ) );
1676 	else
1677 		mpGDIMetaFile->AddAction( new MetaBmpScaleAction( rPos, rSize, aBmpEx.GetBitmap() ) );
1678 }
1679 
1680 //-----------------------------------------------------------------------------------
1681 
ResolveBitmapActions(List & rSaveList)1682 void WinMtfOutput::ResolveBitmapActions( List& rSaveList )
1683 {
1684 	UpdateClipRegion();
1685 
1686 	sal_uInt32 nObjects		= rSaveList.Count();
1687 	sal_uInt32 nObjectsLeft	= nObjects;
1688 
1689 	while ( nObjectsLeft )
1690 	{
1691 		sal_uInt32		i, nObjectsOfSameSize = 0;
1692 		sal_uInt32		nObjectStartIndex = nObjects - nObjectsLeft;
1693 
1694 		BSaveStruct*	pSave = (BSaveStruct*)rSaveList.GetObject( nObjectStartIndex );
1695 		Rectangle		aRect( pSave->aOutRect );
1696 
1697 		for ( i = nObjectStartIndex; i < nObjects; )
1698 		{
1699 			nObjectsOfSameSize++;
1700 			if ( ++i < nObjects )
1701 			{
1702 				pSave = (BSaveStruct*)rSaveList.GetObject( i );
1703 				if ( pSave->aOutRect != aRect )
1704 					break;
1705 			}
1706 		}
1707 		Point	aPos( ImplMap( aRect.TopLeft() ) );
1708 		Size	aSize( ImplMap( aRect.GetSize() ) );
1709 
1710 		for ( i = nObjectStartIndex; i < ( nObjectStartIndex + nObjectsOfSameSize ); i++ )
1711 		{
1712 			pSave = (BSaveStruct*)rSaveList.GetObject( i );
1713 
1714 			sal_uInt32	nWinRop = pSave->nWinRop;
1715 			sal_uInt8	nRasterOperation = (sal_uInt8)( nWinRop >> 16 );
1716 
1717 			sal_uInt32	nUsed =  0;
1718 			if ( ( nRasterOperation & 0xf )  != ( nRasterOperation >> 4 ) )
1719 				nUsed |= 1;		// pattern is used
1720 			if ( ( nRasterOperation & 0x33 ) != ( ( nRasterOperation & 0xcc ) >> 2 ) )
1721 				nUsed |= 2;		// source is used
1722 			if ( ( nRasterOperation & 0xaa ) != ( ( nRasterOperation & 0x55 ) << 1 ) )
1723 				nUsed |= 4;		// destination is used
1724 
1725 			if ( (nUsed & 1) && (( nUsed & 2 ) == 0) )
1726 			{	// patterns aren't well supported yet
1727 				sal_uInt32 nOldRop = SetRasterOp( ROP_OVERPAINT );	// in this case nRasterOperation is either 0 or 0xff
1728 				UpdateFillStyle();
1729 				DrawRect( aRect, sal_False );
1730 				SetRasterOp( nOldRop );
1731 			}
1732 			else
1733 			{
1734 				sal_Bool bDrawn = sal_False;
1735 
1736 				if ( i == nObjectStartIndex )	// optimizing, sometimes it is possible to create just one transparent bitmap
1737 				{
1738 					if ( nObjectsOfSameSize == 2 )
1739 					{
1740 						BSaveStruct* pSave2 = (BSaveStruct*)rSaveList.GetObject( i + 1 );
1741                         if ( ( pSave->aBmp.GetPrefSize() == pSave2->aBmp.GetPrefSize() ) &&
1742                              ( pSave->aBmp.GetPrefMapMode() == pSave2->aBmp.GetPrefMapMode() ) )
1743                         {
1744                             // TODO: Strictly speaking, we should
1745                             // check whether mask is monochrome, and
1746                             // whether image is black (upper branch)
1747                             // or white (lower branch). Otherwise, the
1748                             // effect is not the same as a masked
1749                             // bitmap.
1750                             if ( ( nWinRop == SRCPAINT ) && ( pSave2->nWinRop == SRCAND ) )
1751                             {
1752 								Bitmap aMask( pSave->aBmp ); aMask.Invert();
1753 								BitmapEx aBmpEx( pSave2->aBmp, aMask );
1754 								ImplDrawBitmap( aPos, aSize, aBmpEx );
1755 								bDrawn = sal_True;
1756 								i++;
1757 							}
1758                             // #i20085# This is just the other way
1759                             // around as above. Only difference: mask
1760                             // is inverted
1761                             else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCPAINT ) )
1762                             {
1763 								Bitmap aMask( pSave->aBmp );
1764 								BitmapEx aBmpEx( pSave2->aBmp, aMask );
1765 								ImplDrawBitmap( aPos, aSize, aBmpEx );
1766 								bDrawn = sal_True;
1767 								i++;
1768                             }
1769                         }
1770 					}
1771 				}
1772 
1773 				if ( !bDrawn )
1774 				{
1775 					Push();
1776 					sal_uInt32	nOldRop = SetRasterOp( R2_COPYPEN );
1777 					Bitmap		aBitmap( pSave->aBmp );
1778 					sal_uInt32	nOperation = ( nRasterOperation & 0xf );
1779 					switch( nOperation )
1780 					{
1781 						case 0x1 :
1782 						case 0xe :
1783 						{
1784 							SetRasterOp( R2_XORPEN );
1785 							ImplDrawBitmap( aPos, aSize, aBitmap );
1786 							SetRasterOp( R2_COPYPEN );
1787 							Bitmap	aMask( aBitmap );
1788 							aMask.Invert();
1789 							BitmapEx aBmpEx( aBitmap, aMask );
1790 							ImplDrawBitmap( aPos, aSize, aBmpEx );
1791 							if ( nOperation == 0x1 )
1792 							{
1793 								SetRasterOp( R2_NOT );
1794 								DrawRect( aRect, sal_False );
1795 							}
1796 						}
1797 						break;
1798 						case 0x7 :
1799 						case 0x8 :
1800 						{
1801 							Bitmap	aMask( aBitmap );
1802 							if ( ( nUsed & 1 ) && ( nRasterOperation & 0xb0 ) == 0xb0 )		// pattern used
1803 							{
1804 								aBitmap.Convert( BMP_CONVERSION_24BIT );
1805 								aBitmap.Erase( maFillStyle.aFillColor );
1806 							}
1807 							BitmapEx aBmpEx( aBitmap, aMask );
1808 							ImplDrawBitmap( aPos, aSize, aBmpEx );
1809 							if ( nOperation == 0x7 )
1810 							{
1811 								SetRasterOp( R2_NOT );
1812 								DrawRect( aRect, sal_False );
1813 							}
1814 						}
1815 						break;
1816 
1817 						case 0x4 :
1818 						case 0xb :
1819 						{
1820 							SetRasterOp( R2_NOT );
1821 							DrawRect( aRect, sal_False );
1822 							SetRasterOp( R2_COPYPEN );
1823 							Bitmap	aMask( aBitmap );
1824 							aBitmap.Invert();
1825 							BitmapEx aBmpEx( aBitmap, aMask );
1826 							ImplDrawBitmap( aPos, aSize, aBmpEx );
1827 							SetRasterOp( R2_XORPEN );
1828 							ImplDrawBitmap( aPos, aSize, aBitmap );
1829 							if ( nOperation == 0xb )
1830 							{
1831 								SetRasterOp( R2_NOT );
1832 								DrawRect( aRect, sal_False );
1833 							}
1834 						}
1835 						break;
1836 
1837 						case 0x2 :
1838 						case 0xd :
1839 						{
1840 							Bitmap	aMask( aBitmap );
1841 							aMask.Invert();
1842 							BitmapEx aBmpEx( aBitmap, aMask );
1843 							ImplDrawBitmap( aPos, aSize, aBmpEx );
1844 							SetRasterOp( R2_XORPEN );
1845 							ImplDrawBitmap( aPos, aSize, aBitmap );
1846 							if ( nOperation == 0xd )
1847 							{
1848 								SetRasterOp( R2_NOT );
1849 								DrawRect( aRect, sal_False );
1850 							}
1851 						}
1852 						break;
1853 						case 0x6 :
1854 						case 0x9 :
1855 						{
1856 							SetRasterOp( R2_XORPEN );
1857 							ImplDrawBitmap( aPos, aSize, aBitmap );
1858 							if ( nOperation == 0x9 )
1859 							{
1860 								SetRasterOp( R2_NOT );
1861 								DrawRect( aRect, sal_False );
1862 							}
1863 						}
1864 						break;
1865 
1866 						case 0x0 :	// WHITENESS
1867 						case 0xf :	// BLACKNESS
1868 						{													// in this case nRasterOperation is either 0 or 0xff
1869 							maFillStyle = WinMtfFillStyle( Color( nRasterOperation, nRasterOperation, nRasterOperation ) );
1870 							UpdateFillStyle();
1871 							DrawRect( aRect, sal_False );
1872 						}
1873 						break;
1874 
1875 						case 0x3 :	// only source is used
1876 						case 0xc :
1877 						{
1878 							if ( nRasterOperation == 0x33 )
1879 								aBitmap.Invert();
1880 							ImplDrawBitmap( aPos, aSize, aBitmap );
1881 						}
1882 						break;
1883 
1884 						case 0x5 :	// only destination is used
1885 						{
1886 							SetRasterOp( R2_NOT );
1887 							DrawRect( aRect, sal_False );
1888 						}
1889 						case 0xa :	// no operation
1890 						break;
1891 					}
1892 					SetRasterOp( nOldRop );
1893 					Pop();
1894 				}
1895 			}
1896 		}
1897 		nObjectsLeft -= nObjectsOfSameSize;
1898 	}
1899 
1900 	void* pPtr;
1901 	for ( pPtr = rSaveList.First(); pPtr; pPtr = rSaveList.Next() )
1902 		delete (BSaveStruct*)pPtr;
1903 	rSaveList.Clear();
1904 }
1905 
1906 //-----------------------------------------------------------------------------------
1907 
SetDevOrg(const Point & rPoint)1908 void WinMtfOutput::SetDevOrg( const Point& rPoint )
1909 {
1910 	mnDevOrgX = rPoint.X();
1911 	mnDevOrgY = rPoint.Y();
1912 }
1913 
1914 //-----------------------------------------------------------------------------------
1915 
SetDevOrgOffset(sal_Int32 nXAdd,sal_Int32 nYAdd)1916 void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
1917 {
1918 	mnDevOrgX += nXAdd;
1919 	mnDevOrgY += nYAdd;
1920 }
1921 
1922 //-----------------------------------------------------------------------------------
1923 
SetDevExt(const Size & rSize)1924 void WinMtfOutput::SetDevExt( const Size& rSize )
1925 {
1926 	if ( rSize.Width() && rSize.Height() )
1927 	{
1928 		switch( mnMapMode )
1929 		{
1930 			case MM_ISOTROPIC :
1931 			case MM_ANISOTROPIC	:
1932 			{
1933 				mnDevWidth = rSize.Width();
1934 				mnDevHeight = rSize.Height();
1935 			}
1936 		}
1937 	}
1938 }
1939 
1940 //-----------------------------------------------------------------------------------
1941 
ScaleDevExt(double fX,double fY)1942 void WinMtfOutput::ScaleDevExt( double fX, double fY )
1943 {
1944 	mnDevWidth = FRound( mnDevWidth * fX );
1945 	mnDevHeight = FRound( mnDevHeight * fY );
1946 }
1947 
1948 //-----------------------------------------------------------------------------------
1949 
SetWinOrg(const Point & rPoint)1950 void WinMtfOutput::SetWinOrg( const Point& rPoint )
1951 {
1952 	mnWinOrgX = rPoint.X();
1953 	mnWinOrgY = rPoint.Y();
1954 }
1955 
1956 //-----------------------------------------------------------------------------------
1957 
SetWinOrgOffset(sal_Int32 nXAdd,sal_Int32 nYAdd)1958 void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
1959 {
1960 	mnWinOrgX += nXAdd;
1961 	mnWinOrgY += nYAdd;
1962 }
1963 
1964 //-----------------------------------------------------------------------------------
1965 
SetWinExt(const Size & rSize)1966 void WinMtfOutput::SetWinExt( const Size& rSize )
1967 {
1968 
1969 	if( rSize.Width() && rSize.Height() )
1970 	{
1971 		switch( mnMapMode )
1972 		{
1973 			case MM_ISOTROPIC :
1974 			case MM_ANISOTROPIC	:
1975 			{
1976 				mnWinExtX = rSize.Width();
1977 				mnWinExtY = rSize.Height();
1978 			}
1979 		}
1980 	}
1981 }
1982 
1983 //-----------------------------------------------------------------------------------
1984 
ScaleWinExt(double fX,double fY)1985 void WinMtfOutput::ScaleWinExt( double fX, double fY )
1986 {
1987 	mnWinExtX = FRound( mnWinExtX * fX );
1988 	mnWinExtY = FRound( mnWinExtY * fY );
1989 }
1990 
1991 //-----------------------------------------------------------------------------------
1992 
SetrclBounds(const Rectangle & rRect)1993 void WinMtfOutput::SetrclBounds( const Rectangle& rRect )
1994 {
1995 	mrclBounds = rRect;
1996 }
1997 
1998 //-----------------------------------------------------------------------------------
1999 
SetrclFrame(const Rectangle & rRect)2000 void WinMtfOutput::SetrclFrame( const Rectangle& rRect )
2001 {
2002 	mrclFrame = rRect;
2003 }
2004 
2005 //-----------------------------------------------------------------------------------
2006 
SetRefPix(const Size & rSize)2007 void WinMtfOutput::SetRefPix( const Size& rSize )
2008 {
2009 	mnPixX = rSize.Width();
2010 	mnPixY = rSize.Height();
2011 }
2012 
2013 //-----------------------------------------------------------------------------------
2014 
SetRefMill(const Size & rSize)2015 void WinMtfOutput::SetRefMill( const Size& rSize )
2016 {
2017 	mnMillX = rSize.Width();
2018 	mnMillY = rSize.Height();
2019 }
2020 
2021 //-----------------------------------------------------------------------------------
2022 
SetMapMode(sal_uInt32 nMapMode)2023 void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode )
2024 {
2025     mnMapMode = nMapMode;
2026 	if ( nMapMode == MM_TEXT )
2027 	{
2028 		mnWinExtX = mnDevWidth;
2029 		mnWinExtY = mnDevHeight;
2030 	}
2031 	else if ( mnMapMode == MM_HIMETRIC )
2032 	{
2033 		mnWinExtX = mnMillX * 100;
2034 		mnWinExtY = mnMillY * 100;
2035 	}
2036 }
2037 
2038 //-----------------------------------------------------------------------------------
2039 
SetWorldTransform(const XForm & rXForm)2040 void WinMtfOutput::SetWorldTransform( const XForm& rXForm )
2041 {
2042 	maXForm.eM11 = rXForm.eM11;
2043 	maXForm.eM12 = rXForm.eM12;
2044 	maXForm.eM21 = rXForm.eM21;
2045 	maXForm.eM22 = rXForm.eM22;
2046 	maXForm.eDx = rXForm.eDx;
2047 	maXForm.eDy = rXForm.eDy;
2048 }
2049 
2050 //-----------------------------------------------------------------------------------
2051 
ModifyWorldTransform(const XForm & rXForm,sal_uInt32 nMode)2052 void WinMtfOutput::ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode )
2053 {
2054 	switch( nMode )
2055 	{
2056 		case MWT_IDENTITY :
2057 		{
2058             maXForm.eM11 = maXForm.eM22 = 1.0f;
2059             maXForm.eM12 = maXForm.eM21 = maXForm.eDx = maXForm.eDy = 0.0f;
2060             break;
2061 		}
2062 
2063 		case MWT_RIGHTMULTIPLY :
2064 		case MWT_LEFTMULTIPLY :
2065         {
2066             const XForm* pLeft;
2067             const XForm* pRight;
2068 
2069             if ( nMode == MWT_LEFTMULTIPLY )
2070             {
2071                 pLeft = &rXForm;
2072                 pRight = &maXForm;
2073             }
2074             else
2075             {
2076                 pLeft = &maXForm;
2077                 pRight = &rXForm;
2078             }
2079 
2080             float aF[3][3];
2081             float bF[3][3];
2082             float cF[3][3];
2083 
2084             aF[0][0] = pLeft->eM11;
2085             aF[0][1] = pLeft->eM12;
2086             aF[0][2] = 0;
2087             aF[1][0] = pLeft->eM21;
2088             aF[1][1] = pLeft->eM22;
2089             aF[1][2] = 0;
2090             aF[2][0] = pLeft->eDx;
2091             aF[2][1] = pLeft->eDy;
2092             aF[2][2] = 1;
2093 
2094             bF[0][0] = pRight->eM11;
2095             bF[0][1] = pRight->eM12;
2096             bF[0][2] = 0;
2097             bF[1][0] = pRight->eM21;
2098             bF[1][1] = pRight->eM22;
2099             bF[1][2] = 0;
2100             bF[2][0] = pRight->eDx;
2101             bF[2][1] = pRight->eDy;
2102             bF[2][2] = 1;
2103 
2104             int i, j, k;
2105             for ( i = 0; i < 3; i++ )
2106             {
2107               for ( j = 0; j < 3; j++ )
2108               {
2109                  cF[i][j] = 0;
2110                  for ( k = 0; k < 3; k++ )
2111                     cF[i][j] += aF[i][k] * bF[k][j];
2112               }
2113             }
2114             maXForm.eM11 = cF[0][0];
2115             maXForm.eM12 = cF[0][1];
2116             maXForm.eM21 = cF[1][0];
2117             maXForm.eM22 = cF[1][1];
2118             maXForm.eDx = cF[2][0];
2119             maXForm.eDy = cF[2][1];
2120             break;
2121         }
2122         case MWT_SET:
2123         {
2124             SetWorldTransform(rXForm);
2125             break;
2126         }
2127 	}
2128  }
2129 
2130 //-----------------------------------------------------------------------------------
2131 
Push()2132 void WinMtfOutput::Push()						// !! to be able to access the original ClipRegion it
2133 {                                               // is not allowed to use the MetaPushAction()
2134 	UpdateClipRegion();                         // (the original clip region is on top of the stack) (SJ)
2135 	SaveStructPtr pSave( new SaveStruct );
2136 
2137 	pSave->aLineStyle = maLineStyle;
2138 	pSave->aFillStyle = maFillStyle;
2139 
2140 	pSave->aFont = maFont;
2141 	pSave->aTextColor = maTextColor;
2142     pSave->nTextAlign = mnTextAlign;
2143 	pSave->nTextLayoutMode = mnTextLayoutMode;
2144 	pSave->nMapMode = mnMapMode;
2145 	pSave->nGfxMode = mnGfxMode;
2146 	pSave->nBkMode = mnBkMode;
2147 	pSave->aBkColor = maBkColor;
2148 	pSave->bFillStyleSelected = mbFillStyleSelected;
2149 
2150 	pSave->aActPos = maActPos;
2151     pSave->aXForm = maXForm;
2152     pSave->eRasterOp = meRasterOp;
2153 
2154 	pSave->nWinOrgX = mnWinOrgX;
2155 	pSave->nWinOrgY = mnWinOrgY;
2156 	pSave->nWinExtX = mnWinExtX;
2157 	pSave->nWinExtY = mnWinExtY;
2158 	pSave->nDevOrgX = mnDevOrgX;
2159 	pSave->nDevOrgY = mnDevOrgY;
2160 	pSave->nDevWidth = mnDevWidth;
2161 	pSave->nDevHeight = mnDevHeight;
2162 
2163 	pSave->aPathObj = aPathObj;
2164 	pSave->aClipPath = aClipPath;
2165 
2166 	vSaveStack.push_back( pSave );
2167 }
2168 
2169 //-----------------------------------------------------------------------------------
2170 
Pop()2171 void WinMtfOutput::Pop()
2172 {
2173 	// Die aktuellen Daten vom Stack holen
2174 	if( vSaveStack.size() )
2175 	{
2176 		// Die aktuelle Daten auf dem Stack sichern
2177 		SaveStructPtr pSave( vSaveStack.back() );
2178 
2179 		maLineStyle = pSave->aLineStyle;
2180 		maFillStyle = pSave->aFillStyle;
2181 
2182 		maFont = pSave->aFont;
2183 		maTextColor = pSave->aTextColor;
2184         mnTextAlign = pSave->nTextAlign;
2185 		mnTextLayoutMode = pSave->nTextLayoutMode;
2186 		mnBkMode = pSave->nBkMode;
2187 		mnGfxMode = pSave->nGfxMode;
2188 		mnMapMode = pSave->nMapMode;
2189 		maBkColor = pSave->aBkColor;
2190 		mbFillStyleSelected = pSave->bFillStyleSelected;
2191 
2192 		maActPos = pSave->aActPos;
2193         maXForm = pSave->aXForm;
2194         meRasterOp = pSave->eRasterOp;
2195 
2196 		mnWinOrgX = pSave->nWinOrgX;
2197 		mnWinOrgY = pSave->nWinOrgY;
2198 		mnWinExtX = pSave->nWinExtX;
2199 		mnWinExtY = pSave->nWinExtY;
2200 		mnDevOrgX = pSave->nDevOrgX;
2201 		mnDevOrgY = pSave->nDevOrgY;
2202 		mnDevWidth = pSave->nDevWidth;
2203 		mnDevHeight = pSave->nDevHeight;
2204 
2205 		aPathObj = pSave->aPathObj;
2206         if ( ! ( aClipPath == pSave->aClipPath ) )
2207         {
2208             aClipPath = pSave->aClipPath;
2209 		    aClipPath.bNeedsUpdate = sal_True;
2210         }
2211         if ( meLatestRasterOp != meRasterOp )
2212 	    	mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
2213 		vSaveStack.pop_back();
2214 	}
2215 }
2216 
AddFromGDIMetaFile(GDIMetaFile & rGDIMetaFile)2217 void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile )
2218 {
2219    rGDIMetaFile.Play( *mpGDIMetaFile, 0xFFFFFFFF );
2220 }
2221