bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / filter / wmf / wmfwr.cxx
blob25536eb80e65420392a8bbabe0b878eb978f4e5a
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>
21 #include <osl/diagnose.h>
23 #include <algorithm>
25 #include "wmfwr.hxx"
26 #include "emfwr.hxx"
27 #include <rtl/crc.h>
28 #include <rtl/tencinfo.h>
29 #include <tools/bigint.hxx>
30 #include <tools/helpers.hxx>
31 #include <tools/tenccvt.hxx>
32 #include <tools/fract.hxx>
33 #include <tools/stream.hxx>
34 #include <vcl/dibtools.hxx>
35 #include <vcl/metaact.hxx>
36 #include <vcl/FilterConfigItem.hxx>
37 #include <basegfx/polygon/b2dpolygon.hxx>
38 #include <basegfx/polygon/b2dpolypolygon.hxx>
39 #include <memory>
40 #include <vcl/fontcharmap.hxx>
42 // MS Windows defines
44 #define W_META_SETBKMODE 0x0102
45 #define W_META_SETROP2 0x0104
46 #define W_META_SETSTRETCHBLTMODE 0x0107
47 #define W_META_SETTEXTCOLOR 0x0209
48 #define W_META_SETWINDOWORG 0x020B
49 #define W_META_SETWINDOWEXT 0x020C
50 #define W_META_LINETO 0x0213
51 #define W_META_MOVETO 0x0214
52 #define W_META_INTERSECTCLIPRECT 0x0416
53 #define W_META_ARC 0x0817
54 #define W_META_ELLIPSE 0x0418
55 #define W_META_PIE 0x081A
56 #define W_META_RECTANGLE 0x041B
57 #define W_META_ROUNDRECT 0x061C
58 #define W_META_SAVEDC 0x001E
59 #define W_META_SETPIXEL 0x041F
60 #define W_META_TEXTOUT 0x0521
61 #define W_META_POLYGON 0x0324
62 #define W_META_POLYLINE 0x0325
63 #define W_META_ESCAPE 0x0626
64 #define W_META_RESTOREDC 0x0127
65 #define W_META_SELECTOBJECT 0x012D
66 #define W_META_SETTEXTALIGN 0x012E
67 #define W_META_CHORD 0x0830
68 #define W_META_EXTTEXTOUT 0x0a32
69 #define W_META_POLYPOLYGON 0x0538
70 #define W_META_STRETCHDIB 0x0f43
71 #define W_META_DELETEOBJECT 0x01f0
72 #define W_META_CREATEPENINDIRECT 0x02FA
73 #define W_META_CREATEFONTINDIRECT 0x02FB
74 #define W_META_CREATEBRUSHINDIRECT 0x02FC
76 #define W_TRANSPARENT 1
77 #define W_OPAQUE 2
79 #define W_R2_NOT 6
80 #define W_R2_XORPEN 7
81 #define W_R2_COPYPEN 13
83 #define W_TA_NOUPDATECP 0x0000
84 #define W_TA_LEFT 0x0000
85 #define W_TA_RIGHT 0x0002
86 #define W_TA_TOP 0x0000
87 #define W_TA_BOTTOM 0x0008
88 #define W_TA_BASELINE 0x0018
89 #define W_TA_RTLREADING 0x0100
91 #define W_SRCCOPY 0x00CC0020L
92 #define W_SRCPAINT 0x00EE0086L
93 #define W_SRCAND 0x008800C6L
94 #define W_SRCINVERT 0x00660046L
95 #define W_DSTINVERT 0x00550009L
97 #define W_PS_SOLID 0
98 #define W_PS_DASH 1
99 #define W_PS_DOT 2
100 #define W_PS_DASHDOT 3
101 #define W_PS_DASHDOTDOT 4
102 #define W_PS_NULL 5
104 #define W_LF_FACESIZE 32
106 #define W_ANSI_CHARSET 0
108 #define W_DEFAULT_PITCH 0x00
109 #define W_FIXED_PITCH 0x01
110 #define W_VARIABLE_PITCH 0x02
112 #define W_FF_DONTCARE 0x00
113 #define W_FF_ROMAN 0x10
114 #define W_FF_SWISS 0x20
115 #define W_FF_MODERN 0x30
116 #define W_FF_SCRIPT 0x40
117 #define W_FF_DECORATIVE 0x50
119 #define W_FW_DONTCARE 0
120 #define W_FW_THIN 100
121 #define W_FW_LIGHT 300
122 #define W_FW_NORMAL 400
123 #define W_FW_MEDIUM 500
124 #define W_FW_SEMIBOLD 600
125 #define W_FW_BOLD 700
126 #define W_FW_ULTRALIGHT 200
127 #define W_FW_ULTRABOLD 800
128 #define W_FW_BLACK 900
130 #define W_BS_SOLID 0
131 #define W_BS_HOLLOW 1
133 #define W_MFCOMMENT 15
135 #define PRIVATE_ESCAPE_UNICODE 2
137 WMFWriter::WMFWriter()
138 : bStatus(false)
139 , nLastPercent(0)
140 , pWMF(nullptr)
141 , pVirDev(nullptr)
142 , nMetafileHeaderPos(0)
143 , nMaxRecordSize(0)
144 , nActRecordPos(0)
145 , eSrcRasterOp(RasterOp::OverPaint)
146 , eSrcTextAlign(ALIGN_BASELINE)
147 , pAttrStack(nullptr)
148 , eSrcHorTextAlign(W_TA_LEFT)
149 , eDstROP2(RasterOp::OverPaint)
150 , eDstTextAlign(ALIGN_BASELINE)
151 , eDstHorTextAlign(W_TA_LEFT)
152 , bHandleAllocated{}
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 tools::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 tools::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 tools::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==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.GetFontSize().Width(),-rFont.GetFontSize().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()==LINESTYLE_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.GetFamilyType()) {
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.GetFamilyName(), 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 == COL_TRANSPARENT ? W_PS_NULL : W_PS_SOLID;
374 switch( rLineInfo.GetStyle() )
376 case LineStyle::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 LineStyle::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 tools::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->WriteBytes( 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 if (aTextEncoding == RTL_TEXTENCODING_DONTKNOW) {
471 aTextEncoding = aTextEncodingOrg;
473 for ( i = 1; i < nStringLen; i++)
475 if (aTextEncoding != aTextEncodingOrg) // found something
476 break;
477 pCheckChar++;
478 aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the next character
479 if (aTextEncoding == RTL_TEXTENCODING_DONTKNOW) {
480 aTextEncoding = aTextEncodingOrg;
484 aByteStr = OUStringToOString(rUniStr, aTextEncoding);
485 aUniStr2 = OStringToOUString(aByteStr, aTextEncoding);
486 pConversion = aUniStr2.getStr(); // this is the unicode array after bytestring <-> unistring conversion
487 for ( i = 0; i < nStringLen; i++ )
489 if ( *pBuf++ != *pConversion++ )
490 break;
492 if (i == nStringLen)
494 aSrcFont.SetCharSet (aTextEncoding);
495 SetAllAttr();
499 if ( ( i != nStringLen ) || IsStarSymbol( aSrcFont.GetFamilyName() ) ) // after conversion the characters are not original, so we
500 { // will store the unicode string and a polypoly replacement
501 Color aOldFillColor( aSrcFillColor );
502 Color aOldLineColor( aSrcLineColor );
503 aSrcLineInfo = LineInfo();
504 aSrcFillColor = aSrcTextColor;
505 aSrcLineColor = COL_TRANSPARENT;
506 SetLineAndFillAttr();
507 pVirDev->SetFont( aSrcFont );
508 std::vector<tools::PolyPolygon> aPolyPolyVec;
509 if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniStr ) )
511 sal_uInt32 nDXCount = pDXAry ? nStringLen : 0;
512 sal_uInt32 nSkipActions = aPolyPolyVec.size();
513 sal_Int32 nStrmLen = 8 +
514 + sizeof( nStringLen ) + ( nStringLen * 2 )
515 + sizeof( nDXCount ) + ( nDXCount * 4 )
516 + sizeof( nSkipActions );
518 SvMemoryStream aMemoryStream( nStrmLen );
519 Point aPt( OutputDevice::LogicToLogic( rPoint, aSrcMapMode, aTargetMapMode ) );
520 aMemoryStream.WriteInt32( aPt.X() )
521 .WriteInt32( aPt.Y() )
522 .WriteUInt32( nStringLen );
523 for ( i = 0; i < nStringLen; i++ )
524 aMemoryStream.WriteUInt16( rUniStr[ i ] );
525 aMemoryStream.WriteUInt32( nDXCount );
526 for ( i = 0; i < nDXCount; i++ )
527 aMemoryStream.WriteInt32( pDXAry[ i ] );
528 aMemoryStream.WriteUInt32( nSkipActions );
529 WMFRecord_Escape( PRIVATE_ESCAPE_UNICODE, nStrmLen, static_cast<const sal_Int8*>(aMemoryStream.GetData()) );
531 for ( const auto& rPolyPoly : aPolyPolyVec )
533 tools::PolyPolygon aPolyPoly( rPolyPoly );
534 aPolyPoly.Move( rPoint.X(), rPoint.Y() );
535 WMFRecord_PolyPolygon( aPolyPoly );
537 aSrcFillColor = aOldFillColor;
538 aSrcLineColor = aOldLineColor;
539 bEscapeUsed = true;
544 return bEscapeUsed;
547 void WMFWriter::WMFRecord_ExtTextOut( const Point& rPoint,
548 const OUString& rString,
549 const long* pDXAry )
551 sal_Int32 nOriginalTextLen = rString.getLength();
553 if ( (nOriginalTextLen <= 1) || (pDXAry == nullptr) )
555 WMFRecord_TextOut(rPoint, rString);
556 return;
558 rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
559 OString aByteString(OUStringToOString(rString, eChrSet));
560 TrueExtTextOut(rPoint, rString, aByteString, pDXAry);
563 void WMFWriter::TrueExtTextOut( const Point& rPoint, const OUString& rString,
564 const OString& rByteString, const long* pDXAry )
566 WriteRecordHeader( 0, W_META_EXTTEXTOUT );
567 WritePointYX( rPoint );
568 sal_uInt16 nNewTextLen = static_cast<sal_uInt16>(rByteString.getLength());
569 pWMF->WriteUInt16( nNewTextLen ).WriteUInt16( 0 );
570 write_uInt8s_FromOString(*pWMF, rByteString, nNewTextLen);
571 if ( nNewTextLen & 1 )
572 pWMF->WriteUChar( 0 );
574 sal_Int32 nOriginalTextLen = rString.getLength();
575 std::unique_ptr<sal_Int16[]> pConvertedDXAry(new sal_Int16[ nOriginalTextLen ]);
576 sal_Int32 j = 0;
577 pConvertedDXAry[ j++ ] = static_cast<sal_Int16>(ScaleWidth( pDXAry[ 0 ] ));
578 for (sal_Int32 i = 1; i < ( nOriginalTextLen - 1 ); ++i)
579 pConvertedDXAry[ j++ ] = static_cast<sal_Int16>(ScaleWidth( pDXAry[ i ] - pDXAry[ i - 1 ] ));
580 pConvertedDXAry[ j ] = static_cast<sal_Int16>(ScaleWidth( pDXAry[ nOriginalTextLen - 2 ] / ( nOriginalTextLen - 1 ) ));
582 for (sal_Int32 i = 0; i < nOriginalTextLen; ++i)
584 sal_Int16 nDx = pConvertedDXAry[ i ];
585 pWMF->WriteInt16( nDx );
586 if ( nOriginalTextLen < nNewTextLen )
588 sal_Unicode nUniChar = rString[i];
589 OString aTemp(&nUniChar, 1, aSrcFont.GetCharSet());
590 j = aTemp.getLength();
591 while ( --j > 0 )
592 pWMF->WriteUInt16( 0 );
595 pConvertedDXAry.reset();
596 UpdateRecordHeader();
599 void WMFWriter::WMFRecord_LineTo(const Point & rPoint)
601 WriteRecordHeader(0x00000005,W_META_LINETO);
602 WritePointYX(rPoint);
605 void WMFWriter::WMFRecord_MoveTo(const Point & rPoint)
607 WriteRecordHeader(0x00000005,W_META_MOVETO);
608 WritePointYX(rPoint);
611 void WMFWriter::WMFRecord_Pie(const tools::Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
613 WriteRecordHeader(0x0000000b,W_META_PIE);
614 WritePointYX(rEndPt);
615 WritePointYX(rStartPt);
616 WriteRectangle(rRect);
619 void WMFWriter::WMFRecord_Polygon(const tools::Polygon & rPoly)
621 tools::Polygon aSimplePoly;
622 if ( rPoly.HasFlags() )
623 rPoly.AdaptiveSubdivide( aSimplePoly );
624 else
625 aSimplePoly = rPoly;
626 const sal_uInt16 nSize = aSimplePoly.GetSize();
627 WriteRecordHeader(static_cast<sal_uInt32>(nSize)*2+4,W_META_POLYGON);
628 pWMF->WriteUInt16( nSize );
629 for (sal_uInt16 i=0; i<nSize; ++i)
630 WritePointXY(aSimplePoly.GetPoint(i));
633 void WMFWriter::WMFRecord_PolyLine(const tools::Polygon & rPoly)
635 tools::Polygon aSimplePoly;
636 if ( rPoly.HasFlags() )
637 rPoly.AdaptiveSubdivide( aSimplePoly );
638 else
639 aSimplePoly = rPoly;
640 const sal_uInt16 nSize = aSimplePoly.GetSize();
641 WriteRecordHeader(static_cast<sal_uInt32>(nSize)*2+4,W_META_POLYLINE);
642 pWMF->WriteUInt16( nSize );
643 for (sal_uInt16 i=0; i<nSize; ++i)
644 WritePointXY(aSimplePoly.GetPoint(i));
647 void WMFWriter::WMFRecord_PolyPolygon(const tools::PolyPolygon & rPolyPoly)
649 const tools::Polygon * pPoly;
650 sal_uInt16 nCount,nSize,i,j;
652 nCount=rPolyPoly.Count();
653 tools::PolyPolygon aSimplePolyPoly( rPolyPoly );
654 for ( i = 0; i < nCount; i++ )
656 if ( aSimplePolyPoly[ i ].HasFlags() )
658 tools::Polygon aSimplePoly;
659 aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly );
660 aSimplePolyPoly[ i ] = aSimplePoly;
663 WriteRecordHeader(0,W_META_POLYPOLYGON);
664 pWMF->WriteUInt16( nCount );
665 for (i=0; i<nCount; i++) pWMF->WriteUInt16( aSimplePolyPoly.GetObject(i).GetSize() );
666 for (i=0; i<nCount; i++) {
667 pPoly=&(aSimplePolyPoly.GetObject(i));
668 nSize=pPoly->GetSize();
669 for (j=0; j<nSize; j++) WritePointXY(pPoly->GetPoint(j));
671 UpdateRecordHeader();
674 void WMFWriter::WMFRecord_Rectangle(const tools::Rectangle & rRect)
676 WriteRecordHeader( 0x00000007,W_META_RECTANGLE );
677 WriteRectangle( rRect );
680 void WMFWriter::WMFRecord_RestoreDC()
682 WriteRecordHeader(0x00000004,W_META_RESTOREDC);
683 pWMF->WriteInt16( -1 );
686 void WMFWriter::WMFRecord_RoundRect(const tools::Rectangle & rRect, long nHorzRound, long nVertRound)
688 WriteRecordHeader(0x00000009,W_META_ROUNDRECT);
689 WriteHeightWidth(Size(nHorzRound,nVertRound));
690 WriteRectangle(rRect);
693 void WMFWriter::WMFRecord_SaveDC()
695 WriteRecordHeader(0x00000003,W_META_SAVEDC);
698 void WMFWriter::WMFRecord_SelectObject(sal_uInt16 nObjectHandle)
700 WriteRecordHeader(0x00000004,W_META_SELECTOBJECT);
701 pWMF->WriteUInt16( nObjectHandle );
704 void WMFWriter::WMFRecord_SetBkMode(bool bTransparent)
706 WriteRecordHeader(0x00000004,W_META_SETBKMODE);
707 if (bTransparent) pWMF->WriteUInt16( W_TRANSPARENT );
708 else pWMF->WriteUInt16( W_OPAQUE );
711 void WMFWriter::WMFRecord_SetStretchBltMode()
713 WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE );
714 pWMF->WriteUInt16( 3 ); // STRETCH_DELETESCANS
717 void WMFWriter::WMFRecord_SetPixel(const Point & rPoint, const Color & rColor)
719 WriteRecordHeader(0x00000007,W_META_SETPIXEL);
720 WriteColor(rColor);
721 WritePointYX(rPoint);
724 void WMFWriter::WMFRecord_SetROP2(RasterOp eROP)
726 sal_uInt16 nROP2;
728 switch (eROP) {
729 case RasterOp::Invert: nROP2=W_R2_NOT; break;
730 case RasterOp::Xor: nROP2=W_R2_XORPEN; break;
731 default: nROP2=W_R2_COPYPEN;
733 WriteRecordHeader(0x00000004,W_META_SETROP2);
734 pWMF->WriteUInt16( nROP2 );
737 void WMFWriter::WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_uInt16 eHorTextAlign)
739 sal_uInt16 nAlign;
741 switch (eFontAlign) {
742 case ALIGN_TOP: nAlign=W_TA_TOP; break;
743 case ALIGN_BOTTOM: nAlign=W_TA_BOTTOM; break;
744 default: nAlign=W_TA_BASELINE;
746 nAlign|=eHorTextAlign;
747 nAlign|=W_TA_NOUPDATECP;
749 WriteRecordHeader(0x00000004,W_META_SETTEXTALIGN);
750 pWMF->WriteUInt16( nAlign );
753 void WMFWriter::WMFRecord_SetTextColor(const Color & rColor)
755 WriteRecordHeader(0x00000005,W_META_SETTEXTCOLOR);
756 WriteColor(rColor);
759 void WMFWriter::WMFRecord_SetWindowExt(const Size & rSize)
761 WriteRecordHeader(0x00000005,W_META_SETWINDOWEXT);
762 WriteHeightWidth(rSize);
765 void WMFWriter::WMFRecord_SetWindowOrg(const Point & rPoint)
767 WriteRecordHeader(0x00000005,W_META_SETWINDOWORG);
768 WritePointYX(rPoint);
771 void WMFWriter::WMFRecord_StretchDIB( const Point & rPoint, const Size & rSize,
772 const Bitmap & rBitmap, sal_uInt32 nROP )
774 sal_uLong nPosAnf,nPosEnd;
776 nActBitmapPercent=50;
777 MayCallback();
779 WriteRecordHeader(0x00000000,W_META_STRETCHDIB);
781 // The sequence in the metafile should be:
782 // some parameters (length 22), then the bitmap without FILEHEADER.
783 // As *pWMF << rBitmap generates a FILEHEADER of size 14,
784 // we first write the bitmap at the right position
785 // and overwrite later the FILEHEADER with the parameters.
786 nPosAnf=pWMF->Tell(); // remember position, where parameters should be stored
787 pWMF->WriteInt32( 0 ).WriteInt32( 0 ); // replenish 8 bytes (these 8 bytes +
788 // 14 bytes superfluous FILEHEADER
789 // = 22 bytes parameter)
791 // write bitmap
792 WriteDIB(rBitmap, *pWMF, false, true);
794 // write the parameters:
795 nPosEnd=pWMF->Tell();
796 pWMF->Seek(nPosAnf);
798 // determine raster-op, if nothing was passed
799 if( !nROP )
801 switch( eSrcRasterOp )
803 case RasterOp::Invert: nROP = W_DSTINVERT; break;
804 case RasterOp::Xor: nROP = W_SRCINVERT; break;
805 default: nROP = W_SRCCOPY;
809 pWMF->WriteUInt32( nROP ).
810 WriteInt16( 0 ).
811 WriteInt16( rBitmap.GetSizePixel().Height() ).
812 WriteInt16( rBitmap.GetSizePixel().Width() ).
813 WriteInt16( 0 ).
814 WriteInt16( 0 );
816 WriteHeightWidth(rSize);
817 WritePointYX(rPoint);
818 pWMF->Seek(nPosEnd);
820 UpdateRecordHeader();
822 nWrittenBitmaps++;
823 nActBitmapPercent=0;
826 void WMFWriter::WMFRecord_TextOut(const Point & rPoint, const OUString & rStr)
828 rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
829 OString aString(OUStringToOString(rStr, eChrSet));
830 TrueTextOut(rPoint, aString);
833 void WMFWriter::TrueTextOut(const Point & rPoint, const OString& rString)
835 WriteRecordHeader(0,W_META_TEXTOUT);
837 write_uInt16_lenPrefixed_uInt8s_FromOString(*pWMF, rString);
838 sal_Int32 nLen = rString.getLength();
839 if ((nLen&1)!=0) pWMF->WriteUChar( 0 );
840 WritePointYX(rPoint);
841 UpdateRecordHeader();
844 void WMFWriter::WMFRecord_IntersectClipRect( const tools::Rectangle& rRect )
846 WriteRecordHeader( 0x00000007, W_META_INTERSECTCLIPRECT );
847 WriteRectangle(rRect);
850 sal_uInt16 WMFWriter::AllocHandle()
852 sal_uInt16 i;
854 for (i=0; i<MAXOBJECTHANDLES; i++) {
855 if (!bHandleAllocated[i]) {
856 bHandleAllocated[i]=true;
857 return i;
860 bStatus=false;
861 return 0xffff;
864 void WMFWriter::FreeHandle(sal_uInt16 nObjectHandle)
866 if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=false;
869 void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo )
871 sal_uInt16 nOldHandle;
873 nOldHandle=nDstPenHandle;
874 nDstPenHandle=AllocHandle();
875 WMFRecord_CreatePenIndirect( rColor, rLineInfo );
876 WMFRecord_SelectObject(nDstPenHandle);
877 if (nOldHandle<MAXOBJECTHANDLES) {
878 WMFRecord_DeleteObject(nOldHandle);
879 FreeHandle(nOldHandle);
883 void WMFWriter::CreateSelectDeleteFont(const vcl::Font & rFont)
885 sal_uInt16 nOldHandle;
887 nOldHandle=nDstFontHandle;
888 nDstFontHandle=AllocHandle();
889 WMFRecord_CreateFontIndirect(rFont);
890 WMFRecord_SelectObject(nDstFontHandle);
891 if (nOldHandle<MAXOBJECTHANDLES) {
892 WMFRecord_DeleteObject(nOldHandle);
893 FreeHandle(nOldHandle);
897 void WMFWriter::CreateSelectDeleteBrush(const Color& rColor)
899 sal_uInt16 nOldHandle;
901 nOldHandle=nDstBrushHandle;
902 nDstBrushHandle=AllocHandle();
903 WMFRecord_CreateBrushIndirect(rColor);
904 WMFRecord_SelectObject(nDstBrushHandle);
905 if (nOldHandle<MAXOBJECTHANDLES) {
906 WMFRecord_DeleteObject(nOldHandle);
907 FreeHandle(nOldHandle);
911 void WMFWriter::SetLineAndFillAttr()
913 if ( eDstROP2 != eSrcRasterOp )
915 eDstROP2=eSrcRasterOp;
916 WMFRecord_SetROP2(eDstROP2);
918 if ( ( aDstLineColor != aSrcLineColor ) || ( aDstLineInfo != aSrcLineInfo ) )
920 aDstLineColor = aSrcLineColor;
921 aDstLineInfo = aSrcLineInfo;
922 CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
924 if ( aDstFillColor != aSrcFillColor )
926 aDstFillColor = aSrcFillColor;
927 CreateSelectDeleteBrush( aDstFillColor );
931 void WMFWriter::SetAllAttr()
933 SetLineAndFillAttr();
934 if ( aDstTextColor != aSrcTextColor )
936 aDstTextColor = aSrcTextColor;
937 WMFRecord_SetTextColor(aDstTextColor);
939 if ( eDstTextAlign != eSrcTextAlign || eDstHorTextAlign != eSrcHorTextAlign )
941 eDstTextAlign = eSrcTextAlign;
942 eDstHorTextAlign = eSrcHorTextAlign;
943 WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
945 if ( aDstFont != aSrcFont )
947 pVirDev->SetFont(aSrcFont);
948 if ( aDstFont.GetFamilyName() != aSrcFont.GetFamilyName() )
950 FontCharMapRef xFontCharMap;
951 if ( pVirDev->GetFontCharMap( xFontCharMap ) )
953 if ( ( xFontCharMap->GetFirstChar() & 0xff00 ) == 0xf000 )
954 aSrcFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
955 else if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
956 aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
960 aDstFont = aSrcFont;
961 CreateSelectDeleteFont(aDstFont);
965 void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
967 if(rLinePolygon.count())
969 basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
970 basegfx::B2DPolyPolygon aFillPolyPolygon;
972 rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
974 if(aLinePolyPolygon.count())
976 aSrcLineInfo = rInfo;
977 SetLineAndFillAttr();
979 for(auto const& rB2DPolygon : aLinePolyPolygon)
981 WMFRecord_PolyLine( tools::Polygon(rB2DPolygon) );
985 if(aFillPolyPolygon.count())
987 const Color aOldLineColor(aSrcLineColor);
988 const Color aOldFillColor(aSrcFillColor);
990 aSrcLineColor = COL_TRANSPARENT;
991 aSrcFillColor = aOldLineColor;
992 SetLineAndFillAttr();
994 for(auto const& rB2DPolygon : aFillPolyPolygon)
996 WMFRecord_Polygon( tools::Polygon(rB2DPolygon) );
999 aSrcLineColor = aOldLineColor;
1000 aSrcFillColor = aOldFillColor;
1001 SetLineAndFillAttr();
1006 void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
1008 if( bStatus )
1010 size_t nACount = rMTF.GetActionSize();
1012 WMFRecord_SetStretchBltMode();
1014 for( size_t nA = 0; nA < nACount; nA++ )
1016 MetaAction* pMA = rMTF.GetAction( nA );
1018 switch( pMA->GetType() )
1020 case MetaActionType::PIXEL:
1022 const MetaPixelAction* pA = static_cast<const MetaPixelAction *>(pMA);
1023 aSrcLineInfo = LineInfo();
1024 SetLineAndFillAttr();
1025 WMFRecord_SetPixel( pA->GetPoint(), pA->GetColor() );
1027 break;
1029 case MetaActionType::POINT:
1031 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pMA);
1032 const Point& rPt = pA->GetPoint();
1033 aSrcLineInfo = LineInfo();
1034 SetLineAndFillAttr();
1035 WMFRecord_MoveTo( rPt);
1036 WMFRecord_LineTo( rPt );
1038 break;
1040 case MetaActionType::LINE:
1042 const MetaLineAction* pA = static_cast<const MetaLineAction *>(pMA);
1043 if(pA->GetLineInfo().IsDefault())
1045 aSrcLineInfo = pA->GetLineInfo();
1046 SetLineAndFillAttr();
1047 WMFRecord_MoveTo( pA->GetStartPoint() );
1048 WMFRecord_LineTo( pA->GetEndPoint() );
1050 else
1052 // LineInfo used; handle Dash/Dot and fat lines
1053 basegfx::B2DPolygon aPolygon;
1054 aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1055 aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1056 HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
1059 break;
1061 case MetaActionType::RECT:
1063 const MetaRectAction* pA = static_cast<const MetaRectAction*>(pMA);
1064 aSrcLineInfo = LineInfo();
1065 SetLineAndFillAttr();
1066 WMFRecord_Rectangle( pA->GetRect() );
1068 break;
1070 case MetaActionType::ROUNDRECT:
1072 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pMA);
1073 aSrcLineInfo = LineInfo();
1074 SetLineAndFillAttr();
1075 WMFRecord_RoundRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
1077 break;
1079 case MetaActionType::ELLIPSE:
1081 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pMA);
1082 aSrcLineInfo = LineInfo();
1083 SetLineAndFillAttr();
1084 WMFRecord_Ellipse( pA->GetRect() );
1086 break;
1088 case MetaActionType::ARC:
1090 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pMA);
1091 aSrcLineInfo = LineInfo();
1092 SetLineAndFillAttr();
1093 WMFRecord_Arc( pA->GetRect(),pA->GetStartPoint(),pA->GetEndPoint() );
1095 break;
1097 case MetaActionType::PIE:
1099 const MetaPieAction* pA = static_cast<const MetaPieAction*>(pMA);
1100 aSrcLineInfo = LineInfo();
1101 SetLineAndFillAttr();
1102 WMFRecord_Pie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1104 break;
1106 case MetaActionType::CHORD:
1108 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pMA);
1109 aSrcLineInfo = LineInfo();
1110 SetLineAndFillAttr();
1111 WMFRecord_Chord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1113 break;
1115 case MetaActionType::POLYLINE:
1117 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pMA);
1118 const tools::Polygon& rPoly = pA->GetPolygon();
1120 if( rPoly.GetSize() )
1122 if(pA->GetLineInfo().IsDefault())
1124 aSrcLineInfo = pA->GetLineInfo();
1125 SetLineAndFillAttr();
1126 WMFRecord_PolyLine( rPoly );
1128 else
1130 // LineInfo used; handle Dash/Dot and fat lines
1131 HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1135 break;
1137 case MetaActionType::POLYGON:
1139 const MetaPolygonAction* pA = static_cast<const MetaPolygonAction*>(pMA);
1140 aSrcLineInfo = LineInfo();
1141 SetLineAndFillAttr();
1142 WMFRecord_Polygon( pA->GetPolygon() );
1144 break;
1146 case MetaActionType::POLYPOLYGON:
1148 const MetaPolyPolygonAction* pA = static_cast<const MetaPolyPolygonAction*>(pMA);
1149 aSrcLineInfo = LineInfo();
1150 SetLineAndFillAttr();
1151 WMFRecord_PolyPolygon( pA->GetPolyPolygon() );
1153 break;
1155 case MetaActionType::TEXTRECT:
1157 const MetaTextRectAction * pA = static_cast<const MetaTextRectAction*>(pMA);
1158 OUString aTemp( pA->GetText() );
1159 aSrcLineInfo = LineInfo();
1160 SetAllAttr();
1162 Point aPos( pA->GetRect().TopLeft() );
1163 if ( !WMFRecord_Escape_Unicode( aPos, aTemp, nullptr ) )
1164 WMFRecord_TextOut( aPos, aTemp );
1166 break;
1168 case MetaActionType::TEXT:
1170 const MetaTextAction * pA = static_cast<const MetaTextAction*>(pMA);
1171 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1172 aSrcLineInfo = LineInfo();
1173 SetAllAttr();
1174 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, nullptr ) )
1175 WMFRecord_TextOut( pA->GetPoint(), aTemp );
1177 break;
1179 case MetaActionType::TEXTARRAY:
1181 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pMA);
1183 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1184 aSrcLineInfo = LineInfo();
1185 SetAllAttr();
1186 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pA->GetDXArray() ) )
1187 WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pA->GetDXArray() );
1189 break;
1191 case MetaActionType::STRETCHTEXT:
1193 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction *>(pMA);
1194 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1196 pVirDev->SetFont( aSrcFont );
1197 const sal_Int32 nLen = aTemp.getLength();
1198 std::unique_ptr<long[]> pDXAry(nLen ? new long[ nLen ] : nullptr);
1199 const sal_Int32 nNormSize = pVirDev->GetTextArray( aTemp, pDXAry.get() );
1200 if (nLen && nNormSize == 0)
1202 OSL_FAIL("Impossible div by 0 action: MetaStretchTextAction!");
1204 else
1206 for ( sal_Int32 i = 0; i < ( nLen - 1 ); i++ )
1207 pDXAry[ i ] = pDXAry[ i ] * static_cast<sal_Int32>(pA->GetWidth()) / nNormSize;
1208 if ( ( nLen <= 1 ) || ( static_cast<sal_Int32>(pA->GetWidth()) == nNormSize ) )
1209 pDXAry.reset();
1210 aSrcLineInfo = LineInfo();
1211 SetAllAttr();
1212 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pDXAry.get() ) )
1213 WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pDXAry.get() );
1216 break;
1218 case MetaActionType::BMP:
1220 const MetaBmpAction* pA = static_cast<const MetaBmpAction *>(pMA);
1221 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetBitmap().GetSizePixel(), pA->GetBitmap() );
1223 break;
1225 case MetaActionType::BMPSCALE:
1227 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pMA);
1228 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pA->GetBitmap() );
1230 break;
1232 case MetaActionType::BMPSCALEPART:
1234 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pMA);
1235 Bitmap aTmp( pA->GetBitmap() );
1237 if( aTmp.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1238 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aTmp );
1240 break;
1242 case MetaActionType::BMPEX:
1244 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction *>(pMA);
1245 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1246 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1248 if( !!aMsk )
1250 aBmp.Replace( aMsk, COL_WHITE );
1251 aMsk.Invert();
1252 WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT );
1253 WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND );
1255 else
1256 WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp );
1258 break;
1260 case MetaActionType::BMPEXSCALE:
1262 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pMA);
1263 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1264 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1266 if( !!aMsk )
1268 aBmp.Replace( aMsk, COL_WHITE );
1269 aMsk.Invert();
1270 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT );
1271 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND );
1273 else
1274 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp );
1276 break;
1278 case MetaActionType::BMPEXSCALEPART:
1280 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pMA);
1281 BitmapEx aBmpEx( pA->GetBitmapEx() );
1282 aBmpEx.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1283 Bitmap aBmp( aBmpEx.GetBitmap() );
1284 Bitmap aMsk( aBmpEx.GetMask() );
1286 if( !!aMsk )
1288 aBmp.Replace( aMsk, COL_WHITE );
1289 aMsk.Invert();
1290 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT );
1291 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND );
1293 else
1294 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp );
1296 break;
1298 case MetaActionType::GRADIENT:
1300 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pMA);
1301 GDIMetaFile aTmpMtf;
1303 pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1304 WriteRecords( aTmpMtf );
1306 break;
1308 case MetaActionType::HATCH:
1310 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pMA);
1311 GDIMetaFile aTmpMtf;
1313 pVirDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1314 WriteRecords( aTmpMtf );
1316 break;
1318 case MetaActionType::WALLPAPER:
1320 const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pMA);
1321 const Color& rColor = pA->GetWallpaper().GetColor();
1322 const Color aOldLineColor( aSrcLineColor );
1323 const Color aOldFillColor( aSrcFillColor );
1325 aSrcLineColor = rColor;
1326 aSrcFillColor = rColor;
1327 aSrcLineInfo = LineInfo();
1328 SetLineAndFillAttr();
1329 WMFRecord_Rectangle( pA->GetRect() );
1330 aSrcLineColor = aOldLineColor;
1331 aSrcFillColor = aOldFillColor;
1333 break;
1335 case MetaActionType::ISECTRECTCLIPREGION:
1337 const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pMA);
1338 WMFRecord_IntersectClipRect( pA->GetRect() );
1340 break;
1342 case MetaActionType::LINECOLOR:
1344 const MetaLineColorAction* pA = static_cast<const MetaLineColorAction*>(pMA);
1346 if( pA->IsSetting() )
1347 aSrcLineColor = pA->GetColor();
1348 else
1349 aSrcLineColor = COL_TRANSPARENT;
1351 break;
1353 case MetaActionType::FILLCOLOR:
1355 const MetaFillColorAction* pA = static_cast<const MetaFillColorAction*>(pMA);
1357 if( pA->IsSetting() )
1358 aSrcFillColor = pA->GetColor();
1359 else
1360 aSrcFillColor = COL_TRANSPARENT;
1362 break;
1364 case MetaActionType::TEXTCOLOR:
1366 const MetaTextColorAction* pA = static_cast<const MetaTextColorAction*>(pMA);
1367 aSrcTextColor = pA->GetColor();
1369 break;
1371 case MetaActionType::TEXTFILLCOLOR:
1373 const MetaTextFillColorAction* pA = static_cast<const MetaTextFillColorAction*>(pMA);
1374 if( pA->IsSetting() )
1375 aSrcFont.SetFillColor( pA->GetColor() );
1376 else
1377 aSrcFont.SetFillColor( COL_TRANSPARENT );
1379 break;
1381 case MetaActionType::TEXTALIGN:
1383 const MetaTextAlignAction* pA = static_cast<const MetaTextAlignAction*>(pMA);
1384 eSrcTextAlign = pA->GetTextAlign();
1386 break;
1388 case MetaActionType::MAPMODE:
1390 const MetaMapModeAction* pA = static_cast<const MetaMapModeAction*>(pMA);
1392 if (aSrcMapMode!=pA->GetMapMode())
1394 if( pA->GetMapMode().GetMapUnit() == MapUnit::MapRelative )
1396 const MapMode& aMM = pA->GetMapMode();
1397 Fraction aScaleX = aMM.GetScaleX();
1398 Fraction aScaleY = aMM.GetScaleY();
1400 Point aOrigin = aSrcMapMode.GetOrigin();
1401 BigInt aX( aOrigin.X() );
1402 aX *= BigInt( aScaleX.GetDenominator() );
1403 if( aOrigin.X() >= 0 )
1404 if( aScaleX.GetNumerator() >= 0 )
1405 aX += BigInt( aScaleX.GetNumerator()/2 );
1406 else
1407 aX -= BigInt( (aScaleX.GetNumerator()+1)/2 );
1408 else
1409 if( aScaleX.GetNumerator() >= 0 )
1410 aX -= BigInt( (aScaleX.GetNumerator()-1)/2 );
1411 else
1412 aX += BigInt( aScaleX.GetNumerator()/2 );
1413 aX /= BigInt( aScaleX.GetNumerator() );
1414 aOrigin.setX( static_cast<long>(aX) + aMM.GetOrigin().X() );
1415 BigInt aY( aOrigin.Y() );
1416 aY *= BigInt( aScaleY.GetDenominator() );
1417 if( aOrigin.Y() >= 0 )
1418 if( aScaleY.GetNumerator() >= 0 )
1419 aY += BigInt( aScaleY.GetNumerator()/2 );
1420 else
1421 aY -= BigInt( (aScaleY.GetNumerator()+1)/2 );
1422 else
1423 if( aScaleY.GetNumerator() >= 0 )
1424 aY -= BigInt( (aScaleY.GetNumerator()-1)/2 );
1425 else
1426 aY += BigInt( aScaleY.GetNumerator()/2 );
1427 aY /= BigInt( aScaleY.GetNumerator() );
1428 aOrigin.setY( static_cast<long>(aY) + aMM.GetOrigin().Y() );
1429 aSrcMapMode.SetOrigin( aOrigin );
1431 aScaleX *= aSrcMapMode.GetScaleX();
1432 aScaleY *= aSrcMapMode.GetScaleY();
1433 aSrcMapMode.SetScaleX( aScaleX );
1434 aSrcMapMode.SetScaleY( aScaleY );
1436 else
1437 aSrcMapMode=pA->GetMapMode();
1440 break;
1442 case MetaActionType::FONT:
1444 const MetaFontAction* pA = static_cast<const MetaFontAction*>(pMA);
1445 aSrcFont = pA->GetFont();
1447 if ( (aSrcFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW)
1448 || (aSrcFont.GetCharSet() == RTL_TEXTENCODING_UNICODE) )
1450 aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
1452 eSrcTextAlign = aSrcFont.GetAlignment();
1453 aSrcTextColor = aSrcFont.GetColor();
1454 aSrcFont.SetAlignment( ALIGN_BASELINE );
1455 aSrcFont.SetColor( COL_WHITE );
1457 break;
1459 case MetaActionType::PUSH:
1461 const MetaPushAction* pA = static_cast<const MetaPushAction*>(pMA);
1463 WMFWriterAttrStackMember* pAt = new WMFWriterAttrStackMember;
1464 pAt->nFlags = pA->GetFlags();
1465 pAt->aClipRegion = aSrcClipRegion;
1466 pAt->aLineColor=aSrcLineColor;
1467 pAt->aFillColor=aSrcFillColor;
1468 pAt->eRasterOp=eSrcRasterOp;
1469 pAt->aFont=aSrcFont;
1470 pAt->eTextAlign=eSrcTextAlign;
1471 pAt->aTextColor=aSrcTextColor;
1472 pAt->aMapMode=aSrcMapMode;
1473 pAt->aLineInfo=aDstLineInfo;
1474 pAt->pSucc=pAttrStack;
1475 pAttrStack=pAt;
1477 SetAllAttr(); // update ( now all source attributes are equal to the destination attributes )
1478 WMFRecord_SaveDC();
1481 break;
1483 case MetaActionType::POP:
1485 WMFWriterAttrStackMember * pAt=pAttrStack;
1487 if( pAt )
1489 aDstLineInfo = pAt->aLineInfo;
1490 aDstLineColor = pAt->aLineColor;
1491 if ( pAt->nFlags & PushFlags::LINECOLOR )
1492 aSrcLineColor = pAt->aLineColor;
1493 aDstFillColor = pAt->aFillColor;
1494 if ( pAt->nFlags & PushFlags::FILLCOLOR )
1495 aSrcFillColor = pAt->aFillColor;
1496 eDstROP2 = pAt->eRasterOp;
1497 if ( pAt->nFlags & PushFlags::RASTEROP )
1498 eSrcRasterOp = pAt->eRasterOp;
1499 aDstFont = pAt->aFont;
1500 if ( pAt->nFlags & PushFlags::FONT )
1501 aSrcFont = pAt->aFont;
1502 eDstTextAlign = pAt->eTextAlign;
1503 if ( pAt->nFlags & ( PushFlags::FONT | PushFlags::TEXTALIGN ) )
1504 eSrcTextAlign = pAt->eTextAlign;
1505 aDstTextColor = pAt->aTextColor;
1506 if ( pAt->nFlags & ( PushFlags::FONT | PushFlags::TEXTCOLOR ) )
1507 aSrcTextColor = pAt->aTextColor;
1508 if ( pAt->nFlags & PushFlags::MAPMODE )
1509 aSrcMapMode = pAt->aMapMode;
1510 aDstClipRegion = pAt->aClipRegion;
1511 if ( pAt->nFlags & PushFlags::CLIPREGION )
1512 aSrcClipRegion = pAt->aClipRegion;
1514 WMFRecord_RestoreDC();
1515 pAttrStack = pAt->pSucc;
1516 delete pAt;
1519 break;
1521 case MetaActionType::EPS :
1523 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pMA);
1524 const GDIMetaFile& aGDIMetaFile( pA->GetSubstitute() );
1526 size_t nCount = aGDIMetaFile.GetActionSize();
1527 for ( size_t i = 0; i < nCount; i++ )
1529 const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i );
1530 if ( pMetaAct->GetType() == MetaActionType::BMPSCALE )
1532 const MetaBmpScaleAction* pBmpScaleAction = static_cast<const MetaBmpScaleAction*>(pMetaAct);
1533 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap() );
1534 break;
1538 break;
1540 case MetaActionType::RASTEROP:
1542 const MetaRasterOpAction* pA = static_cast<const MetaRasterOpAction*>(pMA);
1543 eSrcRasterOp=pA->GetRasterOp();
1545 break;
1547 case MetaActionType::Transparent:
1549 aSrcLineInfo = LineInfo();
1550 SetLineAndFillAttr();
1551 WMFRecord_PolyPolygon( static_cast<const MetaTransparentAction*>(pMA)->GetPolyPolygon() );
1553 break;
1555 case MetaActionType::FLOATTRANSPARENT:
1557 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pMA);
1559 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1560 Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1561 const Size aSrcSize( aTmpMtf.GetPrefSize() );
1562 const Point aDestPt( pA->GetPoint() );
1563 const Size aDestSize( pA->GetSize() );
1564 const double fScaleX = aSrcSize.Width() ? static_cast<double>(aDestSize.Width()) / aSrcSize.Width() : 1.0;
1565 const double fScaleY = aSrcSize.Height() ? static_cast<double>(aDestSize.Height()) / aSrcSize.Height() : 1.0;
1566 long nMoveX, nMoveY;
1568 aSrcLineInfo = LineInfo();
1569 SetAllAttr();
1571 if( fScaleX != 1.0 || fScaleY != 1.0 )
1573 aTmpMtf.Scale( fScaleX, fScaleY );
1574 aSrcPt.setX( FRound( aSrcPt.X() * fScaleX ) );
1575 aSrcPt.setY( FRound( aSrcPt.Y() * fScaleY ) );
1578 nMoveX = aDestPt.X() - aSrcPt.X();
1579 nMoveY = aDestPt.Y() - aSrcPt.Y();
1581 if( nMoveX || nMoveY )
1582 aTmpMtf.Move( nMoveX, nMoveY );
1584 WriteRecords( aTmpMtf );
1586 break;
1588 case MetaActionType::LAYOUTMODE:
1590 ComplexTextLayoutFlags nLayoutMode = static_cast<const MetaLayoutModeAction*>(pMA)->GetLayoutMode();
1591 eSrcHorTextAlign = 0; // TA_LEFT
1592 if ((nLayoutMode & ComplexTextLayoutFlags::BiDiRtl) != ComplexTextLayoutFlags::Default)
1594 eSrcHorTextAlign = W_TA_RIGHT | W_TA_RTLREADING;
1596 if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginRight) != ComplexTextLayoutFlags::Default)
1597 eSrcHorTextAlign |= W_TA_RIGHT;
1598 else if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginLeft) != ComplexTextLayoutFlags::Default)
1599 eSrcHorTextAlign &= ~W_TA_RIGHT;
1600 break;
1603 case MetaActionType::CLIPREGION:
1604 case MetaActionType::TEXTLANGUAGE:
1605 case MetaActionType::COMMENT:
1606 // Explicitly ignored cases
1607 break;
1609 default:
1610 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1611 break;
1614 nWrittenActions++;
1615 MayCallback();
1617 if (pWMF->GetError())
1618 bStatus=false;
1620 if(!bStatus)
1621 break;
1626 void WMFWriter::WriteHeader( bool bPlaceable )
1628 if( bPlaceable )
1630 sal_uInt16 nCheckSum, nValue;
1631 Size aSize( OutputDevice::LogicToLogic(Size(1,1),MapMode(MapUnit::MapInch), aTargetMapMode) );
1632 sal_uInt16 nUnitsPerInch = static_cast<sal_uInt16>( ( aSize.Width() + aSize.Height() ) >> 1 );
1634 nCheckSum=0;
1635 nValue=0xcdd7; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1636 nValue=0x9ac6; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1637 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1638 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1639 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1640 nValue=static_cast<sal_uInt16>(aTargetSize.Width()); nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1641 nValue=static_cast<sal_uInt16>(aTargetSize.Height()); nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1642 nValue=nUnitsPerInch; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1643 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1644 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1645 pWMF->WriteUInt16( nCheckSum );
1648 nMetafileHeaderPos=pWMF->Tell();
1649 pWMF->WriteUInt16( 0x0001 ) // type: file
1650 .WriteUInt16( 0x0009 ) // header length in words
1651 .WriteUInt16( 0x0300 ) // Version as BCD number
1652 .WriteUInt32( 0x00000000 ) // file length (without 1st header), is later corrected by UpdateHeader()
1653 .WriteUInt16( MAXOBJECTHANDLES ) // maximum number of simultaneous objects
1654 .WriteUInt32( 0x00000000 ) // maximum record length, is later corrected by UpdateHeader()
1655 .WriteUInt16( 0x0000 ); // reserved
1658 void WMFWriter::UpdateHeader()
1660 sal_uLong nPos;
1661 sal_uInt32 nFileSize;
1663 nPos=pWMF->Tell(); // endposition = total size of file
1664 nFileSize=nPos-nMetafileHeaderPos; // subtract size of 1st header
1665 if ((nFileSize&1)!=0) { // if needed round to words
1666 pWMF->WriteUChar( 0 );
1667 nPos++;
1668 nFileSize++;
1670 nFileSize>>=1; // convert to number of words
1671 pWMF->Seek(nMetafileHeaderPos+6); // to filesize entry in second header
1672 pWMF->WriteUInt32( nFileSize ); // rectify file size
1673 pWMF->SeekRel(2); // to max-record-length-entry in second header
1674 pWMF->WriteUInt32( nMaxRecordSize ); // and rectify
1675 pWMF->Seek(nPos);
1678 bool WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream,
1679 FilterConfigItem const * pFConfigItem, bool bPlaceable )
1681 WMFWriterAttrStackMember * pAt;
1683 bEmbedEMF = true;
1684 bStatus=true;
1685 pVirDev = VclPtr<VirtualDevice>::Create();
1687 if (pFConfigItem)
1689 xStatusIndicator = pFConfigItem->GetStatusIndicator();
1690 if ( xStatusIndicator.is() )
1692 xStatusIndicator->start( OUString(), 100 );
1695 nLastPercent=0;
1697 pWMF=&rTargetStream;
1698 pWMF->SetEndian(SvStreamEndian::LITTLE);
1700 nMaxRecordSize=0;
1702 aSrcMapMode=rMTF.GetPrefMapMode();
1704 if( bPlaceable )
1706 aTargetMapMode = aSrcMapMode;
1707 aTargetSize = rMTF.GetPrefSize();
1708 sal_uInt16 nTargetDivisor = CalcSaveTargetMapMode(aTargetMapMode, aTargetSize);
1709 aTargetSize.setWidth( aTargetSize.Width() / nTargetDivisor );
1710 aTargetSize.setHeight( aTargetSize.Height() / nTargetDivisor );
1712 else
1714 aTargetMapMode = MapMode( MapUnit::MapInch );
1716 const long nUnit = pVirDev->LogicToPixel( Size( 1, 1 ), aTargetMapMode ).Width();
1717 const Fraction aFrac( 1, nUnit );
1719 aTargetMapMode.SetScaleX( aFrac );
1720 aTargetMapMode.SetScaleY( aFrac );
1721 aTargetSize = OutputDevice::LogicToLogic( rMTF.GetPrefSize(), aSrcMapMode, aTargetMapMode );
1724 pVirDev->SetMapMode( aTargetMapMode );
1726 pAttrStack=nullptr;
1728 for (bool & rn : bHandleAllocated)
1729 rn=false;
1731 nDstPenHandle=0xffff;
1732 nDstFontHandle=0xffff;
1733 nDstBrushHandle=0xffff;
1735 nNumberOfActions=0;
1736 nNumberOfBitmaps=0;
1737 nWrittenActions=0;
1738 nWrittenBitmaps=0;
1739 nActBitmapPercent=0;
1741 CountActionsAndBitmaps(rMTF);
1743 WriteHeader(bPlaceable);
1744 if( bEmbedEMF )
1745 WriteEmbeddedEMF( rMTF );
1746 WMFRecord_SetWindowOrg(Point(0,0));
1747 WMFRecord_SetWindowExt(rMTF.GetPrefSize());
1748 WMFRecord_SetBkMode( true );
1750 eDstROP2 = eSrcRasterOp = RasterOp::OverPaint;
1751 WMFRecord_SetROP2(eDstROP2);
1753 aDstLineInfo = LineInfo();
1754 aDstLineColor = aSrcLineColor = COL_BLACK;
1755 CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
1757 aDstFillColor = aSrcFillColor = COL_WHITE;
1758 CreateSelectDeleteBrush( aDstFillColor );
1760 aDstClipRegion = aSrcClipRegion = vcl::Region();
1762 vcl::Font aFont;
1763 aFont.SetCharSet( GetExtendedTextEncoding( RTL_TEXTENCODING_MS_1252 ) );
1764 aFont.SetColor( COL_WHITE );
1765 aFont.SetAlignment( ALIGN_BASELINE );
1766 aDstFont = aSrcFont = aFont;
1767 CreateSelectDeleteFont(aDstFont);
1769 eDstTextAlign = eSrcTextAlign = ALIGN_BASELINE;
1770 eDstHorTextAlign = eSrcHorTextAlign = W_TA_LEFT;
1771 WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
1773 aDstTextColor = aSrcTextColor = COL_WHITE;
1774 WMFRecord_SetTextColor(aDstTextColor);
1776 // Write records
1777 WriteRecords(rMTF);
1779 WriteRecordHeader(0x00000003,0x0000); // end of file
1780 UpdateHeader();
1782 while(pAttrStack)
1784 pAt=pAttrStack;
1785 pAttrStack=pAt->pSucc;
1786 delete pAt;
1789 pVirDev.disposeAndClear();
1791 if ( xStatusIndicator.is() )
1792 xStatusIndicator->end();
1794 return bStatus;
1797 sal_uInt16 WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode,
1798 const Size& rPrefSize)
1800 Fraction aDivFrac(2, 1);
1801 sal_uInt16 nDivisor = 1;
1803 Size aSize = OutputDevice::LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
1805 while( nDivisor <= 64 && (aSize.Width() > 32767 || aSize.Height() > 32767) )
1807 Fraction aFrac = rMapMode.GetScaleX();
1809 aFrac *= aDivFrac;
1810 rMapMode.SetScaleX(aFrac);
1811 aFrac = rMapMode.GetScaleY();
1812 aFrac *= aDivFrac;
1813 rMapMode.SetScaleY(aFrac);
1814 nDivisor <<= 1;
1815 aSize = OutputDevice::LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
1818 return nDivisor;
1821 void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF )
1823 SvMemoryStream aStream;
1824 EMFWriter aEMFWriter(aStream);
1826 if( !aEMFWriter.WriteEMF( rMTF ) )
1827 return;
1829 sal_uInt64 const nTotalSize = aStream.Tell();
1830 if( nTotalSize > SAL_MAX_UINT32 )
1831 return;
1832 aStream.Seek( 0 );
1833 sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize );
1834 sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1;
1835 sal_uInt16 nCheckSum = 0, nWord;
1837 sal_uInt32 nPos = 0;
1839 while( nPos + 1 < nTotalSize )
1841 aStream.ReadUInt16( nWord );
1842 nCheckSum ^= nWord;
1843 nPos += 2;
1846 nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 );
1848 aStream.Seek( 0 );
1849 while( nRemainingSize > 0 )
1851 sal_uInt32 nCurSize;
1852 if( nRemainingSize > 0x2000 )
1854 nCurSize = 0x2000;
1855 nRemainingSize -= 0x2000;
1857 else
1859 nCurSize = nRemainingSize;
1860 nRemainingSize = 0;
1862 WriteEMFRecord( aStream,
1863 nCurSize,
1864 nRemainingSize,
1865 nTotalSize,
1866 nRecCounts,
1867 nCheckSum );
1868 nCheckSum = 0;
1873 void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize,
1874 sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum )
1876 // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx
1877 WriteRecordHeader( 0, W_META_ESCAPE );
1878 pWMF->WriteUInt16( W_MFCOMMENT ) // same as META_ESCAPE_ENHANCED_METAFILE
1879 .WriteUInt16( nCurSize + 34 ) // we will always have a 34 byte escape header:
1880 .WriteUInt32( 0x43464D57 ) // WMFC
1881 .WriteUInt32( 0x00000001 ) // Comment type
1882 .WriteUInt32( 0x00010000 ) // version
1883 .WriteUInt16( nCheckSum ) // check sum
1884 .WriteUInt32( 0 ) // flags = 0
1885 .WriteUInt32( nRecCounts ) // total number of records
1886 .WriteUInt32( nCurSize ) // size of this record's data
1887 .WriteUInt32( nRemainingSize ) // remaining size of data in following records, missing in MSDN documentation
1888 .WriteUInt32( nTotalSize ); // total size of EMF stream
1890 pWMF->WriteBytes(static_cast<const sal_Char*>(rStream.GetData()) + rStream.Tell(), nCurSize);
1891 rStream.SeekRel( nCurSize );
1892 UpdateRecordHeader();
1895 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */