xref: /trunk/main/svtools/source/filter/wmf/wmfwr.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 <vcl/salbtype.hxx>
26 #include "wmfwr.hxx"
27 #include <unotools/fontcvt.hxx>
28 #include "emfwr.hxx"
29 #include <rtl/crc.h>
30 #include <rtl/tencinfo.h>
31 #include <tools/tenccvt.hxx>
32 #include <osl/endian.h>
33 #include <i18nutil/unicode.hxx>	//unicode::getUnicodeScriptType
34 #include <vcl/metric.hxx>
35 #include <basegfx/polygon/b2dpolygon.hxx>
36 #include <basegfx/polygon/b2dpolypolygon.hxx>
37 #include <vcl/dibtools.hxx>
38 
39 //====================== MS-Windows-defines ===============================
40 
41 #define W_META_SETBKCOLOR           0x0201
42 #define W_META_SETBKMODE            0x0102
43 #define W_META_SETMAPMODE           0x0103
44 #define W_META_SETROP2              0x0104
45 #define W_META_SETRELABS            0x0105
46 #define W_META_SETPOLYFILLMODE      0x0106
47 #define W_META_SETSTRETCHBLTMODE    0x0107
48 #define W_META_SETTEXTCHAREXTRA     0x0108
49 #define W_META_SETTEXTCOLOR         0x0209
50 #define W_META_SETTEXTJUSTIFICATION 0x020A
51 #define W_META_SETWINDOWORG         0x020B
52 #define W_META_SETWINDOWEXT         0x020C
53 #define W_META_SETVIEWPORTORG       0x020D
54 #define W_META_SETVIEWPORTEXT       0x020E
55 #define W_META_OFFSETWINDOWORG      0x020F
56 #define W_META_SCALEWINDOWEXT       0x0410
57 #define W_META_OFFSETVIEWPORTORG    0x0211
58 #define W_META_SCALEVIEWPORTEXT     0x0412
59 #define W_META_LINETO               0x0213
60 #define W_META_MOVETO               0x0214
61 #define W_META_EXCLUDECLIPRECT      0x0415
62 #define W_META_INTERSECTCLIPRECT    0x0416
63 #define W_META_ARC                  0x0817
64 #define W_META_ELLIPSE              0x0418
65 #define W_META_FLOODFILL            0x0419
66 #define W_META_PIE                  0x081A
67 #define W_META_RECTANGLE            0x041B
68 #define W_META_ROUNDRECT            0x061C
69 #define W_META_PATBLT               0x061D
70 #define W_META_SAVEDC               0x001E
71 #define W_META_SETPIXEL             0x041F
72 #define W_META_OFFSETCLIPRGN        0x0220
73 #define W_META_TEXTOUT              0x0521
74 #define W_META_BITBLT               0x0922
75 #define W_META_STRETCHBLT           0x0B23
76 #define W_META_POLYGON              0x0324
77 #define W_META_POLYLINE             0x0325
78 #define W_META_ESCAPE               0x0626
79 #define W_META_RESTOREDC            0x0127
80 #define W_META_FILLREGION           0x0228
81 #define W_META_FRAMEREGION          0x0429
82 #define W_META_INVERTREGION         0x012A
83 #define W_META_PAINTREGION          0x012B
84 #define W_META_SELECTCLIPREGION     0x012C
85 #define W_META_SELECTOBJECT         0x012D
86 #define W_META_SETTEXTALIGN         0x012E
87 #define W_META_DRAWTEXT             0x062F
88 #define W_META_CHORD                0x0830
89 #define W_META_SETMAPPERFLAGS       0x0231
90 #define W_META_EXTTEXTOUT           0x0a32
91 #define W_META_SETDIBTODEV          0x0d33
92 #define W_META_SELECTPALETTE        0x0234
93 #define W_META_REALIZEPALETTE       0x0035
94 #define W_META_ANIMATEPALETTE       0x0436
95 #define W_META_SETPALENTRIES        0x0037
96 #define W_META_POLYPOLYGON          0x0538
97 #define W_META_RESIZEPALETTE        0x0139
98 #define W_META_DIBBITBLT            0x0940
99 #define W_META_DIBSTRETCHBLT        0x0b41
100 #define W_META_DIBCREATEPATTERNBRUSH 0x0142
101 #define W_META_STRETCHDIB           0x0f43
102 #define W_META_EXTFLOODFILL         0x0548
103 #define W_META_RESETDC              0x014C
104 #define W_META_STARTDOC             0x014D
105 #define W_META_STARTPAGE            0x004F
106 #define W_META_ENDPAGE              0x0050
107 #define W_META_ABORTDOC             0x0052
108 #define W_META_ENDDOC               0x005E
109 #define W_META_DELETEOBJECT         0x01f0
110 #define W_META_CREATEPALETTE        0x00f7
111 #define W_META_CREATEBRUSH          0x00F8
112 #define W_META_CREATEPATTERNBRUSH   0x01F9
113 #define W_META_CREATEPENINDIRECT    0x02FA
114 #define W_META_CREATEFONTINDIRECT   0x02FB
115 #define W_META_CREATEBRUSHINDIRECT  0x02FC
116 #define W_META_CREATEBITMAPINDIRECT 0x02FD
117 #define W_META_CREATEBITMAP         0x06FE
118 #define W_META_CREATEREGION         0x06FF
119 
120 #define W_TRANSPARENT     1
121 #define W_OPAQUE          2
122 
123 #define W_R2_BLACK            1
124 #define W_R2_NOTMERGEPEN      2
125 #define W_R2_MASKNOTPEN       3
126 #define W_R2_NOTCOPYPEN       4
127 #define W_R2_MASKPENNOT       5
128 #define W_R2_NOT              6
129 #define W_R2_XORPEN           7
130 #define W_R2_NOTMASKPEN       8
131 #define W_R2_MASKPEN          9
132 #define W_R2_NOTXORPEN        10
133 #define W_R2_NOP              11
134 #define W_R2_MERGENOTPEN      12
135 #define W_R2_COPYPEN          13
136 #define W_R2_MERGEPENNOT      14
137 #define W_R2_MERGEPEN         15
138 #define W_R2_WHITE            16
139 
140 #define W_TA_NOUPDATECP      0x0000
141 #define W_TA_UPDATECP        0x0001
142 #define W_TA_LEFT            0x0000
143 #define W_TA_RIGHT           0x0002
144 #define W_TA_CENTER          0x0006
145 #define W_TA_TOP             0x0000
146 #define W_TA_BOTTOM          0x0008
147 #define W_TA_BASELINE        0x0018
148 #define W_TA_RTLREADING      0x0100
149 
150 #define W_SRCCOPY             0x00CC0020L
151 #define W_SRCPAINT            0x00EE0086L
152 #define W_SRCAND              0x008800C6L
153 #define W_SRCINVERT           0x00660046L
154 #define W_SRCERASE            0x00440328L
155 #define W_NOTSRCCOPY          0x00330008L
156 #define W_NOTSRCERASE         0x001100A6L
157 #define W_MERGECOPY           0x00C000CAL
158 #define W_MERGEPAINT          0x00BB0226L
159 #define W_PATCOPY             0x00F00021L
160 #define W_PATPAINT            0x00FB0A09L
161 #define W_PATINVERT           0x005A0049L
162 #define W_DSTINVERT           0x00550009L
163 #define W_BLACKNESS           0x00000042L
164 #define W_WHITENESS           0x00FF0062L
165 
166 #define W_PS_SOLID            0
167 #define W_PS_DASH             1
168 #define W_PS_DOT              2
169 #define W_PS_DASHDOT          3
170 #define W_PS_DASHDOTDOT       4
171 #define W_PS_NULL             5
172 #define W_PS_INSIDEFRAME      6
173 
174 #define W_LF_FACESIZE       32
175 
176 #define W_ANSI_CHARSET          0
177 #define W_DEFAULT_CHARSET       1
178 #define W_SYMBOL_CHARSET        2
179 #define W_SHIFTJIS_CHARSET    128
180 #define W_HANGEUL_CHARSET     129
181 #define W_GB2312_CHARSET      134
182 #define W_CHINESEBIG5_CHARSET 136
183 #define W_OEM_CHARSET         255
184 /*WINVER >= 0x0400*/
185 #define W_JOHAB_CHARSET		 130
186 #define W_HEBREW_CHARSET	 177
187 #define W_ARABIC_CHARSET	 178
188 #define W_GREEK_CHARSET		 161
189 #define W_TURKISH_CHARSET	 162
190 #define W_VIETNAMESE_CHARSET 163
191 #define W_THAI_CHARSET		 222
192 #define W_EASTEUROPE_CHARSET 238
193 #define W_RUSSIAN_CHARSET    204
194 #define W_MAC_CHARSET        77
195 #define W_BALTIC_CHARSET	 186
196 
197 #define W_DEFAULT_PITCH       0x00
198 #define W_FIXED_PITCH         0x01
199 #define W_VARIABLE_PITCH      0x02
200 
201 #define W_FF_DONTCARE         0x00
202 #define W_FF_ROMAN            0x10
203 #define W_FF_SWISS            0x20
204 #define W_FF_MODERN           0x30
205 #define W_FF_SCRIPT           0x40
206 #define W_FF_DECORATIVE       0x50
207 
208 #define W_FW_DONTCARE       0
209 #define W_FW_THIN           100
210 #define W_FW_EXTRALIGHT     200
211 #define W_FW_LIGHT          300
212 #define W_FW_NORMAL         400
213 #define W_FW_MEDIUM         500
214 #define W_FW_SEMIBOLD       600
215 #define W_FW_BOLD           700
216 #define W_FW_EXTRABOLD      800
217 #define W_FW_HEAVY          900
218 #define W_FW_ULTRALIGHT     200
219 #define W_FW_REGULAR        400
220 #define W_FW_DEMIBOLD       600
221 #define W_FW_ULTRABOLD      800
222 #define W_FW_BLACK          900
223 
224 #define W_BS_SOLID          0
225 #define W_BS_HOLLOW         1
226 #define W_BS_HATCHED        2
227 #define W_BS_PATTERN        3
228 #define W_BS_INDEXED        4
229 #define W_BS_DIBPATTERN     5
230 
231 #define W_HS_HORIZONTAL     0
232 #define W_HS_VERTICAL       1
233 #define W_HS_FDIAGONAL      2
234 #define W_HS_BDIAGONAL      3
235 #define W_HS_CROSS          4
236 #define W_HS_DIAGCROSS      5
237 
238 #define W_MFCOMMENT			15
239 
240 #define PRIVATE_ESCAPE_UNICODE			2
241 
242 /// copied from writerwordglue.cxx
243 
244 /*
245 	Utility to categorize unicode characters into the best fit windows charset
246 	range for exporting to ww6, or as a hint to non \u unicode token aware rtf
247 	readers
248 */
getScriptClass(sal_Unicode cChar)249 rtl_TextEncoding getScriptClass(sal_Unicode cChar)
250 {
251 	using namespace com::sun::star::i18n;
252 
253 	static ScriptTypeList aScripts[] =
254 	{
255 		{ UnicodeScript_kBasicLatin, UnicodeScript_kBasicLatin, RTL_TEXTENCODING_MS_1252},
256 		{ UnicodeScript_kLatin1Supplement, UnicodeScript_kLatin1Supplement, RTL_TEXTENCODING_MS_1252},
257 		{ UnicodeScript_kLatinExtendedA, UnicodeScript_kLatinExtendedA, RTL_TEXTENCODING_MS_1250},
258 		{ UnicodeScript_kLatinExtendedB, UnicodeScript_kLatinExtendedB, RTL_TEXTENCODING_MS_1257},
259 		{ UnicodeScript_kGreek, UnicodeScript_kGreek, RTL_TEXTENCODING_MS_1253},
260 		{ UnicodeScript_kCyrillic, UnicodeScript_kCyrillic, RTL_TEXTENCODING_MS_1251},
261 		{ UnicodeScript_kHebrew, UnicodeScript_kHebrew, RTL_TEXTENCODING_MS_1255},
262 		{ UnicodeScript_kArabic, UnicodeScript_kArabic, RTL_TEXTENCODING_MS_1256},
263 		{ UnicodeScript_kThai, UnicodeScript_kThai, RTL_TEXTENCODING_MS_1258},
264 		{ UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, RTL_TEXTENCODING_MS_1252}
265 	};
266 	return unicode::getUnicodeScriptType(cChar, aScripts,
267 		RTL_TEXTENCODING_MS_1252);
268 }
269 
270 //========================== Methoden von WMFWriter ==========================
271 
MayCallback()272 void WMFWriter::MayCallback()
273 {
274 	if ( xStatusIndicator.is() )
275 	{
276 		sal_uLong nPercent;
277 
278 		// Wir gehen mal einfach so davon aus, dass 16386 Actions einer Bitmap entsprechen
279 		// (in der Regel wird ein Metafile entweder nur Actions oder einige Bitmaps und fast
280 		// keine Actions enthalten. Dann ist das Verhaeltnis ziemlich unwichtig)
281 
282 		nPercent=((nWrittenBitmaps<<14)+(nActBitmapPercent<<14)/100+nWrittenActions)
283 				*100
284 				/((nNumberOfBitmaps<<14)+nNumberOfActions);
285 
286 		if ( nPercent >= nLastPercent + 3 )
287 		{
288 			nLastPercent = nPercent;
289 			if( nPercent <= 100 )
290 				xStatusIndicator->setValue( nPercent );
291 		}
292 	}
293 }
294 
CountActionsAndBitmaps(const GDIMetaFile & rMTF)295 void WMFWriter::CountActionsAndBitmaps( const GDIMetaFile & rMTF )
296 {
297 	sal_uLong nAction, nActionCount;
298 
299 	nActionCount = rMTF.GetActionCount();
300 
301 	for ( nAction=0; nAction<nActionCount; nAction++ )
302 	{
303 		MetaAction* pMA = rMTF.GetAction( nAction );
304 
305 		switch( pMA->GetType() )
306 		{
307 			case META_BMP_ACTION:
308 			case META_BMPSCALE_ACTION:
309 			case META_BMPSCALEPART_ACTION:
310 			case META_BMPEX_ACTION:
311 			case META_BMPEXSCALE_ACTION:
312 			case META_BMPEXSCALEPART_ACTION:
313 				nNumberOfBitmaps++;
314 			break;
315 		}
316 		nNumberOfActions++;
317 	}
318 }
319 
320 
WritePointXY(const Point & rPoint)321 void WMFWriter::WritePointXY(const Point & rPoint)
322 {
323 	Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
324 	*pWMF << ((short)aPt.X()) << ((short)aPt.Y());
325 }
326 
327 
WritePointYX(const Point & rPoint)328 void WMFWriter::WritePointYX(const Point & rPoint)
329 {
330 	Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
331 	*pWMF << ((short)aPt.Y()) << ((short)aPt.X());
332 }
333 
334 
ScaleWidth(sal_Int32 nDX)335 sal_Int32 WMFWriter::ScaleWidth( sal_Int32 nDX )
336 {
337 	Size aSz( pVirDev->LogicToLogic(Size(nDX,0),aSrcMapMode,aTargetMapMode) );
338 	return aSz.Width();
339 }
340 
341 
WriteSize(const Size & rSize)342 void WMFWriter::WriteSize(const Size & rSize)
343 {
344 	Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
345 	*pWMF << ((short)aSz.Width()) << ((short)aSz.Height());
346 }
347 
348 
WriteHeightWidth(const Size & rSize)349 void WMFWriter::WriteHeightWidth(const Size & rSize)
350 {
351 	Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
352 	*pWMF << ((short)aSz.Height()) << ((short)aSz.Width());
353 }
354 
355 
WriteRectangle(const Rectangle & rRect)356 void WMFWriter::WriteRectangle(const Rectangle & rRect)
357 {
358 	WritePointYX(Point(rRect.Right()+1,rRect.Bottom()+1));
359 	WritePointYX(rRect.TopLeft());
360 }
361 
362 
WriteColor(const Color & rColor)363 void WMFWriter::WriteColor(const Color & rColor)
364 {
365 	*pWMF << (sal_uInt8) rColor.GetRed() << (sal_uInt8) rColor.GetGreen() << (sal_uInt8) rColor.GetBlue() << (sal_uInt8) 0;
366 }
367 
368 
WriteRecordHeader(sal_uInt32 nSizeWords,sal_uInt16 nType)369 void WMFWriter::WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType)
370 {
371 	nActRecordPos=pWMF->Tell();
372 	if (nSizeWords>nMaxRecordSize) nMaxRecordSize=nSizeWords;
373 	*pWMF << nSizeWords << nType;
374 }
375 
376 
UpdateRecordHeader()377 void WMFWriter::UpdateRecordHeader()
378 {
379 	sal_uLong nPos;
380 	sal_uInt32 nSize;
381 
382 	nPos=pWMF->Tell(); nSize=nPos-nActRecordPos;
383 	if ((nSize & 1)!=0) {
384 		*pWMF << (sal_uInt8)0;
385 		nPos++; nSize++;
386 	}
387 	nSize/=2;
388 	if (nSize>nMaxRecordSize) nMaxRecordSize=nSize;
389 	pWMF->Seek(nActRecordPos);
390 	*pWMF << nSize;
391 	pWMF->Seek(nPos);
392 }
393 
394 
WMFRecord_Arc(const Rectangle & rRect,const Point & rStartPt,const Point & rEndPt)395 void WMFWriter::WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
396 {
397 	WriteRecordHeader(0x0000000b,W_META_ARC);
398 	WritePointYX(rEndPt);
399 	WritePointYX(rStartPt);
400 	WriteRectangle(rRect);
401 }
402 
WMFRecord_Chord(const Rectangle & rRect,const Point & rStartPt,const Point & rEndPt)403 void WMFWriter::WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
404 {
405 	WriteRecordHeader(0x0000000b,W_META_CHORD);
406 	WritePointYX(rEndPt);
407 	WritePointYX(rStartPt);
408 	WriteRectangle(rRect);
409 }
410 
411 
WMFRecord_CreateBrushIndirect(const Color & rColor)412 void WMFWriter::WMFRecord_CreateBrushIndirect(const Color& rColor)
413 {
414 	WriteRecordHeader(0x00000007,W_META_CREATEBRUSHINDIRECT);
415 
416 	if( rColor==Color(COL_TRANSPARENT) )
417 		*pWMF << (sal_uInt16) W_BS_HOLLOW;
418 	else
419 		*pWMF << (sal_uInt16) W_BS_SOLID;
420 
421 	WriteColor( rColor );
422 	*pWMF << (sal_uInt16) 0;
423 }
424 
425 
WMFRecord_CreateFontIndirect(const Font & rFont)426 void WMFWriter::WMFRecord_CreateFontIndirect(const Font & rFont)
427 {
428 	sal_uInt16 nWeight,i;
429 	sal_uInt8 nPitchFamily;
430 
431 	WriteRecordHeader(0x00000000,W_META_CREATEFONTINDIRECT);
432 	WriteHeightWidth(Size(rFont.GetSize().Width(),-rFont.GetSize().Height()));
433 	*pWMF << (short)rFont.GetOrientation() << (short)rFont.GetOrientation();
434 
435 	switch (rFont.GetWeight()) {
436 		case WEIGHT_THIN:       nWeight=W_FW_THIN;       break;
437 		case WEIGHT_ULTRALIGHT: nWeight=W_FW_ULTRALIGHT; break;
438 		case WEIGHT_LIGHT:      nWeight=W_FW_LIGHT;      break;
439 		case WEIGHT_SEMILIGHT:  nWeight=W_FW_LIGHT;      break;
440 		case WEIGHT_NORMAL:     nWeight=W_FW_NORMAL;     break;
441 		case WEIGHT_MEDIUM:     nWeight=W_FW_MEDIUM;     break;
442 		case WEIGHT_SEMIBOLD:   nWeight=W_FW_SEMIBOLD;   break;
443 		case WEIGHT_BOLD:       nWeight=W_FW_BOLD;       break;
444 		case WEIGHT_ULTRABOLD:  nWeight=W_FW_ULTRABOLD;  break;
445 		case WEIGHT_BLACK:      nWeight=W_FW_BLACK;      break;
446 		default:                nWeight=W_FW_DONTCARE;
447 	}
448 	*pWMF << nWeight;
449 
450 	if (rFont.GetItalic()==ITALIC_NONE)       *pWMF << (sal_uInt8)0; else  *pWMF << (sal_uInt8)1;
451 	if (rFont.GetUnderline()==UNDERLINE_NONE) *pWMF << (sal_uInt8)0; else  *pWMF << (sal_uInt8)1;
452 	if (rFont.GetStrikeout()==STRIKEOUT_NONE) *pWMF << (sal_uInt8)0; else  *pWMF << (sal_uInt8)1;
453 
454 	CharSet		eFontNameEncoding = rFont.GetCharSet();
455 	sal_uInt8	nCharSet = rtl_getBestWindowsCharsetFromTextEncoding( eFontNameEncoding );
456 	if ( eFontNameEncoding == RTL_TEXTENCODING_SYMBOL )
457 		eFontNameEncoding = RTL_TEXTENCODING_MS_1252;
458 	if ( nCharSet == 1 )
459 		nCharSet = W_ANSI_CHARSET;
460 	*pWMF << nCharSet;
461 
462 	*pWMF << (sal_uInt8)0 << (sal_uInt8)0 << (sal_uInt8)0;
463 
464 	switch (rFont.GetPitch()) {
465 		case PITCH_FIXED:    nPitchFamily=W_FIXED_PITCH;    break;
466 		case PITCH_VARIABLE: nPitchFamily=W_VARIABLE_PITCH; break;
467 		default:             nPitchFamily=W_DEFAULT_PITCH;
468 	}
469 	switch (rFont.GetFamily()) {
470 		case FAMILY_DECORATIVE: nPitchFamily|=W_FF_DECORATIVE; break;
471 		case FAMILY_MODERN:     nPitchFamily|=W_FF_MODERN;     break;
472 		case FAMILY_ROMAN:      nPitchFamily|=W_FF_ROMAN;      break;
473 		case FAMILY_SCRIPT:     nPitchFamily|=W_FF_SCRIPT;     break;
474 		case FAMILY_SWISS:      nPitchFamily|=W_FF_SWISS;      break;
475 		default:                nPitchFamily|=W_FF_DONTCARE;
476 	}
477 	*pWMF << nPitchFamily;
478 
479 	ByteString aFontName( rFont.GetName(), eFontNameEncoding );
480 	for ( i = 0; i < W_LF_FACESIZE; i++ )
481 	{
482 		sal_Char nChar = ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0;
483 		*pWMF << nChar;
484 	}
485 	UpdateRecordHeader();
486 }
487 
WMFRecord_CreatePenIndirect(const Color & rColor,const LineInfo & rLineInfo)488 void WMFWriter::WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo )
489 {
490 	WriteRecordHeader(0x00000008,W_META_CREATEPENINDIRECT);
491 	sal_uInt16 nStyle = rColor == Color( COL_TRANSPARENT ) ? W_PS_NULL : W_PS_SOLID;
492 	switch( rLineInfo.GetStyle() )
493 	{
494 		case LINE_DASH :
495 		{
496 			if ( rLineInfo.GetDotCount() )
497 			{
498 				if ( !rLineInfo.GetDashCount() )
499 					nStyle = W_PS_DOT;
500 				else
501 				{
502 					if ( !rLineInfo.GetDotCount() == 1 )
503 						nStyle = W_PS_DASHDOT;
504 					else
505 						nStyle = W_PS_DASHDOTDOT;
506 				}
507 			}
508 			else
509 				nStyle = W_PS_DASH;
510 		}
511 		break;
512 		case LINE_NONE :
513 			nStyle = W_PS_NULL;
514 		break;
515         default:
516         break;
517 	}
518 	*pWMF << nStyle;
519 
520 	WriteSize( Size( rLineInfo.GetWidth(), 0 ) );
521 	WriteColor( rColor );
522 }
523 
WMFRecord_DeleteObject(sal_uInt16 nObjectHandle)524 void WMFWriter::WMFRecord_DeleteObject(sal_uInt16 nObjectHandle)
525 {
526 	WriteRecordHeader(0x00000004,W_META_DELETEOBJECT);
527 	*pWMF << nObjectHandle;
528 }
529 
530 
WMFRecord_Ellipse(const Rectangle & rRect)531 void WMFWriter::WMFRecord_Ellipse(const Rectangle & rRect)
532 {
533 	WriteRecordHeader(0x00000007,W_META_ELLIPSE);
534 	WriteRectangle(rRect);
535 }
536 
IsStarSymbol(const String & rStr)537 bool IsStarSymbol(const String &rStr)
538 {
539     return rStr.EqualsIgnoreCaseAscii("starsymbol") ||
540         rStr.EqualsIgnoreCaseAscii("opensymbol");
541 }
542 
WMFRecord_Escape(sal_uInt32 nEsc,sal_uInt32 nLen,const sal_Int8 * pData)543 void WMFWriter::WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData )
544 {
545 #ifdef OSL_BIGENDIAN
546 	sal_uInt32 nTmp = SWAPLONG( nEsc );
547 	sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
548 #else
549 	sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
550 #endif
551 	if ( nLen )
552 		nCheckSum = rtl_crc32( nCheckSum, pData, nLen );
553 
554 	WriteRecordHeader( 3 + 9 + ( ( nLen + 1 ) >> 1 ), W_META_ESCAPE );
555 	*pWMF << (sal_uInt16)W_MFCOMMENT
556 		  << (sal_uInt16)( nLen + 14 )	// we will always have a fourteen byte escape header:
557 		  << (sal_uInt16)0x4f4f			// OO
558 		  << (sal_uInt32)0xa2c2a		// evil magic number
559 		  << (sal_uInt32)nCheckSum		// crc32 checksum about nEsc & pData
560 		  << (sal_uInt32)nEsc;			// escape number
561 	pWMF->Write( pData, nLen );
562 	if ( nLen & 1 )
563 		*pWMF << (sal_uInt8)0;			// pad byte
564 }
565 
566 /* if return value is true, then a complete unicode string and also a polygon replacement has been written,
567 	so there is no more action necessary
568 */
WMFRecord_Escape_Unicode(const Point & rPoint,const String & rUniStr,const sal_Int32 * pDXAry)569 sal_Bool WMFWriter::WMFRecord_Escape_Unicode( const Point& rPoint, const String& rUniStr, const sal_Int32* pDXAry )
570 {
571 	sal_Bool bEscapeUsed = sal_False;
572 
573 	sal_uInt32 i, nStringLen = rUniStr.Len();
574 	if ( nStringLen )
575 	{
576 		// first we will check if a comment is necessary
577 		if ( aSrcFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL )		// symbol is always byte character, so there is no unicode loss
578 		{
579 			const sal_Unicode* pBuf = rUniStr.GetBuffer();
580 			const rtl_TextEncoding aTextEncodingOrg = aSrcFont.GetCharSet();
581 			ByteString aByteStr( rUniStr, aTextEncodingOrg );
582 			String	   aUniStr2( aByteStr, aTextEncodingOrg );
583 			const sal_Unicode* pConversion = aUniStr2.GetBuffer();	// this is the unicode array after bytestring <-> unistring conversion
584 			for ( i = 0; i < nStringLen; i++ )
585 			{
586 				if ( *pBuf++ != *pConversion++ )
587 					break;
588 			}
589 
590 			if  ( i != nStringLen )								// after conversion the characters are not original,
591 			{													// try again, with determining a better charset from unicode char
592 				pBuf = rUniStr.GetBuffer();
593 				const sal_Unicode* pCheckChar = pBuf;
594 				rtl_TextEncoding aTextEncoding = getScriptClass (*pCheckChar); // try the first character
595 				for ( i = 1; i < nStringLen; i++)
596 				{
597 					if (aTextEncoding != aTextEncodingOrg) // found something
598 						break;
599 					pCheckChar++;
600 					aTextEncoding = getScriptClass (*pCheckChar); // try the next character
601 				}
602 
603 				aByteStr = ByteString ( rUniStr,  aTextEncoding );
604 				aUniStr2 = String ( aByteStr, aTextEncoding );
605 				pConversion = aUniStr2.GetBuffer();	// this is the unicode array after bytestring <-> unistring conversion
606 				for ( i = 0; i < nStringLen; i++ )
607 				{
608 					if ( *pBuf++ != *pConversion++ )
609 						break;
610 				}
611 				if (i == nStringLen)
612 				{
613 					aSrcFont.SetCharSet (aTextEncoding);
614 					SetAllAttr();
615 				}
616 			}
617 
618 			if ( ( i != nStringLen ) || IsStarSymbol( aSrcFont.GetName() ) )	// after conversion the characters are not original, so we
619 			{																	// will store the unicode string and a polypoly replacement
620 				Color aOldFillColor( aSrcFillColor );
621 				Color aOldLineColor( aSrcLineColor );
622 				aSrcLineInfo  = LineInfo();
623 				aSrcFillColor = aSrcTextColor;
624 				aSrcLineColor = Color( COL_TRANSPARENT );
625 				SetLineAndFillAttr();
626 				pVirDev->SetFont( aSrcFont );
627 				std::vector<PolyPolygon> aPolyPolyVec;
628 				if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniStr ) )
629 				{
630 					sal_uInt32 nDXCount = pDXAry ? nStringLen : 0;
631 					sal_uInt32 nSkipActions = aPolyPolyVec.size();
632 					sal_Int32 nStrmLen = 8 +
633 										   + sizeof( nStringLen ) + ( nStringLen * 2 )
634 										   + sizeof( nDXCount ) + ( nDXCount * 4 )
635 										   + sizeof( nSkipActions );
636 
637 					SvMemoryStream aMemoryStream( nStrmLen );
638 					Point aPt( pVirDev->LogicToLogic( rPoint, aSrcMapMode, aTargetMapMode ) );
639 					aMemoryStream << aPt.X()
640 								  << aPt.Y()
641 								  << nStringLen;
642 					for ( i = 0; i < nStringLen; i++ )
643 						aMemoryStream << rUniStr.GetChar( (sal_uInt16)i );
644 					aMemoryStream << nDXCount;
645 					for ( i = 0; i < nDXCount; i++ )
646 						aMemoryStream << pDXAry[ i ];
647 					aMemoryStream << nSkipActions;
648 					WMFRecord_Escape( PRIVATE_ESCAPE_UNICODE, nStrmLen, (const sal_Int8*)aMemoryStream.GetData() );
649 
650 					std::vector<PolyPolygon>::iterator aIter( aPolyPolyVec.begin() );
651 					while ( aIter != aPolyPolyVec.end() )
652 					{
653 						PolyPolygon aPolyPoly( *aIter++ );
654 						aPolyPoly.Move( rPoint.X(), rPoint.Y() );
655 						WMFRecord_PolyPolygon( aPolyPoly );
656 					}
657 					aSrcFillColor = aOldFillColor;
658 					aSrcLineColor = aOldLineColor;
659 					bEscapeUsed = sal_True;
660 				}
661 			}
662 		}
663 	}
664 	return bEscapeUsed;
665 }
666 
WMFRecord_ExtTextOut(const Point & rPoint,const String & rString,const sal_Int32 * pDXAry)667 void WMFWriter::WMFRecord_ExtTextOut( const Point & rPoint,
668     const String & rString, const sal_Int32 * pDXAry )
669 {
670     sal_uInt16 nOriginalTextLen = rString.Len();
671 
672 	if ( (nOriginalTextLen <= 1) || (pDXAry == NULL) )
673 	{
674 		WMFRecord_TextOut(rPoint, rString);
675 		return;
676 	}
677 	rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
678     ByteString aByteString(rString, eChrSet);
679     TrueExtTextOut(rPoint,rString,aByteString,pDXAry);
680 }
681 
TrueExtTextOut(const Point & rPoint,const String & rString,const ByteString & rByteString,const sal_Int32 * pDXAry)682 void WMFWriter::TrueExtTextOut( const Point & rPoint, const String & rString,
683     const ByteString & rByteString, const sal_Int32 * pDXAry )
684 {
685 	WriteRecordHeader( 0, W_META_EXTTEXTOUT );
686 	WritePointYX( rPoint );
687     sal_uInt16 nNewTextLen = rByteString.Len();
688 	*pWMF << nNewTextLen << (sal_uInt16)0;
689 
690     sal_uInt16 i;
691 	for ( i = 0; i < nNewTextLen; i++ )
692 		*pWMF << (sal_uInt8)rByteString.GetChar( i );
693 	if ( nNewTextLen & 1 )
694 		*pWMF << (sal_uInt8)0;
695 
696     sal_uInt16 nOriginalTextLen = rString.Len();
697 	sal_Int16* pConvertedDXAry = new sal_Int16[ nOriginalTextLen ];
698     sal_Int32 j = 0;
699 	pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ 0 ] );
700 	for ( i = 1; i < ( nOriginalTextLen - 1 ); i++ )
701 		pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ i ] - pDXAry[ i - 1 ] );
702 	pConvertedDXAry[ j ] = (sal_Int16)ScaleWidth( pDXAry[ nOriginalTextLen - 2 ] / ( nOriginalTextLen - 1 ) );
703 
704 	for ( i = 0; i < nOriginalTextLen; i++ )
705 	{
706 		sal_Int16 nDx = pConvertedDXAry[ i ];
707 		*pWMF << nDx;
708 		if ( nOriginalTextLen < nNewTextLen )
709 		{
710 			ByteString aTemp( rString.GetChar( i ), aSrcFont.GetCharSet());
711 			j = aTemp.Len();
712 			while ( --j > 0 )
713 				*pWMF << (sal_uInt16)0;
714 		}
715 	}
716 	delete[] pConvertedDXAry;
717 	UpdateRecordHeader();
718 }
719 
WMFRecord_LineTo(const Point & rPoint)720 void WMFWriter::WMFRecord_LineTo(const Point & rPoint)
721 {
722 	WriteRecordHeader(0x00000005,W_META_LINETO);
723 	WritePointYX(rPoint);
724 }
725 
726 
WMFRecord_MoveTo(const Point & rPoint)727 void WMFWriter::WMFRecord_MoveTo(const Point & rPoint)
728 {
729 	WriteRecordHeader(0x00000005,W_META_MOVETO);
730 	WritePointYX(rPoint);
731 }
732 
733 
WMFRecord_Pie(const Rectangle & rRect,const Point & rStartPt,const Point & rEndPt)734 void WMFWriter::WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
735 {
736 	WriteRecordHeader(0x0000000b,W_META_PIE);
737 	WritePointYX(rEndPt);
738 	WritePointYX(rStartPt);
739 	WriteRectangle(rRect);
740 }
741 
742 
WMFRecord_Polygon(const Polygon & rPoly)743 void WMFWriter::WMFRecord_Polygon(const Polygon & rPoly)
744 {
745 	sal_uInt16 nSize,i;
746 
747 	Polygon aSimplePoly;
748 	if ( rPoly.HasFlags() )
749 		rPoly.AdaptiveSubdivide( aSimplePoly );
750 	else
751 		aSimplePoly = rPoly;
752 	nSize = aSimplePoly.GetSize();
753 	WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYGON);
754 	*pWMF << nSize;
755 	for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i));
756 }
757 
758 
WMFRecord_PolyLine(const Polygon & rPoly)759 void WMFWriter::WMFRecord_PolyLine(const Polygon & rPoly)
760 {
761 	sal_uInt16 nSize,i;
762 	Polygon aSimplePoly;
763 	if ( rPoly.HasFlags() )
764 		rPoly.AdaptiveSubdivide( aSimplePoly );
765 	else
766 		aSimplePoly = rPoly;
767 	nSize=aSimplePoly.GetSize();
768 	WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYLINE);
769 	*pWMF << nSize;
770 	for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i));
771 }
772 
773 
WMFRecord_PolyPolygon(const PolyPolygon & rPolyPoly)774 void WMFWriter::WMFRecord_PolyPolygon(const PolyPolygon & rPolyPoly)
775 {
776 	const Polygon * pPoly;
777 	sal_uInt16 nCount,nSize,i,j;
778 
779 	nCount=rPolyPoly.Count();
780 	PolyPolygon aSimplePolyPoly( rPolyPoly );
781 	for ( i = 0; i < nCount; i++ )
782 	{
783 		if ( aSimplePolyPoly[ i ].HasFlags() )
784 		{
785 			Polygon aSimplePoly;
786 			aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly );
787 			aSimplePolyPoly[ i ] = aSimplePoly;
788 		}
789 	}
790 	WriteRecordHeader(0,W_META_POLYPOLYGON);
791 	*pWMF << nCount;
792 	for (i=0; i<nCount; i++) *pWMF << ((sal_uInt16)(aSimplePolyPoly.GetObject(i).GetSize()));
793 	for (i=0; i<nCount; i++) {
794 		pPoly=&(aSimplePolyPoly.GetObject(i));
795 		nSize=pPoly->GetSize();
796 		for (j=0; j<nSize; j++) WritePointXY(pPoly->GetPoint(j));
797 	}
798 	UpdateRecordHeader();
799 }
800 
801 
WMFRecord_Rectangle(const Rectangle & rRect)802 void WMFWriter::WMFRecord_Rectangle(const Rectangle & rRect)
803 {
804 	WriteRecordHeader( 0x00000007,W_META_RECTANGLE );
805 	WriteRectangle( rRect );
806 }
807 
808 
WMFRecord_RestoreDC()809 void WMFWriter::WMFRecord_RestoreDC()
810 {
811 	WriteRecordHeader(0x00000004,W_META_RESTOREDC);
812 	*pWMF << (short)-1;
813 }
814 
815 
WMFRecord_RoundRect(const Rectangle & rRect,long nHorzRound,long nVertRound)816 void WMFWriter::WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound)
817 {
818 	WriteRecordHeader(0x00000009,W_META_ROUNDRECT);
819 	WriteHeightWidth(Size(nHorzRound,nVertRound));
820 	WriteRectangle(rRect);
821 }
822 
823 
WMFRecord_SaveDC()824 void WMFWriter::WMFRecord_SaveDC()
825 {
826 	WriteRecordHeader(0x00000003,W_META_SAVEDC);
827 }
828 
829 
WMFRecord_SelectObject(sal_uInt16 nObjectHandle)830 void WMFWriter::WMFRecord_SelectObject(sal_uInt16 nObjectHandle)
831 {
832 	WriteRecordHeader(0x00000004,W_META_SELECTOBJECT);
833 	*pWMF << nObjectHandle;
834 }
835 
836 
WMFRecord_SetBkColor(const Color & rColor)837 void WMFWriter::WMFRecord_SetBkColor(const Color & rColor)
838 {
839 	WriteRecordHeader(0x00000005,W_META_SETBKCOLOR);
840 	WriteColor(rColor);
841 }
842 
843 
WMFRecord_SetBkMode(sal_Bool bTransparent)844 void WMFWriter::WMFRecord_SetBkMode(sal_Bool bTransparent)
845 {
846 	WriteRecordHeader(0x00000004,W_META_SETBKMODE);
847 	if (bTransparent==sal_True) *pWMF << (sal_uInt16)W_TRANSPARENT;
848 	else                    *pWMF << (sal_uInt16)W_OPAQUE;
849 }
850 
WMFRecord_SetStretchBltMode()851 void WMFWriter::WMFRecord_SetStretchBltMode()
852 {
853 	WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE );
854 	*pWMF << (sal_uInt16) 3; // STRETCH_DELETESCANS
855 }
856 
WMFRecord_SetPixel(const Point & rPoint,const Color & rColor)857 void WMFWriter::WMFRecord_SetPixel(const Point & rPoint, const Color & rColor)
858 {
859 	WriteRecordHeader(0x00000007,W_META_SETPIXEL);
860 	WriteColor(rColor);
861 	WritePointYX(rPoint);
862 }
863 
864 
WMFRecord_SetROP2(RasterOp eROP)865 void WMFWriter::WMFRecord_SetROP2(RasterOp eROP)
866 {
867 	sal_uInt16 nROP2;
868 
869 	switch (eROP) {
870 		case ROP_INVERT: nROP2=W_R2_NOT;        break;
871 		case ROP_XOR:    nROP2=W_R2_XORPEN;     break;
872 		default:         nROP2=W_R2_COPYPEN;
873 	}
874 	WriteRecordHeader(0x00000004,W_META_SETROP2);
875 	*pWMF << nROP2;
876 }
877 
878 
WMFRecord_SetTextAlign(FontAlign eFontAlign,sal_uInt32 eHorTextAlign)879 void WMFWriter::WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_uInt32 eHorTextAlign)
880 {
881 	sal_uInt16 nAlign;
882 
883 	switch (eFontAlign) {
884 		case ALIGN_TOP:    nAlign=W_TA_TOP; break;
885 		case ALIGN_BOTTOM: nAlign=W_TA_BOTTOM; break;
886 		default:           nAlign=W_TA_BASELINE;
887 	}
888 	nAlign|=eHorTextAlign;
889 	nAlign|=W_TA_NOUPDATECP;
890 
891 	WriteRecordHeader(0x00000004,W_META_SETTEXTALIGN);
892 	*pWMF << nAlign;
893 }
894 
895 
WMFRecord_SetTextColor(const Color & rColor)896 void WMFWriter::WMFRecord_SetTextColor(const Color & rColor)
897 {
898 	WriteRecordHeader(0x00000005,W_META_SETTEXTCOLOR);
899 	WriteColor(rColor);
900 }
901 
902 
WMFRecord_SetWindowExt(const Size & rSize)903 void WMFWriter::WMFRecord_SetWindowExt(const Size & rSize)
904 {
905 	WriteRecordHeader(0x00000005,W_META_SETWINDOWEXT);
906 	WriteHeightWidth(rSize);
907 }
908 
909 
WMFRecord_SetWindowOrg(const Point & rPoint)910 void WMFWriter::WMFRecord_SetWindowOrg(const Point & rPoint)
911 {
912 	WriteRecordHeader(0x00000005,W_META_SETWINDOWORG);
913 	WritePointYX(rPoint);
914 }
915 
916 
WMFRecord_StretchDIB(const Point & rPoint,const Size & rSize,const Bitmap & rBitmap,sal_uInt32 nROP)917 void WMFWriter::WMFRecord_StretchDIB( const Point & rPoint, const Size & rSize,
918 									  const Bitmap & rBitmap, sal_uInt32 nROP )
919 {
920 	sal_uLong nPosAnf,nPosEnd;
921 
922 	nActBitmapPercent=50;
923 	MayCallback();
924 
925 	WriteRecordHeader(0x00000000,W_META_STRETCHDIB);
926 
927 	// Die Reihenfolge im Metafile soll jetzt sein:
928 	// einige Parameter (laenge 22), dann die Bitmap ohne FILEHEADER.
929 	// Da aber *pWMF << rBitmap einen FILEHEADER der Laenge 14
930 	// erzeugt, schreiben wir zuerst die Bitmap an die richtige Position
931 	// Und ueberschreiben hinterher den FILEHEADER mit den Parametern.
932 	nPosAnf=pWMF->Tell(); // Position merken, wo Parameter hin sollen
933 	*pWMF << (long)0 << (long)0; // 8 bytes auffuellen (diese 8 bytes +
934 								 // 14 bytes ueberfluessigen FILEHEADER
935 								 // = 22 bytes Parameter)
936 
937     // write bitmap
938     WriteDIB(rBitmap, *pWMF, false, true);
939 
940 	// Parameter schreiben:
941 	nPosEnd=pWMF->Tell();
942 	pWMF->Seek(nPosAnf);
943 
944 	// Raster-Op bestimmen, falls nichts uebergeben wurde
945 	if( !nROP )
946 	{
947 		switch( eSrcRasterOp )
948 		{
949 			case ROP_INVERT: nROP = W_DSTINVERT; break;
950 			case ROP_XOR:    nROP = W_SRCINVERT; break;
951 			default:         nROP = W_SRCCOPY;
952 		}
953 	}
954 
955 	*pWMF << nROP <<
956 			 (short) 0 <<
957 			 (short) rBitmap.GetSizePixel().Height() <<
958 			 (short) rBitmap.GetSizePixel().Width() <<
959 			 (short) 0 <<
960 			 (short) 0;
961 
962 	WriteHeightWidth(rSize);
963 	WritePointYX(rPoint);
964 	pWMF->Seek(nPosEnd);
965 
966 	UpdateRecordHeader();
967 
968 	nWrittenBitmaps++;
969 	nActBitmapPercent=0;
970 }
971 
972 
WMFRecord_TextOut(const Point & rPoint,const String & rStr)973 void WMFWriter::WMFRecord_TextOut(const Point & rPoint, const String & rStr)
974 {
975     rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
976     ByteString aString( rStr, eChrSet );
977     TrueTextOut(rPoint, aString);
978 }
979 
TrueTextOut(const Point & rPoint,const ByteString & rString)980 void WMFWriter::TrueTextOut(const Point & rPoint, const ByteString& rString)
981 {
982 	sal_uInt16 nLen,i;
983 
984 	WriteRecordHeader(0,W_META_TEXTOUT);
985 	nLen=rString.Len();
986 	*pWMF << nLen;
987 	for ( i = 0; i < nLen; i++ )
988 		*pWMF << (sal_uInt8)rString.GetChar( i );
989 	if ((nLen&1)!=0) *pWMF << (sal_uInt8)0;
990 	WritePointYX(rPoint);
991 	UpdateRecordHeader();
992 }
993 
WMFRecord_EndOfFile()994 void WMFWriter::WMFRecord_EndOfFile()
995 {
996 	WriteRecordHeader(0x00000003,0x0000);
997 }
998 
999 
WMFRecord_IntersectClipRect(const Rectangle & rRect)1000 void WMFWriter::WMFRecord_IntersectClipRect( const Rectangle& rRect )
1001 {
1002 	WriteRecordHeader( 0x00000007, W_META_INTERSECTCLIPRECT );
1003 	WriteRectangle(rRect);
1004 }
1005 
1006 
AllocHandle()1007 sal_uInt16 WMFWriter::AllocHandle()
1008 {
1009 	sal_uInt16 i;
1010 
1011 	for (i=0; i<MAXOBJECTHANDLES; i++) {
1012 		if (bHandleAllocated[i]==sal_False) {
1013 			bHandleAllocated[i]=sal_True;
1014 			return i;
1015 		}
1016 	}
1017 	bStatus=sal_False;
1018 	return 0xffff;
1019 }
1020 
1021 
FreeHandle(sal_uInt16 nObjectHandle)1022 void WMFWriter::FreeHandle(sal_uInt16 nObjectHandle)
1023 {
1024 	if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=sal_False;
1025 }
1026 
1027 
CreateSelectDeletePen(const Color & rColor,const LineInfo & rLineInfo)1028 void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo )
1029 {
1030 	sal_uInt16 nOldHandle;
1031 
1032 	nOldHandle=nDstPenHandle;
1033 	nDstPenHandle=AllocHandle();
1034 	WMFRecord_CreatePenIndirect( rColor, rLineInfo );
1035 	WMFRecord_SelectObject(nDstPenHandle);
1036 	if (nOldHandle<MAXOBJECTHANDLES) {
1037 		WMFRecord_DeleteObject(nOldHandle);
1038 		FreeHandle(nOldHandle);
1039 	}
1040 }
1041 
1042 
CreateSelectDeleteFont(const Font & rFont)1043 void WMFWriter::CreateSelectDeleteFont(const Font & rFont)
1044 {
1045 	sal_uInt16 nOldHandle;
1046 
1047 	nOldHandle=nDstFontHandle;
1048 	nDstFontHandle=AllocHandle();
1049 	WMFRecord_CreateFontIndirect(rFont);
1050 	WMFRecord_SelectObject(nDstFontHandle);
1051 	if (nOldHandle<MAXOBJECTHANDLES) {
1052 		WMFRecord_DeleteObject(nOldHandle);
1053 		FreeHandle(nOldHandle);
1054 	}
1055 }
1056 
1057 
CreateSelectDeleteBrush(const Color & rColor)1058 void WMFWriter::CreateSelectDeleteBrush(const Color& rColor)
1059 {
1060 	sal_uInt16 nOldHandle;
1061 
1062 	nOldHandle=nDstBrushHandle;
1063 	nDstBrushHandle=AllocHandle();
1064 	WMFRecord_CreateBrushIndirect(rColor);
1065 	WMFRecord_SelectObject(nDstBrushHandle);
1066 	if (nOldHandle<MAXOBJECTHANDLES) {
1067 		WMFRecord_DeleteObject(nOldHandle);
1068 		FreeHandle(nOldHandle);
1069 	}
1070 }
1071 
1072 
SetLineAndFillAttr()1073 void WMFWriter::SetLineAndFillAttr()
1074 {
1075 	if ( eDstROP2 != eSrcRasterOp )
1076     {
1077 		eDstROP2=eSrcRasterOp;
1078 		WMFRecord_SetROP2(eDstROP2);
1079 	}
1080 	if ( ( aDstLineColor != aSrcLineColor ) || ( aDstLineInfo != aSrcLineInfo ) )
1081     {
1082 		aDstLineColor = aSrcLineColor;
1083 		aDstLineInfo  = aSrcLineInfo;
1084 		CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
1085 	}
1086 	if ( aDstFillColor != aSrcFillColor )
1087     {
1088 		aDstFillColor = aSrcFillColor;
1089 		CreateSelectDeleteBrush( aDstFillColor );
1090 	}
1091 	if ( bDstIsClipping != bSrcIsClipping ||
1092 		(bSrcIsClipping==sal_True && aDstClipRegion!=aSrcClipRegion)) {
1093 		bDstIsClipping=bSrcIsClipping;
1094 		aDstClipRegion=aSrcClipRegion;
1095 	}
1096 }
1097 
SetAllAttr()1098 void WMFWriter::SetAllAttr()
1099 {
1100     SetLineAndFillAttr();
1101 	if ( aDstTextColor != aSrcTextColor )
1102     {
1103 		aDstTextColor = aSrcTextColor;
1104 		WMFRecord_SetTextColor(aDstTextColor);
1105 	}
1106 	if ( eDstTextAlign != eSrcTextAlign || eDstHorTextAlign != eSrcHorTextAlign )
1107     {
1108 		eDstTextAlign = eSrcTextAlign;
1109 		eDstHorTextAlign = eSrcHorTextAlign;
1110 		WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
1111 	}
1112 	if ( aDstFont != aSrcFont )
1113 	{
1114 		pVirDev->SetFont(aSrcFont);
1115 		if ( aDstFont.GetName() != aSrcFont.GetName() )
1116 		{
1117 			FontCharMap aFontCharMap;
1118 			if ( pVirDev->GetFontCharMap( aFontCharMap ) )
1119 			{
1120 				if ( ( aFontCharMap.GetFirstChar() & 0xff00 ) == 0xf000 )
1121 					aSrcFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
1122 				else if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
1123 					aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
1124 			}
1125 		}
1126 		aDstFont = aSrcFont;
1127 		CreateSelectDeleteFont(aDstFont);
1128 	}
1129 }
1130 
1131 
HandleLineInfoPolyPolygons(const LineInfo & rInfo,const basegfx::B2DPolygon & rLinePolygon)1132 void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
1133 {
1134 	if(rLinePolygon.count())
1135 	{
1136 		basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
1137 		basegfx::B2DPolyPolygon aFillPolyPolygon;
1138 
1139 		rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
1140 
1141 		if(aLinePolyPolygon.count())
1142 		{
1143 			aSrcLineInfo = rInfo;
1144 			SetLineAndFillAttr();
1145 
1146 			for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
1147 			{
1148 				const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
1149 				WMFRecord_PolyLine(Polygon(aCandidate));
1150 			}
1151 		}
1152 
1153 		if(aFillPolyPolygon.count())
1154 		{
1155 			const Color aOldLineColor(aSrcLineColor);
1156 			const Color aOldFillColor(aSrcFillColor);
1157 
1158 			aSrcLineColor = Color( COL_TRANSPARENT );
1159 			aSrcFillColor = aOldLineColor;
1160 			SetLineAndFillAttr();
1161 
1162 			for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
1163 			{
1164 				const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
1165 				WMFRecord_Polygon(Polygon(aPolygon));
1166 			}
1167 
1168 			aSrcLineColor = aOldLineColor;
1169 			aSrcFillColor = aOldFillColor;
1170 			SetLineAndFillAttr();
1171 		}
1172 	}
1173 }
1174 
WriteRecords(const GDIMetaFile & rMTF)1175 void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
1176 {
1177 	sal_uLong		nA, nACount;
1178 	MetaAction*	pMA;
1179 
1180 	if( bStatus )
1181 	{
1182 		nACount = rMTF.GetActionCount();
1183 
1184 		WMFRecord_SetStretchBltMode();
1185 
1186 		for( nA=0; nA<nACount; nA++ )
1187 		{
1188 			pMA = rMTF.GetAction( nA );
1189 
1190 			switch( pMA->GetType() )
1191 			{
1192 				case META_PIXEL_ACTION:
1193 				{
1194 					const MetaPixelAction* pA = (const MetaPixelAction *) pMA;
1195 					aSrcLineInfo = LineInfo();
1196 					SetLineAndFillAttr();
1197 					WMFRecord_SetPixel( pA->GetPoint(), pA->GetColor() );
1198 				}
1199 				break;
1200 
1201 				case META_POINT_ACTION:
1202 				{
1203 					const MetaPointAction*	pA = (const MetaPointAction*) pMA;
1204 					const Point&			rPt = pA->GetPoint();
1205 					aSrcLineInfo = LineInfo();
1206 					SetLineAndFillAttr();
1207 					WMFRecord_MoveTo( rPt);
1208 					WMFRecord_LineTo( rPt );
1209 				}
1210 				break;
1211 
1212 				case META_LINE_ACTION:
1213 				{
1214 					const MetaLineAction* pA = (const MetaLineAction *) pMA;
1215                     if(pA->GetLineInfo().IsDefault())
1216                     {
1217 					    aSrcLineInfo = pA->GetLineInfo();
1218 					    SetLineAndFillAttr();
1219 					    WMFRecord_MoveTo( pA->GetStartPoint() );
1220 					    WMFRecord_LineTo( pA->GetEndPoint() );
1221                     }
1222                     else
1223                     {
1224                         // LineInfo used; handle Dash/Dot and fat lines
1225                         basegfx::B2DPolygon aPolygon;
1226                         aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1227                         aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1228                         HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
1229                     }
1230 				}
1231 				break;
1232 
1233 				case META_RECT_ACTION:
1234 				{
1235 					const MetaRectAction* pA = (const MetaRectAction*) pMA;
1236 					aSrcLineInfo = LineInfo();
1237 					SetLineAndFillAttr();
1238 					WMFRecord_Rectangle( pA->GetRect() );
1239 				}
1240 				break;
1241 
1242 				case META_ROUNDRECT_ACTION:
1243 				{
1244 					const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pMA;
1245 					aSrcLineInfo = LineInfo();
1246 					SetLineAndFillAttr();
1247 					WMFRecord_RoundRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
1248 				}
1249 				break;
1250 
1251 				case META_ELLIPSE_ACTION:
1252 				{
1253 					const MetaEllipseAction* pA = (const MetaEllipseAction*) pMA;
1254 					aSrcLineInfo = LineInfo();
1255 					SetLineAndFillAttr();
1256 					WMFRecord_Ellipse( pA->GetRect() );
1257 				}
1258 				break;
1259 
1260 				case META_ARC_ACTION:
1261 				{
1262 					const MetaArcAction* pA = (const MetaArcAction*) pMA;
1263 					aSrcLineInfo = LineInfo();
1264 					SetLineAndFillAttr();
1265 					WMFRecord_Arc( pA->GetRect(),pA->GetStartPoint(),pA->GetEndPoint() );
1266 				}
1267 				break;
1268 
1269 				case META_PIE_ACTION:
1270 				{
1271 					const MetaPieAction* pA = (const MetaPieAction*) pMA;
1272 					aSrcLineInfo = LineInfo();
1273 					SetLineAndFillAttr();
1274 					WMFRecord_Pie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1275 				}
1276 				break;
1277 
1278 
1279 				case META_CHORD_ACTION:
1280 				{
1281 					const MetaChordAction* pA = (const MetaChordAction*) pMA;
1282 					aSrcLineInfo = LineInfo();
1283 					SetLineAndFillAttr();
1284 					WMFRecord_Chord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1285 				}
1286 				break;
1287 
1288 				case META_POLYLINE_ACTION:
1289 				{
1290 					const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pMA;
1291 				    const Polygon&				rPoly = pA->GetPolygon();
1292 
1293 			        if( rPoly.GetSize() )
1294                     {
1295                         if(pA->GetLineInfo().IsDefault())
1296                         {
1297 					        aSrcLineInfo = pA->GetLineInfo();
1298 					        SetLineAndFillAttr();
1299 					        WMFRecord_PolyLine( rPoly );
1300                         }
1301                         else
1302                         {
1303                             // LineInfo used; handle Dash/Dot and fat lines
1304                             HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1305                         }
1306                     }
1307 				}
1308 				break;
1309 
1310 				case META_POLYGON_ACTION:
1311 				{
1312 					const MetaPolygonAction* pA = (const MetaPolygonAction*) pMA;
1313 					aSrcLineInfo = LineInfo();
1314 					SetLineAndFillAttr();
1315 					WMFRecord_Polygon( pA->GetPolygon() );
1316 				}
1317 				break;
1318 
1319 				case META_POLYPOLYGON_ACTION:
1320 				{
1321 					const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pMA;
1322 					aSrcLineInfo = LineInfo();
1323 					SetLineAndFillAttr();
1324 					WMFRecord_PolyPolygon( pA->GetPolyPolygon() );
1325 				}
1326 				break;
1327 
1328 				case META_TEXTRECT_ACTION:
1329 				{
1330 					const MetaTextRectAction * pA = (const MetaTextRectAction*)pMA;
1331 					String aTemp( pA->GetText() );
1332 					aSrcLineInfo = LineInfo();
1333 			        SetAllAttr();
1334 
1335 					Point aPos( pA->GetRect().TopLeft() );
1336 					if ( !WMFRecord_Escape_Unicode( aPos, aTemp, NULL ) )
1337 						WMFRecord_TextOut( aPos, aTemp );
1338 				}
1339 				break;
1340 
1341 				case META_TEXT_ACTION:
1342 				{
1343 					const MetaTextAction * pA = (const MetaTextAction*) pMA;
1344 					String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1345 					aSrcLineInfo = LineInfo();
1346 			        SetAllAttr();
1347 					if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, NULL ) )
1348 						WMFRecord_TextOut( pA->GetPoint(), aTemp );
1349 				}
1350 				break;
1351 
1352 				case META_TEXTARRAY_ACTION:
1353 				{
1354 					const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pMA;
1355 
1356 					String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1357 					aSrcLineInfo = LineInfo();
1358 				    SetAllAttr();
1359 					if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pA->GetDXArray() ) )
1360 						WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pA->GetDXArray() );
1361 				}
1362 				break;
1363 
1364 				case META_STRETCHTEXT_ACTION:
1365 				{
1366 					const MetaStretchTextAction* pA = (const MetaStretchTextAction *) pMA;
1367 					String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1368 
1369 					sal_uInt16 nLen,i;
1370 					sal_Int32 nNormSize;
1371 
1372 					pVirDev->SetFont( aSrcFont );
1373 					nLen = aTemp.Len();
1374 					sal_Int32* pDXAry = nLen ? new sal_Int32[ nLen ] : NULL;
1375 					nNormSize = pVirDev->GetTextArray( aTemp, pDXAry );
1376 					for ( i = 0; i < ( nLen - 1 ); i++ )
1377 						pDXAry[ i ] = pDXAry[ i ] * (sal_Int32)pA->GetWidth() / nNormSize;
1378 					if ( ( nLen <= 1 ) || ( (sal_Int32)pA->GetWidth() == nNormSize ) )
1379 						delete[] pDXAry, pDXAry = NULL;
1380 					aSrcLineInfo = LineInfo();
1381 					SetAllAttr();
1382 					if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pDXAry ) )
1383 						WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pDXAry );
1384 					delete[] pDXAry;
1385 				}
1386 				break;
1387 
1388 				case META_BMP_ACTION:
1389 				{
1390 					const MetaBmpAction* pA = (const MetaBmpAction *) pMA;
1391 					WMFRecord_StretchDIB( pA->GetPoint(), pA->GetBitmap().GetSizePixel(), pA->GetBitmap() );
1392 				}
1393 				break;
1394 
1395 				case META_BMPSCALE_ACTION:
1396 				{
1397 					const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pMA;
1398 					WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pA->GetBitmap() );
1399 				}
1400 				break;
1401 
1402 				case META_BMPSCALEPART_ACTION:
1403 				{
1404 					const MetaBmpScalePartAction*	pA = (const MetaBmpScalePartAction*) pMA;
1405 					Bitmap							aTmp( pA->GetBitmap() );
1406 
1407 					if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1408 						WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aTmp );
1409 				}
1410 				break;
1411 
1412 				case META_BMPEX_ACTION:
1413 				{
1414 					const MetaBmpExAction*	pA = (const MetaBmpExAction *) pMA;
1415 					Bitmap					aBmp( pA->GetBitmapEx().GetBitmap() );
1416 					Bitmap					aMsk( pA->GetBitmapEx().GetMask() );
1417 
1418 					if( !!aMsk )
1419 					{
1420 						aBmp.Replace( aMsk, COL_WHITE );
1421 						aMsk.Invert();
1422 						WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT );
1423 						WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND );
1424 					}
1425 					else
1426 						WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp );
1427 				}
1428 				break;
1429 
1430 				case META_BMPEXSCALE_ACTION:
1431 				{
1432 					const MetaBmpExScaleAction*	pA = (const MetaBmpExScaleAction*) pMA;
1433 					Bitmap						aBmp( pA->GetBitmapEx().GetBitmap() );
1434 					Bitmap						aMsk( pA->GetBitmapEx().GetMask() );
1435 
1436 					if( !!aMsk )
1437 					{
1438 						aBmp.Replace( aMsk, COL_WHITE );
1439 						aMsk.Invert();
1440 						WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT );
1441 						WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND );
1442 					}
1443 					else
1444 						WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp );
1445 				}
1446 				break;
1447 
1448 				case META_BMPEXSCALEPART_ACTION:
1449 				{
1450 					const MetaBmpExScalePartAction*	pA = (const MetaBmpExScalePartAction*) pMA;
1451 					BitmapEx						aBmpEx( pA->GetBitmapEx() );
1452 					aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1453 					Bitmap							aBmp( aBmpEx.GetBitmap() );
1454 					Bitmap							aMsk( aBmpEx.GetMask() );
1455 
1456 					if( !!aMsk )
1457 					{
1458 						aBmp.Replace( aMsk, COL_WHITE );
1459 						aMsk.Invert();
1460 						WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT );
1461 						WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND );
1462 					}
1463 					else
1464 						WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp );
1465 				}
1466 				break;
1467 
1468 				case META_GRADIENT_ACTION:
1469 				{
1470 					const MetaGradientAction*	pA = (const MetaGradientAction*) pMA;
1471 					GDIMetaFile					aTmpMtf;
1472 
1473 					pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1474 					WriteRecords( aTmpMtf );
1475 				}
1476 				break;
1477 
1478 				case META_HATCH_ACTION:
1479 				{
1480 					const MetaHatchAction*	pA = (const MetaHatchAction*) pMA;
1481 					GDIMetaFile				aTmpMtf;
1482 
1483 					pVirDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1484 					WriteRecords( aTmpMtf );
1485 				}
1486 				break;
1487 
1488 				case META_WALLPAPER_ACTION:
1489 				{
1490 					const MetaWallpaperAction*	pA = (const MetaWallpaperAction*) pMA;
1491 					const Color&				rColor = pA->GetWallpaper().GetColor();
1492 					const Color					aOldLineColor( aSrcLineColor );
1493 					const Color					aOldFillColor( aSrcFillColor );
1494 
1495 					aSrcLineColor = rColor;
1496 					aSrcFillColor = rColor;
1497 					aSrcLineInfo = LineInfo();
1498 					SetLineAndFillAttr();
1499 					WMFRecord_Rectangle( pA->GetRect() );
1500 					aSrcLineColor = aOldLineColor;
1501 					aSrcFillColor = aOldFillColor;
1502 				}
1503 				break;
1504 
1505 				case META_ISECTRECTCLIPREGION_ACTION:
1506 				{
1507 					const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pMA;
1508 					WMFRecord_IntersectClipRect( pA->GetRect() );
1509 				}
1510 				break;
1511 
1512 				case META_LINECOLOR_ACTION:
1513 				{
1514 					const MetaLineColorAction* pA = (const MetaLineColorAction*) pMA;
1515 
1516 					if( pA->IsSetting() )
1517 						aSrcLineColor = pA->GetColor();
1518 					else
1519 						aSrcLineColor = Color( COL_TRANSPARENT );
1520 				}
1521 				break;
1522 
1523 				case META_FILLCOLOR_ACTION:
1524 				{
1525 					const MetaFillColorAction* pA = (const MetaFillColorAction*) pMA;
1526 
1527 					if( pA->IsSetting() )
1528 						aSrcFillColor = pA->GetColor();
1529 					else
1530 						aSrcFillColor = Color( COL_TRANSPARENT );
1531 				}
1532 				break;
1533 
1534 				case META_TEXTCOLOR_ACTION:
1535 				{
1536 					const MetaTextColorAction* pA = (const MetaTextColorAction*) pMA;
1537 					aSrcTextColor = pA->GetColor();
1538 				}
1539 				break;
1540 
1541 				case META_TEXTFILLCOLOR_ACTION:
1542 				{
1543 					const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*) pMA;
1544 					if( pA->IsSetting() )
1545 						aSrcFont.SetFillColor( pA->GetColor() );
1546 					else
1547 						aSrcFont.SetFillColor( Color( COL_TRANSPARENT ) );
1548 				}
1549 				break;
1550 
1551 				case META_TEXTALIGN_ACTION:
1552 				{
1553 					const MetaTextAlignAction* pA = (const MetaTextAlignAction*) pMA;
1554 					eSrcTextAlign = pA->GetTextAlign();
1555 				}
1556 				break;
1557 
1558 				case META_MAPMODE_ACTION:
1559 				{
1560 					const MetaMapModeAction* pA = (const MetaMapModeAction*) pMA;
1561 
1562 					if (aSrcMapMode!=pA->GetMapMode())
1563 					{
1564 						if( pA->GetMapMode().GetMapUnit() == MAP_RELATIVE )
1565 						{
1566 							MapMode aMM = pA->GetMapMode();
1567 							Fraction aScaleX = aMM.GetScaleX();
1568 							Fraction aScaleY = aMM.GetScaleY();
1569 
1570 							Point aOrigin = aSrcMapMode.GetOrigin();
1571 							BigInt aX( aOrigin.X() );
1572 							aX *= BigInt( aScaleX.GetDenominator() );
1573 							if( aOrigin.X() >= 0 )
1574 								if( aScaleX.GetNumerator() >= 0 )
1575 									aX += BigInt( aScaleX.GetNumerator()/2 );
1576 								else
1577 									aX -= BigInt( (aScaleX.GetNumerator()+1)/2 );
1578 							else
1579 								if( aScaleX.GetNumerator() >= 0 )
1580 									aX -= BigInt( (aScaleX.GetNumerator()-1)/2 );
1581 								else
1582 									aX += BigInt( aScaleX.GetNumerator()/2 );
1583 							aX /= BigInt( aScaleX.GetNumerator() );
1584 							aOrigin.X() = (long)aX + aMM.GetOrigin().X();
1585 							BigInt aY( aOrigin.Y() );
1586 							aY *= BigInt( aScaleY.GetDenominator() );
1587 							if( aOrigin.Y() >= 0 )
1588 								if( aScaleY.GetNumerator() >= 0 )
1589 									aY += BigInt( aScaleY.GetNumerator()/2 );
1590 								else
1591 									aY -= BigInt( (aScaleY.GetNumerator()+1)/2 );
1592 							else
1593 								if( aScaleY.GetNumerator() >= 0 )
1594 									aY -= BigInt( (aScaleY.GetNumerator()-1)/2 );
1595 								else
1596 									aY += BigInt( aScaleY.GetNumerator()/2 );
1597 							aY /= BigInt( aScaleY.GetNumerator() );
1598 							aOrigin.Y() = (long)aY + aMM.GetOrigin().Y();
1599 							aSrcMapMode.SetOrigin( aOrigin );
1600 
1601 							aScaleX *= aSrcMapMode.GetScaleX();
1602 							aScaleY *= aSrcMapMode.GetScaleY();
1603 							aSrcMapMode.SetScaleX( aScaleX );
1604 							aSrcMapMode.SetScaleY( aScaleY );
1605 						}
1606 						else
1607 							aSrcMapMode=pA->GetMapMode();
1608 					}
1609 				}
1610 				break;
1611 
1612 				case META_FONT_ACTION:
1613 				{
1614 					const MetaFontAction* pA = (const MetaFontAction*) pMA;
1615 					aSrcFont = pA->GetFont();
1616 
1617 					if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
1618 						aSrcFont.SetCharSet( GetExtendedTextEncoding( gsl_getSystemTextEncoding() ) );
1619 					if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_UNICODE )
1620 						aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
1621                     eSrcTextAlign = aSrcFont.GetAlign();
1622                     aSrcTextColor = aSrcFont.GetColor();
1623                     aSrcFont.SetAlign( ALIGN_BASELINE );
1624                     aSrcFont.SetColor( COL_WHITE );
1625 				}
1626 				break;
1627 
1628 				case META_PUSH_ACTION:
1629 				{
1630 					const MetaPushAction* pA = (const MetaPushAction*)pMA;
1631 
1632 					WMFWriterAttrStackMember* pAt = new WMFWriterAttrStackMember;
1633                     pAt->nFlags = pA->GetFlags();
1634     				pAt->aClipRegion = aSrcClipRegion;
1635     				pAt->aLineColor=aSrcLineColor;
1636 					pAt->aFillColor=aSrcFillColor;
1637 					pAt->eRasterOp=eSrcRasterOp;
1638 					pAt->aFont=aSrcFont;
1639                     pAt->eTextAlign=eSrcTextAlign;
1640                     pAt->aTextColor=aSrcTextColor;
1641 					pAt->aMapMode=aSrcMapMode;
1642 					pAt->aLineInfo=aDstLineInfo;
1643 					pAt->pSucc=pAttrStack;
1644 					pAttrStack=pAt;
1645 
1646                     SetAllAttr();           // update ( now all source attributes are equal to the destination attributes )
1647         			WMFRecord_SaveDC();
1648 
1649 				}
1650 				break;
1651 
1652 				case META_POP_ACTION:
1653 				{
1654 					WMFWriterAttrStackMember * pAt=pAttrStack;
1655 
1656 					if( pAt )
1657 					{
1658 						aDstLineInfo = pAt->aLineInfo;
1659 						aDstLineColor = pAt->aLineColor;
1660                         if ( pAt->nFlags & PUSH_LINECOLOR )
1661 						    aSrcLineColor = pAt->aLineColor;
1662 						aDstFillColor = pAt->aFillColor;
1663                         if ( pAt->nFlags & PUSH_FILLCOLOR )
1664 						    aSrcFillColor = pAt->aFillColor;
1665 						eDstROP2 = pAt->eRasterOp;
1666                         if ( pAt->nFlags & PUSH_RASTEROP )
1667 						    eSrcRasterOp = pAt->eRasterOp;
1668 					    aDstFont = pAt->aFont;
1669                         if ( pAt->nFlags & PUSH_FONT )
1670 					        aSrcFont = pAt->aFont;
1671                         eDstTextAlign = pAt->eTextAlign;
1672                         if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTALIGN ) )
1673                             eSrcTextAlign = pAt->eTextAlign;
1674                         aDstTextColor = pAt->aTextColor;
1675                         if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTCOLOR ) )
1676                             aSrcTextColor = pAt->aTextColor;
1677                         if ( pAt->nFlags & PUSH_MAPMODE )
1678                             aSrcMapMode = pAt->aMapMode;
1679 						aDstClipRegion = pAt->aClipRegion;
1680                         if ( pAt->nFlags & PUSH_CLIPREGION )
1681 						    aSrcClipRegion = pAt->aClipRegion;
1682 
1683 						WMFRecord_RestoreDC();
1684 						pAttrStack = pAt->pSucc;
1685 						delete pAt;
1686 					}
1687 				}
1688 				break;
1689 
1690 				case META_EPS_ACTION :
1691 				{
1692 					const MetaEPSAction* pA = (const MetaEPSAction*)pMA;
1693 					const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
1694 
1695 					sal_Int32 nCount = aGDIMetaFile.GetActionCount();
1696 					for ( sal_Int32 i = 0; i < nCount; i++ )
1697 					{
1698 						const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i );
1699 						if ( pMetaAct->GetType() == META_BMPSCALE_ACTION )
1700 						{
1701 							const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*)pMetaAct;
1702 							WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap() );
1703 							break;
1704 						}
1705 					}
1706 				}
1707 				break;
1708 
1709 				case META_RASTEROP_ACTION:
1710 				{
1711 					const MetaRasterOpAction* pA = (const MetaRasterOpAction*) pMA;
1712 					eSrcRasterOp=pA->GetRasterOp();
1713                 }
1714 				break;
1715 
1716 				case META_TRANSPARENT_ACTION:
1717 				{
1718 					aSrcLineInfo = LineInfo();
1719 					SetLineAndFillAttr();
1720 					WMFRecord_PolyPolygon( ( (MetaTransparentAction*) pMA )->GetPolyPolygon() );
1721 				}
1722 				break;
1723 
1724 				case META_FLOATTRANSPARENT_ACTION:
1725 				{
1726 					const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pMA;
1727 
1728 					GDIMetaFile		aTmpMtf( pA->GetGDIMetaFile() );
1729 					Point			aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1730 					const Size		aSrcSize( aTmpMtf.GetPrefSize() );
1731 					const Point		aDestPt( pA->GetPoint() );
1732 					const Size		aDestSize( pA->GetSize() );
1733 					const double	fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1734 					const double	fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1735 					long			nMoveX, nMoveY;
1736 
1737 					aSrcLineInfo = LineInfo();
1738 					SetAllAttr();
1739 
1740 					if( fScaleX != 1.0 || fScaleY != 1.0 )
1741 					{
1742 						aTmpMtf.Scale( fScaleX, fScaleY );
1743 						aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1744 					}
1745 
1746 					nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
1747 
1748 					if( nMoveX || nMoveY )
1749 						aTmpMtf.Move( nMoveX, nMoveY );
1750 
1751 					WriteRecords( aTmpMtf );
1752 				}
1753 				break;
1754 
1755 				case( META_LAYOUTMODE_ACTION ):
1756 				{
1757 					sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pMA )->GetLayoutMode();
1758 					eSrcHorTextAlign = 0; // TA_LEFT
1759 					if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL)
1760 					{
1761 						eSrcHorTextAlign = W_TA_RIGHT | W_TA_RTLREADING;
1762 					}
1763 					if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT)
1764 						eSrcHorTextAlign |= W_TA_RIGHT;
1765 					else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT)
1766 						eSrcHorTextAlign &= ~W_TA_RIGHT;
1767 					break;
1768 				}
1769 
1770 				// Unsupported Actions
1771 				case META_MASK_ACTION:
1772 				case META_MASKSCALE_ACTION:
1773 				case META_MASKSCALEPART_ACTION:
1774 				{
1775 					DBG_ERROR( "Unsupported action: MetaMask...Action!" );
1776 				}
1777 				break;
1778 
1779 				case META_CLIPREGION_ACTION:
1780 				break;
1781 
1782 				case META_ISECTREGIONCLIPREGION_ACTION:
1783 				{
1784 					DBG_ERROR( "Unsupported action: MetaISectRegionClipRegionAction!" );
1785 				}
1786 				break;
1787 
1788 				case META_MOVECLIPREGION_ACTION:
1789 				{
1790 					DBG_ERROR( "Unsupported action: MetaMoveClipRegionAction!" );
1791 				}
1792 				break;
1793 
1794 				default:
1795 				{
1796 					DBG_ERROR( "Unsupported meta action!" );
1797 				}
1798 				break;
1799 		  }
1800 
1801 		  nWrittenActions++;
1802 		  MayCallback();
1803 
1804 		  if (pWMF->GetError())
1805 			bStatus=sal_False;
1806 
1807 		  if(bStatus==sal_False)
1808 			break;
1809 		}
1810 	}
1811 }
1812 
1813 // ------------------------------------------------------------------------
1814 
WriteHeader(const GDIMetaFile &,sal_Bool bPlaceable)1815 void WMFWriter::WriteHeader( const GDIMetaFile &, sal_Bool bPlaceable )
1816 {
1817 	if( bPlaceable )
1818 	{
1819 		sal_uInt16	nCheckSum, nValue;
1820 		Size	aSize( pVirDev->LogicToLogic(Size(1,1),MapMode(MAP_INCH), aTargetMapMode) );
1821 		sal_uInt16	nUnitsPerInch = (sal_uInt16) ( ( aSize.Width() + aSize.Height() ) >> 1 );
1822 
1823 		nCheckSum=0;
1824 		nValue=0xcdd7;                              nCheckSum^=nValue; *pWMF << nValue;
1825 		nValue=0x9ac6;                              nCheckSum^=nValue; *pWMF << nValue;
1826 		nValue=0x0000;                              nCheckSum^=nValue; *pWMF << nValue;
1827 		nValue=0x0000;                              nCheckSum^=nValue; *pWMF << nValue;
1828 		nValue=0x0000;                              nCheckSum^=nValue; *pWMF << nValue;
1829 		nValue=(sal_uInt16) aTargetSize.Width();		nCheckSum^=nValue; *pWMF << nValue;
1830 		nValue=(sal_uInt16) aTargetSize.Height();		nCheckSum^=nValue; *pWMF << nValue;
1831 		nValue=nUnitsPerInch;                       nCheckSum^=nValue; *pWMF << nValue;
1832 		nValue=0x0000;                              nCheckSum^=nValue; *pWMF << nValue;
1833 		nValue=0x0000;                              nCheckSum^=nValue; *pWMF << nValue;
1834 		*pWMF << nCheckSum;
1835 	}
1836 
1837 	nMetafileHeaderPos=pWMF->Tell();
1838 	*pWMF << (sal_uInt16)0x0001           // Typ: Datei
1839 		  << (sal_uInt16)0x0009           // Headerlaenge in Worten
1840 		  << (sal_uInt16)0x0300           // Version als BCD-Zahl
1841 		  << (sal_uInt32) 0x00000000  	  // Dateilaenge (ohne 1. Header), wird spaeter durch UpdateHeader() berichtigt
1842 		  << (sal_uInt16)MAXOBJECTHANDLES // Maximalezahl der gleichzeitigen Objekte
1843 		  << (sal_uInt32) 0x00000000  	  // Maximale Record-laenge, wird spaeter durch UpdateHeader() berichtigt
1844 		  << (sal_uInt16)0x0000;          // Reserved
1845 }
1846 
1847 // ------------------------------------------------------------------------
1848 
UpdateHeader()1849 void WMFWriter::UpdateHeader()
1850 {
1851 	sal_uLong nPos;
1852 	sal_uInt32 nFileSize;
1853 
1854 	nPos=pWMF->Tell();                 // Endposition = Gesammtgroesse der Datei
1855 	nFileSize=nPos-nMetafileHeaderPos; // Groesse des 1. Headers abziehen
1856 	if ((nFileSize&1)!=0) {            // ggf. auf ganze Worte aufrunden
1857 		*pWMF << (sal_uInt8)0;
1858 		nPos++;
1859 		nFileSize++;
1860 	}
1861 	nFileSize>>=1;                    // In Anzahl Worte umrechnen
1862 	pWMF->Seek(nMetafileHeaderPos+6); // Zum Dateigroessen-Eintrag im zweiten Header
1863 	*pWMF << nFileSize;               // Dateigroesse berichtigen
1864 	pWMF->SeekRel(2);                 // Zum Max-Record-Laenge-Eintrag im zweiten Header
1865 	*pWMF << nMaxRecordSize;          // und berichtigen
1866 	pWMF->Seek(nPos);
1867 }
1868 
1869 // ------------------------------------------------------------------------
1870 
WriteWMF(const GDIMetaFile & rMTF,SvStream & rTargetStream,FilterConfigItem * pFConfigItem,sal_Bool bPlaceable)1871 sal_Bool WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream,
1872 							FilterConfigItem* pFConfigItem, sal_Bool bPlaceable )
1873 {
1874 	WMFWriterAttrStackMember * pAt;
1875 
1876     bEmbedEMF = sal_True;
1877 	bStatus=sal_True;
1878     pConvert = 0;
1879 	pVirDev = new VirtualDevice;
1880 
1881 	pFilterConfigItem = pFConfigItem;
1882 	if ( pFilterConfigItem )
1883 	{
1884 		xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
1885 		if ( xStatusIndicator.is() )
1886 		{
1887 			rtl::OUString aMsg;
1888 			xStatusIndicator->start( aMsg, 100 );
1889 		}
1890 	}
1891 	nLastPercent=0;
1892 
1893 	pWMF=&rTargetStream;
1894 	pWMF->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
1895 
1896 	nMaxRecordSize=0;
1897 
1898 	aSrcMapMode=rMTF.GetPrefMapMode();
1899 
1900 	if( bPlaceable )
1901 	{
1902 		aTargetMapMode = aSrcMapMode;
1903 		aTargetSize = rMTF.GetPrefSize();
1904 		nTargetDivisor = CalcSaveTargetMapMode(aTargetMapMode, aTargetSize);
1905 		aTargetSize.Width() /= nTargetDivisor;
1906 		aTargetSize.Height() /= nTargetDivisor;
1907 	}
1908 	else
1909 	{
1910 		aTargetMapMode = MapMode( MAP_INCH );
1911 
1912 		const long		nUnit = pVirDev->LogicToPixel( Size( 1, 1 ), aTargetMapMode ).Width();
1913 		const Fraction	aFrac( 1, nUnit );
1914 
1915 		aTargetMapMode.SetScaleX( aFrac );
1916 		aTargetMapMode.SetScaleY( aFrac );
1917 		aTargetSize = pVirDev->LogicToLogic( rMTF.GetPrefSize(), aSrcMapMode, aTargetMapMode );
1918 	}
1919 
1920 	pVirDev->SetMapMode( aTargetMapMode );
1921 
1922 	pAttrStack=NULL;
1923 
1924 	for (sal_uInt16 i=0; i<MAXOBJECTHANDLES; i++)
1925 		bHandleAllocated[i]=sal_False;
1926 
1927 	nDstPenHandle=0xffff;
1928 	nDstFontHandle=0xffff;
1929 	nDstBrushHandle=0xffff;
1930 
1931 	nNumberOfActions=0;
1932 	nNumberOfBitmaps=0;
1933 	nWrittenActions=0;
1934 	nWrittenBitmaps=0;
1935 	nActBitmapPercent=0;
1936 
1937 	CountActionsAndBitmaps(rMTF);
1938 
1939 	WriteHeader(rMTF,bPlaceable);
1940     if( bEmbedEMF )
1941         WriteEmbeddedEMF( rMTF );
1942 	WMFRecord_SetWindowOrg(Point(0,0));
1943 	WMFRecord_SetWindowExt(rMTF.GetPrefSize());
1944 	WMFRecord_SetBkMode( sal_True );
1945 
1946 	eDstROP2 = eSrcRasterOp = ROP_OVERPAINT;
1947 	WMFRecord_SetROP2(eDstROP2);
1948 
1949 	aDstLineInfo = LineInfo();
1950 	aDstLineColor = aSrcLineColor = Color( COL_BLACK );
1951 	CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
1952 
1953     aDstFillColor = aSrcFillColor = Color( COL_WHITE );
1954 	CreateSelectDeleteBrush( aDstFillColor );
1955 
1956     aDstClipRegion = aSrcClipRegion = Region();
1957 	bDstIsClipping = bSrcIsClipping = sal_False;
1958 
1959     Font aFont;
1960     aFont.SetCharSet( GetExtendedTextEncoding( gsl_getSystemTextEncoding() ) );
1961     aFont.SetColor( Color( COL_WHITE ) );
1962     aFont.SetAlign( ALIGN_BASELINE );
1963 	aDstFont = aSrcFont = aFont;
1964 	CreateSelectDeleteFont(aDstFont);
1965 
1966     eDstTextAlign = eSrcTextAlign = ALIGN_BASELINE;
1967 	eDstHorTextAlign = eSrcHorTextAlign = W_TA_LEFT;
1968 	WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
1969 
1970     aDstTextColor = aSrcTextColor = Color( COL_WHITE );
1971 	WMFRecord_SetTextColor(aDstTextColor);
1972 
1973 	// Write records
1974 	WriteRecords(rMTF);
1975 
1976 	WMFRecord_EndOfFile();
1977 	UpdateHeader();
1978 
1979 	while(pAttrStack)
1980 	{
1981 		pAt=pAttrStack;
1982 		pAttrStack=pAt->pSucc;
1983 		delete pAt;
1984 	}
1985 
1986 	delete pVirDev;
1987     delete pConvert;
1988 
1989 	if ( xStatusIndicator.is() )
1990 		xStatusIndicator->end();
1991 
1992 	return bStatus;
1993 }
1994 
1995 // ------------------------------------------------------------------------
1996 
CalcSaveTargetMapMode(MapMode & rMapMode,const Size & rPrefSize)1997 sal_uInt16 WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode,
1998 										const Size& rPrefSize)
1999 {
2000 	Fraction	aDivFrac(2, 1);
2001 	sal_uInt16		nDivisor = 1;
2002 
2003 	Size aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
2004 
2005 	while( nDivisor <= 64 && (aSize.Width() > 32767 || aSize.Height() > 32767) )
2006 	{
2007 		Fraction aFrac = rMapMode.GetScaleX();
2008 
2009 		aFrac *= aDivFrac;
2010 		rMapMode.SetScaleX(aFrac);
2011 		aFrac = rMapMode.GetScaleY();
2012 		aFrac *= aDivFrac;
2013 		rMapMode.SetScaleY(aFrac);
2014 		nDivisor <<= 1;
2015 		aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
2016 	}
2017 
2018 	return nDivisor;
2019 }
2020 
2021 // ------------------------------------------------------------------------
2022 
WriteEmbeddedEMF(const GDIMetaFile & rMTF)2023 void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF )
2024 {
2025     EMFWriter aEMFWriter;
2026     SvMemoryStream aStream;
2027 
2028     if( aEMFWriter.WriteEMF( rMTF, aStream ) )
2029     {
2030         sal_Size nTotalSize = aStream.Tell();
2031         if( nTotalSize > SAL_MAX_UINT32 )
2032             return;
2033         aStream.Seek( 0 );
2034         sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize );
2035         sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1;
2036         sal_uInt16 nCheckSum = 0, nWord;
2037 
2038         sal_uInt32 nPos = 0;
2039 
2040         while( nPos + 1 < nTotalSize )
2041         {
2042             aStream >> nWord;
2043             nCheckSum ^= nWord;
2044             nPos += 2;
2045         }
2046 
2047         nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 );
2048 
2049         aStream.Seek( 0 );
2050         while( nRemainingSize > 0 )
2051         {
2052             sal_uInt32 nCurSize;
2053             if( nRemainingSize > 0x2000 )
2054             {
2055                 nCurSize = 0x2000;
2056                 nRemainingSize -= 0x2000;
2057             }
2058             else
2059             {
2060                 nCurSize = nRemainingSize;
2061                 nRemainingSize = 0;
2062             }
2063             WriteEMFRecord( aStream,
2064                             nCurSize,
2065                             nRemainingSize,
2066                             nTotalSize,
2067                             nRecCounts,
2068                             nCheckSum );
2069             nCheckSum = 0;
2070         }
2071     }
2072 }
2073 
2074 // ------------------------------------------------------------------------
2075 
WriteEMFRecord(SvMemoryStream & rStream,sal_uInt32 nCurSize,sal_uInt32 nRemainingSize,sal_uInt32 nTotalSize,sal_uInt32 nRecCounts,sal_uInt16 nCheckSum)2076 void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize,
2077                 sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum )
2078 {
2079    // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx
2080    WriteRecordHeader( 0, W_META_ESCAPE );
2081    *pWMF << (sal_uInt16)W_MFCOMMENT			// same as META_ESCAPE_ENHANCED_METAFILE
2082 		  << (sal_uInt16)( nCurSize + 34 )	// we will always have a 34 byte escape header:
2083 		  << (sal_uInt32) 0x43464D57		// WMFC
2084 		  << (sal_uInt32) 0x00000001		// Comment type
2085 		  << (sal_uInt32) 0x00010000        // version
2086           << nCheckSum                      // check sum
2087           << (sal_uInt32) 0                 // flags = 0
2088           << nRecCounts                     // total number of records
2089           << nCurSize                       // size of this record's data
2090           << nRemainingSize                 // remaining size of data in following records, missing in MSDN documentation
2091           << nTotalSize;                    // total size of EMF stream
2092 
2093    pWMF->Write( static_cast< const sal_Char* >( rStream.GetData() ) + rStream.Tell(), nCurSize );
2094    rStream.SeekRel( nCurSize );
2095    UpdateRecordHeader();
2096 }
2097