LibreOffice Module vcl (master)  1
gdimtf.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 <cstdlib>
21 #include <memory>
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <tools/diagnose_ex.h>
25 #include <tools/helpers.hxx>
26 #include <tools/stream.hxx>
27 #include <tools/vcompat.hxx>
28 #include <tools/fract.hxx>
29 #include <vcl/BitmapPalette.hxx>
30 #include <vcl/metaact.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/window.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/gdimtf.hxx>
36 #include <vcl/graphictools.hxx>
38 #include <vcl/canvastools.hxx>
39 #include <vcl/mtfxmldump.hxx>
40 
41 #include <svmconverter.hxx>
42 #include <TypeSerializer.hxx>
43 
44 #include <com/sun/star/beans/XFastPropertySet.hpp>
45 #include <com/sun/star/rendering/MtfRenderer.hpp>
46 #include <com/sun/star/rendering/XBitmapCanvas.hpp>
47 #include <com/sun/star/rendering/XCanvas.hpp>
49 
50 using namespace com::sun::star;
51 
52 #define GAMMA( _def_cVal, _def_InvGamma ) (static_cast<sal_uInt8>(MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0,255)))
53 
54 namespace {
55 
56 struct ImplColAdjustParam
57 {
58  std::unique_ptr<sal_uInt8[]> pMapR;
59  std::unique_ptr<sal_uInt8[]> pMapG;
60  std::unique_ptr<sal_uInt8[]> pMapB;
61 };
62 
63 struct ImplBmpAdjustParam
64 {
65  short nLuminancePercent;
66  short nContrastPercent;
67  short nChannelRPercent;
68  short nChannelGPercent;
69  short nChannelBPercent;
70  double fGamma;
71  bool bInvert;
72 };
73 
74 struct ImplColConvertParam
75 {
76  MtfConversion eConversion;
77 };
78 
79 struct ImplBmpConvertParam
80 {
81  BmpConversion eConversion;
82 };
83 
84 struct ImplColMonoParam
85 {
86  Color aColor;
87 };
88 
89 struct ImplBmpMonoParam
90 {
91  Color aColor;
92 };
93 
94 struct ImplColReplaceParam
95 {
96  std::unique_ptr<sal_uLong[]> pMinR;
97  std::unique_ptr<sal_uLong[]> pMaxR;
98  std::unique_ptr<sal_uLong[]> pMinG;
99  std::unique_ptr<sal_uLong[]> pMaxG;
100  std::unique_ptr<sal_uLong[]> pMinB;
101  std::unique_ptr<sal_uLong[]> pMaxB;
102  const Color * pDstCols;
104 };
105 
106 struct ImplBmpReplaceParam
107 {
108  const Color* pSrcCols;
109  const Color* pDstCols;
111 };
112 
113 }
114 
116  m_nCurrentActionElement( 0 ),
117  m_aPrefSize ( 1, 1 ),
118  m_pPrev ( nullptr ),
119  m_pNext ( nullptr ),
120  m_pOutDev ( nullptr ),
121  m_bPause ( false ),
122  m_bRecord ( false ),
123  m_bUseCanvas ( false )
124 {
125 }
126 
128  m_nCurrentActionElement( rMtf.m_nCurrentActionElement ),
129  m_aPrefMapMode ( rMtf.m_aPrefMapMode ),
130  m_aPrefSize ( rMtf.m_aPrefSize ),
131  m_pPrev ( rMtf.m_pPrev ),
132  m_pNext ( rMtf.m_pNext ),
133  m_pOutDev ( nullptr ),
134  m_bPause ( false ),
135  m_bRecord ( false ),
136  m_bUseCanvas ( rMtf.m_bUseCanvas )
137 {
138  for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i )
139  {
140  m_aList.push_back( rMtf.GetAction( i ) );
141  }
142 
143  if( rMtf.m_bRecord )
144  {
145  Record( rMtf.m_pOutDev );
146 
147  if ( rMtf.m_bPause )
148  Pause( true );
149  }
150 }
151 
153 {
154  Clear();
155 }
156 
158 {
159  MetaAction* pCurrAct;
160 
161  // watch for transparent drawing actions
162  for(pCurrAct = const_cast<GDIMetaFile*>(this)->FirstAction();
163  pCurrAct;
164  pCurrAct = const_cast<GDIMetaFile*>(this)->NextAction())
165  {
166  // #i10613# determine if the action is transparency capable
167 
168  // #107169# Also examine metafiles with masked bitmaps in
169  // detail. Further down, this is optimized in such a way
170  // that there's no unnecessary painting of masked bitmaps
171  // (which are _always_ subdivided into rectangular regions
172  // of uniform opacity): if a masked bitmap is printed over
173  // empty background, we convert to a plain bitmap with
174  // white background.
175  if (pCurrAct->IsTransparent())
176  return true;
177  }
178 
179  return false;
180 }
181 
183 {
184  return m_aList.size();
185 }
186 
187 MetaAction* GDIMetaFile::GetAction( size_t nAction ) const
188 {
189  return (nAction < m_aList.size()) ? m_aList[ nAction ].get() : nullptr;
190 }
191 
193 {
195  return m_aList.empty() ? nullptr : m_aList[ 0 ].get();
196 }
197 
199 {
200  return ( m_nCurrentActionElement + 1 < m_aList.size() ) ? m_aList[ ++m_nCurrentActionElement ].get() : nullptr;
201 }
202 
204 {
205  if ( nAction >= m_aList.size() )
206  {
207  return;
208  }
209  //fdo#39995 This doesn't increment the incoming action ref-count nor does it
210  //decrement the outgoing action ref-count
211  std::swap(pAction, m_aList[nAction]);
212 }
213 
215 {
216  if( this != &rMtf )
217  {
218  Clear();
219 
220  // Increment RefCount of MetaActions
221  for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i )
222  {
223  m_aList.push_back( rMtf.GetAction( i ) );
224  }
225 
227  m_aPrefSize = rMtf.m_aPrefSize;
228  m_pPrev = rMtf.m_pPrev;
229  m_pNext = rMtf.m_pNext;
230  m_pOutDev = nullptr;
231  m_bPause = false;
232  m_bRecord = false;
233  m_bUseCanvas = rMtf.m_bUseCanvas;
234 
235  if( rMtf.m_bRecord )
236  {
237  Record( rMtf.m_pOutDev );
238 
239  if( rMtf.m_bPause )
240  Pause( true );
241  }
242  }
243 
244  return *this;
245 }
246 
247 bool GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const
248 {
249  const size_t nObjCount = m_aList.size();
250  bool bRet = false;
251 
252  if( this == &rMtf )
253  bRet = true;
254  else if( rMtf.GetActionSize() == nObjCount &&
255  rMtf.GetPrefSize() == m_aPrefSize &&
256  rMtf.GetPrefMapMode() == m_aPrefMapMode )
257  {
258  bRet = true;
259 
260  for( size_t n = 0; n < nObjCount; n++ )
261  {
262  if( m_aList[ n ] != rMtf.GetAction( n ) )
263  {
264  bRet = false;
265  break;
266  }
267  }
268  }
269 
270  return bRet;
271 }
272 
274 {
275  if( m_bRecord )
276  Stop();
277 
278  m_aList.clear();
279 }
280 
281 void GDIMetaFile::Linker( OutputDevice* pOut, bool bLink )
282 {
283  if( bLink )
284  {
285  m_pNext = nullptr;
286  m_pPrev = pOut->GetConnectMetaFile();
287  pOut->SetConnectMetaFile( this );
288 
289  if( m_pPrev )
290  m_pPrev->m_pNext = this;
291  }
292  else
293  {
294  if( m_pNext )
295  {
297 
298  if( m_pPrev )
300  }
301  else
302  {
303  if( m_pPrev )
304  m_pPrev->m_pNext = nullptr;
305 
306  pOut->SetConnectMetaFile( m_pPrev );
307  }
308 
309  m_pPrev = nullptr;
310  m_pNext = nullptr;
311  }
312 }
313 
315 {
316  if( m_bRecord )
317  Stop();
318 
319  m_nCurrentActionElement = m_aList.empty() ? 0 : (m_aList.size() - 1);
320  m_pOutDev = pOut;
321  m_bRecord = true;
322  Linker( pOut, true );
323 }
324 
326 {
327  if ( !m_bRecord && !rMtf.m_bRecord )
328  {
329  MetaAction* pAction = GetCurAction();
330  const size_t nObjCount = m_aList.size();
331 
332  rMtf.UseCanvas( rMtf.GetUseCanvas() || m_bUseCanvas );
333 
334  for( size_t nCurPos = m_nCurrentActionElement; nCurPos < nObjCount; nCurPos++ )
335  {
336  if( pAction )
337  {
338  rMtf.AddAction( pAction );
339  }
340 
341  pAction = NextAction();
342  }
343  }
344 }
345 
346 void GDIMetaFile::Play( OutputDevice* pOut, size_t nPos )
347 {
348  if( !m_bRecord )
349  {
350  MetaAction* pAction = GetCurAction();
351  const size_t nObjCount = m_aList.size();
352  size_t nSyncCount = pOut->GetSyncCount();
353 
354  if( nPos > nObjCount )
355  nPos = nObjCount;
356 
357  // #i23407# Set backwards-compatible text language and layout mode
358  // This is necessary, since old metafiles don't even know of these
359  // recent add-ons. Newer metafiles must of course explicitly set
360  // those states.
364 
365  SAL_INFO( "vcl.gdi", "GDIMetaFile::Play on device of size: " << pOut->GetOutputSizePixel().Width() << " " << pOut->GetOutputSizePixel().Height());
366 
367  if( !ImplPlayWithRenderer( pOut, Point(0,0), pOut->GetOutputSize() ) ) {
368  size_t i = 0;
369  for( size_t nCurPos = m_nCurrentActionElement; nCurPos < nPos; nCurPos++ )
370  {
371  if( pAction )
372  {
373  pAction->Execute( pOut );
374 
375  // flush output from time to time
376  if( i++ > nSyncCount )
377  {
378  static_cast<vcl::Window*>( pOut )->Flush();
379  i = 0;
380  }
381  }
382 
383  pAction = NextAction();
384  }
385  }
386  pOut->Pop();
387  }
388 }
389 
390 bool GDIMetaFile::ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, Size rLogicDestSize )
391 {
392  if (!m_bUseCanvas)
393  return false;
394 
395  Size rDestSize( pOut->LogicToPixel( rLogicDestSize ) );
396 
397  const vcl::Window* win = dynamic_cast <vcl::Window*> ( pOut );
398 
399  if (!win)
401  if (!win)
403 
404  if (!win)
405  return false;
406 
407  try
408  {
409  uno::Reference<rendering::XCanvas> xCanvas = win->GetCanvas ();
410 
411  if (!xCanvas.is())
412  return false;
413 
414  Size aSize (rDestSize.Width () + 1, rDestSize.Height () + 1);
415  uno::Reference<rendering::XBitmap> xBitmap = xCanvas->getDevice ()->createCompatibleAlphaBitmap (vcl::unotools::integerSize2DFromSize( aSize));
416  if( xBitmap.is () )
417  {
418  uno::Reference< rendering::XBitmapCanvas > xBitmapCanvas( xBitmap, uno::UNO_QUERY );
419  if( xBitmapCanvas.is() )
420  {
421  uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
422  uno::Reference< rendering::XMtfRenderer > xMtfRenderer = rendering::MtfRenderer::createWithBitmapCanvas( xContext, xBitmapCanvas );
423 
424  xBitmapCanvas->clear();
425  uno::Reference< beans::XFastPropertySet > xMtfFastPropertySet( xMtfRenderer, uno::UNO_QUERY );
426  if( xMtfFastPropertySet.is() )
427  // set this metafile to the renderer to
428  // speedup things (instead of copying data to
429  // sequence of bytes passed to renderer)
430  xMtfFastPropertySet->setFastPropertyValue( 0, uno::Any( reinterpret_cast<sal_Int64>( this ) ) );
431 
432  xMtfRenderer->draw( rDestSize.Width(), rDestSize.Height() );
433 
434  BitmapEx aBitmapEx;
435  if( aBitmapEx.Create( xBitmapCanvas, aSize ) )
436  {
437  if (pOut->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
438  pOut->DrawBitmapEx( rPos, aBitmapEx );
439  else
440  pOut->DrawBitmapEx( rPos, rLogicDestSize, aBitmapEx );
441  return true;
442  }
443  }
444  }
445  }
446  catch (const uno::RuntimeException& )
447  {
448  throw; // runtime errors are fatal
449  }
450  catch (const uno::Exception&)
451  {
452  // ignore errors, no way of reporting them here
453  TOOLS_WARN_EXCEPTION("vcl.gdi", "GDIMetaFile::ImplPlayWithRenderer");
454  }
455 
456  return false;
457 }
458 
459 void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos,
460  const Size& rSize )
461 {
462  MapMode aDrawMap( GetPrefMapMode() );
463  Size aDestSize( pOut->LogicToPixel( rSize ) );
464 
465  if( !aDestSize.Width() || !aDestSize.Height() )
466  return;
467 
468  GDIMetaFile* pMtf = pOut->GetConnectMetaFile();
469 
470  if( ImplPlayWithRenderer( pOut, rPos, rSize ) )
471  return;
472 
473  Size aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) );
474 
475  if( !aTmpPrefSize.Width() )
476  aTmpPrefSize.setWidth( aDestSize.Width() );
477 
478  if( !aTmpPrefSize.Height() )
479  aTmpPrefSize.setHeight( aDestSize.Height() );
480 
481  Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() );
482  Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() );
483 
484  aScaleX *= aDrawMap.GetScaleX(); aDrawMap.SetScaleX( aScaleX );
485  aScaleY *= aDrawMap.GetScaleY(); aDrawMap.SetScaleY( aScaleY );
486 
487  // #i47260# Convert logical output position to offset within
488  // the metafile's mapmode. Therefore, disable pixel offset on
489  // outdev, it's inverse mnOutOffLogicX/Y is calculated for a
490  // different mapmode (the one currently set on pOut, that is)
491  // - thus, aDrawMap's origin would generally be wrong. And
492  // even _if_ aDrawMap is similar to pOutDev's current mapmode,
493  // it's _still_ undesirable to have pixel offset unequal zero,
494  // because one would still get round-off errors (the
495  // round-trip error for LogicToPixel( PixelToLogic() ) was the
496  // reason for having pixel offset in the first place).
497  const Size& rOldOffset( pOut->GetPixelOffset() );
498  const Size aEmptySize;
499  pOut->SetPixelOffset( aEmptySize );
500  aDrawMap.SetOrigin( pOut->PixelToLogic( pOut->LogicToPixel( rPos ), aDrawMap ) );
501  pOut->SetPixelOffset( rOldOffset );
502 
503  pOut->Push();
504 
505  bool bIsRecord = (pMtf && pMtf->IsRecord());
506  pOut->SetMetafileMapMode(aDrawMap, bIsRecord);
507 
508  // #i23407# Set backwards-compatible text language and layout mode
509  // This is necessary, since old metafiles don't even know of these
510  // recent add-ons. Newer metafiles must of course explicitly set
511  // those states.
514 
515  Play( pOut );
516 
517  pOut->Pop();
518 
519 }
520 
521 void GDIMetaFile::Pause( bool _bPause )
522 {
523  if( m_bRecord )
524  {
525  if( _bPause )
526  {
527  if( !m_bPause )
528  Linker( m_pOutDev, false );
529  }
530  else
531  {
532  if( m_bPause )
533  Linker( m_pOutDev, true );
534  }
535 
536  m_bPause = _bPause;
537  }
538 }
539 
541 {
542  if( m_bRecord )
543  {
544  m_bRecord = false;
545 
546  if( !m_bPause )
547  Linker( m_pOutDev, false );
548  else
549  m_bPause = false;
550  }
551 }
552 
554 {
555  if( !m_bRecord )
557 }
558 
560 {
561  if( !m_bRecord )
562  if ( m_nCurrentActionElement > 0 )
564 }
565 
567 {
568  m_aList.push_back( pAction );
569 
570  if( m_pPrev )
571  {
572  m_pPrev->AddAction( pAction );
573  }
574 }
575 
576 void GDIMetaFile::AddAction(const rtl::Reference<MetaAction>& pAction, size_t nPos)
577 {
578  if ( nPos < m_aList.size() )
579  {
580  m_aList.insert( m_aList.begin() + nPos, pAction );
581  }
582  else
583  {
584  m_aList.push_back( pAction );
585  }
586 
587  if( m_pPrev )
588  {
589  m_pPrev->AddAction( pAction, nPos );
590  }
591 }
592 
594 {
595  m_aList.push_back( pAction );
596 }
597 
599 {
600  const Size aOldPrefSize( GetPrefSize() );
601  long nMoveX, nMoveY;
602  double fScaleX, fScaleY;
603 
604  if( nMirrorFlags & BmpMirrorFlags::Horizontal )
605  {
606  nMoveX = std::abs( aOldPrefSize.Width() ) - 1;
607  fScaleX = -1.0;
608  }
609  else
610  {
611  nMoveX = 0;
612  fScaleX = 1.0;
613  }
614 
615  if( nMirrorFlags & BmpMirrorFlags::Vertical )
616  {
617  nMoveY = std::abs( aOldPrefSize.Height() ) - 1;
618  fScaleY = -1.0;
619  }
620  else
621  {
622  nMoveY = 0;
623  fScaleY = 1.0;
624  }
625 
626  if( ( fScaleX != 1.0 ) || ( fScaleY != 1.0 ) )
627  {
628  Scale( fScaleX, fScaleY );
629  Move( nMoveX, nMoveY );
630  SetPrefSize( aOldPrefSize );
631  }
632 }
633 
634 void GDIMetaFile::Move( long nX, long nY )
635 {
636  const Size aBaseOffset( nX, nY );
637  Size aOffset( aBaseOffset );
639 
640  aMapVDev->EnableOutput( false );
641  aMapVDev->SetMapMode( GetPrefMapMode() );
642 
643  for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
644  {
645  const MetaActionType nType = pAct->GetType();
646  MetaAction* pModAct;
647 
648  if( pAct->GetRefCount() > 1 )
649  {
650  m_aList[ m_nCurrentActionElement ] = pAct->Clone();
651  pModAct = m_aList[ m_nCurrentActionElement ].get();
652  }
653  else
654  pModAct = pAct;
655 
656  if( ( MetaActionType::MAPMODE == nType ) ||
657  ( MetaActionType::PUSH == nType ) ||
658  ( MetaActionType::POP == nType ) )
659  {
660  pModAct->Execute( aMapVDev.get() );
661  aOffset = OutputDevice::LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev->GetMapMode() );
662  }
663 
664  pModAct->Move( aOffset.Width(), aOffset.Height() );
665  }
666 }
667 
668 void GDIMetaFile::Move( long nX, long nY, long nDPIX, long nDPIY )
669 {
670  const Size aBaseOffset( nX, nY );
671  Size aOffset( aBaseOffset );
673 
674  aMapVDev->EnableOutput( false );
675  aMapVDev->SetReferenceDevice( nDPIX, nDPIY );
676  aMapVDev->SetMapMode( GetPrefMapMode() );
677 
678  for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
679  {
680  const MetaActionType nType = pAct->GetType();
681  MetaAction* pModAct;
682 
683  if( pAct->GetRefCount() > 1 )
684  {
685  m_aList[ m_nCurrentActionElement ] = pAct->Clone();
686  pModAct = m_aList[ m_nCurrentActionElement ].get();
687  }
688  else
689  pModAct = pAct;
690 
691  if( ( MetaActionType::MAPMODE == nType ) ||
692  ( MetaActionType::PUSH == nType ) ||
693  ( MetaActionType::POP == nType ) )
694  {
695  pModAct->Execute( aMapVDev.get() );
696  if( aMapVDev->GetMapMode().GetMapUnit() == MapUnit::MapPixel )
697  {
698  aOffset = aMapVDev->LogicToPixel( aBaseOffset, GetPrefMapMode() );
699  MapMode aMap( aMapVDev->GetMapMode() );
700  aOffset.setWidth( static_cast<long>(aOffset.Width() * static_cast<double>(aMap.GetScaleX())) );
701  aOffset.setHeight( static_cast<long>(aOffset.Height() * static_cast<double>(aMap.GetScaleY())) );
702  }
703  else
704  aOffset = OutputDevice::LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev->GetMapMode() );
705  }
706 
707  pModAct->Move( aOffset.Width(), aOffset.Height() );
708  }
709 }
710 
711 void GDIMetaFile::Scale( double fScaleX, double fScaleY )
712 {
713  for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
714  {
715  MetaAction* pModAct;
716 
717  if( pAct->GetRefCount() > 1 )
718  {
719  m_aList[ m_nCurrentActionElement ] = pAct->Clone();
720  pModAct = m_aList[ m_nCurrentActionElement ].get();
721  }
722  else
723  pModAct = pAct;
724 
725  pModAct->Scale( fScaleX, fScaleY );
726  }
727 
728  m_aPrefSize.setWidth( FRound( m_aPrefSize.Width() * fScaleX ) );
729  m_aPrefSize.setHeight( FRound( m_aPrefSize.Height() * fScaleY ) );
730 }
731 
732 void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY )
733 {
734  Scale( static_cast<double>(rScaleX), static_cast<double>(rScaleY) );
735 }
736 
737 void GDIMetaFile::Clip( const tools::Rectangle& i_rClipRect )
738 {
739  tools::Rectangle aCurRect( i_rClipRect );
741 
742  aMapVDev->EnableOutput( false );
743  aMapVDev->SetMapMode( GetPrefMapMode() );
744 
745  for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
746  {
747  const MetaActionType nType = pAct->GetType();
748 
749  if( ( MetaActionType::MAPMODE == nType ) ||
750  ( MetaActionType::PUSH == nType ) ||
751  ( MetaActionType::POP == nType ) )
752  {
753  pAct->Execute( aMapVDev.get() );
754  aCurRect = OutputDevice::LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev->GetMapMode() );
755  }
756  else if( nType == MetaActionType::CLIPREGION )
757  {
758  MetaClipRegionAction* pOldAct = static_cast<MetaClipRegionAction*>(pAct);
759  vcl::Region aNewReg( aCurRect );
760  if( pOldAct->IsClipping() )
761  aNewReg.Intersect( pOldAct->GetRegion() );
762  MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, true );
763  m_aList[ m_nCurrentActionElement ] = pNewAct;
764  }
765  }
766 }
767 
768 Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt,
769  const Size& rOffset, double fSin, double fCos )
770 {
771  const long nX = rPt.X() - rRotatePt.X();
772  const long nY = rPt.Y() - rRotatePt.Y();
773 
774  return Point( FRound( fCos * nX + fSin * nY ) + rRotatePt.X() + rOffset.Width(),
775  -FRound( fSin * nX - fCos * nY ) + rRotatePt.Y() + rOffset.Height() );
776 }
777 
779  const Size& rOffset, double fSin, double fCos )
780 {
781  tools::Polygon aRet( rPoly );
782 
783  aRet.Rotate( rRotatePt, fSin, fCos );
784  aRet.Move( rOffset.Width(), rOffset.Height() );
785 
786  return aRet;
787 }
788 
790  const Size& rOffset, double fSin, double fCos )
791 {
792  tools::PolyPolygon aRet( rPolyPoly );
793 
794  aRet.Rotate( rRotatePt, fSin, fCos );
795  aRet.Move( rOffset.Width(), rOffset.Height() );
796 
797  return aRet;
798 }
799 
801  const OutputDevice& rMapDev,
802  const tools::PolyPolygon& rPolyPoly,
803  const Gradient& rGrad )
804 {
805  // Generate comment, GradientEx and Gradient actions (within DrawGradient)
807  aVDev->EnableOutput( false );
808  GDIMetaFile aGradMtf;
809 
810  aGradMtf.Record( aVDev.get() );
811  aVDev->DrawGradient( rPolyPoly, rGrad );
812  aGradMtf.Stop();
813 
814  size_t i, nAct( aGradMtf.GetActionSize() );
815  for( i=0; i < nAct; ++i )
816  {
817  MetaAction* pMetaAct = aGradMtf.GetAction( i );
818  rMtf.AddAction( pMetaAct );
819  }
820 }
821 
822 void GDIMetaFile::Rotate( long nAngle10 )
823 {
824  nAngle10 %= 3600;
825  nAngle10 = ( nAngle10 < 0 ) ? ( 3599 + nAngle10 ) : nAngle10;
826 
827  if( !nAngle10 )
828  return;
829 
830  GDIMetaFile aMtf;
832  const double fAngle = F_PI1800 * nAngle10;
833  const double fSin = sin( fAngle );
834  const double fCos = cos( fAngle );
835  tools::Rectangle aRect( Point(), GetPrefSize() );
836  tools::Polygon aPoly( aRect );
837 
838  aPoly.Rotate( Point(), fSin, fCos );
839 
840  aMapVDev->EnableOutput( false );
841  aMapVDev->SetMapMode( GetPrefMapMode() );
842 
843  const tools::Rectangle aNewBound( aPoly.GetBoundRect() );
844 
845  const Point aOrigin( GetPrefMapMode().GetOrigin().X(), GetPrefMapMode().GetOrigin().Y() );
846  const Size aOffset( -aNewBound.Left(), -aNewBound.Top() );
847 
848  Point aRotAnchor( aOrigin );
849  Size aRotOffset( aOffset );
850 
851  for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() )
852  {
853  const MetaActionType nActionType = pAction->GetType();
854 
855  switch( nActionType )
856  {
858  {
859  MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
860  aMtf.AddAction( new MetaPixelAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
861  pAct->GetColor() ) );
862  }
863  break;
864 
866  {
867  MetaPointAction* pAct = static_cast<MetaPointAction*>(pAction);
868  aMtf.AddAction( new MetaPointAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
869  }
870  break;
871 
873  {
874  MetaLineAction* pAct = static_cast<MetaLineAction*>(pAction);
875  aMtf.AddAction( new MetaLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
876  ImplGetRotatedPoint( pAct->GetEndPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
877  pAct->GetLineInfo() ) );
878  }
879  break;
880 
882  {
883  MetaRectAction* pAct = static_cast<MetaRectAction*>(pAction);
884  aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
885  }
886  break;
887 
889  {
890  MetaRoundRectAction* pAct = static_cast<MetaRoundRectAction*>(pAction);
891  const tools::Polygon aRoundRectPoly( pAct->GetRect(), pAct->GetHorzRound(), pAct->GetVertRound() );
892 
893  aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aRoundRectPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
894  }
895  break;
896 
898  {
899  MetaEllipseAction* pAct = static_cast<MetaEllipseAction*>(pAction);
900  const tools::Polygon aEllipsePoly( pAct->GetRect().Center(), pAct->GetRect().GetWidth() >> 1, pAct->GetRect().GetHeight() >> 1 );
901 
902  aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aEllipsePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
903  }
904  break;
905 
906  case MetaActionType::ARC:
907  {
908  MetaArcAction* pAct = static_cast<MetaArcAction*>(pAction);
909  const tools::Polygon aArcPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Arc );
910 
911  aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aArcPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
912  }
913  break;
914 
915  case MetaActionType::PIE:
916  {
917  MetaPieAction* pAct = static_cast<MetaPieAction*>(pAction);
918  const tools::Polygon aPiePoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Pie );
919 
920  aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aPiePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
921  }
922  break;
923 
925  {
926  MetaChordAction* pAct = static_cast<MetaChordAction*>(pAction);
927  const tools::Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Chord );
928 
929  aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aChordPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
930  }
931  break;
932 
934  {
935  MetaPolyLineAction* pAct = static_cast<MetaPolyLineAction*>(pAction);
936  aMtf.AddAction( new MetaPolyLineAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->GetLineInfo() ) );
937  }
938  break;
939 
941  {
942  MetaPolygonAction* pAct = static_cast<MetaPolygonAction*>(pAction);
943  aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
944  }
945  break;
946 
948  {
949  MetaPolyPolygonAction* pAct = static_cast<MetaPolyPolygonAction*>(pAction);
950  aMtf.AddAction( new MetaPolyPolygonAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
951  }
952  break;
953 
955  {
956  MetaTextAction* pAct = static_cast<MetaTextAction*>(pAction);
957  aMtf.AddAction( new MetaTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
958  pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
959  }
960  break;
961 
963  {
964  MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pAction);
965  aMtf.AddAction( new MetaTextArrayAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
966  pAct->GetText(), pAct->GetDXArray(), pAct->GetIndex(), pAct->GetLen() ) );
967  }
968  break;
969 
971  {
972  MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pAction);
973  aMtf.AddAction( new MetaStretchTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
974  pAct->GetWidth(), pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
975  }
976  break;
977 
979  {
980  MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pAction);
981  aMtf.AddAction( new MetaTextLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
982  pAct->GetWidth(), pAct->GetStrikeout(), pAct->GetUnderline(), pAct->GetOverline() ) );
983  }
984  break;
985 
987  {
988  MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
989  tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
990  tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
991  BitmapEx aBmpEx( pAct->GetBitmap() );
992 
993  aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
994  aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(),
995  aBmpEx ) );
996  }
997  break;
998 
1000  {
1001  MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
1002  tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1003  tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
1004  BitmapEx aBmpEx( pAct->GetBitmap() );
1005 
1006  aBmpEx.Crop( tools::Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
1007  aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
1008 
1009  aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1010  }
1011  break;
1012 
1014  {
1015  MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
1016  tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1017  tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
1018  BitmapEx aBmpEx( pAct->GetBitmapEx() );
1019 
1020  aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
1021 
1022  aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1023  }
1024  break;
1025 
1027  {
1028  MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
1029  tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1030  tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
1031  BitmapEx aBmpEx( pAct->GetBitmapEx() );
1032 
1033  aBmpEx.Crop( tools::Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
1034  aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
1035 
1036  aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
1037  }
1038  break;
1039 
1041  {
1042  MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction);
1043 
1044  ImplAddGradientEx( aMtf, *aMapVDev,
1045  ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ),
1046  pAct->GetGradient() );
1047  }
1048  break;
1049 
1051  {
1052  MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
1053  aMtf.AddAction( new MetaGradientExAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1054  pAct->GetGradient() ) );
1055  }
1056  break;
1057 
1058  // Handle gradientex comment block correctly
1060  {
1061  MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction);
1062  if( pCommentAct->GetComment() == "XGRAD_SEQ_BEGIN" )
1063  {
1064  int nBeginComments( 1 );
1065  pAction = NextAction();
1066 
1067  // skip everything, except gradientex action
1068  while( pAction )
1069  {
1070  const MetaActionType nType = pAction->GetType();
1071 
1072  if( MetaActionType::GRADIENTEX == nType )
1073  {
1074  // Add rotated gradientex
1075  MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
1076  ImplAddGradientEx( aMtf, *aMapVDev,
1077  ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1078  pAct->GetGradient() );
1079  }
1080  else if( MetaActionType::COMMENT == nType)
1081  {
1082  MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pAction);
1083  if( pAct->GetComment() == "XGRAD_SEQ_END" )
1084  {
1085  // handle nested blocks
1086  --nBeginComments;
1087 
1088  // gradientex comment block: end reached, done.
1089  if( !nBeginComments )
1090  break;
1091  }
1092  else if( pAct->GetComment() == "XGRAD_SEQ_BEGIN" )
1093  {
1094  // handle nested blocks
1095  ++nBeginComments;
1096  }
1097 
1098  }
1099 
1100  pAction =NextAction();
1101  }
1102  }
1103  else
1104  {
1105  bool bPathStroke = (pCommentAct->GetComment() == "XPATHSTROKE_SEQ_BEGIN");
1106  if ( bPathStroke || pCommentAct->GetComment() == "XPATHFILL_SEQ_BEGIN" )
1107  {
1108  if ( pCommentAct->GetDataSize() )
1109  {
1110  SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pCommentAct->GetData()), pCommentAct->GetDataSize(), StreamMode::READ );
1111  SvMemoryStream aDest;
1112  if ( bPathStroke )
1113  {
1114  SvtGraphicStroke aStroke;
1115  ReadSvtGraphicStroke( aMemStm, aStroke );
1116  tools::Polygon aPath;
1117  aStroke.getPath( aPath );
1118  aStroke.setPath( ImplGetRotatedPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
1119  WriteSvtGraphicStroke( aDest, aStroke );
1120  aMtf.AddAction( new MetaCommentAction( "XPATHSTROKE_SEQ_BEGIN", 0,
1121  static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
1122  }
1123  else
1124  {
1125  SvtGraphicFill aFill;
1126  ReadSvtGraphicFill( aMemStm, aFill );
1127  tools::PolyPolygon aPath;
1128  aFill.getPath( aPath );
1129  aFill.setPath( ImplGetRotatedPolyPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
1130  WriteSvtGraphicFill( aDest, aFill );
1131  aMtf.AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
1132  static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
1133  }
1134  }
1135  }
1136  else if ( pCommentAct->GetComment() == "XPATHSTROKE_SEQ_END"
1137  || pCommentAct->GetComment() == "XPATHFILL_SEQ_END" )
1138  {
1139  pAction->Execute( aMapVDev.get() );
1140  aMtf.AddAction( pAction );
1141  }
1142  }
1143  }
1144  break;
1145 
1146  case MetaActionType::HATCH:
1147  {
1148  MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction);
1149  Hatch aHatch( pAct->GetHatch() );
1150 
1151  aHatch.SetAngle( aHatch.GetAngle() + static_cast<sal_uInt16>(nAngle10) );
1152  aMtf.AddAction( new MetaHatchAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1153  aHatch ) );
1154  }
1155  break;
1156 
1158  {
1159  MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pAction);
1160  aMtf.AddAction( new MetaTransparentAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
1161  pAct->GetTransparence() ) );
1162  }
1163  break;
1164 
1166  {
1167  MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction);
1168  GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
1169  tools::Polygon aMtfPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1170  tools::Rectangle aMtfRect( aMtfPoly.GetBoundRect() );
1171 
1172  aTransMtf.Rotate( nAngle10 );
1173  aMtf.AddAction( new MetaFloatTransparentAction( aTransMtf, aMtfRect.TopLeft(), aMtfRect.GetSize(),
1174  pAct->GetGradient() ) );
1175  }
1176  break;
1177 
1178  case MetaActionType::EPS:
1179  {
1180  MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
1181  GDIMetaFile aEPSMtf( pAct->GetSubstitute() );
1182  tools::Polygon aEPSPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
1183  tools::Rectangle aEPSRect( aEPSPoly.GetBoundRect() );
1184 
1185  aEPSMtf.Rotate( nAngle10 );
1186  aMtf.AddAction( new MetaEPSAction( aEPSRect.TopLeft(), aEPSRect.GetSize(),
1187  pAct->GetLink(), aEPSMtf ) );
1188  }
1189  break;
1190 
1192  {
1193  MetaClipRegionAction* pAct = static_cast<MetaClipRegionAction*>(pAction);
1194 
1195  if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygonOrB2DPolyPolygon() )
1196  aMtf.AddAction( new MetaClipRegionAction( vcl::Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), true ) );
1197  else
1198  {
1199  aMtf.AddAction( pAction );
1200  }
1201  }
1202  break;
1203 
1205  {
1206  MetaISectRectClipRegionAction* pAct = static_cast<MetaISectRectClipRegionAction*>(pAction);
1207  aMtf.AddAction( new MetaISectRegionClipRegionAction(vcl::Region(
1208  ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor,
1209  aRotOffset, fSin, fCos )) ) );
1210  }
1211  break;
1212 
1214  {
1215  MetaISectRegionClipRegionAction* pAct = static_cast<MetaISectRegionClipRegionAction*>(pAction);
1216  const vcl::Region& rRegion = pAct->GetRegion();
1217 
1218  if( rRegion.HasPolyPolygonOrB2DPolyPolygon() )
1219  aMtf.AddAction( new MetaISectRegionClipRegionAction( vcl::Region( ImplGetRotatedPolyPolygon( rRegion.GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) );
1220  else
1221  {
1222  aMtf.AddAction( pAction );
1223  }
1224  }
1225  break;
1226 
1228  {
1229  MetaRefPointAction* pAct = static_cast<MetaRefPointAction*>(pAction);
1230  aMtf.AddAction( new MetaRefPointAction( ImplGetRotatedPoint( pAct->GetRefPoint(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->IsSetting() ) );
1231  }
1232  break;
1233 
1234  case MetaActionType::FONT:
1235  {
1236  MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction);
1237  vcl::Font aFont( pAct->GetFont() );
1238 
1239  aFont.SetOrientation( aFont.GetOrientation() + static_cast<sal_uInt16>(nAngle10) );
1240  aMtf.AddAction( new MetaFontAction( aFont ) );
1241  }
1242  break;
1243 
1244  case MetaActionType::BMP:
1245  case MetaActionType::BMPEX:
1246  case MetaActionType::MASK:
1252  {
1253  OSL_FAIL( "GDIMetaFile::Rotate(): unsupported action" );
1254  }
1255  break;
1256 
1257  default:
1258  {
1259  pAction->Execute( aMapVDev.get() );
1260  aMtf.AddAction( pAction );
1261 
1262  // update rotation point and offset, if necessary
1263  if( ( MetaActionType::MAPMODE == nActionType ) ||
1264  ( MetaActionType::PUSH == nActionType ) ||
1265  ( MetaActionType::POP == nActionType ) )
1266  {
1267  aRotAnchor = OutputDevice::LogicToLogic( aOrigin, m_aPrefMapMode, aMapVDev->GetMapMode() );
1268  aRotOffset = OutputDevice::LogicToLogic( aOffset, m_aPrefMapMode, aMapVDev->GetMapMode() );
1269  }
1270  }
1271  break;
1272  }
1273  }
1274 
1276  aMtf.m_aPrefSize = aNewBound.GetSize();
1277 
1278  *this = aMtf;
1279 
1280 }
1281 
1282 static void ImplActionBounds( tools::Rectangle& o_rOutBounds,
1283  const tools::Rectangle& i_rInBounds,
1284  const std::vector<tools::Rectangle>& i_rClipStack,
1285  tools::Rectangle* o_pHairline )
1286 {
1287  tools::Rectangle aBounds( i_rInBounds );
1288  if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() )
1289  aBounds.Intersection( i_rClipStack.back() );
1290  if( ! aBounds.IsEmpty() )
1291  {
1292  if( ! o_rOutBounds.IsEmpty() )
1293  o_rOutBounds.Union( aBounds );
1294  else
1295  o_rOutBounds = aBounds;
1296 
1297  if(o_pHairline)
1298  {
1299  if( ! o_pHairline->IsEmpty() )
1300  o_pHairline->Union( aBounds );
1301  else
1302  *o_pHairline = aBounds;
1303  }
1304  }
1305 }
1306 
1308 {
1309  ScopedVclPtrInstance< VirtualDevice > aMapVDev( i_rReference );
1310 
1311  aMapVDev->EnableOutput( false );
1312  aMapVDev->SetMapMode( GetPrefMapMode() );
1313 
1314  std::vector<tools::Rectangle> aClipStack( 1, tools::Rectangle() );
1315  std::vector<PushFlags> aPushFlagStack;
1316 
1317  tools::Rectangle aBound;
1318 
1319  if(pHairline)
1320  *pHairline = tools::Rectangle();
1321 
1322  const sal_uLong nCount(GetActionSize());
1323 
1324  for(sal_uLong a(0); a < nCount; a++)
1325  {
1326  MetaAction* pAction = GetAction(a);
1327  const MetaActionType nActionType = pAction->GetType();
1328  tools::Rectangle* pUseHairline = (pHairline && aMapVDev->IsLineColor()) ? pHairline : nullptr;
1329 
1330  switch( nActionType )
1331  {
1332  case MetaActionType::PIXEL:
1333  {
1334  MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
1335  ImplActionBounds( aBound,
1336  tools::Rectangle( OutputDevice::LogicToLogic( pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ),
1337  aMapVDev->PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1338  aClipStack, pUseHairline );
1339  }
1340  break;
1341 
1342  case MetaActionType::POINT:
1343  {
1344  MetaPointAction* pAct = static_cast<MetaPointAction*>(pAction);
1345  ImplActionBounds( aBound,
1346  tools::Rectangle( OutputDevice::LogicToLogic( pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ),
1347  aMapVDev->PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
1348  aClipStack, pUseHairline );
1349  }
1350  break;
1351 
1352  case MetaActionType::LINE:
1353  {
1354  MetaLineAction* pAct = static_cast<MetaLineAction*>(pAction);
1355  Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() );
1356  tools::Rectangle aRect( aP1, aP2 );
1357  aRect.Justify();
1358 
1359  if(pUseHairline)
1360  {
1361  const LineInfo& rLineInfo = pAct->GetLineInfo();
1362 
1363  if(0 != rLineInfo.GetWidth())
1364  pUseHairline = nullptr;
1365  }
1366 
1367  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1368  }
1369  break;
1370 
1371  case MetaActionType::RECT:
1372  {
1373  MetaRectAction* pAct = static_cast<MetaRectAction*>(pAction);
1374  ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1375  }
1376  break;
1377 
1379  {
1380  MetaRoundRectAction* pAct = static_cast<MetaRoundRectAction*>(pAction);
1381  ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1382  }
1383  break;
1384 
1386  {
1387  MetaEllipseAction* pAct = static_cast<MetaEllipseAction*>(pAction);
1388  ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1389  }
1390  break;
1391 
1392  case MetaActionType::ARC:
1393  {
1394  MetaArcAction* pAct = static_cast<MetaArcAction*>(pAction);
1395  // FIXME: this is imprecise
1396  // e.g. for small arcs the whole rectangle is WAY too large
1397  ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1398  }
1399  break;
1400 
1401  case MetaActionType::PIE:
1402  {
1403  MetaPieAction* pAct = static_cast<MetaPieAction*>(pAction);
1404  // FIXME: this is imprecise
1405  // e.g. for small arcs the whole rectangle is WAY too large
1406  ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1407  }
1408  break;
1409 
1410  case MetaActionType::CHORD:
1411  {
1412  MetaChordAction* pAct = static_cast<MetaChordAction*>(pAction);
1413  // FIXME: this is imprecise
1414  // e.g. for small arcs the whole rectangle is WAY too large
1415  ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1416  }
1417  break;
1418 
1420  {
1421  MetaPolyLineAction* pAct = static_cast<MetaPolyLineAction*>(pAction);
1422  tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1423 
1424  if(pUseHairline)
1425  {
1426  const LineInfo& rLineInfo = pAct->GetLineInfo();
1427 
1428  if(0 != rLineInfo.GetWidth())
1429  pUseHairline = nullptr;
1430  }
1431 
1432  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1433  }
1434  break;
1435 
1437  {
1438  MetaPolygonAction* pAct = static_cast<MetaPolygonAction*>(pAction);
1439  tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
1440  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1441  }
1442  break;
1443 
1445  {
1446  MetaPolyPolygonAction* pAct = static_cast<MetaPolyPolygonAction*>(pAction);
1447  tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1448  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
1449  }
1450  break;
1451 
1452  case MetaActionType::TEXT:
1453  {
1454  MetaTextAction* pAct = static_cast<MetaTextAction*>(pAction);
1455  tools::Rectangle aRect;
1456  // hdu said base = index
1457  aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() );
1458  Point aPt( pAct->GetPoint() );
1459  aRect.Move( aPt.X(), aPt.Y() );
1460  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1461  }
1462  break;
1463 
1465  {
1466  MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pAction);
1467  tools::Rectangle aRect;
1468  // hdu said base = index
1469  aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1470  0, pAct->GetDXArray() );
1471  Point aPt( pAct->GetPoint() );
1472  aRect.Move( aPt.X(), aPt.Y() );
1473  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1474  }
1475  break;
1476 
1478  {
1479  MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pAction);
1480  tools::Rectangle aRect;
1481  // hdu said base = index
1482  aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
1483  pAct->GetWidth() );
1484  Point aPt( pAct->GetPoint() );
1485  aRect.Move( aPt.X(), aPt.Y() );
1486  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1487  }
1488  break;
1489 
1491  {
1492  MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pAction);
1493  // measure a test string to get ascend and descent right
1494  static const sal_Unicode pStr[] = { 0xc4, 0x67, 0 };
1495  OUString aStr( pStr );
1496 
1497  tools::Rectangle aRect;
1498  aMapVDev->GetTextBoundRect( aRect, aStr, 0, 0, aStr.getLength() );
1499  Point aPt( pAct->GetStartPoint() );
1500  aRect.Move( aPt.X(), aPt.Y() );
1501  aRect.SetRight( aRect.Left() + pAct->GetWidth() );
1502  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1503  }
1504  break;
1505 
1507  {
1508  MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
1509  tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1510  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1511  }
1512  break;
1513 
1515  {
1516  MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
1517  tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1518  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1519  }
1520  break;
1521 
1523  {
1524  MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
1525  tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1526  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1527  }
1528  break;
1529 
1531  {
1532  MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
1533  tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1534  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1535  }
1536  break;
1537 
1539  {
1540  MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction);
1541  tools::Rectangle aRect( pAct->GetRect() );
1542  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1543  }
1544  break;
1545 
1547  {
1548  MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
1549  tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1550  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1551  }
1552  break;
1553 
1555  {
1556  // nothing to do
1557  };
1558  break;
1559 
1560  case MetaActionType::HATCH:
1561  {
1562  MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction);
1563  tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1564  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1565  }
1566  break;
1567 
1569  {
1570  MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pAction);
1571  tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
1572  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1573  }
1574  break;
1575 
1577  {
1578  MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction);
1579  // MetaFloatTransparentAction is defined limiting its content Metafile
1580  // to its geometry definition(Point, Size), so use these directly
1581  const tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1582  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1583  }
1584  break;
1585 
1586  case MetaActionType::EPS:
1587  {
1588  MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
1589  tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
1590  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1591  }
1592  break;
1593 
1595  {
1596  MetaClipRegionAction* pAct = static_cast<MetaClipRegionAction*>(pAction);
1597  if( pAct->IsClipping() )
1598  aClipStack.back() = OutputDevice::LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev->GetMapMode(), GetPrefMapMode() );
1599  else
1600  aClipStack.back() = tools::Rectangle();
1601  }
1602  break;
1603 
1605  {
1606  MetaISectRectClipRegionAction* pAct = static_cast<MetaISectRectClipRegionAction*>(pAction);
1607  tools::Rectangle aRect( OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ) );
1608  if( aClipStack.back().IsEmpty() )
1609  aClipStack.back() = aRect;
1610  else
1611  aClipStack.back().Intersection( aRect );
1612  }
1613  break;
1614 
1616  {
1617  MetaISectRegionClipRegionAction* pAct = static_cast<MetaISectRegionClipRegionAction*>(pAction);
1618  tools::Rectangle aRect( OutputDevice::LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ) );
1619  if( aClipStack.back().IsEmpty() )
1620  aClipStack.back() = aRect;
1621  else
1622  aClipStack.back().Intersection( aRect );
1623  }
1624  break;
1625 
1626  case MetaActionType::BMP:
1627  {
1628  MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
1629  tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1630  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1631  }
1632  break;
1633 
1634  case MetaActionType::BMPEX:
1635  {
1636  MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
1637  tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmapEx().GetSizePixel() ) );
1638  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1639  }
1640  break;
1641 
1642  case MetaActionType::MASK:
1643  {
1644  MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pAction);
1645  tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
1646  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1647  }
1648  break;
1649 
1651  {
1652  MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
1653  tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1654  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1655  }
1656  break;
1657 
1659  {
1660  MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
1661  tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
1662  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1663  }
1664  break;
1665 
1667  {
1668  MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction);
1669  tools::Rectangle aRect( pAct->GetRect() );
1670  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1671  }
1672  break;
1673 
1675  {
1676  MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pAction);
1677  tools::Rectangle aRect( pAct->GetRect() );
1678  ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
1679  }
1680  break;
1681 
1683  {
1684  MetaMoveClipRegionAction* pAct = static_cast<MetaMoveClipRegionAction*>(pAction);
1685  if( ! aClipStack.back().IsEmpty() )
1686  {
1687  Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() );
1688  aDelta = OutputDevice::LogicToLogic( aDelta, aMapVDev->GetMapMode(), GetPrefMapMode() );
1689  aClipStack.back().Move( aDelta.Width(), aDelta.Width() );
1690  }
1691  }
1692  break;
1693 
1694  default:
1695  {
1696  pAction->Execute( aMapVDev.get() );
1697 
1698  if( nActionType == MetaActionType::PUSH )
1699  {
1700  MetaPushAction* pAct = static_cast<MetaPushAction*>(pAction);
1701  aPushFlagStack.push_back( pAct->GetFlags() );
1702  if( aPushFlagStack.back() & PushFlags::CLIPREGION )
1703  {
1704  tools::Rectangle aRect( aClipStack.back() );
1705  aClipStack.push_back( aRect );
1706  }
1707  }
1708  else if( nActionType == MetaActionType::POP )
1709  {
1710  // sanity check
1711  if( ! aPushFlagStack.empty() )
1712  {
1713  if( aPushFlagStack.back() & PushFlags::CLIPREGION )
1714  {
1715  if( aClipStack.size() > 1 )
1716  aClipStack.pop_back();
1717  }
1718  aPushFlagStack.pop_back();
1719  }
1720  }
1721  }
1722  break;
1723  }
1724  }
1725  return aBound;
1726 }
1727 
1728 Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam )
1729 {
1730  return Color( rColor.GetTransparency(),
1731  static_cast<const ImplColAdjustParam*>(pColParam)->pMapR[ rColor.GetRed() ],
1732  static_cast<const ImplColAdjustParam*>(pColParam)->pMapG[ rColor.GetGreen() ],
1733  static_cast<const ImplColAdjustParam*>(pColParam)->pMapB[ rColor.GetBlue() ] );
1734 
1735 }
1736 
1737 BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1738 {
1739  const ImplBmpAdjustParam* p = static_cast<const ImplBmpAdjustParam*>(pBmpParam);
1740  BitmapEx aRet( rBmpEx );
1741 
1742  aRet.Adjust( p->nLuminancePercent, p->nContrastPercent,
1743  p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent,
1744  p->fGamma, p->bInvert );
1745 
1746  return aRet;
1747 }
1748 
1749 Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam )
1750 {
1751  sal_uInt8 cLum = rColor.GetLuminance();
1752 
1753  if( MtfConversion::N1BitThreshold == static_cast<const ImplColConvertParam*>(pColParam)->eConversion )
1754  cLum = ( cLum < 128 ) ? 0 : 255;
1755 
1756  return Color( rColor.GetTransparency(), cLum, cLum, cLum );
1757 }
1758 
1759 BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1760 {
1761  BitmapEx aRet( rBmpEx );
1762 
1763  aRet.Convert( static_cast<const ImplBmpConvertParam*>(pBmpParam)->eConversion );
1764 
1765  return aRet;
1766 }
1767 
1768 Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam )
1769 {
1770  return static_cast<const ImplColMonoParam*>(pColParam)->aColor;
1771 }
1772 
1773 BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1774 {
1775  BitmapPalette aPal( 3 );
1776 
1777  aPal[ 0 ] = COL_BLACK;
1778  aPal[ 1 ] = COL_WHITE;
1779  aPal[ 2 ] = static_cast<const ImplBmpMonoParam*>(pBmpParam)->aColor;
1780 
1781  Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal );
1782  aBmp.Erase( static_cast<const ImplBmpMonoParam*>(pBmpParam)->aColor );
1783 
1784  if( rBmpEx.IsAlpha() )
1785  return BitmapEx( aBmp, rBmpEx.GetAlpha() );
1786  else if( rBmpEx.IsTransparent() )
1787  return BitmapEx( aBmp, rBmpEx.GetMask() );
1788  else
1789  return BitmapEx( aBmp );
1790 }
1791 
1792 Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam )
1793 {
1794  const sal_uLong nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue();
1795 
1796  for( sal_uLong i = 0; i < static_cast<const ImplColReplaceParam*>(pColParam)->nCount; i++ )
1797  {
1798  if( ( static_cast<const ImplColReplaceParam*>(pColParam)->pMinR[ i ] <= nR ) &&
1799  ( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxR[ i ] >= nR ) &&
1800  ( static_cast<const ImplColReplaceParam*>(pColParam)->pMinG[ i ] <= nG ) &&
1801  ( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxG[ i ] >= nG ) &&
1802  ( static_cast<const ImplColReplaceParam*>(pColParam)->pMinB[ i ] <= nB ) &&
1803  ( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxB[ i ] >= nB ) )
1804  {
1805  return static_cast<const ImplColReplaceParam*>(pColParam)->pDstCols[ i ];
1806  }
1807  }
1808 
1809  return rColor;
1810 }
1811 
1812 BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
1813 {
1814  const ImplBmpReplaceParam* p = static_cast<const ImplBmpReplaceParam*>(pBmpParam);
1815  BitmapEx aRet( rBmpEx );
1816 
1817  aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount );
1818 
1819  return aRet;
1820 }
1821 
1822 void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam,
1823  BmpExchangeFnc pFncBmp, const void* pBmpParam )
1824 {
1825  GDIMetaFile aMtf;
1826 
1827  aMtf.m_aPrefSize = m_aPrefSize;
1829  aMtf.m_bUseCanvas = m_bUseCanvas;
1830 
1831  for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() )
1832  {
1833  const MetaActionType nType = pAction->GetType();
1834 
1835  switch( nType )
1836  {
1837  case MetaActionType::PIXEL:
1838  {
1839  MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
1840  aMtf.push_back( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ) );
1841  }
1842  break;
1843 
1845  {
1846  MetaLineColorAction* pAct = static_cast<MetaLineColorAction*>(pAction);
1847 
1848  if( pAct->IsSetting() )
1849  pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
1850 
1851  aMtf.push_back( pAct );
1852  }
1853  break;
1854 
1856  {
1857  MetaFillColorAction* pAct = static_cast<MetaFillColorAction*>(pAction);
1858 
1859  if( pAct->IsSetting() )
1860  pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
1861 
1862  aMtf.push_back( pAct );
1863  }
1864  break;
1865 
1867  {
1868  MetaTextColorAction* pAct = static_cast<MetaTextColorAction*>(pAction);
1869  aMtf.push_back( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ) );
1870  }
1871  break;
1872 
1874  {
1875  MetaTextFillColorAction* pAct = static_cast<MetaTextFillColorAction*>(pAction);
1876 
1877  if( pAct->IsSetting() )
1878  pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
1879 
1880  aMtf.push_back( pAct );
1881  }
1882  break;
1883 
1885  {
1886  MetaTextLineColorAction* pAct = static_cast<MetaTextLineColorAction*>(pAction);
1887 
1888  if( pAct->IsSetting() )
1889  pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
1890 
1891  aMtf.push_back( pAct );
1892  }
1893  break;
1894 
1896  {
1897  MetaOverlineColorAction* pAct = static_cast<MetaOverlineColorAction*>(pAction);
1898 
1899  if( pAct->IsSetting() )
1900  pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
1901 
1902  aMtf.push_back( pAct );
1903  }
1904  break;
1905 
1906  case MetaActionType::FONT:
1907  {
1908  MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction);
1909  vcl::Font aFont( pAct->GetFont() );
1910 
1911  aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) );
1912  aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) );
1913  aMtf.push_back( new MetaFontAction( aFont ) );
1914  }
1915  break;
1916 
1918  {
1919  MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction);
1920  Wallpaper aWall( pAct->GetWallpaper() );
1921  const tools::Rectangle& rRect = pAct->GetRect();
1922 
1923  aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) );
1924 
1925  if( aWall.IsBitmap() )
1926  aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) );
1927 
1928  if( aWall.IsGradient() )
1929  {
1930  Gradient aGradient( aWall.GetGradient() );
1931 
1932  aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
1933  aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
1934  aWall.SetGradient( aGradient );
1935  }
1936 
1937  aMtf.push_back( new MetaWallpaperAction( rRect, aWall ) );
1938  }
1939  break;
1940 
1941  case MetaActionType::BMP:
1942  case MetaActionType::BMPEX:
1943  case MetaActionType::MASK:
1944  {
1945  OSL_FAIL( "Don't use bitmap actions of this type in metafiles!" );
1946  }
1947  break;
1948 
1950  {
1951  MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
1952  aMtf.push_back( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(),
1953  pFncBmp( BitmapEx(pAct->GetBitmap()), pBmpParam ).GetBitmap() ) );
1954  }
1955  break;
1956 
1958  {
1959  MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
1960  aMtf.push_back( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
1961  pAct->GetSrcPoint(), pAct->GetSrcSize(),
1962  pFncBmp( BitmapEx(pAct->GetBitmap()), pBmpParam ).GetBitmap() )
1963  );
1964  }
1965  break;
1966 
1968  {
1969  MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
1970  aMtf.push_back( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(),
1971  pFncBmp( pAct->GetBitmapEx(), pBmpParam ) )
1972  );
1973  }
1974  break;
1975 
1977  {
1978  MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
1979  aMtf.push_back( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
1980  pAct->GetSrcPoint(), pAct->GetSrcSize(),
1981  pFncBmp( pAct->GetBitmapEx(), pBmpParam ) )
1982  );
1983  }
1984  break;
1985 
1987  {
1988  MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pAction);
1989  aMtf.push_back( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(),
1990  pAct->GetBitmap(),
1991  pFncCol( pAct->GetColor(), pColParam ) )
1992  );
1993  }
1994  break;
1995 
1997  {
1998  MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
1999  aMtf.push_back( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
2000  pAct->GetSrcPoint(), pAct->GetSrcSize(),
2001  pAct->GetBitmap(),
2002  pFncCol( pAct->GetColor(), pColParam ) )
2003  );
2004  }
2005  break;
2006 
2008  {
2009  MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction);
2010  Gradient aGradient( pAct->GetGradient() );
2011 
2012  aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2013  aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2014  aMtf.push_back( new MetaGradientAction( pAct->GetRect(), aGradient ) );
2015  }
2016  break;
2017 
2019  {
2020  MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
2021  Gradient aGradient( pAct->GetGradient() );
2022 
2023  aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
2024  aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
2025  aMtf.push_back( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ) );
2026  }
2027  break;
2028 
2029  case MetaActionType::HATCH:
2030  {
2031  MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction);
2032  Hatch aHatch( pAct->GetHatch() );
2033 
2034  aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) );
2035  aMtf.push_back( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ) );
2036  }
2037  break;
2038 
2040  {
2041  MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction);
2042  GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
2043 
2044  aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2045  aMtf.push_back( new MetaFloatTransparentAction( aTransMtf,
2046  pAct->GetPoint(), pAct->GetSize(),
2047  pAct->GetGradient() )
2048  );
2049  }
2050  break;
2051 
2052  case MetaActionType::EPS:
2053  {
2054  MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
2055  GDIMetaFile aSubst( pAct->GetSubstitute() );
2056 
2057  aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
2058  aMtf.push_back( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(),
2059  pAct->GetLink(), aSubst )
2060  );
2061  }
2062  break;
2063 
2064  default:
2065  {
2066  aMtf.push_back( pAction );
2067  }
2068  break;
2069  }
2070  }
2071 
2072  *this = aMtf;
2073 }
2074 
2075 void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent,
2076  short nChannelRPercent, short nChannelGPercent,
2077  short nChannelBPercent, double fGamma, bool bInvert, bool msoBrightness )
2078 {
2079  // nothing to do? => return quickly
2080  if( !(nLuminancePercent || nContrastPercent ||
2081  nChannelRPercent || nChannelGPercent || nChannelBPercent ||
2082  ( fGamma != 1.0 ) || bInvert) )
2083  return;
2084 
2085  double fM, fROff, fGOff, fBOff, fOff;
2086  ImplColAdjustParam aColParam;
2087  ImplBmpAdjustParam aBmpParam;
2088 
2089  aColParam.pMapR.reset(new sal_uInt8[ 256 ]);
2090  aColParam.pMapG.reset(new sal_uInt8[ 256 ]);
2091  aColParam.pMapB.reset(new sal_uInt8[ 256 ]);
2092 
2093  // calculate slope
2094  if( nContrastPercent >= 0 )
2095  fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0, 100 ) );
2096  else
2097  fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100, 0 ) ) / 128.0;
2098 
2099  if(!msoBrightness)
2100  // total offset = luminance offset + contrast offset
2101  fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55 + 128.0 - fM * 128.0;
2102  else
2103  fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55;
2104 
2105  // channel offset = channel offset + total offset
2106  fROff = nChannelRPercent * 2.55 + fOff;
2107  fGOff = nChannelGPercent * 2.55 + fOff;
2108  fBOff = nChannelBPercent * 2.55 + fOff;
2109 
2110  // calculate gamma value
2111  fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2112  const bool bGamma = ( fGamma != 1.0 );
2113 
2114  // create mapping table
2115  for( long nX = 0; nX < 256; nX++ )
2116  {
2117  if(!msoBrightness)
2118  {
2119  aColParam.pMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fROff ), 0, 255 ));
2120  aColParam.pMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fGOff ), 0, 255 ));
2121  aColParam.pMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fBOff ), 0, 255 ));
2122  }
2123  else
2124  {
2125  aColParam.pMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0, 255 ));
2126  aColParam.pMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0, 255 ));
2127  aColParam.pMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0, 255 ));
2128  }
2129  if( bGamma )
2130  {
2131  aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma );
2132  aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma );
2133  aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma );
2134  }
2135 
2136  if( bInvert )
2137  {
2138  aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ];
2139  aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ];
2140  aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ];
2141  }
2142  }
2143 
2144  aBmpParam.nLuminancePercent = nLuminancePercent;
2145  aBmpParam.nContrastPercent = nContrastPercent;
2146  aBmpParam.nChannelRPercent = nChannelRPercent;
2147  aBmpParam.nChannelGPercent = nChannelGPercent;
2148  aBmpParam.nChannelBPercent = nChannelBPercent;
2149  aBmpParam.fGamma = fGamma;
2150  aBmpParam.bInvert = bInvert;
2151 
2152  // do color adjustment
2153  ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam );
2154 }
2155 
2157 {
2158  ImplColConvertParam aColParam;
2159  ImplBmpConvertParam aBmpParam;
2160 
2161  aColParam.eConversion = eConversion;
2162  aBmpParam.eConversion = ( MtfConversion::N1BitThreshold == eConversion ) ? BmpConversion::N1BitThreshold : BmpConversion::N8BitGreys;
2163 
2164  ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam );
2165 }
2166 
2167 void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount )
2168 {
2169  ImplColReplaceParam aColParam;
2170  ImplBmpReplaceParam aBmpParam;
2171 
2172  aColParam.pMinR.reset(new sal_uLong[ nColorCount ]);
2173  aColParam.pMaxR.reset(new sal_uLong[ nColorCount ]);
2174  aColParam.pMinG.reset(new sal_uLong[ nColorCount ]);
2175  aColParam.pMaxG.reset(new sal_uLong[ nColorCount ]);
2176  aColParam.pMinB.reset(new sal_uLong[ nColorCount ]);
2177  aColParam.pMaxB.reset(new sal_uLong[ nColorCount ]);
2178 
2179  for( sal_uLong i = 0; i < nColorCount; i++ )
2180  {
2181  long nVal;
2182 
2183  nVal = pSearchColors[ i ].GetRed();
2184  aColParam.pMinR[ i ] = static_cast<sal_uLong>(std::max( nVal, 0L ));
2185  aColParam.pMaxR[ i ] = static_cast<sal_uLong>(std::min( nVal, 255L ));
2186 
2187  nVal = pSearchColors[ i ].GetGreen();
2188  aColParam.pMinG[ i ] = static_cast<sal_uLong>(std::max( nVal, 0L ));
2189  aColParam.pMaxG[ i ] = static_cast<sal_uLong>(std::min( nVal, 255L ));
2190 
2191  nVal = pSearchColors[ i ].GetBlue();
2192  aColParam.pMinB[ i ] = static_cast<sal_uLong>(std::max( nVal, 0L ));
2193  aColParam.pMaxB[ i ] = static_cast<sal_uLong>(std::min( nVal, 255L ));
2194  }
2195 
2196  aColParam.pDstCols = pReplaceColors;
2197  aColParam.nCount = nColorCount;
2198 
2199  aBmpParam.pSrcCols = pSearchColors;
2200  aBmpParam.pDstCols = pReplaceColors;
2201  aBmpParam.nCount = nColorCount;
2202 
2203  ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam );
2204 };
2205 
2207 {
2208  GDIMetaFile aRet( *this );
2209 
2210  ImplColMonoParam aColParam;
2211  ImplBmpMonoParam aBmpParam;
2212 
2213  aColParam.aColor = rColor;
2214  aBmpParam.aColor = rColor;
2215 
2216  aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam );
2217 
2218  return aRet;
2219 }
2220 
2222 {
2223  SvMemoryStream aMemStm( 65535, 65535 );
2224  ImplMetaWriteData aWriteData;
2225  SVBT16 aBT16;
2226  SVBT32 aBT32;
2228  BitmapChecksum nCrc = 0;
2229 
2230  aWriteData.meActualCharSet = aMemStm.GetStreamCharSet();
2231  for( size_t i = 0, nObjCount = GetActionSize(); i < nObjCount; i++ )
2232  {
2233  MetaAction* pAction = GetAction( i );
2234 
2235  switch( pAction->GetType() )
2236  {
2237  case MetaActionType::BMP:
2238  {
2239  MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
2240 
2241  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2242  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2243 
2244  BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
2245  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2246 
2247  Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2248  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2249 
2250  Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2251  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2252  }
2253  break;
2254 
2256  {
2257  MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
2258 
2259  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2260  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2261 
2262  BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
2263  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2264 
2265  Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2266  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2267 
2268  Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2269  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2270 
2271  Int32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2272  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2273 
2274  Int32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2275  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2276  }
2277  break;
2278 
2280  {
2281  MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
2282 
2283  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2284  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2285 
2286  BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
2287  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2288 
2289  Int32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2290  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2291 
2292  Int32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2293  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2294 
2295  Int32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2296  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2297 
2298  Int32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2299  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2300 
2301  Int32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2302  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2303 
2304  Int32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2305  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2306 
2307  Int32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2308  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2309 
2310  Int32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2311  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2312  }
2313  break;
2314 
2315  case MetaActionType::BMPEX:
2316  {
2317  MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
2318 
2319  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2320  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2321 
2322  BCToBCOA( pAct->GetBitmapEx().GetChecksum(), aBCOA );
2323  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2324 
2325  Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2326  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2327 
2328  Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2329  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2330  }
2331  break;
2332 
2334  {
2335  MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
2336 
2337  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2338  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2339 
2340  BCToBCOA( pAct->GetBitmapEx().GetChecksum(), aBCOA );
2341  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2342 
2343  Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2344  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2345 
2346  Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2347  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2348 
2349  Int32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2350  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2351 
2352  Int32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2353  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2354  }
2355  break;
2356 
2358  {
2359  MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
2360 
2361  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2362  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2363 
2364  BCToBCOA( pAct->GetBitmapEx().GetChecksum(), aBCOA );
2365  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2366 
2367  Int32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2368  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2369 
2370  Int32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2371  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2372 
2373  Int32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2374  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2375 
2376  Int32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2377  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2378 
2379  Int32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2380  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2381 
2382  Int32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2383  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2384 
2385  Int32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2386  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2387 
2388  Int32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2389  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2390  }
2391  break;
2392 
2393  case MetaActionType::MASK:
2394  {
2395  MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pAction);
2396 
2397  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2398  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2399 
2400  BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
2401  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2402 
2403  UInt32ToSVBT32( sal_uInt32(pAct->GetColor()), aBT32 );
2404  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2405 
2406  Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2407  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2408 
2409  Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2410  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2411  }
2412  break;
2413 
2415  {
2416  MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pAction);
2417 
2418  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2419  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2420 
2421  BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
2422  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2423 
2424  UInt32ToSVBT32( sal_uInt32(pAct->GetColor()), aBT32 );
2425  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2426 
2427  Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
2428  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2429 
2430  Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
2431  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2432 
2433  Int32ToSVBT32( pAct->GetSize().Width(), aBT32 );
2434  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2435 
2436  Int32ToSVBT32( pAct->GetSize().Height(), aBT32 );
2437  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2438  }
2439  break;
2440 
2442  {
2443  MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
2444 
2445  ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
2446  nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
2447 
2448  BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
2449  nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
2450 
2451  UInt32ToSVBT32( sal_uInt32(pAct->GetColor()), aBT32 );
2452  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2453 
2454  Int32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
2455  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2456 
2457  Int32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
2458  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2459 
2460  Int32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
2461  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2462 
2463  Int32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
2464  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2465 
2466  Int32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
2467  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2468 
2469  Int32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
2470  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2471 
2472  Int32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
2473  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2474 
2475  Int32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
2476  nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
2477  }
2478  break;
2479 
2480  case MetaActionType::EPS :
2481  {
2482  MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
2483  nCrc = vcl_get_checksum( nCrc, pAct->GetLink().GetData(), pAct->GetLink().GetDataSize() );
2484  }
2485  break;
2486 
2488  {
2489  MetaClipRegionAction& rAct = static_cast<MetaClipRegionAction&>(*pAction);
2490  const vcl::Region& rRegion = rAct.GetRegion();
2491 
2492  if(rRegion.HasPolyPolygonOrB2DPolyPolygon())
2493  {
2494  // It has shown that this is a possible bottleneck for checksum calculation.
2495  // In worst case a very expensive RegionHandle representation gets created.
2496  // In this case it's cheaper to use the PolyPolygon
2497  const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetAsB2DPolyPolygon());
2498  SVBT64 aSVBT64;
2499 
2500  for(auto const& rPolygon : aPolyPolygon)
2501  {
2502  const sal_uInt32 nPointCount(rPolygon.count());
2503  const bool bControl(rPolygon.areControlPointsUsed());
2504 
2505  for(sal_uInt32 b(0); b < nPointCount; b++)
2506  {
2507  const basegfx::B2DPoint aPoint(rPolygon.getB2DPoint(b));
2508 
2509  DoubleToSVBT64(aPoint.getX(), aSVBT64);
2510  nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
2511  DoubleToSVBT64(aPoint.getY(), aSVBT64);
2512  nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
2513 
2514  if(bControl)
2515  {
2516  if(rPolygon.isPrevControlPointUsed(b))
2517  {
2518  const basegfx::B2DPoint aCtrl(rPolygon.getPrevControlPoint(b));
2519 
2520  DoubleToSVBT64(aCtrl.getX(), aSVBT64);
2521  nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
2522  DoubleToSVBT64(aCtrl.getY(), aSVBT64);
2523  nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
2524  }
2525 
2526  if(rPolygon.isNextControlPointUsed(b))
2527  {
2528  const basegfx::B2DPoint aCtrl(rPolygon.getNextControlPoint(b));
2529 
2530  DoubleToSVBT64(aCtrl.getX(), aSVBT64);
2531  nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
2532  DoubleToSVBT64(aCtrl.getY(), aSVBT64);
2533  nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
2534  }
2535  }
2536  }
2537  }
2538 
2539  sal_uInt8 tmp = static_cast<sal_uInt8>(rAct.IsClipping());
2540  nCrc = vcl_get_checksum(nCrc, &tmp, 1);
2541  }
2542  else
2543  {
2544  pAction->Write( aMemStm, &aWriteData );
2545  nCrc = vcl_get_checksum( nCrc, aMemStm.GetData(), aMemStm.Tell() );
2546  aMemStm.Seek( 0 );
2547  }
2548  }
2549  break;
2550 
2551  default:
2552  {
2553  pAction->Write( aMemStm, &aWriteData );
2554  nCrc = vcl_get_checksum( nCrc, aMemStm.GetData(), aMemStm.Tell() );
2555  aMemStm.Seek( 0 );
2556  }
2557  break;
2558  }
2559  }
2560 
2561  return nCrc;
2562 }
2563 
2565 {
2566  sal_uLong nSizeBytes = 0;
2567 
2568  for( size_t i = 0, nObjCount = GetActionSize(); i < nObjCount; ++i )
2569  {
2570  MetaAction* pAction = GetAction( i );
2571 
2572  // default action size is set to 32 (=> not the exact value)
2573  nSizeBytes += 32;
2574 
2575  // add sizes for large action content
2576  switch( pAction->GetType() )
2577  {
2578  case MetaActionType::BMP: nSizeBytes += static_cast<MetaBmpAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
2579  case MetaActionType::BMPSCALE: nSizeBytes += static_cast<MetaBmpScaleAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
2580  case MetaActionType::BMPSCALEPART: nSizeBytes += static_cast<MetaBmpScalePartAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
2581 
2582  case MetaActionType::BMPEX: nSizeBytes += static_cast<MetaBmpExAction*>( pAction )->GetBitmapEx().GetSizeBytes(); break;
2583  case MetaActionType::BMPEXSCALE: nSizeBytes += static_cast<MetaBmpExScaleAction*>( pAction )->GetBitmapEx().GetSizeBytes(); break;
2584  case MetaActionType::BMPEXSCALEPART: nSizeBytes += static_cast<MetaBmpExScalePartAction*>( pAction )->GetBitmapEx().GetSizeBytes(); break;
2585 
2586  case MetaActionType::MASK: nSizeBytes += static_cast<MetaMaskAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
2587  case MetaActionType::MASKSCALE: nSizeBytes += static_cast<MetaMaskScaleAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
2588  case MetaActionType::MASKSCALEPART: nSizeBytes += static_cast<MetaMaskScalePartAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
2589 
2590  case MetaActionType::POLYLINE: nSizeBytes += static_cast<MetaPolyLineAction*>( pAction )->GetPolygon().GetSize() * sizeof( Point ); break;
2591  case MetaActionType::POLYGON: nSizeBytes += static_cast<MetaPolygonAction*>( pAction )->GetPolygon().GetSize() * sizeof( Point ); break;
2593  {
2594  const tools::PolyPolygon& rPolyPoly = static_cast<MetaPolyPolygonAction*>( pAction )->GetPolyPolygon();
2595 
2596  for( sal_uInt16 n = 0; n < rPolyPoly.Count(); ++n )
2597  nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) );
2598  }
2599  break;
2600 
2601  case MetaActionType::TEXT: nSizeBytes += static_cast<MetaTextAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break;
2602  case MetaActionType::STRETCHTEXT: nSizeBytes += static_cast<MetaStretchTextAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break;
2603  case MetaActionType::TEXTRECT: nSizeBytes += static_cast<MetaTextRectAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break;
2605  {
2606  MetaTextArrayAction* pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction);
2607 
2608  nSizeBytes += ( pTextArrayAction->GetText().getLength() * sizeof( sal_Unicode ) );
2609 
2610  if( pTextArrayAction->GetDXArray() )
2611  nSizeBytes += ( pTextArrayAction->GetLen() << 2 );
2612  }
2613  break;
2614  default: break;
2615  }
2616  }
2617 
2618  return nSizeBytes;
2619 }
2620 
2621 namespace
2622 {
2623  class DepthGuard
2624  {
2625  private:
2627  rtl_TextEncoding m_eOrigCharSet;
2628  public:
2629  DepthGuard(ImplMetaReadData& rData, SvStream const & rIStm)
2630  : m_rData(rData)
2631  , m_eOrigCharSet(m_rData.meActualCharSet)
2632  {
2633  ++m_rData.mnParseDepth;
2634  m_rData.meActualCharSet = rIStm.GetStreamCharSet();
2635  }
2636  bool TooDeep() const { return m_rData.mnParseDepth > 1024; }
2637  ~DepthGuard()
2638  {
2639  --m_rData.mnParseDepth;
2640  m_rData.meActualCharSet = m_eOrigCharSet;
2641  }
2642  };
2643 }
2644 
2646 {
2647  if (rIStm.GetError())
2648  {
2649  SAL_WARN("vcl.gdi", "Stream error: " << rIStm.GetError());
2650  return rIStm;
2651  }
2652 
2653  sal_uLong nStmPos = rIStm.Tell();
2654  SvStreamEndian nOldFormat = rIStm.GetEndian();
2655 
2656  rIStm.SetEndian( SvStreamEndian::LITTLE );
2657 
2658  try
2659  {
2660  char aId[7];
2661  aId[0] = 0;
2662  aId[6] = 0;
2663  rIStm.ReadBytes( aId, 6 );
2664 
2665  if ( !strcmp( aId, "VCLMTF" ) )
2666  {
2667  // new format
2668  sal_uInt32 nStmCompressMode = 0;
2669  sal_uInt32 nCount = 0;
2670  std::unique_ptr<VersionCompat> pCompat(new VersionCompat( rIStm, StreamMode::READ ));
2671 
2672  rIStm.ReadUInt32( nStmCompressMode );
2673  ReadMapMode( rIStm, rGDIMetaFile.m_aPrefMapMode );
2674  TypeSerializer aSerializer(rIStm);
2675  aSerializer.readSize(rGDIMetaFile.m_aPrefSize);
2676  rIStm.ReadUInt32( nCount );
2677 
2678  pCompat.reset(); // destructor writes stuff into the header
2679 
2680  std::unique_ptr<ImplMetaReadData> xReadData;
2681  if (!pData)
2682  {
2683  xReadData.reset(new ImplMetaReadData);
2684  pData = xReadData.get();
2685  }
2686  DepthGuard aDepthGuard(*pData, rIStm);
2687 
2688  if (aDepthGuard.TooDeep())
2689  throw std::runtime_error("too much recursion");
2690 
2691  for( sal_uInt32 nAction = 0; ( nAction < nCount ) && !rIStm.eof(); nAction++ )
2692  {
2693  MetaAction* pAction = MetaAction::ReadMetaAction(rIStm, pData);
2694  if( pAction )
2695  {
2696  if (pAction->GetType() == MetaActionType::COMMENT)
2697  {
2698  MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction);
2699  if ( pCommentAct->GetComment() == "EMF_PLUS" )
2700  rGDIMetaFile.UseCanvas( true );
2701  }
2702  rGDIMetaFile.AddAction( pAction );
2703  }
2704  }
2705  }
2706  else
2707  {
2708  rIStm.Seek( nStmPos );
2709  SVMConverter( rIStm, rGDIMetaFile );
2710  }
2711  }
2712  catch (...)
2713  {
2714  SAL_WARN("vcl", "GDIMetaFile exception during load");
2716  };
2717 
2718  // check for errors
2719  if( rIStm.GetError() )
2720  {
2721  rGDIMetaFile.Clear();
2722  rIStm.Seek( nStmPos );
2723  }
2724 
2725  rIStm.SetEndian( nOldFormat );
2726  return rIStm;
2727 }
2728 
2729 SvStream& WriteGDIMetaFile( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile )
2730 {
2731  if( !rOStm.GetError() )
2732  {
2733  const_cast< GDIMetaFile& >( rGDIMetaFile ).Write( rOStm );
2734  }
2735  return rOStm;
2736 }
2737 
2739 {
2740  Clear();
2741  ReadGDIMetaFile( rIStm, *this );
2742 
2743  return rIStm;
2744 }
2745 
2747 {
2748  VersionCompat* pCompat;
2749  const SvStreamCompressFlags nStmCompressMode = rOStm.GetCompressMode();
2750  SvStreamEndian nOldFormat = rOStm.GetEndian();
2751 
2752  rOStm.SetEndian( SvStreamEndian::LITTLE );
2753  rOStm.WriteBytes( "VCLMTF", 6 );
2754 
2755  pCompat = new VersionCompat( rOStm, StreamMode::WRITE, 1 );
2756 
2757  rOStm.WriteUInt32( static_cast<sal_uInt32>(nStmCompressMode) );
2758  WriteMapMode( rOStm, m_aPrefMapMode );
2759  TypeSerializer aSerializer(rOStm);
2760  aSerializer.writeSize(m_aPrefSize);
2761  rOStm.WriteUInt32( GetActionSize() );
2762 
2763  delete pCompat;
2764 
2765  ImplMetaWriteData aWriteData;
2766 
2767  aWriteData.meActualCharSet = rOStm.GetStreamCharSet();
2768 
2769  MetaAction* pAct = FirstAction();
2770  while ( pAct )
2771  {
2772  pAct->Write( rOStm, &aWriteData );
2773  pAct = NextAction();
2774  }
2775 
2776  rOStm.SetEndian( nOldFormat );
2777 
2778  return rOStm;
2779 }
2780 
2781 bool GDIMetaFile::CreateThumbnail(BitmapEx& rBitmapEx, BmpConversion eColorConversion, BmpScaleFlag nScaleFlag) const
2782 {
2783  // initialization seems to be complicated but is used to avoid rounding errors
2785  const Point aNullPt;
2786  const Point aTLPix( aVDev->LogicToPixel( aNullPt, GetPrefMapMode() ) );
2787  const Point aBRPix( aVDev->LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) );
2788  Size aDrawSize( aVDev->LogicToPixel( GetPrefSize(), GetPrefMapMode() ) );
2789  Size aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
2790  sal_uInt32 nMaximumExtent = 256;
2791 
2792  if (!rBitmapEx.IsEmpty())
2793  rBitmapEx.SetEmpty();
2794 
2795  // determine size that has the same aspect ratio as image size and
2796  // fits into the rectangle determined by nMaximumExtent
2797  if ( aSizePix.Width() && aSizePix.Height()
2798  && ( sal::static_int_cast< unsigned long >(aSizePix.Width()) >
2799  nMaximumExtent ||
2800  sal::static_int_cast< unsigned long >(aSizePix.Height()) >
2801  nMaximumExtent ) )
2802  {
2803  const Size aOldSizePix( aSizePix );
2804  double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height();
2805 
2806  if ( fWH <= 1.0 )
2807  {
2808  aSizePix.setWidth( FRound( nMaximumExtent * fWH ) );
2809  aSizePix.setHeight( nMaximumExtent );
2810  }
2811  else
2812  {
2813  aSizePix.setWidth( nMaximumExtent );
2814  aSizePix.setHeight( FRound( nMaximumExtent / fWH ) );
2815  }
2816 
2817  aDrawSize.setWidth( FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() ) );
2818  aDrawSize.setHeight( FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() ) );
2819  }
2820 
2821  // draw image(s) into VDev and get resulting image
2822  // do it 4x larger to be able to scale it down & get beautiful antialias
2823  Size aAntialiasSize(aSizePix.Width() * 4, aSizePix.Height() * 4);
2824  if (aVDev->SetOutputSizePixel(aAntialiasSize))
2825  {
2826  // antialias: provide 4x larger size, and then scale down the result
2827  Size aAntialias(aDrawSize.Width() * 4, aDrawSize.Height() * 4);
2828 
2829  // draw metafile into VDev
2830  const_cast<GDIMetaFile *>(this)->WindStart();
2831  const_cast<GDIMetaFile *>(this)->Play(aVDev.get(), Point(), aAntialias);
2832 
2833  // get paint bitmap
2834  BitmapEx aBitmap( aVDev->GetBitmapEx( aNullPt, aVDev->GetOutputSizePixel() ) );
2835 
2836  // scale down the image to the desired size - use the input scaler for the scaling operation
2837  aBitmap.Scale(aDrawSize, nScaleFlag);
2838 
2839  // convert to desired bitmap color format
2840  Size aSize(aBitmap.GetSizePixel());
2841  if (aSize.Width() && aSize.Height())
2842  aBitmap.Convert(eColorConversion);
2843 
2844  rBitmapEx = aBitmap;
2845  }
2846 
2847  return !rBitmapEx.IsEmpty();
2848 }
2849 
2850 void GDIMetaFile::UseCanvas( bool _bUseCanvas )
2851 {
2852  m_bUseCanvas = _bUseCanvas;
2853 }
2854 
2855 void GDIMetaFile::dumpAsXml(const char* pFileName) const
2856 {
2857  SvFileStream aStream(pFileName ? OUString::fromUtf8(pFileName) : OUString("file:///tmp/metafile.xml"),
2858  StreamMode::STD_READWRITE | StreamMode::TRUNC);
2859  assert(aStream.good());
2860  MetafileXmlDump aDumper;
2861  aDumper.dump(*this, aStream);
2862 }
2863 
2864 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
static SAL_DLLPRIVATE BitmapEx ImplBmpAdjustFnc(const BitmapEx &rBmpEx, const void *pBmpParam)
Definition: gdimtf.cxx:1737
const Fraction & GetScaleX() const
Definition: mapmod.cxx:172
long Width() const
const Gradient & GetGradient() const
Definition: metaact.hxx:1569
void Mirror(BmpMirrorFlags nMirrorFlags)
Definition: gdimtf.cxx:598
virtual void Execute(OutputDevice *pOut)
Definition: metaact.cxx:168
const LineInfo & GetLineInfo() const
Definition: metaact.hxx:187
void dump(const GDIMetaFile &rMetaFile, SvStream &rStream)
The actual result that will be used for testing.
Definition: mtfxmldump.cxx:517
void SetDigitLanguage(LanguageType)
void SetPixelOffset(const Size &rOffset)
Set an offset in pixel.
Definition: map.cxx:1912
GDIMetaFile * m_pPrev
Definition: gdimtf.hxx:65
Bitmap GetMask() const
Definition: bitmapex.cxx:259
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
const Size & GetDestSize() const
Definition: metaact.hxx:957
Definition: hatch.hxx:44
VclPtr< OutputDevice > m_pOutDev
Definition: gdimtf.hxx:67
const Bitmap & GetBitmap() const
Definition: metaact.hxx:915
sal_Int32 GetLen() const
Definition: metaact.hxx:497
MetaAction * GetCurAction() const
Definition: gdimtf.hxx:173
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
const Point & GetPoint() const
Definition: metaact.hxx:705
sal_uInt8 GetRed() const
rtl_TextEncoding meActualCharSet
Definition: metaact.hxx:47
static MetaAction * ReadMetaAction(SvStream &rIStm, ImplMetaReadData *pData)
Definition: metaact.cxx:195
void ReplaceColors(const Color *pSearchColors, const Color *rReplaceColors, sal_uLong nColorCount)
Definition: gdimtf.cxx:2167
sal_uInt8 SVBT16[2]
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
long FRound(double fVal)
SAL_DLLPRIVATE bool ImplPlayWithRenderer(OutputDevice *pOut, const Point &rPos, Size rLogicDestSize)
Definition: gdimtf.cxx:390
const GDIMetaFile & GetGDIMetaFile() const
Definition: metaact.hxx:1566
void Replace(const Color &rSearchColor, const Color &rReplaceColor)
Replace all pixel having the search color with the specified color.
Definition: bitmapex.cxx:597
bool Adjust(short nLuminancePercent, short nContrastPercent, short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, double fGamma=1.0, bool bInvert=false, bool msoBrightness=false)
Change various global color characteristics.
Definition: bitmapex.cxx:609
SvStream & WriteMapMode(SvStream &rOStm, const MapMode &rMapMode)
Definition: mapmod.cxx:152
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1676
GDIMetaFile & operator=(const GDIMetaFile &rMtf)
Definition: gdimtf.cxx:214
long Height() const
void DrawBitmapEx(const Point &rDestPt, const BitmapEx &rBitmapEx)
This is an overloaded member function, provided for convenience. It differs from the above function o...
SvStream & WriteSvtGraphicStroke(SvStream &rOStm, const SvtGraphicStroke &rClass)
SvStream & Read(SvStream &rIStm)
Definition: gdimtf.cxx:2738
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:178
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
Scale the bitmap.
Definition: bitmapex.cxx:371
sal_uInt8 GetTransparency() const
sal_uIntPtr sal_uLong
MtfConversion
Definition: gdimtf.hxx:44
void writeSize(const Size &rSize)
void dumpAsXml(const char *pFileName=nullptr) const
Dumps the meta actions as XML in metafile.xml.
Definition: gdimtf.cxx:2855
MetaAction * NextAction()
Definition: gdimtf.cxx:198
#define F_PI1800
sal_uInt8 GetLuminance() const
const Point & GetPoint() const
Definition: metaact.hxx:1604
virtual bool IsTransparent() const
#i10613# Extracted from Printer::GetPreparedMetaFile.
Definition: metaact.hxx:94
sal_Int64 n
Encapsulates geometry and associated attributes of a graphical 'pen stroke'.
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:176
const Point & GetPoint() const
Definition: metaact.hxx:1567
void Clear()
Definition: gdimtf.cxx:273
static SAL_DLLPRIVATE Color ImplColMonoFnc(const Color &rColor, const void *pColParam)
Definition: gdimtf.cxx:1768
sal_uInt64 Seek(sal_uInt64 nPos)
const Size & GetSize() const
Definition: metaact.hxx:706
const MapMode & GetMapMode() const
Definition: outdev.hxx:1679
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:1531
OUString aId
void SetLayoutMode(ComplexTextLayoutFlags nTextLayoutMode)
BitmapChecksum vcl_get_checksum(BitmapChecksum Checksum, const void *Data, sal_uInt32 DatLen)
Definition: checksum.hxx:72
const Point & GetEndPoint() const
Definition: metaact.hxx:186
GDIMetaFile * GetConnectMetaFile() const
Definition: outdev.hxx:415
const OUString & GetText() const
Definition: metaact.hxx:569
bool IsRecord() const
Definition: gdimtf.hxx:144
Size GetSizePixel() const
SvStream & ReadSvtGraphicStroke(SvStream &rIStm, SvtGraphicStroke &rClass)
static SAL_DLLPRIVATE void ImplAddGradientEx(GDIMetaFile &rMtf, const OutputDevice &rMapDev, const tools::PolyPolygon &rPolyPoly, const Gradient &rGrad)
Definition: gdimtf.cxx:800
void SetOrientation(short nLineOrientation)
Definition: font/font.cxx:192
SvStreamCompressFlags GetCompressMode() const
static SAL_DLLPRIVATE BitmapEx ImplBmpReplaceFnc(const BitmapEx &rBmpEx, const void *pBmpParam)
Definition: gdimtf.cxx:1812
void Clip(const tools::Rectangle &)
Definition: gdimtf.cxx:737
const Point & GetPoint() const
Definition: metaact.hxx:917
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: bitmapex.cxx:455
BitmapChecksum GetChecksum() const
Definition: bitmapex.cxx:293
SvStream & ReadSvtGraphicFill(SvStream &rIStm, SvtGraphicFill &rClass)
sal_uInt8 SVBT32[4]
void Move(long nHorzMoveDelta, long nVertMoveDelta)
const sal_uInt8 * GetData() const
Definition: metaact.hxx:1666
bool IsEmpty() const
HashMap_OWString_Interface aMap
sal_uInt16 sal_Unicode
constexpr::Color COL_TRANSPARENT(0xFF, 0xFF, 0xFF, 0xFF)
void Rotate(long nAngle10)
Definition: gdimtf.cxx:822
bool IsAlpha() const
Definition: bitmapex.cxx:227
static SAL_DLLPRIVATE tools::Polygon ImplGetRotatedPolygon(const tools::Polygon &rPoly, const Point &rRotatePt, const Size &rOffset, double fSin, double fCos)
Definition: gdimtf.cxx:778
ErrCode GetError() const
const Point & GetPoint() const
Definition: metaact.hxx:807
void Record(OutputDevice *pOutDev)
Definition: gdimtf.cxx:314
const Sequence< Sequence< double > > & m_rData
void push_back(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:593
bool eof() const
const OUString & GetText() const
Definition: metaact.hxx:495
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
const Fraction & GetScaleY() const
Definition: mapmod.cxx:174
const Color & GetColor() const
Definition: metaact.hxx:881
SvStream & WriteGDIMetaFile(SvStream &rOStm, const GDIMetaFile &rGDIMetaFile)
Definition: gdimtf.cxx:2729
geometry::IntegerSize2D integerSize2DFromSize(const Size &rSize)
#define X
Definition: field.cxx:1087
const Bitmap & GetBitmap() const
Definition: metaact.hxx:672
void Rotate(const Point &rCenter, double fSin, double fCos)
void Adjust(short nLuminancePercent, short nContrastPercent, short nChannelRPercent=0, short nChannelGPercent=0, short nChannelBPercent=0, double fGamma=1.0, bool bInvert=false, bool msoBrightness=false)
Definition: gdimtf.cxx:2075
int nCount
long GetWidth() const
Definition: metaact.hxx:640
bool CreateThumbnail(BitmapEx &rBitmapEx, BmpConversion nColorConversion=BmpConversion::N24Bit, BmpScaleFlag nScaleFlag=BmpScaleFlag::BestQuality) const
Creates an antialiased thumbnail.
Definition: gdimtf.cxx:2781
void SetStartColor(const Color &rColor)
const Gradient & GetGradient() const
Definition: metaact.hxx:989
SvStream & WriteUInt32(sal_uInt32 nUInt32)
const Color & GetColor() const
Definition: metaact.hxx:1221
MetaActionType
void Play(GDIMetaFile &rMtf)
Definition: gdimtf.cxx:325
BitmapEx(* BmpExchangeFnc)(const BitmapEx &rBmpEx, const void *pBmpParam)
Definition: gdimtf.hxx:52
const Size & GetSize() const
Definition: metaact.hxx:808
GDIMetaFile GetMonochromeMtf(const Color &rCol) const
Definition: gdimtf.cxx:2206
void readSize(Size &rSize)
sal_uInt8 GetBlue() const
FontLineStyle GetUnderline() const
Definition: metaact.hxx:642
Size m_aPrefSize
Definition: gdimtf.hxx:64
tools::PolyPolygon GetAsPolyPolygon() const
Definition: region.cxx:1261
void Move(long nHorzMove, long nVertMove)
void Rotate(const Point &rCenter, double fSin, double fCos)
void setPath(const tools::PolyPolygon &rPath)
Set path to fill.
static SAL_DLLPRIVATE tools::PolyPolygon ImplGetRotatedPolyPolygon(const tools::PolyPolygon &rPoly, const Point &rRotatePt, const Size &rOffset, double fSin, double fCos)
Definition: gdimtf.cxx:789
const Size & GetSrcSize() const
Definition: metaact.hxx:959
bool m_bPause
Definition: gdimtf.hxx:68
static SAL_DLLPRIVATE Point ImplGetRotatedPoint(const Point &rPt, const Point &rRotatePt, const Size &rOffset, double fSin, double fCos)
Definition: gdimtf.cxx:768
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
void SetEmpty()
Definition: bitmapex.cxx:209
static vcl::Window * GetFirstTopLevelWindow()
Get the first top-level window of the application.
Definition: svapp.cxx:1065
bool IsEmpty() const
Definition: bitmapex.cxx:204
void Move(long nHorzMove, long nVertMove)
bool GetUseCanvas() const
Definition: gdimtf.hxx:201
bool Create(const css::uno::Reference< css::rendering::XBitmapCanvas > &xBitmapCanvas, const Size &rSize)
populate from a canvas implementation
Definition: bitmapex.cxx:775
#define BITMAP_CHECKSUM_SIZE
Definition: checksum.hxx:28
void SetConnectMetaFile(GDIMetaFile *pMtf)
Definition: outdev.cxx:208
void SetScaleX(const Fraction &rScaleX)
Definition: mapmod.cxx:108
#define TOOLS_WARN_EXCEPTION(area, stream)
friend VCL_DLLPUBLIC SvStream & ReadGDIMetaFile(SvStream &rIStm, GDIMetaFile &rGDIMetaFile, ImplMetaReadData *pReadData)
Definition: gdimtf.cxx:2645
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:215
static SAL_DLLPRIVATE BitmapEx ImplBmpConvertFnc(const BitmapEx &rBmpEx, const void *pBmpParam)
Definition: gdimtf.cxx:1759
const Size & GetPrefSize() const
Definition: gdimtf.hxx:175
~GDIMetaFile()
Definition: gdimtf.cxx:152
GDIMetaFile * m_pNext
Definition: gdimtf.hxx:66
int i
::std::vector< rtl::Reference< MetaAction > > m_aList
Definition: gdimtf.hxx:60
uno_Any a
sal_uInt16 GetTransparence() const
Definition: metaact.hxx:1532
virtual void Scale(double fScaleX, double fScaleY)
Definition: metaact.cxx:181
const Size & GetSize() const
Definition: metaact.hxx:918
const Point & GetPoint() const
Definition: metaact.hxx:494
SAL_DLLPRIVATE void ImplExchangeColors(ColorExchangeFnc pFncCol, const void *pColParam, BmpExchangeFnc pFncBmp, const void *pBmpParam)
Definition: gdimtf.cxx:1822
void Convert(MtfConversion eConversion)
Definition: gdimtf.cxx:2156
bool IsSetting() const
Definition: metaact.hxx:1222
#define LANGUAGE_SYSTEM
BitmapChecksum GetChecksum() const
Color(* ColorExchangeFnc)(const Color &rColor, const void *pColParam)
Definition: gdimtf.hxx:51
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:773
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:988
Size GetOutputSize() const
Definition: outdev.hxx:450
const Size & GetSize() const
Definition: metaact.hxx:1568
void SetOrigin(const Point &rOrigin)
Definition: mapmod.cxx:102
sal_uInt32 GetWidth() const
Definition: metaact.hxx:570
void SetRight(long v)
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:302
std::size_t WriteBytes(const void *pData, std::size_t nSize)
rtl_TextEncoding meActualCharSet
Definition: metaact.hxx:58
SvStreamCompressFlags
BmpMirrorFlags
Definition: bitmap.hxx:36
void SetScaleY(const Fraction &rScaleY)
Definition: mapmod.cxx:115
void UseCanvas(bool _bUseCanvas)
Definition: gdimtf.cxx:2850
void SetError(ErrCode nErrorCode)
BmpScaleFlag
Definition: bitmap.hxx:48
void Intersect(const tools::Rectangle &rRegion)
Definition: region.cxx:584
void getPath(tools::Polygon &) const
Query path to stroke.
sal_Int32 GetLen() const
Definition: metaact.hxx:572
const Point & GetPoint() const
Definition: metaact.hxx:774
bool m_bRecord
Definition: gdimtf.hxx:69
const Bitmap & GetBitmap() const
Definition: metaact.hxx:880
Size GetOutputSizePixel() const
Definition: outdev.hxx:441
MapUnit GetMapUnit() const
Definition: mapmod.cxx:168
sal_uInt8 SVBT64[8]
virtual void SetMetafileMapMode(const MapMode &rNewMapMode, bool bIsRecord)
Definition: map.cxx:773
BmpConversion
Definition: bitmap.hxx:65
void WindStart()
Definition: gdimtf.cxx:553
bool IsTransparent() const
Definition: bitmapex.cxx:222
bool HasTransparentActions() const
Definition: gdimtf.cxx:157
const Bitmap & GetBitmap() const
Definition: metaact.hxx:954
const Point & GetPoint() const
Definition: metaact.hxx:882
static vcl::Window * GetActiveTopWindow()
Get the "active" top window.
Definition: svapp.cxx:1109
static SAL_DLLPRIVATE Color ImplColAdjustFnc(const Color &rColor, const void *pColParam)
Definition: gdimtf.cxx:1728
FontStrikeout GetStrikeout() const
Definition: metaact.hxx:641
tools::Rectangle GetBoundRect(OutputDevice &i_rReference, tools::Rectangle *pHairline=nullptr) const
Definition: gdimtf.cxx:1307
#define Y
const Size & GetSize() const
Definition: metaact.hxx:1605
const Bitmap & GetBitmap() const
Definition: metaact.hxx:704
void SetColor(const Color &)
Definition: font/font.cxx:80
std::size_t ReadBytes(void *pData, std::size_t nSize)
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1187
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:942
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:1048
SvStream & WriteSvtGraphicFill(SvStream &rOStm, const SvtGraphicFill &rClass)
const GfxLink & GetLink() const
Definition: metaact.hxx:1602
const Point & GetPoint() const
Definition: metaact.hxx:568
void SetAngle(sal_uInt16 nAngle10)
Definition: gdi/hatch.cxx:74
bool IsSetting() const
Definition: metaact.hxx:1249
sal_uInt8 GetGreen() const
SvStreamEndian GetEndian() const
void Stop()
Definition: gdimtf.cxx:540
const Color & GetColor() const
Definition: metaact.hxx:916
MapMode m_aPrefMapMode
Definition: gdimtf.hxx:63
const Point & GetStartPoint() const
Definition: metaact.hxx:185
sal_uInt32 GetDataSize() const
Definition: metaact.hxx:1665
bool operator==(const GDIMetaFile &rMtf) const
Definition: gdimtf.cxx:247
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:806
void Pause(bool bPause)
Definition: gdimtf.cxx:521
AlphaMask GetAlpha() const
Definition: bitmapex.cxx:269
BitmapChecksum GetChecksum() const
Definition: gdimtf.cxx:2221
const Color & GetColor() const
Definition: metaact.hxx:955
tools::Rectangle & Union(const tools::Rectangle &rRect)
unsigned char sal_uInt8
void ReplaceAction(rtl::Reference< MetaAction > pAction, size_t nAction)
Definition: gdimtf.cxx:203
void BCToBCOA(BitmapChecksum n, BitmapChecksumOctetArray p)
Definition: checksum.hxx:34
const Point & GetStartPoint() const
Definition: metaact.hxx:639
static SAL_DLLPRIVATE Color ImplColReplaceFnc(const Color &rColor, const void *pColParam)
Definition: gdimtf.cxx:1792
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:566
MetaAction * GetAction(size_t nAction) const
Definition: gdimtf.cxx:187
void Move(long nX, long nY)
Definition: gdimtf.cxx:634
SvStream & ReadGDIMetaFile(SvStream &rIStm, GDIMetaFile &rGDIMetaFile, ImplMetaReadData *pData)
Definition: gdimtf.cxx:2645
void SetEndian(SvStreamEndian SvStreamEndian)
#define SAL_INFO(area, stream)
const Point & GetPoint() const
Definition: metaact.hxx:153
const Point & GetPoint() const
Definition: metaact.hxx:673
bool m_bUseCanvas
Definition: gdimtf.hxx:70
void Linker(OutputDevice *pOut, bool bLink)
Definition: gdimtf.cxx:281
const Point & GetDestPoint() const
Definition: metaact.hxx:956
#define SVSTREAM_FILEFORMAT_ERROR
Definition: errcode.hxx:262
rtl_TextEncoding GetStreamCharSet() const
void Scale(double fScaleX, double fScaleY)
Definition: gdimtf.cxx:711
static SAL_DLLPRIVATE BitmapEx ImplBmpMonoFnc(const BitmapEx &rBmpEx, const void *pBmpParam)
Definition: gdimtf.cxx:1773
bool HasPolyPolygonOrB2DPolyPolygon() const
Definition: region.hxx:110
sal_uInt64 Tell() const
void * p
Reference< XComponentContext > getProcessComponentContext()
size_t GetActionSize() const
Definition: gdimtf.cxx:182
QPRO_FUNC_TYPE nType
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
MetaActionType GetType() const
Definition: metaact.hxx:90
long Left() const
void setPath(const tools::Polygon &)
Set path to stroke.
const Hatch & GetHatch() const
Definition: metaact.hxx:1049
const Point & GetSrcPoint() const
Definition: metaact.hxx:958
FontLineStyle GetOverline() const
Definition: metaact.hxx:643
bool good() const
bool Erase(const Color &rFillColor)
Fill the entire bitmap with the given color.
Definition: bitmappaint.cxx:34
basegfx::B2DPolyPolygon GetAsB2DPolyPolygon() const
Definition: region.cxx:1289
MetaAction * FirstAction()
Definition: gdimtf.cxx:192
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
Size GetPixelOffset() const
Get the offset in pixel.
Definition: outdev.hxx:1723
tools::Rectangle GetBoundRect() const
#define SAL_WARN(area, stream)
DepthGuard(HWPFile &rFile)
sal_uInt8 BitmapChecksumOctetArray[BITMAP_CHECKSUM_SIZE]
Definition: checksum.hxx:31
SvStreamEndian
SvStream & ReadMapMode(SvStream &rIStm, MapMode &rMapMode)
Definition: mapmod.cxx:136
const OString & GetComment() const
Definition: metaact.hxx:1663
Encapsulates geometry and associated attributes of a filled area.
tools::Rectangle GetBoundRect() const
static void ImplActionBounds(tools::Rectangle &o_rOutBounds, const tools::Rectangle &i_rInBounds, const std::vector< tools::Rectangle > &i_rClipStack, tools::Rectangle *o_pHairline)
Definition: gdimtf.cxx:1282
virtual void Move(long nHorzMove, long nVertMove)
Definition: metaact.cxx:177
size_t m_nCurrentActionElement
Definition: gdimtf.hxx:61
virtual size_t GetSyncCount() const
Definition: outdev.hxx:458
void getPath(tools::PolyPolygon &) const
Query path to fill.
Converts old SVGDI aka SVM1 format data to current VCLMTF aka SVM2 format metafile data...
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, long nMin, long nMax)
const Size & GetSizePixel() const
Definition: bitmapex.hxx:83
const Color & GetColor() const
Definition: metaact.hxx:1248
virtual void Write(SvStream &rOStm, ImplMetaWriteData *pData)
Definition: metaact.cxx:185
const GDIMetaFile & GetSubstitute() const
Definition: metaact.hxx:1603
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:60
void SetColor(const Color &rColor)
Definition: gdi/hatch.cxx:64
void setWidth(long nWidth)
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
Definition: bitmapex.cxx:435
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:603
#define GAMMA(_def_cVal, _def_InvGamma)
Definition: gdimtf.cxx:52
aStr
sal_Int32 GetIndex() const
Definition: metaact.hxx:571
sal_Int32 GetIndex() const
Definition: metaact.hxx:496
SvStream & Write(SvStream &rOStm)
Definition: gdimtf.cxx:2746
static SAL_DLLPRIVATE Color ImplColConvertFnc(const Color &rColor, const void *pColParam)
Definition: gdimtf.cxx:1749
void WindPrev()
Definition: gdimtf.cxx:559
const void * GetData()
void setHeight(long nHeight)
bool Rotate(long nAngle10, const Color &rFillColor)
Rotate bitmap by the specified angle.
Definition: bitmapex.cxx:391
sal_uLong GetSizeBytes() const
Definition: gdimtf.cxx:2564