LibreOffice Module vcl (master)  1
emfwr.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <algorithm>
24 
25 #include "emfwr.hxx"
26 #include <tools/helpers.hxx>
27 #include <tools/fract.hxx>
28 #include <tools/stream.hxx>
31 #include <vcl/lineinfo.hxx>
32 #include <vcl/dibtools.hxx>
33 #include <vcl/metaact.hxx>
34 #include <memory>
35 
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
69 
70 #define WIN_EMR_GDICOMMENT 70
71 #define WIN_EMR_STRETCHDIBITS 81
72 #define WIN_EMR_EXTCREATEFONTINDIRECTW 82
73 #define WIN_EMR_EXTTEXTOUTW 84
74 
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
80 
81 #define HANDLE_INVALID 0xffffffff
82 #define MAXHANDLES 65000
83 
84 #define LINE_SELECT 0x00000001
85 #define FILL_SELECT 0x00000002
86 #define TEXT_SELECT 0x00000004
87 
88 /* Text Alignment Options */
89 #define TA_RIGHT 2
90 
91 #define TA_TOP 0
92 #define TA_BOTTOM 8
93 #define TA_BASELINE 24
94 #define TA_RTLREADING 256
95 
96 #define MM_ANISOTROPIC 8
97 
99 {
100  Header = 0x4001,
101  EndOfFile = 0x4002,
102  GetDC = 0x4004,
103  FillPolygon = 0x400C,
104  SetAntiAliasMode = 0x401E,
105  SetInterpolationMode = 0x4021,
106  SetPixelOffsetMode = 0x4022,
107  SetCompositingQuality = 0x4024
108 };
109 
110 void EMFWriter::ImplBeginCommentRecord( sal_Int32 nCommentType )
111 {
113  m_rStm.SeekRel( 4 );
114  m_rStm.WriteInt32( nCommentType );
115 }
116 
118 {
119  if( mbRecordOpen )
120  {
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 );
125  }
126  ImplEndRecord();
127 }
128 
129 void EMFWriter::ImplBeginPlusRecord( EmfPlusRecordType nType, sal_uInt16 nFlags )
130 {
131  SAL_WARN_IF( mbRecordPlusOpen, "vcl", "Another EMF+ record is already opened!" );
132 
133  if( !mbRecordPlusOpen )
134  {
135  mbRecordPlusOpen = true;
137 
138  m_rStm.WriteUInt16( static_cast<sal_uInt16>(nType) ).WriteUInt16( nFlags );
139  m_rStm.SeekRel( 8 );
140  }
141 }
142 
144 {
145  SAL_WARN_IF( !mbRecordPlusOpen, "vcl", "EMF+ Record was not opened!" );
146 
147  if( mbRecordPlusOpen )
148  {
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;
156  }
157 }
158 
159 void EMFWriter::ImplPlusRecord( EmfPlusRecordType nType, sal_uInt16 nFlags )
160 {
161  ImplBeginPlusRecord( nType, nFlags );
163 }
164 
165 void EMFWriter::WriteEMFPlusHeader( const Size &rMtfSizePix, const Size &rMtfSizeLog )
166 {
168 
169  sal_Int32 nDPIX = rMtfSizePix.Width()*25;
170  sal_Int32 nDivX = rMtfSizeLog.Width()/100;
171  if (nDivX)
172  nDPIX /= nDivX; // DPI X
173 
174  sal_Int32 nDPIY = rMtfSizePix.Height()*25;
175  sal_Int32 nDivY = rMtfSizeLog.Height()/100;
176  if (nDivY)
177  nDPIY /= nDivY; // DPI Y
178 
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 );
188 
189  // Write more properties
192  ImplPlusRecord( EmfPlusRecordType::SetAntiAliasMode, 0x09 ); // TODO: Check actual values for AntiAlias
193  ImplPlusRecord( EmfPlusRecordType::SetCompositingQuality, 0x0100 ); // Default Quality
197 }
198 
200 {
204 }
205 
206 void EMFWriter::ImplWritePlusColor( const Color& rColor, sal_uInt32 nTrans )
207 {
208  sal_uInt32 nAlpha = ((100-nTrans)*0xFF)/100;
209  sal_uInt32 nCol = rColor.GetBlue();
210 
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 );
215 }
216 
217 void EMFWriter::ImplWritePlusPoint( const Point& rPoint )
218 {
219  // Convert to pixels
220  const Point aPoint(maVDev->LogicToPixel( rPoint, maDestMapMode ));
221  m_rStm.WriteUInt16( aPoint.X() ).WriteUInt16( aPoint.Y() );
222 }
223 
224 void EMFWriter::ImplWritePlusFillPolygonRecord( const tools::Polygon& rPoly, sal_uInt32 nTrans )
225 {
227  if( rPoly.GetSize() )
228  {
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 ] );
235  }
237 }
238 
240 {
241  const sal_uLong nHeaderPos = m_rStm.Tell();
242 
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);
249  mbRecordOpen = mbRecordPlusOpen = false;
252  mnHorTextAlign = 0;
253 
254  const Size aMtfSizePix( maVDev->LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) );
255  const Size aMtfSizeLog( OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
256 
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 );
260 
261  // Write EMF+ Header
262  WriteEMFPlusHeader( aMtfSizePix, aMtfSizeLog );
263 
264  // write initial values
265 
266  // set 100th mm map mode in EMF
269  ImplEndRecord();
270 
272  m_rStm.WriteInt32( maVDev->GetDPIX() ).WriteInt32( maVDev->GetDPIY() );
273  ImplEndRecord();
274 
276  m_rStm.WriteInt32( 2540 ).WriteInt32( 2540 );
277  ImplEndRecord();
278 
280  m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
281  ImplEndRecord();
282 
284  m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
285  ImplEndRecord();
286 
288 
290  m_rStm.WriteUInt32( 1 ); // TRANSPARENT
291  ImplEndRecord();
292 
293  // write emf data
294  ImplWrite( rMtf );
295 
297 
299  m_rStm.WriteUInt32( 0 ) // nPalEntries
300  .WriteUInt32( 0x10 ) // offPalEntries
301  .WriteUInt32( 0x14 ); // nSizeLast
302  ImplEndRecord();
303 
304  // write header
305  const sal_uLong nEndPos = m_rStm.Tell(); m_rStm.Seek( nHeaderPos );
306 
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
316 
317  m_rStm.Seek( nEndPos );
318  mHandlesUsed.clear();
319 
320  return( m_rStm.GetError() == ERRCODE_NONE );
321 }
322 
324 {
326 
327  for( sal_uLong i = 0; i < mHandlesUsed.size() && ( HANDLE_INVALID == nHandle ); i++ )
328  {
329  if( !mHandlesUsed[ i ] )
330  {
331  mHandlesUsed[ i ] = true;
332 
333  if( ( nHandle = i ) == mnHandleCount )
334  mnHandleCount++;
335  }
336  }
337 
338  SAL_WARN_IF( nHandle == HANDLE_INVALID, "vcl", "No more handles available" );
339  return( nHandle != HANDLE_INVALID ? nHandle + 1 : HANDLE_INVALID );
340 }
341 
343 {
344  SAL_WARN_IF( !nHandle || ( nHandle >= mHandlesUsed.size() ), "vcl", "Handle out of range" );
345  mHandlesUsed[ nHandle - 1 ] = false;
346 }
347 
348 void EMFWriter::ImplBeginRecord( sal_uInt32 nType )
349 {
350  SAL_WARN_IF( mbRecordOpen, "vcl", "Another record is already opened!" );
351 
352  if( !mbRecordOpen )
353  {
354  mbRecordOpen = true;
355  mnRecordPos = m_rStm.Tell();
356 
357  m_rStm.WriteUInt32( nType );
358  m_rStm.SeekRel( 4 );
359  }
360 }
361 
363 {
364  SAL_WARN_IF( !mbRecordOpen, "vcl", "Record was not opened!" );
365 
366  if( !mbRecordOpen )
367  return;
368 
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;
381 
382 }
383 
384 bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType )
385 {
386  if( rHandle != HANDLE_INVALID )
387  {
388  sal_uInt32 nStockObject = 0x80000000;
389 
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;
396 
397  // select stock object first
399  m_rStm.WriteUInt32( nStockObject );
400  ImplEndRecord();
401 
402  // destroy handle of created object
404  m_rStm.WriteUInt32( rHandle );
405  ImplEndRecord();
406 
407  // mark handle as free
408  ImplReleaseHandle( rHandle );
409  }
410 
411  rHandle = ImplAcquireHandle();
412 
413  return( HANDLE_INVALID != rHandle );
414 }
415 
417 {
419  return;
420 
421  sal_uInt32 nStyle = maVDev->IsLineColor() ? 0 : 5;
422 
424  m_rStm.WriteUInt32( mnLineHandle ).WriteUInt32( nStyle ).WriteUInt32( 0/*nWidth*/ ).WriteUInt32( 0/*nHeight*/ );
425  ImplWriteColor( maVDev->GetLineColor() );
426  ImplEndRecord();
427 
430  ImplEndRecord();
431 }
432 
434 {
436  return;
437 
438  sal_uInt32 nStyle = maVDev->IsFillColor() ? 0 : 1;
439 
442  ImplWriteColor( maVDev->GetFillColor() );
443  m_rStm.WriteUInt32( 0/*nPatternStyle*/ );
444  ImplEndRecord();
445 
448  ImplEndRecord();
449 }
450 
452 {
454  return;
455 
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;
461 
462  // tdf#127471 adapt nFontWidth from NormedFontScaling to
463  // Windows-like notation if used for text scaling
464  const tools::Long nFontHeight(rFont.GetFontSize().Height());
465  tools::Long nFontWidth(rFont.GetFontSize().Width());
466 
467 #ifndef _WIN32
468  const bool bFontScaledHorizontally(nFontWidth != 0 && nFontWidth != nFontHeight);
469 
470  if(bFontScaledHorizontally)
471  {
472  // tdf#127471 nFontWidth is the non-Windows NormedFontScaling, need to convert to
473  // Windows-like notation with pre-multiplied AvgFontWidth since EMF/WMF are Windows
474  // specific formats.
475  const tools::Long nAverageFontWidth(rFont.GetOrCalculateAverageFontWidth());
476 
477  if(nFontHeight > 0)
478  {
479  const double fScaleFactor(static_cast<double>(nAverageFontWidth) / static_cast<double>(nFontHeight));
480  nFontWidth = static_cast<tools::Long>(static_cast<double>(nFontWidth) * fScaleFactor);
481  }
482  }
483 #endif
484 
487  ImplWriteExtent( -nFontHeight );
488  ImplWriteExtent( nFontWidth );
489  m_rStm.WriteInt32( rFont.GetOrientation().get() ).WriteInt32( rFont.GetOrientation().get() );
490 
491  switch( rFont.GetWeight() )
492  {
493  case WEIGHT_THIN: nWeight = 100; break;
494  case WEIGHT_ULTRALIGHT: nWeight = 200; break;
495  case WEIGHT_LIGHT: nWeight = 300; break;
496  case WEIGHT_SEMILIGHT: nWeight = 300; break;
497  case WEIGHT_NORMAL: nWeight = 400; break;
498  case WEIGHT_MEDIUM: nWeight = 500; break;
499  case WEIGHT_SEMIBOLD: nWeight = 600; break;
500  case WEIGHT_BOLD: nWeight = 700; break;
501  case WEIGHT_ULTRABOLD: nWeight = 800; break;
502  case WEIGHT_BLACK: nWeight = 900; break;
503  default: nWeight = 0; break;
504  }
505 
506  m_rStm.WriteInt32( nWeight );
507  m_rStm.WriteUChar( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 );
508  m_rStm.WriteUChar( ( LINESTYLE_NONE == rFont.GetUnderline() ) ? 0 : 1 );
509  m_rStm.WriteUChar( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 );
510  m_rStm.WriteUChar( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 );
511  m_rStm.WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
512 
513  switch( rFont.GetPitch() )
514  {
515  case PITCH_FIXED: nPitchAndFamily = 0x01; break;
516  case PITCH_VARIABLE: nPitchAndFamily = 0x02; break;
517  default: nPitchAndFamily = 0x00; break;
518  }
519 
520  switch( rFont.GetFamilyType() )
521  {
522  case FAMILY_DECORATIVE: nPitchAndFamily |= 0x50; break;
523  case FAMILY_MODERN: nPitchAndFamily |= 0x30; break;
524  case FAMILY_ROMAN: nPitchAndFamily |= 0x10; break;
525  case FAMILY_SCRIPT: nPitchAndFamily |= 0x40; break;
526  case FAMILY_SWISS: nPitchAndFamily |= 0x20; break;
527  default: break;
528  }
529 
530  m_rStm.WriteUChar( nPitchAndFamily );
531 
532  for( i = 0; i < 32; i++ )
533  m_rStm.WriteUInt16( ( i < aFontName.getLength() ) ? aFontName[ i ] : 0 );
534 
535  // dummy elfFullName
536  for( i = 0; i < 64; i++ )
537  m_rStm.WriteUInt16( 0 );
538 
539  // dummy elfStyle
540  for( i = 0; i < 32; i++ )
541  m_rStm.WriteUInt16( 0 );
542 
543  // dummy elfVersion, elfStyleSize, elfMatch, elfReserved
545 
546  // dummy elfVendorId
547  m_rStm.WriteUInt32( 0 );
548 
549  // dummy elfCulture
550  m_rStm.WriteUInt32( 0 );
551 
552  // dummy elfPanose
554 
555  // fill record to get a record size divideable by 4
556  m_rStm.WriteUInt16( 0 );
557 
558  ImplEndRecord();
559 
560  // TextAlign
561  sal_uInt32 nTextAlign;
562 
563  switch( rFont.GetAlignment() )
564  {
565  case ALIGN_TOP: nTextAlign = TA_TOP; break;
566  case ALIGN_BOTTOM: nTextAlign = TA_BOTTOM; break;
567  default: nTextAlign = TA_BASELINE; break;
568  }
569  nTextAlign |= mnHorTextAlign;
570 
572  m_rStm.WriteUInt32( nTextAlign );
573  ImplEndRecord();
574 
575  // Text color
577  ImplWriteColor( maVDev->GetTextColor() );
578  ImplEndRecord();
579 
582  ImplEndRecord();
583 
584 }
585 
586 void EMFWriter::ImplWriteColor( const Color& rColor )
587 {
588  sal_uInt32 nCol = rColor.GetRed();
589 
590  nCol |= static_cast<sal_uInt32>(rColor.GetGreen()) << 8;
591  nCol |= static_cast<sal_uInt32>(rColor.GetBlue()) << 16;
592 
593  m_rStm.WriteUInt32( nCol );
594 }
595 
597 {
598  sal_uInt32 nROP2;
599 
600  switch( eRop )
601  {
602  case RasterOp::Invert: nROP2 = 6; break;
603  case RasterOp::Xor: nROP2 = 7; break;
604  default: nROP2 = 13;break;
605  }
606 
608  m_rStm.WriteUInt32( nROP2 );
609  ImplEndRecord();
610 }
611 
613 {
614  nExtent = OutputDevice::LogicToLogic( Size( nExtent, 0 ), maVDev->GetMapMode(), maDestMapMode ).Width();
615  m_rStm.WriteInt32( nExtent );
616 }
617 
618 void EMFWriter::ImplWritePoint( const Point& rPoint )
619 {
620  const Point aPoint( OutputDevice::LogicToLogic( rPoint, maVDev->GetMapMode(), maDestMapMode ));
621  m_rStm.WriteInt32( aPoint.X() ).WriteInt32( aPoint.Y() );
622 }
623 
624 void EMFWriter::ImplWriteSize( const Size& rSize)
625 {
626  const Size aSize( OutputDevice::LogicToLogic( rSize, maVDev->GetMapMode(), maDestMapMode ));
627  m_rStm.WriteInt32( aSize.Width() ).WriteInt32( aSize.Height() );
628 }
629 
631 {
632  const tools::Rectangle aRect( OutputDevice::LogicToLogic ( rRect, maVDev->GetMapMode(), maDestMapMode ));
633  auto right = aRect.IsWidthEmpty() ? aRect.Left() : aRect.Right();
634  auto bottom = aRect.IsHeightEmpty() ? aRect.Top() : aRect.Bottom();
635  m_rStm
636  .WriteInt32( aRect.Left() )
637  .WriteInt32( aRect.Top() )
638  .WriteInt32( right )
639  .WriteInt32( bottom );
640 }
641 
642 void EMFWriter::ImplWritePolygonRecord( const tools::Polygon& rPoly, bool bClose )
643 {
644  if( !rPoly.GetSize() )
645  return;
646 
647  if( rPoly.HasFlags() )
648  ImplWritePath( rPoly, bClose );
649  else
650  {
651  if( bClose )
653 
655 
657  ImplWriteRect( rPoly.GetBoundRect() );
658  m_rStm.WriteUInt32( rPoly.GetSize() );
659 
660  for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ )
661  ImplWritePoint( rPoly[ i ] );
662 
663  ImplEndRecord();
664  }
665 }
666 
668 {
669  sal_uInt16 n, i, nPolyCount = rPolyPoly.Count();
670 
671  if( !nPolyCount )
672  return;
673 
674  if( 1 == nPolyCount )
675  ImplWritePolygonRecord( rPolyPoly[ 0 ], true );
676  else
677  {
678  bool bHasFlags = false;
679  sal_uInt32 nTotalPoints = 0;
680 
681  for( i = 0; i < nPolyCount; i++ )
682  {
683  nTotalPoints += rPolyPoly[ i ].GetSize();
684  if ( rPolyPoly[ i ].HasFlags() )
685  bHasFlags = true;
686  }
687  if( nTotalPoints )
688  {
689  if ( bHasFlags )
690  ImplWritePath( rPolyPoly, true );
691  else
692  {
695 
697  ImplWriteRect( rPolyPoly.GetBoundRect() );
698  m_rStm.WriteUInt32( nPolyCount ).WriteUInt32( nTotalPoints );
699 
700  for( i = 0; i < nPolyCount; i++ )
701  m_rStm.WriteUInt32( rPolyPoly[ i ].GetSize() );
702 
703  for( i = 0; i < nPolyCount; i++ )
704  {
705  const tools::Polygon& rPoly = rPolyPoly[ i ];
706 
707  for( n = 0; n < rPoly.GetSize(); n++ )
708  ImplWritePoint( rPoly[ n ] );
709  }
710  ImplEndRecord();
711  }
712  }
713  }
714 }
715 
716 void EMFWriter::ImplWritePath( const tools::PolyPolygon& rPolyPoly, bool bClosed )
717 {
718  if ( bClosed )
721 
723  ImplEndRecord();
724 
725  sal_uInt16 i, n, o, nPolyCount = rPolyPoly.Count();
726  for ( i = 0; i < nPolyCount; i++ )
727  {
728  n = 0;
729  const tools::Polygon& rPoly = rPolyPoly[ i ];
730  while ( n < rPoly.GetSize() )
731  {
732  if( n == 0 )
733  {
735  ImplWritePoint( rPoly[ 0 ] );
736  ImplEndRecord();
737  n++;
738  continue;
739  }
740 
741  sal_uInt16 nBezPoints = 0;
742 
743  while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == PolyFlags::Control ) )
744  nBezPoints += 3;
745 
746  if ( nBezPoints )
747  {
749  tools::Polygon aNewPoly( nBezPoints + 1 );
750  aNewPoly[ 0 ] = rPoly[ n - 1 ];
751  for ( o = 0; o < nBezPoints; o++ )
752  aNewPoly[ o + 1 ] = rPoly[ n + o ];
753  ImplWriteRect( aNewPoly.GetBoundRect() );
754  m_rStm.WriteUInt32( nBezPoints );
755  for( o = 1; o < aNewPoly.GetSize(); o++ )
756  ImplWritePoint( aNewPoly[ o ] );
757  ImplEndRecord();
758  n = n + nBezPoints;
759  }
760  else
761  {
762  sal_uInt16 nPoints = 1;
763  while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != PolyFlags::Control ) )
764  nPoints++;
765 
766  if ( nPoints > 1 )
767  {
769  tools::Polygon aNewPoly( nPoints + 1 );
770  aNewPoly[ 0 ] = rPoly[ n - 1];
771  for ( o = 1; o <= nPoints; o++ )
772  aNewPoly[ o ] = rPoly[ n - 1 + o ];
773  ImplWriteRect( aNewPoly.GetBoundRect() );
774  m_rStm.WriteUInt32( nPoints );
775  for( o = 1; o < aNewPoly.GetSize(); o++ )
776  ImplWritePoint( aNewPoly[ o ] );
777  ImplEndRecord();
778  }
779  else
780  {
782  ImplWritePoint( rPoly[ n ] );
783  ImplEndRecord();
784  }
785  n = n + nPoints;
786  }
787  if ( bClosed && ( n == rPoly.GetSize() ) )
788  {
790  ImplEndRecord();
791  }
792  }
793  }
795  ImplEndRecord();
797  ImplWriteRect( rPolyPoly.GetBoundRect() );
798  ImplEndRecord();
799 }
800 
801 void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt,
802  const Size& rSz, sal_uInt32 nROP )
803 {
804  if( rBmp.IsEmpty() )
805  return;
806 
807  SvMemoryStream aMemStm( 65535, 65535 );
808  const Size aBmpSizePixel( rBmp.GetSizePixel() );
809 
811  ImplWriteRect( tools::Rectangle( rPt, rSz ) );
812  ImplWritePoint( rPt );
813  m_rStm.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( aBmpSizePixel.Width() ).WriteInt32( aBmpSizePixel.Height() );
814 
815  // write offset positions and sizes later
816  const sal_uLong nOffPos = m_rStm.Tell();
817  m_rStm.SeekRel( 16 );
818 
819  m_rStm.WriteUInt32( 0 ).WriteInt32( ( RasterOp::Xor == maVDev->GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP );
820  ImplWriteSize( rSz );
821 
822  WriteDIB(rBmp, aMemStm, true, false);
823 
824  sal_uInt32 nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize;
825  sal_uInt16 nBitCount;
826 
827  // get DIB parameters
828  aMemStm.Seek( 0 );
829  aMemStm.ReadUInt32( nHeaderSize );
830  aMemStm.SeekRel( 10 );
831  aMemStm.ReadUInt16( nBitCount ).ReadUInt32( nCompression ).ReadUInt32( nImageSize );
832  aMemStm.SeekRel( 8 );
833  aMemStm.ReadUInt32( nColsUsed );
834 
835  if (nBitCount <= 8)
836  {
837  if (nColsUsed)
838  nPalCount = nColsUsed;
839  else
840  nPalCount = 1 << static_cast<sal_uInt32>(nBitCount);
841  }
842  else
843  {
844  if (nCompression == BITFIELDS)
845  nPalCount = 3;
846  else
847  nPalCount = 0;
848  }
849 
850  sal_uInt32 nPalSize = nPalCount * 4;
851 
852  m_rStm.WriteBytes( aMemStm.GetData(), nDIBSize );
853 
854  const sal_uLong nEndPos = m_rStm.Tell();
855  m_rStm.Seek( nOffPos );
856  m_rStm.WriteUInt32( 80 ).WriteUInt32( nHeaderSize + nPalSize );
857  m_rStm.WriteUInt32( 80 + nHeaderSize + nPalSize ).WriteUInt32( nImageSize );
858  m_rStm.Seek( nEndPos );
859 
860  ImplEndRecord();
861 
862 }
863 
864 void EMFWriter::ImplWriteTextRecord( const Point& rPos, const OUString& rText, const tools::Long* pDXArray, sal_uInt32 nWidth )
865 {
866  sal_Int32 nLen = rText.getLength(), i;
867 
868  if( !nLen )
869  return;
870 
871  sal_uInt32 nNormWidth;
872  std::unique_ptr<tools::Long[]> pOwnArray;
873  tools::Long* pDX;
874 
875  // get text sizes
876  if( pDXArray )
877  {
878  nNormWidth = maVDev->GetTextWidth( rText );
879  pDX = const_cast<tools::Long*>(pDXArray);
880  }
881  else
882  {
883  pOwnArray.reset(new tools::Long[ nLen ]);
884  nNormWidth = maVDev->GetTextArray( rText, pOwnArray.get() );
885  pDX = pOwnArray.get();
886  }
887 
888  if( nLen > 1 )
889  {
890  nNormWidth = pDX[ nLen - 2 ] + maVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) );
891 
892  if( nWidth && nNormWidth && ( nWidth != nNormWidth ) )
893  {
894  const double fFactor = static_cast<double>(nWidth) / nNormWidth;
895 
896  for( i = 0; i < ( nLen - 1 ); i++ )
897  pDX[ i ] = FRound( pDX[ i ] * fFactor );
898  }
899  }
900 
901  // write text record
903 
904  ImplWriteRect( tools::Rectangle( rPos, Size( nNormWidth, maVDev->GetTextHeight() ) ) );
905  m_rStm.WriteUInt32( 1 );
906  m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
907  ImplWritePoint( rPos );
908  m_rStm.WriteUInt32( nLen ).WriteUInt32( 76 ).WriteUInt32( 2 );
909  m_rStm.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 );
910  m_rStm.WriteUInt32( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) );
911 
912  // write text
913  for( i = 0; i < nLen; i++ )
914  m_rStm.WriteUInt16( rText[ i ] );
915 
916  // padding word
917  if( nLen & 1 )
918  m_rStm.WriteUInt16( 0 );
919 
920  // write DX array
921  ImplWriteExtent( pDX[ 0 ] );
922 
923  if( nLen > 1 )
924  {
925  for( i = 1; i < ( nLen - 1 ); i++ )
926  ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] );
927 
928  ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) );
929  }
930 
931  ImplEndRecord();
932 
933 }
934 
936 {
937  if(!rLinePolygon.count())
938  return;
939 
940  basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
941  basegfx::B2DPolyPolygon aFillPolyPolygon;
942 
943  rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
944 
945  if(aLinePolyPolygon.count())
946  {
947  for(auto const& rB2DPolygon : aLinePolyPolygon)
948  {
949  ImplWritePolygonRecord( tools::Polygon(rB2DPolygon), false );
950  }
951  }
952 
953  if(!aFillPolyPolygon.count())
954  return;
955 
956  const Color aOldLineColor(maVDev->GetLineColor());
957  const Color aOldFillColor(maVDev->GetFillColor());
958 
959  maVDev->SetLineColor();
960  maVDev->SetFillColor(aOldLineColor);
961 
962  for(auto const& rB2DPolygon : aFillPolyPolygon)
963  {
965  }
966 
967  maVDev->SetLineColor(aOldLineColor);
968  maVDev->SetFillColor(aOldFillColor);
969 }
970 
972 {
973  for( size_t j = 0, nActionCount = rMtf.GetActionSize(); j < nActionCount; j++ )
974  {
975  const MetaAction* pAction = rMtf.GetAction( j );
976  const MetaActionType nType = pAction->GetType();
977 
978  switch( nType )
979  {
981  {
982  const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
983 
986  ImplWritePoint( pA->GetPoint() );
987  ImplWriteColor( pA->GetColor() );
988  ImplEndRecord();
989  }
990  break;
991 
993  {
994  if( maVDev->IsLineColor() )
995  {
996  const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
997 
1000  ImplWritePoint( pA->GetPoint() );
1001  ImplWriteColor( maVDev->GetLineColor() );
1002  ImplEndRecord();
1003  }
1004  }
1005  break;
1006 
1007  case MetaActionType::LINE:
1008  {
1009  if( maVDev->IsLineColor() )
1010  {
1011  const MetaLineAction* pA = static_cast<const MetaLineAction*>(pAction);
1012 
1013  if(pA->GetLineInfo().IsDefault())
1014  {
1016 
1018  ImplWritePoint( pA->GetStartPoint() );
1019  ImplEndRecord();
1020 
1022  ImplWritePoint( pA->GetEndPoint() );
1023  ImplEndRecord();
1024 
1026  ImplWritePoint( pA->GetEndPoint() );
1027  ImplWriteColor( maVDev->GetLineColor() );
1028  ImplEndRecord();
1029  }
1030  else
1031  {
1032  // LineInfo used; handle Dash/Dot and fat lines
1033  basegfx::B2DPolygon aPolygon;
1034  aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1035  aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1037  }
1038  }
1039  }
1040  break;
1041 
1042  case MetaActionType::RECT:
1043  {
1044  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1045  {
1046  const MetaRectAction* pA = static_cast<const MetaRectAction*>(pAction);
1047 
1050 
1052  ImplWriteRect( pA->GetRect() );
1053  ImplEndRecord();
1054  }
1055  }
1056  break;
1057 
1059  {
1060  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1061  {
1062  const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pAction);
1063 
1066 
1068  ImplWriteRect( pA->GetRect() );
1069  ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) );
1070  ImplEndRecord();
1071  }
1072  }
1073  break;
1074 
1076  {
1077  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1078  {
1079  const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pAction);
1080 
1083 
1085  ImplWriteRect( pA->GetRect() );
1086  ImplEndRecord();
1087  }
1088  }
1089  break;
1090 
1091  case MetaActionType::ARC:
1092  case MetaActionType::PIE:
1093  case MetaActionType::CHORD:
1095  {
1096  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1097  {
1098  tools::Polygon aPoly;
1099 
1100  switch( nType )
1101  {
1102  case MetaActionType::ARC:
1103  {
1104  const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
1105  aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Arc );
1106  }
1107  break;
1108 
1109  case MetaActionType::PIE:
1110  {
1111  const MetaPieAction* pA = static_cast<const MetaPieAction*>(pAction);
1112  aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Pie );
1113  }
1114  break;
1115 
1116  case MetaActionType::CHORD:
1117  {
1118  const MetaChordAction* pA = static_cast<const MetaChordAction*>(pAction);
1119  aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Chord );
1120  }
1121  break;
1122 
1124  aPoly = static_cast<const MetaPolygonAction*>(pAction)->GetPolygon();
1125  break;
1126  default: break;
1127  }
1128 
1129  ImplWritePolygonRecord( aPoly, nType != MetaActionType::ARC );
1130  }
1131  }
1132  break;
1133 
1135  {
1136  if( maVDev->IsLineColor() )
1137  {
1138  const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pAction);
1139  const tools::Polygon& rPoly = pA->GetPolygon();
1140 
1141  if( rPoly.GetSize() )
1142  {
1143  if(pA->GetLineInfo().IsDefault())
1144  {
1145  ImplWritePolygonRecord( rPoly, false );
1146  }
1147  else
1148  {
1149  // LineInfo used; handle Dash/Dot and fat lines
1150  Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1151  }
1152  }
1153  }
1154  }
1155  break;
1156 
1158  {
1159  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1160  ImplWritePolyPolygonRecord( static_cast<const MetaPolyPolygonAction*>(pAction)->GetPolyPolygon() );
1161  }
1162  break;
1163 
1165  {
1166  const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pAction);
1167  GDIMetaFile aTmpMtf;
1168 
1169  maVDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1170  ImplWrite( aTmpMtf );
1171  }
1172  break;
1173 
1174  case MetaActionType::HATCH:
1175  {
1176  const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
1177  GDIMetaFile aTmpMtf;
1178 
1179  maVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1180  ImplWrite( aTmpMtf );
1181  }
1182  break;
1183 
1185  {
1186  const tools::PolyPolygon& rPolyPoly = static_cast<const MetaTransparentAction*>(pAction)->GetPolyPolygon();
1187  if( rPolyPoly.Count() )
1188  ImplWritePlusFillPolygonRecord( rPolyPoly[0], static_cast<const MetaTransparentAction*>(pAction)->GetTransparence() );
1191  ImplWritePolyPolygonRecord( rPolyPoly );
1192 
1196  }
1197  break;
1198 
1200  {
1201  const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
1202 
1203  GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1204  Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1205  const Size aSrcSize( aTmpMtf.GetPrefSize() );
1206  const Point aDestPt( pA->GetPoint() );
1207  const Size aDestSize( pA->GetSize() );
1208  const double fScaleX = aSrcSize.Width() ? static_cast<double>(aDestSize.Width()) / aSrcSize.Width() : 1.0;
1209  const double fScaleY = aSrcSize.Height() ? static_cast<double>(aDestSize.Height()) / aSrcSize.Height() : 1.0;
1210  tools::Long nMoveX, nMoveY;
1211 
1212  if( fScaleX != 1.0 || fScaleY != 1.0 )
1213  {
1214  aTmpMtf.Scale( fScaleX, fScaleY );
1215  aSrcPt.setX( FRound( aSrcPt.X() * fScaleX ) );
1216  aSrcPt.setY( FRound( aSrcPt.Y() * fScaleY ) );
1217  }
1218 
1219  nMoveX = aDestPt.X() - aSrcPt.X();
1220  nMoveY = aDestPt.Y() - aSrcPt.Y();
1221 
1222  if( nMoveX || nMoveY )
1223  aTmpMtf.Move( nMoveX, nMoveY );
1224 
1228  ImplWrite( aTmpMtf );
1229  }
1230  break;
1231 
1232  case MetaActionType::EPS:
1233  {
1234  const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pAction);
1235  const GDIMetaFile& aSubstitute( pA->GetSubstitute() );
1236 
1237  for( size_t i = 0, nCount = aSubstitute.GetActionSize(); i < nCount; i++ )
1238  {
1239  const MetaAction* pSubstAct = aSubstitute.GetAction( i );
1240  if( pSubstAct->GetType() == MetaActionType::BMPSCALE )
1241  {
1242  maVDev->Push();
1244  ImplEndRecord();
1245 
1246  MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1247  Size aOutSize( OutputDevice::LogicToLogic( pA->GetSize(), maVDev->GetMapMode(), aMapMode ) );
1248  aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
1249  aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
1250  aMapMode.SetOrigin( OutputDevice::LogicToLogic( pA->GetPoint(), maVDev->GetMapMode(), aMapMode ) );
1251  maVDev->SetMapMode( aMapMode );
1252  ImplWrite( aSubstitute );
1253 
1254  maVDev->Pop();
1256  m_rStm.WriteInt32( -1 );
1257  ImplEndRecord();
1258  break;
1259  }
1260  }
1261  }
1262  break;
1263 
1264  case MetaActionType::BMP:
1265  {
1266  const MetaBmpAction* pA = static_cast<const MetaBmpAction *>(pAction);
1267  ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ), WIN_SRCCOPY );
1268  }
1269  break;
1270 
1272  {
1273  const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
1274  ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1275  }
1276  break;
1277 
1279  {
1280  const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pAction);
1281  Bitmap aTmp( pA->GetBitmap() );
1282 
1283  if( aTmp.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1284  ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1285  }
1286  break;
1287 
1288  case MetaActionType::BMPEX:
1289  {
1290  const MetaBmpExAction* pA = static_cast<const MetaBmpExAction *>(pAction);
1291  Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1292  Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1293 
1294  if( !aMsk.IsEmpty() )
1295  {
1296  aBmp.Replace( aMsk, COL_WHITE );
1297  aMsk.Invert();
1298  ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev->PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT );
1299  ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev->PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND );
1300  }
1301  else
1302  ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY );
1303  }
1304  break;
1305 
1307  {
1308  const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
1309  Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1310  Bitmap aMsk( pA->GetBitmapEx().GetMask() );
1311 
1312  if( !aMsk.IsEmpty() )
1313  {
1314  aBmp.Replace( aMsk, COL_WHITE );
1315  aMsk.Invert();
1316  ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT );
1317  ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND );
1318  }
1319  else
1320  ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1321  }
1322  break;
1323 
1325  {
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  Bitmap aMsk( aBmpEx.GetMask() );
1331 
1332  if( !aMsk.IsEmpty() )
1333  {
1334  aBmp.Replace( aMsk, COL_WHITE );
1335  aMsk.Invert();
1336  ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT );
1337  ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND );
1338  }
1339  else
1340  ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1341  }
1342  break;
1343 
1344  case MetaActionType::TEXT:
1345  {
1346  const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
1347  const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1348 
1350  ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, 0 );
1351  }
1352  break;
1353 
1355  {
1356  const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
1357  const OUString& aText( pA->GetText() );
1358 
1360  ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, nullptr, 0 );
1361  }
1362  break;
1363 
1365  {
1366  const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
1367  const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1368 
1370  ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
1371  }
1372  break;
1373 
1375  {
1376  const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
1377  const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1378 
1380  ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, pA->GetWidth() );
1381  }
1382  break;
1383 
1385  {
1386  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1387  mbLineChanged = true;
1388  }
1389  break;
1390 
1392  {
1393  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1394  mbFillChanged = true;
1395  }
1396  break;
1397 
1402  case MetaActionType::FONT:
1403  {
1404  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1405  mbTextChanged = true;
1406  }
1407  break;
1408 
1410  {
1411  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1412 
1414  ImplWriteRect( static_cast<const MetaISectRectClipRegionAction*>(pAction)->GetRect() );
1415  ImplEndRecord();
1416  }
1417  break;
1418 
1422  {
1423  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1424  }
1425  break;
1426 
1429  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1430  break;
1431 
1432  case MetaActionType::PUSH:
1433  {
1434  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1435 
1437  ImplEndRecord();
1438  }
1439  break;
1440 
1441  case MetaActionType::POP:
1442  {
1443  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1444 
1446  m_rStm.WriteInt32( -1 );
1447  ImplEndRecord();
1448 
1449  ImplWriteRasterOp( maVDev->GetRasterOp() );
1451  }
1452  break;
1453 
1455  {
1456  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1457  ImplWriteRasterOp( static_cast<const MetaRasterOpAction*>(pAction)->GetRasterOp() );
1458  }
1459  break;
1460 
1462  {
1463  ComplexTextLayoutFlags nLayoutMode = static_cast<const MetaLayoutModeAction*>(pAction)->GetLayoutMode();
1464  mnHorTextAlign = 0;
1466  {
1468  }
1473  break;
1474  }
1475 
1477  {
1478  MetaCommentAction const*const pCommentAction(
1479  static_cast<MetaCommentAction const*>(pAction));
1480  if (pCommentAction->GetComment() == "EMF_PLUS")
1481  {
1483  m_rStm.WriteBytes(pCommentAction->GetData(),
1484  pCommentAction->GetDataSize());
1486  }
1487  }
1488  break;
1489 
1490  case MetaActionType::MASK:
1496  // Explicitly ignored cases
1497  break;
1498 
1499  default:
1500  // TODO: Implement more cases as necessary. Let's not bother with a warning.
1501  break;
1502  }
1503  }
1504 }
1505 
1506 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
Point TopLeft() const
#define TEXT_SELECT
Definition: emfwr.cxx:86
void ImplEndCommentRecord()
Definition: emfwr.cxx:117
void ImplWriteSize(const Size &rSize)
Definition: emfwr.cxx:624
const LineInfo & GetLineInfo() const
Definition: metaact.hxx:190
sal_uInt32 mnLineHandle
Definition: emfwr.hxx:45
void ImplCheckTextAttr()
Definition: emfwr.cxx:451
void ImplWriteRect(const tools::Rectangle &rRect)
Definition: emfwr.cxx:630
Bitmap GetMask() const
Definition: BitmapEx.cxx:246
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
#define WIN_EMR_ROUNDRECT
Definition: emfwr.cxx:62
sal_Int32 GetLen() const
Definition: metaact.hxx:500
bool IsHeightEmpty() const
const Point & GetPoint() const
Definition: metaact.hxx:708
sal_uInt8 GetRed() const
const OUString & GetFamilyName() const
Definition: font/font.cxx:827
FAMILY_SCRIPT
void ImplBeginPlusRecord(EmfPlusRecordType nType, sal_uInt16 nFlags)
Definition: emfwr.cxx:129
SvStream & WriteUInt16(sal_uInt16 nUInt16)
std::vector< bool > mHandlesUsed
Definition: emfwr.hxx:37
const GDIMetaFile & GetGDIMetaFile() const
Definition: metaact.hxx:1577
void ImplWritePlusFillPolygonRecord(const tools::Polygon &rPoly, sal_uInt32 nTrans)
Definition: emfwr.cxx:224
void ImplWrite(const GDIMetaFile &rMtf)
Definition: emfwr.cxx:971
#define WIN_EMR_SETWINDOWORGEX
Definition: emfwr.cxx:42
SvStream & WriteInt32(sal_Int32 nInt32)
FAMILY_MODERN
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
#define WIN_EMR_SETTEXTALIGN
Definition: emfwr.cxx:50
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1521
#define WIN_EMR_DELETEOBJECT
Definition: emfwr.cxx:59
MapMode maDestMapMode
Definition: emfwr.hxx:35
#define WIN_EMR_BEGINPATH
Definition: emfwr.cxx:64
void ImplWritePlusColor(const Color &rColor, sal_uInt32 nTrans)
Definition: emfwr.cxx:206
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:178
bool mbLineChanged
Definition: emfwr.hxx:44
void ImplWritePolygonRecord(const tools::Polygon &rPoly, bool bClose)
Definition: emfwr.cxx:642
sal_uIntPtr sal_uLong
long Long
const Point & GetPoint() const
Definition: metaact.hxx:1615
WEIGHT_THIN
sal_Int64 n
bool ImplPrepareHandleSelect(sal_uInt32 &rHandle, sal_uLong nSelectType)
Definition: emfwr.cxx:384
#define WIN_EMR_ELLIPSE
Definition: emfwr.cxx:60
#define WIN_EMR_CLOSEFIGURE
Definition: emfwr.cxx:66
const Point & GetPoint() const
Definition: metaact.hxx:1578
bool mbRecordOpen
Definition: emfwr.hxx:42
WEIGHT_BLACK
#define WIN_EMR_CREATEPEN
Definition: emfwr.cxx:57
sal_uInt64 Seek(sal_uInt64 nPos)
#define TA_TOP
Definition: emfwr.cxx:91
const Size & GetSize() const
Definition: metaact.hxx:709
#define WIN_EMR_STROKEPATH
Definition: emfwr.cxx:68
WEIGHT_SEMIBOLD
#define WIN_EMR_EOF
Definition: emfwr.cxx:45
#define WIN_EMR_SETTEXTCOLOR
Definition: emfwr.cxx:51
#define WIN_EMR_RESTOREDC
Definition: emfwr.cxx:55
#define WIN_EMR_SETPIXELV
Definition: emfwr.cxx:46
const Point & GetEndPoint() const
Definition: metaact.hxx:189
const OUString & GetText() const
Definition: metaact.hxx:572
FAMILY_ROMAN
Size GetSizePixel() const
sal_uLong mnRecordPos
Definition: emfwr.hxx:40
bool mbTextChanged
Definition: emfwr.hxx:48
WEIGHT_LIGHT
sal_uInt64 SeekRel(sal_Int64 nPos)
#define WIN_EMR_SETMAPMODE
Definition: emfwr.cxx:47
FontFamily GetFamilyType()
Definition: font/font.cxx:851
FontAlign GetAlignment() const
Definition: font/font.cxx:825
const sal_uInt8 * GetData() const
Definition: metaact.hxx:1677
WEIGHT_BOLD
constexpr tools::Long Width() const
FontItalic GetItalic()
Definition: font/font.cxx:850
#define WIN_EMR_POLYGON
Definition: emfwr.cxx:36
void ImplCheckFillAttr()
Definition: emfwr.cxx:433
sal_uInt32 mnTextHandle
Definition: emfwr.hxx:49
ErrCode GetError() const
const Point & GetPoint() const
Definition: metaact.hxx:810
void ImplBeginRecord(sal_uInt32 nType)
Definition: emfwr.cxx:348
tools::Long Left() const
LINESTYLE_NONE
const OUString & GetText() const
Definition: metaact.hxx:498
void ImplWriteRasterOp(RasterOp eRop)
Definition: emfwr.cxx:596
RasterOp
Definition: vclenum.hxx:192
void ImplReleaseHandle(sal_uLong nHandle)
Definition: emfwr.cxx:342
const Bitmap & GetBitmap() const
Definition: metaact.hxx:675
PolyFlags GetFlags(sal_uInt16 nPos) const
#define WIN_SRCAND
Definition: emfwr.cxx:77
int nCount
#define MM_ANISOTROPIC
Definition: emfwr.cxx:96
tools::Long Bottom() const
const Gradient & GetGradient() const
Definition: metaact.hxx:992
bool mbRecordPlusOpen
Definition: emfwr.hxx:43
SvStream & WriteUInt32(sal_uInt32 nUInt32)
#define TA_BASELINE
Definition: emfwr.cxx:93
MetaActionType
#define WIN_SRCINVERT
Definition: emfwr.cxx:78
PITCH_VARIABLE
#define WIN_EMR_SETVIEWPORTEXTEX
Definition: emfwr.cxx:43
const Size & GetSize() const
Definition: metaact.hxx:811
void ImplWritePoint(const Point &rPoint)
Definition: emfwr.cxx:618
ScopedVclPtr< VirtualDevice > maVDev
Definition: emfwr.hxx:34
FAMILY_DECORATIVE
sal_uInt8 GetBlue() const
#define WIN_SRCCOPY
Definition: emfwr.cxx:75
sal_Int32 nHandle
void ImplWriteColor(const Color &rColor)
Definition: emfwr.cxx:586
void ImplWriteExtent(tools::Long nExtent)
Definition: emfwr.cxx:612
void ImplWritePlusPoint(const Point &rPoint)
Definition: emfwr.cxx:217
void SetMapUnit(MapUnit eUnit)
Definition: mapmod.cxx:97
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
#define WIN_EMR_SELECTOBJECT
Definition: emfwr.cxx:56
#define HANDLE_INVALID
Definition: emfwr.cxx:81
void ImplEndPlusRecord()
Definition: emfwr.cxx:143
WEIGHT_SEMILIGHT
def right
UNDERLYING_TYPE get() const
EmfPlusRecordType
Definition: emfwr.cxx:98
#define WIN_EMR_SETROP2
Definition: emfwr.cxx:49
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:218
FontPitch GetPitch()
Definition: font/font.cxx:847
const Size & GetPrefSize() const
Definition: gdimtf.hxx:175
int i
const Point & GetPoint() const
Definition: metaact.hxx:497
tools::Long FRound(double fVal)
PITCH_FIXED
#define TA_RTLREADING
Definition: emfwr.cxx:94
tools::Long GetOrCalculateAverageFontWidth() const
Definition: font/font.cxx:369
ComplexTextLayoutFlags
Definition: outdevstate.hxx:66
void Impl_handleLineInfoPolyPolygons(const LineInfo &rInfo, const basegfx::B2DPolygon &rLinePolygon)
Definition: emfwr.cxx:935
#define WIN_EMR_POLYPOLYGON
Definition: emfwr.cxx:40
#define WIN_SRCPAINT
Definition: emfwr.cxx:76
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:776
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:991
#define WIN_EMR_INTERSECTCLIPRECT
Definition: emfwr.cxx:53
WEIGHT_MEDIUM
const Size & GetSize() const
Definition: metaact.hxx:1579
sal_uLong mnRecordCount
Definition: emfwr.hxx:39
sal_uInt32 GetWidth() const
Definition: metaact.hxx:573
void ImplBeginCommentRecord(sal_Int32 nCommentType)
Definition: emfwr.cxx:110
bool HasFlags() const
#define WIN_EMR_GDICOMMENT
Definition: emfwr.cxx:70
std::size_t WriteBytes(const void *pData, std::size_t nSize)
WEIGHT_NORMAL
sal_uInt32 mnHorTextAlign
Definition: emfwr.hxx:50
WEIGHT_ULTRALIGHT
#define TA_RIGHT
Definition: emfwr.cxx:89
#define WIN_EMR_COMMENT_EMFPLUS
Definition: emfwr.cxx:79
bool WriteEMF(const GDIMetaFile &rMtf)
Definition: emfwr.cxx:239
const Size & GetFontSize() const
Definition: font/font.cxx:830
const OUString & GetText() const
Definition: metaact.hxx:607
void ImplWritePlusEOF()
Definition: emfwr.cxx:199
ALIGN_BOTTOM
#define WIN_EMR_EXTTEXTOUTW
Definition: emfwr.cxx:73
sal_uInt32 mnFillHandle
Definition: emfwr.hxx:47
FontStrikeout GetStrikeout() const
Definition: font/font.cxx:869
sal_uInt16 GetSize() const
sal_Int32 GetLen() const
Definition: metaact.hxx:575
const Point & GetPoint() const
Definition: metaact.hxx:777
WEIGHT_ULTRABOLD
::basegfx::B2DPolygon getB2DPolygon() const
#define WIN_EMR_POLYLINETO
Definition: emfwr.cxx:39
ITALIC_NONE
void ImplWritePolyPolygonRecord(const tools::PolyPolygon &rPolyPoly)
Definition: emfwr.cxx:667
tools::Long Top() const
void ImplWritePath(const tools::PolyPolygon &rPolyPoly, bool bClose)
Definition: emfwr.cxx:716
#define WIN_EMR_CREATEBRUSHINDIRECT
Definition: emfwr.cxx:58
short nBitCount
Definition: ipict.cxx:80
#define WIN_EMR_ENDPATH
Definition: emfwr.cxx:65
#define WIN_EMR_SETWINDOWEXTEX
Definition: emfwr.cxx:41
const Size & GetSize() const
Definition: metaact.hxx:1616
const Bitmap & GetBitmap() const
Definition: metaact.hxx:707
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:229
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:1051
void ImplEndRecord()
Definition: emfwr.cxx:362
#define WIN_EMR_STRETCHDIBITS
Definition: emfwr.cxx:71
const Point & GetPoint() const
Definition: metaact.hxx:571
#define WIN_EMR_MOVETOEX
Definition: emfwr.cxx:52
sal_uInt8 GetGreen() const
const Point & GetStartPoint() const
Definition: metaact.hxx:188
#define WIN_EMR_POLYBEZIERTO
Definition: emfwr.cxx:38
ALIGN_TOP
sal_uInt32 GetDataSize() const
Definition: metaact.hxx:1676
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:809
void ImplWriteBmpRecord(const Bitmap &rBmp, const Point &rPt, const Size &rSz, sal_uInt32 nROP)
Definition: emfwr.cxx:801
sal_uInt32 count() const
#define SAL_WARN_IF(condition, area, stream)
#define ERRCODE_NONE
Definition: errcode.hxx:196
sal_uLong mnHandleCount
Definition: emfwr.hxx:38
FontWeight GetWeight()
Definition: font/font.cxx:848
constexpr tools::Long Height() const
unsigned char sal_uInt8
MetaAction * GetAction(size_t nAction) const
Definition: gdimtf.cxx:185
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
#define LINE_SELECT
Definition: emfwr.cxx:84
FAMILY_SWISS
SvStream & WriteUChar(unsigned char nChar)
#define WIN_EMR_RECTANGLE
Definition: emfwr.cxx:61
const Point & GetPoint() const
Definition: metaact.hxx:156
const Point & GetPoint() const
Definition: metaact.hxx:676
SvStream & WriteInt16(sal_Int16 nInt16)
SvStream & m_rStm
Definition: emfwr.hxx:36
bool IsEmpty() const
Definition: bitmap.hxx:547
#define TA_BOTTOM
Definition: emfwr.cxx:92
sal_uInt64 Tell() const
size_t GetActionSize() const
Definition: gdimtf.cxx:180
QPRO_FUNC_TYPE nType
Degree10 GetOrientation() const
Definition: font/font.cxx:843
void ImplPlusRecord(EmfPlusRecordType nType, sal_uInt16 nFlags)
Definition: emfwr.cxx:159
bool IsWidthEmpty() const
MetaActionType GetType() const
Definition: metaact.hxx:90
#define FILL_SELECT
Definition: emfwr.cxx:85
void ImplWriteTextRecord(const Point &rPos, const OUString &rText, const tools::Long *pDXArray, sal_uInt32 nWidth)
Definition: emfwr.cxx:864
#define WIN_EMR_SETBKMODE
Definition: emfwr.cxx:48
#define WIN_EMR_FILLPATH
Definition: emfwr.cxx:67
const Hatch & GetHatch() const
Definition: metaact.hxx:1052
FontLineStyle GetUnderline() const
Definition: font/font.cxx:867
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
tools::Rectangle GetBoundRect() const
void WriteEMFPlusHeader(const Size &rMtfSizePix, const Size &rMtfSizeLog)
Definition: emfwr.cxx:165
const OString & GetComment() const
Definition: metaact.hxx:1674
#define MAXHANDLES
Definition: emfwr.cxx:82
#define WIN_EMR_LINETO
Definition: emfwr.cxx:63
tools::Rectangle GetBoundRect() const
sal_uLong mnRecordPlusPos
Definition: emfwr.hxx:41
#define BITFIELDS
Definition: dibtools.hxx:37
void reset()=delete
STRIKEOUT_NONE
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1823
bool Replace(const Bitmap &rMask, const Color &rReplaceColor)
Replace all pixel where the given mask is on with the specified color.
sal_uLong ImplAcquireHandle()
Definition: emfwr.cxx:323
bool mbFillChanged
Definition: emfwr.hxx:46
#define WIN_EMR_POLYLINE
Definition: emfwr.cxx:37
#define WIN_EMR_SAVEDC
Definition: emfwr.cxx:54
const GDIMetaFile & GetSubstitute() const
Definition: metaact.hxx:1614
#define WIN_EMR_SETVIEWPORTORGEX
Definition: emfwr.cxx:44
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
Definition: BitmapEx.cxx:412
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:606
sal_Int32 GetIndex() const
Definition: metaact.hxx:574
sal_Int32 GetIndex() const
Definition: metaact.hxx:499
tools::Long Right() const
#define WIN_EMR_EXTCREATEFONTINDIRECTW
Definition: emfwr.cxx:72
rtl_TextEncoding GetCharSet() const
Definition: font/font.cxx:836
void ImplCheckLineAttr()
Definition: emfwr.cxx:416
const void * GetData()
sal_uInt32 count() const