build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / filter / wmf / wmfwr.cxx
blob969a6f74d5a07ec215ffa33f14e0a7a2813b5faa
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 <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 , bSrcIsClipping(false)
148 , pAttrStack(nullptr)
149 , eSrcHorTextAlign(W_TA_LEFT)
150 , eDstROP2(RasterOp::OverPaint)
151 , eDstTextAlign(ALIGN_BASELINE)
152 , eDstHorTextAlign(W_TA_LEFT)
153 , bDstIsClipping(false)
154 , bHandleAllocated{}
155 , nDstPenHandle(0)
156 , nDstFontHandle(0)
157 , nDstBrushHandle(0)
158 , nNumberOfActions(0)
159 , nNumberOfBitmaps(0)
160 , nWrittenActions(0)
161 , nWrittenBitmaps(0)
162 , nActBitmapPercent(0)
163 , bEmbedEMF(false)
167 void WMFWriter::MayCallback()
169 if ( xStatusIndicator.is() )
171 sal_uLong nPercent;
173 // we simply assume that 16386 actions match to a bitmap
174 // (normally a metafile either contains only actions or some bitmaps and
175 // almost no actions. In which case the ratio is less important)
177 nPercent=((nWrittenBitmaps<<14)+(nActBitmapPercent<<14)/100+nWrittenActions)
178 *100
179 /((nNumberOfBitmaps<<14)+nNumberOfActions);
181 if ( nPercent >= nLastPercent + 3 )
183 nLastPercent = nPercent;
184 if( nPercent <= 100 )
185 xStatusIndicator->setValue( nPercent );
190 void WMFWriter::CountActionsAndBitmaps( const GDIMetaFile & rMTF )
192 size_t nAction, nActionCount;
194 nActionCount = rMTF.GetActionSize();
196 for ( nAction=0; nAction < nActionCount; nAction++ )
198 MetaAction* pMA = rMTF.GetAction( nAction );
200 switch( pMA->GetType() )
202 case MetaActionType::BMP:
203 case MetaActionType::BMPSCALE:
204 case MetaActionType::BMPSCALEPART:
205 case MetaActionType::BMPEX:
206 case MetaActionType::BMPEXSCALE:
207 case MetaActionType::BMPEXSCALEPART:
208 nNumberOfBitmaps++;
209 break;
210 default: break;
212 nNumberOfActions++;
216 void WMFWriter::WritePointXY(const Point & rPoint)
218 Point aPt( OutputDevice::LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
219 pWMF->WriteInt16( aPt.X() ).WriteInt16( aPt.Y() );
222 void WMFWriter::WritePointYX(const Point & rPoint)
224 Point aPt( OutputDevice::LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) );
225 pWMF->WriteInt16( aPt.Y() ).WriteInt16( aPt.X() );
228 sal_Int32 WMFWriter::ScaleWidth( sal_Int32 nDX )
230 Size aSz( OutputDevice::LogicToLogic(Size(nDX,0),aSrcMapMode,aTargetMapMode) );
231 return aSz.Width();
234 void WMFWriter::WriteSize(const Size & rSize)
236 Size aSz( OutputDevice::LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
237 pWMF->WriteInt16( aSz.Width() ).WriteInt16( aSz.Height() );
240 void WMFWriter::WriteHeightWidth(const Size & rSize)
242 Size aSz( OutputDevice::LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) );
243 pWMF->WriteInt16( aSz.Height() ).WriteInt16( aSz.Width() );
246 void WMFWriter::WriteRectangle(const Rectangle & rRect)
248 WritePointYX(Point(rRect.Right()+1,rRect.Bottom()+1));
249 WritePointYX(rRect.TopLeft());
252 void WMFWriter::WriteColor(const Color & rColor)
254 pWMF->WriteUChar( rColor.GetRed() ).WriteUChar( rColor.GetGreen() ).WriteUChar( rColor.GetBlue() ).WriteUChar( 0 );
257 void WMFWriter::WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType)
259 nActRecordPos=pWMF->Tell();
260 if (nSizeWords>nMaxRecordSize) nMaxRecordSize=nSizeWords;
261 pWMF->WriteUInt32( nSizeWords ).WriteUInt16( nType );
264 void WMFWriter::UpdateRecordHeader()
266 sal_uLong nPos;
267 sal_uInt32 nSize;
269 nPos=pWMF->Tell(); nSize=nPos-nActRecordPos;
270 if ((nSize & 1)!=0) {
271 pWMF->WriteUChar( 0 );
272 nPos++; nSize++;
274 nSize/=2;
275 if (nSize>nMaxRecordSize) nMaxRecordSize=nSize;
276 pWMF->Seek(nActRecordPos);
277 pWMF->WriteUInt32( nSize );
278 pWMF->Seek(nPos);
281 void WMFWriter::WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
283 WriteRecordHeader(0x0000000b,W_META_ARC);
284 WritePointYX(rEndPt);
285 WritePointYX(rStartPt);
286 WriteRectangle(rRect);
289 void WMFWriter::WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
291 WriteRecordHeader(0x0000000b,W_META_CHORD);
292 WritePointYX(rEndPt);
293 WritePointYX(rStartPt);
294 WriteRectangle(rRect);
297 void WMFWriter::WMFRecord_CreateBrushIndirect(const Color& rColor)
299 WriteRecordHeader(0x00000007,W_META_CREATEBRUSHINDIRECT);
301 if( rColor==Color(COL_TRANSPARENT) )
302 pWMF->WriteUInt16( W_BS_HOLLOW );
303 else
304 pWMF->WriteUInt16( W_BS_SOLID );
306 WriteColor( rColor );
307 pWMF->WriteUInt16( 0 );
310 void WMFWriter::WMFRecord_CreateFontIndirect(const vcl::Font & rFont)
312 sal_uInt16 nWeight,i;
313 sal_uInt8 nPitchFamily;
315 WriteRecordHeader(0x00000000,W_META_CREATEFONTINDIRECT);
316 WriteHeightWidth(Size(rFont.GetFontSize().Width(),-rFont.GetFontSize().Height()));
317 pWMF->WriteInt16( rFont.GetOrientation() ).WriteInt16( rFont.GetOrientation() );
319 switch (rFont.GetWeight()) {
320 case WEIGHT_THIN: nWeight=W_FW_THIN; break;
321 case WEIGHT_ULTRALIGHT: nWeight=W_FW_ULTRALIGHT; break;
322 case WEIGHT_LIGHT: nWeight=W_FW_LIGHT; break;
323 case WEIGHT_SEMILIGHT: nWeight=W_FW_LIGHT; break;
324 case WEIGHT_NORMAL: nWeight=W_FW_NORMAL; break;
325 case WEIGHT_MEDIUM: nWeight=W_FW_MEDIUM; break;
326 case WEIGHT_SEMIBOLD: nWeight=W_FW_SEMIBOLD; break;
327 case WEIGHT_BOLD: nWeight=W_FW_BOLD; break;
328 case WEIGHT_ULTRABOLD: nWeight=W_FW_ULTRABOLD; break;
329 case WEIGHT_BLACK: nWeight=W_FW_BLACK; break;
330 default: nWeight=W_FW_DONTCARE;
332 pWMF->WriteUInt16( nWeight );
334 if (rFont.GetItalic()==ITALIC_NONE) pWMF->WriteUChar( 0 ); else pWMF->WriteUChar( 1 );
335 if (rFont.GetUnderline()==LINESTYLE_NONE) pWMF->WriteUChar( 0 ); else pWMF->WriteUChar( 1 );
336 if (rFont.GetStrikeout()==STRIKEOUT_NONE) pWMF->WriteUChar( 0 ); else pWMF->WriteUChar( 1 );
338 rtl_TextEncoding eFontNameEncoding = rFont.GetCharSet();
339 sal_uInt8 nCharSet = rtl_getBestWindowsCharsetFromTextEncoding( eFontNameEncoding );
340 if ( eFontNameEncoding == RTL_TEXTENCODING_SYMBOL )
341 eFontNameEncoding = RTL_TEXTENCODING_MS_1252;
342 if ( nCharSet == 1 )
343 nCharSet = W_ANSI_CHARSET;
344 pWMF->WriteUChar( nCharSet );
346 pWMF->WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
348 switch (rFont.GetPitch()) {
349 case PITCH_FIXED: nPitchFamily=W_FIXED_PITCH; break;
350 case PITCH_VARIABLE: nPitchFamily=W_VARIABLE_PITCH; break;
351 default: nPitchFamily=W_DEFAULT_PITCH;
353 switch (rFont.GetFamilyType()) {
354 case FAMILY_DECORATIVE: nPitchFamily|=W_FF_DECORATIVE; break;
355 case FAMILY_MODERN: nPitchFamily|=W_FF_MODERN; break;
356 case FAMILY_ROMAN: nPitchFamily|=W_FF_ROMAN; break;
357 case FAMILY_SCRIPT: nPitchFamily|=W_FF_SCRIPT; break;
358 case FAMILY_SWISS: nPitchFamily|=W_FF_SWISS; break;
359 default: nPitchFamily|=W_FF_DONTCARE;
361 pWMF->WriteUChar( nPitchFamily );
363 OString aFontName(OUStringToOString(rFont.GetFamilyName(), eFontNameEncoding));
364 for ( i = 0; i < W_LF_FACESIZE; i++ )
366 sal_Char nChar = ( i < aFontName.getLength() ) ? aFontName[i] : 0;
367 pWMF->WriteChar( nChar );
369 UpdateRecordHeader();
372 void WMFWriter::WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo )
374 WriteRecordHeader(0x00000008,W_META_CREATEPENINDIRECT);
375 sal_uInt16 nStyle = rColor == Color( COL_TRANSPARENT ) ? W_PS_NULL : W_PS_SOLID;
376 switch( rLineInfo.GetStyle() )
378 case LineStyle::Dash :
380 if ( rLineInfo.GetDotCount() )
382 if ( !rLineInfo.GetDashCount() )
383 nStyle = W_PS_DOT;
384 else
386 if ( rLineInfo.GetDotCount() == 1 )
387 nStyle = W_PS_DASHDOT;
388 else
389 nStyle = W_PS_DASHDOTDOT;
392 else
393 nStyle = W_PS_DASH;
395 break;
396 case LineStyle::NONE :
397 nStyle = W_PS_NULL;
398 break;
399 default:
400 break;
402 pWMF->WriteUInt16( nStyle );
404 WriteSize( Size( rLineInfo.GetWidth(), 0 ) );
405 WriteColor( rColor );
408 void WMFWriter::WMFRecord_DeleteObject(sal_uInt16 nObjectHandle)
410 WriteRecordHeader(0x00000004,W_META_DELETEOBJECT);
411 pWMF->WriteUInt16( nObjectHandle );
414 void WMFWriter::WMFRecord_Ellipse(const Rectangle & rRect)
416 WriteRecordHeader(0x00000007,W_META_ELLIPSE);
417 WriteRectangle(rRect);
420 void WMFWriter::WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData )
422 #ifdef OSL_BIGENDIAN
423 sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc );
424 sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
425 #else
426 sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
427 #endif
428 if ( nLen )
429 nCheckSum = rtl_crc32( nCheckSum, pData, nLen );
431 WriteRecordHeader( 3 + 9 + ( ( nLen + 1 ) >> 1 ), W_META_ESCAPE );
432 pWMF->WriteUInt16( W_MFCOMMENT )
433 .WriteUInt16( nLen + 14 ) // we will always have a fourteen byte escape header:
434 .WriteUInt16( 0x4f4f ) // OO
435 .WriteUInt32( 0xa2c2a ) // evil magic number
436 .WriteUInt32( nCheckSum ) // crc32 checksum about nEsc & pData
437 .WriteUInt32( nEsc ); // escape number
438 pWMF->WriteBytes( pData, nLen );
439 if ( nLen & 1 )
440 pWMF->WriteUChar( 0 ); // pad byte
443 /* if return value is true, then a complete unicode string and also a polygon replacement has been written,
444 so there is no more action necessary
446 bool WMFWriter::WMFRecord_Escape_Unicode( const Point& rPoint, const OUString& rUniStr, const long* pDXAry )
448 bool bEscapeUsed = false;
450 sal_uInt32 i, nStringLen = rUniStr.getLength();
451 if ( nStringLen )
453 // first we will check if a comment is necessary
454 if ( aSrcFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) // symbol is always byte character, so there is no unicode loss
456 const sal_Unicode* pBuf = rUniStr.getStr();
457 const rtl_TextEncoding aTextEncodingOrg = aSrcFont.GetCharSet();
458 OString aByteStr(OUStringToOString(rUniStr, aTextEncodingOrg));
459 OUString aUniStr2(OStringToOUString(aByteStr, aTextEncodingOrg));
460 const sal_Unicode* pConversion = aUniStr2.getStr(); // this is the unicode array after bytestring <-> unistring conversion
461 for ( i = 0; i < nStringLen; i++ )
463 if ( *pBuf++ != *pConversion++ )
464 break;
467 if ( i != nStringLen ) // after conversion the characters are not original,
468 { // try again, with determining a better charset from unicode char
469 pBuf = rUniStr.getStr();
470 const sal_Unicode* pCheckChar = pBuf;
471 rtl_TextEncoding aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the first character
472 for ( i = 1; i < nStringLen; i++)
474 if (aTextEncoding != aTextEncodingOrg) // found something
475 break;
476 pCheckChar++;
477 aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the next character
480 aByteStr = OUStringToOString(rUniStr, aTextEncoding);
481 aUniStr2 = OStringToOUString(aByteStr, aTextEncoding);
482 pConversion = aUniStr2.getStr(); // this is the unicode array after bytestring <-> unistring conversion
483 for ( i = 0; i < nStringLen; i++ )
485 if ( *pBuf++ != *pConversion++ )
486 break;
488 if (i == nStringLen)
490 aSrcFont.SetCharSet (aTextEncoding);
491 SetAllAttr();
495 if ( ( i != nStringLen ) || IsStarSymbol( aSrcFont.GetFamilyName() ) ) // after conversion the characters are not original, so we
496 { // will store the unicode string and a polypoly replacement
497 Color aOldFillColor( aSrcFillColor );
498 Color aOldLineColor( aSrcLineColor );
499 aSrcLineInfo = LineInfo();
500 aSrcFillColor = aSrcTextColor;
501 aSrcLineColor = Color( COL_TRANSPARENT );
502 SetLineAndFillAttr();
503 pVirDev->SetFont( aSrcFont );
504 std::vector<tools::PolyPolygon> aPolyPolyVec;
505 if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniStr ) )
507 sal_uInt32 nDXCount = pDXAry ? nStringLen : 0;
508 sal_uInt32 nSkipActions = aPolyPolyVec.size();
509 sal_Int32 nStrmLen = 8 +
510 + sizeof( nStringLen ) + ( nStringLen * 2 )
511 + sizeof( nDXCount ) + ( nDXCount * 4 )
512 + sizeof( nSkipActions );
514 SvMemoryStream aMemoryStream( nStrmLen );
515 Point aPt( OutputDevice::LogicToLogic( rPoint, aSrcMapMode, aTargetMapMode ) );
516 aMemoryStream.WriteInt32( aPt.X() )
517 .WriteInt32( aPt.Y() )
518 .WriteUInt32( nStringLen );
519 for ( i = 0; i < nStringLen; i++ )
520 aMemoryStream.WriteUInt16( rUniStr[ i ] );
521 aMemoryStream.WriteUInt32( nDXCount );
522 for ( i = 0; i < nDXCount; i++ )
523 aMemoryStream.WriteInt32( pDXAry[ i ] );
524 aMemoryStream.WriteUInt32( nSkipActions );
525 WMFRecord_Escape( PRIVATE_ESCAPE_UNICODE, nStrmLen, static_cast<const sal_Int8*>(aMemoryStream.GetData()) );
527 std::vector<tools::PolyPolygon>::iterator aIter( aPolyPolyVec.begin() );
528 while ( aIter != aPolyPolyVec.end() )
530 tools::PolyPolygon aPolyPoly( *aIter++ );
531 aPolyPoly.Move( rPoint.X(), rPoint.Y() );
532 WMFRecord_PolyPolygon( aPolyPoly );
534 aSrcFillColor = aOldFillColor;
535 aSrcLineColor = aOldLineColor;
536 bEscapeUsed = true;
541 return bEscapeUsed;
544 void WMFWriter::WMFRecord_ExtTextOut( const Point& rPoint,
545 const OUString& rString,
546 const long* pDXAry )
548 sal_Int32 nOriginalTextLen = rString.getLength();
550 if ( (nOriginalTextLen <= 1) || (pDXAry == nullptr) )
552 WMFRecord_TextOut(rPoint, rString);
553 return;
555 rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
556 OString aByteString(OUStringToOString(rString, eChrSet));
557 TrueExtTextOut(rPoint, rString, aByteString, pDXAry);
560 void WMFWriter::TrueExtTextOut( const Point& rPoint, const OUString& rString,
561 const OString& rByteString, const long* pDXAry )
563 WriteRecordHeader( 0, W_META_EXTTEXTOUT );
564 WritePointYX( rPoint );
565 sal_uInt16 nNewTextLen = static_cast<sal_uInt16>(rByteString.getLength());
566 pWMF->WriteUInt16( nNewTextLen ).WriteUInt16( 0 );
567 write_uInt8s_FromOString(*pWMF, rByteString, nNewTextLen);
568 if ( nNewTextLen & 1 )
569 pWMF->WriteUChar( 0 );
571 sal_Int32 nOriginalTextLen = rString.getLength();
572 std::unique_ptr<sal_Int16[]> pConvertedDXAry(new sal_Int16[ nOriginalTextLen ]);
573 sal_Int32 j = 0;
574 pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ 0 ] );
575 for (sal_Int32 i = 1; i < ( nOriginalTextLen - 1 ); ++i)
576 pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ i ] - pDXAry[ i - 1 ] );
577 pConvertedDXAry[ j ] = (sal_Int16)ScaleWidth( pDXAry[ nOriginalTextLen - 2 ] / ( nOriginalTextLen - 1 ) );
579 for (sal_Int32 i = 0; i < nOriginalTextLen; ++i)
581 sal_Int16 nDx = pConvertedDXAry[ i ];
582 pWMF->WriteInt16( nDx );
583 if ( nOriginalTextLen < nNewTextLen )
585 sal_Unicode nUniChar = rString[i];
586 OString aTemp(&nUniChar, 1, aSrcFont.GetCharSet());
587 j = aTemp.getLength();
588 while ( --j > 0 )
589 pWMF->WriteUInt16( 0 );
592 pConvertedDXAry.reset();
593 UpdateRecordHeader();
596 void WMFWriter::WMFRecord_LineTo(const Point & rPoint)
598 WriteRecordHeader(0x00000005,W_META_LINETO);
599 WritePointYX(rPoint);
602 void WMFWriter::WMFRecord_MoveTo(const Point & rPoint)
604 WriteRecordHeader(0x00000005,W_META_MOVETO);
605 WritePointYX(rPoint);
608 void WMFWriter::WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt)
610 WriteRecordHeader(0x0000000b,W_META_PIE);
611 WritePointYX(rEndPt);
612 WritePointYX(rStartPt);
613 WriteRectangle(rRect);
616 void WMFWriter::WMFRecord_Polygon(const tools::Polygon & rPoly)
618 tools::Polygon aSimplePoly;
619 if ( rPoly.HasFlags() )
620 rPoly.AdaptiveSubdivide( aSimplePoly );
621 else
622 aSimplePoly = rPoly;
623 const sal_uInt16 nSize = aSimplePoly.GetSize();
624 WriteRecordHeader(static_cast<sal_uInt32>(nSize)*2+4,W_META_POLYGON);
625 pWMF->WriteUInt16( nSize );
626 for (sal_uInt16 i=0; i<nSize; ++i)
627 WritePointXY(aSimplePoly.GetPoint(i));
630 void WMFWriter::WMFRecord_PolyLine(const tools::Polygon & rPoly)
632 tools::Polygon aSimplePoly;
633 if ( rPoly.HasFlags() )
634 rPoly.AdaptiveSubdivide( aSimplePoly );
635 else
636 aSimplePoly = rPoly;
637 const sal_uInt16 nSize = aSimplePoly.GetSize();
638 WriteRecordHeader(static_cast<sal_uInt32>(nSize)*2+4,W_META_POLYLINE);
639 pWMF->WriteUInt16( nSize );
640 for (sal_uInt16 i=0; i<nSize; ++i)
641 WritePointXY(aSimplePoly.GetPoint(i));
644 void WMFWriter::WMFRecord_PolyPolygon(const tools::PolyPolygon & rPolyPoly)
646 const tools::Polygon * pPoly;
647 sal_uInt16 nCount,nSize,i,j;
649 nCount=rPolyPoly.Count();
650 tools::PolyPolygon aSimplePolyPoly( rPolyPoly );
651 for ( i = 0; i < nCount; i++ )
653 if ( aSimplePolyPoly[ i ].HasFlags() )
655 tools::Polygon aSimplePoly;
656 aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly );
657 aSimplePolyPoly[ i ] = aSimplePoly;
660 WriteRecordHeader(0,W_META_POLYPOLYGON);
661 pWMF->WriteUInt16( nCount );
662 for (i=0; i<nCount; i++) pWMF->WriteUInt16( (aSimplePolyPoly.GetObject(i).GetSize()) );
663 for (i=0; i<nCount; i++) {
664 pPoly=&(aSimplePolyPoly.GetObject(i));
665 nSize=pPoly->GetSize();
666 for (j=0; j<nSize; j++) WritePointXY(pPoly->GetPoint(j));
668 UpdateRecordHeader();
671 void WMFWriter::WMFRecord_Rectangle(const Rectangle & rRect)
673 WriteRecordHeader( 0x00000007,W_META_RECTANGLE );
674 WriteRectangle( rRect );
677 void WMFWriter::WMFRecord_RestoreDC()
679 WriteRecordHeader(0x00000004,W_META_RESTOREDC);
680 pWMF->WriteInt16( -1 );
683 void WMFWriter::WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound)
685 WriteRecordHeader(0x00000009,W_META_ROUNDRECT);
686 WriteHeightWidth(Size(nHorzRound,nVertRound));
687 WriteRectangle(rRect);
690 void WMFWriter::WMFRecord_SaveDC()
692 WriteRecordHeader(0x00000003,W_META_SAVEDC);
695 void WMFWriter::WMFRecord_SelectObject(sal_uInt16 nObjectHandle)
697 WriteRecordHeader(0x00000004,W_META_SELECTOBJECT);
698 pWMF->WriteUInt16( nObjectHandle );
701 void WMFWriter::WMFRecord_SetBkMode(bool bTransparent)
703 WriteRecordHeader(0x00000004,W_META_SETBKMODE);
704 if (bTransparent) pWMF->WriteUInt16( W_TRANSPARENT );
705 else pWMF->WriteUInt16( W_OPAQUE );
708 void WMFWriter::WMFRecord_SetStretchBltMode()
710 WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE );
711 pWMF->WriteUInt16( 3 ); // STRETCH_DELETESCANS
714 void WMFWriter::WMFRecord_SetPixel(const Point & rPoint, const Color & rColor)
716 WriteRecordHeader(0x00000007,W_META_SETPIXEL);
717 WriteColor(rColor);
718 WritePointYX(rPoint);
721 void WMFWriter::WMFRecord_SetROP2(RasterOp eROP)
723 sal_uInt16 nROP2;
725 switch (eROP) {
726 case RasterOp::Invert: nROP2=W_R2_NOT; break;
727 case RasterOp::Xor: nROP2=W_R2_XORPEN; break;
728 default: nROP2=W_R2_COPYPEN;
730 WriteRecordHeader(0x00000004,W_META_SETROP2);
731 pWMF->WriteUInt16( nROP2 );
734 void WMFWriter::WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_uInt16 eHorTextAlign)
736 sal_uInt16 nAlign;
738 switch (eFontAlign) {
739 case ALIGN_TOP: nAlign=W_TA_TOP; break;
740 case ALIGN_BOTTOM: nAlign=W_TA_BOTTOM; break;
741 default: nAlign=W_TA_BASELINE;
743 nAlign|=eHorTextAlign;
744 nAlign|=W_TA_NOUPDATECP;
746 WriteRecordHeader(0x00000004,W_META_SETTEXTALIGN);
747 pWMF->WriteUInt16( nAlign );
750 void WMFWriter::WMFRecord_SetTextColor(const Color & rColor)
752 WriteRecordHeader(0x00000005,W_META_SETTEXTCOLOR);
753 WriteColor(rColor);
756 void WMFWriter::WMFRecord_SetWindowExt(const Size & rSize)
758 WriteRecordHeader(0x00000005,W_META_SETWINDOWEXT);
759 WriteHeightWidth(rSize);
762 void WMFWriter::WMFRecord_SetWindowOrg(const Point & rPoint)
764 WriteRecordHeader(0x00000005,W_META_SETWINDOWORG);
765 WritePointYX(rPoint);
768 void WMFWriter::WMFRecord_StretchDIB( const Point & rPoint, const Size & rSize,
769 const Bitmap & rBitmap, sal_uInt32 nROP )
771 sal_uLong nPosAnf,nPosEnd;
773 nActBitmapPercent=50;
774 MayCallback();
776 WriteRecordHeader(0x00000000,W_META_STRETCHDIB);
778 // The sequence in the metafile should be:
779 // some parameters (length 22), then the bitmap without FILEHEADER.
780 // As *pWMF << rBitmap generates a FILEHEADER of size 14,
781 // we first write the bitmap at the right position
782 // and overwrite later the FILEHEADER with the parameters.
783 nPosAnf=pWMF->Tell(); // remember position, where parameters should be stored
784 pWMF->WriteInt32( 0 ).WriteInt32( 0 ); // replenish 8 bytes (these 8 bytes +
785 // 14 bytes superfluous FILEHEADER
786 // = 22 bytes parameter)
788 // write bitmap
789 WriteDIB(rBitmap, *pWMF, false, true);
791 // write the parameters:
792 nPosEnd=pWMF->Tell();
793 pWMF->Seek(nPosAnf);
795 // determine raster-op, if nothing was passed
796 if( !nROP )
798 switch( eSrcRasterOp )
800 case RasterOp::Invert: nROP = W_DSTINVERT; break;
801 case RasterOp::Xor: nROP = W_SRCINVERT; break;
802 default: nROP = W_SRCCOPY;
806 pWMF->WriteUInt32( nROP ).
807 WriteInt16( 0 ).
808 WriteInt16( rBitmap.GetSizePixel().Height() ).
809 WriteInt16( rBitmap.GetSizePixel().Width() ).
810 WriteInt16( 0 ).
811 WriteInt16( 0 );
813 WriteHeightWidth(rSize);
814 WritePointYX(rPoint);
815 pWMF->Seek(nPosEnd);
817 UpdateRecordHeader();
819 nWrittenBitmaps++;
820 nActBitmapPercent=0;
823 void WMFWriter::WMFRecord_TextOut(const Point & rPoint, const OUString & rStr)
825 rtl_TextEncoding eChrSet = aSrcFont.GetCharSet();
826 OString aString(OUStringToOString(rStr, eChrSet));
827 TrueTextOut(rPoint, aString);
830 void WMFWriter::TrueTextOut(const Point & rPoint, const OString& rString)
832 WriteRecordHeader(0,W_META_TEXTOUT);
834 write_uInt16_lenPrefixed_uInt8s_FromOString(*pWMF, rString);
835 sal_Int32 nLen = rString.getLength();
836 if ((nLen&1)!=0) pWMF->WriteUChar( 0 );
837 WritePointYX(rPoint);
838 UpdateRecordHeader();
841 void WMFWriter::WMFRecord_IntersectClipRect( const Rectangle& rRect )
843 WriteRecordHeader( 0x00000007, W_META_INTERSECTCLIPRECT );
844 WriteRectangle(rRect);
847 sal_uInt16 WMFWriter::AllocHandle()
849 sal_uInt16 i;
851 for (i=0; i<MAXOBJECTHANDLES; i++) {
852 if (!bHandleAllocated[i]) {
853 bHandleAllocated[i]=true;
854 return i;
857 bStatus=false;
858 return 0xffff;
861 void WMFWriter::FreeHandle(sal_uInt16 nObjectHandle)
863 if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=false;
866 void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo )
868 sal_uInt16 nOldHandle;
870 nOldHandle=nDstPenHandle;
871 nDstPenHandle=AllocHandle();
872 WMFRecord_CreatePenIndirect( rColor, rLineInfo );
873 WMFRecord_SelectObject(nDstPenHandle);
874 if (nOldHandle<MAXOBJECTHANDLES) {
875 WMFRecord_DeleteObject(nOldHandle);
876 FreeHandle(nOldHandle);
880 void WMFWriter::CreateSelectDeleteFont(const vcl::Font & rFont)
882 sal_uInt16 nOldHandle;
884 nOldHandle=nDstFontHandle;
885 nDstFontHandle=AllocHandle();
886 WMFRecord_CreateFontIndirect(rFont);
887 WMFRecord_SelectObject(nDstFontHandle);
888 if (nOldHandle<MAXOBJECTHANDLES) {
889 WMFRecord_DeleteObject(nOldHandle);
890 FreeHandle(nOldHandle);
894 void WMFWriter::CreateSelectDeleteBrush(const Color& rColor)
896 sal_uInt16 nOldHandle;
898 nOldHandle=nDstBrushHandle;
899 nDstBrushHandle=AllocHandle();
900 WMFRecord_CreateBrushIndirect(rColor);
901 WMFRecord_SelectObject(nDstBrushHandle);
902 if (nOldHandle<MAXOBJECTHANDLES) {
903 WMFRecord_DeleteObject(nOldHandle);
904 FreeHandle(nOldHandle);
908 void WMFWriter::SetLineAndFillAttr()
910 if ( eDstROP2 != eSrcRasterOp )
912 eDstROP2=eSrcRasterOp;
913 WMFRecord_SetROP2(eDstROP2);
915 if ( ( aDstLineColor != aSrcLineColor ) || ( aDstLineInfo != aSrcLineInfo ) )
917 aDstLineColor = aSrcLineColor;
918 aDstLineInfo = aSrcLineInfo;
919 CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
921 if ( aDstFillColor != aSrcFillColor )
923 aDstFillColor = aSrcFillColor;
924 CreateSelectDeleteBrush( aDstFillColor );
926 if ( bDstIsClipping != bSrcIsClipping ||
927 (bSrcIsClipping && aDstClipRegion!=aSrcClipRegion)) {
928 bDstIsClipping=bSrcIsClipping;
929 aDstClipRegion=aSrcClipRegion;
933 void WMFWriter::SetAllAttr()
935 SetLineAndFillAttr();
936 if ( aDstTextColor != aSrcTextColor )
938 aDstTextColor = aSrcTextColor;
939 WMFRecord_SetTextColor(aDstTextColor);
941 if ( eDstTextAlign != eSrcTextAlign || eDstHorTextAlign != eSrcHorTextAlign )
943 eDstTextAlign = eSrcTextAlign;
944 eDstHorTextAlign = eSrcHorTextAlign;
945 WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
947 if ( aDstFont != aSrcFont )
949 pVirDev->SetFont(aSrcFont);
950 if ( aDstFont.GetFamilyName() != aSrcFont.GetFamilyName() )
952 FontCharMapRef xFontCharMap;
953 if ( pVirDev->GetFontCharMap( xFontCharMap ) )
955 if ( ( xFontCharMap->GetFirstChar() & 0xff00 ) == 0xf000 )
956 aSrcFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
957 else if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
958 aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
962 aDstFont = aSrcFont;
963 CreateSelectDeleteFont(aDstFont);
967 void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
969 if(rLinePolygon.count())
971 basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
972 basegfx::B2DPolyPolygon aFillPolyPolygon;
974 rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
976 if(aLinePolyPolygon.count())
978 aSrcLineInfo = rInfo;
979 SetLineAndFillAttr();
981 for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
983 const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
984 WMFRecord_PolyLine( tools::Polygon(aCandidate) );
988 if(aFillPolyPolygon.count())
990 const Color aOldLineColor(aSrcLineColor);
991 const Color aOldFillColor(aSrcFillColor);
993 aSrcLineColor = Color( COL_TRANSPARENT );
994 aSrcFillColor = aOldLineColor;
995 SetLineAndFillAttr();
997 for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
999 const tools::Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
1000 WMFRecord_Polygon( tools::Polygon(aPolygon) );
1003 aSrcLineColor = aOldLineColor;
1004 aSrcFillColor = aOldFillColor;
1005 SetLineAndFillAttr();
1010 void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
1012 if( bStatus )
1014 size_t nACount = rMTF.GetActionSize();
1016 WMFRecord_SetStretchBltMode();
1018 for( size_t nA = 0; nA < nACount; nA++ )
1020 MetaAction* pMA = rMTF.GetAction( nA );
1022 switch( pMA->GetType() )
1024 case MetaActionType::PIXEL:
1026 const MetaPixelAction* pA = static_cast<const MetaPixelAction *>(pMA);
1027 aSrcLineInfo = LineInfo();
1028 SetLineAndFillAttr();
1029 WMFRecord_SetPixel( pA->GetPoint(), pA->GetColor() );
1031 break;
1033 case MetaActionType::POINT:
1035 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pMA);
1036 const Point& rPt = pA->GetPoint();
1037 aSrcLineInfo = LineInfo();
1038 SetLineAndFillAttr();
1039 WMFRecord_MoveTo( rPt);
1040 WMFRecord_LineTo( rPt );
1042 break;
1044 case MetaActionType::LINE:
1046 const MetaLineAction* pA = static_cast<const MetaLineAction *>(pMA);
1047 if(pA->GetLineInfo().IsDefault())
1049 aSrcLineInfo = pA->GetLineInfo();
1050 SetLineAndFillAttr();
1051 WMFRecord_MoveTo( pA->GetStartPoint() );
1052 WMFRecord_LineTo( pA->GetEndPoint() );
1054 else
1056 // LineInfo used; handle Dash/Dot and fat lines
1057 basegfx::B2DPolygon aPolygon;
1058 aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1059 aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1060 HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
1063 break;
1065 case MetaActionType::RECT:
1067 const MetaRectAction* pA = static_cast<const MetaRectAction*>(pMA);
1068 aSrcLineInfo = LineInfo();
1069 SetLineAndFillAttr();
1070 WMFRecord_Rectangle( pA->GetRect() );
1072 break;
1074 case MetaActionType::ROUNDRECT:
1076 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pMA);
1077 aSrcLineInfo = LineInfo();
1078 SetLineAndFillAttr();
1079 WMFRecord_RoundRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
1081 break;
1083 case MetaActionType::ELLIPSE:
1085 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pMA);
1086 aSrcLineInfo = LineInfo();
1087 SetLineAndFillAttr();
1088 WMFRecord_Ellipse( pA->GetRect() );
1090 break;
1092 case MetaActionType::ARC:
1094 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pMA);
1095 aSrcLineInfo = LineInfo();
1096 SetLineAndFillAttr();
1097 WMFRecord_Arc( pA->GetRect(),pA->GetStartPoint(),pA->GetEndPoint() );
1099 break;
1101 case MetaActionType::PIE:
1103 const MetaPieAction* pA = static_cast<const MetaPieAction*>(pMA);
1104 aSrcLineInfo = LineInfo();
1105 SetLineAndFillAttr();
1106 WMFRecord_Pie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1108 break;
1110 case MetaActionType::CHORD:
1112 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pMA);
1113 aSrcLineInfo = LineInfo();
1114 SetLineAndFillAttr();
1115 WMFRecord_Chord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
1117 break;
1119 case MetaActionType::POLYLINE:
1121 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pMA);
1122 const tools::Polygon& rPoly = pA->GetPolygon();
1124 if( rPoly.GetSize() )
1126 if(pA->GetLineInfo().IsDefault())
1128 aSrcLineInfo = pA->GetLineInfo();
1129 SetLineAndFillAttr();
1130 WMFRecord_PolyLine( rPoly );
1132 else
1134 // LineInfo used; handle Dash/Dot and fat lines
1135 HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1139 break;
1141 case MetaActionType::POLYGON:
1143 const MetaPolygonAction* pA = static_cast<const MetaPolygonAction*>(pMA);
1144 aSrcLineInfo = LineInfo();
1145 SetLineAndFillAttr();
1146 WMFRecord_Polygon( pA->GetPolygon() );
1148 break;
1150 case MetaActionType::POLYPOLYGON:
1152 const MetaPolyPolygonAction* pA = static_cast<const MetaPolyPolygonAction*>(pMA);
1153 aSrcLineInfo = LineInfo();
1154 SetLineAndFillAttr();
1155 WMFRecord_PolyPolygon( pA->GetPolyPolygon() );
1157 break;
1159 case MetaActionType::TEXTRECT:
1161 const MetaTextRectAction * pA = static_cast<const MetaTextRectAction*>(pMA);
1162 OUString aTemp( pA->GetText() );
1163 aSrcLineInfo = LineInfo();
1164 SetAllAttr();
1166 Point aPos( pA->GetRect().TopLeft() );
1167 if ( !WMFRecord_Escape_Unicode( aPos, aTemp, nullptr ) )
1168 WMFRecord_TextOut( aPos, aTemp );
1170 break;
1172 case MetaActionType::TEXT:
1174 const MetaTextAction * pA = static_cast<const MetaTextAction*>(pMA);
1175 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1176 aSrcLineInfo = LineInfo();
1177 SetAllAttr();
1178 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, nullptr ) )
1179 WMFRecord_TextOut( pA->GetPoint(), aTemp );
1181 break;
1183 case MetaActionType::TEXTARRAY:
1185 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pMA);
1187 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1188 aSrcLineInfo = LineInfo();
1189 SetAllAttr();
1190 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pA->GetDXArray() ) )
1191 WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pA->GetDXArray() );
1193 break;
1195 case MetaActionType::STRETCHTEXT:
1197 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction *>(pMA);
1198 OUString aTemp = pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1200 pVirDev->SetFont( aSrcFont );
1201 const sal_Int32 nLen = aTemp.getLength();
1202 std::unique_ptr<long[]> pDXAry(nLen ? new long[ nLen ] : nullptr);
1203 const sal_Int32 nNormSize = pVirDev->GetTextArray( aTemp, pDXAry.get() );
1204 if (nLen && nNormSize == 0)
1206 OSL_FAIL("Impossible div by 0 action: MetaStretchTextAction!");
1208 else
1210 for ( sal_Int32 i = 0; i < ( nLen - 1 ); i++ )
1211 pDXAry[ i ] = pDXAry[ i ] * (sal_Int32)pA->GetWidth() / nNormSize;
1212 if ( ( nLen <= 1 ) || ( (sal_Int32)pA->GetWidth() == nNormSize ) )
1213 pDXAry.reset();
1214 aSrcLineInfo = LineInfo();
1215 SetAllAttr();
1216 if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pDXAry.get() ) )
1217 WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pDXAry.get() );
1220 break;
1222 case MetaActionType::BMP:
1224 const MetaBmpAction* pA = static_cast<const MetaBmpAction *>(pMA);
1225 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetBitmap().GetSizePixel(), pA->GetBitmap() );
1227 break;
1229 case MetaActionType::BMPSCALE:
1231 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pMA);
1232 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pA->GetBitmap() );
1234 break;
1236 case MetaActionType::BMPSCALEPART:
1238 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pMA);
1239 Bitmap aTmp( pA->GetBitmap() );
1241 if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1242 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aTmp );
1244 break;
1246 case MetaActionType::BMPEX:
1248 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction *>(pMA);
1249 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1250 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1252 if( !!aMsk )
1254 aBmp.Replace( aMsk, COL_WHITE );
1255 aMsk.Invert();
1256 WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT );
1257 WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND );
1259 else
1260 WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp );
1262 break;
1264 case MetaActionType::BMPEXSCALE:
1266 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pMA);
1267 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1268 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1270 if( !!aMsk )
1272 aBmp.Replace( aMsk, COL_WHITE );
1273 aMsk.Invert();
1274 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT );
1275 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND );
1277 else
1278 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp );
1280 break;
1282 case MetaActionType::BMPEXSCALEPART:
1284 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pMA);
1285 BitmapEx aBmpEx( pA->GetBitmapEx() );
1286 aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1287 Bitmap aBmp( aBmpEx.GetBitmap() );
1288 Bitmap aMsk( aBmpEx.GetMask() );
1290 if( !!aMsk )
1292 aBmp.Replace( aMsk, COL_WHITE );
1293 aMsk.Invert();
1294 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT );
1295 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND );
1297 else
1298 WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp );
1300 break;
1302 case MetaActionType::GRADIENT:
1304 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pMA);
1305 GDIMetaFile aTmpMtf;
1307 pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1308 WriteRecords( aTmpMtf );
1310 break;
1312 case MetaActionType::HATCH:
1314 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pMA);
1315 GDIMetaFile aTmpMtf;
1317 pVirDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1318 WriteRecords( aTmpMtf );
1320 break;
1322 case MetaActionType::WALLPAPER:
1324 const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pMA);
1325 const Color& rColor = pA->GetWallpaper().GetColor();
1326 const Color aOldLineColor( aSrcLineColor );
1327 const Color aOldFillColor( aSrcFillColor );
1329 aSrcLineColor = rColor;
1330 aSrcFillColor = rColor;
1331 aSrcLineInfo = LineInfo();
1332 SetLineAndFillAttr();
1333 WMFRecord_Rectangle( pA->GetRect() );
1334 aSrcLineColor = aOldLineColor;
1335 aSrcFillColor = aOldFillColor;
1337 break;
1339 case MetaActionType::ISECTRECTCLIPREGION:
1341 const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pMA);
1342 WMFRecord_IntersectClipRect( pA->GetRect() );
1344 break;
1346 case MetaActionType::LINECOLOR:
1348 const MetaLineColorAction* pA = static_cast<const MetaLineColorAction*>(pMA);
1350 if( pA->IsSetting() )
1351 aSrcLineColor = pA->GetColor();
1352 else
1353 aSrcLineColor = Color( COL_TRANSPARENT );
1355 break;
1357 case MetaActionType::FILLCOLOR:
1359 const MetaFillColorAction* pA = static_cast<const MetaFillColorAction*>(pMA);
1361 if( pA->IsSetting() )
1362 aSrcFillColor = pA->GetColor();
1363 else
1364 aSrcFillColor = Color( COL_TRANSPARENT );
1366 break;
1368 case MetaActionType::TEXTCOLOR:
1370 const MetaTextColorAction* pA = static_cast<const MetaTextColorAction*>(pMA);
1371 aSrcTextColor = pA->GetColor();
1373 break;
1375 case MetaActionType::TEXTFILLCOLOR:
1377 const MetaTextFillColorAction* pA = static_cast<const MetaTextFillColorAction*>(pMA);
1378 if( pA->IsSetting() )
1379 aSrcFont.SetFillColor( pA->GetColor() );
1380 else
1381 aSrcFont.SetFillColor( Color( COL_TRANSPARENT ) );
1383 break;
1385 case MetaActionType::TEXTALIGN:
1387 const MetaTextAlignAction* pA = static_cast<const MetaTextAlignAction*>(pMA);
1388 eSrcTextAlign = pA->GetTextAlign();
1390 break;
1392 case MetaActionType::MAPMODE:
1394 const MetaMapModeAction* pA = static_cast<const MetaMapModeAction*>(pMA);
1396 if (aSrcMapMode!=pA->GetMapMode())
1398 if( pA->GetMapMode().GetMapUnit() == MapUnit::MapRelative )
1400 MapMode aMM = pA->GetMapMode();
1401 Fraction aScaleX = aMM.GetScaleX();
1402 Fraction aScaleY = aMM.GetScaleY();
1404 Point aOrigin = aSrcMapMode.GetOrigin();
1405 BigInt aX( aOrigin.X() );
1406 aX *= BigInt( aScaleX.GetDenominator() );
1407 if( aOrigin.X() >= 0 )
1408 if( aScaleX.GetNumerator() >= 0 )
1409 aX += BigInt( aScaleX.GetNumerator()/2 );
1410 else
1411 aX -= BigInt( (aScaleX.GetNumerator()+1)/2 );
1412 else
1413 if( aScaleX.GetNumerator() >= 0 )
1414 aX -= BigInt( (aScaleX.GetNumerator()-1)/2 );
1415 else
1416 aX += BigInt( aScaleX.GetNumerator()/2 );
1417 aX /= BigInt( aScaleX.GetNumerator() );
1418 aOrigin.X() = (long)aX + aMM.GetOrigin().X();
1419 BigInt aY( aOrigin.Y() );
1420 aY *= BigInt( aScaleY.GetDenominator() );
1421 if( aOrigin.Y() >= 0 )
1422 if( aScaleY.GetNumerator() >= 0 )
1423 aY += BigInt( aScaleY.GetNumerator()/2 );
1424 else
1425 aY -= BigInt( (aScaleY.GetNumerator()+1)/2 );
1426 else
1427 if( aScaleY.GetNumerator() >= 0 )
1428 aY -= BigInt( (aScaleY.GetNumerator()-1)/2 );
1429 else
1430 aY += BigInt( aScaleY.GetNumerator()/2 );
1431 aY /= BigInt( aScaleY.GetNumerator() );
1432 aOrigin.Y() = (long)aY + aMM.GetOrigin().Y();
1433 aSrcMapMode.SetOrigin( aOrigin );
1435 aScaleX *= aSrcMapMode.GetScaleX();
1436 aScaleY *= aSrcMapMode.GetScaleY();
1437 aSrcMapMode.SetScaleX( aScaleX );
1438 aSrcMapMode.SetScaleY( aScaleY );
1440 else
1441 aSrcMapMode=pA->GetMapMode();
1444 break;
1446 case MetaActionType::FONT:
1448 const MetaFontAction* pA = static_cast<const MetaFontAction*>(pMA);
1449 aSrcFont = pA->GetFont();
1451 if ( (aSrcFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW)
1452 || (aSrcFont.GetCharSet() == RTL_TEXTENCODING_UNICODE) )
1454 aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 );
1456 eSrcTextAlign = aSrcFont.GetAlignment();
1457 aSrcTextColor = aSrcFont.GetColor();
1458 aSrcFont.SetAlignment( ALIGN_BASELINE );
1459 aSrcFont.SetColor( COL_WHITE );
1461 break;
1463 case MetaActionType::PUSH:
1465 const MetaPushAction* pA = static_cast<const MetaPushAction*>(pMA);
1467 WMFWriterAttrStackMember* pAt = new WMFWriterAttrStackMember;
1468 pAt->nFlags = pA->GetFlags();
1469 pAt->aClipRegion = aSrcClipRegion;
1470 pAt->aLineColor=aSrcLineColor;
1471 pAt->aFillColor=aSrcFillColor;
1472 pAt->eRasterOp=eSrcRasterOp;
1473 pAt->aFont=aSrcFont;
1474 pAt->eTextAlign=eSrcTextAlign;
1475 pAt->aTextColor=aSrcTextColor;
1476 pAt->aMapMode=aSrcMapMode;
1477 pAt->aLineInfo=aDstLineInfo;
1478 pAt->pSucc=pAttrStack;
1479 pAttrStack=pAt;
1481 SetAllAttr(); // update ( now all source attributes are equal to the destination attributes )
1482 WMFRecord_SaveDC();
1485 break;
1487 case MetaActionType::POP:
1489 WMFWriterAttrStackMember * pAt=pAttrStack;
1491 if( pAt )
1493 aDstLineInfo = pAt->aLineInfo;
1494 aDstLineColor = pAt->aLineColor;
1495 if ( pAt->nFlags & PushFlags::LINECOLOR )
1496 aSrcLineColor = pAt->aLineColor;
1497 aDstFillColor = pAt->aFillColor;
1498 if ( pAt->nFlags & PushFlags::FILLCOLOR )
1499 aSrcFillColor = pAt->aFillColor;
1500 eDstROP2 = pAt->eRasterOp;
1501 if ( pAt->nFlags & PushFlags::RASTEROP )
1502 eSrcRasterOp = pAt->eRasterOp;
1503 aDstFont = pAt->aFont;
1504 if ( pAt->nFlags & PushFlags::FONT )
1505 aSrcFont = pAt->aFont;
1506 eDstTextAlign = pAt->eTextAlign;
1507 if ( pAt->nFlags & ( PushFlags::FONT | PushFlags::TEXTALIGN ) )
1508 eSrcTextAlign = pAt->eTextAlign;
1509 aDstTextColor = pAt->aTextColor;
1510 if ( pAt->nFlags & ( PushFlags::FONT | PushFlags::TEXTCOLOR ) )
1511 aSrcTextColor = pAt->aTextColor;
1512 if ( pAt->nFlags & PushFlags::MAPMODE )
1513 aSrcMapMode = pAt->aMapMode;
1514 aDstClipRegion = pAt->aClipRegion;
1515 if ( pAt->nFlags & PushFlags::CLIPREGION )
1516 aSrcClipRegion = pAt->aClipRegion;
1518 WMFRecord_RestoreDC();
1519 pAttrStack = pAt->pSucc;
1520 delete pAt;
1523 break;
1525 case MetaActionType::EPS :
1527 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pMA);
1528 const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
1530 size_t nCount = aGDIMetaFile.GetActionSize();
1531 for ( size_t i = 0; i < nCount; i++ )
1533 const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i );
1534 if ( pMetaAct->GetType() == MetaActionType::BMPSCALE )
1536 const MetaBmpScaleAction* pBmpScaleAction = static_cast<const MetaBmpScaleAction*>(pMetaAct);
1537 WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap() );
1538 break;
1542 break;
1544 case MetaActionType::RASTEROP:
1546 const MetaRasterOpAction* pA = static_cast<const MetaRasterOpAction*>(pMA);
1547 eSrcRasterOp=pA->GetRasterOp();
1549 break;
1551 case MetaActionType::Transparent:
1553 aSrcLineInfo = LineInfo();
1554 SetLineAndFillAttr();
1555 WMFRecord_PolyPolygon( static_cast<const MetaTransparentAction*>(pMA)->GetPolyPolygon() );
1557 break;
1559 case MetaActionType::FLOATTRANSPARENT:
1561 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pMA);
1563 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1564 Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1565 const Size aSrcSize( aTmpMtf.GetPrefSize() );
1566 const Point aDestPt( pA->GetPoint() );
1567 const Size aDestSize( pA->GetSize() );
1568 const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1569 const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1570 long nMoveX, nMoveY;
1572 aSrcLineInfo = LineInfo();
1573 SetAllAttr();
1575 if( fScaleX != 1.0 || fScaleY != 1.0 )
1577 aTmpMtf.Scale( fScaleX, fScaleY );
1578 aSrcPt.X() = FRound( aSrcPt.X() * fScaleX );
1579 aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1582 nMoveX = aDestPt.X() - aSrcPt.X();
1583 nMoveY = aDestPt.Y() - aSrcPt.Y();
1585 if( nMoveX || nMoveY )
1586 aTmpMtf.Move( nMoveX, nMoveY );
1588 WriteRecords( aTmpMtf );
1590 break;
1592 case( MetaActionType::LAYOUTMODE ):
1594 ComplexTextLayoutFlags nLayoutMode = static_cast<const MetaLayoutModeAction*>(pMA)->GetLayoutMode();
1595 eSrcHorTextAlign = 0; // TA_LEFT
1596 if ((nLayoutMode & ComplexTextLayoutFlags::BiDiRtl) != ComplexTextLayoutFlags::Default)
1598 eSrcHorTextAlign = W_TA_RIGHT | W_TA_RTLREADING;
1600 if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginRight) != ComplexTextLayoutFlags::Default)
1601 eSrcHorTextAlign |= W_TA_RIGHT;
1602 else if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginLeft) != ComplexTextLayoutFlags::Default)
1603 eSrcHorTextAlign &= ~W_TA_RIGHT;
1604 break;
1607 case MetaActionType::CLIPREGION:
1608 case MetaActionType::TEXTLANGUAGE:
1609 case MetaActionType::COMMENT:
1610 // Explicitly ignored cases
1611 break;
1613 default:
1614 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1615 break;
1618 nWrittenActions++;
1619 MayCallback();
1621 if (pWMF->GetError())
1622 bStatus=false;
1624 if(!bStatus)
1625 break;
1630 void WMFWriter::WriteHeader( const GDIMetaFile &, bool bPlaceable )
1632 if( bPlaceable )
1634 sal_uInt16 nCheckSum, nValue;
1635 Size aSize( OutputDevice::LogicToLogic(Size(1,1),MapMode(MapUnit::MapInch), aTargetMapMode) );
1636 sal_uInt16 nUnitsPerInch = (sal_uInt16) ( ( aSize.Width() + aSize.Height() ) >> 1 );
1638 nCheckSum=0;
1639 nValue=0xcdd7; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1640 nValue=0x9ac6; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1641 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1642 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1643 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1644 nValue=(sal_uInt16) aTargetSize.Width(); nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1645 nValue=(sal_uInt16) aTargetSize.Height(); nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1646 nValue=nUnitsPerInch; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1647 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1648 nValue=0x0000; nCheckSum^=nValue; pWMF->WriteUInt16( nValue );
1649 pWMF->WriteUInt16( nCheckSum );
1652 nMetafileHeaderPos=pWMF->Tell();
1653 pWMF->WriteUInt16( 0x0001 ) // type: file
1654 .WriteUInt16( 0x0009 ) // header length in words
1655 .WriteUInt16( 0x0300 ) // Version as BCD number
1656 .WriteUInt32( 0x00000000 ) // file length (without 1st header), is later corrected by UpdateHeader()
1657 .WriteUInt16( MAXOBJECTHANDLES ) // maxmimum number of simultaneous objects
1658 .WriteUInt32( 0x00000000 ) // maximum record length, is later corrected by UpdateHeader()
1659 .WriteUInt16( 0x0000 ); // reserved
1662 void WMFWriter::UpdateHeader()
1664 sal_uLong nPos;
1665 sal_uInt32 nFileSize;
1667 nPos=pWMF->Tell(); // endposition = total size of file
1668 nFileSize=nPos-nMetafileHeaderPos; // subtract size of 1st header
1669 if ((nFileSize&1)!=0) { // if needed round to words
1670 pWMF->WriteUChar( 0 );
1671 nPos++;
1672 nFileSize++;
1674 nFileSize>>=1; // convert to number of words
1675 pWMF->Seek(nMetafileHeaderPos+6); // to filesize entry in second header
1676 pWMF->WriteUInt32( nFileSize ); // rectify file size
1677 pWMF->SeekRel(2); // to max-record-length-entry in second header
1678 pWMF->WriteUInt32( nMaxRecordSize ); // and rectify
1679 pWMF->Seek(nPos);
1682 bool WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream,
1683 FilterConfigItem* pFConfigItem, bool bPlaceable )
1685 WMFWriterAttrStackMember * pAt;
1687 bEmbedEMF = true;
1688 bStatus=true;
1689 pVirDev = VclPtr<VirtualDevice>::Create();
1691 if (pFConfigItem)
1693 xStatusIndicator = pFConfigItem->GetStatusIndicator();
1694 if ( xStatusIndicator.is() )
1696 OUString aMsg;
1697 xStatusIndicator->start( aMsg, 100 );
1700 nLastPercent=0;
1702 pWMF=&rTargetStream;
1703 pWMF->SetEndian(SvStreamEndian::LITTLE);
1705 nMaxRecordSize=0;
1707 aSrcMapMode=rMTF.GetPrefMapMode();
1709 if( bPlaceable )
1711 aTargetMapMode = aSrcMapMode;
1712 aTargetSize = rMTF.GetPrefSize();
1713 sal_uInt16 nTargetDivisor = CalcSaveTargetMapMode(aTargetMapMode, aTargetSize);
1714 aTargetSize.Width() /= nTargetDivisor;
1715 aTargetSize.Height() /= nTargetDivisor;
1717 else
1719 aTargetMapMode = MapMode( MapUnit::MapInch );
1721 const long nUnit = pVirDev->LogicToPixel( Size( 1, 1 ), aTargetMapMode ).Width();
1722 const Fraction aFrac( 1, nUnit );
1724 aTargetMapMode.SetScaleX( aFrac );
1725 aTargetMapMode.SetScaleY( aFrac );
1726 aTargetSize = OutputDevice::LogicToLogic( rMTF.GetPrefSize(), aSrcMapMode, aTargetMapMode );
1729 pVirDev->SetMapMode( aTargetMapMode );
1731 pAttrStack=nullptr;
1733 for (bool & rn : bHandleAllocated)
1734 rn=false;
1736 nDstPenHandle=0xffff;
1737 nDstFontHandle=0xffff;
1738 nDstBrushHandle=0xffff;
1740 nNumberOfActions=0;
1741 nNumberOfBitmaps=0;
1742 nWrittenActions=0;
1743 nWrittenBitmaps=0;
1744 nActBitmapPercent=0;
1746 CountActionsAndBitmaps(rMTF);
1748 WriteHeader(rMTF,bPlaceable);
1749 if( bEmbedEMF )
1750 WriteEmbeddedEMF( rMTF );
1751 WMFRecord_SetWindowOrg(Point(0,0));
1752 WMFRecord_SetWindowExt(rMTF.GetPrefSize());
1753 WMFRecord_SetBkMode( true );
1755 eDstROP2 = eSrcRasterOp = RasterOp::OverPaint;
1756 WMFRecord_SetROP2(eDstROP2);
1758 aDstLineInfo = LineInfo();
1759 aDstLineColor = aSrcLineColor = Color( COL_BLACK );
1760 CreateSelectDeletePen( aDstLineColor, aDstLineInfo );
1762 aDstFillColor = aSrcFillColor = Color( COL_WHITE );
1763 CreateSelectDeleteBrush( aDstFillColor );
1765 aDstClipRegion = aSrcClipRegion = vcl::Region();
1766 bDstIsClipping = bSrcIsClipping = false;
1768 vcl::Font aFont;
1769 aFont.SetCharSet( GetExtendedTextEncoding( RTL_TEXTENCODING_MS_1252 ) );
1770 aFont.SetColor( Color( COL_WHITE ) );
1771 aFont.SetAlignment( ALIGN_BASELINE );
1772 aDstFont = aSrcFont = aFont;
1773 CreateSelectDeleteFont(aDstFont);
1775 eDstTextAlign = eSrcTextAlign = ALIGN_BASELINE;
1776 eDstHorTextAlign = eSrcHorTextAlign = W_TA_LEFT;
1777 WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign );
1779 aDstTextColor = aSrcTextColor = Color( COL_WHITE );
1780 WMFRecord_SetTextColor(aDstTextColor);
1782 // Write records
1783 WriteRecords(rMTF);
1785 WriteRecordHeader(0x00000003,0x0000); // end of file
1786 UpdateHeader();
1788 while(pAttrStack)
1790 pAt=pAttrStack;
1791 pAttrStack=pAt->pSucc;
1792 delete pAt;
1795 pVirDev.disposeAndClear();
1797 if ( xStatusIndicator.is() )
1798 xStatusIndicator->end();
1800 return bStatus;
1803 sal_uInt16 WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode,
1804 const Size& rPrefSize)
1806 Fraction aDivFrac(2, 1);
1807 sal_uInt16 nDivisor = 1;
1809 Size aSize = OutputDevice::LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
1811 while( nDivisor <= 64 && (aSize.Width() > 32767 || aSize.Height() > 32767) )
1813 Fraction aFrac = rMapMode.GetScaleX();
1815 aFrac *= aDivFrac;
1816 rMapMode.SetScaleX(aFrac);
1817 aFrac = rMapMode.GetScaleY();
1818 aFrac *= aDivFrac;
1819 rMapMode.SetScaleY(aFrac);
1820 nDivisor <<= 1;
1821 aSize = OutputDevice::LogicToLogic( rPrefSize, aSrcMapMode, rMapMode );
1824 return nDivisor;
1827 void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF )
1829 SvMemoryStream aStream;
1830 EMFWriter aEMFWriter(aStream);
1832 if( aEMFWriter.WriteEMF( rMTF ) )
1834 sal_uInt64 const nTotalSize = aStream.Tell();
1835 if( nTotalSize > SAL_MAX_UINT32 )
1836 return;
1837 aStream.Seek( 0 );
1838 sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize );
1839 sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1;
1840 sal_uInt16 nCheckSum = 0, nWord;
1842 sal_uInt32 nPos = 0;
1844 while( nPos + 1 < nTotalSize )
1846 aStream.ReadUInt16( nWord );
1847 nCheckSum ^= nWord;
1848 nPos += 2;
1851 nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 );
1853 aStream.Seek( 0 );
1854 while( nRemainingSize > 0 )
1856 sal_uInt32 nCurSize;
1857 if( nRemainingSize > 0x2000 )
1859 nCurSize = 0x2000;
1860 nRemainingSize -= 0x2000;
1862 else
1864 nCurSize = nRemainingSize;
1865 nRemainingSize = 0;
1867 WriteEMFRecord( aStream,
1868 nCurSize,
1869 nRemainingSize,
1870 nTotalSize,
1871 nRecCounts,
1872 nCheckSum );
1873 nCheckSum = 0;
1878 void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize,
1879 sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum )
1881 // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx
1882 WriteRecordHeader( 0, W_META_ESCAPE );
1883 pWMF->WriteUInt16( W_MFCOMMENT ) // same as META_ESCAPE_ENHANCED_METAFILE
1884 .WriteUInt16( nCurSize + 34 ) // we will always have a 34 byte escape header:
1885 .WriteUInt32( 0x43464D57 ) // WMFC
1886 .WriteUInt32( 0x00000001 ) // Comment type
1887 .WriteUInt32( 0x00010000 ) // version
1888 .WriteUInt16( nCheckSum ) // check sum
1889 .WriteUInt32( 0 ) // flags = 0
1890 .WriteUInt32( nRecCounts ) // total number of records
1891 .WriteUInt32( nCurSize ) // size of this record's data
1892 .WriteUInt32( nRemainingSize ) // remaining size of data in following records, missing in MSDN documentation
1893 .WriteUInt32( nTotalSize ); // total size of EMF stream
1895 pWMF->WriteBytes(static_cast<const sal_Char*>(rStream.GetData()) + rStream.Tell(), nCurSize);
1896 rStream.SeekRel( nCurSize );
1897 UpdateRecordHeader();
1900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */