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