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