xref: /trunk/main/svtools/source/filter/wmf/emfwr.cxx (revision 45fd3b9a)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svtools.hxx"
24 
25 #include "emfwr.hxx"
26 #include <vcl/salbtype.hxx>
27 #include <basegfx/polygon/b2dpolygon.hxx>
28 #include <basegfx/polygon/b2dpolypolygon.hxx>
29 #include <vcl/lineinfo.hxx>
30 #include <vcl/dibtools.hxx>
31 
32 // -----------
33 // - Defines -
34 // -----------
35 
36 #define WIN_EMR_HEADER                      1
37 #define WIN_EMR_POLYBEZIER                  2
38 #define WIN_EMR_POLYGON                     3
39 #define WIN_EMR_POLYLINE                    4
40 #define WIN_EMR_POLYBEZIERTO                5
41 #define WIN_EMR_POLYLINETO                  6
42 #define WIN_EMR_POLYPOLYLINE                7
43 #define WIN_EMR_POLYPOLYGON                 8
44 #define WIN_EMR_SETWINDOWEXTEX              9
45 #define WIN_EMR_SETWINDOWORGEX              10
46 #define WIN_EMR_SETVIEWPORTEXTEX            11
47 #define WIN_EMR_SETVIEWPORTORGEX            12
48 #define WIN_EMR_SETBRUSHORGEX               13
49 #define WIN_EMR_EOF                         14
50 #define WIN_EMR_SETPIXELV                   15
51 #define WIN_EMR_SETMAPPERFLAGS              16
52 #define WIN_EMR_SETMAPMODE                  17
53 #define WIN_EMR_SETBKMODE                   18
54 #define WIN_EMR_SETPOLYFILLMODE             19
55 #define WIN_EMR_SETROP2                     20
56 #define WIN_EMR_SETSTRETCHBLTMODE           21
57 #define WIN_EMR_SETTEXTALIGN                22
58 #define WIN_EMR_SETCOLORADJUSTMENT          23
59 #define WIN_EMR_SETTEXTCOLOR                24
60 #define WIN_EMR_SETBKCOLOR                  25
61 #define WIN_EMR_OFFSETCLIPRGN               26
62 #define WIN_EMR_MOVETOEX                    27
63 #define WIN_EMR_SETMETARGN                  28
64 #define WIN_EMR_EXCLUDECLIPRECT             29
65 #define WIN_EMR_INTERSECTCLIPRECT           30
66 #define WIN_EMR_SCALEVIEWPORTEXTEX          31
67 #define WIN_EMR_SCALEWINDOWEXTEX            32
68 #define WIN_EMR_SAVEDC                      33
69 #define WIN_EMR_RESTOREDC                   34
70 #define WIN_EMR_SETWORLDTRANSFORM           35
71 #define WIN_EMR_MODIFYWORLDTRANSFORM        36
72 #define WIN_EMR_SELECTOBJECT                37
73 #define WIN_EMR_CREATEPEN                   38
74 #define WIN_EMR_CREATEBRUSHINDIRECT         39
75 #define WIN_EMR_DELETEOBJECT                40
76 #define WIN_EMR_ANGLEARC                    41
77 #define WIN_EMR_ELLIPSE                     42
78 #define WIN_EMR_RECTANGLE                   43
79 #define WIN_EMR_ROUNDRECT                   44
80 #define WIN_EMR_ARC                         45
81 #define WIN_EMR_CHORD                       46
82 #define WIN_EMR_PIE                         47
83 #define WIN_EMR_SELECTPALETTE               48
84 #define WIN_EMR_CREATEPALETTE               49
85 #define WIN_EMR_SETPALETTEENTRIES           50
86 #define WIN_EMR_RESIZEPALETTE               51
87 #define WIN_EMR_REALIZEPALETTE              52
88 #define WIN_EMR_EXTFLOODFILL                53
89 #define WIN_EMR_LINETO                      54
90 #define WIN_EMR_ARCTO                       55
91 #define WIN_EMR_POLYDRAW                    56
92 #define WIN_EMR_SETARCDIRECTION             57
93 #define WIN_EMR_SETMITERLIMIT               58
94 #define WIN_EMR_BEGINPATH                   59
95 #define WIN_EMR_ENDPATH                     60
96 #define WIN_EMR_CLOSEFIGURE                 61
97 #define WIN_EMR_FILLPATH                    62
98 #define WIN_EMR_STROKEANDFILLPATH           63
99 #define WIN_EMR_STROKEPATH                  64
100 #define WIN_EMR_FLATTENPATH                 65
101 #define WIN_EMR_WIDENPATH                   66
102 #define WIN_EMR_SELECTCLIPPATH              67
103 #define WIN_EMR_ABORTPATH                   68
104 
105 #define WIN_EMR_GDICOMMENT                  70
106 #define WIN_EMR_FILLRGN                     71
107 #define WIN_EMR_FRAMERGN                    72
108 #define WIN_EMR_INVERTRGN                   73
109 #define WIN_EMR_PAINTRGN                    74
110 #define WIN_EMR_EXTSELECTCLIPRGN            75
111 #define WIN_EMR_BITBLT                      76
112 #define WIN_EMR_STRETCHBLT                  77
113 #define WIN_EMR_MASKBLT                     78
114 #define WIN_EMR_PLGBLT                      79
115 #define WIN_EMR_SETDIBITSTODEVICE           80
116 #define WIN_EMR_STRETCHDIBITS               81
117 #define WIN_EMR_EXTCREATEFONTINDIRECTW      82
118 #define WIN_EMR_EXTTEXTOUTA                 83
119 #define WIN_EMR_EXTTEXTOUTW                 84
120 #define WIN_EMR_POLYBEZIER16                85
121 #define WIN_EMR_POLYGON16                   86
122 #define WIN_EMR_POLYLINE16                  87
123 #define WIN_EMR_POLYBEZIERTO16              88
124 #define WIN_EMR_POLYLINETO16                89
125 #define WIN_EMR_POLYPOLYLINE16              90
126 #define WIN_EMR_POLYPOLYGON16               91
127 #define WIN_EMR_POLYDRAW16                  92
128 #define WIN_EMR_CREATEMONOBRUSH             93
129 #define WIN_EMR_CREATEDIBPATTERNBRUSHPT     94
130 #define WIN_EMR_EXTCREATEPEN                95
131 #define WIN_EMR_POLYTEXTOUTA                96
132 #define WIN_EMR_POLYTEXTOUTW                97
133 
134 #define WIN_SRCCOPY							0x00CC0020L
135 #define WIN_SRCPAINT						0x00EE0086L
136 #define WIN_SRCAND							0x008800C6L
137 #define WIN_SRCINVERT						0x00660046L
138 
139 #define HANDLE_INVALID						0xffffffff
140 #define MAXHANDLES							65000
141 
142 #define LINE_SELECT							0x00000001
143 #define FILL_SELECT							0x00000002
144 #define TEXT_SELECT							0x00000004
145 
146 /* Text Alignment Options */
147 #define TA_NOUPDATECP						0
148 #define TA_UPDATECP							1
149 
150 #define TA_LEFT								0
151 #define TA_RIGHT							2
152 #define TA_CENTER							6
153 
154 #define TA_TOP								0
155 #define TA_BOTTOM							8
156 #define TA_BASELINE							24
157 #define TA_RTLREADING						256
158 #define TA_MASK		(TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING)
159 
160 #define MM_ANISOTROPIC						8
161 
162 // -------------
163 // - EMFWriter -
164 // -------------
165 
WriteEMF(const GDIMetaFile & rMtf,SvStream & rOStm,FilterConfigItem * pFilterConfigItem)166 sal_Bool EMFWriter::WriteEMF( const GDIMetaFile& rMtf, SvStream& rOStm, FilterConfigItem* pFilterConfigItem )
167 {
168 	const sal_uLong nHeaderPos = rOStm.Tell();
169 
170 	mpHandlesUsed = new sal_Bool[ MAXHANDLES ];
171 	memset( mpHandlesUsed, 0, MAXHANDLES * sizeof( sal_Bool ) );
172 	mnHorTextAlign = mnHandleCount = mnLastPercent = mnRecordPos = mnRecordCount = 0;
173 	mnLineHandle = mnFillHandle = mnTextHandle = HANDLE_INVALID;
174 	mbRecordOpen = sal_False;
175 
176 	mpStm = &rOStm;
177 	maVDev.EnableOutput( sal_False );
178 	maVDev.SetMapMode( rMtf.GetPrefMapMode() );
179 	mpFilterConfigItem = pFilterConfigItem;
180 
181 	// don't work with pixel as destination map mode -> higher resolution preferrable
182 	maDestMapMode.SetMapUnit( MAP_100TH_MM );
183 
184 	const Size aMtfSizePix( maVDev.LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) );
185 	const Size aMtfSizeLog( maVDev.LogicToLogic( rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MAP_100TH_MM ) );
186 
187 	// seek over header
188 	// use [MS-EMF 2.2.11] HeaderExtension2 Object, otherwise resulting EMF cannot be converted with GetWinMetaFileBits()
189 	rOStm.SeekRel( 108 );
190 
191 	// write initial values
192 
193 	// set 100th mm map mode in EMF
194 	ImplBeginRecord( WIN_EMR_SETMAPMODE );
195 	(*mpStm) << (sal_Int32) MM_ANISOTROPIC;
196 	ImplEndRecord();
197 
198 	ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX );
199 	(*mpStm) << (sal_Int32) maVDev.ImplGetDPIX() << (sal_Int32) maVDev.ImplGetDPIY();
200 	ImplEndRecord();
201 
202 	ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX );
203 	(*mpStm) << (sal_Int32) 2540 << (sal_Int32) 2540;
204 	ImplEndRecord();
205 
206 	ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX );
207 	(*mpStm) << (sal_Int32) 0 << (sal_Int32) 0;
208 	ImplEndRecord();
209 
210 	ImplBeginRecord( WIN_EMR_SETWINDOWORGEX );
211 	(*mpStm) << (sal_Int32) 0 << (sal_Int32) 0;
212 	ImplEndRecord();
213 
214 	ImplWriteRasterOp( ROP_OVERPAINT );
215 
216 	ImplBeginRecord( WIN_EMR_SETBKMODE );
217 	(*mpStm) << (sal_uInt32) 1; // TRANSPARENT
218 	ImplEndRecord();
219 
220 	// write emf data
221 	ImplWrite( rMtf );
222 
223 	ImplBeginRecord( WIN_EMR_EOF );
224 	(*mpStm)<< (sal_uInt32)0		// nPalEntries
225 			<< (sal_uInt32)0x10		// offPalEntries
226 			<< (sal_uInt32)0x14;	// nSizeLast
227 	ImplEndRecord();
228 
229 
230 	// write header
231 	const sal_uLong nEndPos = mpStm->Tell(); mpStm->Seek( nHeaderPos );
232 
233 	(*mpStm) << (sal_uInt32) 0x00000001 << (sal_uInt32) 108	//use [MS-EMF 2.2.11] HeaderExtension2 Object
234 			 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizePix.Width() - 1 ) << (sal_Int32) ( aMtfSizePix.Height() - 1 )
235 		     << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizeLog.Width() - 1 ) << (sal_Int32) ( aMtfSizeLog.Height() - 1 )
236 			 << (sal_uInt32) 0x464d4520 << (sal_uInt32) 0x10000 << (sal_uInt32) ( nEndPos - nHeaderPos )
237 			 << (sal_uInt32) mnRecordCount << (sal_uInt16) ( mnHandleCount + 1 ) << (sal_uInt16) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0
238 			 << (sal_Int32) aMtfSizePix.Width() << (sal_Int32) aMtfSizePix.Height()
239 			 << (sal_Int32) ( aMtfSizeLog.Width() / 100 ) << (sal_Int32) ( aMtfSizeLog.Height() / 100 )
240 			 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0
241 			 << (sal_Int32) (  aMtfSizeLog.Width() * 10 ) << (sal_Int32) ( aMtfSizeLog.Height() * 10 ); //use [MS-EMF 2.2.11] HeaderExtension2 Object
242 
243 	mpStm->Seek( nEndPos );
244 	delete[] mpHandlesUsed;
245 
246 	return( mpStm->GetError() == ERRCODE_NONE );
247 }
248 
249 // -----------------------------------------------------------------------------
250 
ImplAcquireHandle()251 sal_uLong EMFWriter::ImplAcquireHandle()
252 {
253 	sal_uLong nHandle = HANDLE_INVALID;
254 
255 	for( sal_uLong i = 0; i < MAXHANDLES && ( HANDLE_INVALID == nHandle ); i++ )
256 	{
257 		if( !mpHandlesUsed[ i ] )
258 		{
259 			mpHandlesUsed[ i ] = sal_True;
260 
261 			if( ( nHandle = i ) == mnHandleCount )
262 				mnHandleCount++;
263 		}
264 	}
265 
266 	DBG_ASSERT( nHandle != HANDLE_INVALID, "No more handles available" );
267 	return( nHandle != HANDLE_INVALID ? nHandle + 1 : HANDLE_INVALID );
268 }
269 
270 // -----------------------------------------------------------------------------
271 
ImplReleaseHandle(sal_uLong nHandle)272 void EMFWriter::ImplReleaseHandle( sal_uLong nHandle )
273 {
274 	DBG_ASSERT( nHandle && ( nHandle < MAXHANDLES ), "Handle out of range" );
275 	mpHandlesUsed[ nHandle - 1 ] = sal_False;
276 }
277 
278 // -----------------------------------------------------------------------------
279 
ImplBeginRecord(sal_uInt32 nType)280 void EMFWriter::ImplBeginRecord( sal_uInt32 nType )
281 {
282 	DBG_ASSERT( !mbRecordOpen, "Another record is already opened!" );
283 
284 	if( !mbRecordOpen )
285 	{
286 		mbRecordOpen = sal_True;
287 		mnRecordPos = mpStm->Tell();
288 
289 		(*mpStm) << nType;
290 		mpStm->SeekRel( 4 );
291 	}
292 }
293 
294 // -----------------------------------------------------------------------------
295 
ImplEndRecord()296 void EMFWriter::ImplEndRecord()
297 {
298 	DBG_ASSERT( mbRecordOpen, "Record was not opened!" );
299 
300 	if( mbRecordOpen )
301 	{
302 		sal_Int32 nFillBytes, nActPos = mpStm->Tell();
303 		mpStm->Seek( mnRecordPos + 4 );
304 		nFillBytes = nActPos - mnRecordPos;
305 		nFillBytes += 3;	// each record has to be dword aligned
306 		nFillBytes ^= 3;
307 		nFillBytes &= 3;
308 		*mpStm << (sal_uInt32)( ( nActPos - mnRecordPos ) + nFillBytes );
309 		mpStm->Seek( nActPos );
310 		while( nFillBytes-- )
311 			*mpStm << (sal_uInt8)0;
312 		mnRecordCount++;
313 		mbRecordOpen = sal_False;
314 	}
315 }
316 
317 // -----------------------------------------------------------------------------
318 
ImplPrepareHandleSelect(sal_uInt32 & rHandle,sal_uLong nSelectType)319 sal_Bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType )
320 {
321 	if( rHandle != HANDLE_INVALID )
322 	{
323 		sal_uInt32 nStockObject = 0x80000000;
324 
325 		if( LINE_SELECT == nSelectType )
326 			nStockObject |= 0x00000007;
327 		else if( FILL_SELECT == nSelectType )
328 			nStockObject |= 0x00000001;
329 		else if( TEXT_SELECT == nSelectType )
330 			nStockObject |= 0x0000000a;
331 
332 		// select stock object first
333 		ImplBeginRecord( WIN_EMR_SELECTOBJECT );
334 		( *mpStm ) << nStockObject;
335 		ImplEndRecord();
336 
337 		// destroy handle of created object
338 		ImplBeginRecord( WIN_EMR_DELETEOBJECT );
339 		( *mpStm ) << rHandle;
340 		ImplEndRecord();
341 
342 		// mark handle as free
343 		ImplReleaseHandle( rHandle );
344 	}
345 
346 	rHandle = ImplAcquireHandle();
347 
348 	return( HANDLE_INVALID != rHandle );
349 }
350 
351 // -----------------------------------------------------------------------------
352 
ImplCheckLineAttr()353 void EMFWriter::ImplCheckLineAttr()
354 {
355 	if( mbLineChanged && ImplPrepareHandleSelect( mnLineHandle, LINE_SELECT ) )
356 	{
357 		sal_uInt32 nStyle = maVDev.IsLineColor() ? 0 : 5;
358 		sal_uInt32 nWidth = 0, nHeight = 0;
359 
360 		ImplBeginRecord( WIN_EMR_CREATEPEN );
361 		(*mpStm) << mnLineHandle << nStyle << nWidth << nHeight;
362 		ImplWriteColor( maVDev.GetLineColor() );
363 		ImplEndRecord();
364 
365 		ImplBeginRecord( WIN_EMR_SELECTOBJECT );
366 		(*mpStm) << mnLineHandle;
367 		ImplEndRecord();
368 	}
369 }
370 
371 // -----------------------------------------------------------------------------
372 
ImplCheckFillAttr()373 void EMFWriter::ImplCheckFillAttr()
374 {
375 	if( mbFillChanged && ImplPrepareHandleSelect( mnFillHandle, FILL_SELECT ) )
376 	{
377 		sal_uInt32 nStyle = maVDev.IsFillColor() ? 0 : 1;
378 		sal_uInt32 nPatternStyle = 0;
379 
380 		ImplBeginRecord( WIN_EMR_CREATEBRUSHINDIRECT );
381 		(*mpStm) << mnFillHandle << nStyle;
382 		ImplWriteColor( maVDev.GetFillColor() );
383 		(*mpStm) << nPatternStyle;
384 		ImplEndRecord();
385 
386 		ImplBeginRecord( WIN_EMR_SELECTOBJECT );
387 		(*mpStm) << mnFillHandle;
388 		ImplEndRecord();
389 	}
390 }
391 
392 // -----------------------------------------------------------------------------
393 
ImplCheckTextAttr()394 void EMFWriter::ImplCheckTextAttr()
395 {
396 	if( mbTextChanged && ImplPrepareHandleSelect( mnTextHandle, TEXT_SELECT ) )
397 	{
398 		const Font&		rFont = maVDev.GetFont();
399 		String			aFontName( rFont.GetName() );
400 		sal_Int32		nWeight;
401 		sal_uInt16		i;
402 		sal_uInt8		nPitchAndFamily;
403 
404 		ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW );
405 		(*mpStm) << mnTextHandle;
406 		ImplWriteExtent( -rFont.GetSize().Height() );
407 		ImplWriteExtent( rFont.GetSize().Width() );
408 		(*mpStm) << (sal_Int32) rFont.GetOrientation() << (sal_Int32) rFont.GetOrientation();
409 
410 		switch( rFont.GetWeight() )
411 		{
412 			case WEIGHT_THIN:       nWeight = 100; break;
413 			case WEIGHT_ULTRALIGHT: nWeight = 200; break;
414 			case WEIGHT_LIGHT:      nWeight = 300; break;
415 			case WEIGHT_SEMILIGHT:  nWeight = 300; break;
416 			case WEIGHT_NORMAL:     nWeight = 400; break;
417 			case WEIGHT_MEDIUM:     nWeight = 500; break;
418 			case WEIGHT_SEMIBOLD:   nWeight = 600; break;
419 			case WEIGHT_BOLD:       nWeight = 700; break;
420 			case WEIGHT_ULTRABOLD:  nWeight = 800; break;
421 			case WEIGHT_BLACK:      nWeight = 900; break;
422 			default:				nWeight = 0; break;
423 		}
424 
425 		(*mpStm) << nWeight;
426 		(*mpStm) << (sal_uInt8) ( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 );
427 		(*mpStm) << (sal_uInt8) ( ( UNDERLINE_NONE == rFont.GetUnderline() ) ? 0 : 1 );
428 		(*mpStm) << (sal_uInt8) ( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 );
429 		(*mpStm) << (sal_uInt8) ( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 );
430 		(*mpStm) << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0;
431 
432 		switch( rFont.GetPitch() )
433 		{
434 			case PITCH_FIXED:    nPitchAndFamily = 0x01; break;
435 			case PITCH_VARIABLE: nPitchAndFamily = 0x02; break;
436 			default:             nPitchAndFamily = 0x00; break;
437 		}
438 
439 		switch( rFont.GetFamily() )
440 		{
441 			case FAMILY_DECORATIVE: nPitchAndFamily |= 0x50; break;
442 			case FAMILY_MODERN:     nPitchAndFamily |= 0x30; break;
443 			case FAMILY_ROMAN:      nPitchAndFamily |= 0x10; break;
444 			case FAMILY_SCRIPT:     nPitchAndFamily |= 0x40; break;
445 			case FAMILY_SWISS:      nPitchAndFamily |= 0x20; break;
446 			default: break;
447 		}
448 
449 		(*mpStm) << nPitchAndFamily;
450 
451 		for( i = 0; i < 32; i++ )
452 			(*mpStm) << (sal_Unicode) ( ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0 );
453 
454 		// dummy elfFullName
455 		for( i = 0; i < 64; i++ )
456 			(*mpStm) << (sal_Unicode) 0;
457 
458 		// dummy elfStyle
459 		for( i = 0; i < 32; i++ )
460 			(*mpStm) << (sal_Unicode) 0;
461 
462 		// dummy elfVersion, elfStyleSize, elfMatch, elfReserved
463 		(*mpStm) << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 ;
464 
465 		// dummy elfVendorId
466 		(*mpStm) << (sal_uInt32) 0;
467 
468 		// dummy elfCulture
469 		(*mpStm) << (sal_uInt32) 0;
470 
471 		// dummy elfPanose
472 		(*mpStm) << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0;
473 
474 		// fill record to get a record size divideable by 4
475 		(*mpStm) << (sal_uInt16) 0;
476 
477 		ImplEndRecord();
478 
479 		// TextAlign
480 		sal_uInt32 nTextAlign;
481 
482 		switch( rFont.GetAlign() )
483 		{
484 			case ALIGN_TOP:    nTextAlign = TA_TOP; break;
485 			case ALIGN_BOTTOM: nTextAlign = TA_BOTTOM; break;
486 			default:           nTextAlign = TA_BASELINE; break;
487 		}
488 		nTextAlign |= mnHorTextAlign;
489 
490 		ImplBeginRecord( WIN_EMR_SETTEXTALIGN );
491 		(*mpStm) << nTextAlign;
492 		ImplEndRecord();
493 
494 		// Text color
495 		ImplBeginRecord( WIN_EMR_SETTEXTCOLOR );
496 		ImplWriteColor( maVDev.GetTextColor() );
497 		ImplEndRecord();
498 
499 		ImplBeginRecord( WIN_EMR_SELECTOBJECT );
500 		(*mpStm) << mnTextHandle;
501 		ImplEndRecord();
502 	}
503 }
504 
505 // -----------------------------------------------------------------------------
506 
ImplWriteColor(const Color & rColor)507 void EMFWriter::ImplWriteColor( const Color& rColor )
508 {
509 	sal_uInt32 nCol = rColor.GetRed();
510 
511 	nCol |= ( (sal_uInt32) rColor.GetGreen() ) << 8;
512 	nCol |= ( (sal_uInt32) rColor.GetBlue() ) << 16;
513 
514 	(*mpStm) << nCol;
515 }
516 
517 // -----------------------------------------------------------------------------
518 
ImplWriteRasterOp(RasterOp eRop)519 void EMFWriter::ImplWriteRasterOp( RasterOp eRop )
520 {
521 	sal_uInt32 nROP2;
522 
523 	switch( eRop )
524 	{
525 		case ROP_INVERT: nROP2 = 6;	break;
526 		case ROP_XOR:    nROP2 = 7;	break;
527 		default:         nROP2 = 13;break;
528 	}
529 
530 	ImplBeginRecord( WIN_EMR_SETROP2 );
531 	(*mpStm) << nROP2;
532 	ImplEndRecord();
533 }
534 
535 // -----------------------------------------------------------------------------
536 
ImplWriteExtent(long nExtent)537 void EMFWriter::ImplWriteExtent( long nExtent )
538 {
539 	nExtent = maVDev.LogicToLogic( Size( nExtent, 0 ), maVDev.GetMapMode(), maDestMapMode ).Width();
540 	(*mpStm) << (sal_Int32) nExtent;
541 }
542 
543 // -----------------------------------------------------------------------------
544 
ImplWritePoint(const Point & rPoint)545 void EMFWriter::ImplWritePoint( const Point& rPoint )
546 {
547 	const Point aPoint( maVDev.LogicToLogic( rPoint, maVDev.GetMapMode(), maDestMapMode ));
548  	(*mpStm) << (sal_Int32) aPoint.X() << (sal_Int32) aPoint.Y();
549 }
550 
551 // -----------------------------------------------------------------------------
552 
ImplWriteSize(const Size & rSize)553 void EMFWriter::ImplWriteSize( const Size& rSize)
554 {
555 	const Size aSize( maVDev.LogicToLogic( rSize, maVDev.GetMapMode(), maDestMapMode ));
556  	(*mpStm) << (sal_Int32) aSize.Width() << (sal_Int32) aSize.Height();
557 }
558 
559 // -----------------------------------------------------------------------------
560 
ImplWriteRect(const Rectangle & rRect)561 void EMFWriter::ImplWriteRect( const Rectangle& rRect )
562 {
563 	const Rectangle aRect( maVDev.LogicToLogic ( rRect, maVDev.GetMapMode(), maDestMapMode ));
564  	(*mpStm) << aRect.Left() << aRect.Top() << aRect.Right() << aRect.Bottom();
565 }
566 
567 // -----------------------------------------------------------------------------
568 
ImplWritePolygonRecord(const Polygon & rPoly,sal_Bool bClose)569 void EMFWriter::ImplWritePolygonRecord( const Polygon& rPoly, sal_Bool bClose )
570 {
571 	if( rPoly.GetSize() )
572 	{
573 		if( rPoly.HasFlags() )
574 			ImplWritePath( rPoly, bClose );
575 		else
576 		{
577 			if( bClose )
578 				ImplCheckFillAttr();
579 
580 			ImplCheckLineAttr();
581 
582 			ImplBeginRecord( bClose ? WIN_EMR_POLYGON : WIN_EMR_POLYLINE );
583 			ImplWriteRect( rPoly.GetBoundRect() );
584 			(*mpStm) << (sal_uInt32) rPoly.GetSize();
585 
586 			for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ )
587 				ImplWritePoint( rPoly[ i ] );
588 
589 			ImplEndRecord();
590 		}
591 	}
592 }
593 
594 // -----------------------------------------------------------------------------
595 
ImplWritePolyPolygonRecord(const PolyPolygon & rPolyPoly)596 void EMFWriter::ImplWritePolyPolygonRecord( const PolyPolygon& rPolyPoly )
597 {
598 	sal_uInt16 n, i, nPolyCount = rPolyPoly.Count();
599 
600 	if( nPolyCount )
601 	{
602 		if( 1 == nPolyCount )
603 			ImplWritePolygonRecord( rPolyPoly[ 0 ], sal_True );
604 		else
605 		{
606 			sal_Bool	bHasFlags = sal_False;
607 			sal_uInt32	nTotalPoints = 0;
608 
609 			for( i = 0; i < nPolyCount; i++ )
610 			{
611 				nTotalPoints += rPolyPoly[ i ].GetSize();
612 				if ( rPolyPoly[ i ].HasFlags() )
613 					bHasFlags = sal_True;
614 			}
615 			if( nTotalPoints )
616 			{
617 				if ( bHasFlags )
618 					ImplWritePath( rPolyPoly, sal_True );
619 				else
620 				{
621 					ImplCheckFillAttr();
622 					ImplCheckLineAttr();
623 
624 					ImplBeginRecord( WIN_EMR_POLYPOLYGON );
625 					ImplWriteRect( rPolyPoly.GetBoundRect() );
626 					(*mpStm) << (sal_uInt32)nPolyCount << nTotalPoints;
627 
628 					for( i = 0; i < nPolyCount; i++ )
629 						(*mpStm) << (sal_uInt32)rPolyPoly[ i ].GetSize();
630 
631 					for( i = 0; i < nPolyCount; i++ )
632 					{
633 						const Polygon& rPoly = rPolyPoly[ i ];
634 
635 						for( n = 0; n < rPoly.GetSize(); n++ )
636 							ImplWritePoint( rPoly[ n ] );
637 					}
638 					ImplEndRecord();
639 				}
640 			}
641 		}
642 	}
643 }
644 
645 // -----------------------------------------------------------------------------
646 
ImplWritePath(const PolyPolygon & rPolyPoly,sal_Bool bClosed)647 void EMFWriter::ImplWritePath( const PolyPolygon& rPolyPoly, sal_Bool bClosed )
648 {
649 	if ( bClosed )
650 		ImplCheckFillAttr();
651 	ImplCheckLineAttr();
652 
653 	ImplBeginRecord( WIN_EMR_BEGINPATH );
654 	ImplEndRecord();
655 
656 	sal_uInt16 i, n, o, nPolyCount = rPolyPoly.Count();
657 	for ( i = 0; i < nPolyCount; i++ )
658 	{
659 		n = 0;
660 		const Polygon& rPoly = rPolyPoly[ i ];
661 		while ( n < rPoly.GetSize() )
662 		{
663             if( n == 0 )
664             {
665 		        ImplBeginRecord( WIN_EMR_MOVETOEX );
666 		        ImplWritePoint( rPoly[ 0 ] );
667 		        ImplEndRecord();
668                 n++;
669                 continue;
670             }
671 
672             sal_uInt16 nBezPoints = 0;
673 
674 			while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == POLY_CONTROL ) )
675 				nBezPoints += 3;
676 
677 			if ( nBezPoints )
678 			{
679 				ImplBeginRecord( WIN_EMR_POLYBEZIERTO );
680 				Polygon aNewPoly( nBezPoints + 1 );
681 				aNewPoly[ 0 ] = rPoly[ n - 1 ];
682 				for ( o = 0; o < nBezPoints; o++ )
683 					aNewPoly[ o + 1 ] = rPoly[ n + o ];
684 				ImplWriteRect( aNewPoly.GetBoundRect() );
685 				(*mpStm) << (sal_uInt32)nBezPoints;
686 				for( o = 1; o < aNewPoly.GetSize(); o++ )
687 					ImplWritePoint( aNewPoly[ o ] );
688 				ImplEndRecord();
689 				n = n + nBezPoints;
690 			}
691 			else
692 			{
693 				sal_uInt16 nPoints = 1;
694 				while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != POLY_CONTROL ) )
695 					nPoints++;
696 
697 				if ( nPoints > 1 )
698 				{
699 					ImplBeginRecord( WIN_EMR_POLYLINETO );
700 					Polygon aNewPoly( nPoints + 1 );
701 					aNewPoly[ 0 ] = rPoly[ n - 1];
702 					for ( o = 1; o <= nPoints; o++ )
703 						aNewPoly[ o ] = rPoly[ n - 1 + o ];
704 					ImplWriteRect( aNewPoly.GetBoundRect() );
705 					(*mpStm) << (sal_uInt32)( nPoints );
706 					for( o = 1; o < aNewPoly.GetSize(); o++ )
707 						ImplWritePoint( aNewPoly[ o ] );
708 					ImplEndRecord();
709 				}
710                 else
711                 {
712                     ImplBeginRecord( WIN_EMR_LINETO );
713                     ImplWritePoint( rPoly[ n ] );
714                     ImplEndRecord();
715                 }
716                 n = n + nPoints;
717 			}
718 			if ( bClosed && ( n == rPoly.GetSize() ) )
719 			{
720 				ImplBeginRecord( WIN_EMR_CLOSEFIGURE );
721 				ImplEndRecord();
722 			}
723 		}
724 	}
725 	ImplBeginRecord( WIN_EMR_ENDPATH );
726 	ImplEndRecord();
727 	ImplBeginRecord( bClosed ? WIN_EMR_FILLPATH : WIN_EMR_STROKEPATH );
728     ImplWriteRect( rPolyPoly.GetBoundRect() );
729 	ImplEndRecord();
730 }
731 
732 // -----------------------------------------------------------------------------
733 
ImplWriteBmpRecord(const Bitmap & rBmp,const Point & rPt,const Size & rSz,sal_uInt32 nROP)734 void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt,
735 									const Size& rSz, sal_uInt32 nROP )
736 {
737 	if( !!rBmp )
738 	{
739 		SvMemoryStream	aMemStm( 65535, 65535 );
740 		const Size		aBmpSizePixel( rBmp.GetSizePixel() );
741 
742 		ImplBeginRecord( WIN_EMR_STRETCHDIBITS );
743 		ImplWriteRect( Rectangle( rPt, rSz ) );
744 		ImplWritePoint( rPt );
745 		(*mpStm) << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) aBmpSizePixel.Width() << (sal_Int32) aBmpSizePixel.Height();
746 
747 		// write offset positions and sizes later
748 		const sal_uLong nOffPos = mpStm->Tell();
749 		mpStm->SeekRel( 16 );
750 
751 		(*mpStm) << (sal_uInt32) 0 << ( ( ROP_XOR == maVDev.GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP );
752 		ImplWriteSize( rSz );
753 
754 		WriteDIB(rBmp, aMemStm, true, false);
755 
756 		sal_uInt32	nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize;
757 		sal_uInt16	nBitCount;
758 
759 		// get DIB parameters
760 		aMemStm.Seek( 0 );
761 		aMemStm >> nHeaderSize;
762 		aMemStm.SeekRel( 10 );
763 		aMemStm >> nBitCount >> nCompression >> nImageSize;
764 		aMemStm.SeekRel( 8 );
765 		aMemStm >> nColsUsed;
766 
767 		nPalCount = ( nBitCount <= 8 ) ? ( nColsUsed ? nColsUsed : ( 1 << (sal_uInt32) nBitCount ) ) :
768 										 ( ( 3 == nCompression ) ? 12 : 0 );
769 
770 		mpStm->Write( aMemStm.GetData(), nDIBSize );
771 
772 		const sal_uLong nEndPos = mpStm->Tell();
773 		mpStm->Seek( nOffPos );
774 		(*mpStm) << (sal_uInt32) 80 << (sal_uInt32)( nHeaderSize + ( nPalCount << 2 ) );
775 		(*mpStm) << (sal_uInt32)( 80 + ( nHeaderSize + ( nPalCount << 2 ) ) ) << nImageSize;
776 		mpStm->Seek( nEndPos );
777 
778 		ImplEndRecord();
779 	}
780 }
781 
782 // -----------------------------------------------------------------------------
783 
ImplWriteTextRecord(const Point & rPos,const String rText,const sal_Int32 * pDXArray,sal_uInt32 nWidth)784 void EMFWriter::ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth )
785 {
786 	xub_StrLen nLen = rText.Len(), i;
787 
788 	if( nLen )
789 	{
790 		sal_uInt32	nNormWidth;
791 		sal_Int32*	pOwnArray;
792 		sal_Int32*	pDX;
793 
794 		// get text sizes
795 		if( pDXArray )
796 		{
797 			pOwnArray = NULL;
798 			nNormWidth = maVDev.GetTextWidth( rText );
799 			pDX = (sal_Int32*) pDXArray;
800 		}
801 		else
802 		{
803 			pOwnArray = new sal_Int32[ nLen ];
804 			nNormWidth = maVDev.GetTextArray( rText, pOwnArray );
805 			pDX = pOwnArray;
806 		}
807 
808 		if( nLen > 1 )
809 		{
810 			nNormWidth = pDX[ nLen - 2 ] + maVDev.GetTextWidth( rText.GetChar( nLen - 1 ) );
811 
812 			if( nWidth && nNormWidth && ( nWidth != nNormWidth ) )
813 			{
814 				const double fFactor = (double) nWidth / nNormWidth;
815 
816 				for( i = 0; i < ( nLen - 1 ); i++ )
817 					pDX[ i ] = FRound( pDX[ i ] * fFactor );
818 			}
819 		}
820 
821 		// write text record
822 		ImplBeginRecord( WIN_EMR_EXTTEXTOUTW );
823 
824 		ImplWriteRect( Rectangle( rPos, Size( nNormWidth, maVDev.GetTextHeight() ) ) );
825 		(*mpStm) << (sal_uInt32)1;
826 		(*mpStm) << (sal_Int32) 0 << (sal_Int32) 0;
827 		ImplWritePoint( rPos );
828 		(*mpStm) << (sal_uInt32) nLen << (sal_uInt32) 76 << (sal_uInt32) 2;
829 		(*mpStm) << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0;
830 		(*mpStm) << (sal_uInt32) ( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) );
831 
832 		// write text
833 		for( i = 0; i < nLen; i++ )
834 			(*mpStm) << (sal_Unicode)rText.GetChar( i );
835 
836 		// padding word
837 		if( nLen & 1 )
838 			(*mpStm) << (sal_uInt16) 0;
839 
840 		// write DX array
841 		ImplWriteExtent( pDX[ 0 ] );
842 
843 		if( nLen > 1 )
844 		{
845 			for( i = 1; i < ( nLen - 1 ); i++ )
846 				ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] );
847 
848 			ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) );
849 		}
850 
851 		ImplEndRecord();
852 		delete[] pOwnArray;
853 	}
854 }
855 
856 // -----------------------------------------------------------------------------
857 
Impl_handleLineInfoPolyPolygons(const LineInfo & rInfo,const basegfx::B2DPolygon & rLinePolygon)858 void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
859 {
860 	if(rLinePolygon.count())
861 	{
862 		basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
863 		basegfx::B2DPolyPolygon aFillPolyPolygon;
864 
865 		rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
866 
867 		if(aLinePolyPolygon.count())
868 		{
869 			for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
870 			{
871 				const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
872     			ImplWritePolygonRecord( Polygon(aCandidate), sal_False );
873 			}
874 		}
875 
876 		if(aFillPolyPolygon.count())
877 		{
878 			const Color aOldLineColor(maVDev.GetLineColor());
879 			const Color aOldFillColor(maVDev.GetFillColor());
880 
881 			maVDev.SetLineColor();
882 			maVDev.SetFillColor(aOldLineColor);
883 
884 			for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
885 			{
886 				const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
887     			ImplWritePolyPolygonRecord(PolyPolygon(Polygon(aPolygon)));
888 			}
889 
890 			maVDev.SetLineColor(aOldLineColor);
891 			maVDev.SetFillColor(aOldFillColor);
892 		}
893 	}
894 }
895 
896 // -----------------------------------------------------------------------------
897 
ImplWrite(const GDIMetaFile & rMtf)898 void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
899 {
900 	for( sal_uLong j = 0, nActionCount = rMtf.GetActionCount(); j < nActionCount; j++ )
901 	{
902 		const MetaAction*	pAction = rMtf.GetAction( j );
903 		const sal_uInt16		nType = pAction->GetType();
904 
905 		switch( nType )
906 		{
907 			case( META_PIXEL_ACTION	):
908 			{
909 				const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
910 
911 				ImplCheckLineAttr();
912 				ImplBeginRecord( WIN_EMR_SETPIXELV );
913 				ImplWritePoint( pA->GetPoint() );
914 				ImplWriteColor( pA->GetColor() );
915 				ImplEndRecord();
916 			}
917 			break;
918 
919 			case( META_POINT_ACTION	):
920 			{
921 				if( maVDev.IsLineColor() )
922 				{
923 					const MetaPointAction* pA = (const MetaPointAction*) pAction;
924 
925 					ImplCheckLineAttr();
926 					ImplBeginRecord( WIN_EMR_SETPIXELV );
927 					ImplWritePoint( pA->GetPoint() );
928 					ImplWriteColor( maVDev.GetLineColor() );
929 					ImplEndRecord();
930 				}
931 			}
932 			break;
933 
934 			case( META_LINE_ACTION ):
935 			{
936 				if( maVDev.IsLineColor() )
937 				{
938 					const MetaLineAction* pA = (const MetaLineAction*) pAction;
939 
940                     if(pA->GetLineInfo().IsDefault())
941                     {
942 					    ImplCheckLineAttr();
943 
944 					    ImplBeginRecord( WIN_EMR_MOVETOEX );
945 					    ImplWritePoint( pA->GetStartPoint() );
946 					    ImplEndRecord();
947 
948 					    ImplBeginRecord( WIN_EMR_LINETO );
949 					    ImplWritePoint( pA->GetEndPoint() );
950 					    ImplEndRecord();
951 
952 					    ImplBeginRecord( WIN_EMR_SETPIXELV );
953 					    ImplWritePoint( pA->GetEndPoint() );
954 					    ImplWriteColor( maVDev.GetLineColor() );
955 					    ImplEndRecord();
956                     }
957                     else
958                     {
959                         // LineInfo used; handle Dash/Dot and fat lines
960                         basegfx::B2DPolygon aPolygon;
961                         aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
962                         aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
963                         Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
964                     }
965 				}
966 			}
967 			break;
968 
969 			case( META_RECT_ACTION ):
970 			{
971 				if( maVDev.IsLineColor() || maVDev.IsFillColor() )
972 				{
973 					const MetaRectAction* pA = (const MetaRectAction*) pAction;
974 
975 					ImplCheckFillAttr();
976 					ImplCheckLineAttr();
977 
978 					ImplBeginRecord( WIN_EMR_RECTANGLE );
979 					ImplWriteRect( pA->GetRect() );
980 					ImplEndRecord();
981 				}
982 			}
983 			break;
984 
985 			case( META_ROUNDRECT_ACTION	):
986 			{
987 				if( maVDev.IsLineColor() || maVDev.IsFillColor() )
988 				{
989 					const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
990 
991 					ImplCheckFillAttr();
992 					ImplCheckLineAttr();
993 
994 					ImplBeginRecord( WIN_EMR_ROUNDRECT );
995 					ImplWriteRect( pA->GetRect() );
996 					ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) );
997 					ImplEndRecord();
998 				}
999 			}
1000 			break;
1001 
1002 			case( META_ELLIPSE_ACTION ):
1003 			{
1004 				if( maVDev.IsLineColor() || maVDev.IsFillColor() )
1005 				{
1006 					const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction;
1007 
1008 					ImplCheckFillAttr();
1009 					ImplCheckLineAttr();
1010 
1011 					ImplBeginRecord( WIN_EMR_ELLIPSE );
1012 					ImplWriteRect( pA->GetRect() );
1013 					ImplEndRecord();
1014 				}
1015 			}
1016 			break;
1017 
1018 			case( META_ARC_ACTION ):
1019 			case( META_PIE_ACTION ):
1020 			case( META_CHORD_ACTION	):
1021 			case( META_POLYGON_ACTION ):
1022 			{
1023 				if( maVDev.IsLineColor() || maVDev.IsFillColor() )
1024 				{
1025 					Polygon aPoly;
1026 
1027 					switch( nType )
1028 					{
1029 						case( META_ARC_ACTION ):
1030 						{
1031 							const MetaArcAction* pA = (const MetaArcAction*) pAction;
1032 							aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
1033 						}
1034 						break;
1035 
1036 						case( META_PIE_ACTION ):
1037 						{
1038 							const MetaPieAction* pA = (const MetaPieAction*) pAction;
1039 							aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
1040 						}
1041 						break;
1042 
1043 						case( META_CHORD_ACTION	):
1044 						{
1045 							const MetaChordAction* pA = (const MetaChordAction*) pAction;
1046 							aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
1047 						}
1048 						break;
1049 
1050 						case( META_POLYGON_ACTION ):
1051 							aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon();
1052 						break;
1053 					}
1054 
1055 					ImplWritePolygonRecord( aPoly, nType != META_ARC_ACTION );
1056 				}
1057 			}
1058 			break;
1059 
1060 			case( META_POLYLINE_ACTION ):
1061 			{
1062 				if( maVDev.IsLineColor() )
1063                 {
1064 				    const MetaPolyLineAction*	pA = (const MetaPolyLineAction*) pAction;
1065 				    const Polygon&				rPoly = pA->GetPolygon();
1066 
1067 			        if( rPoly.GetSize() )
1068                     {
1069                         if(pA->GetLineInfo().IsDefault())
1070                         {
1071     					    ImplWritePolygonRecord( rPoly, sal_False );
1072                         }
1073                         else
1074                         {
1075                             // LineInfo used; handle Dash/Dot and fat lines
1076                             Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1077                         }
1078                     }
1079                 }
1080 			}
1081 			break;
1082 
1083 			case( META_POLYPOLYGON_ACTION ):
1084 			{
1085 				if( maVDev.IsLineColor() || maVDev.IsFillColor() )
1086 					ImplWritePolyPolygonRecord( ( (const MetaPolyPolygonAction*) pAction )->GetPolyPolygon() );
1087 			}
1088 			break;
1089 
1090 			case( META_GRADIENT_ACTION ):
1091 			{
1092 				const MetaGradientAction*	pA = (const MetaGradientAction*) pAction;
1093 				GDIMetaFile					aTmpMtf;
1094 
1095 				maVDev.AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1096 				ImplWrite( aTmpMtf );
1097 			}
1098 			break;
1099 
1100 			case META_HATCH_ACTION:
1101 			{
1102 				const MetaHatchAction*	pA = (const MetaHatchAction*) pAction;
1103 				GDIMetaFile				aTmpMtf;
1104 
1105 				maVDev.AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1106 				ImplWrite( aTmpMtf );
1107 			}
1108 			break;
1109 
1110 			case META_TRANSPARENT_ACTION:
1111 			{
1112 				ImplCheckFillAttr();
1113 				ImplCheckLineAttr();
1114 				ImplWritePolyPolygonRecord( ( (MetaTransparentAction*) pAction )->GetPolyPolygon() );
1115 			}
1116 			break;
1117 
1118 			case META_FLOATTRANSPARENT_ACTION:
1119 			{
1120 				const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction;
1121 
1122 				GDIMetaFile		aTmpMtf( pA->GetGDIMetaFile() );
1123 				Point			aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1124 				const Size		aSrcSize( aTmpMtf.GetPrefSize() );
1125 				const Point		aDestPt( pA->GetPoint() );
1126 				const Size		aDestSize( pA->GetSize() );
1127 				const double	fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1128 				const double	fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1129 				long			nMoveX, nMoveY;
1130 
1131 				if( fScaleX != 1.0 || fScaleY != 1.0 )
1132 				{
1133 					aTmpMtf.Scale( fScaleX, fScaleY );
1134 					aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1135 				}
1136 
1137 				nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
1138 
1139 				if( nMoveX || nMoveY )
1140 					aTmpMtf.Move( nMoveX, nMoveY );
1141 
1142 				ImplCheckFillAttr();
1143 				ImplCheckLineAttr();
1144 				ImplCheckTextAttr();
1145 				ImplWrite( aTmpMtf );
1146 			}
1147 			break;
1148 
1149 			case( META_EPS_ACTION ):
1150 			{
1151 				const MetaEPSAction*	pA = (const MetaEPSAction*) pAction;
1152 				const GDIMetaFile		aSubstitute( pA->GetSubstitute() );
1153 
1154 				for( sal_uLong i = 0, nCount = aSubstitute.GetActionCount(); i < nCount; i++ )
1155 				{
1156 					const MetaAction* pSubstAct = aSubstitute.GetAction( i );
1157 					if( pSubstAct->GetType() == META_BMPSCALE_ACTION )
1158 					{
1159 						maVDev.Push( PUSH_ALL );
1160 						ImplBeginRecord( WIN_EMR_SAVEDC );
1161 						ImplEndRecord();
1162 
1163 						MapMode	aMapMode( aSubstitute.GetPrefMapMode() );
1164 						Size aOutSize( maVDev.LogicToLogic( pA->GetSize(), maVDev.GetMapMode(), aMapMode ) );
1165 						aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
1166 						aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
1167 						aMapMode.SetOrigin( maVDev.LogicToLogic( pA->GetPoint(), maVDev.GetMapMode(), aMapMode ) );
1168 						maVDev.SetMapMode( aMapMode );
1169 						ImplWrite( aSubstitute );
1170 
1171 						maVDev.Pop();
1172 						ImplBeginRecord( WIN_EMR_RESTOREDC );
1173 						(*mpStm) << (sal_Int32) -1;
1174 						ImplEndRecord();
1175 						break;
1176 					}
1177 				}
1178 			}
1179 			break;
1180 
1181 			case META_BMP_ACTION:
1182 			{
1183 				const MetaBmpAction* pA = (const MetaBmpAction *) pAction;
1184 				ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev.PixelToLogic( pA->GetBitmap().GetSizePixel() ), WIN_SRCCOPY );
1185 			}
1186 			break;
1187 
1188 			case META_BMPSCALE_ACTION:
1189 			{
1190 				const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
1191 				ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1192 			}
1193 			break;
1194 
1195 			case META_BMPSCALEPART_ACTION:
1196 			{
1197 				const MetaBmpScalePartAction*	pA = (const MetaBmpScalePartAction*) pAction;
1198 				Bitmap							aTmp( pA->GetBitmap() );
1199 
1200 				if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1201 					ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1202 			}
1203 			break;
1204 
1205 			case META_BMPEX_ACTION:
1206 			{
1207 				const MetaBmpExAction*	pA = (const MetaBmpExAction *) pAction;
1208 				Bitmap					aBmp( pA->GetBitmapEx().GetBitmap() );
1209 				Bitmap					aMsk( pA->GetBitmapEx().GetMask() );
1210 
1211 				if( !!aMsk )
1212 				{
1213 					aBmp.Replace( aMsk, COL_WHITE );
1214 					aMsk.Invert();
1215 					ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev.PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT );
1216 					ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev.PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND );
1217 				}
1218 				else
1219 					ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY );
1220 			}
1221 			break;
1222 
1223 			case META_BMPEXSCALE_ACTION:
1224 			{
1225 				const MetaBmpExScaleAction*	pA = (const MetaBmpExScaleAction*) pAction;
1226 				Bitmap						aBmp( pA->GetBitmapEx().GetBitmap() );
1227 				Bitmap						aMsk( pA->GetBitmapEx().GetMask() );
1228 
1229 				if( !!aMsk )
1230 				{
1231 					aBmp.Replace( aMsk, COL_WHITE );
1232 					aMsk.Invert();
1233 					ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT );
1234 					ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND );
1235 				}
1236 				else
1237 					ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1238 			}
1239 			break;
1240 
1241 			case META_BMPEXSCALEPART_ACTION:
1242 			{
1243 				const MetaBmpExScalePartAction*	pA = (const MetaBmpExScalePartAction*) pAction;
1244 				BitmapEx						aBmpEx( pA->GetBitmapEx() );
1245 				aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1246 				Bitmap							aBmp( aBmpEx.GetBitmap() );
1247 				Bitmap							aMsk( aBmpEx.GetMask() );
1248 
1249 				if( !!aMsk )
1250 				{
1251 					aBmp.Replace( aMsk, COL_WHITE );
1252 					aMsk.Invert();
1253 					ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT );
1254 					ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND );
1255 				}
1256 				else
1257 					ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1258 			}
1259 			break;
1260 
1261 			case META_TEXT_ACTION:
1262 			{
1263 				const MetaTextAction*	pA = (const MetaTextAction*) pAction;
1264 				const String			aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1265 
1266 				ImplCheckTextAttr();
1267 				ImplWriteTextRecord( pA->GetPoint(), aText, NULL, 0 );
1268 			}
1269 			break;
1270 
1271 			case META_TEXTRECT_ACTION:
1272 			{
1273 				const MetaTextRectAction*	pA = (const MetaTextRectAction*) pAction;
1274 				const String				aText( pA->GetText() );
1275 
1276 				ImplCheckTextAttr();
1277 				ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, NULL, 0 );
1278 			}
1279 			break;
1280 
1281 			case META_TEXTARRAY_ACTION:
1282 			{
1283 				const MetaTextArrayAction*	pA = (const MetaTextArrayAction*) pAction;
1284 				const String				aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1285 
1286 				ImplCheckTextAttr();
1287 				ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
1288 			}
1289 			break;
1290 
1291 			case META_STRETCHTEXT_ACTION:
1292 			{
1293 				const MetaStretchTextAction*	pA = (const MetaStretchTextAction*) pAction;
1294 				const String					aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1295 
1296 				ImplCheckTextAttr();
1297 				ImplWriteTextRecord( pA->GetPoint(), aText, NULL, pA->GetWidth() );
1298 			}
1299 			break;
1300 
1301 			case( META_LINECOLOR_ACTION	):
1302 			{
1303 				( (MetaAction*) pAction )->Execute( &maVDev );
1304 				mbLineChanged = sal_True;
1305 			}
1306 			break;
1307 
1308 			case( META_FILLCOLOR_ACTION	):
1309 			{
1310 				( (MetaAction*) pAction )->Execute( &maVDev );
1311 				mbFillChanged = sal_True;
1312 			}
1313 			break;
1314 
1315 			case( META_TEXTCOLOR_ACTION	):
1316 			case( META_TEXTLINECOLOR_ACTION ):
1317 			case( META_TEXTFILLCOLOR_ACTION	):
1318 			case( META_TEXTALIGN_ACTION	):
1319 			case( META_FONT_ACTION ):
1320 			{
1321 				( (MetaAction*) pAction )->Execute( &maVDev );
1322 				mbTextChanged = sal_True;
1323 			}
1324 			break;
1325 
1326 			case( META_ISECTRECTCLIPREGION_ACTION ):
1327 			{
1328 				( (MetaAction*) pAction )->Execute( &maVDev );
1329 
1330 				ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT );
1331 				ImplWriteRect( ( (MetaISectRectClipRegionAction*) pAction )->GetRect() );
1332 				ImplEndRecord();
1333 			}
1334 			break;
1335 
1336 			case( META_CLIPREGION_ACTION ):
1337 			case( META_ISECTREGIONCLIPREGION_ACTION	):
1338 			case( META_MOVECLIPREGION_ACTION ):
1339 			{
1340 				( (MetaAction*) pAction )->Execute( &maVDev );
1341 			}
1342 			break;
1343 
1344 			case( META_REFPOINT_ACTION ):
1345 			case( META_MAPMODE_ACTION ):
1346 				( (MetaAction*) pAction )->Execute( &maVDev );
1347 			break;
1348 
1349 			case( META_PUSH_ACTION ):
1350 			{
1351 				( (MetaAction*) pAction )->Execute( &maVDev );
1352 
1353 				ImplBeginRecord( WIN_EMR_SAVEDC );
1354 				ImplEndRecord();
1355 			}
1356 			break;
1357 
1358 			case( META_POP_ACTION ):
1359 			{
1360 				( (MetaAction*) pAction )->Execute( &maVDev );
1361 
1362 				ImplBeginRecord( WIN_EMR_RESTOREDC );
1363 				(*mpStm) << (sal_Int32) -1;
1364 				ImplEndRecord();
1365 
1366 				ImplWriteRasterOp( maVDev.GetRasterOp() );
1367 				mbLineChanged = mbFillChanged = mbTextChanged = sal_True;
1368 			}
1369 			break;
1370 
1371 			case( META_RASTEROP_ACTION ):
1372 			{
1373 				( (MetaAction*) pAction )->Execute( &maVDev );
1374 				ImplWriteRasterOp( ( (MetaRasterOpAction*) pAction )->GetRasterOp() );
1375 			}
1376 			break;
1377 
1378 			case( META_LAYOUTMODE_ACTION ):
1379 			{
1380 				sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pAction )->GetLayoutMode();
1381 				mnHorTextAlign = 0;
1382 				if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL)
1383 				{
1384 					mnHorTextAlign = TA_RIGHT | TA_RTLREADING;
1385 				}
1386 				if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT)
1387 					mnHorTextAlign |= TA_RIGHT;
1388 				else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT)
1389 					mnHorTextAlign &= ~TA_RIGHT;
1390 				break;
1391 			}
1392 
1393 			case( META_MASK_ACTION ):
1394 			case( META_MASKSCALE_ACTION	):
1395 			case( META_MASKSCALEPART_ACTION	):
1396 			case( META_WALLPAPER_ACTION	):
1397 			case( META_TEXTLINE_ACTION ):
1398 			case( META_COMMENT_ACTION ):
1399 			case( META_GRADIENTEX_ACTION ):
1400 			{
1401 				// !!! >>> we don't want to support these actions
1402 			}
1403 			break;
1404 
1405 			default:
1406 				DBG_ERROR( ( ByteString( "EMFWriter::ImplWriteActions: unsupported MetaAction #" ) += ByteString::CreateFromInt32( nType ) ).GetBuffer() );
1407 			break;
1408 		}
1409 	}
1410 }
1411