cid#1640468 Dereference after null check
[LibreOffice.git] / vcl / source / filter / wmf / emfwr.cxx
blob8914571531031a913a37ace9cabd1e3d864e831c
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_uInt64 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_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 );
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_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;
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_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 )
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;
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
374 nFillBytes ^= 3;
375 nFillBytes &= 3;
376 m_rStm.WriteUInt32( ( nActPos - mnRecordPos ) + nFillBytes );
377 m_rStm.Seek( nActPos );
378 while( nFillBytes-- )
379 m_rStm.WriteUChar( 0 );
380 mnRecordCount++;
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 );
401 ImplEndRecord();
403 // destroy handle of created object
404 ImplBeginRecord( WIN_EMR_DELETEOBJECT );
405 m_rStm.WriteUInt32( rHandle );
406 ImplEndRecord();
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 )) )
420 return;
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() );
427 ImplEndRecord();
429 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
430 m_rStm.WriteUInt32( mnLineHandle );
431 ImplEndRecord();
434 void EMFWriter::ImplCheckFillAttr()
436 if( !(mbFillChanged && ImplPrepareHandleSelect( mnFillHandle, FILL_SELECT )) )
437 return;
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*/ );
445 ImplEndRecord();
447 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
448 m_rStm.WriteUInt32( mnFillHandle );
449 ImplEndRecord();
452 void EMFWriter::ImplCheckTextAttr()
454 if( !(mbTextChanged && ImplPrepareHandleSelect( mnTextHandle, TEXT_SELECT )) )
455 return;
457 const vcl::Font& rFont = maVDev->GetFont();
458 const OUString& aFontName( rFont.GetFamilyName() );
459 sal_Int32 nWeight;
460 sal_uInt16 i;
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());
468 #ifndef _WIN32
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
475 // specific formats.
476 const tools::Long nAverageFontWidth(rFont.GetOrCalculateAverageFontWidth());
478 if(nFontHeight > 0)
480 const double fScaleFactor(static_cast<double>(nAverageFontWidth) / static_cast<double>(nFontHeight));
481 nFontWidth = static_cast<tools::Long>(static_cast<double>(nFontWidth) * fScaleFactor);
484 #endif
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;
528 default: break;
531 m_rStm.WriteUChar( nPitchAndFamily );
533 for( i = 0; i < 32; i++ )
534 m_rStm.WriteUInt16( ( i < aFontName.getLength() ) ? aFontName[ i ] : 0 );
536 // dummy elfFullName
537 for( i = 0; i < 64; i++ )
538 m_rStm.WriteUInt16( 0 );
540 // dummy elfStyle
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 ) ;
547 // dummy elfVendorId
548 m_rStm.WriteUInt32( 0 );
550 // dummy elfCulture
551 m_rStm.WriteUInt32( 0 );
553 // dummy elfPanose
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 );
559 ImplEndRecord();
561 // TextAlign
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 );
574 ImplEndRecord();
576 // Text color
577 ImplBeginRecord( WIN_EMR_SETTEXTCOLOR );
578 ImplWriteColor( maVDev->GetTextColor() );
579 ImplEndRecord();
581 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
582 m_rStm.WriteUInt32( mnTextHandle );
583 ImplEndRecord();
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 )
599 sal_uInt32 nROP2;
601 switch( 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 );
610 ImplEndRecord();
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();
636 m_rStm
637 .WriteInt32( aRect.Left() )
638 .WriteInt32( aRect.Top() )
639 .WriteInt32( right )
640 .WriteInt32( bottom );
643 void EMFWriter::ImplWritePolygonRecord( const tools::Polygon& rPoly, bool bClose )
645 if( !rPoly.GetSize() )
646 return;
648 if( rPoly.HasFlags() )
649 ImplWritePath( tools::PolyPolygon(rPoly), bClose );
650 else
652 if( bClose )
653 ImplCheckFillAttr();
655 ImplCheckLineAttr();
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 ] );
664 ImplEndRecord();
668 void EMFWriter::ImplWritePolyPolygonRecord( const tools::PolyPolygon& rPolyPoly )
670 sal_uInt16 n, i, nPolyCount = rPolyPoly.Count();
672 if( !nPolyCount )
673 return;
675 if( 1 == nPolyCount )
676 ImplWritePolygonRecord( rPolyPoly[ 0 ], true );
677 else
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() )
686 bHasFlags = true;
688 if( nTotalPoints )
690 if ( bHasFlags )
691 ImplWritePath( rPolyPoly, true );
692 else
694 ImplCheckFillAttr();
695 ImplCheckLineAttr();
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 ] );
709 ImplEndRecord();
715 void EMFWriter::ImplWritePath( const tools::PolyPolygon& rPolyPoly, bool bClosed )
717 if ( bClosed )
718 ImplCheckFillAttr();
719 ImplCheckLineAttr();
721 ImplBeginRecord( WIN_EMR_BEGINPATH );
722 ImplEndRecord();
724 sal_uInt16 n, o;
725 for ( auto const& rPoly : rPolyPoly )
727 n = 0;
728 while ( n < rPoly.GetSize() )
730 if( n == 0 )
732 ImplBeginRecord( WIN_EMR_MOVETOEX );
733 ImplWritePoint( rPoly[ 0 ] );
734 ImplEndRecord();
735 n++;
736 continue;
739 sal_uInt16 nBezPoints = 0;
741 while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == PolyFlags::Control ) )
742 nBezPoints += 3;
744 if ( nBezPoints )
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 ] );
755 ImplEndRecord();
756 n = n + nBezPoints;
758 else
760 sal_uInt16 nPoints = 1;
761 while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != PolyFlags::Control ) )
762 nPoints++;
764 if ( nPoints > 1 )
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 ] );
775 ImplEndRecord();
777 else
779 ImplBeginRecord( WIN_EMR_LINETO );
780 ImplWritePoint( rPoly[ n ] );
781 ImplEndRecord();
783 n = n + nPoints;
785 if ( bClosed && ( n == rPoly.GetSize() ) )
787 ImplBeginRecord( WIN_EMR_CLOSEFIGURE );
788 ImplEndRecord();
792 ImplBeginRecord( WIN_EMR_ENDPATH );
793 ImplEndRecord();
794 ImplBeginRecord( bClosed ? WIN_EMR_FILLPATH : WIN_EMR_STROKEPATH );
795 ImplWriteRect( rPolyPoly.GetBoundRect() );
796 ImplEndRecord();
799 void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt,
800 const Size& rSz, sal_uInt32 nROP )
802 if( rBmp.IsEmpty() )
803 return;
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
827 aMemStm.Seek( 0 );
828 aMemStm.ReadUInt32( nHeaderSize );
829 aMemStm.SeekRel( 10 );
830 aMemStm.ReadUInt16( nBitCount ).ReadUInt32( nCompression ).ReadUInt32( nImageSize );
831 aMemStm.SeekRel( 8 );
832 aMemStm.ReadUInt32( nColsUsed );
834 if (nBitCount <= 8)
836 if (nColsUsed)
837 nPalCount = nColsUsed;
838 else
839 nPalCount = 1 << static_cast<sal_uInt32>(nBitCount);
841 else
843 if (nCompression == BITFIELDS)
844 nPalCount = 3;
845 else
846 nPalCount = 0;
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 );
859 ImplEndRecord();
863 void EMFWriter::ImplWriteTextRecord( const Point& rPos, const OUString& rText, KernArraySpan pDXArray, sal_uInt32 nWidth )
865 sal_Int32 nLen = rText.getLength(), i;
867 if( !nLen )
868 return;
870 sal_uInt32 nNormWidth;
871 KernArray aOwnArray;
872 KernArraySpan pDX;
874 // get text sizes
875 if( !pDXArray.empty() )
877 nNormWidth = maVDev->GetTextWidth( rText );
878 pDX = pDXArray;
880 else
882 nNormWidth = basegfx::fround<sal_uInt32>(maVDev->GetTextArray(rText, &aOwnArray).nWidth);
883 pDX = aOwnArray;
886 if( nLen > 1 )
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());
895 pDX = aOwnArray;
897 const double fFactor = static_cast<double>(nWidth) / nNormWidth;
899 for( i = 0; i < ( nLen - 1 ); i++ )
900 aOwnArray[i] *= fFactor;
904 // write text record
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 ) );
915 // write text
916 for( i = 0; i < nLen; i++ )
917 m_rStm.WriteUInt16( rText[ i ] );
919 // padding word
920 if( nLen & 1 )
921 m_rStm.WriteUInt16( 0 );
923 // write DX array
924 ImplWriteExtent( pDX[ 0 ] );
926 if( nLen > 1 )
928 for (i = 1; i < nLen; i++)
929 ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] );
932 ImplEndRecord();
936 void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
938 if(!rLinePolygon.count())
939 return;
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())
955 return;
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();
979 switch( nType )
981 case MetaActionType::PIXEL:
983 const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
985 ImplCheckLineAttr();
986 ImplBeginRecord( WIN_EMR_SETPIXELV );
987 ImplWritePoint( pA->GetPoint() );
988 ImplWriteColor( pA->GetColor() );
989 ImplEndRecord();
991 break;
993 case MetaActionType::POINT:
995 if( maVDev->IsLineColor() )
997 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
999 ImplCheckLineAttr();
1000 ImplBeginRecord( WIN_EMR_SETPIXELV );
1001 ImplWritePoint( pA->GetPoint() );
1002 ImplWriteColor( maVDev->GetLineColor() );
1003 ImplEndRecord();
1006 break;
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() );
1020 ImplEndRecord();
1022 ImplBeginRecord( WIN_EMR_LINETO );
1023 ImplWritePoint( pA->GetEndPoint() );
1024 ImplEndRecord();
1026 ImplBeginRecord( WIN_EMR_SETPIXELV );
1027 ImplWritePoint( pA->GetEndPoint() );
1028 ImplWriteColor( maVDev->GetLineColor() );
1029 ImplEndRecord();
1031 else
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);
1041 break;
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() );
1054 ImplEndRecord();
1057 break;
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() ) );
1071 ImplEndRecord();
1074 break;
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() );
1087 ImplEndRecord();
1090 break;
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;
1101 switch( nType )
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 );
1108 break;
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 );
1115 break;
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 );
1122 break;
1124 case MetaActionType::POLYGON:
1125 aPoly = static_cast<const MetaPolygonAction*>(pAction)->GetPolygon();
1126 break;
1127 default: break;
1130 ImplWritePolygonRecord( aPoly, nType != MetaActionType::ARC );
1133 break;
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 );
1148 else
1150 // LineInfo used; handle Dash/Dot and fat lines
1151 Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1156 break;
1158 case MetaActionType::POLYPOLYGON:
1160 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1161 ImplWritePolyPolygonRecord( static_cast<const MetaPolyPolygonAction*>(pAction)->GetPolyPolygon() );
1163 break;
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 );
1174 break;
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 );
1184 break;
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();
1199 break;
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 );
1232 break;
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 )
1244 maVDev->Push();
1245 ImplBeginRecord( WIN_EMR_SAVEDC );
1246 ImplEndRecord();
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 );
1256 maVDev->Pop();
1257 ImplBeginRecord( WIN_EMR_RESTOREDC );
1258 m_rStm.WriteInt32( -1 );
1259 ImplEndRecord();
1260 break;
1264 break;
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 );
1271 break;
1273 case MetaActionType::BMPSCALE:
1275 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
1276 ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1278 break;
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 );
1288 break;
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 );
1302 else
1303 ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY );
1305 break;
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 );
1319 else
1320 ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1322 break;
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 );
1338 else
1339 ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1341 break;
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 );
1351 break;
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 );
1361 break;
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 );
1371 break;
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() );
1381 break;
1383 case MetaActionType::LINECOLOR:
1385 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1386 mbLineChanged = true;
1388 break;
1390 case MetaActionType::FILLCOLOR:
1392 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1393 mbFillChanged = true;
1395 break;
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;
1406 break;
1408 case MetaActionType::ISECTRECTCLIPREGION:
1410 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1412 ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT );
1413 ImplWriteRect( static_cast<const MetaISectRectClipRegionAction*>(pAction)->GetRect() );
1414 ImplEndRecord();
1416 break;
1418 case MetaActionType::CLIPREGION:
1419 case MetaActionType::ISECTREGIONCLIPREGION:
1420 case MetaActionType::MOVECLIPREGION:
1422 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1424 break;
1426 case MetaActionType::REFPOINT:
1427 case MetaActionType::MAPMODE:
1428 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1429 break;
1431 case MetaActionType::PUSH:
1433 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1435 ImplBeginRecord( WIN_EMR_SAVEDC );
1436 ImplEndRecord();
1438 break;
1440 case MetaActionType::POP:
1442 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1444 ImplBeginRecord( WIN_EMR_RESTOREDC );
1445 m_rStm.WriteInt32( -1 );
1446 ImplEndRecord();
1448 ImplWriteRasterOp( maVDev->GetRasterOp() );
1449 mbLineChanged = mbFillChanged = mbTextChanged = true;
1451 break;
1453 case MetaActionType::RASTEROP:
1455 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1456 ImplWriteRasterOp( static_cast<const MetaRasterOpAction*>(pAction)->GetRasterOp() );
1458 break;
1460 case MetaActionType::LAYOUTMODE:
1462 vcl::text::ComplexTextLayoutFlags nLayoutMode = static_cast<const MetaLayoutModeAction*>(pAction)->GetLayoutMode();
1463 mnHorTextAlign = 0;
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;
1472 break;
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();
1487 break;
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
1496 break;
1498 default:
1499 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1500 break;
1505 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */