build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / filter / wmf / emfwr.cxx
blob670a6ef480015f2d7329972a1e946b081e25842a
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"
22 #include <algorithm>
24 #include "emfwr.hxx"
25 #include <rtl/strbuf.hxx>
26 #include <tools/helpers.hxx>
27 #include <tools/fract.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <basegfx/polygon/b2dpolypolygon.hxx>
30 #include <vcl/lineinfo.hxx>
31 #include <vcl/dibtools.hxx>
32 #include <memory>
34 #define WIN_EMR_POLYGON 3
35 #define WIN_EMR_POLYLINE 4
36 #define WIN_EMR_POLYBEZIERTO 5
37 #define WIN_EMR_POLYLINETO 6
38 #define WIN_EMR_POLYPOLYGON 8
39 #define WIN_EMR_SETWINDOWEXTEX 9
40 #define WIN_EMR_SETWINDOWORGEX 10
41 #define WIN_EMR_SETVIEWPORTEXTEX 11
42 #define WIN_EMR_SETVIEWPORTORGEX 12
43 #define WIN_EMR_EOF 14
44 #define WIN_EMR_SETPIXELV 15
45 #define WIN_EMR_SETMAPMODE 17
46 #define WIN_EMR_SETBKMODE 18
47 #define WIN_EMR_SETROP2 20
48 #define WIN_EMR_SETTEXTALIGN 22
49 #define WIN_EMR_SETTEXTCOLOR 24
50 #define WIN_EMR_MOVETOEX 27
51 #define WIN_EMR_INTERSECTCLIPRECT 30
52 #define WIN_EMR_SAVEDC 33
53 #define WIN_EMR_RESTOREDC 34
54 #define WIN_EMR_SELECTOBJECT 37
55 #define WIN_EMR_CREATEPEN 38
56 #define WIN_EMR_CREATEBRUSHINDIRECT 39
57 #define WIN_EMR_DELETEOBJECT 40
58 #define WIN_EMR_ELLIPSE 42
59 #define WIN_EMR_RECTANGLE 43
60 #define WIN_EMR_ROUNDRECT 44
61 #define WIN_EMR_LINETO 54
62 #define WIN_EMR_BEGINPATH 59
63 #define WIN_EMR_ENDPATH 60
64 #define WIN_EMR_CLOSEFIGURE 61
65 #define WIN_EMR_FILLPATH 62
66 #define WIN_EMR_STROKEPATH 64
68 #define WIN_EMR_GDICOMMENT 70
69 #define WIN_EMR_STRETCHDIBITS 81
70 #define WIN_EMR_EXTCREATEFONTINDIRECTW 82
71 #define WIN_EMR_EXTTEXTOUTW 84
73 #define WIN_SRCCOPY 0x00CC0020L
74 #define WIN_SRCPAINT 0x00EE0086L
75 #define WIN_SRCAND 0x008800C6L
76 #define WIN_SRCINVERT 0x00660046L
77 #define WIN_EMR_COMMENT_EMFPLUS 0x2B464D45L
79 #define HANDLE_INVALID 0xffffffff
80 #define MAXHANDLES 65000
82 #define LINE_SELECT 0x00000001
83 #define FILL_SELECT 0x00000002
84 #define TEXT_SELECT 0x00000004
86 /* Text Alignment Options */
87 #define TA_RIGHT 2
89 #define TA_TOP 0
90 #define TA_BOTTOM 8
91 #define TA_BASELINE 24
92 #define TA_RTLREADING 256
94 #define MM_ANISOTROPIC 8
96 enum class EmfPlusRecordType
98 Header = 0x4001,
99 EndOfFile = 0x4002,
100 GetDC = 0x4004,
101 FillPolygon = 0x400C,
102 SetAntiAliasMode = 0x401E,
103 SetInterpolationMode = 0x4021,
104 SetPixelOffsetMode = 0x4022,
105 SetCompositingQuality = 0x4024
108 void EMFWriter::ImplBeginCommentRecord( sal_Int32 nCommentType )
110 ImplBeginRecord( WIN_EMR_GDICOMMENT );
111 m_rStm.SeekRel( 4 );
112 m_rStm.WriteInt32( nCommentType );
115 void EMFWriter::ImplEndCommentRecord()
117 if( mbRecordOpen )
119 sal_Int32 nActPos = m_rStm.Tell();
120 m_rStm.Seek( mnRecordPos + 8 );
121 m_rStm.WriteUInt32( nActPos - mnRecordPos - 0xc );
122 m_rStm.Seek( nActPos );
124 ImplEndRecord();
127 void EMFWriter::ImplBeginPlusRecord( EmfPlusRecordType nType, sal_uInt16 nFlags )
129 SAL_WARN_IF( mbRecordPlusOpen, "vcl", "Another EMF+ record is already opened!" );
131 if( !mbRecordPlusOpen )
133 mbRecordPlusOpen = true;
134 mnRecordPlusPos = m_rStm.Tell();
136 m_rStm.WriteUInt16( (sal_uInt16)nType ).WriteUInt16( nFlags );
137 m_rStm.SeekRel( 8 );
141 void EMFWriter::ImplEndPlusRecord()
143 SAL_WARN_IF( !mbRecordPlusOpen, "vcl", "EMF+ Record was not opened!" );
145 if( mbRecordPlusOpen )
147 sal_Int32 nActPos = m_rStm.Tell();
148 sal_Int32 nSize = nActPos - mnRecordPlusPos;
149 m_rStm.Seek( mnRecordPlusPos + 4 );
150 m_rStm.WriteUInt32( nSize ) // Size
151 .WriteUInt32( nSize - 0xc ); // Data Size
152 m_rStm.Seek( nActPos );
153 mbRecordPlusOpen = false;
157 void EMFWriter::ImplPlusRecord( EmfPlusRecordType nType, sal_uInt16 nFlags )
159 ImplBeginPlusRecord( nType, nFlags );
160 ImplEndPlusRecord();
163 void EMFWriter::WriteEMFPlusHeader( const Size &rMtfSizePix, const Size &rMtfSizeLog )
165 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS );
167 sal_Int32 nDPIX = rMtfSizePix.Width()*25;
168 sal_Int32 nDivX = rMtfSizeLog.Width()/100;
169 if (nDivX)
170 nDPIX /= nDivX; // DPI X
172 sal_Int32 nDPIY = rMtfSizePix.Height()*25;
173 sal_Int32 nDivY = rMtfSizeLog.Height()/100;
174 if (nDivY)
175 nDPIY /= nDivY; // DPI Y
177 m_rStm.WriteInt16( (sal_Int16)EmfPlusRecordType::Header );
178 m_rStm.WriteInt16( 0x01 ) // Flags - Dual Mode // TODO: Check this
179 .WriteInt32( 0x1C ) // Size
180 .WriteInt32( 0x10 ) // Data Size
181 .WriteInt32( 0xdbc01002 ) // (lower 12bits) 1-> v1 2-> v1.1 // TODO: Check this
182 .WriteInt32( 0x01 ) // Video display
183 .WriteInt32( nDPIX )
184 .WriteInt32( nDPIY );
185 ImplEndCommentRecord();
187 // Write more properties
188 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS );
189 ImplPlusRecord( EmfPlusRecordType::SetPixelOffsetMode, 0x0 );
190 ImplPlusRecord( EmfPlusRecordType::SetAntiAliasMode, 0x09 ); // TODO: Check actual values for AntiAlias
191 ImplPlusRecord( EmfPlusRecordType::SetCompositingQuality, 0x0100 ); // Default Quality
192 ImplPlusRecord( EmfPlusRecordType::SetInterpolationMode, 0x00 ); // Default
193 ImplPlusRecord( EmfPlusRecordType::GetDC, 0x00 );
194 ImplEndCommentRecord();
197 void EMFWriter::ImplWritePlusEOF()
199 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS );
200 ImplPlusRecord( EmfPlusRecordType::EndOfFile, 0x0 );
201 ImplEndCommentRecord();
204 void EMFWriter::ImplWritePlusColor( const Color& rColor, sal_uInt32 nTrans )
206 sal_uInt32 nAlpha = ((100-nTrans)*0xFF)/100;
207 sal_uInt32 nCol = rColor.GetBlue();
209 nCol |= ( (sal_uInt32) rColor.GetGreen() ) << 8;
210 nCol |= ( (sal_uInt32) rColor.GetRed() ) << 16;
211 nCol |= ( nAlpha << 24 );
212 m_rStm.WriteUInt32( nCol );
215 void EMFWriter::ImplWritePlusPoint( const Point& rPoint )
217 // Convert to pixels
218 const Point aPoint(maVDev->LogicToPixel( rPoint, maDestMapMode ));
219 m_rStm.WriteUInt16( aPoint.X() ).WriteUInt16( aPoint.Y() );
222 void EMFWriter::ImplWritePlusFillPolygonRecord( const tools::Polygon& rPoly, sal_uInt32 nTrans )
224 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS );
225 if( rPoly.GetSize() )
227 ImplBeginPlusRecord( EmfPlusRecordType::FillPolygon, 0xC000 ); // Sets the color as well
228 ImplWritePlusColor( maVDev->GetFillColor(), nTrans );
229 m_rStm.WriteUInt32( rPoly.GetSize() );
230 for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ )
231 ImplWritePlusPoint( rPoly[ i ] );
232 ImplEndPlusRecord();
234 ImplEndCommentRecord();
237 bool EMFWriter::WriteEMF(const GDIMetaFile& rMtf)
239 const sal_uLong nHeaderPos = m_rStm.Tell();
241 maVDev->EnableOutput( false );
242 maVDev->SetMapMode( rMtf.GetPrefMapMode() );
243 // don't work with pixel as destination map mode -> higher resolution preferable
244 maDestMapMode.SetMapUnit( MapUnit::Map100thMM );
245 mHandlesUsed = std::vector<bool>(MAXHANDLES, false);
246 mnHandleCount = mnRecordCount = mnRecordPos = mnRecordPlusPos = 0;
247 mbRecordOpen = mbRecordPlusOpen = false;
248 mbLineChanged = mbFillChanged = mbTextChanged = false;
249 mnLineHandle = mnFillHandle = mnTextHandle = HANDLE_INVALID;
250 mnHorTextAlign = 0;
252 const Size aMtfSizePix( maVDev->LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) );
253 const Size aMtfSizeLog( OutputDevice::LogicToLogic( rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapUnit::Map100thMM ) );
255 // seek over header
256 // use [MS-EMF 2.2.11] HeaderExtension2 Object, otherwise resulting EMF cannot be converted with GetWinMetaFileBits()
257 m_rStm.SeekRel( 108 );
259 // Write EMF+ Header
260 WriteEMFPlusHeader( aMtfSizePix, aMtfSizeLog );
262 // write initial values
264 // set 100th mm map mode in EMF
265 ImplBeginRecord( WIN_EMR_SETMAPMODE );
266 m_rStm.WriteInt32( MM_ANISOTROPIC );
267 ImplEndRecord();
269 ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX );
270 m_rStm.WriteInt32( maVDev->GetDPIX() ).WriteInt32( maVDev->GetDPIY() );
271 ImplEndRecord();
273 ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX );
274 m_rStm.WriteInt32( 2540 ).WriteInt32( 2540 );
275 ImplEndRecord();
277 ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX );
278 m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
279 ImplEndRecord();
281 ImplBeginRecord( WIN_EMR_SETWINDOWORGEX );
282 m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
283 ImplEndRecord();
285 ImplWriteRasterOp( RasterOp::OverPaint );
287 ImplBeginRecord( WIN_EMR_SETBKMODE );
288 m_rStm.WriteUInt32( 1 ); // TRANSPARENT
289 ImplEndRecord();
291 // write emf data
292 ImplWrite( rMtf );
294 ImplWritePlusEOF();
296 ImplBeginRecord( WIN_EMR_EOF );
297 m_rStm.WriteUInt32( 0 ) // nPalEntries
298 .WriteUInt32( 0x10 ) // offPalEntries
299 .WriteUInt32( 0x14 ); // nSizeLast
300 ImplEndRecord();
302 // write header
303 const sal_uLong nEndPos = m_rStm.Tell(); m_rStm.Seek( nHeaderPos );
305 m_rStm.WriteUInt32( 0x00000001 ).WriteUInt32( 108 ) //use [MS-EMF 2.2.11] HeaderExtension2 Object
306 .WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aMtfSizePix.Width() - 1 ).WriteInt32( aMtfSizePix.Height() - 1 )
307 .WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aMtfSizeLog.Width() - 1 ).WriteInt32( aMtfSizeLog.Height() - 1 )
308 .WriteUInt32( 0x464d4520 ).WriteUInt32( 0x10000 ).WriteUInt32( nEndPos - nHeaderPos )
309 .WriteUInt32( mnRecordCount ).WriteUInt16( mnHandleCount + 1 ).WriteUInt16( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
310 .WriteInt32( aMtfSizePix.Width() ).WriteInt32( aMtfSizePix.Height() )
311 .WriteInt32( aMtfSizeLog.Width() / 100 ).WriteInt32( aMtfSizeLog.Height() / 100 )
312 .WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
313 .WriteInt32( aMtfSizeLog.Width() * 10 ).WriteInt32( aMtfSizeLog.Height() * 10 ); //use [MS-EMF 2.2.11] HeaderExtension2 Object
315 m_rStm.Seek( nEndPos );
316 mHandlesUsed.clear();
318 return( m_rStm.GetError() == ERRCODE_NONE );
321 sal_uLong EMFWriter::ImplAcquireHandle()
323 sal_uLong nHandle = HANDLE_INVALID;
325 for( sal_uLong i = 0; i < mHandlesUsed.size() && ( HANDLE_INVALID == nHandle ); i++ )
327 if( !mHandlesUsed[ i ] )
329 mHandlesUsed[ i ] = true;
331 if( ( nHandle = i ) == mnHandleCount )
332 mnHandleCount++;
336 SAL_WARN_IF( nHandle == HANDLE_INVALID, "vcl", "No more handles available" );
337 return( nHandle != HANDLE_INVALID ? nHandle + 1 : HANDLE_INVALID );
340 void EMFWriter::ImplReleaseHandle( sal_uLong nHandle )
342 SAL_WARN_IF( !nHandle || ( nHandle >= mHandlesUsed.size() ), "vcl", "Handle out of range" );
343 mHandlesUsed[ nHandle - 1 ] = false;
346 void EMFWriter::ImplBeginRecord( sal_uInt32 nType )
348 SAL_WARN_IF( mbRecordOpen, "vcl", "Another record is already opened!" );
350 if( !mbRecordOpen )
352 mbRecordOpen = true;
353 mnRecordPos = m_rStm.Tell();
355 m_rStm.WriteUInt32( nType );
356 m_rStm.SeekRel( 4 );
360 void EMFWriter::ImplEndRecord()
362 SAL_WARN_IF( !mbRecordOpen, "vcl", "Record was not opened!" );
364 if( mbRecordOpen )
366 sal_Int32 nFillBytes, nActPos = m_rStm.Tell();
367 m_rStm.Seek( mnRecordPos + 4 );
368 nFillBytes = nActPos - mnRecordPos;
369 nFillBytes += 3; // each record has to be dword aligned
370 nFillBytes ^= 3;
371 nFillBytes &= 3;
372 m_rStm.WriteUInt32( ( nActPos - mnRecordPos ) + nFillBytes );
373 m_rStm.Seek( nActPos );
374 while( nFillBytes-- )
375 m_rStm.WriteUChar( 0 );
376 mnRecordCount++;
377 mbRecordOpen = false;
381 bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType )
383 if( rHandle != HANDLE_INVALID )
385 sal_uInt32 nStockObject = 0x80000000;
387 if( LINE_SELECT == nSelectType )
388 nStockObject |= 0x00000007;
389 else if( FILL_SELECT == nSelectType )
390 nStockObject |= 0x00000001;
391 else if( TEXT_SELECT == nSelectType )
392 nStockObject |= 0x0000000a;
394 // select stock object first
395 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
396 m_rStm.WriteUInt32( nStockObject );
397 ImplEndRecord();
399 // destroy handle of created object
400 ImplBeginRecord( WIN_EMR_DELETEOBJECT );
401 m_rStm.WriteUInt32( rHandle );
402 ImplEndRecord();
404 // mark handle as free
405 ImplReleaseHandle( rHandle );
408 rHandle = ImplAcquireHandle();
410 return( HANDLE_INVALID != rHandle );
413 void EMFWriter::ImplCheckLineAttr()
415 if( mbLineChanged && ImplPrepareHandleSelect( mnLineHandle, LINE_SELECT ) )
417 sal_uInt32 nStyle = maVDev->IsLineColor() ? 0 : 5;
418 sal_uInt32 nWidth = 0, nHeight = 0;
420 ImplBeginRecord( WIN_EMR_CREATEPEN );
421 m_rStm.WriteUInt32( mnLineHandle ).WriteUInt32( nStyle ).WriteUInt32( nWidth ).WriteUInt32( nHeight );
422 ImplWriteColor( maVDev->GetLineColor() );
423 ImplEndRecord();
425 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
426 m_rStm.WriteUInt32( mnLineHandle );
427 ImplEndRecord();
431 void EMFWriter::ImplCheckFillAttr()
433 if( mbFillChanged && ImplPrepareHandleSelect( mnFillHandle, FILL_SELECT ) )
435 sal_uInt32 nStyle = maVDev->IsFillColor() ? 0 : 1;
436 sal_uInt32 nPatternStyle = 0;
438 ImplBeginRecord( WIN_EMR_CREATEBRUSHINDIRECT );
439 m_rStm.WriteUInt32( mnFillHandle ).WriteUInt32( nStyle );
440 ImplWriteColor( maVDev->GetFillColor() );
441 m_rStm.WriteUInt32( nPatternStyle );
442 ImplEndRecord();
444 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
445 m_rStm.WriteUInt32( mnFillHandle );
446 ImplEndRecord();
450 void EMFWriter::ImplCheckTextAttr()
452 if( mbTextChanged && ImplPrepareHandleSelect( mnTextHandle, TEXT_SELECT ) )
454 const vcl::Font& rFont = maVDev->GetFont();
455 const OUString& aFontName( rFont.GetFamilyName() );
456 sal_Int32 nWeight;
457 sal_uInt16 i;
458 sal_uInt8 nPitchAndFamily;
460 ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW );
461 m_rStm.WriteUInt32( mnTextHandle );
462 ImplWriteExtent( -rFont.GetFontSize().Height() );
463 ImplWriteExtent( rFont.GetFontSize().Width() );
464 m_rStm.WriteInt32( rFont.GetOrientation() ).WriteInt32( rFont.GetOrientation() );
466 switch( rFont.GetWeight() )
468 case WEIGHT_THIN: nWeight = 100; break;
469 case WEIGHT_ULTRALIGHT: nWeight = 200; break;
470 case WEIGHT_LIGHT: nWeight = 300; break;
471 case WEIGHT_SEMILIGHT: nWeight = 300; break;
472 case WEIGHT_NORMAL: nWeight = 400; break;
473 case WEIGHT_MEDIUM: nWeight = 500; break;
474 case WEIGHT_SEMIBOLD: nWeight = 600; break;
475 case WEIGHT_BOLD: nWeight = 700; break;
476 case WEIGHT_ULTRABOLD: nWeight = 800; break;
477 case WEIGHT_BLACK: nWeight = 900; break;
478 default: nWeight = 0; break;
481 m_rStm.WriteInt32( nWeight );
482 m_rStm.WriteUChar( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 );
483 m_rStm.WriteUChar( ( LINESTYLE_NONE == rFont.GetUnderline() ) ? 0 : 1 );
484 m_rStm.WriteUChar( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 );
485 m_rStm.WriteUChar( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 );
486 m_rStm.WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
488 switch( rFont.GetPitch() )
490 case PITCH_FIXED: nPitchAndFamily = 0x01; break;
491 case PITCH_VARIABLE: nPitchAndFamily = 0x02; break;
492 default: nPitchAndFamily = 0x00; break;
495 switch( rFont.GetFamilyType() )
497 case FAMILY_DECORATIVE: nPitchAndFamily |= 0x50; break;
498 case FAMILY_MODERN: nPitchAndFamily |= 0x30; break;
499 case FAMILY_ROMAN: nPitchAndFamily |= 0x10; break;
500 case FAMILY_SCRIPT: nPitchAndFamily |= 0x40; break;
501 case FAMILY_SWISS: nPitchAndFamily |= 0x20; break;
502 default: break;
505 m_rStm.WriteUChar( nPitchAndFamily );
507 for( i = 0; i < 32; i++ )
508 m_rStm.WriteUInt16( ( i < aFontName.getLength() ) ? aFontName[ i ] : 0 );
510 // dummy elfFullName
511 for( i = 0; i < 64; i++ )
512 m_rStm.WriteUInt16( 0 );
514 // dummy elfStyle
515 for( i = 0; i < 32; i++ )
516 m_rStm.WriteUInt16( 0 );
518 // dummy elfVersion, elfStyleSize, elfMatch, elfReserved
519 m_rStm.WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ) ;
521 // dummy elfVendorId
522 m_rStm.WriteUInt32( 0 );
524 // dummy elfCulture
525 m_rStm.WriteUInt32( 0 );
527 // dummy elfPanose
528 m_rStm.WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
530 // fill record to get a record size divideable by 4
531 m_rStm.WriteUInt16( 0 );
533 ImplEndRecord();
535 // TextAlign
536 sal_uInt32 nTextAlign;
538 switch( rFont.GetAlignment() )
540 case ALIGN_TOP: nTextAlign = TA_TOP; break;
541 case ALIGN_BOTTOM: nTextAlign = TA_BOTTOM; break;
542 default: nTextAlign = TA_BASELINE; break;
544 nTextAlign |= mnHorTextAlign;
546 ImplBeginRecord( WIN_EMR_SETTEXTALIGN );
547 m_rStm.WriteUInt32( nTextAlign );
548 ImplEndRecord();
550 // Text color
551 ImplBeginRecord( WIN_EMR_SETTEXTCOLOR );
552 ImplWriteColor( maVDev->GetTextColor() );
553 ImplEndRecord();
555 ImplBeginRecord( WIN_EMR_SELECTOBJECT );
556 m_rStm.WriteUInt32( mnTextHandle );
557 ImplEndRecord();
561 void EMFWriter::ImplWriteColor( const Color& rColor )
563 sal_uInt32 nCol = rColor.GetRed();
565 nCol |= ( (sal_uInt32) rColor.GetGreen() ) << 8;
566 nCol |= ( (sal_uInt32) rColor.GetBlue() ) << 16;
568 m_rStm.WriteUInt32( nCol );
571 void EMFWriter::ImplWriteRasterOp( RasterOp eRop )
573 sal_uInt32 nROP2;
575 switch( eRop )
577 case RasterOp::Invert: nROP2 = 6; break;
578 case RasterOp::Xor: nROP2 = 7; break;
579 default: nROP2 = 13;break;
582 ImplBeginRecord( WIN_EMR_SETROP2 );
583 m_rStm.WriteUInt32( nROP2 );
584 ImplEndRecord();
587 void EMFWriter::ImplWriteExtent( long nExtent )
589 nExtent = OutputDevice::LogicToLogic( Size( nExtent, 0 ), maVDev->GetMapMode(), maDestMapMode ).Width();
590 m_rStm.WriteInt32( nExtent );
593 void EMFWriter::ImplWritePoint( const Point& rPoint )
595 const Point aPoint( OutputDevice::LogicToLogic( rPoint, maVDev->GetMapMode(), maDestMapMode ));
596 m_rStm.WriteInt32( aPoint.X() ).WriteInt32( aPoint.Y() );
599 void EMFWriter::ImplWriteSize( const Size& rSize)
601 const Size aSize( OutputDevice::LogicToLogic( rSize, maVDev->GetMapMode(), maDestMapMode ));
602 m_rStm.WriteInt32( aSize.Width() ).WriteInt32( aSize.Height() );
605 void EMFWriter::ImplWriteRect( const Rectangle& rRect )
607 const Rectangle aRect( OutputDevice::LogicToLogic ( rRect, maVDev->GetMapMode(), maDestMapMode ));
608 m_rStm
609 .WriteInt32( aRect.Left() )
610 .WriteInt32( aRect.Top() )
611 .WriteInt32( aRect.Right() )
612 .WriteInt32( aRect.Bottom() );
615 void EMFWriter::ImplWritePolygonRecord( const tools::Polygon& rPoly, bool bClose )
617 if( rPoly.GetSize() )
619 if( rPoly.HasFlags() )
620 ImplWritePath( rPoly, bClose );
621 else
623 if( bClose )
624 ImplCheckFillAttr();
626 ImplCheckLineAttr();
628 ImplBeginRecord( bClose ? WIN_EMR_POLYGON : WIN_EMR_POLYLINE );
629 ImplWriteRect( rPoly.GetBoundRect() );
630 m_rStm.WriteUInt32( rPoly.GetSize() );
632 for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ )
633 ImplWritePoint( rPoly[ i ] );
635 ImplEndRecord();
640 void EMFWriter::ImplWritePolyPolygonRecord( const tools::PolyPolygon& rPolyPoly )
642 sal_uInt16 n, i, nPolyCount = rPolyPoly.Count();
644 if( nPolyCount )
646 if( 1 == nPolyCount )
647 ImplWritePolygonRecord( rPolyPoly[ 0 ], true );
648 else
650 bool bHasFlags = false;
651 sal_uInt32 nTotalPoints = 0;
653 for( i = 0; i < nPolyCount; i++ )
655 nTotalPoints += rPolyPoly[ i ].GetSize();
656 if ( rPolyPoly[ i ].HasFlags() )
657 bHasFlags = true;
659 if( nTotalPoints )
661 if ( bHasFlags )
662 ImplWritePath( rPolyPoly, true );
663 else
665 ImplCheckFillAttr();
666 ImplCheckLineAttr();
668 ImplBeginRecord( WIN_EMR_POLYPOLYGON );
669 ImplWriteRect( rPolyPoly.GetBoundRect() );
670 m_rStm.WriteUInt32( nPolyCount ).WriteUInt32( nTotalPoints );
672 for( i = 0; i < nPolyCount; i++ )
673 m_rStm.WriteUInt32( rPolyPoly[ i ].GetSize() );
675 for( i = 0; i < nPolyCount; i++ )
677 const tools::Polygon& rPoly = rPolyPoly[ i ];
679 for( n = 0; n < rPoly.GetSize(); n++ )
680 ImplWritePoint( rPoly[ n ] );
682 ImplEndRecord();
689 void EMFWriter::ImplWritePath( const tools::PolyPolygon& rPolyPoly, bool bClosed )
691 if ( bClosed )
692 ImplCheckFillAttr();
693 ImplCheckLineAttr();
695 ImplBeginRecord( WIN_EMR_BEGINPATH );
696 ImplEndRecord();
698 sal_uInt16 i, n, o, nPolyCount = rPolyPoly.Count();
699 for ( i = 0; i < nPolyCount; i++ )
701 n = 0;
702 const tools::Polygon& rPoly = rPolyPoly[ i ];
703 while ( n < rPoly.GetSize() )
705 if( n == 0 )
707 ImplBeginRecord( WIN_EMR_MOVETOEX );
708 ImplWritePoint( rPoly[ 0 ] );
709 ImplEndRecord();
710 n++;
711 continue;
714 sal_uInt16 nBezPoints = 0;
716 while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == PolyFlags::Control ) )
717 nBezPoints += 3;
719 if ( nBezPoints )
721 ImplBeginRecord( WIN_EMR_POLYBEZIERTO );
722 tools::Polygon aNewPoly( nBezPoints + 1 );
723 aNewPoly[ 0 ] = rPoly[ n - 1 ];
724 for ( o = 0; o < nBezPoints; o++ )
725 aNewPoly[ o + 1 ] = rPoly[ n + o ];
726 ImplWriteRect( aNewPoly.GetBoundRect() );
727 m_rStm.WriteUInt32( nBezPoints );
728 for( o = 1; o < aNewPoly.GetSize(); o++ )
729 ImplWritePoint( aNewPoly[ o ] );
730 ImplEndRecord();
731 n = n + nBezPoints;
733 else
735 sal_uInt16 nPoints = 1;
736 while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != PolyFlags::Control ) )
737 nPoints++;
739 if ( nPoints > 1 )
741 ImplBeginRecord( WIN_EMR_POLYLINETO );
742 tools::Polygon aNewPoly( nPoints + 1 );
743 aNewPoly[ 0 ] = rPoly[ n - 1];
744 for ( o = 1; o <= nPoints; o++ )
745 aNewPoly[ o ] = rPoly[ n - 1 + o ];
746 ImplWriteRect( aNewPoly.GetBoundRect() );
747 m_rStm.WriteUInt32( nPoints );
748 for( o = 1; o < aNewPoly.GetSize(); o++ )
749 ImplWritePoint( aNewPoly[ o ] );
750 ImplEndRecord();
752 else
754 ImplBeginRecord( WIN_EMR_LINETO );
755 ImplWritePoint( rPoly[ n ] );
756 ImplEndRecord();
758 n = n + nPoints;
760 if ( bClosed && ( n == rPoly.GetSize() ) )
762 ImplBeginRecord( WIN_EMR_CLOSEFIGURE );
763 ImplEndRecord();
767 ImplBeginRecord( WIN_EMR_ENDPATH );
768 ImplEndRecord();
769 ImplBeginRecord( bClosed ? WIN_EMR_FILLPATH : WIN_EMR_STROKEPATH );
770 ImplWriteRect( rPolyPoly.GetBoundRect() );
771 ImplEndRecord();
774 void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt,
775 const Size& rSz, sal_uInt32 nROP )
777 if( !!rBmp )
779 SvMemoryStream aMemStm( 65535, 65535 );
780 const Size aBmpSizePixel( rBmp.GetSizePixel() );
782 ImplBeginRecord( WIN_EMR_STRETCHDIBITS );
783 ImplWriteRect( Rectangle( rPt, rSz ) );
784 ImplWritePoint( rPt );
785 m_rStm.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aBmpSizePixel.Width() ).WriteInt32( aBmpSizePixel.Height() );
787 // write offset positions and sizes later
788 const sal_uLong nOffPos = m_rStm.Tell();
789 m_rStm.SeekRel( 16 );
791 m_rStm.WriteUInt32( 0 ).WriteInt32( ( RasterOp::Xor == maVDev->GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP );
792 ImplWriteSize( rSz );
794 WriteDIB(rBmp, aMemStm, true, false);
796 sal_uInt32 nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize;
797 sal_uInt16 nBitCount;
799 // get DIB parameters
800 aMemStm.Seek( 0 );
801 aMemStm.ReadUInt32( nHeaderSize );
802 aMemStm.SeekRel( 10 );
803 aMemStm.ReadUInt16( nBitCount ).ReadUInt32( nCompression ).ReadUInt32( nImageSize );
804 aMemStm.SeekRel( 8 );
805 aMemStm.ReadUInt32( nColsUsed );
807 if (nBitCount <= 8)
809 if (nColsUsed)
810 nPalCount = nColsUsed;
811 else
812 nPalCount = 1 << (sal_uInt32)nBitCount;
814 else
816 if (nCompression == BITFIELDS)
817 nPalCount = 3;
818 else
819 nPalCount = 0;
822 sal_uInt32 nPalSize = nPalCount * 4;
824 m_rStm.WriteBytes( aMemStm.GetData(), nDIBSize );
826 const sal_uLong nEndPos = m_rStm.Tell();
827 m_rStm.Seek( nOffPos );
828 m_rStm.WriteUInt32( 80 ).WriteUInt32( nHeaderSize + nPalSize );
829 m_rStm.WriteUInt32( 80 + nHeaderSize + nPalSize ).WriteUInt32( nImageSize );
830 m_rStm.Seek( nEndPos );
832 ImplEndRecord();
836 void EMFWriter::ImplWriteTextRecord( const Point& rPos, const OUString& rText, const long* pDXArray, sal_uInt32 nWidth )
838 sal_Int32 nLen = rText.getLength(), i;
840 if( nLen )
842 sal_uInt32 nNormWidth;
843 std::unique_ptr<long[]> pOwnArray;
844 long* pDX;
846 // get text sizes
847 if( pDXArray )
849 nNormWidth = maVDev->GetTextWidth( rText );
850 pDX = const_cast<long*>(pDXArray);
852 else
854 pOwnArray.reset(new long[ nLen ]);
855 nNormWidth = maVDev->GetTextArray( rText, pOwnArray.get() );
856 pDX = pOwnArray.get();
859 if( nLen > 1 )
861 nNormWidth = pDX[ nLen - 2 ] + maVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) );
863 if( nWidth && nNormWidth && ( nWidth != nNormWidth ) )
865 const double fFactor = (double) nWidth / nNormWidth;
867 for( i = 0; i < ( nLen - 1 ); i++ )
868 pDX[ i ] = FRound( pDX[ i ] * fFactor );
872 // write text record
873 ImplBeginRecord( WIN_EMR_EXTTEXTOUTW );
875 ImplWriteRect( Rectangle( rPos, Size( nNormWidth, maVDev->GetTextHeight() ) ) );
876 m_rStm.WriteUInt32( 1 );
877 m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
878 ImplWritePoint( rPos );
879 m_rStm.WriteUInt32( nLen ).WriteUInt32( 76 ).WriteUInt32( 2 );
880 m_rStm.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 );
881 m_rStm.WriteUInt32( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) );
883 // write text
884 for( i = 0; i < nLen; i++ )
885 m_rStm.WriteUInt16( rText[ i ] );
887 // padding word
888 if( nLen & 1 )
889 m_rStm.WriteUInt16( 0 );
891 // write DX array
892 ImplWriteExtent( pDX[ 0 ] );
894 if( nLen > 1 )
896 for( i = 1; i < ( nLen - 1 ); i++ )
897 ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] );
899 ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) );
902 ImplEndRecord();
906 void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
908 if(rLinePolygon.count())
910 basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
911 basegfx::B2DPolyPolygon aFillPolyPolygon;
913 rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
915 if(aLinePolyPolygon.count())
917 for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
919 const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
920 ImplWritePolygonRecord( tools::Polygon(aCandidate), false );
924 if(aFillPolyPolygon.count())
926 const Color aOldLineColor(maVDev->GetLineColor());
927 const Color aOldFillColor(maVDev->GetFillColor());
929 maVDev->SetLineColor();
930 maVDev->SetFillColor(aOldLineColor);
932 for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
934 const tools::Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
935 ImplWritePolyPolygonRecord(tools::PolyPolygon( tools::Polygon(aPolygon) ));
938 maVDev->SetLineColor(aOldLineColor);
939 maVDev->SetFillColor(aOldFillColor);
944 void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
946 for( size_t j = 0, nActionCount = rMtf.GetActionSize(); j < nActionCount; j++ )
948 const MetaAction* pAction = rMtf.GetAction( j );
949 const MetaActionType nType = pAction->GetType();
951 switch( nType )
953 case( MetaActionType::PIXEL ):
955 const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
957 ImplCheckLineAttr();
958 ImplBeginRecord( WIN_EMR_SETPIXELV );
959 ImplWritePoint( pA->GetPoint() );
960 ImplWriteColor( pA->GetColor() );
961 ImplEndRecord();
963 break;
965 case( MetaActionType::POINT ):
967 if( maVDev->IsLineColor() )
969 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
971 ImplCheckLineAttr();
972 ImplBeginRecord( WIN_EMR_SETPIXELV );
973 ImplWritePoint( pA->GetPoint() );
974 ImplWriteColor( maVDev->GetLineColor() );
975 ImplEndRecord();
978 break;
980 case( MetaActionType::LINE ):
982 if( maVDev->IsLineColor() )
984 const MetaLineAction* pA = static_cast<const MetaLineAction*>(pAction);
986 if(pA->GetLineInfo().IsDefault())
988 ImplCheckLineAttr();
990 ImplBeginRecord( WIN_EMR_MOVETOEX );
991 ImplWritePoint( pA->GetStartPoint() );
992 ImplEndRecord();
994 ImplBeginRecord( WIN_EMR_LINETO );
995 ImplWritePoint( pA->GetEndPoint() );
996 ImplEndRecord();
998 ImplBeginRecord( WIN_EMR_SETPIXELV );
999 ImplWritePoint( pA->GetEndPoint() );
1000 ImplWriteColor( maVDev->GetLineColor() );
1001 ImplEndRecord();
1003 else
1005 // LineInfo used; handle Dash/Dot and fat lines
1006 basegfx::B2DPolygon aPolygon;
1007 aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1008 aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1009 Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
1013 break;
1015 case( MetaActionType::RECT ):
1017 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1019 const MetaRectAction* pA = static_cast<const MetaRectAction*>(pAction);
1021 ImplCheckFillAttr();
1022 ImplCheckLineAttr();
1024 ImplBeginRecord( WIN_EMR_RECTANGLE );
1025 ImplWriteRect( pA->GetRect() );
1026 ImplEndRecord();
1029 break;
1031 case( MetaActionType::ROUNDRECT ):
1033 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1035 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pAction);
1037 ImplCheckFillAttr();
1038 ImplCheckLineAttr();
1040 ImplBeginRecord( WIN_EMR_ROUNDRECT );
1041 ImplWriteRect( pA->GetRect() );
1042 ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) );
1043 ImplEndRecord();
1046 break;
1048 case( MetaActionType::ELLIPSE ):
1050 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1052 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pAction);
1054 ImplCheckFillAttr();
1055 ImplCheckLineAttr();
1057 ImplBeginRecord( WIN_EMR_ELLIPSE );
1058 ImplWriteRect( pA->GetRect() );
1059 ImplEndRecord();
1062 break;
1064 case( MetaActionType::ARC ):
1065 case( MetaActionType::PIE ):
1066 case( MetaActionType::CHORD ):
1067 case( MetaActionType::POLYGON ):
1069 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1071 tools::Polygon aPoly;
1073 switch( nType )
1075 case( MetaActionType::ARC ):
1077 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
1078 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
1080 break;
1082 case( MetaActionType::PIE ):
1084 const MetaPieAction* pA = static_cast<const MetaPieAction*>(pAction);
1085 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
1087 break;
1089 case( MetaActionType::CHORD ):
1091 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pAction);
1092 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
1094 break;
1096 case( MetaActionType::POLYGON ):
1097 aPoly = static_cast<const MetaPolygonAction*>(pAction)->GetPolygon();
1098 break;
1099 default: break;
1102 ImplWritePolygonRecord( aPoly, nType != MetaActionType::ARC );
1105 break;
1107 case( MetaActionType::POLYLINE ):
1109 if( maVDev->IsLineColor() )
1111 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pAction);
1112 const tools::Polygon& rPoly = pA->GetPolygon();
1114 if( rPoly.GetSize() )
1116 if(pA->GetLineInfo().IsDefault())
1118 ImplWritePolygonRecord( rPoly, false );
1120 else
1122 // LineInfo used; handle Dash/Dot and fat lines
1123 Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1128 break;
1130 case( MetaActionType::POLYPOLYGON ):
1132 if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1133 ImplWritePolyPolygonRecord( static_cast<const MetaPolyPolygonAction*>(pAction)->GetPolyPolygon() );
1135 break;
1137 case( MetaActionType::GRADIENT ):
1139 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pAction);
1140 GDIMetaFile aTmpMtf;
1142 maVDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1143 ImplWrite( aTmpMtf );
1145 break;
1147 case MetaActionType::HATCH:
1149 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
1150 GDIMetaFile aTmpMtf;
1152 maVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1153 ImplWrite( aTmpMtf );
1155 break;
1157 case MetaActionType::Transparent:
1159 const tools::PolyPolygon& rPolyPoly = static_cast<const MetaTransparentAction*>(pAction)->GetPolyPolygon();
1160 if( rPolyPoly.Count() )
1161 ImplWritePlusFillPolygonRecord( rPolyPoly[0], static_cast<const MetaTransparentAction*>(pAction)->GetTransparence() );
1162 ImplCheckFillAttr();
1163 ImplCheckLineAttr();
1164 ImplWritePolyPolygonRecord( rPolyPoly );
1166 ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS );
1167 ImplPlusRecord( EmfPlusRecordType::GetDC, 0x00 );
1168 ImplEndCommentRecord();
1170 break;
1172 case MetaActionType::FLOATTRANSPARENT:
1174 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
1176 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1177 Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1178 const Size aSrcSize( aTmpMtf.GetPrefSize() );
1179 const Point aDestPt( pA->GetPoint() );
1180 const Size aDestSize( pA->GetSize() );
1181 const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1182 const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1183 long nMoveX, nMoveY;
1185 if( fScaleX != 1.0 || fScaleY != 1.0 )
1187 aTmpMtf.Scale( fScaleX, fScaleY );
1188 aSrcPt.X() = FRound( aSrcPt.X() * fScaleX );
1189 aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1192 nMoveX = aDestPt.X() - aSrcPt.X();
1193 nMoveY = aDestPt.Y() - aSrcPt.Y();
1195 if( nMoveX || nMoveY )
1196 aTmpMtf.Move( nMoveX, nMoveY );
1198 ImplCheckFillAttr();
1199 ImplCheckLineAttr();
1200 ImplCheckTextAttr();
1201 ImplWrite( aTmpMtf );
1203 break;
1205 case( MetaActionType::EPS ):
1207 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pAction);
1208 const GDIMetaFile aSubstitute( pA->GetSubstitute() );
1210 for( size_t i = 0, nCount = aSubstitute.GetActionSize(); i < nCount; i++ )
1212 const MetaAction* pSubstAct = aSubstitute.GetAction( i );
1213 if( pSubstAct->GetType() == MetaActionType::BMPSCALE )
1215 maVDev->Push();
1216 ImplBeginRecord( WIN_EMR_SAVEDC );
1217 ImplEndRecord();
1219 MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1220 Size aOutSize( OutputDevice::LogicToLogic( pA->GetSize(), maVDev->GetMapMode(), aMapMode ) );
1221 aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
1222 aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
1223 aMapMode.SetOrigin( OutputDevice::LogicToLogic( pA->GetPoint(), maVDev->GetMapMode(), aMapMode ) );
1224 maVDev->SetMapMode( aMapMode );
1225 ImplWrite( aSubstitute );
1227 maVDev->Pop();
1228 ImplBeginRecord( WIN_EMR_RESTOREDC );
1229 m_rStm.WriteInt32( -1 );
1230 ImplEndRecord();
1231 break;
1235 break;
1237 case MetaActionType::BMP:
1239 const MetaBmpAction* pA = static_cast<const MetaBmpAction *>(pAction);
1240 ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ), WIN_SRCCOPY );
1242 break;
1244 case MetaActionType::BMPSCALE:
1246 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
1247 ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1249 break;
1251 case MetaActionType::BMPSCALEPART:
1253 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pAction);
1254 Bitmap aTmp( pA->GetBitmap() );
1256 if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1257 ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1259 break;
1261 case MetaActionType::BMPEX:
1263 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction *>(pAction);
1264 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1265 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1267 if( !!aMsk )
1269 aBmp.Replace( aMsk, COL_WHITE );
1270 aMsk.Invert();
1271 ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev->PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT );
1272 ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev->PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND );
1274 else
1275 ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY );
1277 break;
1279 case MetaActionType::BMPEXSCALE:
1281 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
1282 Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1283 Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1285 if( !!aMsk )
1287 aBmp.Replace( aMsk, COL_WHITE );
1288 aMsk.Invert();
1289 ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT );
1290 ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND );
1292 else
1293 ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1295 break;
1297 case MetaActionType::BMPEXSCALEPART:
1299 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pAction);
1300 BitmapEx aBmpEx( pA->GetBitmapEx() );
1301 aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1302 Bitmap aBmp( aBmpEx.GetBitmap() );
1303 Bitmap aMsk( aBmpEx.GetMask() );
1305 if( !!aMsk )
1307 aBmp.Replace( aMsk, COL_WHITE );
1308 aMsk.Invert();
1309 ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT );
1310 ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND );
1312 else
1313 ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1315 break;
1317 case MetaActionType::TEXT:
1319 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
1320 const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1322 ImplCheckTextAttr();
1323 ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, 0 );
1325 break;
1327 case MetaActionType::TEXTRECT:
1329 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
1330 const OUString aText( pA->GetText() );
1332 ImplCheckTextAttr();
1333 ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, nullptr, 0 );
1335 break;
1337 case MetaActionType::TEXTARRAY:
1339 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
1340 const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1342 ImplCheckTextAttr();
1343 ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
1345 break;
1347 case MetaActionType::STRETCHTEXT:
1349 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
1350 const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1352 ImplCheckTextAttr();
1353 ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, pA->GetWidth() );
1355 break;
1357 case( MetaActionType::LINECOLOR ):
1359 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1360 mbLineChanged = true;
1362 break;
1364 case( MetaActionType::FILLCOLOR ):
1366 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1367 mbFillChanged = true;
1369 break;
1371 case( MetaActionType::TEXTCOLOR ):
1372 case( MetaActionType::TEXTLINECOLOR ):
1373 case( MetaActionType::TEXTFILLCOLOR ):
1374 case( MetaActionType::TEXTALIGN ):
1375 case( MetaActionType::FONT ):
1377 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1378 mbTextChanged = true;
1380 break;
1382 case( MetaActionType::ISECTRECTCLIPREGION ):
1384 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1386 ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT );
1387 ImplWriteRect( static_cast<const MetaISectRectClipRegionAction*>(pAction)->GetRect() );
1388 ImplEndRecord();
1390 break;
1392 case( MetaActionType::CLIPREGION ):
1393 case( MetaActionType::ISECTREGIONCLIPREGION ):
1394 case( MetaActionType::MOVECLIPREGION ):
1396 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1398 break;
1400 case( MetaActionType::REFPOINT ):
1401 case( MetaActionType::MAPMODE ):
1402 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1403 break;
1405 case( MetaActionType::PUSH ):
1407 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1409 ImplBeginRecord( WIN_EMR_SAVEDC );
1410 ImplEndRecord();
1412 break;
1414 case( MetaActionType::POP ):
1416 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1418 ImplBeginRecord( WIN_EMR_RESTOREDC );
1419 m_rStm.WriteInt32( -1 );
1420 ImplEndRecord();
1422 ImplWriteRasterOp( maVDev->GetRasterOp() );
1423 mbLineChanged = mbFillChanged = mbTextChanged = true;
1425 break;
1427 case( MetaActionType::RASTEROP ):
1429 const_cast<MetaAction*>(pAction)->Execute( maVDev );
1430 ImplWriteRasterOp( static_cast<const MetaRasterOpAction*>(pAction)->GetRasterOp() );
1432 break;
1434 case( MetaActionType::LAYOUTMODE ):
1436 ComplexTextLayoutFlags nLayoutMode = static_cast<const MetaLayoutModeAction*>(pAction)->GetLayoutMode();
1437 mnHorTextAlign = 0;
1438 if ((nLayoutMode & ComplexTextLayoutFlags::BiDiRtl) != ComplexTextLayoutFlags::Default)
1440 mnHorTextAlign = TA_RIGHT | TA_RTLREADING;
1442 if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginRight) != ComplexTextLayoutFlags::Default)
1443 mnHorTextAlign |= TA_RIGHT;
1444 else if ((nLayoutMode & ComplexTextLayoutFlags::TextOriginLeft) != ComplexTextLayoutFlags::Default)
1445 mnHorTextAlign &= ~TA_RIGHT;
1446 break;
1449 case( MetaActionType::COMMENT ):
1451 MetaCommentAction const*const pCommentAction(
1452 static_cast<MetaCommentAction const*>(pAction));
1453 if (pCommentAction->GetComment() == "EMF_PLUS")
1455 ImplBeginCommentRecord(WIN_EMR_COMMENT_EMFPLUS);
1456 m_rStm.WriteBytes(pCommentAction->GetData(),
1457 pCommentAction->GetDataSize());
1458 ImplEndCommentRecord();
1461 break;
1463 case( MetaActionType::MASK ):
1464 case( MetaActionType::MASKSCALE ):
1465 case( MetaActionType::MASKSCALEPART ):
1466 case( MetaActionType::WALLPAPER ):
1467 case( MetaActionType::TEXTLINE ):
1468 case( MetaActionType::GRADIENTEX ):
1469 // Explicitly ignored cases
1470 break;
1472 default:
1473 // TODO: Implement more cases as necessary. Let's not bother with a warning.
1474 break;
1479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */