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::vector<tools::Long> aOwnArray;
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  nNormWidth = maVDev->GetTextArray( rText, &aOwnArray );
884  pDX = aOwnArray.data();
885  }
886 
887  if( nLen > 1 )
888  {
889  nNormWidth = pDX[ nLen - 2 ] + maVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) );
890 
891  if( nWidth && nNormWidth && ( nWidth != nNormWidth ) )
892  {
893  const double fFactor = static_cast<double>(nWidth) / nNormWidth;
894 
895  for( i = 0; i < ( nLen - 1 ); i++ )
896  pDX[ i ] = FRound( pDX[ i ] * fFactor );
897  }
898  }
899 
900  // write text record
902 
903  ImplWriteRect( tools::Rectangle( rPos, Size( nNormWidth, maVDev->GetTextHeight() ) ) );
904  m_rStm.WriteUInt32( 1 );
905  m_rStm.WriteInt32( 0 ).WriteInt32( 0 );
906  ImplWritePoint( rPos );
907  m_rStm.WriteUInt32( nLen ).WriteUInt32( 76 ).WriteUInt32( 2 );
908  m_rStm.WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 ).WriteInt32( 0 );
909  m_rStm.WriteUInt32( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) );
910 
911  // write text
912  for( i = 0; i < nLen; i++ )
913  m_rStm.WriteUInt16( rText[ i ] );
914 
915  // padding word
916  if( nLen & 1 )
917  m_rStm.WriteUInt16( 0 );
918 
919  // write DX array
920  ImplWriteExtent( pDX[ 0 ] );
921 
922  if( nLen > 1 )
923  {
924  for( i = 1; i < ( nLen - 1 ); i++ )
925  ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] );
926 
927  ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) );
928  }
929 
930  ImplEndRecord();
931 
932 }
933 
935 {
936  if(!rLinePolygon.count())
937  return;
938 
939  basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
940  basegfx::B2DPolyPolygon aFillPolyPolygon;
941 
942  rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
943 
944  if(aLinePolyPolygon.count())
945  {
946  for(auto const& rB2DPolygon : std::as_const(aLinePolyPolygon))
947  {
948  ImplWritePolygonRecord( tools::Polygon(rB2DPolygon), false );
949  }
950  }
951 
952  if(!aFillPolyPolygon.count())
953  return;
954 
955  const Color aOldLineColor(maVDev->GetLineColor());
956  const Color aOldFillColor(maVDev->GetFillColor());
957 
958  maVDev->SetLineColor();
959  maVDev->SetFillColor(aOldLineColor);
960 
961  for(auto const& rB2DPolygon : std::as_const(aFillPolyPolygon))
962  {
964  }
965 
966  maVDev->SetLineColor(aOldLineColor);
967  maVDev->SetFillColor(aOldFillColor);
968 }
969 
971 {
972  for( size_t j = 0, nActionCount = rMtf.GetActionSize(); j < nActionCount; j++ )
973  {
974  const MetaAction* pAction = rMtf.GetAction( j );
975  const MetaActionType nType = pAction->GetType();
976 
977  switch( nType )
978  {
980  {
981  const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
982 
985  ImplWritePoint( pA->GetPoint() );
986  ImplWriteColor( pA->GetColor() );
987  ImplEndRecord();
988  }
989  break;
990 
992  {
993  if( maVDev->IsLineColor() )
994  {
995  const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
996 
999  ImplWritePoint( pA->GetPoint() );
1000  ImplWriteColor( maVDev->GetLineColor() );
1001  ImplEndRecord();
1002  }
1003  }
1004  break;
1005 
1006  case MetaActionType::LINE:
1007  {
1008  if( maVDev->IsLineColor() )
1009  {
1010  const MetaLineAction* pA = static_cast<const MetaLineAction*>(pAction);
1011 
1012  if(pA->GetLineInfo().IsDefault())
1013  {
1015 
1017  ImplWritePoint( pA->GetStartPoint() );
1018  ImplEndRecord();
1019 
1021  ImplWritePoint( pA->GetEndPoint() );
1022  ImplEndRecord();
1023 
1025  ImplWritePoint( pA->GetEndPoint() );
1026  ImplWriteColor( maVDev->GetLineColor() );
1027  ImplEndRecord();
1028  }
1029  else
1030  {
1031  // LineInfo used; handle Dash/Dot and fat lines
1032  basegfx::B2DPolygon aPolygon;
1033  aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1034  aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1036  }
1037  }
1038  }
1039  break;
1040 
1041  case MetaActionType::RECT:
1042  {
1043  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1044  {
1045  const MetaRectAction* pA = static_cast<const MetaRectAction*>(pAction);
1046 
1049 
1051  ImplWriteRect( pA->GetRect() );
1052  ImplEndRecord();
1053  }
1054  }
1055  break;
1056 
1058  {
1059  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1060  {
1061  const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pAction);
1062 
1065 
1067  ImplWriteRect( pA->GetRect() );
1068  ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) );
1069  ImplEndRecord();
1070  }
1071  }
1072  break;
1073 
1075  {
1076  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1077  {
1078  const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pAction);
1079 
1082 
1084  ImplWriteRect( pA->GetRect() );
1085  ImplEndRecord();
1086  }
1087  }
1088  break;
1089 
1090  case MetaActionType::ARC:
1091  case MetaActionType::PIE:
1092  case MetaActionType::CHORD:
1094  {
1095  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1096  {
1097  tools::Polygon aPoly;
1098 
1099  switch( nType )
1100  {
1101  case MetaActionType::ARC:
1102  {
1103  const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
1104  aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Arc );
1105  }
1106  break;
1107 
1108  case MetaActionType::PIE:
1109  {
1110  const MetaPieAction* pA = static_cast<const MetaPieAction*>(pAction);
1111  aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Pie );
1112  }
1113  break;
1114 
1115  case MetaActionType::CHORD:
1116  {
1117  const MetaChordAction* pA = static_cast<const MetaChordAction*>(pAction);
1118  aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Chord );
1119  }
1120  break;
1121 
1123  aPoly = static_cast<const MetaPolygonAction*>(pAction)->GetPolygon();
1124  break;
1125  default: break;
1126  }
1127 
1128  ImplWritePolygonRecord( aPoly, nType != MetaActionType::ARC );
1129  }
1130  }
1131  break;
1132 
1134  {
1135  if( maVDev->IsLineColor() )
1136  {
1137  const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pAction);
1138  const tools::Polygon& rPoly = pA->GetPolygon();
1139 
1140  if( rPoly.GetSize() )
1141  {
1142  if(pA->GetLineInfo().IsDefault())
1143  {
1144  ImplWritePolygonRecord( rPoly, false );
1145  }
1146  else
1147  {
1148  // LineInfo used; handle Dash/Dot and fat lines
1149  Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1150  }
1151  }
1152  }
1153  }
1154  break;
1155 
1157  {
1158  if( maVDev->IsLineColor() || maVDev->IsFillColor() )
1159  ImplWritePolyPolygonRecord( static_cast<const MetaPolyPolygonAction*>(pAction)->GetPolyPolygon() );
1160  }
1161  break;
1162 
1164  {
1165  const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pAction);
1166  GDIMetaFile aTmpMtf;
1167 
1168  maVDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1169  ImplWrite( aTmpMtf );
1170  }
1171  break;
1172 
1173  case MetaActionType::HATCH:
1174  {
1175  const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
1176  GDIMetaFile aTmpMtf;
1177 
1178  maVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1179  ImplWrite( aTmpMtf );
1180  }
1181  break;
1182 
1184  {
1185  const tools::PolyPolygon& rPolyPoly = static_cast<const MetaTransparentAction*>(pAction)->GetPolyPolygon();
1186  if( rPolyPoly.Count() )
1187  ImplWritePlusFillPolygonRecord( rPolyPoly[0], static_cast<const MetaTransparentAction*>(pAction)->GetTransparence() );
1190  ImplWritePolyPolygonRecord( rPolyPoly );
1191 
1195  }
1196  break;
1197 
1199  {
1200  const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
1201 
1202  GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1203  Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1204  const Size aSrcSize( aTmpMtf.GetPrefSize() );
1205  const Point aDestPt( pA->GetPoint() );
1206  const Size aDestSize( pA->GetSize() );
1207  const double fScaleX = aSrcSize.Width() ? static_cast<double>(aDestSize.Width()) / aSrcSize.Width() : 1.0;
1208  const double fScaleY = aSrcSize.Height() ? static_cast<double>(aDestSize.Height()) / aSrcSize.Height() : 1.0;
1209  tools::Long nMoveX, nMoveY;
1210 
1211  if( fScaleX != 1.0 || fScaleY != 1.0 )
1212  {
1213  aTmpMtf.Scale( fScaleX, fScaleY );
1214  aSrcPt.setX( FRound( aSrcPt.X() * fScaleX ) );
1215  aSrcPt.setY( FRound( aSrcPt.Y() * fScaleY ) );
1216  }
1217 
1218  nMoveX = aDestPt.X() - aSrcPt.X();
1219  nMoveY = aDestPt.Y() - aSrcPt.Y();
1220 
1221  if( nMoveX || nMoveY )
1222  aTmpMtf.Move( nMoveX, nMoveY );
1223 
1227  ImplWrite( aTmpMtf );
1228  }
1229  break;
1230 
1231  case MetaActionType::EPS:
1232  {
1233  const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pAction);
1234  const GDIMetaFile& aSubstitute( pA->GetSubstitute() );
1235 
1236  for( size_t i = 0, nCount = aSubstitute.GetActionSize(); i < nCount; i++ )
1237  {
1238  const MetaAction* pSubstAct = aSubstitute.GetAction( i );
1239  if( pSubstAct->GetType() == MetaActionType::BMPSCALE )
1240  {
1241  maVDev->Push();
1243  ImplEndRecord();
1244 
1245  MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1246  Size aOutSize( OutputDevice::LogicToLogic( pA->GetSize(), maVDev->GetMapMode(), aMapMode ) );
1247  aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
1248  aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
1249  aMapMode.SetOrigin( OutputDevice::LogicToLogic( pA->GetPoint(), maVDev->GetMapMode(), aMapMode ) );
1250  maVDev->SetMapMode( aMapMode );
1251  ImplWrite( aSubstitute );
1252 
1253  maVDev->Pop();
1255  m_rStm.WriteInt32( -1 );
1256  ImplEndRecord();
1257  break;
1258  }
1259  }
1260  }
1261  break;
1262 
1263  case MetaActionType::BMP:
1264  {
1265  const MetaBmpAction* pA = static_cast<const MetaBmpAction *>(pAction);
1266  ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ), WIN_SRCCOPY );
1267  }
1268  break;
1269 
1271  {
1272  const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
1273  ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1274  }
1275  break;
1276 
1278  {
1279  const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pAction);
1280  Bitmap aTmp( pA->GetBitmap() );
1281 
1282  if( aTmp.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1283  ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1284  }
1285  break;
1286 
1287  case MetaActionType::BMPEX:
1288  {
1289  const MetaBmpExAction* pA = static_cast<const MetaBmpExAction *>(pAction);
1290  Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1291  Bitmap aMsk( pA->GetBitmapEx().GetAlpha() );
1292 
1293  if( !aMsk.IsEmpty() )
1294  {
1295  aBmp.Replace( aMsk, COL_WHITE );
1296  aMsk.Invert();
1297  ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev->PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT );
1298  ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev->PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND );
1299  }
1300  else
1301  ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY );
1302  }
1303  break;
1304 
1306  {
1307  const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
1308  Bitmap aBmp( pA->GetBitmapEx().GetBitmap() );
1309  Bitmap aMsk( pA->GetBitmapEx().GetAlpha() );
1310 
1311  if( !aMsk.IsEmpty() )
1312  {
1313  aBmp.Replace( aMsk, COL_WHITE );
1314  aMsk.Invert();
1315  ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT );
1316  ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND );
1317  }
1318  else
1319  ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1320  }
1321  break;
1322 
1324  {
1325  const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pAction);
1326  BitmapEx aBmpEx( pA->GetBitmapEx() );
1327  aBmpEx.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1328  Bitmap aBmp( aBmpEx.GetBitmap() );
1329  Bitmap aMsk( aBmpEx.GetAlpha() );
1330 
1331  if( !aMsk.IsEmpty() )
1332  {
1333  aBmp.Replace( aMsk, COL_WHITE );
1334  aMsk.Invert();
1335  ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT );
1336  ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND );
1337  }
1338  else
1339  ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1340  }
1341  break;
1342 
1343  case MetaActionType::TEXT:
1344  {
1345  const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
1346  const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1347 
1349  ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, 0 );
1350  }
1351  break;
1352 
1354  {
1355  const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
1356  const OUString& aText( pA->GetText() );
1357 
1359  ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, nullptr, 0 );
1360  }
1361  break;
1362 
1364  {
1365  const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
1366  const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1367 
1369  ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
1370  }
1371  break;
1372 
1374  {
1375  const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
1376  const OUString aText = pA->GetText().copy( pA->GetIndex(), std::min(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) );
1377 
1379  ImplWriteTextRecord( pA->GetPoint(), aText, nullptr, pA->GetWidth() );
1380  }
1381  break;
1382 
1384  {
1385  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1386  mbLineChanged = true;
1387  }
1388  break;
1389 
1391  {
1392  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1393  mbFillChanged = true;
1394  }
1395  break;
1396 
1401  case MetaActionType::FONT:
1402  {
1403  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1404  mbTextChanged = true;
1405  }
1406  break;
1407 
1409  {
1410  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1411 
1413  ImplWriteRect( static_cast<const MetaISectRectClipRegionAction*>(pAction)->GetRect() );
1414  ImplEndRecord();
1415  }
1416  break;
1417 
1421  {
1422  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1423  }
1424  break;
1425 
1428  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1429  break;
1430 
1431  case MetaActionType::PUSH:
1432  {
1433  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1434 
1436  ImplEndRecord();
1437  }
1438  break;
1439 
1440  case MetaActionType::POP:
1441  {
1442  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1443 
1445  m_rStm.WriteInt32( -1 );
1446  ImplEndRecord();
1447 
1448  ImplWriteRasterOp( maVDev->GetRasterOp() );
1450  }
1451  break;
1452 
1454  {
1455  const_cast<MetaAction*>(pAction)->Execute( maVDev );
1456  ImplWriteRasterOp( static_cast<const MetaRasterOpAction*>(pAction)->GetRasterOp() );
1457  }
1458  break;
1459 
1461  {
1462  ComplexTextLayoutFlags nLayoutMode = static_cast<const MetaLayoutModeAction*>(pAction)->GetLayoutMode();
1463  mnHorTextAlign = 0;
1465  {
1467  }
1472  break;
1473  }
1474 
1476  {
1477  MetaCommentAction const*const pCommentAction(
1478  static_cast<MetaCommentAction const*>(pAction));
1479  if (pCommentAction->GetComment() == "EMF_PLUS")
1480  {
1482  m_rStm.WriteBytes(pCommentAction->GetData(),
1483  pCommentAction->GetDataSize());
1485  }
1486  }
1487  break;
1488 
1489  case MetaActionType::MASK:
1495  // Explicitly ignored cases
1496  break;
1497 
1498  default:
1499  // TODO: Implement more cases as necessary. Let's not bother with a warning.
1500  break;
1501  }
1502  }
1503 }
1504 
1505 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() 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:186
sal_uInt32 mnLineHandle
Definition: emfwr.hxx:45
void ImplCheckTextAttr()
Definition: emfwr.cxx:451
void ImplWriteRect(const tools::Rectangle &rRect)
Definition: emfwr.cxx:630
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
#define WIN_EMR_ROUNDRECT
Definition: emfwr.cxx:62
sal_Int32 GetLen() const
Definition: metaact.hxx:497
const Point & GetPoint() const
Definition: metaact.hxx:716
sal_uInt8 GetRed() const
const OUString & GetFamilyName() const
Definition: font/font.cxx:829
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:1590
void ImplWritePlusFillPolygonRecord(const tools::Polygon &rPoly, sal_uInt32 nTrans)
Definition: emfwr.cxx:224
void ImplWrite(const GDIMetaFile &rMtf)
Definition: emfwr.cxx:970
#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
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1562
#define WIN_EMR_DELETEOBJECT
Definition: emfwr.cxx:59
constexpr tools::Long Left() const
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:175
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:1630
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
const ::avmedia::MediaItem * Execute(const SdrMarkView *pSdrView, SfxRequest const &rReq)
#define WIN_EMR_CLOSEFIGURE
Definition: emfwr.cxx:66
const Point & GetPoint() const
Definition: metaact.hxx:1591
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:717
#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:185
const OUString & GetText() const
Definition: metaact.hxx:573
FAMILY_ROMAN
Size GetSizePixel() const
sal_uLong mnRecordPos
Definition: emfwr.hxx:40
bool mbTextChanged
Definition: emfwr.hxx:48
constexpr bool IsHeightEmpty() const
WEIGHT_LIGHT
sal_uInt64 SeekRel(sal_Int64 nPos)
#define WIN_EMR_SETMAPMODE
Definition: emfwr.cxx:47
FontFamily GetFamilyType()
Definition: font/font.cxx:853
const sal_uInt8 * GetData() const
Definition: metaact.hxx:1694
WEIGHT_BOLD
constexpr tools::Long Width() const
FontItalic GetItalic()
Definition: font/font.cxx:852
#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:822
void ImplBeginRecord(sal_uInt32 nType)
Definition: emfwr.cxx:348
LINESTYLE_NONE
const OUString & GetText() const
Definition: metaact.hxx:495
void ImplWriteRasterOp(RasterOp eRop)
Definition: emfwr.cxx:596
void ImplReleaseHandle(sal_uLong nHandle)
Definition: emfwr.cxx:342
const Bitmap & GetBitmap() const
Definition: metaact.hxx:683
PolyFlags GetFlags(sal_uInt16 nPos) const
#define WIN_SRCAND
Definition: emfwr.cxx:77
TextAlign GetAlignment() const
Definition: font/font.cxx:827
int nCount
#define MM_ANISOTROPIC
Definition: emfwr.cxx:96
const Gradient & GetGradient() const
Definition: metaact.hxx:1013
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:823
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:99
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:215
FontPitch GetPitch()
Definition: font/font.cxx:849
const Size & GetPrefSize() const
Definition: gdimtf.hxx:172
int i
const Point & GetPoint() const
Definition: metaact.hxx:494
tools::Long FRound(double fVal)
PITCH_FIXED
#define TA_RTLREADING
Definition: emfwr.cxx:94
tools::Long GetOrCalculateAverageFontWidth() const
Definition: font/font.cxx:371
ComplexTextLayoutFlags
Definition: outdevstate.hxx:65
void Impl_handleLineInfoPolyPolygons(const LineInfo &rInfo, const basegfx::B2DPolygon &rLinePolygon)
Definition: emfwr.cxx:934
#define WIN_EMR_POLYPOLYGON
Definition: emfwr.cxx:40
#define WIN_SRCPAINT
Definition: emfwr.cxx:76
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:788
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:1012
#define WIN_EMR_INTERSECTCLIPRECT
Definition: emfwr.cxx:53
WEIGHT_MEDIUM
const Size & GetSize() const
Definition: metaact.hxx:1592
sal_uLong mnRecordCount
Definition: emfwr.hxx:39
sal_uInt32 GetWidth() const
Definition: metaact.hxx:574
void ImplBeginCommentRecord(sal_Int32 nCommentType)
Definition: emfwr.cxx:110
bool HasFlags() const
#define WIN_EMR_GDICOMMENT
Definition: emfwr.cxx:70
constexpr tools::Long Right() const
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:832
const OUString & GetText() const
Definition: metaact.hxx:611
void ImplWritePlusEOF()
Definition: emfwr.cxx:199
constexpr tools::Long Top() const
ALIGN_BOTTOM
#define WIN_EMR_EXTTEXTOUTW
Definition: emfwr.cxx:73
sal_uInt32 mnFillHandle
Definition: emfwr.hxx:47
FontStrikeout GetStrikeout() const
Definition: font/font.cxx:871
sal_uInt16 GetSize() const
sal_Int32 GetLen() const
Definition: metaact.hxx:576
const Point & GetPoint() const
Definition: metaact.hxx:789
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
RasterOp
Definition: RasterOp.hxx:22
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:1631
const Bitmap & GetBitmap() const
Definition: metaact.hxx:715
constexpr Point TopLeft() const
constexpr tools::Long Bottom() const
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:1072
void ImplEndRecord()
Definition: emfwr.cxx:362
#define WIN_EMR_STRETCHDIBITS
Definition: emfwr.cxx:71
const Point & GetPoint() const
Definition: metaact.hxx:572
#define WIN_EMR_MOVETOEX
Definition: emfwr.cxx:52
sal_uInt8 GetGreen() const
const Point & GetStartPoint() const
Definition: metaact.hxx:184
#define WIN_EMR_POLYBEZIERTO
Definition: emfwr.cxx:38
ALIGN_TOP
sal_uInt32 GetDataSize() const
Definition: metaact.hxx:1693
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:821
void ImplWriteBmpRecord(const Bitmap &rBmp, const Point &rPt, const Size &rSz, sal_uInt32 nROP)
Definition: emfwr.cxx:801
sal_uInt32 count() const
AlphaMask GetAlpha() const
Definition: BitmapEx.cxx:215
#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:850
constexpr tools::Long Height() const
unsigned char sal_uInt8
MetaAction * GetAction(size_t nAction) const
Definition: gdimtf.cxx:184
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:153
const Point & GetPoint() const
Definition: metaact.hxx:684
SvStream & WriteInt16(sal_Int16 nInt16)
SvStream & m_rStm
Definition: emfwr.hxx:36
bool IsEmpty() const
#define TA_BOTTOM
Definition: emfwr.cxx:92
sal_uInt64 Tell() const
size_t GetActionSize() const
Definition: gdimtf.cxx:179
QPRO_FUNC_TYPE nType
Degree10 GetOrientation() const
Definition: font/font.cxx:845
void ImplPlusRecord(EmfPlusRecordType nType, sal_uInt16 nFlags)
Definition: emfwr.cxx:159
MetaActionType GetType() const
Definition: metaact.hxx:91
#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:1073
FontLineStyle GetUnderline() const
Definition: font/font.cxx:869
tools::Rectangle GetBoundRect() const
void WriteEMFPlusHeader(const Size &rMtfSizePix, const Size &rMtfSizeLog)
Definition: emfwr.cxx:165
const OString & GetComment() const
Definition: metaact.hxx:1691
#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
STRIKEOUT_NONE
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1818
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:1629
#define WIN_EMR_SETVIEWPORTORGEX
Definition: emfwr.cxx:44
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
Definition: BitmapEx.cxx:354
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:610
sal_Int32 GetIndex() const
Definition: metaact.hxx:575
sal_Int32 GetIndex() const
Definition: metaact.hxx:496
constexpr bool IsWidthEmpty() const
#define WIN_EMR_EXTCREATEFONTINDIRECTW
Definition: emfwr.cxx:72
rtl_TextEncoding GetCharSet() const
Definition: font/font.cxx:838
void ImplCheckLineAttr()
Definition: emfwr.cxx:416
const void * GetData()
sal_uInt32 count() const