1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
40 #include <vcl/fontcharmap.hxx>
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
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
100 #define W_PS_DASHDOT 3
101 #define W_PS_DASHDOTDOT 4
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
131 #define W_BS_HOLLOW 1
133 #define W_MFCOMMENT 15
135 #define PRIVATE_ESCAPE_UNICODE 2
137 WMFWriter::WMFWriter()
142 , nMetafileHeaderPos(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
)
156 , nNumberOfActions(0)
157 , nNumberOfBitmaps(0)
160 , nActBitmapPercent(0)
165 void WMFWriter::MayCallback()
167 if ( xStatusIndicator
.is() )
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
)
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
:
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
) );
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()
267 nPos
=pWMF
->Tell(); nSize
=nPos
-nActRecordPos
;
268 if ((nSize
& 1)!=0) {
269 pWMF
->WriteUChar( 0 );
273 if (nSize
>nMaxRecordSize
) nMaxRecordSize
=nSize
;
274 pWMF
->Seek(nActRecordPos
);
275 pWMF
->WriteUInt32( nSize
);
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
);
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
;
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() )
384 if ( rLineInfo
.GetDotCount() == 1 )
385 nStyle
= W_PS_DASHDOT
;
387 nStyle
= W_PS_DASHDOTDOT
;
394 case LineStyle::NONE
:
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
)
421 sal_uInt32 nTmp
= OSL_SWAPDWORD( nEsc
);
422 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nTmp
, 4 );
424 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nEsc
, 4 );
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
);
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();
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
++ )
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
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
++ )
494 aSrcFont
.SetCharSet (aTextEncoding
);
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
;
547 void WMFWriter::WMFRecord_ExtTextOut( const Point
& rPoint
,
548 const OUString
& rString
,
551 sal_Int32 nOriginalTextLen
= rString
.getLength();
553 if ( (nOriginalTextLen
<= 1) || (pDXAry
== nullptr) )
555 WMFRecord_TextOut(rPoint
, rString
);
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
]);
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();
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
);
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
);
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
);
721 WritePointYX(rPoint
);
724 void WMFWriter::WMFRecord_SetROP2(RasterOp 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
)
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
);
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;
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)
792 WriteDIB(rBitmap
, *pWMF
, false, true);
794 // write the parameters:
795 nPosEnd
=pWMF
->Tell();
798 // determine raster-op, if nothing was passed
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
).
811 WriteInt16( rBitmap
.GetSizePixel().Height() ).
812 WriteInt16( rBitmap
.GetSizePixel().Width() ).
816 WriteHeightWidth(rSize
);
817 WritePointYX(rPoint
);
820 UpdateRecordHeader();
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()
854 for (i
=0; i
<MAXOBJECTHANDLES
; i
++) {
855 if (!bHandleAllocated
[i
]) {
856 bHandleAllocated
[i
]=true;
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
);
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
)
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() );
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
);
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() );
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
);
1061 case MetaActionType::RECT
:
1063 const MetaRectAction
* pA
= static_cast<const MetaRectAction
*>(pMA
);
1064 aSrcLineInfo
= LineInfo();
1065 SetLineAndFillAttr();
1066 WMFRecord_Rectangle( pA
->GetRect() );
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() );
1079 case MetaActionType::ELLIPSE
:
1081 const MetaEllipseAction
* pA
= static_cast<const MetaEllipseAction
*>(pMA
);
1082 aSrcLineInfo
= LineInfo();
1083 SetLineAndFillAttr();
1084 WMFRecord_Ellipse( pA
->GetRect() );
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() );
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() );
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() );
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
);
1130 // LineInfo used; handle Dash/Dot and fat lines
1131 HandleLineInfoPolyPolygons(pA
->GetLineInfo(), rPoly
.getB2DPolygon());
1137 case MetaActionType::POLYGON
:
1139 const MetaPolygonAction
* pA
= static_cast<const MetaPolygonAction
*>(pMA
);
1140 aSrcLineInfo
= LineInfo();
1141 SetLineAndFillAttr();
1142 WMFRecord_Polygon( pA
->GetPolygon() );
1146 case MetaActionType::POLYPOLYGON
:
1148 const MetaPolyPolygonAction
* pA
= static_cast<const MetaPolyPolygonAction
*>(pMA
);
1149 aSrcLineInfo
= LineInfo();
1150 SetLineAndFillAttr();
1151 WMFRecord_PolyPolygon( pA
->GetPolyPolygon() );
1155 case MetaActionType::TEXTRECT
:
1157 const MetaTextRectAction
* pA
= static_cast<const MetaTextRectAction
*>(pMA
);
1158 OUString
aTemp( pA
->GetText() );
1159 aSrcLineInfo
= LineInfo();
1162 Point
aPos( pA
->GetRect().TopLeft() );
1163 if ( !WMFRecord_Escape_Unicode( aPos
, aTemp
, nullptr ) )
1164 WMFRecord_TextOut( aPos
, aTemp
);
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();
1174 if ( !WMFRecord_Escape_Unicode( pA
->GetPoint(), aTemp
, nullptr ) )
1175 WMFRecord_TextOut( pA
->GetPoint(), aTemp
);
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();
1186 if ( !WMFRecord_Escape_Unicode( pA
->GetPoint(), aTemp
, pA
->GetDXArray() ) )
1187 WMFRecord_ExtTextOut( pA
->GetPoint(), aTemp
, pA
->GetDXArray() );
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!");
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
) )
1210 aSrcLineInfo
= LineInfo();
1212 if ( !WMFRecord_Escape_Unicode( pA
->GetPoint(), aTemp
, pDXAry
.get() ) )
1213 WMFRecord_ExtTextOut( pA
->GetPoint(), aTemp
, pDXAry
.get() );
1218 case MetaActionType::BMP
:
1220 const MetaBmpAction
* pA
= static_cast<const MetaBmpAction
*>(pMA
);
1221 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetBitmap().GetSizePixel(), pA
->GetBitmap() );
1225 case MetaActionType::BMPSCALE
:
1227 const MetaBmpScaleAction
* pA
= static_cast<const MetaBmpScaleAction
*>(pMA
);
1228 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), pA
->GetBitmap() );
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
);
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() );
1250 aBmp
.Replace( aMsk
, COL_WHITE
);
1252 WMFRecord_StretchDIB( pA
->GetPoint(), aMsk
.GetSizePixel(), aBmp
, W_SRCPAINT
);
1253 WMFRecord_StretchDIB( pA
->GetPoint(), aBmp
.GetSizePixel(), aBmp
, W_SRCAND
);
1256 WMFRecord_StretchDIB( pA
->GetPoint(), aBmp
.GetSizePixel(), aBmp
);
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() );
1268 aBmp
.Replace( aMsk
, COL_WHITE
);
1270 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), aMsk
, W_SRCPAINT
);
1271 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), aBmp
, W_SRCAND
);
1274 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), aBmp
);
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() );
1288 aBmp
.Replace( aMsk
, COL_WHITE
);
1290 WMFRecord_StretchDIB( pA
->GetDestPoint(), pA
->GetDestSize(), aMsk
, W_SRCPAINT
);
1291 WMFRecord_StretchDIB( pA
->GetDestPoint(), pA
->GetDestSize(), aBmp
, W_SRCAND
);
1294 WMFRecord_StretchDIB( pA
->GetDestPoint(), pA
->GetDestSize(), aBmp
);
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
);
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
);
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
;
1335 case MetaActionType::ISECTRECTCLIPREGION
:
1337 const MetaISectRectClipRegionAction
* pA
= static_cast<const MetaISectRectClipRegionAction
*>(pMA
);
1338 WMFRecord_IntersectClipRect( pA
->GetRect() );
1342 case MetaActionType::LINECOLOR
:
1344 const MetaLineColorAction
* pA
= static_cast<const MetaLineColorAction
*>(pMA
);
1346 if( pA
->IsSetting() )
1347 aSrcLineColor
= pA
->GetColor();
1349 aSrcLineColor
= COL_TRANSPARENT
;
1353 case MetaActionType::FILLCOLOR
:
1355 const MetaFillColorAction
* pA
= static_cast<const MetaFillColorAction
*>(pMA
);
1357 if( pA
->IsSetting() )
1358 aSrcFillColor
= pA
->GetColor();
1360 aSrcFillColor
= COL_TRANSPARENT
;
1364 case MetaActionType::TEXTCOLOR
:
1366 const MetaTextColorAction
* pA
= static_cast<const MetaTextColorAction
*>(pMA
);
1367 aSrcTextColor
= pA
->GetColor();
1371 case MetaActionType::TEXTFILLCOLOR
:
1373 const MetaTextFillColorAction
* pA
= static_cast<const MetaTextFillColorAction
*>(pMA
);
1374 if( pA
->IsSetting() )
1375 aSrcFont
.SetFillColor( pA
->GetColor() );
1377 aSrcFont
.SetFillColor( COL_TRANSPARENT
);
1381 case MetaActionType::TEXTALIGN
:
1383 const MetaTextAlignAction
* pA
= static_cast<const MetaTextAlignAction
*>(pMA
);
1384 eSrcTextAlign
= pA
->GetTextAlign();
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 );
1407 aX
-= BigInt( (aScaleX
.GetNumerator()+1)/2 );
1409 if( aScaleX
.GetNumerator() >= 0 )
1410 aX
-= BigInt( (aScaleX
.GetNumerator()-1)/2 );
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 );
1421 aY
-= BigInt( (aScaleY
.GetNumerator()+1)/2 );
1423 if( aScaleY
.GetNumerator() >= 0 )
1424 aY
-= BigInt( (aScaleY
.GetNumerator()-1)/2 );
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
);
1437 aSrcMapMode
=pA
->GetMapMode();
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
);
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
;
1477 SetAllAttr(); // update ( now all source attributes are equal to the destination attributes )
1483 case MetaActionType::POP
:
1485 WMFWriterAttrStackMember
* pAt
=pAttrStack
;
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
;
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() );
1540 case MetaActionType::RASTEROP
:
1542 const MetaRasterOpAction
* pA
= static_cast<const MetaRasterOpAction
*>(pMA
);
1543 eSrcRasterOp
=pA
->GetRasterOp();
1547 case MetaActionType::Transparent
:
1549 aSrcLineInfo
= LineInfo();
1550 SetLineAndFillAttr();
1551 WMFRecord_PolyPolygon( static_cast<const MetaTransparentAction
*>(pMA
)->GetPolyPolygon() );
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();
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
);
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
;
1603 case MetaActionType::CLIPREGION
:
1604 case MetaActionType::TEXTLANGUAGE
:
1605 case MetaActionType::COMMENT
:
1606 // Explicitly ignored cases
1610 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1617 if (pWMF
->GetError())
1626 void WMFWriter::WriteHeader( bool 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 );
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()
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 );
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
1678 bool WMFWriter::WriteWMF( const GDIMetaFile
& rMTF
, SvStream
& rTargetStream
,
1679 FilterConfigItem
const * pFConfigItem
, bool bPlaceable
)
1681 WMFWriterAttrStackMember
* pAt
;
1685 pVirDev
= VclPtr
<VirtualDevice
>::Create();
1689 xStatusIndicator
= pFConfigItem
->GetStatusIndicator();
1690 if ( xStatusIndicator
.is() )
1692 xStatusIndicator
->start( OUString(), 100 );
1697 pWMF
=&rTargetStream
;
1698 pWMF
->SetEndian(SvStreamEndian::LITTLE
);
1702 aSrcMapMode
=rMTF
.GetPrefMapMode();
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
);
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
);
1728 for (bool & rn
: bHandleAllocated
)
1731 nDstPenHandle
=0xffff;
1732 nDstFontHandle
=0xffff;
1733 nDstBrushHandle
=0xffff;
1739 nActBitmapPercent
=0;
1741 CountActionsAndBitmaps(rMTF
);
1743 WriteHeader(bPlaceable
);
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();
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
);
1779 WriteRecordHeader(0x00000003,0x0000); // end of file
1785 pAttrStack
=pAt
->pSucc
;
1789 pVirDev
.disposeAndClear();
1791 if ( xStatusIndicator
.is() )
1792 xStatusIndicator
->end();
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();
1810 rMapMode
.SetScaleX(aFrac
);
1811 aFrac
= rMapMode
.GetScaleY();
1813 rMapMode
.SetScaleY(aFrac
);
1815 aSize
= OutputDevice::LogicToLogic( rPrefSize
, aSrcMapMode
, rMapMode
);
1821 void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile
& rMTF
)
1823 SvMemoryStream aStream
;
1824 EMFWriter
aEMFWriter(aStream
);
1826 if( !aEMFWriter
.WriteEMF( rMTF
) )
1829 sal_uInt64
const nTotalSize
= aStream
.Tell();
1830 if( nTotalSize
> SAL_MAX_UINT32
)
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
);
1846 nCheckSum
= static_cast< sal_uInt16
>( nCheckSum
* -1 );
1849 while( nRemainingSize
> 0 )
1851 sal_uInt32 nCurSize
;
1852 if( nRemainingSize
> 0x2000 )
1855 nRemainingSize
-= 0x2000;
1859 nCurSize
= nRemainingSize
;
1862 WriteEMFRecord( aStream
,
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: */