LibreOffice Module vcl (master)  1
print2.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 <utility>
21 #include <list>
22 #include <vector>
23 
25 #include <sal/log.hxx>
26 #include <officecfg/Office/Common.hxx>
27 
28 #include <vcl/virdev.hxx>
29 #include <vcl/metaact.hxx>
30 #include <vcl/gdimtf.hxx>
31 #include <vcl/print.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/bitmapaccess.hxx>
34 
35 #include "pdfwriter_impl.hxx"
36 
37 #define MAX_TILE_WIDTH 1024
38 #define MAX_TILE_HEIGHT 1024
39 
40 typedef ::std::pair< MetaAction*, int > Component; // MetaAction plus index in metafile
41 
42 namespace {
43 
44 // List of (intersecting) actions, plus overall bounds
45 struct ConnectedComponents
46 {
47  ConnectedComponents() :
48  aComponentList(),
49  aBounds(),
50  aBgColor(COL_WHITE),
51  bIsSpecial(false),
52  bIsFullyTransparent(false)
53  {}
54 
55  ::std::list< Component > aComponentList;
56  tools::Rectangle aBounds;
57  Color aBgColor;
58  bool bIsSpecial;
59  bool bIsFullyTransparent;
60 };
61 
62 }
63 
64 namespace {
65 
70 bool DoesActionHandleTransparency( const MetaAction& rAct )
71 {
72  // MetaActionType::FLOATTRANSPARENT can contain a whole metafile,
73  // which is to be rendered with the given transparent gradient. We
74  // currently cannot emulate transparent painting on a white
75  // background reliably.
76 
77  // the remainder can handle printing itself correctly on a uniform
78  // white background.
79  switch( rAct.GetType() )
80  {
85  return true;
86 
87  default:
88  return false;
89  }
90 }
91 
92 bool doesRectCoverWithUniformColor(
93  tools::Rectangle const & rPrevRect,
94  tools::Rectangle const & rCurrRect,
95  OutputDevice const & rMapModeVDev)
96 {
97  // shape needs to fully cover previous content, and have uniform
98  // color
99  return (rMapModeVDev.LogicToPixel(rCurrRect).IsInside(rPrevRect) &&
100  rMapModeVDev.IsFillColor());
101 }
102 
106 bool checkRect( tools::Rectangle& io_rPrevRect,
107  Color& o_rBgColor,
108  const tools::Rectangle& rCurrRect,
109  OutputDevice const & rMapModeVDev )
110 {
111  bool bRet = doesRectCoverWithUniformColor(io_rPrevRect, rCurrRect, rMapModeVDev);
112 
113  if( bRet )
114  {
115  io_rPrevRect = rCurrRect;
116  o_rBgColor = rMapModeVDev.GetFillColor();
117  }
118 
119  return bRet;
120 }
121 
129 void ImplConvertTransparentAction( GDIMetaFile& o_rMtf,
130  const MetaAction& rAct,
131  const OutputDevice& rStateOutDev,
132  Color aBgColor )
133 {
134  if (rAct.GetType() == MetaActionType::Transparent)
135  {
136  const MetaTransparentAction* pTransAct = static_cast<const MetaTransparentAction*>(&rAct);
137  sal_uInt16 nTransparency( pTransAct->GetTransparence() );
138 
139  // #i10613# Respect transparency for draw color
140  if (nTransparency)
141  {
142  o_rMtf.AddAction(new MetaPushAction(PushFlags::LINECOLOR|PushFlags::FILLCOLOR));
143 
144  // assume white background for alpha blending
145  Color aLineColor(rStateOutDev.GetLineColor());
146  aLineColor.SetRed(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetRed()) / 100));
147  aLineColor.SetGreen(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetGreen()) / 100));
148  aLineColor.SetBlue(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetBlue()) / 100));
149  o_rMtf.AddAction(new MetaLineColorAction(aLineColor, true));
150 
151  Color aFillColor(rStateOutDev.GetFillColor());
152  aFillColor.SetRed(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetRed()) / 100));
153  aFillColor.SetGreen(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetGreen()) / 100));
154  aFillColor.SetBlue(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetBlue()) / 100));
155  o_rMtf.AddAction(new MetaFillColorAction(aFillColor, true));
156  }
157 
158  o_rMtf.AddAction(new MetaPolyPolygonAction(pTransAct->GetPolyPolygon()));
159 
160  if(nTransparency)
161  o_rMtf.AddAction(new MetaPopAction());
162  }
163  else
164  {
165  BitmapEx aBmpEx;
166 
167  switch (rAct.GetType())
168  {
170  aBmpEx = static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx();
171  break;
172 
174  aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
175  break;
176 
178  aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
179  break;
180 
182 
183  default:
184  OSL_FAIL("Printer::GetPreparedMetafile impossible state reached");
185  break;
186  }
187 
188  Bitmap aBmp(aBmpEx.GetBitmap());
189  if (!aBmpEx.IsAlpha())
190  {
191  // blend with mask
192  Bitmap::ScopedReadAccess pRA(aBmp);
193 
194  if (!pRA)
195  return; // what else should I do?
196 
197  Color aActualColor(aBgColor);
198 
199  if (pRA->HasPalette())
200  aActualColor = pRA->GetBestPaletteColor(aBgColor);
201 
202  pRA.reset();
203 
204  // did we get true white?
205  if (aActualColor.GetColorError(aBgColor))
206  {
207  // no, create truecolor bitmap, then
208  aBmp.Convert(BmpConversion::N24Bit);
209 
210  // fill masked out areas white
211  aBmp.Replace(aBmpEx.GetMask(), aBgColor);
212  }
213  else
214  {
215  // fill masked out areas white
216  aBmp.Replace(aBmpEx.GetMask(), aActualColor);
217  }
218  }
219  else
220  {
221  // blend with alpha channel
222  aBmp.Convert(BmpConversion::N24Bit);
223  aBmp.Blend(aBmpEx.GetAlpha(), aBgColor);
224  }
225 
226  // add corresponding action
227  switch (rAct.GetType())
228  {
230  o_rMtf.AddAction(new MetaBmpAction(
231  static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
232  aBmp));
233  break;
235  o_rMtf.AddAction(new MetaBmpScaleAction(
236  static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
237  static_cast<const MetaBmpExScaleAction&>(rAct).GetSize(),
238  aBmp));
239  break;
241  o_rMtf.AddAction(new MetaBmpScalePartAction(
242  static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
243  static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize(),
244  static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcPoint(),
245  static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcSize(),
246  aBmp));
247  break;
248  default:
249  OSL_FAIL("Unexpected case");
250  break;
251  }
252  }
253 }
254 
255 // #i10613# Extracted from ImplCheckRect::ImplCreate
256 // Returns true, if given action creates visible (i.e. non-transparent) output
257 bool ImplIsNotTransparent( const MetaAction& rAct, const OutputDevice& rOut )
258 {
259  const bool bLineTransparency( !rOut.IsLineColor() || rOut.GetLineColor().GetTransparency() == 255 );
260  const bool bFillTransparency( !rOut.IsFillColor() || rOut.GetFillColor().GetTransparency() == 255 );
261  bool bRet( false );
262 
263  switch( rAct.GetType() )
264  {
266  if( !bLineTransparency )
267  bRet = true;
268  break;
269 
271  if( !bLineTransparency )
272  bRet = true;
273  break;
274 
276  if( !bLineTransparency || !bFillTransparency )
277  bRet = true;
278  break;
279 
281  if( !bLineTransparency || !bFillTransparency )
282  bRet = true;
283  break;
284 
286  if( !bLineTransparency || !bFillTransparency )
287  bRet = true;
288  break;
289 
290  case MetaActionType::ARC:
291  if( !bLineTransparency || !bFillTransparency )
292  bRet = true;
293  break;
294 
295  case MetaActionType::PIE:
296  if( !bLineTransparency || !bFillTransparency )
297  bRet = true;
298  break;
299 
301  if( !bLineTransparency || !bFillTransparency )
302  bRet = true;
303  break;
304 
306  if( !bLineTransparency )
307  bRet = true;
308  break;
309 
311  if( !bLineTransparency || !bFillTransparency )
312  bRet = true;
313  break;
314 
316  if( !bLineTransparency || !bFillTransparency )
317  bRet = true;
318  break;
319 
321  {
322  const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
323  const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
324  if (!aString.isEmpty())
325  bRet = true;
326  }
327  break;
328 
330  {
331  const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
332  const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
333  if (!aString.isEmpty())
334  bRet = true;
335  }
336  break;
337 
339  case MetaActionType::BMP:
354  case MetaActionType::EPS:
358  // all other actions: generate non-transparent output
359  bRet = true;
360  break;
361 
362  default:
363  break;
364  }
365 
366  return bRet;
367 }
368 
369 // #i10613# Extracted from ImplCheckRect::ImplCreate
370 tools::Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevice& rOut )
371 {
372  tools::Rectangle aActionBounds;
373 
374  switch( rAct.GetType() )
375  {
377  aActionBounds = tools::Rectangle( static_cast<const MetaPixelAction&>(rAct).GetPoint(), Size( 1, 1 ) );
378  break;
379 
381  aActionBounds = tools::Rectangle( static_cast<const MetaPointAction&>(rAct).GetPoint(), Size( 1, 1 ) );
382  break;
383 
385  {
386  const MetaLineAction& rMetaLineAction = static_cast<const MetaLineAction&>(rAct);
387  aActionBounds = tools::Rectangle( rMetaLineAction.GetStartPoint(), rMetaLineAction.GetEndPoint() );
388  aActionBounds.Justify();
389  const long nLineWidth(rMetaLineAction.GetLineInfo().GetWidth());
390  if(nLineWidth)
391  {
392  const long nHalfLineWidth((nLineWidth + 1) / 2);
393  aActionBounds.AdjustLeft( -nHalfLineWidth );
394  aActionBounds.AdjustTop( -nHalfLineWidth );
395  aActionBounds.AdjustRight(nHalfLineWidth );
396  aActionBounds.AdjustBottom(nHalfLineWidth );
397  }
398  break;
399  }
400 
402  aActionBounds = static_cast<const MetaRectAction&>(rAct).GetRect();
403  break;
404 
406  aActionBounds = tools::Polygon( static_cast<const MetaRoundRectAction&>(rAct).GetRect(),
407  static_cast<const MetaRoundRectAction&>(rAct).GetHorzRound(),
408  static_cast<const MetaRoundRectAction&>(rAct).GetVertRound() ).GetBoundRect();
409  break;
410 
412  {
413  const tools::Rectangle& rRect = static_cast<const MetaEllipseAction&>(rAct).GetRect();
414  aActionBounds = tools::Polygon( rRect.Center(),
415  rRect.GetWidth() >> 1,
416  rRect.GetHeight() >> 1 ).GetBoundRect();
417  break;
418  }
419 
420  case MetaActionType::ARC:
421  aActionBounds = tools::Polygon( static_cast<const MetaArcAction&>(rAct).GetRect(),
422  static_cast<const MetaArcAction&>(rAct).GetStartPoint(),
423  static_cast<const MetaArcAction&>(rAct).GetEndPoint(), PolyStyle::Arc ).GetBoundRect();
424  break;
425 
426  case MetaActionType::PIE:
427  aActionBounds = tools::Polygon( static_cast<const MetaPieAction&>(rAct).GetRect(),
428  static_cast<const MetaPieAction&>(rAct).GetStartPoint(),
429  static_cast<const MetaPieAction&>(rAct).GetEndPoint(), PolyStyle::Pie ).GetBoundRect();
430  break;
431 
433  aActionBounds = tools::Polygon( static_cast<const MetaChordAction&>(rAct).GetRect(),
434  static_cast<const MetaChordAction&>(rAct).GetStartPoint(),
435  static_cast<const MetaChordAction&>(rAct).GetEndPoint(), PolyStyle::Chord ).GetBoundRect();
436  break;
437 
439  {
440  const MetaPolyLineAction& rMetaPolyLineAction = static_cast<const MetaPolyLineAction&>(rAct);
441  aActionBounds = rMetaPolyLineAction.GetPolygon().GetBoundRect();
442  const long nLineWidth(rMetaPolyLineAction.GetLineInfo().GetWidth());
443  if(nLineWidth)
444  {
445  const long nHalfLineWidth((nLineWidth + 1) / 2);
446  aActionBounds.AdjustLeft( -nHalfLineWidth );
447  aActionBounds.AdjustTop( -nHalfLineWidth );
448  aActionBounds.AdjustRight(nHalfLineWidth );
449  aActionBounds.AdjustBottom(nHalfLineWidth );
450  }
451  break;
452  }
453 
455  aActionBounds = static_cast<const MetaPolygonAction&>(rAct).GetPolygon().GetBoundRect();
456  break;
457 
459  aActionBounds = static_cast<const MetaPolyPolygonAction&>(rAct).GetPolyPolygon().GetBoundRect();
460  break;
461 
462  case MetaActionType::BMP:
463  aActionBounds = tools::Rectangle( static_cast<const MetaBmpAction&>(rAct).GetPoint(),
464  rOut.PixelToLogic( static_cast<const MetaBmpAction&>(rAct).GetBitmap().GetSizePixel() ) );
465  break;
466 
468  aActionBounds = tools::Rectangle( static_cast<const MetaBmpScaleAction&>(rAct).GetPoint(),
469  static_cast<const MetaBmpScaleAction&>(rAct).GetSize() );
470  break;
471 
473  aActionBounds = tools::Rectangle( static_cast<const MetaBmpScalePartAction&>(rAct).GetDestPoint(),
474  static_cast<const MetaBmpScalePartAction&>(rAct).GetDestSize() );
475  break;
476 
478  aActionBounds = tools::Rectangle( static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
479  rOut.PixelToLogic( static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx().GetSizePixel() ) );
480  break;
481 
483  aActionBounds = tools::Rectangle( static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
484  static_cast<const MetaBmpExScaleAction&>(rAct).GetSize() );
485  break;
486 
488  aActionBounds = tools::Rectangle( static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
489  static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize() );
490  break;
491 
493  aActionBounds = tools::Rectangle( static_cast<const MetaMaskAction&>(rAct).GetPoint(),
494  rOut.PixelToLogic( static_cast<const MetaMaskAction&>(rAct).GetBitmap().GetSizePixel() ) );
495  break;
496 
498  aActionBounds = tools::Rectangle( static_cast<const MetaMaskScaleAction&>(rAct).GetPoint(),
499  static_cast<const MetaMaskScaleAction&>(rAct).GetSize() );
500  break;
501 
503  aActionBounds = tools::Rectangle( static_cast<const MetaMaskScalePartAction&>(rAct).GetDestPoint(),
504  static_cast<const MetaMaskScalePartAction&>(rAct).GetDestSize() );
505  break;
506 
508  aActionBounds = static_cast<const MetaGradientAction&>(rAct).GetRect();
509  break;
510 
512  aActionBounds = static_cast<const MetaGradientExAction&>(rAct).GetPolyPolygon().GetBoundRect();
513  break;
514 
516  aActionBounds = static_cast<const MetaHatchAction&>(rAct).GetPolyPolygon().GetBoundRect();
517  break;
518 
520  aActionBounds = static_cast<const MetaWallpaperAction&>(rAct).GetRect();
521  break;
522 
524  aActionBounds = static_cast<const MetaTransparentAction&>(rAct).GetPolyPolygon().GetBoundRect();
525  break;
526 
528  aActionBounds = tools::Rectangle( static_cast<const MetaFloatTransparentAction&>(rAct).GetPoint(),
529  static_cast<const MetaFloatTransparentAction&>(rAct).GetSize() );
530  break;
531 
532  case MetaActionType::EPS:
533  aActionBounds = tools::Rectangle( static_cast<const MetaEPSAction&>(rAct).GetPoint(),
534  static_cast<const MetaEPSAction&>(rAct).GetSize() );
535  break;
536 
538  {
539  const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
540  const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
541 
542  if (!aString.isEmpty())
543  {
544  const Point aPtLog( rTextAct.GetPoint() );
545 
546  // #105987# Use API method instead of Impl* methods
547  // #107490# Set base parameter equal to index parameter
548  rOut.GetTextBoundRect( aActionBounds, rTextAct.GetText(), rTextAct.GetIndex(),
549  rTextAct.GetIndex(), rTextAct.GetLen() );
550  aActionBounds.Move( aPtLog.X(), aPtLog.Y() );
551  }
552  }
553  break;
554 
556  {
557  const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
558  const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
559 
560  if( !aString.isEmpty() )
561  {
562  // #105987# ImplLayout takes everything in logical coordinates
563  std::unique_ptr<SalLayout> pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
564  rTextAct.GetLen(), rTextAct.GetPoint(),
565  0, rTextAct.GetDXArray() );
566  if( pSalLayout )
567  {
568  tools::Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
569  aActionBounds = rOut.PixelToLogic( aBoundRect );
570  }
571  }
572  }
573  break;
574 
576  aActionBounds = static_cast<const MetaTextRectAction&>(rAct).GetRect();
577  break;
578 
580  {
581  const MetaStretchTextAction& rTextAct = static_cast<const MetaStretchTextAction&>(rAct);
582  const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
583 
584  // #i16195# Literate copy from TextArray action, the
585  // semantics for the ImplLayout call are copied from the
586  // OutDev::DrawStretchText() code. Unfortunately, also in
587  // this case, public outdev methods such as GetTextWidth()
588  // don't provide enough info.
589  if( !aString.isEmpty() )
590  {
591  // #105987# ImplLayout takes everything in logical coordinates
592  std::unique_ptr<SalLayout> pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
593  rTextAct.GetLen(), rTextAct.GetPoint(),
594  rTextAct.GetWidth() );
595  if( pSalLayout )
596  {
597  tools::Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
598  aActionBounds = rOut.PixelToLogic( aBoundRect );
599  }
600  }
601  }
602  break;
603 
605  OSL_FAIL("MetaActionType::TEXTLINE not supported");
606  break;
607 
608  default:
609  break;
610  }
611 
612  if( !aActionBounds.IsEmpty() )
613  {
614  // fdo#40421 limit current action's output to clipped area
615  if( rOut.IsClipRegion() )
616  return rOut.LogicToPixel(
617  rOut.GetClipRegion().GetBoundRect().Intersection( aActionBounds ) );
618  else
619  return rOut.LogicToPixel( aActionBounds );
620  }
621  else
622  return tools::Rectangle();
623 }
624 
625 } // end anon namespace
626 
628  long nMaxBmpDPIX, long nMaxBmpDPIY,
629  bool bReduceTransparency, bool bTransparencyAutoMode,
630  bool bDownsampleBitmaps,
631  const Color& rBackground
632  )
633 {
634  MetaAction* pCurrAct;
635  bool bTransparent( false );
636 
637  rOutMtf.Clear();
638 
639  if(!bReduceTransparency || bTransparencyAutoMode)
640  bTransparent = rInMtf.HasTransparentActions();
641 
642  // #i10613# Determine set of connected components containing transparent objects. These are
643  // then processed as bitmaps, the original actions are removed from the metafile.
644  if( !bTransparent )
645  {
646  // nothing transparent -> just copy
647  rOutMtf = rInMtf;
648  }
649  else
650  {
651  // #i10613#
652  // This works as follows: we want a number of distinct sets of
653  // connected components, where each set contains metafile
654  // actions that are intersecting (note: there are possibly
655  // more actions contained as are directly intersecting,
656  // because we can only produce rectangular bitmaps later
657  // on. Thus, each set of connected components is the smallest
658  // enclosing, axis-aligned rectangle that completely bounds a
659  // number of intersecting metafile actions, plus any action
660  // that would otherwise be cut in two). Therefore, we
661  // iteratively add metafile actions from the original metafile
662  // to this connected components list (aCCList), by checking
663  // each element's bounding box against intersection with the
664  // metaaction at hand.
665  // All those intersecting elements are removed from aCCList
666  // and collected in a temporary list (aCCMergeList). After all
667  // elements have been checked, the aCCMergeList elements are
668  // merged with the metaaction at hand into one resulting
669  // connected component, with one big bounding box, and
670  // inserted into aCCList again.
671  // The time complexity of this algorithm is O(n^3), where n is
672  // the number of metafile actions, and it finds all distinct
673  // regions of rectangle-bounded connected components. This
674  // algorithm was designed by AF.
675 
676  // STAGE 1: Detect background
677 
678  // Receives uniform background content, and is _not_ merged
679  // nor checked for intersection against other aCCList elements
680  ConnectedComponents aBackgroundComponent;
681 
682  // Read the configuration value of minimal object area where transparency will be removed
683  double fReduceTransparencyMinArea = officecfg::Office::Common::VCL::ReduceTransparencyMinArea::get() / 100.0;
684  SAL_WARN_IF(fReduceTransparencyMinArea > 1.0, "vcl",
685  "Value of ReduceTransparencyMinArea config option is too high");
686  SAL_WARN_IF(fReduceTransparencyMinArea < 0.0, "vcl",
687  "Value of ReduceTransparencyMinArea config option is too low");
688  fReduceTransparencyMinArea = std::clamp(fReduceTransparencyMinArea, 0.0, 1.0);
689 
690  // create an OutputDevice to record mapmode changes and the like
692  aMapModeVDev->mnDPIX = mnDPIX;
693  aMapModeVDev->mnDPIY = mnDPIY;
694  aMapModeVDev->EnableOutput(false);
695 
696  int nLastBgAction, nActionNum;
697 
698  // weed out page-filling background objects (if they are
699  // uniformly coloured). Keeping them outside the other
700  // connected components often prevents whole-page bitmap
701  // generation.
702  bool bStillBackground=true; // true until first non-bg action
703  nActionNum=0; nLastBgAction=-1;
704  pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
705  if( rBackground != COL_TRANSPARENT )
706  {
707  aBackgroundComponent.aBgColor = rBackground;
708  aBackgroundComponent.aBounds = GetBackgroundComponentBounds();
709  }
710  while( pCurrAct && bStillBackground )
711  {
712  switch( pCurrAct->GetType() )
713  {
715  {
716  if( !checkRect(
717  aBackgroundComponent.aBounds,
718  aBackgroundComponent.aBgColor,
719  static_cast<const MetaRectAction*>(pCurrAct)->GetRect(),
720  *aMapModeVDev) )
721  bStillBackground=false; // incomplete occlusion of background
722  else
723  nLastBgAction=nActionNum; // this _is_ background
724  break;
725  }
727  {
728  const tools::Polygon aPoly(
729  static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
731  aPoly.getB2DPolygon()) ||
732  !checkRect(
733  aBackgroundComponent.aBounds,
734  aBackgroundComponent.aBgColor,
735  aPoly.GetBoundRect(),
736  *aMapModeVDev) )
737  bStillBackground=false; // incomplete occlusion of background
738  else
739  nLastBgAction=nActionNum; // this _is_ background
740  break;
741  }
743  {
744  const tools::PolyPolygon aPoly(
745  static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
746  if( aPoly.Count() != 1 ||
748  aPoly[0].getB2DPolygon()) ||
749  !checkRect(
750  aBackgroundComponent.aBounds,
751  aBackgroundComponent.aBgColor,
752  aPoly.GetBoundRect(),
753  *aMapModeVDev) )
754  bStillBackground=false; // incomplete occlusion of background
755  else
756  nLastBgAction=nActionNum; // this _is_ background
757  break;
758  }
760  {
761  if( !checkRect(
762  aBackgroundComponent.aBounds,
763  aBackgroundComponent.aBgColor,
764  static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect(),
765  *aMapModeVDev) )
766  bStillBackground=false; // incomplete occlusion of background
767  else
768  nLastBgAction=nActionNum; // this _is_ background
769  break;
770  }
771  default:
772  {
773  if( ImplIsNotTransparent( *pCurrAct,
774  *aMapModeVDev ) )
775  bStillBackground=false; // non-transparent action, possibly
776  // not uniform
777  else
778  // extend current bounds (next uniform action
779  // needs to fully cover this area)
780  aBackgroundComponent.aBounds.Union(
781  ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
782  break;
783  }
784  }
785 
786  // execute action to get correct MapModes etc.
787  pCurrAct->Execute( aMapModeVDev.get() );
788 
789  pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
790  ++nActionNum;
791  }
792 
793  aMapModeVDev->ClearStack(); // clean up aMapModeVDev
794 
795  // fast-forward until one after the last background action
796  // (need to reconstruct map mode vdev state)
797  nActionNum=0;
798  pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
799  while( pCurrAct && nActionNum<=nLastBgAction )
800  {
801  // up to and including last ink-generating background
802  // action go to background component
803  aBackgroundComponent.aComponentList.emplace_back(
804  pCurrAct, nActionNum );
805 
806  // execute action to get correct MapModes etc.
807  pCurrAct->Execute( aMapModeVDev.get() );
808  pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
809  ++nActionNum;
810  }
811 
812  // STAGE 2: Generate connected components list
813 
814  ::std::vector<ConnectedComponents> aCCList; // contains distinct sets of connected components as elements.
815 
816  // iterate over all actions (start where background action
817  // search left off)
818  for( ;
819  pCurrAct;
820  pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
821  {
822  // execute action to get correct MapModes etc.
823  pCurrAct->Execute( aMapModeVDev.get() );
824 
825  // cache bounds of current action
826  const tools::Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
827 
828  // accumulate collected bounds here, initialize with current action
829  tools::Rectangle aTotalBounds( aBBCurrAct ); // thus, aTotalComponents.aBounds is empty
830  // for non-output-generating actions
831  bool bTreatSpecial( false );
832  ConnectedComponents aTotalComponents;
833 
834  // STAGE 2.1: Search for intersecting cc entries
835 
836  // if aBBCurrAct is empty, it will intersect with no
837  // aCCList member. Thus, we can save the check.
838  // Furthermore, this ensures that non-output-generating
839  // actions get their own aCCList entry, which is necessary
840  // when copying them to the output metafile (see stage 4
841  // below).
842 
843  // #107169# Wholly transparent objects need
844  // not be considered for connected components,
845  // too. Just put each of them into a separate
846  // component.
847  aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, *aMapModeVDev);
848 
849  if( !aBBCurrAct.IsEmpty() &&
850  !aTotalComponents.bIsFullyTransparent )
851  {
852  if( !aBackgroundComponent.aComponentList.empty() &&
853  !aBackgroundComponent.aBounds.IsInside(aTotalBounds) )
854  {
855  // it seems the background is not large enough. to
856  // be on the safe side, combine with this component.
857  aTotalBounds.Union( aBackgroundComponent.aBounds );
858 
859  // extract all aCurr actions to aTotalComponents
860  aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
861  aBackgroundComponent.aComponentList );
862 
863  if( aBackgroundComponent.bIsSpecial )
864  bTreatSpecial = true;
865  }
866 
867  bool bSomeComponentsChanged;
868 
869  // now, this is unfortunate: since changing anyone of
870  // the aCCList elements (e.g. by merging or addition
871  // of an action) might generate new intersection with
872  // other aCCList elements, have to repeat the whole
873  // element scanning, until nothing changes anymore.
874  // Thus, this loop here makes us O(n^3) in the worst
875  // case.
876  do
877  {
878  // only loop here if 'intersects' branch below was hit
879  bSomeComponentsChanged = false;
880 
881  // iterate over all current members of aCCList
882  for( auto aCurrCC=aCCList.begin(); aCurrCC != aCCList.end(); )
883  {
884  // first check if current element's bounds are
885  // empty. This ensures that empty actions are not
886  // merged into one component, as a matter of fact,
887  // they have no position.
888 
889  // #107169# Wholly transparent objects need
890  // not be considered for connected components,
891  // too. Just put each of them into a separate
892  // component.
893  if( !aCurrCC->aBounds.IsEmpty() &&
894  !aCurrCC->bIsFullyTransparent &&
895  aCurrCC->aBounds.IsOver( aTotalBounds ) )
896  {
897  // union the intersecting aCCList element into aTotalComponents
898 
899  // calc union bounding box
900  aTotalBounds.Union( aCurrCC->aBounds );
901 
902  // extract all aCurr actions to aTotalComponents
903  aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
904  aCurrCC->aComponentList );
905 
906  if( aCurrCC->bIsSpecial )
907  bTreatSpecial = true;
908 
909  // remove and delete aCurrCC element from list (we've now merged its content)
910  aCurrCC = aCCList.erase( aCurrCC );
911 
912  // at least one component changed, need to rescan everything
913  bSomeComponentsChanged = true;
914  }
915  else
916  {
917  ++aCurrCC;
918  }
919  }
920  }
921  while( bSomeComponentsChanged );
922  }
923 
924  // STAGE 2.2: Determine special state for cc element
925 
926  // now test whether the whole connected component must be
927  // treated specially (i.e. rendered as a bitmap): if the
928  // added action is the very first action, or all actions
929  // before it are completely transparent, the connected
930  // component need not be treated specially, not even if
931  // the added action contains transparency. This is because
932  // painting of transparent objects on _white background_
933  // works without alpha compositing (you just calculate the
934  // color). Note that for the test "all objects before me
935  // are transparent" no sorting is necessary, since the
936  // added metaaction pCurrAct is always in the order the
937  // metafile is painted. Generally, the order of the
938  // metaactions in the ConnectedComponents are not
939  // guaranteed to be the same as in the metafile.
940  if( bTreatSpecial )
941  {
942  // prev component(s) special -> this one, too
943  aTotalComponents.bIsSpecial = true;
944  }
945  else if(!pCurrAct->IsTransparent())
946  {
947  // added action and none of prev components special ->
948  // this one normal, too
949  aTotalComponents.bIsSpecial = false;
950  }
951  else
952  {
953  // added action is special and none of prev components
954  // special -> do the detailed tests
955 
956  // can the action handle transparency correctly
957  // (i.e. when painted on white background, does the
958  // action still look correct)?
959  if( !DoesActionHandleTransparency( *pCurrAct ) )
960  {
961  // no, action cannot handle its transparency on
962  // a printer device, render to bitmap
963  aTotalComponents.bIsSpecial = true;
964  }
965  else
966  {
967  // yes, action can handle its transparency, so
968  // check whether we're on white background
969  if( aTotalComponents.aComponentList.empty() )
970  {
971  // nothing between pCurrAct and page
972  // background -> don't be special
973  aTotalComponents.bIsSpecial = false;
974  }
975  else
976  {
977  // #107169# Fixes above now ensure that _no_
978  // object in the list is fully transparent. Thus,
979  // if the component list is not empty above, we
980  // must assume that we have to treat this
981  // component special.
982 
983  // there are non-transparent objects between
984  // pCurrAct and the empty sheet of paper -> be
985  // special, then
986  aTotalComponents.bIsSpecial = true;
987  }
988  }
989  }
990 
991  // STAGE 2.3: Add newly generated CC list element
992 
993  // set new bounds and add action to list
994  aTotalComponents.aBounds = aTotalBounds;
995  aTotalComponents.aComponentList.emplace_back(
996  pCurrAct, nActionNum );
997 
998  // add aTotalComponents as a new entry to aCCList
999  aCCList.push_back( aTotalComponents );
1000 
1001  SAL_WARN_IF( aTotalComponents.aComponentList.empty(), "vcl",
1002  "Printer::GetPreparedMetaFile empty component" );
1003  SAL_WARN_IF( aTotalComponents.aBounds.IsEmpty() && (aTotalComponents.aComponentList.size() != 1), "vcl",
1004  "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
1005  SAL_WARN_IF( aTotalComponents.bIsFullyTransparent && (aTotalComponents.aComponentList.size() != 1), "vcl",
1006  "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
1007  }
1008 
1009  // well now, we've got the list of disjunct connected
1010  // components. Now we've got to create a map, which contains
1011  // the corresponding aCCList element for every
1012  // metaaction. Later on, we always process the complete
1013  // metafile for each bitmap to be generated, but switch on
1014  // output only for actions contained in the then current
1015  // aCCList element. This ensures correct mapmode and attribute
1016  // settings for all cases.
1017 
1018  // maps mtf actions to CC list entries
1019  ::std::vector< const ConnectedComponents* > aCCList_MemberMap( rInMtf.GetActionSize() );
1020 
1021  // iterate over all aCCList members and their contained metaactions
1022  for (auto const& currentItem : aCCList)
1023  {
1024  for (auto const& currentAction : currentItem.aComponentList)
1025  {
1026  // set pointer to aCCList element for corresponding index
1027  aCCList_MemberMap[ currentAction.second ] = &currentItem;
1028  }
1029  }
1030 
1031  // STAGE 3.1: Output background mtf actions (if there are any)
1032 
1033  for (auto & component : aBackgroundComponent.aComponentList)
1034  {
1035  // simply add this action (above, we inserted the actions
1036  // starting at index 0 up to and including nLastBgAction)
1037  rOutMtf.AddAction( component.first );
1038  }
1039 
1040  // STAGE 3.2: Generate banded bitmaps for special regions
1041 
1042  Point aPageOffset;
1043  Size aTmpSize( GetOutputSizePixel() );
1044  if( meOutDevType == OUTDEV_PDF )
1045  {
1046  auto pPdfWriter = static_cast<vcl::PDFWriterImpl*>(this);
1047  aTmpSize = LogicToPixel(pPdfWriter->getCurPageSize(), MapMode(MapUnit::MapPoint));
1048 
1049  // also add error code to PDFWriter
1050  pPdfWriter->insertError(vcl::PDFWriter::Warning_Transparency_Converted);
1051  }
1052  else if( meOutDevType == OUTDEV_PRINTER )
1053  {
1054  Printer* pThis = dynamic_cast<Printer*>(this);
1055  assert(pThis);
1056  aPageOffset = pThis->GetPageOffsetPixel();
1057  aPageOffset = Point( 0, 0 ) - aPageOffset;
1058  aTmpSize = pThis->GetPaperSizePixel();
1059  }
1060  const tools::Rectangle aOutputRect( aPageOffset, aTmpSize );
1061  bool bTiling = dynamic_cast<Printer*>(this) != nullptr;
1062 
1063  // iterate over all aCCList members and generate bitmaps for the special ones
1064  for (auto & currentItem : aCCList)
1065  {
1066  if( currentItem.bIsSpecial )
1067  {
1068  tools::Rectangle aBoundRect( currentItem.aBounds );
1069  aBoundRect.Intersection( aOutputRect );
1070 
1071  const double fBmpArea( static_cast<double>(aBoundRect.GetWidth()) * aBoundRect.GetHeight() );
1072  const double fOutArea( static_cast<double>(aOutputRect.GetWidth()) * aOutputRect.GetHeight() );
1073 
1074  // check if output doesn't exceed given size
1075  if( bReduceTransparency && bTransparencyAutoMode && ( fBmpArea > ( fReduceTransparencyMinArea * fOutArea ) ) )
1076  {
1077  // output normally. Therefore, we simply clear the
1078  // special attribute, as everything non-special is
1079  // copied to rOutMtf further below.
1080  currentItem.bIsSpecial = false;
1081  }
1082  else
1083  {
1084  // create new bitmap action first
1085  if( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
1086  {
1087  Point aDstPtPix( aBoundRect.TopLeft() );
1088  Size aDstSzPix;
1089 
1090  ScopedVclPtrInstance<VirtualDevice> aMapVDev; // here, we record only mapmode information
1091  aMapVDev->EnableOutput(false);
1092 
1093  ScopedVclPtrInstance<VirtualDevice> aPaintVDev; // into this one, we render.
1094  aPaintVDev->SetBackground( aBackgroundComponent.aBgColor );
1095 
1096  rOutMtf.AddAction( new MetaPushAction( PushFlags::MAPMODE ) );
1097  rOutMtf.AddAction( new MetaMapModeAction() );
1098 
1099  aPaintVDev->SetDrawMode( GetDrawMode() );
1100 
1101  while( aDstPtPix.Y() <= aBoundRect.Bottom() )
1102  {
1103  aDstPtPix.setX( aBoundRect.Left() );
1104  aDstSzPix = bTiling ? Size( MAX_TILE_WIDTH, MAX_TILE_HEIGHT ) : aBoundRect.GetSize();
1105 
1106  if( ( aDstPtPix.Y() + aDstSzPix.Height() - 1 ) > aBoundRect.Bottom() )
1107  aDstSzPix.setHeight( aBoundRect.Bottom() - aDstPtPix.Y() + 1 );
1108 
1109  while( aDstPtPix.X() <= aBoundRect.Right() )
1110  {
1111  if( ( aDstPtPix.X() + aDstSzPix.Width() - 1 ) > aBoundRect.Right() )
1112  aDstSzPix.setWidth( aBoundRect.Right() - aDstPtPix.X() + 1 );
1113 
1114  if( !tools::Rectangle( aDstPtPix, aDstSzPix ).Intersection( aBoundRect ).IsEmpty() &&
1115  aPaintVDev->SetOutputSizePixel( aDstSzPix ) )
1116  {
1117  aPaintVDev->Push();
1118  aMapVDev->Push();
1119 
1120  aMapVDev->mnDPIX = aPaintVDev->mnDPIX = mnDPIX;
1121  aMapVDev->mnDPIY = aPaintVDev->mnDPIY = mnDPIY;
1122 
1123  aPaintVDev->EnableOutput(false);
1124 
1125  // iterate over all actions
1126  for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
1127  pCurrAct;
1128  pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
1129  {
1130  // enable output only for
1131  // actions that are members of
1132  // the current aCCList element
1133  // (currentItem)
1134  if( aCCList_MemberMap[nActionNum] == &currentItem )
1135  aPaintVDev->EnableOutput();
1136 
1137  // but process every action
1138  const MetaActionType nType( pCurrAct->GetType() );
1139 
1141  {
1142  pCurrAct->Execute( aMapVDev.get() );
1143 
1144  MapMode aMtfMap( aMapVDev->GetMapMode() );
1145  const Point aNewOrg( aMapVDev->PixelToLogic( aDstPtPix ) );
1146 
1147  aMtfMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
1148  aPaintVDev->SetMapMode( aMtfMap );
1149  }
1150  else if( ( MetaActionType::PUSH == nType ) || MetaActionType::POP == nType )
1151  {
1152  pCurrAct->Execute( aMapVDev.get() );
1153  pCurrAct->Execute( aPaintVDev.get() );
1154  }
1155  else if( MetaActionType::GRADIENT == nType )
1156  {
1157  MetaGradientAction* pGradientAction = static_cast<MetaGradientAction*>(pCurrAct);
1158  Printer* pPrinter = dynamic_cast< Printer* >(this);
1159  if( pPrinter )
1160  pPrinter->DrawGradientEx( aPaintVDev.get(), pGradientAction->GetRect(), pGradientAction->GetGradient() );
1161  else
1162  DrawGradient( pGradientAction->GetRect(), pGradientAction->GetGradient() );
1163  }
1164  else
1165  {
1166  pCurrAct->Execute( aPaintVDev.get() );
1167  }
1168 
1169  Application::Reschedule( true );
1170  }
1171 
1172  const bool bOldMap = mbMap;
1173  mbMap = aPaintVDev->mbMap = false;
1174 
1175  Bitmap aBandBmp( aPaintVDev->GetBitmap( Point(), aDstSzPix ) );
1176 
1177  // scale down bitmap, if requested
1178  if( bDownsampleBitmaps )
1179  {
1180  aBandBmp = GetDownsampledBitmap( aDstSzPix,
1181  Point(), aBandBmp.GetSizePixel(),
1182  aBandBmp, nMaxBmpDPIX, nMaxBmpDPIY );
1183  }
1184 
1185  rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) );
1186  rOutMtf.AddAction( new MetaBmpScaleAction( aDstPtPix, aDstSzPix, aBandBmp ) );
1187  rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_END" ) );
1188 
1189  aPaintVDev->mbMap = true;
1190  mbMap = bOldMap;
1191  aMapVDev->Pop();
1192  aPaintVDev->Pop();
1193  }
1194 
1195  // overlapping bands to avoid missing lines (e.g. PostScript)
1196  aDstPtPix.AdjustX(aDstSzPix.Width() );
1197  }
1198 
1199  // overlapping bands to avoid missing lines (e.g. PostScript)
1200  aDstPtPix.AdjustY(aDstSzPix.Height() );
1201  }
1202 
1203  rOutMtf.AddAction( new MetaPopAction() );
1204  }
1205  }
1206  }
1207  }
1208 
1209  aMapModeVDev->ClearStack(); // clean up aMapModeVDev
1210 
1211  // STAGE 4: Copy actions to output metafile
1212 
1213  // iterate over all actions and duplicate the ones not in a
1214  // special aCCList member into rOutMtf
1215  for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
1216  pCurrAct;
1217  pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
1218  {
1219  const ConnectedComponents* pCurrAssociatedComponent = aCCList_MemberMap[nActionNum];
1220 
1221  // NOTE: This relies on the fact that map-mode or draw
1222  // mode changing actions are solitary aCCList elements and
1223  // have empty bounding boxes, see comment on stage 2.1
1224  // above
1225  if( pCurrAssociatedComponent &&
1226  (pCurrAssociatedComponent->aBounds.IsEmpty() ||
1227  !pCurrAssociatedComponent->bIsSpecial) )
1228  {
1229  // #107169# Treat transparent bitmaps special, if they
1230  // are the first (or sole) action in their bounds
1231  // list. Note that we previously ensured that no
1232  // fully-transparent objects are before us here.
1233  if( DoesActionHandleTransparency( *pCurrAct ) &&
1234  pCurrAssociatedComponent->aComponentList.begin()->first == pCurrAct )
1235  {
1236  // convert actions, where masked-out parts are of
1237  // given background color
1238  ImplConvertTransparentAction(rOutMtf,
1239  *pCurrAct,
1240  *aMapModeVDev,
1241  aBackgroundComponent.aBgColor);
1242  }
1243  else
1244  {
1245  // simply add this action
1246  rOutMtf.AddAction( pCurrAct );
1247  }
1248 
1249  pCurrAct->Execute(aMapModeVDev.get());
1250  }
1251  }
1252 
1253  rOutMtf.SetPrefMapMode( rInMtf.GetPrefMapMode() );
1254  rOutMtf.SetPrefSize( rInMtf.GetPrefSize() );
1255 
1256 #if OSL_DEBUG_LEVEL > 1
1257  // iterate over all aCCList members and generate rectangles for the bounding boxes
1258  rOutMtf.AddAction( new MetaFillColorAction( COL_WHITE, false ) );
1259  for(auto const& aCurr:aCCList)
1260  {
1261  if( aCurr.bIsSpecial )
1262  rOutMtf.AddAction( new MetaLineColorAction( COL_RED, true) );
1263  else
1264  rOutMtf.AddAction( new MetaLineColorAction( COL_BLUE, true) );
1265 
1266  rOutMtf.AddAction( new MetaRectAction( aMapModeVDev->PixelToLogic( aCurr.aBounds ) ) );
1267  }
1268 #endif
1269  }
1270  return bTransparent;
1271 }
1272 
1273 void Printer::DrawGradientEx( OutputDevice* pOut, const tools::Rectangle& rRect, const Gradient& rGradient )
1274 {
1275  const PrinterOptions& rPrinterOptions = GetPrinterOptions();
1276 
1277  if( rPrinterOptions.IsReduceGradients() )
1278  {
1279  if( PrinterGradientMode::Stripes == rPrinterOptions.GetReducedGradientMode() )
1280  {
1281  if( !rGradient.GetSteps() || ( rGradient.GetSteps() > rPrinterOptions.GetReducedGradientStepCount() ) )
1282  {
1283  Gradient aNewGradient( rGradient );
1284 
1285  aNewGradient.SetSteps( rPrinterOptions.GetReducedGradientStepCount() );
1286  pOut->DrawGradient( rRect, aNewGradient );
1287  }
1288  else
1289  pOut->DrawGradient( rRect, rGradient );
1290  }
1291  else
1292  {
1293  const Color& rStartColor = rGradient.GetStartColor();
1294  const Color& rEndColor = rGradient.GetEndColor();
1295  const long nR = ( ( static_cast<long>(rStartColor.GetRed()) * rGradient.GetStartIntensity() ) / 100 +
1296  ( static_cast<long>(rEndColor.GetRed()) * rGradient.GetEndIntensity() ) / 100 ) >> 1;
1297  const long nG = ( ( static_cast<long>(rStartColor.GetGreen()) * rGradient.GetStartIntensity() ) / 100 +
1298  ( static_cast<long>(rEndColor.GetGreen()) * rGradient.GetEndIntensity() ) / 100 ) >> 1;
1299  const long nB = ( ( static_cast<long>(rStartColor.GetBlue()) * rGradient.GetStartIntensity() ) / 100 +
1300  ( static_cast<long>(rEndColor.GetBlue()) * rGradient.GetEndIntensity() ) / 100 ) >> 1;
1301  const Color aColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
1302 
1304  pOut->SetLineColor( aColor );
1305  pOut->SetFillColor( aColor );
1306  pOut->DrawRect( rRect );
1307  pOut->Pop();
1308  }
1309  }
1310  else
1311  pOut->DrawGradient( rRect, rGradient );
1312 }
1313 
1314 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
Point TopLeft() const
vcl::Region GetClipRegion() const
const PrinterOptions & GetPrinterOptions() const
Definition: print.hxx:285
virtual void Execute(OutputDevice *pOut)
Definition: metaact.cxx:168
const LineInfo & GetLineInfo() const
Definition: metaact.hxx:187
Bitmap GetMask() const
Definition: bitmapex.cxx:254
long GetWidth() const
sal_Int32 GetLen() const
Definition: metaact.hxx:497
long GetHeight() const
sal_uInt8 GetRed() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
constexpr::Color COL_RED(0x80, 0x00, 0x00)
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:178
long AdjustLeft(long nHorzMoveDelta)
sal_uInt8 GetTransparency() const
virtual bool IsTransparent() const
#i10613# Extracted from Printer::GetPreparedMetaFile.
Definition: metaact.hxx:94
SAL_DLLPRIVATE Bitmap GetDownsampledBitmap(const Size &rDstSz, const Point &rSrcPt, const Size &rSrcSz, const Bitmap &rBmp, long nMaxBmpDPIX, long nMaxBmpDPIY)
Retrieve downsampled and cropped bitmap.
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:176
void Clear()
Definition: gdimtf.cxx:273
sal_Int32 mnDPIY
Definition: outdev.hxx:346
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:1531
bool RemoveTransparenciesFromMetaFile(const GDIMetaFile &rInMtf, GDIMetaFile &rOutMtf, long nMaxBmpDPIX, long nMaxBmpDPIY, bool bReduceTransparency, bool bTransparencyAutoMode, bool bDownsampleBitmaps, const Color &rBackground=COL_TRANSPARENT)
helper method removing transparencies from a metafile (e.g.
Definition: print2.cxx:627
const Point & GetEndPoint() const
Definition: metaact.hxx:186
sal_Int32 mnDPIX
Definition: outdev.hxx:345
const OUString & GetText() const
Definition: metaact.hxx:569
bool mbMap
Definition: outdev.hxx:374
tools::Rectangle GetBoundRect() const
Definition: region.cxx:1214
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, const long *pDXArray=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Return the exact bounding rectangle of rStr.
Definition: text.cxx:2257
long AdjustBottom(long nVertMoveDelta)
void Move(long nHorzMoveDelta, long nVertMoveDelta)
bool IsEmpty() const
void SetSteps(sal_uInt16 nSteps)
constexpr::Color COL_TRANSPARENT(0xFF, 0xFF, 0xFF, 0xFF)
bool IsAlpha() const
Definition: bitmapex.cxx:222
long Right() const
const OUString & GetText() const
Definition: metaact.hxx:495
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
const Gradient & GetGradient() const
Definition: metaact.hxx:989
const Size & GetPaperSizePixel() const
Definition: print.hxx:310
MetaActionType
void DrawGradientEx(OutputDevice *pOut, const tools::Rectangle &rRect, const Gradient &rGradient)
Definition: print2.cxx:1273
sal_uInt8 GetBlue() const
void DrawRect(const tools::Rectangle &rRect)
Definition: rect.cxx:51
void SetLineColor()
static bool Reschedule(bool bHandleAllCurrentEvents=false)
Attempt to process current pending event(s)
Definition: svapp.cxx:466
const Size & GetPrefSize() const
Definition: gdimtf.hxx:175
virtual tools::Rectangle GetBackgroundComponentBounds() const
Definition: outdev.cxx:573
bool IsClipRegion() const
Definition: outdev.hxx:675
sal_uInt16 GetTransparence() const
Definition: metaact.hxx:1532
bool IsLineColor() const
Definition: outdev.hxx:631
const Point & GetPoint() const
Definition: metaact.hxx:494
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:988
sal_uInt32 GetWidth() const
Definition: metaact.hxx:570
const OutDevType meOutDevType
Definition: outdev.hxx:357
void SetFillColor()
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:302
const Color & GetLineColor() const
Definition: outdev.hxx:630
void SetRed(sal_uInt8 nRed)
long Bottom() const
sal_uInt16 GetEndIntensity() const
sal_Int32 GetLen() const
Definition: metaact.hxx:572
Size GetOutputSizePixel() const
Definition: outdev.hxx:441
::basegfx::B2DPolygon getB2DPolygon() const
DrawModeFlags GetDrawMode() const
Definition: outdev.hxx:607
bool HasTransparentActions() const
Definition: gdimtf.cxx:157
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), long nLogicWidth=0, const long *pLogicDXArray=nullptr, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1245
sal_Int32 nLineWidth
Size GetSize() const
sal_uInt16 GetSteps() const
#define MAX_TILE_WIDTH
Definition: print2.cxx:37
const Color & GetStartColor() const
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: bitmapex.cxx:232
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1187
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:942
const Point & GetPoint() const
Definition: metaact.hxx:568
sal_uInt8 GetGreen() const
const Point & GetStartPoint() const
Definition: metaact.hxx:185
const Point & GetPageOffsetPixel() const
Definition: print.hxx:313
AlphaMask GetAlpha() const
Definition: bitmapex.cxx:264
long AdjustRight(long nHorzMoveDelta)
tools::Rectangle & Union(const tools::Rectangle &rRect)
#define SAL_WARN_IF(condition, area, stream)
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:566
const Color & GetEndColor() const
long AdjustTop(long nVertMoveDelta)
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
::std::pair< MetaAction *, int > Component
Definition: print2.cxx:40
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
tools::Rectangle GetBoundRect() const
constexpr::Color COL_BLUE(0x00, 0x00, 0x80)
tools::Rectangle GetBoundRect() const
bool IsFillColor() const
Definition: outdev.hxx:636
#define MAX_TILE_HEIGHT
Definition: print2.cxx:38
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:60
void DrawGradient(const tools::Rectangle &rRect, const Gradient &rGradient)
sal_uInt16 GetStartIntensity() const
sal_Int32 GetIndex() const
Definition: metaact.hxx:571
bool isRectangle(const B2DPolygon &rPoly)
sal_Int32 GetIndex() const
Definition: metaact.hxx:496
Point Center() const
const Color & GetFillColor() const
Definition: outdev.hxx:635
void SetPrefMapMode(const MapMode &rMapMode)
Definition: gdimtf.hxx:179
void setHeight(long nHeight)