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 <sal/log.hxx>
26 #include <tools/helpers.hxx>
27 #include <tools/fract.hxx>
28 #include <tools/stream.hxx>
29 #include <basegfx/polygon/b2dpolygon.hxx>
30 #include <basegfx/polygon/b2dpolypolygon.hxx>
31 #include <vcl/lineinfo.hxx>
32 #include <vcl/dibtools.hxx>
33 #include <vcl/metaact.hxx>
36 #define WIN_EMR_POLYGON 3
37 #define WIN_EMR_POLYLINE 4
38 #define WIN_EMR_POLYBEZIERTO 5
39 #define WIN_EMR_POLYLINETO 6
40 #define WIN_EMR_POLYPOLYGON 8
41 #define WIN_EMR_SETWINDOWEXTEX 9
42 #define WIN_EMR_SETWINDOWORGEX 10
43 #define WIN_EMR_SETVIEWPORTEXTEX 11
44 #define WIN_EMR_SETVIEWPORTORGEX 12
45 #define WIN_EMR_EOF 14
46 #define WIN_EMR_SETPIXELV 15
47 #define WIN_EMR_SETMAPMODE 17
48 #define WIN_EMR_SETBKMODE 18
49 #define WIN_EMR_SETROP2 20
50 #define WIN_EMR_SETTEXTALIGN 22
51 #define WIN_EMR_SETTEXTCOLOR 24
52 #define WIN_EMR_MOVETOEX 27
53 #define WIN_EMR_INTERSECTCLIPRECT 30
54 #define WIN_EMR_SAVEDC 33
55 #define WIN_EMR_RESTOREDC 34
56 #define WIN_EMR_SELECTOBJECT 37
57 #define WIN_EMR_CREATEPEN 38
58 #define WIN_EMR_CREATEBRUSHINDIRECT 39
59 #define WIN_EMR_DELETEOBJECT 40
60 #define WIN_EMR_ELLIPSE 42
61 #define WIN_EMR_RECTANGLE 43
62 #define WIN_EMR_ROUNDRECT 44
63 #define WIN_EMR_LINETO 54
64 #define WIN_EMR_BEGINPATH 59
65 #define WIN_EMR_ENDPATH 60
66 #define WIN_EMR_CLOSEFIGURE 61
67 #define WIN_EMR_FILLPATH 62
68 #define WIN_EMR_STROKEPATH 64
70 #define WIN_EMR_GDICOMMENT 70
71 #define WIN_EMR_STRETCHDIBITS 81
72 #define WIN_EMR_EXTCREATEFONTINDIRECTW 82
73 #define WIN_EMR_EXTTEXTOUTW 84
75 #define WIN_SRCCOPY 0x00CC0020L
76 #define WIN_SRCPAINT 0x00EE0086L
77 #define WIN_SRCAND 0x008800C6L
78 #define WIN_SRCINVERT 0x00660046L
79 #define WIN_EMR_COMMENT_EMFPLUS 0x2B464D45L
81 #define HANDLE_INVALID 0xffffffff
82 #define MAXHANDLES 65000
84 #define LINE_SELECT 0x00000001
85 #define FILL_SELECT 0x00000002
86 #define TEXT_SELECT 0x00000004
88 /* Text Alignment Options */
93 #define TA_BASELINE 24
94 #define TA_RTLREADING 256
96 #define MM_ANISOTROPIC 8
98 enum class EmfPlusRecordType
103 FillPolygon
= 0x400C,
104 SetAntiAliasMode
= 0x401E,
105 SetInterpolationMode
= 0x4021,
106 SetPixelOffsetMode
= 0x4022,
107 SetCompositingQuality
= 0x4024
110 void EMFWriter::ImplBeginCommentRecord( sal_Int32 nCommentType
)
112 ImplBeginRecord( WIN_EMR_GDICOMMENT
);
114 m_rStm
.WriteInt32( nCommentType
);
117 void EMFWriter::ImplEndCommentRecord()
121 sal_uInt64 nActPos
= m_rStm
.Tell();
122 m_rStm
.Seek( mnRecordPos
+ 8 );
123 m_rStm
.WriteUInt32( nActPos
- mnRecordPos
- 0xc );
124 m_rStm
.Seek( nActPos
);
129 void EMFWriter::ImplBeginPlusRecord( EmfPlusRecordType nType
, sal_uInt16 nFlags
)
131 SAL_WARN_IF( mbRecordPlusOpen
, "vcl", "Another EMF+ record is already opened!" );
133 if( !mbRecordPlusOpen
)
135 mbRecordPlusOpen
= true;
136 mnRecordPlusPos
= m_rStm
.Tell();
138 m_rStm
.WriteUInt16( static_cast<sal_uInt16
>(nType
) ).WriteUInt16( nFlags
);
143 void EMFWriter::ImplEndPlusRecord()
145 SAL_WARN_IF( !mbRecordPlusOpen
, "vcl", "EMF+ Record was not opened!" );
147 if( mbRecordPlusOpen
)
149 sal_uInt64 nActPos
= m_rStm
.Tell();
150 sal_Int32 nSize
= nActPos
- mnRecordPlusPos
;
151 m_rStm
.Seek( mnRecordPlusPos
+ 4 );
152 m_rStm
.WriteUInt32( nSize
) // Size
153 .WriteUInt32( nSize
- 0xc ); // Data Size
154 m_rStm
.Seek( nActPos
);
155 mbRecordPlusOpen
= false;
159 void EMFWriter::ImplPlusRecord( EmfPlusRecordType nType
, sal_uInt16 nFlags
)
161 ImplBeginPlusRecord( nType
, nFlags
);
165 void EMFWriter::WriteEMFPlusHeader( const Size
&rMtfSizePix
, const Size
&rMtfSizeLog
)
167 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS
);
169 sal_Int32 nDPIX
= rMtfSizePix
.Width()*25;
170 sal_Int32 nDivX
= rMtfSizeLog
.Width()/100;
172 nDPIX
/= nDivX
; // DPI X
174 sal_Int32 nDPIY
= rMtfSizePix
.Height()*25;
175 sal_Int32 nDivY
= rMtfSizeLog
.Height()/100;
177 nDPIY
/= nDivY
; // DPI Y
179 m_rStm
.WriteInt16( sal_Int16(EmfPlusRecordType::Header
) );
180 m_rStm
.WriteInt16( 0x01 ) // Flags - Dual Mode // TODO: Check this
181 .WriteInt32( 0x1C ) // Size
182 .WriteInt32( 0x10 ) // Data Size
183 .WriteInt32( 0xdbc01002 ) // (lower 12bits) 1-> v1 2-> v1.1 // TODO: Check this
184 .WriteInt32( 0x01 ) // Video display
186 .WriteInt32( nDPIY
);
187 ImplEndCommentRecord();
189 // Write more properties
190 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS
);
191 ImplPlusRecord( EmfPlusRecordType::SetPixelOffsetMode
, 0x0 );
192 ImplPlusRecord( EmfPlusRecordType::SetAntiAliasMode
, 0x09 ); // TODO: Check actual values for AntiAlias
193 ImplPlusRecord( EmfPlusRecordType::SetCompositingQuality
, 0x0100 ); // Default Quality
194 ImplPlusRecord( EmfPlusRecordType::SetInterpolationMode
, 0x00 ); // Default
195 ImplPlusRecord( EmfPlusRecordType::GetDC
, 0x00 );
196 ImplEndCommentRecord();
199 void EMFWriter::ImplWritePlusEOF()
201 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS
);
202 ImplPlusRecord( EmfPlusRecordType::EndOfFile
, 0x0 );
203 ImplEndCommentRecord();
206 void EMFWriter::ImplWritePlusColor( const Color
& rColor
, sal_uInt32 nTrans
)
208 sal_uInt32 nAlpha
= ((100-nTrans
)*0xFF)/100;
209 sal_uInt32 nCol
= rColor
.GetBlue();
211 nCol
|= static_cast<sal_uInt32
>(rColor
.GetGreen()) << 8;
212 nCol
|= static_cast<sal_uInt32
>(rColor
.GetRed()) << 16;
213 nCol
|= ( nAlpha
<< 24 );
214 m_rStm
.WriteUInt32( nCol
);
217 void EMFWriter::ImplWritePlusPoint( const Point
& rPoint
)
220 const Point
aPoint(maVDev
->LogicToPixel( rPoint
, maDestMapMode
));
221 m_rStm
.WriteUInt16( aPoint
.X() ).WriteUInt16( aPoint
.Y() );
224 void EMFWriter::ImplWritePlusFillPolygonRecord( const tools::Polygon
& rPoly
, sal_uInt32 nTrans
)
226 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS
);
227 if( rPoly
.GetSize() )
229 ImplBeginPlusRecord( EmfPlusRecordType::FillPolygon
, 0xC000 ); // Sets the color as well
230 ImplWritePlusColor( maVDev
->GetFillColor(), nTrans
);
231 m_rStm
.WriteUInt32( rPoly
.GetSize() );
232 for( sal_uInt16 i
= 0; i
< rPoly
.GetSize(); i
++ )
233 ImplWritePlusPoint( rPoly
[ i
] );
236 ImplEndCommentRecord();
239 bool EMFWriter::WriteEMF(const GDIMetaFile
& rMtf
)
241 const sal_uInt64 nHeaderPos
= m_rStm
.Tell();
243 maVDev
->EnableOutput( false );
244 maVDev
->SetMapMode( rMtf
.GetPrefMapMode() );
245 // don't work with pixel as destination map mode -> higher resolution preferable
246 maDestMapMode
.SetMapUnit( MapUnit::Map100thMM
);
247 mHandlesUsed
= std::vector
<bool>(MAXHANDLES
, false);
248 mnHandleCount
= mnRecordCount
= mnRecordPos
= mnRecordPlusPos
= 0;
249 mbRecordOpen
= mbRecordPlusOpen
= false;
250 mbLineChanged
= mbFillChanged
= mbTextChanged
= false;
251 mnLineHandle
= mnFillHandle
= mnTextHandle
= HANDLE_INVALID
;
254 const Size
aMtfSizePix( maVDev
->LogicToPixel( rMtf
.GetPrefSize(), rMtf
.GetPrefMapMode() ) );
255 const Size
aMtfSizeLog( OutputDevice::LogicToLogic(rMtf
.GetPrefSize(), rMtf
.GetPrefMapMode(), MapMode(MapUnit::Map100thMM
)) );
258 // use [MS-EMF 2.2.11] HeaderExtension2 Object, otherwise resulting EMF cannot be converted with GetWinMetaFileBits()
259 m_rStm
.SeekRel( 108 );
262 WriteEMFPlusHeader( aMtfSizePix
, aMtfSizeLog
);
264 // write initial values
266 // set 100th mm map mode in EMF
267 ImplBeginRecord( WIN_EMR_SETMAPMODE
);
268 m_rStm
.WriteInt32( MM_ANISOTROPIC
);
271 ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX
);
272 m_rStm
.WriteInt32( maVDev
->GetDPIX() ).WriteInt32( maVDev
->GetDPIY() );
275 ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX
);
276 m_rStm
.WriteInt32( 2540 ).WriteInt32( 2540 );
279 ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX
);
280 m_rStm
.WriteInt32( 0 ).WriteInt32( 0 );
283 ImplBeginRecord( WIN_EMR_SETWINDOWORGEX
);
284 m_rStm
.WriteInt32( 0 ).WriteInt32( 0 );
287 ImplWriteRasterOp( RasterOp::OverPaint
);
289 ImplBeginRecord( WIN_EMR_SETBKMODE
);
290 m_rStm
.WriteUInt32( 1 ); // TRANSPARENT
298 ImplBeginRecord( WIN_EMR_EOF
);
299 m_rStm
.WriteUInt32( 0 ) // nPalEntries
300 .WriteUInt32( 0x10 ) // offPalEntries
301 .WriteUInt32( 0x14 ); // nSizeLast
305 const sal_uInt64 nEndPos
= m_rStm
.Tell(); m_rStm
.Seek( nHeaderPos
);
307 m_rStm
.WriteUInt32( 0x00000001 ).WriteUInt32( 108 ) //use [MS-EMF 2.2.11] HeaderExtension2 Object
308 .WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aMtfSizePix
.Width() - 1 ).WriteInt32( aMtfSizePix
.Height() - 1 )
309 .WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aMtfSizeLog
.Width() - 1 ).WriteInt32( aMtfSizeLog
.Height() - 1 )
310 .WriteUInt32( 0x464d4520 ).WriteUInt32( 0x10000 ).WriteUInt32( nEndPos
- nHeaderPos
)
311 .WriteUInt32( mnRecordCount
).WriteUInt16( mnHandleCount
+ 1 ).WriteUInt16( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
312 .WriteInt32( aMtfSizePix
.Width() ).WriteInt32( aMtfSizePix
.Height() )
313 .WriteInt32( aMtfSizeLog
.Width() / 100 ).WriteInt32( aMtfSizeLog
.Height() / 100 )
314 .WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
315 .WriteInt32( aMtfSizeLog
.Width() * 10 ).WriteInt32( aMtfSizeLog
.Height() * 10 ); //use [MS-EMF 2.2.11] HeaderExtension2 Object
317 m_rStm
.Seek( nEndPos
);
318 mHandlesUsed
.clear();
320 return( m_rStm
.GetError() == ERRCODE_NONE
);
323 sal_uLong
EMFWriter::ImplAcquireHandle()
325 sal_uLong nHandle
= HANDLE_INVALID
;
327 for( sal_uLong i
= 0; i
< mHandlesUsed
.size() && ( HANDLE_INVALID
== nHandle
); i
++ )
329 if( !mHandlesUsed
[ i
] )
331 mHandlesUsed
[ i
] = true;
333 if( ( nHandle
= i
) == mnHandleCount
)
338 SAL_WARN_IF( nHandle
== HANDLE_INVALID
, "vcl", "No more handles available" );
339 return( nHandle
!= HANDLE_INVALID
? nHandle
+ 1 : HANDLE_INVALID
);
342 void EMFWriter::ImplReleaseHandle( sal_uLong nHandle
)
344 SAL_WARN_IF( !nHandle
|| ( nHandle
>= mHandlesUsed
.size() ), "vcl", "Handle out of range" );
345 mHandlesUsed
[ nHandle
- 1 ] = false;
348 void EMFWriter::ImplBeginRecord( sal_uInt32 nType
)
350 SAL_WARN_IF( mbRecordOpen
, "vcl", "Another record is already opened!" );
355 mnRecordPos
= m_rStm
.Tell();
357 m_rStm
.WriteUInt32( nType
);
362 void EMFWriter::ImplEndRecord()
364 SAL_WARN_IF( !mbRecordOpen
, "vcl", "Record was not opened!" );
369 sal_Int32 nFillBytes
;
370 sal_uInt64 nActPos
= m_rStm
.Tell();
371 m_rStm
.Seek( mnRecordPos
+ 4 );
372 nFillBytes
= nActPos
- mnRecordPos
;
373 nFillBytes
+= 3; // each record has to be dword aligned
376 m_rStm
.WriteUInt32( ( nActPos
- mnRecordPos
) + nFillBytes
);
377 m_rStm
.Seek( nActPos
);
378 while( nFillBytes
-- )
379 m_rStm
.WriteUChar( 0 );
381 mbRecordOpen
= false;
385 bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32
& rHandle
, sal_uLong nSelectType
)
387 if( rHandle
!= HANDLE_INVALID
)
389 sal_uInt32 nStockObject
= 0x80000000;
391 if( LINE_SELECT
== nSelectType
)
392 nStockObject
|= 0x00000007;
393 else if( FILL_SELECT
== nSelectType
)
394 nStockObject
|= 0x00000001;
395 else if( TEXT_SELECT
== nSelectType
)
396 nStockObject
|= 0x0000000a;
398 // select stock object first
399 ImplBeginRecord( WIN_EMR_SELECTOBJECT
);
400 m_rStm
.WriteUInt32( nStockObject
);
403 // destroy handle of created object
404 ImplBeginRecord( WIN_EMR_DELETEOBJECT
);
405 m_rStm
.WriteUInt32( rHandle
);
408 // mark handle as free
409 ImplReleaseHandle( rHandle
);
412 rHandle
= ImplAcquireHandle();
414 return( HANDLE_INVALID
!= rHandle
);
417 void EMFWriter::ImplCheckLineAttr()
419 if( !(mbLineChanged
&& ImplPrepareHandleSelect( mnLineHandle
, LINE_SELECT
)) )
422 sal_uInt32 nStyle
= maVDev
->IsLineColor() ? 0 : 5;
424 ImplBeginRecord( WIN_EMR_CREATEPEN
);
425 m_rStm
.WriteUInt32( mnLineHandle
).WriteUInt32( nStyle
).WriteUInt32( 0/*nWidth*/ ).WriteUInt32( 0/*nHeight*/ );
426 ImplWriteColor( maVDev
->GetLineColor() );
429 ImplBeginRecord( WIN_EMR_SELECTOBJECT
);
430 m_rStm
.WriteUInt32( mnLineHandle
);
434 void EMFWriter::ImplCheckFillAttr()
436 if( !(mbFillChanged
&& ImplPrepareHandleSelect( mnFillHandle
, FILL_SELECT
)) )
439 sal_uInt32 nStyle
= maVDev
->IsFillColor() ? 0 : 1;
441 ImplBeginRecord( WIN_EMR_CREATEBRUSHINDIRECT
);
442 m_rStm
.WriteUInt32( mnFillHandle
).WriteUInt32( nStyle
);
443 ImplWriteColor( maVDev
->GetFillColor() );
444 m_rStm
.WriteUInt32( 0/*nPatternStyle*/ );
447 ImplBeginRecord( WIN_EMR_SELECTOBJECT
);
448 m_rStm
.WriteUInt32( mnFillHandle
);
452 void EMFWriter::ImplCheckTextAttr()
454 if( !(mbTextChanged
&& ImplPrepareHandleSelect( mnTextHandle
, TEXT_SELECT
)) )
457 const vcl::Font
& rFont
= maVDev
->GetFont();
458 const OUString
& aFontName( rFont
.GetFamilyName() );
461 sal_uInt8 nPitchAndFamily
;
463 // tdf#127471 adapt nFontWidth from NormedFontScaling to
464 // Windows-like notation if used for text scaling
465 const tools::Long
nFontHeight(rFont
.GetFontSize().Height());
466 tools::Long
nFontWidth(rFont
.GetFontSize().Width());
469 const bool bFontScaledHorizontally(nFontWidth
!= 0 && nFontWidth
!= nFontHeight
);
471 if(bFontScaledHorizontally
)
473 // tdf#127471 nFontWidth is the non-Windows NormedFontScaling, need to convert to
474 // Windows-like notation with pre-multiplied AvgFontWidth since EMF/WMF are Windows
476 const tools::Long
nAverageFontWidth(rFont
.GetOrCalculateAverageFontWidth());
480 const double fScaleFactor(static_cast<double>(nAverageFontWidth
) / static_cast<double>(nFontHeight
));
481 nFontWidth
= static_cast<tools::Long
>(static_cast<double>(nFontWidth
) * fScaleFactor
);
486 ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW
);
487 m_rStm
.WriteUInt32( mnTextHandle
);
488 ImplWriteExtent( -nFontHeight
);
489 ImplWriteExtent( nFontWidth
);
490 m_rStm
.WriteInt32( rFont
.GetOrientation().get() ).WriteInt32( rFont
.GetOrientation().get() );
492 switch( rFont
.GetWeight() )
494 case WEIGHT_THIN
: nWeight
= 100; break;
495 case WEIGHT_ULTRALIGHT
: nWeight
= 200; break;
496 case WEIGHT_LIGHT
: nWeight
= 300; break;
497 case WEIGHT_SEMILIGHT
: nWeight
= 300; break;
498 case WEIGHT_NORMAL
: nWeight
= 400; break;
499 case WEIGHT_MEDIUM
: nWeight
= 500; break;
500 case WEIGHT_SEMIBOLD
: nWeight
= 600; break;
501 case WEIGHT_BOLD
: nWeight
= 700; break;
502 case WEIGHT_ULTRABOLD
: nWeight
= 800; break;
503 case WEIGHT_BLACK
: nWeight
= 900; break;
504 default: nWeight
= 0; break;
507 m_rStm
.WriteInt32( nWeight
);
508 m_rStm
.WriteUChar( ( ITALIC_NONE
== rFont
.GetItalic() ) ? 0 : 1 );
509 m_rStm
.WriteUChar( ( LINESTYLE_NONE
== rFont
.GetUnderline() ) ? 0 : 1 );
510 m_rStm
.WriteUChar( ( STRIKEOUT_NONE
== rFont
.GetStrikeout() ) ? 0 : 1 );
511 m_rStm
.WriteUChar( ( RTL_TEXTENCODING_SYMBOL
== rFont
.GetCharSet() ) ? 2 : 0 );
512 m_rStm
.WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
514 switch( rFont
.GetPitch() )
516 case PITCH_FIXED
: nPitchAndFamily
= 0x01; break;
517 case PITCH_VARIABLE
: nPitchAndFamily
= 0x02; break;
518 default: nPitchAndFamily
= 0x00; break;
521 switch( rFont
.GetFamilyType() )
523 case FAMILY_DECORATIVE
: nPitchAndFamily
|= 0x50; break;
524 case FAMILY_MODERN
: nPitchAndFamily
|= 0x30; break;
525 case FAMILY_ROMAN
: nPitchAndFamily
|= 0x10; break;
526 case FAMILY_SCRIPT
: nPitchAndFamily
|= 0x40; break;
527 case FAMILY_SWISS
: nPitchAndFamily
|= 0x20; break;
531 m_rStm
.WriteUChar( nPitchAndFamily
);
533 for( i
= 0; i
< 32; i
++ )
534 m_rStm
.WriteUInt16( ( i
< aFontName
.getLength() ) ? aFontName
[ i
] : 0 );
537 for( i
= 0; i
< 64; i
++ )
538 m_rStm
.WriteUInt16( 0 );
541 for( i
= 0; i
< 32; i
++ )
542 m_rStm
.WriteUInt16( 0 );
544 // dummy elfVersion, elfStyleSize, elfMatch, elfReserved
545 m_rStm
.WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ) ;
548 m_rStm
.WriteUInt32( 0 );
551 m_rStm
.WriteUInt32( 0 );
554 m_rStm
.WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
556 // fill record to get a record size divideable by 4
557 m_rStm
.WriteUInt16( 0 );
562 sal_uInt32 nTextAlign
;
564 switch( rFont
.GetAlignment() )
566 case ALIGN_TOP
: nTextAlign
= TA_TOP
; break;
567 case ALIGN_BOTTOM
: nTextAlign
= TA_BOTTOM
; break;
568 default: nTextAlign
= TA_BASELINE
; break;
570 nTextAlign
|= mnHorTextAlign
;
572 ImplBeginRecord( WIN_EMR_SETTEXTALIGN
);
573 m_rStm
.WriteUInt32( nTextAlign
);
577 ImplBeginRecord( WIN_EMR_SETTEXTCOLOR
);
578 ImplWriteColor( maVDev
->GetTextColor() );
581 ImplBeginRecord( WIN_EMR_SELECTOBJECT
);
582 m_rStm
.WriteUInt32( mnTextHandle
);
587 void EMFWriter::ImplWriteColor( const Color
& rColor
)
589 sal_uInt32 nCol
= rColor
.GetRed();
591 nCol
|= static_cast<sal_uInt32
>(rColor
.GetGreen()) << 8;
592 nCol
|= static_cast<sal_uInt32
>(rColor
.GetBlue()) << 16;
594 m_rStm
.WriteUInt32( nCol
);
597 void EMFWriter::ImplWriteRasterOp( RasterOp eRop
)
603 case RasterOp::Invert
: nROP2
= 6; break;
604 case RasterOp::Xor
: nROP2
= 7; break;
605 default: nROP2
= 13;break;
608 ImplBeginRecord( WIN_EMR_SETROP2
);
609 m_rStm
.WriteUInt32( nROP2
);
613 void EMFWriter::ImplWriteExtent( tools::Long nExtent
)
615 nExtent
= OutputDevice::LogicToLogic( Size( nExtent
, 0 ), maVDev
->GetMapMode(), maDestMapMode
).Width();
616 m_rStm
.WriteInt32( nExtent
);
619 void EMFWriter::ImplWritePoint( const Point
& rPoint
)
621 const Point
aPoint( OutputDevice::LogicToLogic( rPoint
, maVDev
->GetMapMode(), maDestMapMode
));
622 m_rStm
.WriteInt32( aPoint
.X() ).WriteInt32( aPoint
.Y() );
625 void EMFWriter::ImplWriteSize( const Size
& rSize
)
627 const Size
aSize( OutputDevice::LogicToLogic( rSize
, maVDev
->GetMapMode(), maDestMapMode
));
628 m_rStm
.WriteInt32( aSize
.Width() ).WriteInt32( aSize
.Height() );
631 void EMFWriter::ImplWriteRect( const tools::Rectangle
& rRect
)
633 const tools::Rectangle
aRect( OutputDevice::LogicToLogic ( rRect
, maVDev
->GetMapMode(), maDestMapMode
));
634 auto right
= aRect
.IsWidthEmpty() ? aRect
.Left() : aRect
.Right();
635 auto bottom
= aRect
.IsHeightEmpty() ? aRect
.Top() : aRect
.Bottom();
637 .WriteInt32( aRect
.Left() )
638 .WriteInt32( aRect
.Top() )
640 .WriteInt32( bottom
);
643 void EMFWriter::ImplWritePolygonRecord( const tools::Polygon
& rPoly
, bool bClose
)
645 if( !rPoly
.GetSize() )
648 if( rPoly
.HasFlags() )
649 ImplWritePath( tools::PolyPolygon(rPoly
), bClose
);
657 ImplBeginRecord( bClose
? WIN_EMR_POLYGON
: WIN_EMR_POLYLINE
);
658 ImplWriteRect( rPoly
.GetBoundRect() );
659 m_rStm
.WriteUInt32( rPoly
.GetSize() );
661 for( sal_uInt16 i
= 0; i
< rPoly
.GetSize(); i
++ )
662 ImplWritePoint( rPoly
[ i
] );
668 void EMFWriter::ImplWritePolyPolygonRecord( const tools::PolyPolygon
& rPolyPoly
)
670 sal_uInt16 n
, i
, nPolyCount
= rPolyPoly
.Count();
675 if( 1 == nPolyCount
)
676 ImplWritePolygonRecord( rPolyPoly
[ 0 ], true );
679 bool bHasFlags
= false;
680 sal_uInt32 nTotalPoints
= 0;
682 for( i
= 0; i
< nPolyCount
; i
++ )
684 nTotalPoints
+= rPolyPoly
[ i
].GetSize();
685 if ( rPolyPoly
[ i
].HasFlags() )
691 ImplWritePath( rPolyPoly
, true );
697 ImplBeginRecord( WIN_EMR_POLYPOLYGON
);
698 ImplWriteRect( rPolyPoly
.GetBoundRect() );
699 m_rStm
.WriteUInt32( nPolyCount
).WriteUInt32( nTotalPoints
);
701 for( auto const& rPoly
: rPolyPoly
)
702 m_rStm
.WriteUInt32( rPoly
.GetSize() );
704 for( auto const& rPoly
: rPolyPoly
)
706 for( n
= 0; n
< rPoly
.GetSize(); n
++ )
707 ImplWritePoint( rPoly
[ n
] );
715 void EMFWriter::ImplWritePath( const tools::PolyPolygon
& rPolyPoly
, bool bClosed
)
721 ImplBeginRecord( WIN_EMR_BEGINPATH
);
725 for ( auto const& rPoly
: rPolyPoly
)
728 while ( n
< rPoly
.GetSize() )
732 ImplBeginRecord( WIN_EMR_MOVETOEX
);
733 ImplWritePoint( rPoly
[ 0 ] );
739 sal_uInt16 nBezPoints
= 0;
741 while ( ( ( nBezPoints
+ n
+ 2 ) < rPoly
.GetSize() ) && ( rPoly
.GetFlags( nBezPoints
+ n
) == PolyFlags::Control
) )
746 ImplBeginRecord( WIN_EMR_POLYBEZIERTO
);
747 tools::Polygon
aNewPoly( nBezPoints
+ 1 );
748 aNewPoly
[ 0 ] = rPoly
[ n
- 1 ];
749 for ( o
= 0; o
< nBezPoints
; o
++ )
750 aNewPoly
[ o
+ 1 ] = rPoly
[ n
+ o
];
751 ImplWriteRect( aNewPoly
.GetBoundRect() );
752 m_rStm
.WriteUInt32( nBezPoints
);
753 for( o
= 1; o
< aNewPoly
.GetSize(); o
++ )
754 ImplWritePoint( aNewPoly
[ o
] );
760 sal_uInt16 nPoints
= 1;
761 while( ( nPoints
+ n
) < rPoly
.GetSize() && ( rPoly
.GetFlags( nPoints
+ n
) != PolyFlags::Control
) )
766 ImplBeginRecord( WIN_EMR_POLYLINETO
);
767 tools::Polygon
aNewPoly( nPoints
+ 1 );
768 aNewPoly
[ 0 ] = rPoly
[ n
- 1];
769 for ( o
= 1; o
<= nPoints
; o
++ )
770 aNewPoly
[ o
] = rPoly
[ n
- 1 + o
];
771 ImplWriteRect( aNewPoly
.GetBoundRect() );
772 m_rStm
.WriteUInt32( nPoints
);
773 for( o
= 1; o
< aNewPoly
.GetSize(); o
++ )
774 ImplWritePoint( aNewPoly
[ o
] );
779 ImplBeginRecord( WIN_EMR_LINETO
);
780 ImplWritePoint( rPoly
[ n
] );
785 if ( bClosed
&& ( n
== rPoly
.GetSize() ) )
787 ImplBeginRecord( WIN_EMR_CLOSEFIGURE
);
792 ImplBeginRecord( WIN_EMR_ENDPATH
);
794 ImplBeginRecord( bClosed
? WIN_EMR_FILLPATH
: WIN_EMR_STROKEPATH
);
795 ImplWriteRect( rPolyPoly
.GetBoundRect() );
799 void EMFWriter::ImplWriteBmpRecord( const Bitmap
& rBmp
, const Point
& rPt
,
800 const Size
& rSz
, sal_uInt32 nROP
)
805 SvMemoryStream
aMemStm( 65535, 65535 );
806 const Size
aBmpSizePixel( rBmp
.GetSizePixel() );
808 ImplBeginRecord( WIN_EMR_STRETCHDIBITS
);
809 ImplWriteRect( tools::Rectangle( rPt
, rSz
) );
810 ImplWritePoint( rPt
);
811 m_rStm
.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aBmpSizePixel
.Width() ).WriteInt32( aBmpSizePixel
.Height() );
813 // write offset positions and sizes later
814 const sal_uInt64 nOffPos
= m_rStm
.Tell();
815 m_rStm
.SeekRel( 16 );
817 m_rStm
.WriteUInt32( 0 ).WriteInt32( ( RasterOp::Xor
== maVDev
->GetRasterOp() && WIN_SRCCOPY
== nROP
) ? WIN_SRCINVERT
: nROP
);
818 ImplWriteSize( rSz
);
820 WriteDIB(rBmp
, aMemStm
, true, false);
822 sal_uInt64 nDIBSize
= aMemStm
.Tell();
823 sal_uInt32 nHeaderSize
, nCompression
, nColsUsed
, nPalCount
, nImageSize
;
824 sal_uInt16 nBitCount
;
826 // get DIB parameters
828 aMemStm
.ReadUInt32( nHeaderSize
);
829 aMemStm
.SeekRel( 10 );
830 aMemStm
.ReadUInt16( nBitCount
).ReadUInt32( nCompression
).ReadUInt32( nImageSize
);
831 aMemStm
.SeekRel( 8 );
832 aMemStm
.ReadUInt32( nColsUsed
);
837 nPalCount
= nColsUsed
;
839 nPalCount
= 1 << static_cast<sal_uInt32
>(nBitCount
);
843 if (nCompression
== BITFIELDS
)
849 sal_uInt32 nPalSize
= nPalCount
* 4;
851 m_rStm
.WriteBytes( aMemStm
.GetData(), nDIBSize
);
853 const sal_uInt64 nEndPos
= m_rStm
.Tell();
854 m_rStm
.Seek( nOffPos
);
855 m_rStm
.WriteUInt32( 80 ).WriteUInt32( nHeaderSize
+ nPalSize
);
856 m_rStm
.WriteUInt32( 80 + nHeaderSize
+ nPalSize
).WriteUInt32( nImageSize
);
857 m_rStm
.Seek( nEndPos
);
863 void EMFWriter::ImplWriteTextRecord( const Point
& rPos
, const OUString
& rText
, KernArraySpan pDXArray
, sal_uInt32 nWidth
)
865 sal_Int32 nLen
= rText
.getLength(), i
;
870 sal_uInt32 nNormWidth
;
875 if( !pDXArray
.empty() )
877 nNormWidth
= maVDev
->GetTextWidth( rText
);
882 nNormWidth
= basegfx::fround
<sal_uInt32
>(maVDev
->GetTextArray(rText
, &aOwnArray
).nWidth
);
888 nNormWidth
= pDX
[ nLen
- 2 ] + maVDev
->GetTextWidth( OUString(rText
[ nLen
- 1 ]) );
890 if( nWidth
&& nNormWidth
&& ( nWidth
!= nNormWidth
) )
892 if (!pDXArray
.empty())
894 aOwnArray
.assign(pDXArray
.begin(), pDXArray
.end());
897 const double fFactor
= static_cast<double>(nWidth
) / nNormWidth
;
899 for( i
= 0; i
< ( nLen
- 1 ); i
++ )
900 aOwnArray
[i
] *= fFactor
;
905 ImplBeginRecord( WIN_EMR_EXTTEXTOUTW
);
907 ImplWriteRect( tools::Rectangle( rPos
, Size( nNormWidth
, maVDev
->GetTextHeight() ) ) );
908 m_rStm
.WriteUInt32( 1 );
909 m_rStm
.WriteInt32( 0 ).WriteInt32( 0 );
910 ImplWritePoint( rPos
);
911 m_rStm
.WriteUInt32( nLen
).WriteUInt32( 76 ).WriteUInt32( 2 );
912 m_rStm
.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 );
913 m_rStm
.WriteUInt32( 76 + ( nLen
<< 1 ) + ( (nLen
& 1 ) ? 2 : 0 ) );
916 for( i
= 0; i
< nLen
; i
++ )
917 m_rStm
.WriteUInt16( rText
[ i
] );
921 m_rStm
.WriteUInt16( 0 );
924 ImplWriteExtent( pDX
[ 0 ] );
928 for (i
= 1; i
< nLen
; i
++)
929 ImplWriteExtent( pDX
[ i
] - pDX
[ i
- 1 ] );
936 void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo
& rInfo
, const basegfx::B2DPolygon
& rLinePolygon
)
938 if(!rLinePolygon
.count())
941 basegfx::B2DPolyPolygon
aLinePolyPolygon(rLinePolygon
);
942 basegfx::B2DPolyPolygon aFillPolyPolygon
;
944 rInfo
.applyToB2DPolyPolygon(aLinePolyPolygon
, aFillPolyPolygon
);
946 if(aLinePolyPolygon
.count())
948 for(auto const& rB2DPolygon
: std::as_const(aLinePolyPolygon
))
950 ImplWritePolygonRecord( tools::Polygon(rB2DPolygon
), false );
954 if(!aFillPolyPolygon
.count())
957 const Color
aOldLineColor(maVDev
->GetLineColor());
958 const Color
aOldFillColor(maVDev
->GetFillColor());
960 maVDev
->SetLineColor();
961 maVDev
->SetFillColor(aOldLineColor
);
963 for(auto const& rB2DPolygon
: std::as_const(aFillPolyPolygon
))
965 ImplWritePolyPolygonRecord(tools::PolyPolygon( tools::Polygon(rB2DPolygon
) ));
968 maVDev
->SetLineColor(aOldLineColor
);
969 maVDev
->SetFillColor(aOldFillColor
);
972 void EMFWriter::ImplWrite( const GDIMetaFile
& rMtf
)
974 for( size_t j
= 0, nActionCount
= rMtf
.GetActionSize(); j
< nActionCount
; j
++ )
976 const MetaAction
* pAction
= rMtf
.GetAction( j
);
977 const MetaActionType nType
= pAction
->GetType();
981 case MetaActionType::PIXEL
:
983 const MetaPixelAction
* pA
= static_cast<const MetaPixelAction
*>(pAction
);
986 ImplBeginRecord( WIN_EMR_SETPIXELV
);
987 ImplWritePoint( pA
->GetPoint() );
988 ImplWriteColor( pA
->GetColor() );
993 case MetaActionType::POINT
:
995 if( maVDev
->IsLineColor() )
997 const MetaPointAction
* pA
= static_cast<const MetaPointAction
*>(pAction
);
1000 ImplBeginRecord( WIN_EMR_SETPIXELV
);
1001 ImplWritePoint( pA
->GetPoint() );
1002 ImplWriteColor( maVDev
->GetLineColor() );
1008 case MetaActionType::LINE
:
1010 if( maVDev
->IsLineColor() )
1012 const MetaLineAction
* pA
= static_cast<const MetaLineAction
*>(pAction
);
1014 if(pA
->GetLineInfo().IsDefault())
1016 ImplCheckLineAttr();
1018 ImplBeginRecord( WIN_EMR_MOVETOEX
);
1019 ImplWritePoint( pA
->GetStartPoint() );
1022 ImplBeginRecord( WIN_EMR_LINETO
);
1023 ImplWritePoint( pA
->GetEndPoint() );
1026 ImplBeginRecord( WIN_EMR_SETPIXELV
);
1027 ImplWritePoint( pA
->GetEndPoint() );
1028 ImplWriteColor( maVDev
->GetLineColor() );
1033 // LineInfo used; handle Dash/Dot and fat lines
1034 basegfx::B2DPolygon aPolygon
;
1035 aPolygon
.append(basegfx::B2DPoint(pA
->GetStartPoint().X(), pA
->GetStartPoint().Y()));
1036 aPolygon
.append(basegfx::B2DPoint(pA
->GetEndPoint().X(), pA
->GetEndPoint().Y()));
1037 Impl_handleLineInfoPolyPolygons(pA
->GetLineInfo(), aPolygon
);
1043 case MetaActionType::RECT
:
1045 if( maVDev
->IsLineColor() || maVDev
->IsFillColor() )
1047 const MetaRectAction
* pA
= static_cast<const MetaRectAction
*>(pAction
);
1049 ImplCheckFillAttr();
1050 ImplCheckLineAttr();
1052 ImplBeginRecord( WIN_EMR_RECTANGLE
);
1053 ImplWriteRect( pA
->GetRect() );
1059 case MetaActionType::ROUNDRECT
:
1061 if( maVDev
->IsLineColor() || maVDev
->IsFillColor() )
1063 const MetaRoundRectAction
* pA
= static_cast<const MetaRoundRectAction
*>(pAction
);
1065 ImplCheckFillAttr();
1066 ImplCheckLineAttr();
1068 ImplBeginRecord( WIN_EMR_ROUNDRECT
);
1069 ImplWriteRect( pA
->GetRect() );
1070 ImplWriteSize( Size( pA
->GetHorzRound(), pA
->GetVertRound() ) );
1076 case MetaActionType::ELLIPSE
:
1078 if( maVDev
->IsLineColor() || maVDev
->IsFillColor() )
1080 const MetaEllipseAction
* pA
= static_cast<const MetaEllipseAction
*>(pAction
);
1082 ImplCheckFillAttr();
1083 ImplCheckLineAttr();
1085 ImplBeginRecord( WIN_EMR_ELLIPSE
);
1086 ImplWriteRect( pA
->GetRect() );
1092 case MetaActionType::ARC
:
1093 case MetaActionType::PIE
:
1094 case MetaActionType::CHORD
:
1095 case MetaActionType::POLYGON
:
1097 if( maVDev
->IsLineColor() || maVDev
->IsFillColor() )
1099 tools::Polygon aPoly
;
1103 case MetaActionType::ARC
:
1105 const MetaArcAction
* pA
= static_cast<const MetaArcAction
*>(pAction
);
1106 aPoly
= tools::Polygon( pA
->GetRect(), pA
->GetStartPoint(), pA
->GetEndPoint(), PolyStyle::Arc
);
1110 case MetaActionType::PIE
:
1112 const MetaPieAction
* pA
= static_cast<const MetaPieAction
*>(pAction
);
1113 aPoly
= tools::Polygon( pA
->GetRect(), pA
->GetStartPoint(), pA
->GetEndPoint(), PolyStyle::Pie
);
1117 case MetaActionType::CHORD
:
1119 const MetaChordAction
* pA
= static_cast<const MetaChordAction
*>(pAction
);
1120 aPoly
= tools::Polygon( pA
->GetRect(), pA
->GetStartPoint(), pA
->GetEndPoint(), PolyStyle::Chord
);
1124 case MetaActionType::POLYGON
:
1125 aPoly
= static_cast<const MetaPolygonAction
*>(pAction
)->GetPolygon();
1130 ImplWritePolygonRecord( aPoly
, nType
!= MetaActionType::ARC
);
1135 case MetaActionType::POLYLINE
:
1137 if( maVDev
->IsLineColor() )
1139 const MetaPolyLineAction
* pA
= static_cast<const MetaPolyLineAction
*>(pAction
);
1140 const tools::Polygon
& rPoly
= pA
->GetPolygon();
1142 if( rPoly
.GetSize() )
1144 if(pA
->GetLineInfo().IsDefault())
1146 ImplWritePolygonRecord( rPoly
, false );
1150 // LineInfo used; handle Dash/Dot and fat lines
1151 Impl_handleLineInfoPolyPolygons(pA
->GetLineInfo(), rPoly
.getB2DPolygon());
1158 case MetaActionType::POLYPOLYGON
:
1160 if( maVDev
->IsLineColor() || maVDev
->IsFillColor() )
1161 ImplWritePolyPolygonRecord( static_cast<const MetaPolyPolygonAction
*>(pAction
)->GetPolyPolygon() );
1165 case MetaActionType::GRADIENT
:
1167 const MetaGradientAction
* pA
= static_cast<const MetaGradientAction
*>(pAction
);
1168 GDIMetaFile aTmpMtf
;
1170 Gradient aGradient
= pA
->GetGradient();
1171 aGradient
.AddGradientActions( pA
->GetRect(), aTmpMtf
);
1172 ImplWrite( aTmpMtf
);
1176 case MetaActionType::HATCH
:
1178 const MetaHatchAction
* pA
= static_cast<const MetaHatchAction
*>(pAction
);
1179 GDIMetaFile aTmpMtf
;
1181 maVDev
->AddHatchActions( pA
->GetPolyPolygon(), pA
->GetHatch(), aTmpMtf
);
1182 ImplWrite( aTmpMtf
);
1186 case MetaActionType::Transparent
:
1188 const tools::PolyPolygon
& rPolyPoly
= static_cast<const MetaTransparentAction
*>(pAction
)->GetPolyPolygon();
1189 if( rPolyPoly
.Count() )
1190 ImplWritePlusFillPolygonRecord( rPolyPoly
[0], static_cast<const MetaTransparentAction
*>(pAction
)->GetTransparence() );
1191 ImplCheckFillAttr();
1192 ImplCheckLineAttr();
1193 ImplWritePolyPolygonRecord( rPolyPoly
);
1195 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS
);
1196 ImplPlusRecord( EmfPlusRecordType::GetDC
, 0x00 );
1197 ImplEndCommentRecord();
1201 case MetaActionType::FLOATTRANSPARENT
:
1203 const MetaFloatTransparentAction
* pA
= static_cast<const MetaFloatTransparentAction
*>(pAction
);
1205 GDIMetaFile
aTmpMtf( pA
->GetGDIMetaFile() );
1206 Point
aSrcPt( aTmpMtf
.GetPrefMapMode().GetOrigin() );
1207 const Size
aSrcSize( aTmpMtf
.GetPrefSize() );
1208 const Point
aDestPt( pA
->GetPoint() );
1209 const Size
aDestSize( pA
->GetSize() );
1210 const double fScaleX
= aSrcSize
.Width() ? static_cast<double>(aDestSize
.Width()) / aSrcSize
.Width() : 1.0;
1211 const double fScaleY
= aSrcSize
.Height() ? static_cast<double>(aDestSize
.Height()) / aSrcSize
.Height() : 1.0;
1212 tools::Long nMoveX
, nMoveY
;
1214 if( fScaleX
!= 1.0 || fScaleY
!= 1.0 )
1216 aTmpMtf
.Scale( fScaleX
, fScaleY
);
1217 aSrcPt
.setX(basegfx::fround
<tools::Long
>(aSrcPt
.X() * fScaleX
));
1218 aSrcPt
.setY(basegfx::fround
<tools::Long
>(aSrcPt
.Y() * fScaleY
));
1221 nMoveX
= aDestPt
.X() - aSrcPt
.X();
1222 nMoveY
= aDestPt
.Y() - aSrcPt
.Y();
1224 if( nMoveX
|| nMoveY
)
1225 aTmpMtf
.Move( nMoveX
, nMoveY
);
1227 ImplCheckFillAttr();
1228 ImplCheckLineAttr();
1229 ImplCheckTextAttr();
1230 ImplWrite( aTmpMtf
);
1234 case MetaActionType::EPS
:
1236 const MetaEPSAction
* pA
= static_cast<const MetaEPSAction
*>(pAction
);
1237 const GDIMetaFile
& aSubstitute( pA
->GetSubstitute() );
1239 for( size_t i
= 0, nCount
= aSubstitute
.GetActionSize(); i
< nCount
; i
++ )
1241 const MetaAction
* pSubstAct
= aSubstitute
.GetAction( i
);
1242 if( pSubstAct
->GetType() == MetaActionType::BMPSCALE
)
1245 ImplBeginRecord( WIN_EMR_SAVEDC
);
1248 MapMode
aMapMode( aSubstitute
.GetPrefMapMode() );
1249 Size
aOutSize( OutputDevice::LogicToLogic( pA
->GetSize(), maVDev
->GetMapMode(), aMapMode
) );
1250 aMapMode
.SetScaleX( Fraction( aOutSize
.Width(), aSubstitute
.GetPrefSize().Width() ) );
1251 aMapMode
.SetScaleY( Fraction( aOutSize
.Height(), aSubstitute
.GetPrefSize().Height() ) );
1252 aMapMode
.SetOrigin( OutputDevice::LogicToLogic( pA
->GetPoint(), maVDev
->GetMapMode(), aMapMode
) );
1253 maVDev
->SetMapMode( aMapMode
);
1254 ImplWrite( aSubstitute
);
1257 ImplBeginRecord( WIN_EMR_RESTOREDC
);
1258 m_rStm
.WriteInt32( -1 );
1266 case MetaActionType::BMP
:
1268 const MetaBmpAction
* pA
= static_cast<const MetaBmpAction
*>(pAction
);
1269 ImplWriteBmpRecord( pA
->GetBitmap(), pA
->GetPoint(), maVDev
->PixelToLogic( pA
->GetBitmap().GetSizePixel() ), WIN_SRCCOPY
);
1273 case MetaActionType::BMPSCALE
:
1275 const MetaBmpScaleAction
* pA
= static_cast<const MetaBmpScaleAction
*>(pAction
);
1276 ImplWriteBmpRecord( pA
->GetBitmap(), pA
->GetPoint(), pA
->GetSize(), WIN_SRCCOPY
);
1280 case MetaActionType::BMPSCALEPART
:
1282 const MetaBmpScalePartAction
* pA
= static_cast<const MetaBmpScalePartAction
*>(pAction
);
1283 Bitmap
aTmp( pA
->GetBitmap() );
1285 if( aTmp
.Crop( tools::Rectangle( pA
->GetSrcPoint(), pA
->GetSrcSize() ) ) )
1286 ImplWriteBmpRecord( aTmp
, pA
->GetDestPoint(), pA
->GetDestSize(), WIN_SRCCOPY
);
1290 case MetaActionType::BMPEX
:
1292 const MetaBmpExAction
* pA
= static_cast<const MetaBmpExAction
*>(pAction
);
1293 Bitmap
aBmp( pA
->GetBitmapEx().GetBitmap() );
1294 AlphaMask
aMsk( pA
->GetBitmapEx().GetAlphaMask() );
1296 if( !aMsk
.IsEmpty() )
1298 aBmp
.Replace( aMsk
, COL_WHITE
);
1299 ImplWriteBmpRecord( aMsk
.GetBitmap(), pA
->GetPoint(), maVDev
->PixelToLogic( aMsk
.GetSizePixel() ), WIN_SRCPAINT
);
1300 ImplWriteBmpRecord( aBmp
, pA
->GetPoint(), maVDev
->PixelToLogic( aBmp
.GetSizePixel() ), WIN_SRCAND
);
1303 ImplWriteBmpRecord( aBmp
, pA
->GetPoint(), aBmp
.GetSizePixel(), WIN_SRCCOPY
);
1307 case MetaActionType::BMPEXSCALE
:
1309 const MetaBmpExScaleAction
* pA
= static_cast<const MetaBmpExScaleAction
*>(pAction
);
1310 Bitmap
aBmp( pA
->GetBitmapEx().GetBitmap() );
1311 AlphaMask
aMsk( pA
->GetBitmapEx().GetAlphaMask() );
1313 if( !aMsk
.IsEmpty() )
1315 aBmp
.Replace( aMsk
, COL_WHITE
);
1316 ImplWriteBmpRecord( aMsk
.GetBitmap(), pA
->GetPoint(), pA
->GetSize(), WIN_SRCPAINT
);
1317 ImplWriteBmpRecord( aBmp
, pA
->GetPoint(), pA
->GetSize(), WIN_SRCAND
);
1320 ImplWriteBmpRecord( aBmp
, pA
->GetPoint(), pA
->GetSize(), WIN_SRCCOPY
);
1324 case MetaActionType::BMPEXSCALEPART
:
1326 const MetaBmpExScalePartAction
* pA
= static_cast<const MetaBmpExScalePartAction
*>(pAction
);
1327 BitmapEx
aBmpEx( pA
->GetBitmapEx() );
1328 aBmpEx
.Crop( tools::Rectangle( pA
->GetSrcPoint(), pA
->GetSrcSize() ) );
1329 Bitmap
aBmp( aBmpEx
.GetBitmap() );
1330 AlphaMask
aMsk( aBmpEx
.GetAlphaMask() );
1332 if( !aMsk
.IsEmpty() )
1334 aBmp
.Replace( aMsk
, COL_WHITE
);
1335 ImplWriteBmpRecord( aMsk
.GetBitmap(), pA
->GetDestPoint(), pA
->GetDestSize(), WIN_SRCPAINT
);
1336 ImplWriteBmpRecord( aBmp
, pA
->GetDestPoint(), pA
->GetDestSize(), WIN_SRCAND
);
1339 ImplWriteBmpRecord( aBmp
, pA
->GetDestPoint(), pA
->GetDestSize(), WIN_SRCCOPY
);
1343 case MetaActionType::TEXT
:
1345 const MetaTextAction
* pA
= static_cast<const MetaTextAction
*>(pAction
);
1346 const OUString aText
= pA
->GetText().copy( pA
->GetIndex(), std::min(pA
->GetText().getLength() - pA
->GetIndex(), pA
->GetLen()) );
1348 ImplCheckTextAttr();
1349 ImplWriteTextRecord( pA
->GetPoint(), aText
, {}, 0 );
1353 case MetaActionType::TEXTRECT
:
1355 const MetaTextRectAction
* pA
= static_cast<const MetaTextRectAction
*>(pAction
);
1356 const OUString
& aText( pA
->GetText() );
1358 ImplCheckTextAttr();
1359 ImplWriteTextRecord( pA
->GetRect().TopLeft(), aText
, {}, 0 );
1363 case MetaActionType::TEXTARRAY
:
1365 const MetaTextArrayAction
* pA
= static_cast<const MetaTextArrayAction
*>(pAction
);
1366 const OUString aText
= pA
->GetText().copy( pA
->GetIndex(), std::min(pA
->GetText().getLength() - pA
->GetIndex(), pA
->GetLen()) );
1368 ImplCheckTextAttr();
1369 ImplWriteTextRecord( pA
->GetPoint(), aText
, pA
->GetDXArray(), 0 );
1373 case MetaActionType::STRETCHTEXT
:
1375 const MetaStretchTextAction
* pA
= static_cast<const MetaStretchTextAction
*>(pAction
);
1376 const OUString aText
= pA
->GetText().copy( pA
->GetIndex(), std::min(pA
->GetText().getLength() - pA
->GetIndex(), pA
->GetLen()) );
1378 ImplCheckTextAttr();
1379 ImplWriteTextRecord( pA
->GetPoint(), aText
, {}, pA
->GetWidth() );
1383 case MetaActionType::LINECOLOR
:
1385 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1386 mbLineChanged
= true;
1390 case MetaActionType::FILLCOLOR
:
1392 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1393 mbFillChanged
= true;
1397 case MetaActionType::TEXTCOLOR
:
1398 case MetaActionType::TEXTLINECOLOR
:
1399 case MetaActionType::TEXTFILLCOLOR
:
1400 case MetaActionType::TEXTALIGN
:
1401 case MetaActionType::FONT
:
1403 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1404 mbTextChanged
= true;
1408 case MetaActionType::ISECTRECTCLIPREGION
:
1410 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1412 ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT
);
1413 ImplWriteRect( static_cast<const MetaISectRectClipRegionAction
*>(pAction
)->GetRect() );
1418 case MetaActionType::CLIPREGION
:
1419 case MetaActionType::ISECTREGIONCLIPREGION
:
1420 case MetaActionType::MOVECLIPREGION
:
1422 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1426 case MetaActionType::REFPOINT
:
1427 case MetaActionType::MAPMODE
:
1428 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1431 case MetaActionType::PUSH
:
1433 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1435 ImplBeginRecord( WIN_EMR_SAVEDC
);
1440 case MetaActionType::POP
:
1442 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1444 ImplBeginRecord( WIN_EMR_RESTOREDC
);
1445 m_rStm
.WriteInt32( -1 );
1448 ImplWriteRasterOp( maVDev
->GetRasterOp() );
1449 mbLineChanged
= mbFillChanged
= mbTextChanged
= true;
1453 case MetaActionType::RASTEROP
:
1455 const_cast<MetaAction
*>(pAction
)->Execute( maVDev
);
1456 ImplWriteRasterOp( static_cast<const MetaRasterOpAction
*>(pAction
)->GetRasterOp() );
1460 case MetaActionType::LAYOUTMODE
:
1462 vcl::text::ComplexTextLayoutFlags nLayoutMode
= static_cast<const MetaLayoutModeAction
*>(pAction
)->GetLayoutMode();
1464 if ((nLayoutMode
& vcl::text::ComplexTextLayoutFlags::BiDiRtl
) != vcl::text::ComplexTextLayoutFlags::Default
)
1466 mnHorTextAlign
= TA_RIGHT
| TA_RTLREADING
;
1468 if ((nLayoutMode
& vcl::text::ComplexTextLayoutFlags::TextOriginRight
) != vcl::text::ComplexTextLayoutFlags::Default
)
1469 mnHorTextAlign
|= TA_RIGHT
;
1470 else if ((nLayoutMode
& vcl::text::ComplexTextLayoutFlags::TextOriginLeft
) != vcl::text::ComplexTextLayoutFlags::Default
)
1471 mnHorTextAlign
&= ~TA_RIGHT
;
1475 case MetaActionType::COMMENT
:
1477 MetaCommentAction
const*const pCommentAction(
1478 static_cast<MetaCommentAction
const*>(pAction
));
1479 if (pCommentAction
->GetComment() == "EMF_PLUS")
1481 ImplBeginCommentRecord(WIN_EMR_COMMENT_EMFPLUS
);
1482 m_rStm
.WriteBytes(pCommentAction
->GetData(),
1483 pCommentAction
->GetDataSize());
1484 ImplEndCommentRecord();
1489 case MetaActionType::MASK
:
1490 case MetaActionType::MASKSCALE
:
1491 case MetaActionType::MASKSCALEPART
:
1492 case MetaActionType::WALLPAPER
:
1493 case MetaActionType::TEXTLINE
:
1494 case MetaActionType::GRADIENTEX
:
1495 // Explicitly ignored cases
1499 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1505 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */