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"
25 #include <unotools/fontcvt.hxx>
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>
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 , 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)
158 , nNumberOfActions(0)
159 , nNumberOfBitmaps(0)
162 , nActBitmapPercent(0)
167 void WMFWriter::MayCallback()
169 if ( xStatusIndicator
.is() )
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
)
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
:
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
) );
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()
269 nPos
=pWMF
->Tell(); nSize
=nPos
-nActRecordPos
;
270 if ((nSize
& 1)!=0) {
271 pWMF
->WriteUChar( 0 );
275 if (nSize
>nMaxRecordSize
) nMaxRecordSize
=nSize
;
276 pWMF
->Seek(nActRecordPos
);
277 pWMF
->WriteUInt32( nSize
);
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
);
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
;
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() )
386 if ( rLineInfo
.GetDotCount() == 1 )
387 nStyle
= W_PS_DASHDOT
;
389 nStyle
= W_PS_DASHDOTDOT
;
396 case LineStyle::NONE
:
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
)
423 sal_uInt32 nTmp
= OSL_SWAPDWORD( nEsc
);
424 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nTmp
, 4 );
426 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nEsc
, 4 );
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
);
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();
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
++ )
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
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
++ )
490 aSrcFont
.SetCharSet (aTextEncoding
);
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
;
544 void WMFWriter::WMFRecord_ExtTextOut( const Point
& rPoint
,
545 const OUString
& rString
,
548 sal_Int32 nOriginalTextLen
= rString
.getLength();
550 if ( (nOriginalTextLen
<= 1) || (pDXAry
== nullptr) )
552 WMFRecord_TextOut(rPoint
, rString
);
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
]);
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();
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
);
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
);
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
);
718 WritePointYX(rPoint
);
721 void WMFWriter::WMFRecord_SetROP2(RasterOp 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
)
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
);
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;
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)
789 WriteDIB(rBitmap
, *pWMF
, false, true);
791 // write the parameters:
792 nPosEnd
=pWMF
->Tell();
795 // determine raster-op, if nothing was passed
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
).
808 WriteInt16( rBitmap
.GetSizePixel().Height() ).
809 WriteInt16( rBitmap
.GetSizePixel().Width() ).
813 WriteHeightWidth(rSize
);
814 WritePointYX(rPoint
);
817 UpdateRecordHeader();
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()
851 for (i
=0; i
<MAXOBJECTHANDLES
; i
++) {
852 if (!bHandleAllocated
[i
]) {
853 bHandleAllocated
[i
]=true;
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
);
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
)
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() );
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
);
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() );
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
);
1065 case MetaActionType::RECT
:
1067 const MetaRectAction
* pA
= static_cast<const MetaRectAction
*>(pMA
);
1068 aSrcLineInfo
= LineInfo();
1069 SetLineAndFillAttr();
1070 WMFRecord_Rectangle( pA
->GetRect() );
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() );
1083 case MetaActionType::ELLIPSE
:
1085 const MetaEllipseAction
* pA
= static_cast<const MetaEllipseAction
*>(pMA
);
1086 aSrcLineInfo
= LineInfo();
1087 SetLineAndFillAttr();
1088 WMFRecord_Ellipse( pA
->GetRect() );
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() );
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() );
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() );
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
);
1134 // LineInfo used; handle Dash/Dot and fat lines
1135 HandleLineInfoPolyPolygons(pA
->GetLineInfo(), rPoly
.getB2DPolygon());
1141 case MetaActionType::POLYGON
:
1143 const MetaPolygonAction
* pA
= static_cast<const MetaPolygonAction
*>(pMA
);
1144 aSrcLineInfo
= LineInfo();
1145 SetLineAndFillAttr();
1146 WMFRecord_Polygon( pA
->GetPolygon() );
1150 case MetaActionType::POLYPOLYGON
:
1152 const MetaPolyPolygonAction
* pA
= static_cast<const MetaPolyPolygonAction
*>(pMA
);
1153 aSrcLineInfo
= LineInfo();
1154 SetLineAndFillAttr();
1155 WMFRecord_PolyPolygon( pA
->GetPolyPolygon() );
1159 case MetaActionType::TEXTRECT
:
1161 const MetaTextRectAction
* pA
= static_cast<const MetaTextRectAction
*>(pMA
);
1162 OUString
aTemp( pA
->GetText() );
1163 aSrcLineInfo
= LineInfo();
1166 Point
aPos( pA
->GetRect().TopLeft() );
1167 if ( !WMFRecord_Escape_Unicode( aPos
, aTemp
, nullptr ) )
1168 WMFRecord_TextOut( aPos
, aTemp
);
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();
1178 if ( !WMFRecord_Escape_Unicode( pA
->GetPoint(), aTemp
, nullptr ) )
1179 WMFRecord_TextOut( pA
->GetPoint(), aTemp
);
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();
1190 if ( !WMFRecord_Escape_Unicode( pA
->GetPoint(), aTemp
, pA
->GetDXArray() ) )
1191 WMFRecord_ExtTextOut( pA
->GetPoint(), aTemp
, pA
->GetDXArray() );
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!");
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
) )
1214 aSrcLineInfo
= LineInfo();
1216 if ( !WMFRecord_Escape_Unicode( pA
->GetPoint(), aTemp
, pDXAry
.get() ) )
1217 WMFRecord_ExtTextOut( pA
->GetPoint(), aTemp
, pDXAry
.get() );
1222 case MetaActionType::BMP
:
1224 const MetaBmpAction
* pA
= static_cast<const MetaBmpAction
*>(pMA
);
1225 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetBitmap().GetSizePixel(), pA
->GetBitmap() );
1229 case MetaActionType::BMPSCALE
:
1231 const MetaBmpScaleAction
* pA
= static_cast<const MetaBmpScaleAction
*>(pMA
);
1232 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), pA
->GetBitmap() );
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
);
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() );
1254 aBmp
.Replace( aMsk
, COL_WHITE
);
1256 WMFRecord_StretchDIB( pA
->GetPoint(), aMsk
.GetSizePixel(), aBmp
, W_SRCPAINT
);
1257 WMFRecord_StretchDIB( pA
->GetPoint(), aBmp
.GetSizePixel(), aBmp
, W_SRCAND
);
1260 WMFRecord_StretchDIB( pA
->GetPoint(), aBmp
.GetSizePixel(), aBmp
);
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() );
1272 aBmp
.Replace( aMsk
, COL_WHITE
);
1274 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), aMsk
, W_SRCPAINT
);
1275 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), aBmp
, W_SRCAND
);
1278 WMFRecord_StretchDIB( pA
->GetPoint(), pA
->GetSize(), aBmp
);
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() );
1292 aBmp
.Replace( aMsk
, COL_WHITE
);
1294 WMFRecord_StretchDIB( pA
->GetDestPoint(), pA
->GetDestSize(), aMsk
, W_SRCPAINT
);
1295 WMFRecord_StretchDIB( pA
->GetDestPoint(), pA
->GetDestSize(), aBmp
, W_SRCAND
);
1298 WMFRecord_StretchDIB( pA
->GetDestPoint(), pA
->GetDestSize(), aBmp
);
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
);
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
);
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
;
1339 case MetaActionType::ISECTRECTCLIPREGION
:
1341 const MetaISectRectClipRegionAction
* pA
= static_cast<const MetaISectRectClipRegionAction
*>(pMA
);
1342 WMFRecord_IntersectClipRect( pA
->GetRect() );
1346 case MetaActionType::LINECOLOR
:
1348 const MetaLineColorAction
* pA
= static_cast<const MetaLineColorAction
*>(pMA
);
1350 if( pA
->IsSetting() )
1351 aSrcLineColor
= pA
->GetColor();
1353 aSrcLineColor
= Color( COL_TRANSPARENT
);
1357 case MetaActionType::FILLCOLOR
:
1359 const MetaFillColorAction
* pA
= static_cast<const MetaFillColorAction
*>(pMA
);
1361 if( pA
->IsSetting() )
1362 aSrcFillColor
= pA
->GetColor();
1364 aSrcFillColor
= Color( COL_TRANSPARENT
);
1368 case MetaActionType::TEXTCOLOR
:
1370 const MetaTextColorAction
* pA
= static_cast<const MetaTextColorAction
*>(pMA
);
1371 aSrcTextColor
= pA
->GetColor();
1375 case MetaActionType::TEXTFILLCOLOR
:
1377 const MetaTextFillColorAction
* pA
= static_cast<const MetaTextFillColorAction
*>(pMA
);
1378 if( pA
->IsSetting() )
1379 aSrcFont
.SetFillColor( pA
->GetColor() );
1381 aSrcFont
.SetFillColor( Color( COL_TRANSPARENT
) );
1385 case MetaActionType::TEXTALIGN
:
1387 const MetaTextAlignAction
* pA
= static_cast<const MetaTextAlignAction
*>(pMA
);
1388 eSrcTextAlign
= pA
->GetTextAlign();
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 );
1411 aX
-= BigInt( (aScaleX
.GetNumerator()+1)/2 );
1413 if( aScaleX
.GetNumerator() >= 0 )
1414 aX
-= BigInt( (aScaleX
.GetNumerator()-1)/2 );
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 );
1425 aY
-= BigInt( (aScaleY
.GetNumerator()+1)/2 );
1427 if( aScaleY
.GetNumerator() >= 0 )
1428 aY
-= BigInt( (aScaleY
.GetNumerator()-1)/2 );
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
);
1441 aSrcMapMode
=pA
->GetMapMode();
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
);
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
;
1481 SetAllAttr(); // update ( now all source attributes are equal to the destination attributes )
1487 case MetaActionType::POP
:
1489 WMFWriterAttrStackMember
* pAt
=pAttrStack
;
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
;
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() );
1544 case MetaActionType::RASTEROP
:
1546 const MetaRasterOpAction
* pA
= static_cast<const MetaRasterOpAction
*>(pMA
);
1547 eSrcRasterOp
=pA
->GetRasterOp();
1551 case MetaActionType::Transparent
:
1553 aSrcLineInfo
= LineInfo();
1554 SetLineAndFillAttr();
1555 WMFRecord_PolyPolygon( static_cast<const MetaTransparentAction
*>(pMA
)->GetPolyPolygon() );
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();
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
);
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
;
1607 case MetaActionType::CLIPREGION
:
1608 case MetaActionType::TEXTLANGUAGE
:
1609 case MetaActionType::COMMENT
:
1610 // Explicitly ignored cases
1614 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1621 if (pWMF
->GetError())
1630 void WMFWriter::WriteHeader( const GDIMetaFile
&, bool 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 );
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()
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 );
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
1682 bool WMFWriter::WriteWMF( const GDIMetaFile
& rMTF
, SvStream
& rTargetStream
,
1683 FilterConfigItem
* pFConfigItem
, bool bPlaceable
)
1685 WMFWriterAttrStackMember
* pAt
;
1689 pVirDev
= VclPtr
<VirtualDevice
>::Create();
1693 xStatusIndicator
= pFConfigItem
->GetStatusIndicator();
1694 if ( xStatusIndicator
.is() )
1697 xStatusIndicator
->start( aMsg
, 100 );
1702 pWMF
=&rTargetStream
;
1703 pWMF
->SetEndian(SvStreamEndian::LITTLE
);
1707 aSrcMapMode
=rMTF
.GetPrefMapMode();
1711 aTargetMapMode
= aSrcMapMode
;
1712 aTargetSize
= rMTF
.GetPrefSize();
1713 sal_uInt16 nTargetDivisor
= CalcSaveTargetMapMode(aTargetMapMode
, aTargetSize
);
1714 aTargetSize
.Width() /= nTargetDivisor
;
1715 aTargetSize
.Height() /= nTargetDivisor
;
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
);
1733 for (bool & rn
: bHandleAllocated
)
1736 nDstPenHandle
=0xffff;
1737 nDstFontHandle
=0xffff;
1738 nDstBrushHandle
=0xffff;
1744 nActBitmapPercent
=0;
1746 CountActionsAndBitmaps(rMTF
);
1748 WriteHeader(rMTF
,bPlaceable
);
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;
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
);
1785 WriteRecordHeader(0x00000003,0x0000); // end of file
1791 pAttrStack
=pAt
->pSucc
;
1795 pVirDev
.disposeAndClear();
1797 if ( xStatusIndicator
.is() )
1798 xStatusIndicator
->end();
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();
1816 rMapMode
.SetScaleX(aFrac
);
1817 aFrac
= rMapMode
.GetScaleY();
1819 rMapMode
.SetScaleY(aFrac
);
1821 aSize
= OutputDevice::LogicToLogic( rPrefSize
, aSrcMapMode
, rMapMode
);
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
)
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
);
1851 nCheckSum
= static_cast< sal_uInt16
>( nCheckSum
* -1 );
1854 while( nRemainingSize
> 0 )
1856 sal_uInt32 nCurSize
;
1857 if( nRemainingSize
> 0x2000 )
1860 nRemainingSize
-= 0x2000;
1864 nCurSize
= nRemainingSize
;
1867 WriteEMFRecord( aStream
,
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: */