bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / filter / wmf / emfwr.cxx
blob0204999672dcaa9463139cf7109e4e75df84bb2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <algorithm>
25 #include "emfwr.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>
34 #include <memory>
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 */
89 #define TA_RIGHT 2
91 #define TA_TOP 0
92 #define TA_BOTTOM 8
93 #define TA_BASELINE 24
94 #define TA_RTLREADING 256
96 #define MM_ANISOTROPIC 8
98 enum class EmfPlusRecordType
100 Header = 0x4001,
101 EndOfFile = 0x4002,
102 GetDC = 0x4004,
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 );
113 m_rStm.SeekRel( 4 );
114 m_rStm.WriteInt32( nCommentType );
117 void EMFWriter::ImplEndCommentRecord()
119 if( mbRecordOpen )
121 sal_Int32 nActPos = m_rStm.Tell();
122 m_rStm.Seek( mnRecordPos + 8 );
123 m_rStm.WriteUInt32( nActPos - mnRecordPos - 0xc );
124 m_rStm.Seek( nActPos );
126 ImplEndRecord();
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 );
139 m_rStm.SeekRel( 8 );
143 void EMFWriter::ImplEndPlusRecord()
145 SAL_WARN_IF( !mbRecordPlusOpen, "vcl", "EMF+ Record was not opened!" );
147 if( mbRecordPlusOpen )
149 sal_Int32 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 );
162 ImplEndPlusRecord();
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;
171 if (nDivX)
172 nDPIX /= nDivX; // DPI X
174 sal_Int32 nDPIY = rMtfSizePix.Height()*25;
175 sal_Int32 nDivY = rMtfSizeLog.Height()/100;
176 if (nDivY)
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
185 .WriteInt32( nDPIX )
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 )
219 // Convert to pixels
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 ] );
234 ImplEndPlusRecord();
236 ImplEndCommentRecord();
239 bool EMFWriter::WriteEMF(const GDIMetaFile& rMtf)
241 const sal_uLong 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;
252 mnHorTextAlign = 0;
254 const Size aMtfSizePix( maVDev->LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) );
255 const Size aMtfSizeLog( OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
257 // seek over header
258 // use [MS-EMF 2.2.11] HeaderExtension2 Object, otherwise resulting EMF cannot be converted with GetWinMetaFileBits()
259 m_rStm.SeekRel( 108 );
261 // Write EMF+ Header
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 );
269 ImplEndRecord();
271 ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX );
272 m_rStm.WriteInt32( maVDev->GetDPIX() ).WriteInt32( maVDev->GetDPIY() );
273 ImplEndRecord();
275 ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX );
276 m_rStm.WriteInt32( 2540 ).WriteInt32( 2540 );
277 ImplEndRecord();
279 ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX );
280 m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
281 ImplEndRecord();
283 ImplBeginRecord( WIN_EMR_SETWINDOWORGEX );
284 m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
285 ImplEndRecord();
287 ImplWriteRasterOp( RasterOp::OverPaint );
289 ImplBeginRecord( WIN_EMR_SETBKMODE );
290 m_rStm.WriteUInt32( 1 ); // TRANSPARENT
291 ImplEndRecord();
293 // write emf data
294 ImplWrite( rMtf );
296 ImplWritePlusEOF();
298 ImplBeginRecord( WIN_EMR_EOF );
299 m_rStm.WriteUInt32( 0 ) // nPalEntries
300 .WriteUInt32( 0x10 ) // offPalEntries
301 .WriteUInt32( 0x14 ); // nSizeLast
302 ImplEndRecord();
304 // write header
305 const sal_uLong 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 )
334 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!" );
352 if( !mbRecordOpen )
354 mbRecordOpen = true;
355 mnRecordPos = m_rStm.Tell();
357 m_rStm.WriteUInt32( nType );
358 m_rStm.SeekRel( 4 );
362 void EMFWriter::ImplEndRecord()
364 SAL_WARN_IF( !mbRecordOpen, "vcl", "Record was not opened!" );
366 if( !mbRecordOpen )
367 return;
369 sal_Int32 nFillBytes, nActPos = m_rStm.Tell();
370 m_rStm.Seek( mnRecordPos + 4 );
371 nFillBytes = nActPos - mnRecordPos;
372 nFillBytes += 3; // each record has to be dword aligned
373 nFillBytes ^= 3;
374 nFillBytes &= 3;
375 m_rStm.WriteUInt32( ( nActPos - mnRecordPos ) + nFillBytes );
376 m_rStm.Seek( nActPos );
377 while( nFillBytes-- )
378 m_rStm.WriteUChar( 0 );
379 mnRecordCount++;
380 mbRecordOpen = false;
384 bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType )
386 if( rHandle != HANDLE_INVALID )
388 sal_uInt32 nStockObject = 0x80000000;
390 if( LINE_SELECT == nSelectType )
391 nStockObject |= 0x00000007;
392 else if( FILL_SELECT == nSelectType )
393 nStockObject |= 0x00000001;
394 else if( TEXT_SELECT == nSelectType )
395 nStockObject |= 0x0000000a;
397 // select stock object first
398 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
399 m_rStm.WriteUInt32( nStockObject );
400 ImplEndRecord();
402 // destroy handle of created object
403 ImplBeginRecord( WIN_EMR_DELETEOBJECT );
404 m_rStm.WriteUInt32( rHandle );
405 ImplEndRecord();
407 // mark handle as free
408 ImplReleaseHandle( rHandle );
411 rHandle = ImplAcquireHandle();
413 return( HANDLE_INVALID != rHandle );
416 void EMFWriter::ImplCheckLineAttr()
418 if( mbLineChanged && ImplPrepareHandleSelect( mnLineHandle, LINE_SELECT ) )
420 sal_uInt32 nStyle = maVDev->IsLineColor() ? 0 : 5;
422 ImplBeginRecord( WIN_EMR_CREATEPEN );
423 m_rStm.WriteUInt32( mnLineHandle ).WriteUInt32( nStyle ).WriteUInt32( 0/*nWidth*/ ).WriteUInt32( 0/*nHeight*/ );
424 ImplWriteColor( maVDev->GetLineColor() );
425 ImplEndRecord();
427 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
428 m_rStm.WriteUInt32( mnLineHandle );
429 ImplEndRecord();
433 void EMFWriter::ImplCheckFillAttr()
435 if( mbFillChanged && ImplPrepareHandleSelect( mnFillHandle, FILL_SELECT ) )
437 sal_uInt32 nStyle = maVDev->IsFillColor() ? 0 : 1;
439 ImplBeginRecord( WIN_EMR_CREATEBRUSHINDIRECT );
440 m_rStm.WriteUInt32( mnFillHandle ).WriteUInt32( nStyle );
441 ImplWriteColor( maVDev->GetFillColor() );
442 m_rStm.WriteUInt32( 0/*nPatternStyle*/ );
443 ImplEndRecord();
445 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
446 m_rStm.WriteUInt32( mnFillHandle );
447 ImplEndRecord();
451 void EMFWriter::ImplCheckTextAttr()
453 if( !(mbTextChanged && ImplPrepareHandleSelect( mnTextHandle, TEXT_SELECT )) )
454 return;
456 const vcl::Font& rFont = maVDev->GetFont();
457 const OUString& aFontName( rFont.GetFamilyName() );
458 sal_Int32 nWeight;
459 sal_uInt16 i;
460 sal_uInt8 nPitchAndFamily;
462 ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW );
463 m_rStm.WriteUInt32( mnTextHandle );
464 ImplWriteExtent( -rFont.GetFontSize().Height() );
465 ImplWriteExtent( rFont.GetFontSize().Width() );
466 m_rStm.WriteInt32( rFont.GetOrientation() ).WriteInt32( rFont.GetOrientation() );
468 switch( rFont.GetWeight() )
470 case WEIGHT_THIN: nWeight = 100; break;
471 case WEIGHT_ULTRALIGHT: nWeight = 200; break;
472 case WEIGHT_LIGHT: nWeight = 300; break;
473 case WEIGHT_SEMILIGHT: nWeight = 300; break;
474 case WEIGHT_NORMAL: nWeight = 400; break;
475 case WEIGHT_MEDIUM: nWeight = 500; break;
476 case WEIGHT_SEMIBOLD: nWeight = 600; break;
477 case WEIGHT_BOLD: nWeight = 700; break;
478 case WEIGHT_ULTRABOLD: nWeight = 800; break;
479 case WEIGHT_BLACK: nWeight = 900; break;
480 default: nWeight = 0; break;
483 m_rStm.WriteInt32( nWeight );
484 m_rStm.WriteUChar( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 );
485 m_rStm.WriteUChar( ( LINESTYLE_NONE == rFont.GetUnderline() ) ? 0 : 1 );
486 m_rStm.WriteUChar( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 );
487 m_rStm.WriteUChar( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 );
488 m_rStm.WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
490 switch( rFont.GetPitch() )
492 case PITCH_FIXED: nPitchAndFamily = 0x01; break;
493 case PITCH_VARIABLE: nPitchAndFamily = 0x02; break;
494 default: nPitchAndFamily = 0x00; break;
497 switch( rFont.GetFamilyType() )
499 case FAMILY_DECORATIVE: nPitchAndFamily |= 0x50; break;
500 case FAMILY_MODERN: nPitchAndFamily |= 0x30; break;
501 case FAMILY_ROMAN: nPitchAndFamily |= 0x10; break;
502 case FAMILY_SCRIPT: nPitchAndFamily |= 0x40; break;
503 case FAMILY_SWISS: nPitchAndFamily |= 0x20; break;
504 default: break;
507 m_rStm.WriteUChar( nPitchAndFamily );
509 for( i = 0; i < 32; i++ )
510 m_rStm.WriteUInt16( ( i < aFontName.getLength() ) ? aFontName[ i ] : 0 );
512 // dummy elfFullName
513 for( i = 0; i < 64; i++ )
514 m_rStm.WriteUInt16( 0 );
516 // dummy elfStyle
517 for( i = 0; i < 32; i++ )
518 m_rStm.WriteUInt16( 0 );
520 // dummy elfVersion, elfStyleSize, elfMatch, elfReserved
521 m_rStm.WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ) ;
523 // dummy elfVendorId
524 m_rStm.WriteUInt32( 0 );
526 // dummy elfCulture
527 m_rStm.WriteUInt32( 0 );
529 // dummy elfPanose
530 m_rStm.WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
532 // fill record to get a record size divideable by 4
533 m_rStm.WriteUInt16( 0 );
535 ImplEndRecord();
537 // TextAlign
538 sal_uInt32 nTextAlign;
540 switch( rFont.GetAlignment() )
542 case ALIGN_TOP: nTextAlign = TA_TOP; break;
543 case ALIGN_BOTTOM: nTextAlign = TA_BOTTOM; break;
544 default: nTextAlign = TA_BASELINE; break;
546 nTextAlign |= mnHorTextAlign;
548 ImplBeginRecord( WIN_EMR_SETTEXTALIGN );
549 m_rStm.WriteUInt32( nTextAlign );
550 ImplEndRecord();
552 // Text color
553 ImplBeginRecord( WIN_EMR_SETTEXTCOLOR );
554 ImplWriteColor( maVDev->GetTextColor() );
555 ImplEndRecord();
557 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
558 m_rStm.WriteUInt32( mnTextHandle );
559 ImplEndRecord();
563 void EMFWriter::ImplWriteColor( const Color& rColor )
565 sal_uInt32 nCol = rColor.GetRed();
567 nCol |= static_cast<sal_uInt32>(rColor.GetGreen()) << 8;
568 nCol |= static_cast<sal_uInt32>(rColor.GetBlue()) << 16;
570 m_rStm.WriteUInt32( nCol );
573 void EMFWriter::ImplWriteRasterOp( RasterOp eRop )
575 sal_uInt32 nROP2;
577 switch( eRop )
579 case RasterOp::Invert: nROP2 = 6; break;
580 case RasterOp::Xor: nROP2 = 7; break;
581 default: nROP2 = 13;break;
584 ImplBeginRecord( WIN_EMR_SETROP2 );
585 m_rStm.WriteUInt32( nROP2 );
586 ImplEndRecord();
589 void EMFWriter::ImplWriteExtent( long nExtent )
591 nExtent = OutputDevice::LogicToLogic( Size( nExtent, 0 ), maVDev->GetMapMode(), maDestMapMode ).Width();
592 m_rStm.WriteInt32( nExtent );
595 void EMFWriter::ImplWritePoint( const Point& rPoint )
597 const Point aPoint( OutputDevice::LogicToLogic( rPoint, maVDev->GetMapMode(), maDestMapMode ));
598 m_rStm.WriteInt32( aPoint.X() ).WriteInt32( aPoint.Y() );
601 void EMFWriter::ImplWriteSize( const Size& rSize)
603 const Size aSize( OutputDevice::LogicToLogic( rSize, maVDev->GetMapMode(), maDestMapMode ));
604 m_rStm.WriteInt32( aSize.Width() ).WriteInt32( aSize.Height() );
607 void EMFWriter::ImplWriteRect( const tools::Rectangle& rRect )
609 const tools::Rectangle aRect( OutputDevice::LogicToLogic ( rRect, maVDev->GetMapMode(), maDestMapMode ));
610 auto right = aRect.IsWidthEmpty() ? aRect.Left() : aRect.Right();
611 auto bottom = aRect.IsHeightEmpty() ? aRect.Top() : aRect.Bottom();
612 m_rStm
613 .WriteInt32( aRect.Left() )
614 .WriteInt32( aRect.Top() )
615 .WriteInt32( right )
616 .WriteInt32( bottom );
619 void EMFWriter::ImplWritePolygonRecord( const tools::Polygon& rPoly, bool bClose )
621 if( rPoly.GetSize() )
623 if( rPoly.HasFlags() )
624 ImplWritePath( rPoly, bClose );
625 else
627 if( bClose )
628 ImplCheckFillAttr();
630 ImplCheckLineAttr();
632 ImplBeginRecord( bClose ? WIN_EMR_POLYGON : WIN_EMR_POLYLINE );
633 ImplWriteRect( rPoly.GetBoundRect() );
634 m_rStm.WriteUInt32( rPoly.GetSize() );
636 for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ )
637 ImplWritePoint( rPoly[ i ] );
639 ImplEndRecord();
644 void EMFWriter::ImplWritePolyPolygonRecord( const tools::PolyPolygon& rPolyPoly )
646 sal_uInt16 n, i, nPolyCount = rPolyPoly.Count();
648 if( nPolyCount )
650 if( 1 == nPolyCount )
651 ImplWritePolygonRecord( rPolyPoly[ 0 ], true );
652 else
654 bool bHasFlags = false;
655 sal_uInt32 nTotalPoints = 0;
657 for( i = 0; i < nPolyCount; i++ )
659 nTotalPoints += rPolyPoly[ i ].GetSize();
660 if ( rPolyPoly[ i ].HasFlags() )
661 bHasFlags = true;
663 if( nTotalPoints )
665 if ( bHasFlags )
666 ImplWritePath( rPolyPoly, true );
667 else
669 ImplCheckFillAttr();
670 ImplCheckLineAttr();
672 ImplBeginRecord( WIN_EMR_POLYPOLYGON );
673 ImplWriteRect( rPolyPoly.GetBoundRect() );
674 m_rStm.WriteUInt32( nPolyCount ).WriteUInt32( nTotalPoints );
676 for( i = 0; i < nPolyCount; i++ )
677 m_rStm.WriteUInt32( rPolyPoly[ i ].GetSize() );
679 for( i = 0; i < nPolyCount; i++ )
681 const tools::Polygon& rPoly = rPolyPoly[ i ];
683 for( n = 0; n < rPoly.GetSize(); n++ )
684 ImplWritePoint( rPoly[ n ] );
686 ImplEndRecord();
693 void EMFWriter::ImplWritePath( const tools::PolyPolygon& rPolyPoly, bool bClosed )
695 if ( bClosed )
696 ImplCheckFillAttr();
697 ImplCheckLineAttr();
699 ImplBeginRecord( WIN_EMR_BEGINPATH );
700 ImplEndRecord();
702 sal_uInt16 i, n, o, nPolyCount = rPolyPoly.Count();
703 for ( i = 0; i < nPolyCount; i++ )
705 n = 0;
706 const tools::Polygon& rPoly = rPolyPoly[ i ];
707 while ( n < rPoly.GetSize() )
709 if( n == 0 )
711 ImplBeginRecord( WIN_EMR_MOVETOEX );
712 ImplWritePoint( rPoly[ 0 ] );
713 ImplEndRecord();
714 n++;
715 continue;
718 sal_uInt16 nBezPoints = 0;
720 while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == PolyFlags::Control ) )
721 nBezPoints += 3;
723 if ( nBezPoints )
725 ImplBeginRecord( WIN_EMR_POLYBEZIERTO );
726 tools::Polygon aNewPoly( nBezPoints + 1 );
727 aNewPoly[ 0 ] = rPoly[ n - 1 ];
728 for ( o = 0; o < nBezPoints; o++ )
729 aNewPoly[ o + 1 ] = rPoly[ n + o ];
730 ImplWriteRect( aNewPoly.GetBoundRect() );
731 m_rStm.WriteUInt32( nBezPoints );
732 for( o = 1; o < aNewPoly.GetSize(); o++ )
733 ImplWritePoint( aNewPoly[ o ] );
734 ImplEndRecord();
735 n = n + nBezPoints;
737 else
739 sal_uInt16 nPoints = 1;
740 while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != PolyFlags::Control ) )
741 nPoints++;
743 if ( nPoints > 1 )
745 ImplBeginRecord( WIN_EMR_POLYLINETO );
746 tools::Polygon aNewPoly( nPoints + 1 );
747 aNewPoly[ 0 ] = rPoly[ n - 1];
748 for ( o = 1; o <= nPoints; o++ )
749 aNewPoly[ o ] = rPoly[ n - 1 + o ];
750 ImplWriteRect( aNewPoly.GetBoundRect() );
751 m_rStm.WriteUInt32( nPoints );
752 for( o = 1; o < aNewPoly.GetSize(); o++ )
753 ImplWritePoint( aNewPoly[ o ] );
754 ImplEndRecord();
756 else
758 ImplBeginRecord( WIN_EMR_LINETO );
759 ImplWritePoint( rPoly[ n ] );
760 ImplEndRecord();
762 n = n + nPoints;
764 if ( bClosed && ( n == rPoly.GetSize() ) )
766 ImplBeginRecord( WIN_EMR_CLOSEFIGURE );
767 ImplEndRecord();
771 ImplBeginRecord( WIN_EMR_ENDPATH );
772 ImplEndRecord();
773 ImplBeginRecord( bClosed ? WIN_EMR_FILLPATH : WIN_EMR_STROKEPATH );
774 ImplWriteRect( rPolyPoly.GetBoundRect() );
775 ImplEndRecord();
778 void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt,
779 const Size& rSz, sal_uInt32 nROP )
781 if( !rBmp )
782 return;
784 SvMemoryStream aMemStm( 65535, 65535 );
785 const Size aBmpSizePixel( rBmp.GetSizePixel() );
787 ImplBeginRecord( WIN_EMR_STRETCHDIBITS );
788 ImplWriteRect( tools::Rectangle( rPt, rSz ) );
789 ImplWritePoint( rPt );
790 m_rStm.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aBmpSizePixel.Width() ).WriteInt32( aBmpSizePixel.Height() );
792 // write offset positions and sizes later
793 const sal_uLong nOffPos = m_rStm.Tell();
794 m_rStm.SeekRel( 16 );
796 m_rStm.WriteUInt32( 0 ).WriteInt32( ( RasterOp::Xor == maVDev->GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP );
797 ImplWriteSize( rSz );
799 WriteDIB(rBmp, aMemStm, true, false);
801 sal_uInt32 nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize;
802 sal_uInt16 nBitCount;
804 // get DIB parameters
805 aMemStm.Seek( 0 );
806 aMemStm.ReadUInt32( nHeaderSize );
807 aMemStm.SeekRel( 10 );
808 aMemStm.ReadUInt16( nBitCount ).ReadUInt32( nCompression ).ReadUInt32( nImageSize );
809 aMemStm.SeekRel( 8 );
810 aMemStm.ReadUInt32( nColsUsed );
812 if (nBitCount <= 8)
814 if (nColsUsed)
815 nPalCount = nColsUsed;
816 else
817 nPalCount = 1 << static_cast<sal_uInt32>(nBitCount);
819 else
821 if (nCompression == BITFIELDS)
822 nPalCount = 3;
823 else
824 nPalCount = 0;
827 sal_uInt32 nPalSize = nPalCount * 4;
829 m_rStm.WriteBytes( aMemStm.GetData(), nDIBSize );
831 const sal_uLong nEndPos = m_rStm.Tell();
832 m_rStm.Seek( nOffPos );
833 m_rStm.WriteUInt32( 80 ).WriteUInt32( nHeaderSize + nPalSize );
834 m_rStm.WriteUInt32( 80 + nHeaderSize + nPalSize ).WriteUInt32( nImageSize );
835 m_rStm.Seek( nEndPos );
837 ImplEndRecord();
841 void EMFWriter::ImplWriteTextRecord( const Point& rPos, const OUString& rText, const long* pDXArray, sal_uInt32 nWidth )
843 sal_Int32 nLen = rText.getLength(), i;
845 if( !nLen )
846 return;
848 sal_uInt32 nNormWidth;
849 std::unique_ptr<long[]> pOwnArray;
850 long* pDX;
852 // get text sizes
853 if( pDXArray )
855 nNormWidth = maVDev->GetTextWidth( rText );
856 pDX = const_cast<long*>(pDXArray);
858 else
860 pOwnArray.reset(new long[ nLen ]);
861 nNormWidth = maVDev->GetTextArray( rText, pOwnArray.get() );
862 pDX = pOwnArray.get();
865 if( nLen > 1 )
867 nNormWidth = pDX[ nLen - 2 ] + maVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) );
869 if( nWidth && nNormWidth && ( nWidth != nNormWidth ) )
871 const double fFactor = static_cast<double>(nWidth) / nNormWidth;
873 for( i = 0; i < ( nLen - 1 ); i++ )
874 pDX[ i ] = FRound( pDX[ i ] * fFactor );
878 // write text record
879 ImplBeginRecord( WIN_EMR_EXTTEXTOUTW );
881 ImplWriteRect( tools::Rectangle( rPos, Size( nNormWidth, maVDev->GetTextHeight() ) ) );
882 m_rStm.WriteUInt32( 1 );
883 m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
884 ImplWritePoint( rPos );
885 m_rStm.WriteUInt32( nLen ).WriteUInt32( 76 ).WriteUInt32( 2 );
886 m_rStm.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 );
887 m_rStm.WriteUInt32( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) );
889 // write text
890 for( i = 0; i < nLen; i++ )
891 m_rStm.WriteUInt16( rText[ i ] );
893 // padding word
894 if( nLen & 1 )
895 m_rStm.WriteUInt16( 0 );
897 // write DX array
898 ImplWriteExtent( pDX[ 0 ] );
900 if( nLen > 1 )
902 for( i = 1; i < ( nLen - 1 ); i++ )
903 ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] );
905 ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) );
908 ImplEndRecord();
912 void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
914 if(rLinePolygon.count())
916 basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
917 basegfx::B2DPolyPolygon aFillPolyPolygon;
919 rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
921 if(aLinePolyPolygon.count())
923 for(auto const& rB2DPolygon : aLinePolyPolygon)
925 ImplWritePolygonRecord( tools::Polygon(rB2DPolygon), false );
929 if(aFillPolyPolygon.count())
931 const Color aOldLineColor(maVDev->GetLineColor());
932 const Color aOldFillColor(maVDev->GetFillColor());
934 maVDev->SetLineColor();
935 maVDev->SetFillColor(aOldLineColor);
937 for(auto const& rB2DPolygon : aFillPolyPolygon)
939 ImplWritePolyPolygonRecord(tools::PolyPolygon( tools::Polygon(rB2DPolygon) ));
942 maVDev->SetLineColor(aOldLineColor);
943 maVDev->SetFillColor(aOldFillColor);
948 void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
950 for( size_t j = 0, nActionCount = rMtf.GetActionSize(); j < nActionCount; j++ )
952 const MetaAction* pAction = rMtf.GetAction( j );
953 const MetaActionType nType = pAction->GetType();
955 switch( nType )
957 case MetaActionType::PIXEL:
959 const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
961 ImplCheckLineAttr();
962 ImplBeginRecord( WIN_EMR_SETPIXELV );
963 ImplWritePoint( pA->GetPoint() );
964 ImplWriteColor( pA->GetColor() );
965 ImplEndRecord();
967 break;
969 case MetaActionType::POINT:
971 if( maVDev->IsLineColor() )
973 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
975 ImplCheckLineAttr();
976 ImplBeginRecord( WIN_EMR_SETPIXELV );
977 ImplWritePoint( pA->GetPoint() );
978 ImplWriteColor( maVDev->GetLineColor() );
979 ImplEndRecord();
982 break;
984 case MetaActionType::LINE:
986 if( maVDev->IsLineColor() )
988 const MetaLineAction* pA = static_cast<const MetaLineAction*>(pAction);
990 if(pA->GetLineInfo().IsDefault())
992 ImplCheckLineAttr();
994 ImplBeginRecord( WIN_EMR_MOVETOEX );
995 ImplWritePoint( pA->GetStartPoint() );
996 ImplEndRecord();
998 ImplBeginRecord( WIN_EMR_LINETO );
999 ImplWritePoint( pA->GetEndPoint() );
1000 ImplEndRecord();
1002 ImplBeginRecord( WIN_EMR_SETPIXELV );
1003 ImplWritePoint( pA->GetEndPoint() );
1004 ImplWriteColor( maVDev->GetLineColor() );
1005 ImplEndRecord();
1007 else
1009 // LineInfo used; handle Dash/Dot and fat lines
1010 basegfx::B2DPolygon aPolygon;
1011 aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1012 aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1013 Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
1017 break;
1019 case MetaActionType::RECT:
1021 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1023 const MetaRectAction* pA = static_cast<const MetaRectAction*>(pAction);
1025 ImplCheckFillAttr();
1026 ImplCheckLineAttr();
1028 ImplBeginRecord( WIN_EMR_RECTANGLE );
1029 ImplWriteRect( pA->GetRect() );
1030 ImplEndRecord();
1033 break;
1035 case MetaActionType::ROUNDRECT:
1037 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1039 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pAction);
1041 ImplCheckFillAttr();
1042 ImplCheckLineAttr();
1044 ImplBeginRecord( WIN_EMR_ROUNDRECT );
1045 ImplWriteRect( pA->GetRect() );
1046 ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) );
1047 ImplEndRecord();
1050 break;
1052 case MetaActionType::ELLIPSE:
1054 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1056 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pAction);
1058 ImplCheckFillAttr();
1059 ImplCheckLineAttr();
1061 ImplBeginRecord( WIN_EMR_ELLIPSE );
1062 ImplWriteRect( pA->GetRect() );
1063 ImplEndRecord();
1066 break;
1068 case MetaActionType::ARC:
1069 case MetaActionType::PIE:
1070 case MetaActionType::CHORD:
1071 case MetaActionType::POLYGON:
1073 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1075 tools::Polygon aPoly;
1077 switch( nType )
1079 case MetaActionType::ARC:
1081 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
1082 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Arc );
1084 break;
1086 case MetaActionType::PIE:
1088 const MetaPieAction* pA = static_cast<const MetaPieAction*>(pAction);
1089 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Pie );
1091 break;
1093 case MetaActionType::CHORD:
1095 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pAction);
1096 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Chord );
1098 break;
1100 case MetaActionType::POLYGON:
1101 aPoly = static_cast<const MetaPolygonAction*>(pAction)->GetPolygon();
1102 break;
1103 default: break;
1106 ImplWritePolygonRecord( aPoly, nType != MetaActionType::ARC );
1109 break;
1111 case MetaActionType::POLYLINE:
1113 if( maVDev->IsLineColor() )
1115 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pAction);
1116 const tools::Polygon& rPoly = pA->GetPolygon();
1118 if( rPoly.GetSize() )
1120 if(pA->GetLineInfo().IsDefault())
1122 ImplWritePolygonRecord( rPoly, false );
1124 else
1126 // LineInfo used; handle Dash/Dot and fat lines
1127 Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1132 break;
1134 case MetaActionType::POLYPOLYGON:
1136 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1137 ImplWritePolyPolygonRecord( static_cast<const MetaPolyPolygonAction*>(pAction)->GetPolyPolygon() );
1139 break;
1141 case MetaActionType::GRADIENT:
1143 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pAction);
1144 GDIMetaFile aTmpMtf;
1146 maVDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1147 ImplWrite( aTmpMtf );
1149 break;
1151 case MetaActionType::HATCH:
1153 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
1154 GDIMetaFile aTmpMtf;
1156 maVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1157 ImplWrite( aTmpMtf );
1159 break;
1161 case MetaActionType::Transparent:
1163 const tools::PolyPolygon& rPolyPoly = static_cast<const MetaTransparentAction*>(pAction)->GetPolyPolygon();
1164 if( rPolyPoly.Count() )
1165 ImplWritePlusFillPolygonRecord( rPolyPoly[0], static_cast<const MetaTransparentAction*>(pAction)->GetTransparence() );
1166 ImplCheckFillAttr();
1167 ImplCheckLineAttr();
1168 ImplWritePolyPolygonRecord( rPolyPoly );
1170 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS );
1171 ImplPlusRecord( EmfPlusRecordType::GetDC, 0x00 );
1172 ImplEndCommentRecord();
1174 break;
1176 case MetaActionType::FLOATTRANSPARENT:
1178 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
1180 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1181 Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1182 const Size aSrcSize( aTmpMtf.GetPrefSize() );
1183 const Point aDestPt( pA->GetPoint() );
1184 const Size aDestSize( pA->GetSize() );
1185 const double fScaleX = aSrcSize.Width() ? static_cast<double>(aDestSize.Width()) / aSrcSize.Width() : 1.0;
1186 const double fScaleY = aSrcSize.Height() ? static_cast<double>(aDestSize.Height()) / aSrcSize.Height() : 1.0;
1187 long nMoveX, nMoveY;
1189 if( fScaleX != 1.0 || fScaleY != 1.0 )
1191 aTmpMtf.Scale( fScaleX, fScaleY );
1192 aSrcPt.setX( FRound( aSrcPt.X() * fScaleX ) );
1193 aSrcPt.setY( FRound( aSrcPt.Y() * fScaleY ) );
1196 nMoveX = aDestPt.X() - aSrcPt.X();
1197 nMoveY = aDestPt.Y() - aSrcPt.Y();
1199 if( nMoveX || nMoveY )
1200 aTmpMtf.Move( nMoveX, nMoveY );
1202 ImplCheckFillAttr();
1203 ImplCheckLineAttr();
1204 ImplCheckTextAttr();
1205 ImplWrite( aTmpMtf );
1207 break;
1209 case MetaActionType::EPS:
1211 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pAction);
1212 const GDIMetaFile& aSubstitute( pA->GetSubstitute() );
1214 for( size_t i = 0, nCount = aSubstitute.GetActionSize(); i < nCount; i++ )
1216 const MetaAction* pSubstAct = aSubstitute.GetAction( i );
1217 if( pSubstAct->GetType() == MetaActionType::BMPSCALE )
1219 maVDev->Push();
1220 ImplBeginRecord( WIN_EMR_SAVEDC );
1221 ImplEndRecord();
1223 MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1224 Size aOutSize( OutputDevice::LogicToLogic( pA->GetSize(), maVDev->GetMapMode(), aMapMode ) );
1225 aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
1226 aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
1227 aMapMode.SetOrigin( OutputDevice::LogicToLogic( pA->GetPoint(), maVDev->GetMapMode(), aMapMode ) );
1228 maVDev->SetMapMode( aMapMode );
1229 ImplWrite( aSubstitute );
1231 maVDev->Pop();
1232 ImplBeginRecord( WIN_EMR_RESTOREDC );
1233 m_rStm.WriteInt32( -1 );
1234 ImplEndRecord();
1235 break;
1239 break;
1241 case MetaActionType::BMP:
1243 const MetaBmpAction* pA = static_cast<const MetaBmpAction *>(pAction);
1244 ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ), WIN_SRCCOPY );
1246 break;
1248 case MetaActionType::BMPSCALE:
1250 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
1251 ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1253 break;
1255 case MetaActionType::BMPSCALEPART:
1257 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pAction);
1258 Bitmap aTmp( pA->GetBitmap() );
1260 if( aTmp.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1261 ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1263 break;
1265 case MetaActionType::BMPEX:
1267 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction *>(pAction);
1268 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1269 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1271 if( !!aMsk )
1273 aBmp.Replace( aMsk, COL_WHITE );
1274 aMsk.Invert();
1275 ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev->PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT );
1276 ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev->PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND );
1278 else
1279 ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY );
1281 break;
1283 case MetaActionType::BMPEXSCALE:
1285 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
1286 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1287 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1289 if( !!aMsk )
1291 aBmp.Replace( aMsk, COL_WHITE );
1292 aMsk.Invert();
1293 ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT );
1294 ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND );
1296 else
1297 ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1299 break;
1301 case MetaActionType::BMPEXSCALEPART:
1303 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pAction);
1304 BitmapEx aBmpEx( pA->GetBitmapEx() );
1305 aBmpEx.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1306 Bitmap aBmp( aBmpEx.GetBitmap() );
1307 Bitmap aMsk( aBmpEx.GetMask() );
1309 if( !!aMsk )
1311 aBmp.Replace( aMsk, COL_WHITE );
1312 aMsk.Invert();
1313 ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT );
1314 ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND );
1316 else
1317 ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1319 break;
1321 case MetaActionType::TEXT:
1323 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
1324 const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1326 ImplCheckTextAttr();
1327 ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, 0 );
1329 break;
1331 case MetaActionType::TEXTRECT:
1333 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
1334 const OUString& aText( pA->GetText() );
1336 ImplCheckTextAttr();
1337 ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, nullptr, 0 );
1339 break;
1341 case MetaActionType::TEXTARRAY:
1343 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
1344 const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1346 ImplCheckTextAttr();
1347 ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
1349 break;
1351 case MetaActionType::STRETCHTEXT:
1353 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
1354 const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1356 ImplCheckTextAttr();
1357 ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, pA->GetWidth() );
1359 break;
1361 case MetaActionType::LINECOLOR:
1363 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1364 mbLineChanged = true;
1366 break;
1368 case MetaActionType::FILLCOLOR:
1370 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1371 mbFillChanged = true;
1373 break;
1375 case MetaActionType::TEXTCOLOR:
1376 case MetaActionType::TEXTLINECOLOR:
1377 case MetaActionType::TEXTFILLCOLOR:
1378 case MetaActionType::TEXTALIGN:
1379 case MetaActionType::FONT:
1381 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1382 mbTextChanged = true;
1384 break;
1386 case MetaActionType::ISECTRECTCLIPREGION:
1388 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1390 ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT );
1391 ImplWriteRect( static_cast<const MetaISectRectClipRegionAction*>(pAction)->GetRect() );
1392 ImplEndRecord();
1394 break;
1396 case MetaActionType::CLIPREGION:
1397 case MetaActionType::ISECTREGIONCLIPREGION:
1398 case MetaActionType::MOVECLIPREGION:
1400 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1402 break;
1404 case MetaActionType::REFPOINT:
1405 case MetaActionType::MAPMODE:
1406 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1407 break;
1409 case MetaActionType::PUSH:
1411 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1413 ImplBeginRecord( WIN_EMR_SAVEDC );
1414 ImplEndRecord();
1416 break;
1418 case MetaActionType::POP:
1420 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1422 ImplBeginRecord( WIN_EMR_RESTOREDC );
1423 m_rStm.WriteInt32( -1 );
1424 ImplEndRecord();
1426 ImplWriteRasterOp( maVDev->GetRasterOp() );
1427 mbLineChanged = mbFillChanged = mbTextChanged = true;
1429 break;
1431 case MetaActionType::RASTEROP:
1433 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1434 ImplWriteRasterOp( static_cast<const MetaRasterOpAction*>(pAction)->GetRasterOp() );
1436 break;
1438 case MetaActionType::LAYOUTMODE:
1440 ComplexTextLayoutFlags nLayoutMode = static_cast<const MetaLayoutModeAction*>(pAction)->GetLayoutMode();
1441 mnHorTextAlign = 0;
1442 if ((nLayoutMode & ComplexTextLayoutFlags::BiDiRtl) != ComplexTextLayoutFlags::Default)
1444 mnHorTextAlign = TA_RIGHT | TA_RTLREADING;
1446 if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginRight) != ComplexTextLayoutFlags::Default)
1447 mnHorTextAlign |= TA_RIGHT;
1448 else if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginLeft) != ComplexTextLayoutFlags::Default)
1449 mnHorTextAlign &= ~TA_RIGHT;
1450 break;
1453 case MetaActionType::COMMENT:
1455 MetaCommentAction const*const pCommentAction(
1456 static_cast<MetaCommentAction const*>(pAction));
1457 if (pCommentAction->GetComment() == "EMF_PLUS")
1459 ImplBeginCommentRecord(WIN_EMR_COMMENT_EMFPLUS);
1460 m_rStm.WriteBytes(pCommentAction->GetData(),
1461 pCommentAction->GetDataSize());
1462 ImplEndCommentRecord();
1465 break;
1467 case MetaActionType::MASK:
1468 case MetaActionType::MASKSCALE:
1469 case MetaActionType::MASKSCALEPART:
1470 case MetaActionType::WALLPAPER:
1471 case MetaActionType::TEXTLINE:
1472 case MetaActionType::GRADIENTEX:
1473 // Explicitly ignored cases
1474 break;
1476 default:
1477 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1478 break;
1483 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */