LibreOffice Module vcl (master)  1
transparent.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 <cassert>
21 
22 #include <sal/types.h>
23 #include <tools/helpers.hxx>
24 #include <rtl/math.hxx>
25 
26 #include <memory>
27 
28 #include <vcl/bitmapaccess.hxx>
29 #include <vcl/gdimtf.hxx>
30 #include <vcl/metaact.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/settings.hxx>
33 #include <vcl/virdev.hxx>
34 
35 #include <outdata.hxx>
36 #include <salgdi.hxx>
37 #include <bitmapwriteaccess.hxx>
38 
39 namespace
40 {
46  tools::Polygon toPolygon( const basegfx::B2DPolygon& rPoly )
47  {
48  basegfx::B2DRange aRange = rPoly.getB2DRange();
49  double fW = aRange.getWidth(), fH = aRange.getHeight();
50  if (0.0 < fW && 0.0 < fH && (fW <= 1.0 || fH <= 1.0))
51  {
52  // This polygon not empty but is too small to display. Approximate it
53  // with a rectangle large enough to be displayed.
54  double nX = aRange.getMinX(), nY = aRange.getMinY();
55  double nW = std::max<double>(1.0, rtl::math::round(fW));
56  double nH = std::max<double>(1.0, rtl::math::round(fH));
57 
58  tools::Polygon aTarget;
59  aTarget.Insert(0, Point(nX, nY));
60  aTarget.Insert(1, Point(nX+nW, nY));
61  aTarget.Insert(2, Point(nX+nW, nY+nH));
62  aTarget.Insert(3, Point(nX, nY+nH));
63  aTarget.Insert(4, Point(nX, nY));
64  return aTarget;
65  }
66  return tools::Polygon(rPoly);
67  }
68 
69  tools::PolyPolygon toPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly )
70  {
71  tools::PolyPolygon aTarget;
72  for (auto const& rB2DPolygon : rPolyPoly)
73  aTarget.Insert(toPolygon(rB2DPolygon));
74 
75  return aTarget;
76  }
77 }
78 
80 {
81  Color aColor( rColor );
82  DrawModeFlags nDrawMode = GetDrawMode();
83 
87  {
88  if( !ImplIsColorTransparent( aColor ) )
89  {
90  if( nDrawMode & DrawModeFlags::BlackLine )
91  {
92  aColor = COL_BLACK;
93  }
94  else if( nDrawMode & DrawModeFlags::WhiteLine )
95  {
96  aColor = COL_WHITE;
97  }
98  else if( nDrawMode & DrawModeFlags::GrayLine )
99  {
100  const sal_uInt8 cLum = aColor.GetLuminance();
101  aColor = Color( cLum, cLum, cLum );
102  }
103  else if( nDrawMode & DrawModeFlags::SettingsLine )
104  {
106  }
107  }
108  }
109  return aColor;
110 }
111 
112 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
113  const Point& rDestPt, const Size& rDestSize,
114  const Point& rSrcPtPixel, const Size& rSrcSizePixel )
115 {
116  Point aDestPt( LogicToPixel( rDestPt ) );
117  Size aDestSz( LogicToPixel( rDestSize ) );
118  tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
119 
120  aSrcRect.Justify();
121 
122  if( rBmp.IsEmpty() || !aSrcRect.GetWidth() || !aSrcRect.GetHeight() || !aDestSz.Width() || !aDestSz.Height() )
123  return;
124 
125  Bitmap aPaint( rBmp ), aMask( rMask );
127 
128  if( aMask.GetBitCount() > 1 )
130 
131  // mirrored horizontically
132  if( aDestSz.Width() < 0 )
133  {
134  aDestSz.setWidth( -aDestSz.Width() );
135  aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
136  nMirrFlags |= BmpMirrorFlags::Horizontal;
137  }
138 
139  // mirrored vertically
140  if( aDestSz.Height() < 0 )
141  {
142  aDestSz.setHeight( -aDestSz.Height() );
143  aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
144  nMirrFlags |= BmpMirrorFlags::Vertical;
145  }
146 
147  // source cropped?
148  if( aSrcRect != tools::Rectangle( Point(), aPaint.GetSizePixel() ) )
149  {
150  aPaint.Crop( aSrcRect );
151  aMask.Crop( aSrcRect );
152  }
153 
154  // destination mirrored
155  if( nMirrFlags != BmpMirrorFlags::NONE )
156  {
157  aPaint.Mirror( nMirrFlags );
158  aMask.Mirror( nMirrFlags );
159  }
160 
161  // we always want to have a mask
162  if( aMask.IsEmpty() )
163  {
164  aMask = Bitmap( aSrcRect.GetSize(), 1 );
165  aMask.Erase( COL_BLACK );
166  }
167 
168  // do painting
169  const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
170  long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight;
171  std::unique_ptr<long[]> pMapX(new long[ nSrcWidth + 1 ]);
172  std::unique_ptr<long[]> pMapY(new long[ nSrcHeight + 1 ]);
173  const bool bOldMap = mbMap;
174 
175  mbMap = false;
176 
177  // create forward mapping tables
178  for( nX = 0; nX <= nSrcWidth; nX++ )
179  pMapX[ nX ] = aDestPt.X() + FRound( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth );
180 
181  for( nY = 0; nY <= nSrcHeight; nY++ )
182  pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
183 
184  // walk through all rectangles of mask
185  const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel())));
186  RectangleVector aRectangles;
187  aWorkRgn.GetRegionRectangles(aRectangles);
188 
189  for (auto const& rectangle : aRectangles)
190  {
191  const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]);
192  const Size aMapSz( pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
193  pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y
194  Bitmap aBandBmp(aPaint);
195 
196  aBandBmp.Crop(rectangle);
197  DrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp);
198  }
199 
200  mbMap = bOldMap;
201 
202 }
203 
204 // Caution: This method is nearly the same as
205 // void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
206 // so when changes are made here do not forget to make changes there, too
207 
209  const basegfx::B2DHomMatrix& rObjectTransform,
210  const basegfx::B2DPolyPolygon& rB2DPolyPoly,
211  double fTransparency)
212 {
214 
215  // AW: Do NOT paint empty PolyPolygons
216  if(!rB2DPolyPoly.count())
217  return;
218 
219  // we need a graphics
220  if( !mpGraphics && !AcquireGraphics() )
221  return;
222 
223  if( mbInitClipRegion )
224  InitClipRegion();
225 
226  if( mbOutputClipped )
227  return;
228 
229  if( mbInitLineColor )
230  InitLineColor();
231 
232  if( mbInitFillColor )
233  InitFillColor();
234 
238  {
239  // b2dpolygon support not implemented yet on non-UNX platforms
240  basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
241 
242  // ensure it is closed
243  if(!aB2DPolyPolygon.isClosed())
244  {
245  // maybe assert, prevents buffering due to making a copy
246  aB2DPolyPolygon.setClosed( true );
247  }
248 
249  // create ObjectToDevice transformation
250  const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rObjectTransform);
251  const double fAdjustedTransparency = mpAlphaVDev ? 0 : fTransparency;
252  bool bDrawnOk(true);
253 
254  if( IsFillColor() )
255  {
256  bDrawnOk = mpGraphics->DrawPolyPolygon(
257  aFullTransform,
258  aB2DPolyPolygon,
259  fAdjustedTransparency,
260  this);
261  }
262 
263  if( bDrawnOk && IsLineColor() )
264  {
265  const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
266 
267  for(auto const& rPolygon : aB2DPolyPolygon)
268  {
270  aFullTransform,
271  rPolygon,
272  fAdjustedTransparency,
273  0.0, // tdf#124848 hairline
274  nullptr, // MM01
276  css::drawing::LineCap_BUTT,
277  basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
278  bPixelSnapHairline,
279  this );
280  }
281  }
282 
283  if( bDrawnOk )
284  {
285  if( mpMetaFile )
286  {
287  // tdf#119843 need transformed Polygon here
288  basegfx::B2DPolyPolygon aB2DPolyPoly(rB2DPolyPoly);
289  aB2DPolyPoly.transform(rObjectTransform);
292  tools::PolyPolygon(aB2DPolyPoly),
293  static_cast< sal_uInt16 >(fTransparency * 100.0)));
294  }
295 
296  if (mpAlphaVDev)
297  {
298  const Color aFillCol(mpAlphaVDev->GetFillColor());
299  const Color aLineColor(mpAlphaVDev->GetLineColor());
300  const auto nGreyScale = static_cast<sal_uInt8>(std::round(255 * fTransparency));
301  const Color aNewColor(nGreyScale, nGreyScale, nGreyScale);
302  mpAlphaVDev->SetFillColor(aNewColor);
303  mpAlphaVDev->SetLineColor(aNewColor);
304 
305  mpAlphaVDev->DrawTransparent(rObjectTransform, rB2DPolyPoly, fTransparency);
306 
307  mpAlphaVDev->SetFillColor(aFillCol);
308  mpAlphaVDev->SetLineColor(aLineColor);
309  }
310 
311  return;
312  }
313  }
314 
315  // fallback to old polygon drawing if needed
316  // tdf#119843 need transformed Polygon here
317  basegfx::B2DPolyPolygon aB2DPolyPoly(rB2DPolyPoly);
318  aB2DPolyPoly.transform(rObjectTransform);
320  toPolyPolygon(aB2DPolyPoly),
321  static_cast<sal_uInt16>(fTransparency * 100.0));
322 }
323 
325 {
327 
328  // short circuit if the polygon border is invisible too
329  if( !mbLineColor )
330  return;
331 
332  // we assume that the border is NOT to be drawn transparently???
334  SetFillColor();
335  DrawPolyPolygon( rPolyPoly );
336  Pop();
337 }
338 
340  sal_uInt16 nTransparencePercent )
341 {
343 
344  bool bDrawn = false;
345 
346  // debug helper:
347  static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
348 
349  if( !pDisableNative &&
351 #if defined UNX && ! defined MACOSX && ! defined IOS
352  && GetBitCount() > 8
353 #endif
354 #ifdef _WIN32
355  // workaround bad dithering on remote displaying when using GDI+ with toolbar button highlighting
356  && !rPolyPoly.IsRect()
357 #endif
358  )
359  {
360  // prepare the graphics device
361  if( mbInitClipRegion )
362  InitClipRegion();
363 
364  if( mbOutputClipped )
365  return false;
366 
367  if( mbInitLineColor )
368  InitLineColor();
369 
370  if( mbInitFillColor )
371  InitFillColor();
372 
373  // get the polygon in device coordinates
374  basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
376 
377  const double fTransparency = 0.01 * nTransparencePercent;
378  if( mbFillColor )
379  {
380  // #i121591#
381  // CAUTION: Only non printing (pixel-renderer) VCL commands from OutputDevices
382  // should be used when printing. Normally this is avoided by the printer being
383  // non-AAed and thus e.g. on WIN GdiPlus calls are not used. It may be necessary
384  // to figure out a way of moving this code to its own function that is
385  // overridden by the Print class, which will mean we deliberately override the
386  // functionality and we use the fallback some lines below (which is not very good,
387  // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and
388  // correct the wrong mapping (see there for details)
389  bDrawn = mpGraphics->DrawPolyPolygon(
390  aTransform,
391  aB2DPolyPolygon,
392  fTransparency,
393  this);
394  }
395 
396  if( mbLineColor )
397  {
398  // disable the fill color for now
400 
401  // draw the border line
402  const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
403 
404  for(auto const& rPolygon : aB2DPolyPolygon)
405  {
406  bDrawn = mpGraphics->DrawPolyLine(
407  aTransform,
408  rPolygon,
409  fTransparency,
410  0.0, // tdf#124848 hairline
411  nullptr, // MM01
413  css::drawing::LineCap_BUTT,
414  basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
415  bPixelSnapHairline,
416  this );
417  }
418 
419  // prepare to restore the fill color
421  }
422  }
423 
424  return bDrawn;
425 }
426 
428  sal_uInt16 nTransparencePercent )
429 {
430  // #110958# Disable alpha VDev, we perform the necessary
431  VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
432 
433  // operation explicitly further below.
434  if( mpAlphaVDev )
435  mpAlphaVDev = nullptr;
436 
437  GDIMetaFile* pOldMetaFile = mpMetaFile;
438  mpMetaFile = nullptr;
439 
440  tools::PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
441  tools::Rectangle aPolyRect( aPolyPoly.GetBoundRect() );
442  tools::Rectangle aDstRect( Point(), GetOutputSizePixel() );
443 
444  aDstRect.Intersection( aPolyRect );
445 
446  ClipToPaintRegion( aDstRect );
447 
448  if( !aDstRect.IsEmpty() )
449  {
450  bool bDrawn = false;
451 
452  // debug helper:
453  static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA" );
454 
455  // #i66849# Added fast path for exactly rectangular
456  // polygons
457  // #i83087# Naturally, system alpha blending cannot
458  // work with separate alpha VDev
459  if( !mpAlphaVDev && !pDisableNative && aPolyPoly.IsRect() )
460  {
461  // setup Graphics only here (other cases delegate
462  // to basic OutDev methods)
463  if ( mbInitClipRegion )
464  InitClipRegion();
465 
466  if ( mbInitLineColor )
467  InitLineColor();
468 
469  if ( mbInitFillColor )
470  InitFillColor();
471 
472  tools::Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() );
473  tools::Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) );
474 
475  if( !mbOutputClipped )
476  {
477  bDrawn = mpGraphics->DrawAlphaRect( aPixelRect.Left(), aPixelRect.Top(),
478  // #i98405# use methods with small g, else one pixel too much will be painted.
479  // This is because the source is a polygon which when painted would not paint
480  // the rightmost and lowest pixel line(s), so use one pixel less for the
481  // rectangle, too.
482  aPixelRect.getWidth(), aPixelRect.getHeight(),
483  sal::static_int_cast<sal_uInt8>(nTransparencePercent),
484  this );
485  }
486  else
487  {
488  bDrawn = true;
489  }
490  }
491 
492  if( !bDrawn )
493  {
495  const Size aDstSz( aDstRect.GetSize() );
496  const sal_uInt8 cTrans = static_cast<sal_uInt8>(MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 ));
497 
498  if( aDstRect.Left() || aDstRect.Top() )
499  aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() );
500 
501  if( aVDev->SetOutputSizePixel( aDstSz ) )
502  {
503  const bool bOldMap = mbMap;
504 
505  EnableMapMode( false );
506 
507  aVDev->SetLineColor( COL_BLACK );
508  aVDev->SetFillColor( COL_BLACK );
509  aVDev->DrawPolyPolygon( aPolyPoly );
510 
511  Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) );
512  Bitmap aPolyMask( aVDev->GetBitmap( Point(), aDstSz ) );
513 
514  // #107766# check for non-empty bitmaps before accessing them
515  if( !!aPaint && !!aPolyMask )
516  {
517  BitmapScopedWriteAccess pW(aPaint);
518  Bitmap::ScopedReadAccess pR(aPolyMask);
519 
520  if( pW && pR )
521  {
522  BitmapColor aPixCol;
523  const BitmapColor aFillCol( GetFillColor() );
524  const BitmapColor aBlack( pR->GetBestMatchingColor( COL_BLACK ) );
525  const long nWidth = pW->Width();
526  const long nHeight = pW->Height();
527  const long nR = aFillCol.GetRed();
528  const long nG = aFillCol.GetGreen();
529  const long nB = aFillCol.GetBlue();
530  long nX, nY;
531 
532  if( aPaint.GetBitCount() <= 8 )
533  {
534  const BitmapPalette& rPal = pW->GetPalette();
535  const sal_uInt16 nCount = rPal.GetEntryCount();
536  BitmapColor* pMap = reinterpret_cast<BitmapColor*>(new sal_uInt8[ nCount * sizeof( BitmapColor ) ]);
537 
538  for( sal_uInt16 i = 0; i < nCount; i++ )
539  {
540  BitmapColor aCol( rPal[ i ] );
541  aCol.Merge( aFillCol, cTrans );
542  pMap[ i ] = BitmapColor( static_cast<sal_uInt8>(rPal.GetBestIndex( aCol )) );
543  }
544 
547  {
548  const sal_uInt8 cBlack = aBlack.GetIndex();
549 
550  for( nY = 0; nY < nHeight; nY++ )
551  {
552  Scanline pWScan = pW->GetScanline( nY );
553  Scanline pRScan = pR->GetScanline( nY );
554  sal_uInt8 cBit = 128;
555 
556  for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ )
557  {
558  if( !cBit )
559  {
560  cBit = 128;
561  pRScan += 1;
562  }
563  if( ( *pRScan & cBit ) == cBlack )
564  {
565  *pWScan = pMap[ *pWScan ].GetIndex();
566  }
567  }
568  }
569  }
570  else
571  {
572  for( nY = 0; nY < nHeight; nY++ )
573  {
574  Scanline pScanline = pW->GetScanline(nY);
575  Scanline pScanlineRead = pR->GetScanline(nY);
576  for( nX = 0; nX < nWidth; nX++ )
577  {
578  if( pR->GetPixelFromData( pScanlineRead, nX ) == aBlack )
579  {
580  pW->SetPixelOnData( pScanline, nX, pMap[ pW->GetIndexFromData( pScanline, nX ) ] );
581  }
582  }
583  }
584  }
585  delete[] reinterpret_cast<sal_uInt8*>(pMap);
586  }
587  else
588  {
591  {
592  const sal_uInt8 cBlack = aBlack.GetIndex();
593 
594  for( nY = 0; nY < nHeight; nY++ )
595  {
596  Scanline pWScan = pW->GetScanline( nY );
597  Scanline pRScan = pR->GetScanline( nY );
598  sal_uInt8 cBit = 128;
599 
600  for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 )
601  {
602  if( !cBit )
603  {
604  cBit = 128;
605  pRScan += 1;
606  }
607  if( ( *pRScan & cBit ) == cBlack )
608  {
609  pWScan[ 0 ] = ColorChannelMerge( pWScan[ 0 ], nB, cTrans );
610  pWScan[ 1 ] = ColorChannelMerge( pWScan[ 1 ], nG, cTrans );
611  pWScan[ 2 ] = ColorChannelMerge( pWScan[ 2 ], nR, cTrans );
612  }
613  }
614  }
615  }
616  else
617  {
618  for( nY = 0; nY < nHeight; nY++ )
619  {
620  Scanline pScanline = pW->GetScanline(nY);
621  Scanline pScanlineRead = pR->GetScanline(nY);
622  for( nX = 0; nX < nWidth; nX++ )
623  {
624  if( pR->GetPixelFromData( pScanlineRead, nX ) == aBlack )
625  {
626  aPixCol = pW->GetColor( nY, nX );
627  aPixCol.Merge(aFillCol, cTrans);
628  pW->SetPixelOnData(pScanline, nX, aPixCol);
629  }
630  }
631  }
632  }
633  }
634  }
635 
636  pR.reset();
637  pW.reset();
638 
639  DrawBitmap( aDstRect.TopLeft(), aPaint );
640 
641  EnableMapMode( bOldMap );
642 
643  if( mbLineColor )
644  {
646  SetFillColor();
647  DrawPolyPolygon( rPolyPoly );
648  Pop();
649  }
650  }
651  }
652  else
653  {
654  DrawPolyPolygon( rPolyPoly );
655  }
656  }
657  }
658 
659  mpMetaFile = pOldMetaFile;
660 
661  // #110958# Restore disabled alpha VDev
662  mpAlphaVDev = pOldAlphaVDev;
663 }
664 
666  sal_uInt16 nTransparencePercent )
667 {
669 
670  // short circuit for drawing an opaque polygon
671  if( (nTransparencePercent < 1) || (mnDrawMode & DrawModeFlags::NoTransparency) )
672  {
673  DrawPolyPolygon( rPolyPoly );
674  return;
675  }
676 
677  // short circuit for drawing an invisible polygon
678  if( !mbFillColor || (nTransparencePercent >= 100) )
679  {
680  DrawInvisiblePolygon( rPolyPoly );
681  return; // tdf#84294: do not record it in metafile
682  }
683 
684  // handle metafile recording
685  if( mpMetaFile )
686  mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
687 
688  bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
689  if( bDrawn )
690  return;
691 
692  // get the device graphics as drawing target
693  if( !mpGraphics && !AcquireGraphics() )
694  return;
695 
696  // try hard to draw it directly, because the emulation layers are slower
697  bDrawn = DrawTransparentNatively( rPolyPoly, nTransparencePercent );
698 
699  if (!bDrawn)
700  EmulateDrawTransparent( rPolyPoly, nTransparencePercent );
701 
702  // #110958# Apply alpha value also to VDev alpha channel
703  if( mpAlphaVDev )
704  {
705  const Color aFillCol( mpAlphaVDev->GetFillColor() );
706  mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
707  sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
708  sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) );
709 
710  mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent );
711 
712  mpAlphaVDev->SetFillColor( aFillCol );
713  }
714 }
715 
716 void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
717  const Size& rSize, const Gradient& rTransparenceGradient )
718 {
720 
721  const Color aBlack( COL_BLACK );
722 
723  if( mpMetaFile )
724  {
725  // missing here is to map the data using the DeviceTransformation
726  mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) );
727  }
728 
729  if ( !IsDeviceOutputNecessary() )
730  return;
731 
732  if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) ||
734  {
735  const_cast<GDIMetaFile&>(rMtf).WindStart();
736  const_cast<GDIMetaFile&>(rMtf).Play( this, rPos, rSize );
737  const_cast<GDIMetaFile&>(rMtf).WindStart();
738  }
739  else
740  {
741  GDIMetaFile* pOldMetaFile = mpMetaFile;
742  tools::Rectangle aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) );
743  Point aPoint;
744  tools::Rectangle aDstRect( aPoint, GetOutputSizePixel() );
745 
746  mpMetaFile = nullptr;
747  aDstRect.Intersection( aOutRect );
748 
749  ClipToPaintRegion( aDstRect );
750 
751  if( !aDstRect.IsEmpty() )
752  {
754 
755  xVDev->mnDPIX = mnDPIX;
756  xVDev->mnDPIY = mnDPIY;
757 
758  if( xVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
759  {
761  {
762  // #i102109#
763  // For MetaFile replay (see task) it may now be necessary to take
764  // into account that the content is AntiAlialiased and needs to be masked
765  // like that. Instead of masking, i will use a copy-modify-paste cycle
766  // here (as i already use in the VclPrimiziveRenderer with success)
767  xVDev->SetAntialiasing(GetAntialiasing());
768 
769  // create MapMode for buffer (offset needed) and set
771  const Point aOutPos(PixelToLogic(aDstRect.TopLeft()));
772  aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y()));
773  xVDev->SetMapMode(aMap);
774 
775  // copy MapMode state and disable for target
776  const bool bOrigMapModeEnabled(IsMapModeEnabled());
777  EnableMapMode(false);
778 
779  // copy MapMode state and disable for buffer
780  const bool bBufferMapModeEnabled(xVDev->IsMapModeEnabled());
781  xVDev->EnableMapMode(false);
782 
783  // copy content from original to buffer
784  xVDev->DrawOutDev( aPoint, xVDev->GetOutputSizePixel(), // dest
785  aDstRect.TopLeft(), xVDev->GetOutputSizePixel(), // source
786  *this);
787 
788  // draw MetaFile to buffer
789  xVDev->EnableMapMode(bBufferMapModeEnabled);
790  const_cast<GDIMetaFile&>(rMtf).WindStart();
791  const_cast<GDIMetaFile&>(rMtf).Play(xVDev.get(), rPos, rSize);
792  const_cast<GDIMetaFile&>(rMtf).WindStart();
793 
794  // get content bitmap from buffer
795  xVDev->EnableMapMode(false);
796 
797  const Bitmap aPaint(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
798 
799  // create alpha mask from gradient and get as Bitmap
800  xVDev->EnableMapMode(bBufferMapModeEnabled);
801  xVDev->SetDrawMode(DrawModeFlags::GrayGradient);
802  xVDev->DrawGradient(tools::Rectangle(rPos, rSize), rTransparenceGradient);
803  xVDev->SetDrawMode(DrawModeFlags::Default);
804  xVDev->EnableMapMode(false);
805 
806  const AlphaMask aAlpha(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
807 
808  xVDev.disposeAndClear();
809 
810  // draw masked content to target and restore MapMode
811  DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
812  EnableMapMode(bOrigMapModeEnabled);
813  }
814  else
815  {
816  Bitmap aPaint, aMask;
817  AlphaMask aAlpha;
818  MapMode aMap( GetMapMode() );
819  Point aOutPos( PixelToLogic( aDstRect.TopLeft() ) );
820  const bool bOldMap = mbMap;
821 
822  aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) );
823  xVDev->SetMapMode( aMap );
824  const bool bVDevOldMap = xVDev->IsMapModeEnabled();
825 
826  // create paint bitmap
827  const_cast<GDIMetaFile&>(rMtf).WindStart();
828  const_cast<GDIMetaFile&>(rMtf).Play( xVDev.get(), rPos, rSize );
829  const_cast<GDIMetaFile&>(rMtf).WindStart();
830  xVDev->EnableMapMode( false );
831  aPaint = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
832  xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
833 
834  // create mask bitmap
835  xVDev->SetLineColor( COL_BLACK );
836  xVDev->SetFillColor( COL_BLACK );
837  xVDev->DrawRect( tools::Rectangle( xVDev->PixelToLogic( Point() ), xVDev->GetOutputSize() ) );
840  const_cast<GDIMetaFile&>(rMtf).WindStart();
841  const_cast<GDIMetaFile&>(rMtf).Play( xVDev.get(), rPos, rSize );
842  const_cast<GDIMetaFile&>(rMtf).WindStart();
843  xVDev->EnableMapMode( false );
844  aMask = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
845  xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
846 
847  // create alpha mask from gradient
848  xVDev->SetDrawMode( DrawModeFlags::GrayGradient );
849  xVDev->DrawGradient( tools::Rectangle( rPos, rSize ), rTransparenceGradient );
850  xVDev->SetDrawMode( DrawModeFlags::Default );
851  xVDev->EnableMapMode( false );
852  xVDev->DrawMask( Point(), xVDev->GetOutputSizePixel(), aMask, COL_WHITE );
853 
854  aAlpha = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
855 
856  xVDev.disposeAndClear();
857 
858  EnableMapMode( false );
859  DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) );
860  EnableMapMode( bOldMap );
861  }
862  }
863  }
864 
865  mpMetaFile = pOldMetaFile;
866  }
867 }
868 
869 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Point TopLeft() const
long Width() const
long GetWidth() const
sal_uInt8 GetIndex() const
Definition: BitmapColor.hxx:61
long GetHeight() const
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
sal_uInt8 GetRed() const
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:641
double getHeight() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
long FRound(double fVal)
Scanline GetScanline(long nY) const
DrawModeFlags
Definition: outdev.hxx:198
virtual void ClipToPaintRegion(tools::Rectangle &rDstRect)
void Merge(const Color &rMergeColor, sal_uInt8 cTransparency)
long Height() const
void setClosed(bool bNew)
void DrawBitmapEx(const Point &rDestPt, const BitmapEx &rBitmapEx)
This is an overloaded member function, provided for convenience. It differs from the above function o...
virtual bool supportsOperation(OutDevSupportType) const =0
DrawModeFlags mnDrawMode
Definition: outdev.hxx:353
void disposeAndClear()
Definition: vclptr.hxx:200
const StyleSettings & GetStyleSettings() const
sal_uInt8 GetLuminance() const
bool IsMapModeEnabled() const
Definition: outdev.hxx:1671
bool mbOutputClipped
Definition: outdev.hxx:379
SAL_DLLPRIVATE bool is_double_buffered_window() const
const MapMode & GetMapMode() const
Definition: outdev.hxx:1677
sal_Int32 mnDPIY
Definition: outdev.hxx:346
SAL_DLLPRIVATE Color ImplDrawModeToColor(const Color &rColor) const
Definition: transparent.cxx:79
bool ImplIsColorTransparent(Color aColor)
Definition: outdata.hxx:25
sal_Int32 mnDPIX
Definition: outdev.hxx:345
void EnableMapMode(bool bEnable=true)
Definition: map.cxx:647
Size GetSizePixel() const
long Width() const
bool mbMap
Definition: outdev.hxx:374
AntialiasingFlags GetAntialiasing() const
Definition: outdev.hxx:604
std::vector< tools::Rectangle > RectangleVector
Definition: region.hxx:37
bool IsEmpty() const
HashMap_OWString_Interface aMap
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
SAL_DLLPRIVATE void InitLineColor()
bool Mirror(BmpMirrorFlags nMirrorFlags)
Mirror the bitmap.
double getWidth() const
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
int nCount
AntialiasingFlags mnAntialiasing
Definition: outdev.hxx:371
virtual Bitmap GetBitmap(const Point &rSrcPt, const Size &rSize) const
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
void SetPixelOnData(sal_uInt8 *pData, long nX, const BitmapColor &rBitmapColor)
void DrawInvisiblePolygon(const tools::PolyPolygon &rPolyPoly)
sal_uInt8 GetBlue() const
SAL_DLLPRIVATE void ImplPrintTransparent(const Bitmap &rBmp, const Bitmap &rMask, const Point &rDestPt, const Size &rDestSize, const Point &rSrcPtPixel, const Size &rSrcSizePixel)
void DrawPolyLine(sal_uInt32 nPoints, SalPoint const *pPtAry, const OutputDevice *pOutDev)
void DrawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32 *pPoints, PCONSTSALPOINT *pPtAry, const OutputDevice *pOutDev)
void Move(long nHorzMove, long nVertMove)
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:314
SAL_DLLPRIVATE bool DrawTransparentNatively(const tools::PolyPolygon &rPolyPoly, sal_uInt16 nTransparencePercent)
SAL_DLLPRIVATE basegfx::B2DHomMatrix ImplGetDeviceTransformation() const
Get device transformation.
Definition: map.cxx:933
virtual void SetFillColor()=0
sal_uInt16 GetEntryCount() const
virtual void EmulateDrawTransparent(const tools::PolyPolygon &rPolyPoly, sal_uInt16 nTransparencePercent)
void SetLineColor()
SAL_DLLPRIVATE void InitFillColor()
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
constexpr sal_uInt8 ColorChannelMerge(sal_uInt8 nDst, sal_uInt8 nSrc, sal_uInt8 nSrcTrans)
bool isClosed() const
int i
ScanlineFormat GetScanlineFormat() const
bool IsLineColor() const
Definition: outdev.hxx:631
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
bool IsRect() const
void DrawTransparent(const tools::PolyPolygon &rPolyPoly, sal_uInt16 nTransparencePercent)
void SetOrigin(const Point &rOrigin)
Definition: mapmod.cxx:102
bool mbInitLineColor
Definition: outdev.hxx:382
void SetFillColor()
const Color & GetFontColor() const
const Color & GetLineColor() const
Definition: outdev.hxx:630
void transform(const basegfx::B2DHomMatrix &rMatrix)
vcl::Region CreateRegion(const Color &rColor, const tools::Rectangle &rRect) const
Create region of similar colors in a given rectangle.
BmpMirrorFlags
Definition: bitmap.hxx:36
bool mbLineColor
Definition: outdev.hxx:380
constexpr double deg2rad(double v)
const AllSettings & GetSettings() const
Definition: outdev.hxx:418
Size GetOutputSizePixel() const
Definition: outdev.hxx:441
virtual sal_uInt16 GetBitCount() const
Definition: outdev.cxx:305
DrawModeFlags GetDrawMode() const
Definition: outdev.hxx:607
void DrawBitmap(const Point &rDestPt, const Bitmap &rBitmap)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Size GetSize() const
sal_uInt16 GetBestIndex(const BitmapColor &rCol) const
const Color & GetStartColor() const
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1187
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:942
sal_uInt8 GetGreen() const
B2DRange const & getB2DRange() const
bool mbFillColor
Definition: outdev.hxx:381
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:329
def rectangle(l)
double getMinY() const
sal_uInt32 count() const
::basegfx::B2DPolyPolygon getB2DPolyPolygon() const
long Height() const
unsigned char sal_uInt8
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: bitmap3.cxx:229
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:566
BitmapColor GetColor(long nY, long nX) const
bool mbInitClipRegion
Definition: outdev.hxx:386
const BitmapPalette & GetPalette() const
void GetRegionRectangles(RectangleVector &rTarget) const
Definition: region.cxx:1659
const Color & GetEndColor() const
void DrawPolyPolygon(const tools::PolyPolygon &rPolyPoly)
Render the given poly-polygon.
Definition: polygon.cxx:36
virtual void InitClipRegion()
bool IsEmpty() const
Definition: bitmap.hxx:551
RasterOp GetRasterOp() const
Definition: outdev.hxx:616
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
BitmapColor GetPixelFromData(const sal_uInt8 *pData, long nX) const
bool mbInitFillColor
Definition: outdev.hxx:383
bool Erase(const Color &rFillColor)
Fill the entire bitmap with the given color.
Definition: bitmappaint.cxx:34
SAL_DLLPRIVATE tools::Rectangle ImplLogicToDevicePixel(const tools::Rectangle &rLogicRect) const
Convert a logical rectangle to a rectangle in physical device pixel units.
Definition: map.cxx:504
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
tools::Rectangle GetBoundRect() const
double getMinX() const
bool IsFillColor() const
Definition: outdev.hxx:636
sal_uInt16 GetBitCount() const
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, long nMin, long nMax)
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:601
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:60
void setWidth(long nWidth)
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor)
const Color & GetFillColor() const
Definition: outdev.hxx:635
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:317
bool DrawAlphaRect(long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency, const OutputDevice *pOutDev)
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, long nX) const
void setHeight(long nHeight)
void Insert(sal_uInt16 nPos, const Point &rPt)