Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / filter / wmf / wmfwr.cxx
blob83b98ce7f454fcae4252eee695402b46983bac24
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <algorithm>
24 #include "wmfwr.hxx"
25 #include <unotools/fontcvt.hxx>
26 #include "emfwr.hxx"
27 #include <rtl/crc.h>
28 #include <rtl/strbuf.hxx>
29 #include <rtl/tencinfo.h>
30 #include <tools/bigint.hxx>
31 #include <tools/helpers.hxx>
32 #include <tools/tenccvt.hxx>
33 #include <tools/fract.hxx>
34 #include <osl/endian.h>
35 #include <vcl/dibtools.hxx>
36 #include <vcl/metric.hxx>
37 #include <basegfx/polygon/b2dpolygon.hxx>
38 #include <basegfx/polygon/b2dpolypolygon.hxx>
39 #include <boost/scoped_array.hpp>
41 // MS Windows defines
43 #define W_META_SETBKMODE 0x0102
44 #define W_META_SETROP2 0x0104
45 #define W_META_SETSTRETCHBLTMODE 0x0107
46 #define W_META_SETTEXTCOLOR 0x0209
47 #define W_META_SETWINDOWORG 0x020B
48 #define W_META_SETWINDOWEXT 0x020C
49 #define W_META_LINETO 0x0213
50 #define W_META_MOVETO 0x0214
51 #define W_META_INTERSECTCLIPRECT 0x0416
52 #define W_META_ARC 0x0817
53 #define W_META_ELLIPSE 0x0418
54 #define W_META_PIE 0x081A
55 #define W_META_RECTANGLE 0x041B
56 #define W_META_ROUNDRECT 0x061C
57 #define W_META_SAVEDC 0x001E
58 #define W_META_SETPIXEL 0x041F
59 #define W_META_TEXTOUT 0x0521
60 #define W_META_POLYGON 0x0324
61 #define W_META_POLYLINE 0x0325
62 #define W_META_ESCAPE 0x0626
63 #define W_META_RESTOREDC 0x0127
64 #define W_META_SELECTOBJECT 0x012D
65 #define W_META_SETTEXTALIGN 0x012E
66 #define W_META_CHORD 0x0830
67 #define W_META_EXTTEXTOUT 0x0a32
68 #define W_META_POLYPOLYGON 0x0538
69 #define W_META_STRETCHDIB 0x0f43
70 #define W_META_DELETEOBJECT 0x01f0
71 #define W_META_CREATEPENINDIRECT 0x02FA
72 #define W_META_CREATEFONTINDIRECT 0x02FB
73 #define W_META_CREATEBRUSHINDIRECT 0x02FC
75 #define W_TRANSPARENT 1
76 #define W_OPAQUE 2
78 #define W_R2_NOT 6
79 #define W_R2_XORPEN 7
80 #define W_R2_COPYPEN 13
82 #define W_TA_NOUPDATECP 0x0000
83 #define W_TA_LEFT 0x0000
84 #define W_TA_RIGHT 0x0002
85 #define W_TA_TOP 0x0000
86 #define W_TA_BOTTOM 0x0008
87 #define W_TA_BASELINE 0x0018
88 #define W_TA_RTLREADING 0x0100
90 #define W_SRCCOPY 0x00CC0020L
91 #define W_SRCPAINT 0x00EE0086L
92 #define W_SRCAND 0x008800C6L
93 #define W_SRCINVERT 0x00660046L
94 #define W_DSTINVERT 0x00550009L
96 #define W_PS_SOLID 0
97 #define W_PS_DASH 1
98 #define W_PS_DOT 2
99 #define W_PS_DASHDOT 3
100 #define W_PS_DASHDOTDOT 4
101 #define W_PS_NULL 5
103 #define W_LF_FACESIZE 32
105 #define W_ANSI_CHARSET 0
107 #define W_DEFAULT_PITCH 0x00
108 #define W_FIXED_PITCH 0x01
109 #define W_VARIABLE_PITCH 0x02
111 #define W_FF_DONTCARE 0x00
112 #define W_FF_ROMAN 0x10
113 #define W_FF_SWISS 0x20
114 #define W_FF_MODERN 0x30
115 #define W_FF_SCRIPT 0x40
116 #define W_FF_DECORATIVE 0x50
118 #define W_FW_DONTCARE 0
119 #define W_FW_THIN 100
120 #define W_FW_LIGHT 300
121 #define W_FW_NORMAL 400
122 #define W_FW_MEDIUM 500
123 #define W_FW_SEMIBOLD 600
124 #define W_FW_BOLD 700
125 #define W_FW_ULTRALIGHT 200
126 #define W_FW_ULTRABOLD 800
127 #define W_FW_BLACK 900
129 #define W_BS_SOLID 0
130 #define W_BS_HOLLOW 1
132 #define W_MFCOMMENT 15
134 #define PRIVATE_ESCAPE_UNICODE 2
136 WMFWriter::WMFWriter()
137 : bStatus(false)
138 , nLastPercent(0)
139 , pWMF(NULL)
140 , pVirDev(NULL)
141 , nMetafileHeaderPos(0)
142 , nMaxRecordSize(0)
143 , nActRecordPos(0)
144 , eSrcRasterOp(ROP_OVERPAINT)
145 , eSrcTextAlign(ALIGN_BASELINE)
146 , bSrcIsClipping(false)
147 , pAttrStack(NULL)
148 , eSrcHorTextAlign(W_TA_LEFT)
149 , eDstROP2(ROP_OVERPAINT)
150 , eDstTextAlign(ALIGN_BASELINE)
151 , eDstHorTextAlign(W_TA_LEFT)
152 , bDstIsClipping(false)
153 , nDstPenHandle(0)
154 , nDstFontHandle(0)
155 , nDstBrushHandle(0)
156 , nNumberOfActions(0)
157 , nNumberOfBitmaps(0)
158 , nWrittenActions(0)
159 , nWrittenBitmaps(0)
160 , nActBitmapPercent(0)
161 , bEmbedEMF(false)
165 void WMFWriter::MayCallback()
167 if ( xStatusIndicator.is() )
169 sal_uLong nPercent;
171 // we simply assume that 16386 actions match to a bitmap
172 // (normally a metafile either contains only actions or some bitmaps and
173 // almost no actions. In which case the ratio is less important)
175 nPercent=((nWrittenBitmaps<<14)+(nActBitmapPercent<<14)/100+nWrittenActions)
176 *100
177 /((nNumberOfBitmaps<<14)+nNumberOfActions);
179 if ( nPercent >= nLastPercent + 3 )
181 nLastPercent = nPercent;
182 if( nPercent <= 100 )
183 xStatusIndicator->setValue( nPercent );
188 void WMFWriter::CountActionsAndBitmaps( const GDIMetaFile & rMTF )
190 size_t nAction, nActionCount;
192 nActionCount = rMTF.GetActionSize();
194 for ( nAction=0; nAction < nActionCount; nAction++ )
196 MetaAction* pMA = rMTF.GetAction( nAction );
198 switch( pMA->GetType() )
200 case MetaActionType::BMP:
201 case MetaActionType::BMPSCALE:
202 case MetaActionType::BMPSCALEPART:
203 case MetaActionType::BMPEX:
204 case MetaActionType::BMPEXSCALE:
205 case MetaActionType::BMPEXSCALEPART:
206 nNumberOfBitmaps++;
207 break;
208 default: break;
210 nNumberOfActions++;
214 void WMFWriter::WritePointXY(const Point & rPoint)
216 Point aPt( OutputDevice::LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
217 pWMF->WriteInt16( aPt.X() ).WriteInt16( aPt.Y() );
220 void WMFWriter::WritePointYX(const Point & rPoint)
222 Point aPt( OutputDevice::LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
223 pWMF->WriteInt16( aPt.Y() ).WriteInt16( aPt.X() );
226 sal_Int32 WMFWriter::ScaleWidth( sal_Int32 nDX )
228 Size aSz( OutputDevice::LogicToLogic(Size(nDX,0),aSrcMapMode,aTargetMapMode) );
229 return aSz.Width();
232 void WMFWriter::WriteSize(const Size & rSize)
234 Size aSz( OutputDevice::LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
235 pWMF->WriteInt16( aSz.Width() ).WriteInt16( aSz.Height() );
238 void WMFWriter::WriteHeightWidth(const Size & rSize)
240 Size aSz( OutputDevice::LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
241 pWMF->WriteInt16( aSz.Height() ).WriteInt16( aSz.Width() );
244 void WMFWriter::WriteRectangle(const Rectangle & rRect)
246 WritePointYX(Point(rRect.Right()+1,rRect.Bottom()+1));
247 WritePointYX(rRect.TopLeft());
250 void WMFWriter::WriteColor(const Color & rColor)
252 pWMF->WriteUChar( rColor.GetRed() ).WriteUChar( rColor.GetGreen() ).WriteUChar( rColor.GetBlue() ).WriteUChar( 0 );
255 void WMFWriter::WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType)
257 nActRecordPos=pWMF->Tell();
258 if (nSizeWords>nMaxRecordSize) nMaxRecordSize=nSizeWords;
259 pWMF->WriteUInt32( nSizeWords ).WriteUInt16( nType );
262 void WMFWriter::UpdateRecordHeader()
264 sal_uLong nPos;
265 sal_uInt32 nSize;
267 nPos=pWMF->Tell(); nSize=nPos-nActRecordPos;
268 if ((nSize & 1)!=0) {
269 pWMF->WriteUChar( 0 );
270 nPos++; nSize++;
272 nSize/=2;
273 if (nSize>nMaxRecordSize) nMaxRecordSize=nSize;
274 pWMF->Seek(nActRecordPos);
275 pWMF->WriteUInt32( nSize );
276 pWMF->Seek(nPos);
279 void WMFWriter::WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
281 WriteRecordHeader(0x0000000b,W_META_ARC);
282 WritePointYX(rEndPt);
283 WritePointYX(rStartPt);
284 WriteRectangle(rRect);
287 void WMFWriter::WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
289 WriteRecordHeader(0x0000000b,W_META_CHORD);
290 WritePointYX(rEndPt);
291 WritePointYX(rStartPt);
292 WriteRectangle(rRect);
295 void WMFWriter::WMFRecord_CreateBrushIndirect(const Color& rColor)
297 WriteRecordHeader(0x00000007,W_META_CREATEBRUSHINDIRECT);
299 if( rColor==Color(COL_TRANSPARENT) )
300 pWMF->WriteUInt16( W_BS_HOLLOW );
301 else
302 pWMF->WriteUInt16( W_BS_SOLID );
304 WriteColor( rColor );
305 pWMF->WriteUInt16( 0 );
308 void WMFWriter::WMFRecord_CreateFontIndirect(const vcl::Font & rFont)
310 sal_uInt16 nWeight,i;
311 sal_uInt8 nPitchFamily;
313 WriteRecordHeader(0x00000000,W_META_CREATEFONTINDIRECT);
314 WriteHeightWidth(Size(rFont.GetSize().Width(),-rFont.GetSize().Height()));
315 pWMF->WriteInt16( rFont.GetOrientation() ).WriteInt16( rFont.GetOrientation() );
317 switch (rFont.GetWeight()) {
318 case WEIGHT_THIN: nWeight=W_FW_THIN; break;
319 case WEIGHT_ULTRALIGHT: nWeight=W_FW_ULTRALIGHT; break;
320 case WEIGHT_LIGHT: nWeight=W_FW_LIGHT; break;
321 case WEIGHT_SEMILIGHT: nWeight=W_FW_LIGHT; break;
322 case WEIGHT_NORMAL: nWeight=W_FW_NORMAL; break;
323 case WEIGHT_MEDIUM: nWeight=W_FW_MEDIUM; break;
324 case WEIGHT_SEMIBOLD: nWeight=W_FW_SEMIBOLD; break;
325 case WEIGHT_BOLD: nWeight=W_FW_BOLD; break;
326 case WEIGHT_ULTRABOLD: nWeight=W_FW_ULTRABOLD; break;
327 case WEIGHT_BLACK: nWeight=W_FW_BLACK; break;
328 default: nWeight=W_FW_DONTCARE;
330 pWMF->WriteUInt16( nWeight );
332 if (rFont.GetItalic()==ITALIC_NONE) pWMF->WriteUChar( 0 ); else pWMF->WriteUChar( 1 );
333 if (rFont.GetUnderline()==UNDERLINE_NONE) pWMF->WriteUChar( 0 ); else pWMF->WriteUChar( 1 );
334 if (rFont.GetStrikeout()==STRIKEOUT_NONE) pWMF->WriteUChar( 0 ); else pWMF->WriteUChar( 1 );
336 rtl_TextEncoding eFontNameEncoding = rFont.GetCharSet();
337 sal_uInt8 nCharSet = rtl_getBestWindowsCharsetFromTextEncoding( eFontNameEncoding );
338 if ( eFontNameEncoding == RTL_TEXTENCODING_SYMBOL )
339 eFontNameEncoding = RTL_TEXTENCODING_MS_1252;
340 if ( nCharSet == 1 )
341 nCharSet = W_ANSI_CHARSET;
342 pWMF->WriteUChar( nCharSet );
344 pWMF->WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
346 switch (rFont.GetPitch()) {
347 case PITCH_FIXED: nPitchFamily=W_FIXED_PITCH; break;
348 case PITCH_VARIABLE: nPitchFamily=W_VARIABLE_PITCH; break;
349 default: nPitchFamily=W_DEFAULT_PITCH;
351 switch (rFont.GetFamily()) {
352 case FAMILY_DECORATIVE: nPitchFamily|=W_FF_DECORATIVE; break;
353 case FAMILY_MODERN: nPitchFamily|=W_FF_MODERN; break;
354 case FAMILY_ROMAN: nPitchFamily|=W_FF_ROMAN; break;
355 case FAMILY_SCRIPT: nPitchFamily|=W_FF_SCRIPT; break;
356 case FAMILY_SWISS: nPitchFamily|=W_FF_SWISS; break;
357 default: nPitchFamily|=W_FF_DONTCARE;
359 pWMF->WriteUChar( nPitchFamily );
361 OString aFontName(OUStringToOString(rFont.GetName(), eFontNameEncoding));
362 for ( i = 0; i < W_LF_FACESIZE; i++ )
364 sal_Char nChar = ( i < aFontName.getLength() ) ? aFontName[i] : 0;
365 pWMF->WriteChar( nChar );
367 UpdateRecordHeader();
370 void WMFWriter::WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo )
372 WriteRecordHeader(0x00000008,W_META_CREATEPENINDIRECT);
373 sal_uInt16 nStyle = rColor == Color( COL_TRANSPARENT ) ? W_PS_NULL : W_PS_SOLID;
374 switch( rLineInfo.GetStyle() )
376 case LINE_DASH :
378 if ( rLineInfo.GetDotCount() )
380 if ( !rLineInfo.GetDashCount() )
381 nStyle = W_PS_DOT;
382 else
384 if ( rLineInfo.GetDotCount() == 1 )
385 nStyle = W_PS_DASHDOT;
386 else
387 nStyle = W_PS_DASHDOTDOT;
390 else
391 nStyle = W_PS_DASH;
393 break;
394 case LINE_NONE :
395 nStyle = W_PS_NULL;
396 break;
397 default:
398 break;
400 pWMF->WriteUInt16( nStyle );
402 WriteSize( Size( rLineInfo.GetWidth(), 0 ) );
403 WriteColor( rColor );
406 void WMFWriter::WMFRecord_DeleteObject(sal_uInt16 nObjectHandle)
408 WriteRecordHeader(0x00000004,W_META_DELETEOBJECT);
409 pWMF->WriteUInt16( nObjectHandle );
412 void WMFWriter::WMFRecord_Ellipse(const Rectangle & rRect)
414 WriteRecordHeader(0x00000007,W_META_ELLIPSE);
415 WriteRectangle(rRect);
418 void WMFWriter::WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData )
420 #ifdef OSL_BIGENDIAN
421 sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc );
422 sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
423 #else
424 sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
425 #endif
426 if ( nLen )
427 nCheckSum = rtl_crc32( nCheckSum, pData, nLen );
429 WriteRecordHeader( 3 + 9 + ( ( nLen + 1 ) >> 1 ), W_META_ESCAPE );
430 pWMF->WriteUInt16( W_MFCOMMENT )
431 .WriteUInt16( nLen + 14 ) // we will always have a fourteen byte escape header:
432 .WriteUInt16( 0x4f4f ) // OO
433 .WriteUInt32( 0xa2c2a ) // evil magic number
434 .WriteUInt32( nCheckSum ) // crc32 checksum about nEsc & pData
435 .WriteUInt32( nEsc ); // escape number
436 pWMF->Write( pData, nLen );
437 if ( nLen & 1 )
438 pWMF->WriteUChar( 0 ); // pad byte
441 /* if return value is true, then a complete unicode string and also a polygon replacement has been written,
442 so there is no more action necessary
444 bool WMFWriter::WMFRecord_Escape_Unicode( const Point& rPoint, const OUString& rUniStr, const long* pDXAry )
446 bool bEscapeUsed = false;
448 sal_uInt32 i, nStringLen = rUniStr.getLength();
449 if ( nStringLen )
451 // first we will check if a comment is necessary
452 if ( aSrcFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) // symbol is always byte character, so there is no unicode loss
454 const sal_Unicode* pBuf = rUniStr.getStr();
455 const rtl_TextEncoding aTextEncodingOrg = aSrcFont.GetCharSet();
456 OString aByteStr(OUStringToOString(rUniStr, aTextEncodingOrg));
457 OUString aUniStr2(OStringToOUString(aByteStr, aTextEncodingOrg));
458 const sal_Unicode* pConversion = aUniStr2.getStr(); // this is the unicode array after bytestring <-> unistring conversion
459 for ( i = 0; i < nStringLen; i++ )
461 if ( *pBuf++ != *pConversion++ )
462 break;
465 if ( i != nStringLen ) // after conversion the characters are not original,
466 { // try again, with determining a better charset from unicode char
467 pBuf = rUniStr.getStr();
468 const sal_Unicode* pCheckChar = pBuf;
469 rtl_TextEncoding aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the first character
470 for ( i = 1; i < nStringLen; i++)
472 if (aTextEncoding != aTextEncodingOrg) // found something
473 break;
474 pCheckChar++;
475 aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the next character
478 aByteStr = OUStringToOString(rUniStr, aTextEncoding);
479 aUniStr2 = OStringToOUString(aByteStr, aTextEncoding);
480 pConversion = aUniStr2.getStr(); // this is the unicode array after bytestring <-> unistring conversion
481 for ( i = 0; i < nStringLen; i++ )
483 if ( *pBuf++ != *pConversion++ )
484 break;
486 if (i == nStringLen)
488 aSrcFont.SetCharSet (aTextEncoding);
489 SetAllAttr();
493 if ( ( i != nStringLen ) || IsStarSymbol( aSrcFont.GetName() ) ) // after conversion the characters are not original, so we
494 { // will store the unicode string and a polypoly replacement
495 Color aOldFillColor( aSrcFillColor );
496 Color aOldLineColor( aSrcLineColor );
497 aSrcLineInfo = LineInfo();
498 aSrcFillColor = aSrcTextColor;
499 aSrcLineColor = Color( COL_TRANSPARENT );
500 SetLineAndFillAttr();
501 pVirDev->SetFont( aSrcFont );
502 std::vector<tools::PolyPolygon> aPolyPolyVec;
503 if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniStr ) )
505 sal_uInt32 nDXCount = pDXAry ? nStringLen : 0;
506 sal_uInt32 nSkipActions = aPolyPolyVec.size();
507 sal_Int32 nStrmLen = 8 +
508 + sizeof( nStringLen ) + ( nStringLen * 2 )
509 + sizeof( nDXCount ) + ( nDXCount * 4 )
510 + sizeof( nSkipActions );
512 SvMemoryStream aMemoryStream( nStrmLen );
513 Point aPt( OutputDevice::LogicToLogic( rPoint, aSrcMapMode, aTargetMapMode ) );
514 aMemoryStream.WriteInt32( aPt.X() )
515 .WriteInt32( aPt.Y() )
516 .WriteUInt32( nStringLen );
517 for ( i = 0; i < nStringLen; i++ )
518 aMemoryStream.WriteUInt16( rUniStr[ i ] );
519 aMemoryStream.WriteUInt32( nDXCount );
520 for ( i = 0; i < nDXCount; i++ )
521 aMemoryStream.WriteInt32( pDXAry[ i ] );
522 aMemoryStream.WriteUInt32( nSkipActions );
523 WMFRecord_Escape( PRIVATE_ESCAPE_UNICODE, nStrmLen, static_cast<const sal_Int8*>(aMemoryStream.GetData()) );
525 std::vector<tools::PolyPolygon>::iterator aIter( aPolyPolyVec.begin() );
526 while ( aIter != aPolyPolyVec.end() )
528 tools::PolyPolygon aPolyPoly( *aIter++ );
529 aPolyPoly.Move( rPoint.X(), rPoint.Y() );
530 WMFRecord_PolyPolygon( aPolyPoly );
532 aSrcFillColor = aOldFillColor;
533 aSrcLineColor = aOldLineColor;
534 bEscapeUsed = true;
539 return bEscapeUsed;
542 void WMFWriter::WMFRecord_ExtTextOut( const Point& rPoint,
543 const OUString& rString,
544 const long* pDXAry )
546 sal_Int32 nOriginalTextLen = rString.getLength();
548 if ( (nOriginalTextLen <= 1) || (pDXAry == NULL) )
550 WMFRecord_TextOut(rPoint, rString);
551 return;
553 rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
554 OString aByteString(OUStringToOString(rString, eChrSet));
555 TrueExtTextOut(rPoint, rString, aByteString, pDXAry);
558 void WMFWriter::TrueExtTextOut( const Point& rPoint, const OUString& rString,
559 const OString& rByteString, const long* pDXAry )
561 WriteRecordHeader( 0, W_META_EXTTEXTOUT );
562 WritePointYX( rPoint );
563 sal_uInt16 nNewTextLen = static_cast<sal_uInt16>(rByteString.getLength());
564 pWMF->WriteUInt16( nNewTextLen ).WriteUInt16( 0 );
565 write_uInt8s_FromOString(*pWMF, rByteString, nNewTextLen);
566 if ( nNewTextLen & 1 )
567 pWMF->WriteUChar( 0 );
569 sal_Int32 nOriginalTextLen = rString.getLength();
570 boost::scoped_array<sal_Int16> pConvertedDXAry(new sal_Int16[ nOriginalTextLen ]);
571 sal_Int32 j = 0;
572 pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ 0 ] );
573 for (sal_uInt16 i = 1; i < ( nOriginalTextLen - 1 ); ++i)
574 pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ i ] - pDXAry[ i - 1 ] );
575 pConvertedDXAry[ j ] = (sal_Int16)ScaleWidth( pDXAry[ nOriginalTextLen - 2 ] / ( nOriginalTextLen - 1 ) );
577 for (sal_uInt16 i = 0; i < nOriginalTextLen; ++i)
579 sal_Int16 nDx = pConvertedDXAry[ i ];
580 pWMF->WriteInt16( nDx );
581 if ( nOriginalTextLen < nNewTextLen )
583 sal_Unicode nUniChar = rString[i];
584 OString aTemp(&nUniChar, 1, aSrcFont.GetCharSet());
585 j = aTemp.getLength();
586 while ( --j > 0 )
587 pWMF->WriteUInt16( 0 );
590 pConvertedDXAry.reset();
591 UpdateRecordHeader();
594 void WMFWriter::WMFRecord_LineTo(const Point & rPoint)
596 WriteRecordHeader(0x00000005,W_META_LINETO);
597 WritePointYX(rPoint);
600 void WMFWriter::WMFRecord_MoveTo(const Point & rPoint)
602 WriteRecordHeader(0x00000005,W_META_MOVETO);
603 WritePointYX(rPoint);
606 void WMFWriter::WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
608 WriteRecordHeader(0x0000000b,W_META_PIE);
609 WritePointYX(rEndPt);
610 WritePointYX(rStartPt);
611 WriteRectangle(rRect);
614 void WMFWriter::WMFRecord_Polygon(const Polygon & rPoly)
616 sal_uInt16 nSize,i;
618 Polygon aSimplePoly;
619 if ( rPoly.HasFlags() )
620 rPoly.AdaptiveSubdivide( aSimplePoly );
621 else
622 aSimplePoly = rPoly;
623 nSize = aSimplePoly.GetSize();
624 WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYGON);
625 pWMF->WriteUInt16( nSize );
626 for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i));
629 void WMFWriter::WMFRecord_PolyLine(const Polygon & rPoly)
631 sal_uInt16 nSize,i;
632 Polygon aSimplePoly;
633 if ( rPoly.HasFlags() )
634 rPoly.AdaptiveSubdivide( aSimplePoly );
635 else
636 aSimplePoly = rPoly;
637 nSize=aSimplePoly.GetSize();
638 WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYLINE);
639 pWMF->WriteUInt16( nSize );
640 for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i));
643 void WMFWriter::WMFRecord_PolyPolygon(const tools::PolyPolygon & rPolyPoly)
645 const Polygon * pPoly;
646 sal_uInt16 nCount,nSize,i,j;
648 nCount=rPolyPoly.Count();
649 tools::PolyPolygon aSimplePolyPoly( rPolyPoly );
650 for ( i = 0; i < nCount; i++ )
652 if ( aSimplePolyPoly[ i ].HasFlags() )
654 Polygon aSimplePoly;
655 aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly );
656 aSimplePolyPoly[ i ] = aSimplePoly;
659 WriteRecordHeader(0,W_META_POLYPOLYGON);
660 pWMF->WriteUInt16( nCount );
661 for (i=0; i<nCount; i++) pWMF->WriteUInt16( (aSimplePolyPoly.GetObject(i).GetSize()) );
662 for (i=0; i<nCount; i++) {
663 pPoly=&(aSimplePolyPoly.GetObject(i));
664 nSize=pPoly->GetSize();
665 for (j=0; j<nSize; j++) WritePointXY(pPoly->GetPoint(j));
667 UpdateRecordHeader();
670 void WMFWriter::WMFRecord_Rectangle(const Rectangle & rRect)
672 WriteRecordHeader( 0x00000007,W_META_RECTANGLE );
673 WriteRectangle( rRect );
676 void WMFWriter::WMFRecord_RestoreDC()
678 WriteRecordHeader(0x00000004,W_META_RESTOREDC);
679 pWMF->WriteInt16( -1 );
682 void WMFWriter::WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound)
684 WriteRecordHeader(0x00000009,W_META_ROUNDRECT);
685 WriteHeightWidth(Size(nHorzRound,nVertRound));
686 WriteRectangle(rRect);
689 void WMFWriter::WMFRecord_SaveDC()
691 WriteRecordHeader(0x00000003,W_META_SAVEDC);
694 void WMFWriter::WMFRecord_SelectObject(sal_uInt16 nObjectHandle)
696 WriteRecordHeader(0x00000004,W_META_SELECTOBJECT);
697 pWMF->WriteUInt16( nObjectHandle );
700 void WMFWriter::WMFRecord_SetBkMode(bool bTransparent)
702 WriteRecordHeader(0x00000004,W_META_SETBKMODE);
703 if (bTransparent) pWMF->WriteUInt16( W_TRANSPARENT );
704 else pWMF->WriteUInt16( W_OPAQUE );
707 void WMFWriter::WMFRecord_SetStretchBltMode()
709 WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE );
710 pWMF->WriteUInt16( 3 ); // STRETCH_DELETESCANS
713 void WMFWriter::WMFRecord_SetPixel(const Point & rPoint, const Color & rColor)
715 WriteRecordHeader(0x00000007,W_META_SETPIXEL);
716 WriteColor(rColor);
717 WritePointYX(rPoint);
720 void WMFWriter::WMFRecord_SetROP2(RasterOp eROP)
722 sal_uInt16 nROP2;
724 switch (eROP) {
725 case ROP_INVERT: nROP2=W_R2_NOT; break;
726 case ROP_XOR: nROP2=W_R2_XORPEN; break;
727 default: nROP2=W_R2_COPYPEN;
729 WriteRecordHeader(0x00000004,W_META_SETROP2);
730 pWMF->WriteUInt16( nROP2 );
733 void WMFWriter::WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_uInt32 eHorTextAlign)
735 sal_uInt16 nAlign;
737 switch (eFontAlign) {
738 case ALIGN_TOP: nAlign=W_TA_TOP; break;
739 case ALIGN_BOTTOM: nAlign=W_TA_BOTTOM; break;
740 default: nAlign=W_TA_BASELINE;
742 nAlign|=eHorTextAlign;
743 nAlign|=W_TA_NOUPDATECP;
745 WriteRecordHeader(0x00000004,W_META_SETTEXTALIGN);
746 pWMF->WriteUInt16( nAlign );
749 void WMFWriter::WMFRecord_SetTextColor(const Color & rColor)
751 WriteRecordHeader(0x00000005,W_META_SETTEXTCOLOR);
752 WriteColor(rColor);
755 void WMFWriter::WMFRecord_SetWindowExt(const Size & rSize)
757 WriteRecordHeader(0x00000005,W_META_SETWINDOWEXT);
758 WriteHeightWidth(rSize);
761 void WMFWriter::WMFRecord_SetWindowOrg(const Point & rPoint)
763 WriteRecordHeader(0x00000005,W_META_SETWINDOWORG);
764 WritePointYX(rPoint);
767 void WMFWriter::WMFRecord_StretchDIB( const Point & rPoint, const Size & rSize,
768 const Bitmap & rBitmap, sal_uInt32 nROP )
770 sal_uLong nPosAnf,nPosEnd;
772 nActBitmapPercent=50;
773 MayCallback();
775 WriteRecordHeader(0x00000000,W_META_STRETCHDIB);
777 // The sequence in the metafile should be:
778 // some parameters (length 22), then the bitmap without FILEHEADER.
779 // As *pWMF << rBitmap generates a FILEHEADER of size 14,
780 // we first write the bitmap at the right position
781 // and overwrite later the FILEHEADER with the parameters.
782 nPosAnf=pWMF->Tell(); // remember position, where parameters should be stored
783 pWMF->WriteInt32( 0 ).WriteInt32( 0 ); // replenish 8 bytes (these 8 bytes +
784 // 14 bytes superfluous FILEHEADER
785 // = 22 bytes parameter)
787 // write bitmap
788 WriteDIB(rBitmap, *pWMF, false, true);
790 // write the parameters:
791 nPosEnd=pWMF->Tell();
792 pWMF->Seek(nPosAnf);
794 // determine raster-op, if nothing was passed
795 if( !nROP )
797 switch( eSrcRasterOp )
799 case ROP_INVERT: nROP = W_DSTINVERT; break;
800 case ROP_XOR: nROP = W_SRCINVERT; break;
801 default: nROP = W_SRCCOPY;
805 pWMF->WriteUInt32( nROP ). WriteInt16( 0 ). WriteInt16( rBitmap.GetSizePixel().Height() ). WriteInt16( rBitmap.GetSizePixel().Width() ). WriteInt16( 0 ). WriteInt16( 0 );
807 WriteHeightWidth(rSize);
808 WritePointYX(rPoint);
809 pWMF->Seek(nPosEnd);
811 UpdateRecordHeader();
813 nWrittenBitmaps++;
814 nActBitmapPercent=0;
817 void WMFWriter::WMFRecord_TextOut(const Point & rPoint, const OUString & rStr)
819 rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
820 OString aString(OUStringToOString(rStr, eChrSet));
821 TrueTextOut(rPoint, aString);
824 void WMFWriter::TrueTextOut(const Point & rPoint, const OString& rString)
826 WriteRecordHeader(0,W_META_TEXTOUT);
828 write_uInt16_lenPrefixed_uInt8s_FromOString(*pWMF, rString);
829 sal_Int32 nLen = rString.getLength();
830 if ((nLen&1)!=0) pWMF->WriteUChar( 0 );
831 WritePointYX(rPoint);
832 UpdateRecordHeader();
835 void WMFWriter::WMFRecord_EndOfFile()
837 WriteRecordHeader(0x00000003,0x0000);
840 void WMFWriter::WMFRecord_IntersectClipRect( const Rectangle& rRect )
842 WriteRecordHeader( 0x00000007, W_META_INTERSECTCLIPRECT );
843 WriteRectangle(rRect);
846 sal_uInt16 WMFWriter::AllocHandle()
848 sal_uInt16 i;
850 for (i=0; i<MAXOBJECTHANDLES; i++) {
851 if (!bHandleAllocated[i]) {
852 bHandleAllocated[i]=true;
853 return i;
856 bStatus=false;
857 return 0xffff;
860 void WMFWriter::FreeHandle(sal_uInt16 nObjectHandle)
862 if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=false;
865 void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo )
867 sal_uInt16 nOldHandle;
869 nOldHandle=nDstPenHandle;
870 nDstPenHandle=AllocHandle();
871 WMFRecord_CreatePenIndirect( rColor, rLineInfo );
872 WMFRecord_SelectObject(nDstPenHandle);
873 if (nOldHandle<MAXOBJECTHANDLES) {
874 WMFRecord_DeleteObject(nOldHandle);
875 FreeHandle(nOldHandle);
879 void WMFWriter::CreateSelectDeleteFont(const vcl::Font & rFont)
881 sal_uInt16 nOldHandle;
883 nOldHandle=nDstFontHandle;
884 nDstFontHandle=AllocHandle();
885 WMFRecord_CreateFontIndirect(rFont);
886 WMFRecord_SelectObject(nDstFontHandle);
887 if (nOldHandle<MAXOBJECTHANDLES) {
888 WMFRecord_DeleteObject(nOldHandle);
889 FreeHandle(nOldHandle);
893 void WMFWriter::CreateSelectDeleteBrush(const Color& rColor)
895 sal_uInt16 nOldHandle;
897 nOldHandle=nDstBrushHandle;
898 nDstBrushHandle=AllocHandle();
899 WMFRecord_CreateBrushIndirect(rColor);
900 WMFRecord_SelectObject(nDstBrushHandle);
901 if (nOldHandle<MAXOBJECTHANDLES) {
902 WMFRecord_DeleteObject(nOldHandle);
903 FreeHandle(nOldHandle);
907 void WMFWriter::SetLineAndFillAttr()
909 if ( eDstROP2 != eSrcRasterOp )
911 eDstROP2=eSrcRasterOp;
912 WMFRecord_SetROP2(eDstROP2);
914 if ( ( aDstLineColor != aSrcLineColor ) || ( aDstLineInfo != aSrcLineInfo ) )
916 aDstLineColor = aSrcLineColor;
917 aDstLineInfo = aSrcLineInfo;
918 CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
920 if ( aDstFillColor != aSrcFillColor )
922 aDstFillColor = aSrcFillColor;
923 CreateSelectDeleteBrush( aDstFillColor );
925 if ( bDstIsClipping != bSrcIsClipping ||
926 (bSrcIsClipping && aDstClipRegion!=aSrcClipRegion)) {
927 bDstIsClipping=bSrcIsClipping;
928 aDstClipRegion=aSrcClipRegion;
932 void WMFWriter::SetAllAttr()
934 SetLineAndFillAttr();
935 if ( aDstTextColor != aSrcTextColor )
937 aDstTextColor = aSrcTextColor;
938 WMFRecord_SetTextColor(aDstTextColor);
940 if ( eDstTextAlign != eSrcTextAlign || eDstHorTextAlign != eSrcHorTextAlign )
942 eDstTextAlign = eSrcTextAlign;
943 eDstHorTextAlign = eSrcHorTextAlign;
944 WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
946 if ( aDstFont != aSrcFont )
948 pVirDev->SetFont(aSrcFont);
949 if ( aDstFont.GetName() != aSrcFont.GetName() )
951 FontCharMapPtr pFontCharMap;
952 if ( pVirDev->GetFontCharMap( pFontCharMap ) )
954 if ( ( pFontCharMap->GetFirstChar() & 0xff00 ) == 0xf000 )
955 aSrcFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
956 else if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
957 aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
960 pFontCharMap = 0;
963 aDstFont = aSrcFont;
964 CreateSelectDeleteFont(aDstFont);
968 void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
970 if(rLinePolygon.count())
972 basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
973 basegfx::B2DPolyPolygon aFillPolyPolygon;
975 rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
977 if(aLinePolyPolygon.count())
979 aSrcLineInfo = rInfo;
980 SetLineAndFillAttr();
982 for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
984 const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
985 WMFRecord_PolyLine(Polygon(aCandidate));
989 if(aFillPolyPolygon.count())
991 const Color aOldLineColor(aSrcLineColor);
992 const Color aOldFillColor(aSrcFillColor);
994 aSrcLineColor = Color( COL_TRANSPARENT );
995 aSrcFillColor = aOldLineColor;
996 SetLineAndFillAttr();
998 for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
1000 const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
1001 WMFRecord_Polygon(Polygon(aPolygon));
1004 aSrcLineColor = aOldLineColor;
1005 aSrcFillColor = aOldFillColor;
1006 SetLineAndFillAttr();
1011 void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
1013 if( bStatus )
1015 size_t nACount = rMTF.GetActionSize();
1017 WMFRecord_SetStretchBltMode();
1019 for( size_t nA = 0; nA < nACount; nA++ )
1021 MetaAction* pMA = rMTF.GetAction( nA );
1023 switch( pMA->GetType() )
1025 case MetaActionType::PIXEL:
1027 const MetaPixelAction* pA = static_cast<const MetaPixelAction *>(pMA);
1028 aSrcLineInfo = LineInfo();
1029 SetLineAndFillAttr();
1030 WMFRecord_SetPixel( pA->GetPoint(), pA->GetColor() );
1032 break;
1034 case MetaActionType::POINT:
1036 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pMA);
1037 const Point& rPt = pA->GetPoint();
1038 aSrcLineInfo = LineInfo();
1039 SetLineAndFillAttr();
1040 WMFRecord_MoveTo( rPt);
1041 WMFRecord_LineTo( rPt );
1043 break;
1045 case MetaActionType::LINE:
1047 const MetaLineAction* pA = static_cast<const MetaLineAction *>(pMA);
1048 if(pA->GetLineInfo().IsDefault())
1050 aSrcLineInfo = pA->GetLineInfo();
1051 SetLineAndFillAttr();
1052 WMFRecord_MoveTo( pA->GetStartPoint() );
1053 WMFRecord_LineTo( pA->GetEndPoint() );
1055 else
1057 // LineInfo used; handle Dash/Dot and fat lines
1058 basegfx::B2DPolygon aPolygon;
1059 aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1060 aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1061 HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
1064 break;
1066 case MetaActionType::RECT:
1068 const MetaRectAction* pA = static_cast<const MetaRectAction*>(pMA);
1069 aSrcLineInfo = LineInfo();
1070 SetLineAndFillAttr();
1071 WMFRecord_Rectangle( pA->GetRect() );
1073 break;
1075 case MetaActionType::ROUNDRECT:
1077 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pMA);
1078 aSrcLineInfo = LineInfo();
1079 SetLineAndFillAttr();
1080 WMFRecord_RoundRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
1082 break;
1084 case MetaActionType::ELLIPSE:
1086 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pMA);
1087 aSrcLineInfo = LineInfo();
1088 SetLineAndFillAttr();
1089 WMFRecord_Ellipse( pA->GetRect() );
1091 break;
1093 case MetaActionType::ARC:
1095 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pMA);
1096 aSrcLineInfo = LineInfo();
1097 SetLineAndFillAttr();
1098 WMFRecord_Arc( pA->GetRect(),pA->GetStartPoint(),pA->GetEndPoint() );
1100 break;
1102 case MetaActionType::PIE:
1104 const MetaPieAction* pA = static_cast<const MetaPieAction*>(pMA);
1105 aSrcLineInfo = LineInfo();
1106 SetLineAndFillAttr();
1107 WMFRecord_Pie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1109 break;
1111 case MetaActionType::CHORD:
1113 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pMA);
1114 aSrcLineInfo = LineInfo();
1115 SetLineAndFillAttr();
1116 WMFRecord_Chord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1118 break;
1120 case MetaActionType::POLYLINE:
1122 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pMA);
1123 const Polygon& rPoly = pA->GetPolygon();
1125 if( rPoly.GetSize() )
1127 if(pA->GetLineInfo().IsDefault())
1129 aSrcLineInfo = pA->GetLineInfo();
1130 SetLineAndFillAttr();
1131 WMFRecord_PolyLine( rPoly );
1133 else
1135 // LineInfo used; handle Dash/Dot and fat lines
1136 HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1140 break;
1142 case MetaActionType::POLYGON:
1144 const MetaPolygonAction* pA = static_cast<const MetaPolygonAction*>(pMA);
1145 aSrcLineInfo = LineInfo();
1146 SetLineAndFillAttr();
1147 WMFRecord_Polygon( pA->GetPolygon() );
1149 break;
1151 case MetaActionType::POLYPOLYGON:
1153 const MetaPolyPolygonAction* pA = static_cast<const MetaPolyPolygonAction*>(pMA);
1154 aSrcLineInfo = LineInfo();
1155 SetLineAndFillAttr();
1156 WMFRecord_PolyPolygon( pA->GetPolyPolygon() );
1158 break;
1160 case MetaActionType::TEXTRECT:
1162 const MetaTextRectAction * pA = static_cast<const MetaTextRectAction*>(pMA);
1163 OUString aTemp( pA->GetText() );
1164 aSrcLineInfo = LineInfo();
1165 SetAllAttr();
1167 Point aPos( pA->GetRect().TopLeft() );
1168 if ( !WMFRecord_Escape_Unicode( aPos, aTemp, NULL ) )
1169 WMFRecord_TextOut( aPos, aTemp );
1171 break;
1173 case MetaActionType::TEXT:
1175 const MetaTextAction * pA = static_cast<const MetaTextAction*>(pMA);
1176 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1177 aSrcLineInfo = LineInfo();
1178 SetAllAttr();
1179 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, NULL ) )
1180 WMFRecord_TextOut( pA->GetPoint(), aTemp );
1182 break;
1184 case MetaActionType::TEXTARRAY:
1186 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pMA);
1188 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1189 aSrcLineInfo = LineInfo();
1190 SetAllAttr();
1191 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pA->GetDXArray() ) )
1192 WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pA->GetDXArray() );
1194 break;
1196 case MetaActionType::STRETCHTEXT:
1198 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction *>(pMA);
1199 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1201 sal_uInt16 nLen,i;
1202 sal_Int32 nNormSize;
1204 pVirDev->SetFont( aSrcFont );
1205 nLen = aTemp.getLength();
1206 boost::scoped_array<long> pDXAry(nLen ? new long[ nLen ] : NULL);
1207 nNormSize = pVirDev->GetTextArray( aTemp, pDXAry.get() );
1208 if (nLen && nNormSize == 0)
1210 OSL_FAIL("Impossible div by 0 action: MetaStretchTextAction!");
1212 else
1214 for ( i = 0; i < ( nLen - 1 ); i++ )
1215 pDXAry[ i ] = pDXAry[ i ] * (sal_Int32)pA->GetWidth() / nNormSize;
1216 if ( ( nLen <= 1 ) || ( (sal_Int32)pA->GetWidth() == nNormSize ) )
1217 pDXAry.reset();
1218 aSrcLineInfo = LineInfo();
1219 SetAllAttr();
1220 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pDXAry.get() ) )
1221 WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pDXAry.get() );
1224 break;
1226 case MetaActionType::BMP:
1228 const MetaBmpAction* pA = static_cast<const MetaBmpAction *>(pMA);
1229 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetBitmap().GetSizePixel(), pA->GetBitmap() );
1231 break;
1233 case MetaActionType::BMPSCALE:
1235 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pMA);
1236 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pA->GetBitmap() );
1238 break;
1240 case MetaActionType::BMPSCALEPART:
1242 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pMA);
1243 Bitmap aTmp( pA->GetBitmap() );
1245 if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1246 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aTmp );
1248 break;
1250 case MetaActionType::BMPEX:
1252 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction *>(pMA);
1253 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1254 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1256 if( !!aMsk )
1258 aBmp.Replace( aMsk, COL_WHITE );
1259 aMsk.Invert();
1260 WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT );
1261 WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND );
1263 else
1264 WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp );
1266 break;
1268 case MetaActionType::BMPEXSCALE:
1270 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pMA);
1271 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1272 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1274 if( !!aMsk )
1276 aBmp.Replace( aMsk, COL_WHITE );
1277 aMsk.Invert();
1278 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT );
1279 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND );
1281 else
1282 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp );
1284 break;
1286 case MetaActionType::BMPEXSCALEPART:
1288 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pMA);
1289 BitmapEx aBmpEx( pA->GetBitmapEx() );
1290 aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1291 Bitmap aBmp( aBmpEx.GetBitmap() );
1292 Bitmap aMsk( aBmpEx.GetMask() );
1294 if( !!aMsk )
1296 aBmp.Replace( aMsk, COL_WHITE );
1297 aMsk.Invert();
1298 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT );
1299 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND );
1301 else
1302 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp );
1304 break;
1306 case MetaActionType::GRADIENT:
1308 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pMA);
1309 GDIMetaFile aTmpMtf;
1311 pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1312 WriteRecords( aTmpMtf );
1314 break;
1316 case MetaActionType::HATCH:
1318 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pMA);
1319 GDIMetaFile aTmpMtf;
1321 pVirDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1322 WriteRecords( aTmpMtf );
1324 break;
1326 case MetaActionType::WALLPAPER:
1328 const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pMA);
1329 const Color& rColor = pA->GetWallpaper().GetColor();
1330 const Color aOldLineColor( aSrcLineColor );
1331 const Color aOldFillColor( aSrcFillColor );
1333 aSrcLineColor = rColor;
1334 aSrcFillColor = rColor;
1335 aSrcLineInfo = LineInfo();
1336 SetLineAndFillAttr();
1337 WMFRecord_Rectangle( pA->GetRect() );
1338 aSrcLineColor = aOldLineColor;
1339 aSrcFillColor = aOldFillColor;
1341 break;
1343 case MetaActionType::ISECTRECTCLIPREGION:
1345 const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pMA);
1346 WMFRecord_IntersectClipRect( pA->GetRect() );
1348 break;
1350 case MetaActionType::LINECOLOR:
1352 const MetaLineColorAction* pA = static_cast<const MetaLineColorAction*>(pMA);
1354 if( pA->IsSetting() )
1355 aSrcLineColor = pA->GetColor();
1356 else
1357 aSrcLineColor = Color( COL_TRANSPARENT );
1359 break;
1361 case MetaActionType::FILLCOLOR:
1363 const MetaFillColorAction* pA = static_cast<const MetaFillColorAction*>(pMA);
1365 if( pA->IsSetting() )
1366 aSrcFillColor = pA->GetColor();
1367 else
1368 aSrcFillColor = Color( COL_TRANSPARENT );
1370 break;
1372 case MetaActionType::TEXTCOLOR:
1374 const MetaTextColorAction* pA = static_cast<const MetaTextColorAction*>(pMA);
1375 aSrcTextColor = pA->GetColor();
1377 break;
1379 case MetaActionType::TEXTFILLCOLOR:
1381 const MetaTextFillColorAction* pA = static_cast<const MetaTextFillColorAction*>(pMA);
1382 if( pA->IsSetting() )
1383 aSrcFont.SetFillColor( pA->GetColor() );
1384 else
1385 aSrcFont.SetFillColor( Color( COL_TRANSPARENT ) );
1387 break;
1389 case MetaActionType::TEXTALIGN:
1391 const MetaTextAlignAction* pA = static_cast<const MetaTextAlignAction*>(pMA);
1392 eSrcTextAlign = pA->GetTextAlign();
1394 break;
1396 case MetaActionType::MAPMODE:
1398 const MetaMapModeAction* pA = static_cast<const MetaMapModeAction*>(pMA);
1400 if (aSrcMapMode!=pA->GetMapMode())
1402 if( pA->GetMapMode().GetMapUnit() == MAP_RELATIVE )
1404 MapMode aMM = pA->GetMapMode();
1405 Fraction aScaleX = aMM.GetScaleX();
1406 Fraction aScaleY = aMM.GetScaleY();
1408 Point aOrigin = aSrcMapMode.GetOrigin();
1409 BigInt aX( aOrigin.X() );
1410 aX *= BigInt( aScaleX.GetDenominator() );
1411 if( aOrigin.X() >= 0 )
1412 if( aScaleX.GetNumerator() >= 0 )
1413 aX += BigInt( aScaleX.GetNumerator()/2 );
1414 else
1415 aX -= BigInt( (aScaleX.GetNumerator()+1)/2 );
1416 else
1417 if( aScaleX.GetNumerator() >= 0 )
1418 aX -= BigInt( (aScaleX.GetNumerator()-1)/2 );
1419 else
1420 aX += BigInt( aScaleX.GetNumerator()/2 );
1421 aX /= BigInt( aScaleX.GetNumerator() );
1422 aOrigin.X() = (long)aX + aMM.GetOrigin().X();
1423 BigInt aY( aOrigin.Y() );
1424 aY *= BigInt( aScaleY.GetDenominator() );
1425 if( aOrigin.Y() >= 0 )
1426 if( aScaleY.GetNumerator() >= 0 )
1427 aY += BigInt( aScaleY.GetNumerator()/2 );
1428 else
1429 aY -= BigInt( (aScaleY.GetNumerator()+1)/2 );
1430 else
1431 if( aScaleY.GetNumerator() >= 0 )
1432 aY -= BigInt( (aScaleY.GetNumerator()-1)/2 );
1433 else
1434 aY += BigInt( aScaleY.GetNumerator()/2 );
1435 aY /= BigInt( aScaleY.GetNumerator() );
1436 aOrigin.Y() = (long)aY + aMM.GetOrigin().Y();
1437 aSrcMapMode.SetOrigin( aOrigin );
1439 aScaleX *= aSrcMapMode.GetScaleX();
1440 aScaleY *= aSrcMapMode.GetScaleY();
1441 aSrcMapMode.SetScaleX( aScaleX );
1442 aSrcMapMode.SetScaleY( aScaleY );
1444 else
1445 aSrcMapMode=pA->GetMapMode();
1448 break;
1450 case MetaActionType::FONT:
1452 const MetaFontAction* pA = static_cast<const MetaFontAction*>(pMA);
1453 aSrcFont = pA->GetFont();
1455 if ( (aSrcFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW)
1456 || (aSrcFont.GetCharSet() == RTL_TEXTENCODING_UNICODE) )
1458 aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
1460 eSrcTextAlign = aSrcFont.GetAlign();
1461 aSrcTextColor = aSrcFont.GetColor();
1462 aSrcFont.SetAlign( ALIGN_BASELINE );
1463 aSrcFont.SetColor( COL_WHITE );
1465 break;
1467 case MetaActionType::PUSH:
1469 const MetaPushAction* pA = static_cast<const MetaPushAction*>(pMA);
1471 WMFWriterAttrStackMember* pAt = new WMFWriterAttrStackMember;
1472 pAt->nFlags = pA->GetFlags();
1473 pAt->aClipRegion = aSrcClipRegion;
1474 pAt->aLineColor=aSrcLineColor;
1475 pAt->aFillColor=aSrcFillColor;
1476 pAt->eRasterOp=eSrcRasterOp;
1477 pAt->aFont=aSrcFont;
1478 pAt->eTextAlign=eSrcTextAlign;
1479 pAt->aTextColor=aSrcTextColor;
1480 pAt->aMapMode=aSrcMapMode;
1481 pAt->aLineInfo=aDstLineInfo;
1482 pAt->pSucc=pAttrStack;
1483 pAttrStack=pAt;
1485 SetAllAttr(); // update ( now all source attributes are equal to the destination attributes )
1486 WMFRecord_SaveDC();
1489 break;
1491 case MetaActionType::POP:
1493 WMFWriterAttrStackMember * pAt=pAttrStack;
1495 if( pAt )
1497 aDstLineInfo = pAt->aLineInfo;
1498 aDstLineColor = pAt->aLineColor;
1499 if ( pAt->nFlags & PushFlags::LINECOLOR )
1500 aSrcLineColor = pAt->aLineColor;
1501 aDstFillColor = pAt->aFillColor;
1502 if ( pAt->nFlags & PushFlags::FILLCOLOR )
1503 aSrcFillColor = pAt->aFillColor;
1504 eDstROP2 = pAt->eRasterOp;
1505 if ( pAt->nFlags & PushFlags::RASTEROP )
1506 eSrcRasterOp = pAt->eRasterOp;
1507 aDstFont = pAt->aFont;
1508 if ( pAt->nFlags & PushFlags::FONT )
1509 aSrcFont = pAt->aFont;
1510 eDstTextAlign = pAt->eTextAlign;
1511 if ( pAt->nFlags & ( PushFlags::FONT | PushFlags::TEXTALIGN ) )
1512 eSrcTextAlign = pAt->eTextAlign;
1513 aDstTextColor = pAt->aTextColor;
1514 if ( pAt->nFlags & ( PushFlags::FONT | PushFlags::TEXTCOLOR ) )
1515 aSrcTextColor = pAt->aTextColor;
1516 if ( pAt->nFlags & PushFlags::MAPMODE )
1517 aSrcMapMode = pAt->aMapMode;
1518 aDstClipRegion = pAt->aClipRegion;
1519 if ( pAt->nFlags & PushFlags::CLIPREGION )
1520 aSrcClipRegion = pAt->aClipRegion;
1522 WMFRecord_RestoreDC();
1523 pAttrStack = pAt->pSucc;
1524 delete pAt;
1527 break;
1529 case MetaActionType::EPS :
1531 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pMA);
1532 const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
1534 size_t nCount = aGDIMetaFile.GetActionSize();
1535 for ( size_t i = 0; i < nCount; i++ )
1537 const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i );
1538 if ( pMetaAct->GetType() == MetaActionType::BMPSCALE )
1540 const MetaBmpScaleAction* pBmpScaleAction = static_cast<const MetaBmpScaleAction*>(pMetaAct);
1541 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap() );
1542 break;
1546 break;
1548 case MetaActionType::RASTEROP:
1550 const MetaRasterOpAction* pA = static_cast<const MetaRasterOpAction*>(pMA);
1551 eSrcRasterOp=pA->GetRasterOp();
1553 break;
1555 case MetaActionType::Transparent:
1557 aSrcLineInfo = LineInfo();
1558 SetLineAndFillAttr();
1559 WMFRecord_PolyPolygon( static_cast<const MetaTransparentAction*>(pMA)->GetPolyPolygon() );
1561 break;
1563 case MetaActionType::FLOATTRANSPARENT:
1565 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pMA);
1567 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1568 Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1569 const Size aSrcSize( aTmpMtf.GetPrefSize() );
1570 const Point aDestPt( pA->GetPoint() );
1571 const Size aDestSize( pA->GetSize() );
1572 const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1573 const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1574 long nMoveX, nMoveY;
1576 aSrcLineInfo = LineInfo();
1577 SetAllAttr();
1579 if( fScaleX != 1.0 || fScaleY != 1.0 )
1581 aTmpMtf.Scale( fScaleX, fScaleY );
1582 aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1585 nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
1587 if( nMoveX || nMoveY )
1588 aTmpMtf.Move( nMoveX, nMoveY );
1590 WriteRecords( aTmpMtf );
1592 break;
1594 case( MetaActionType::LAYOUTMODE ):
1596 ComplexTextLayoutMode nLayoutMode = static_cast<const MetaLayoutModeAction*>(pMA)->GetLayoutMode();
1597 eSrcHorTextAlign = 0; // TA_LEFT
1598 if ((nLayoutMode & TEXT_LAYOUT_BIDI_RTL) != TEXT_LAYOUT_DEFAULT)
1600 eSrcHorTextAlign = W_TA_RIGHT | W_TA_RTLREADING;
1602 if ((nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT) != TEXT_LAYOUT_DEFAULT)
1603 eSrcHorTextAlign |= W_TA_RIGHT;
1604 else if ((nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT) != TEXT_LAYOUT_DEFAULT)
1605 eSrcHorTextAlign &= ~W_TA_RIGHT;
1606 break;
1609 // Unsupported Actions
1610 case MetaActionType::MASK:
1611 case MetaActionType::MASKSCALE:
1612 case MetaActionType::MASKSCALEPART:
1614 OSL_FAIL( "Unsupported action: MetaMask...Action!" );
1616 break;
1618 case MetaActionType::CLIPREGION:
1619 break;
1621 case MetaActionType::ISECTREGIONCLIPREGION:
1623 OSL_FAIL( "Unsupported action: MetaISectRegionClipRegionAction!" );
1625 break;
1627 case MetaActionType::MOVECLIPREGION:
1629 OSL_FAIL( "Unsupported action: MetaMoveClipRegionAction!" );
1631 break;
1633 default:
1635 OSL_FAIL(OStringBuffer(
1636 "WMFWriter::WriteRecords: unsupported MetaAction #" ).
1637 append(static_cast<sal_Int32>(pMA->GetType())).getStr());
1639 break;
1642 nWrittenActions++;
1643 MayCallback();
1645 if (pWMF->GetError())
1646 bStatus=false;
1648 if(!bStatus)
1649 break;
1654 void WMFWriter::WriteHeader( const GDIMetaFile &, bool bPlaceable )
1656 if( bPlaceable )
1658 sal_uInt16 nCheckSum, nValue;
1659 Size aSize( OutputDevice::LogicToLogic(Size(1,1),MapMode(MAP_INCH), aTargetMapMode) );
1660 sal_uInt16 nUnitsPerInch = (sal_uInt16) ( ( aSize.Width() + aSize.Height() ) >> 1 );
1662 nCheckSum=0;
1663 nValue=0xcdd7; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1664 nValue=0x9ac6; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1665 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1666 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1667 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1668 nValue=(sal_uInt16) aTargetSize.Width(); nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1669 nValue=(sal_uInt16) aTargetSize.Height(); nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1670 nValue=nUnitsPerInch; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1671 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1672 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1673 pWMF->WriteUInt16( nCheckSum );
1676 nMetafileHeaderPos=pWMF->Tell();
1677 pWMF->WriteUInt16( 0x0001 ) // type: file
1678 .WriteUInt16( 0x0009 ) // header length in words
1679 .WriteUInt16( 0x0300 ) // Version as BCD number
1680 .WriteUInt32( 0x00000000 ) // file length (without 1st header), is later corrected by UpdateHeader()
1681 .WriteUInt16( MAXOBJECTHANDLES ) // maxmimum number of simultaneous objects
1682 .WriteUInt32( 0x00000000 ) // maximum record length, is later corrected by UpdateHeader()
1683 .WriteUInt16( 0x0000 ); // reserved
1686 void WMFWriter::UpdateHeader()
1688 sal_uLong nPos;
1689 sal_uInt32 nFileSize;
1691 nPos=pWMF->Tell(); // endposition = total size of file
1692 nFileSize=nPos-nMetafileHeaderPos; // subtract size of 1st header
1693 if ((nFileSize&1)!=0) { // if needed round to words
1694 pWMF->WriteUChar( 0 );
1695 nPos++;
1696 nFileSize++;
1698 nFileSize>>=1; // convert to number of words
1699 pWMF->Seek(nMetafileHeaderPos+6); // to filesize entry in second header
1700 pWMF->WriteUInt32( nFileSize ); // rectify file size
1701 pWMF->SeekRel(2); // to max-recond-length-entry in second header
1702 pWMF->WriteUInt32( nMaxRecordSize ); // and rectify
1703 pWMF->Seek(nPos);
1706 bool WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream,
1707 FilterConfigItem* pFConfigItem, bool bPlaceable )
1709 WMFWriterAttrStackMember * pAt;
1711 bEmbedEMF = true;
1712 bStatus=true;
1713 pVirDev = VclPtr<VirtualDevice>::Create();
1715 if (pFConfigItem)
1717 xStatusIndicator = pFConfigItem->GetStatusIndicator();
1718 if ( xStatusIndicator.is() )
1720 OUString aMsg;
1721 xStatusIndicator->start( aMsg, 100 );
1724 nLastPercent=0;
1726 pWMF=&rTargetStream;
1727 pWMF->SetEndian(SvStreamEndian::LITTLE);
1729 nMaxRecordSize=0;
1731 aSrcMapMode=rMTF.GetPrefMapMode();
1733 if( bPlaceable )
1735 aTargetMapMode = aSrcMapMode;
1736 aTargetSize = rMTF.GetPrefSize();
1737 sal_uInt16 nTargetDivisor = CalcSaveTargetMapMode(aTargetMapMode, aTargetSize);
1738 aTargetSize.Width() /= nTargetDivisor;
1739 aTargetSize.Height() /= nTargetDivisor;
1741 else
1743 aTargetMapMode = MapMode( MAP_INCH );
1745 const long nUnit = pVirDev->LogicToPixel( Size( 1, 1 ), aTargetMapMode ).Width();
1746 const Fraction aFrac( 1, nUnit );
1748 aTargetMapMode.SetScaleX( aFrac );
1749 aTargetMapMode.SetScaleY( aFrac );
1750 aTargetSize = OutputDevice::LogicToLogic( rMTF.GetPrefSize(), aSrcMapMode, aTargetMapMode );
1753 pVirDev->SetMapMode( aTargetMapMode );
1755 pAttrStack=NULL;
1757 for (sal_uInt16 i=0; i<MAXOBJECTHANDLES; i++)
1758 bHandleAllocated[i]=false;
1760 nDstPenHandle=0xffff;
1761 nDstFontHandle=0xffff;
1762 nDstBrushHandle=0xffff;
1764 nNumberOfActions=0;
1765 nNumberOfBitmaps=0;
1766 nWrittenActions=0;
1767 nWrittenBitmaps=0;
1768 nActBitmapPercent=0;
1770 CountActionsAndBitmaps(rMTF);
1772 WriteHeader(rMTF,bPlaceable);
1773 if( bEmbedEMF )
1774 WriteEmbeddedEMF( rMTF );
1775 WMFRecord_SetWindowOrg(Point(0,0));
1776 WMFRecord_SetWindowExt(rMTF.GetPrefSize());
1777 WMFRecord_SetBkMode( true );
1779 eDstROP2 = eSrcRasterOp = ROP_OVERPAINT;
1780 WMFRecord_SetROP2(eDstROP2);
1782 aDstLineInfo = LineInfo();
1783 aDstLineColor = aSrcLineColor = Color( COL_BLACK );
1784 CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
1786 aDstFillColor = aSrcFillColor = Color( COL_WHITE );
1787 CreateSelectDeleteBrush( aDstFillColor );
1789 aDstClipRegion = aSrcClipRegion = vcl::Region();
1790 bDstIsClipping = bSrcIsClipping = false;
1792 vcl::Font aFont;
1793 aFont.SetCharSet( GetExtendedTextEncoding( RTL_TEXTENCODING_MS_1252 ) );
1794 aFont.SetColor( Color( COL_WHITE ) );
1795 aFont.SetAlign( ALIGN_BASELINE );
1796 aDstFont = aSrcFont = aFont;
1797 CreateSelectDeleteFont(aDstFont);
1799 eDstTextAlign = eSrcTextAlign = ALIGN_BASELINE;
1800 eDstHorTextAlign = eSrcHorTextAlign = W_TA_LEFT;
1801 WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
1803 aDstTextColor = aSrcTextColor = Color( COL_WHITE );
1804 WMFRecord_SetTextColor(aDstTextColor);
1806 // Write records
1807 WriteRecords(rMTF);
1809 WMFRecord_EndOfFile();
1810 UpdateHeader();
1812 while(pAttrStack)
1814 pAt=pAttrStack;
1815 pAttrStack=pAt->pSucc;
1816 delete pAt;
1819 pVirDev.disposeAndClear();
1821 if ( xStatusIndicator.is() )
1822 xStatusIndicator->end();
1824 return bStatus;
1827 sal_uInt16 WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode,
1828 const Size& rPrefSize)
1830 Fraction aDivFrac(2, 1);
1831 sal_uInt16 nDivisor = 1;
1833 Size aSize = OutputDevice::LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
1835 while( nDivisor <= 64 && (aSize.Width() > 32767 || aSize.Height() > 32767) )
1837 Fraction aFrac = rMapMode.GetScaleX();
1839 aFrac *= aDivFrac;
1840 rMapMode.SetScaleX(aFrac);
1841 aFrac = rMapMode.GetScaleY();
1842 aFrac *= aDivFrac;
1843 rMapMode.SetScaleY(aFrac);
1844 nDivisor <<= 1;
1845 aSize = OutputDevice::LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
1848 return nDivisor;
1851 void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF )
1853 SvMemoryStream aStream;
1854 EMFWriter aEMFWriter(aStream);
1856 if( aEMFWriter.WriteEMF( rMTF ) )
1858 sal_Size nTotalSize = aStream.Tell();
1859 if( nTotalSize > SAL_MAX_UINT32 )
1860 return;
1861 aStream.Seek( 0 );
1862 sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize );
1863 sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1;
1864 sal_uInt16 nCheckSum = 0, nWord;
1866 sal_uInt32 nPos = 0;
1868 while( nPos + 1 < nTotalSize )
1870 aStream.ReadUInt16( nWord );
1871 nCheckSum ^= nWord;
1872 nPos += 2;
1875 nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 );
1877 aStream.Seek( 0 );
1878 while( nRemainingSize > 0 )
1880 sal_uInt32 nCurSize;
1881 if( nRemainingSize > 0x2000 )
1883 nCurSize = 0x2000;
1884 nRemainingSize -= 0x2000;
1886 else
1888 nCurSize = nRemainingSize;
1889 nRemainingSize = 0;
1891 WriteEMFRecord( aStream,
1892 nCurSize,
1893 nRemainingSize,
1894 nTotalSize,
1895 nRecCounts,
1896 nCheckSum );
1897 nCheckSum = 0;
1902 void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize,
1903 sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum )
1905 // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx
1906 WriteRecordHeader( 0, W_META_ESCAPE );
1907 pWMF->WriteUInt16( W_MFCOMMENT ) // same as META_ESCAPE_ENHANCED_METAFILE
1908 .WriteUInt16( nCurSize + 34 ) // we will always have a 34 byte escape header:
1909 .WriteUInt32( 0x43464D57 ) // WMFC
1910 .WriteUInt32( 0x00000001 ) // Comment type
1911 .WriteUInt32( 0x00010000 ) // version
1912 .WriteUInt16( nCheckSum ) // check sum
1913 .WriteUInt32( 0 ) // flags = 0
1914 .WriteUInt32( nRecCounts ) // total number of records
1915 .WriteUInt32( nCurSize ) // size of this record's data
1916 .WriteUInt32( nRemainingSize ) // remaining size of data in following records, missing in MSDN documentation
1917 .WriteUInt32( nTotalSize ); // total size of EMF stream
1919 pWMF->Write( static_cast< const sal_Char* >( rStream.GetData() ) + rStream.Tell(), nCurSize );
1920 rStream.SeekRel( nCurSize );
1921 UpdateRecordHeader();
1924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */