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 {
213  assert(!is_double_buffered_window());
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  bool bDrawnOk(true);
252 
253  if( IsFillColor() )
254  {
255  bDrawnOk = mpGraphics->DrawPolyPolygon(
256  aFullTransform,
257  aB2DPolyPolygon,
258  fTransparency,
259  this);
260  }
261 
262  if( bDrawnOk && IsLineColor() )
263  {
264  const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
265 
266  for(auto const& rPolygon : aB2DPolyPolygon)
267  {
269  aFullTransform,
270  rPolygon,
271  fTransparency,
272  0.0, // tdf#124848 hairline
273  nullptr, // MM01
275  css::drawing::LineCap_BUTT,
276  basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
277  bPixelSnapHairline,
278  this );
279  }
280  }
281 
282  if( bDrawnOk )
283  {
284  if( mpMetaFile )
285  {
286  // tdf#119843 need transformed Polygon here
287  basegfx::B2DPolyPolygon aB2DPolyPoly(rB2DPolyPoly);
288  aB2DPolyPoly.transform(rObjectTransform);
291  tools::PolyPolygon(aB2DPolyPoly),
292  static_cast< sal_uInt16 >(fTransparency * 100.0)));
293  }
294 
295  return;
296  }
297  }
298 
299  // fallback to old polygon drawing if needed
300  // tdf#119843 need transformed Polygon here
301  basegfx::B2DPolyPolygon aB2DPolyPoly(rB2DPolyPoly);
302  aB2DPolyPoly.transform(rObjectTransform);
304  toPolyPolygon(aB2DPolyPoly),
305  static_cast<sal_uInt16>(fTransparency * 100.0));
306 }
307 
309 {
310  assert(!is_double_buffered_window());
311 
312  // short circuit if the polygon border is invisible too
313  if( !mbLineColor )
314  return;
315 
316  // we assume that the border is NOT to be drawn transparently???
318  SetFillColor();
319  DrawPolyPolygon( rPolyPoly );
320  Pop();
321 }
322 
324  sal_uInt16 nTransparencePercent )
325 {
326  assert(!is_double_buffered_window());
327 
328  bool bDrawn = false;
329 
330  // debug helper:
331  static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
332 
333  if( !pDisableNative &&
335 #if defined UNX && ! defined MACOSX && ! defined IOS
336  && GetBitCount() > 8
337 #endif
338 #ifdef _WIN32
339  // workaround bad dithering on remote displaying when using GDI+ with toolbar button highlighting
340  && !rPolyPoly.IsRect()
341 #endif
342  )
343  {
344  // prepare the graphics device
345  if( mbInitClipRegion )
346  InitClipRegion();
347 
348  if( mbOutputClipped )
349  return false;
350 
351  if( mbInitLineColor )
352  InitLineColor();
353 
354  if( mbInitFillColor )
355  InitFillColor();
356 
357  // get the polygon in device coordinates
358  basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
360 
361  const double fTransparency = 0.01 * nTransparencePercent;
362  if( mbFillColor )
363  {
364  // #i121591#
365  // CAUTION: Only non printing (pixel-renderer) VCL commands from OutputDevices
366  // should be used when printing. Normally this is avoided by the printer being
367  // non-AAed and thus e.g. on WIN GdiPlus calls are not used. It may be necessary
368  // to figure out a way of moving this code to its own function that is
369  // overridden by the Print class, which will mean we deliberately override the
370  // functionality and we use the fallback some lines below (which is not very good,
371  // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and
372  // correct the wrong mapping (see there for details)
373  bDrawn = mpGraphics->DrawPolyPolygon(
374  aTransform,
375  aB2DPolyPolygon,
376  fTransparency,
377  this);
378  }
379 
380  if( mbLineColor )
381  {
382  // disable the fill color for now
384 
385  // draw the border line
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  0.0, // tdf#124848 hairline
395  nullptr, // MM01
397  css::drawing::LineCap_BUTT,
398  basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
399  bPixelSnapHairline,
400  this );
401  }
402 
403  // prepare to restore the fill color
405  }
406  }
407 
408  return bDrawn;
409 }
410 
412  sal_uInt16 nTransparencePercent )
413 {
414  // #110958# Disable alpha VDev, we perform the necessary
415  VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
416 
417  // operation explicitly further below.
418  if( mpAlphaVDev )
419  mpAlphaVDev = nullptr;
420 
421  GDIMetaFile* pOldMetaFile = mpMetaFile;
422  mpMetaFile = nullptr;
423 
424  tools::PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
425  tools::Rectangle aPolyRect( aPolyPoly.GetBoundRect() );
426  tools::Rectangle aDstRect( Point(), GetOutputSizePixel() );
427 
428  aDstRect.Intersection( aPolyRect );
429 
430  ClipToPaintRegion( aDstRect );
431 
432  if( !aDstRect.IsEmpty() )
433  {
434  bool bDrawn = false;
435 
436  // debug helper:
437  static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA" );
438 
439  // #i66849# Added fast path for exactly rectangular
440  // polygons
441  // #i83087# Naturally, system alpha blending cannot
442  // work with separate alpha VDev
443  if( !mpAlphaVDev && !pDisableNative && aPolyPoly.IsRect() )
444  {
445  // setup Graphics only here (other cases delegate
446  // to basic OutDev methods)
447  if ( mbInitClipRegion )
448  InitClipRegion();
449 
450  if ( mbInitLineColor )
451  InitLineColor();
452 
453  if ( mbInitFillColor )
454  InitFillColor();
455 
456  tools::Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() );
457  tools::Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) );
458 
459  if( !mbOutputClipped )
460  {
461  bDrawn = mpGraphics->DrawAlphaRect( aPixelRect.Left(), aPixelRect.Top(),
462  // #i98405# use methods with small g, else one pixel too much will be painted.
463  // This is because the source is a polygon which when painted would not paint
464  // the rightmost and lowest pixel line(s), so use one pixel less for the
465  // rectangle, too.
466  aPixelRect.getWidth(), aPixelRect.getHeight(),
467  sal::static_int_cast<sal_uInt8>(nTransparencePercent),
468  this );
469  }
470  else
471  {
472  bDrawn = true;
473  }
474  }
475 
476  if( !bDrawn )
477  {
479  const Size aDstSz( aDstRect.GetSize() );
480  const sal_uInt8 cTrans = static_cast<sal_uInt8>(MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 ));
481 
482  if( aDstRect.Left() || aDstRect.Top() )
483  aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() );
484 
485  if( aVDev->SetOutputSizePixel( aDstSz ) )
486  {
487  const bool bOldMap = mbMap;
488 
489  EnableMapMode( false );
490 
491  aVDev->SetLineColor( COL_BLACK );
492  aVDev->SetFillColor( COL_BLACK );
493  aVDev->DrawPolyPolygon( aPolyPoly );
494 
495  Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) );
496  Bitmap aPolyMask( aVDev->GetBitmap( Point(), aDstSz ) );
497 
498  // #107766# check for non-empty bitmaps before accessing them
499  if( !!aPaint && !!aPolyMask )
500  {
501  BitmapScopedWriteAccess pW(aPaint);
502  Bitmap::ScopedReadAccess pR(aPolyMask);
503 
504  if( pW && pR )
505  {
506  BitmapColor aPixCol;
507  const BitmapColor aFillCol( GetFillColor() );
508  const BitmapColor aBlack( pR->GetBestMatchingColor( COL_BLACK ) );
509  const long nWidth = pW->Width();
510  const long nHeight = pW->Height();
511  const long nR = aFillCol.GetRed();
512  const long nG = aFillCol.GetGreen();
513  const long nB = aFillCol.GetBlue();
514  long nX, nY;
515 
516  if( aPaint.GetBitCount() <= 8 )
517  {
518  const BitmapPalette& rPal = pW->GetPalette();
519  const sal_uInt16 nCount = rPal.GetEntryCount();
520  BitmapColor* pMap = reinterpret_cast<BitmapColor*>(new sal_uInt8[ nCount * sizeof( BitmapColor ) ]);
521 
522  for( sal_uInt16 i = 0; i < nCount; i++ )
523  {
524  BitmapColor aCol( rPal[ i ] );
525  aCol.Merge( aFillCol, cTrans );
526  pMap[ i ] = BitmapColor( static_cast<sal_uInt8>(rPal.GetBestIndex( aCol )) );
527  }
528 
531  {
532  const sal_uInt8 cBlack = aBlack.GetIndex();
533 
534  for( nY = 0; nY < nHeight; nY++ )
535  {
536  Scanline pWScan = pW->GetScanline( nY );
537  Scanline pRScan = pR->GetScanline( nY );
538  sal_uInt8 cBit = 128;
539 
540  for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ )
541  {
542  if( !cBit )
543  {
544  cBit = 128;
545  pRScan += 1;
546  }
547  if( ( *pRScan & cBit ) == cBlack )
548  {
549  *pWScan = pMap[ *pWScan ].GetIndex();
550  }
551  }
552  }
553  }
554  else
555  {
556  for( nY = 0; nY < nHeight; nY++ )
557  {
558  Scanline pScanline = pW->GetScanline(nY);
559  Scanline pScanlineRead = pR->GetScanline(nY);
560  for( nX = 0; nX < nWidth; nX++ )
561  {
562  if( pR->GetPixelFromData( pScanlineRead, nX ) == aBlack )
563  {
564  pW->SetPixelOnData( pScanline, nX, pMap[ pW->GetIndexFromData( pScanline, nX ) ] );
565  }
566  }
567  }
568  }
569  delete[] reinterpret_cast<sal_uInt8*>(pMap);
570  }
571  else
572  {
575  {
576  const sal_uInt8 cBlack = aBlack.GetIndex();
577 
578  for( nY = 0; nY < nHeight; nY++ )
579  {
580  Scanline pWScan = pW->GetScanline( nY );
581  Scanline pRScan = pR->GetScanline( nY );
582  sal_uInt8 cBit = 128;
583 
584  for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 )
585  {
586  if( !cBit )
587  {
588  cBit = 128;
589  pRScan += 1;
590  }
591  if( ( *pRScan & cBit ) == cBlack )
592  {
593  pWScan[ 0 ] = ColorChannelMerge( pWScan[ 0 ], nB, cTrans );
594  pWScan[ 1 ] = ColorChannelMerge( pWScan[ 1 ], nG, cTrans );
595  pWScan[ 2 ] = ColorChannelMerge( pWScan[ 2 ], nR, cTrans );
596  }
597  }
598  }
599  }
600  else
601  {
602  for( nY = 0; nY < nHeight; nY++ )
603  {
604  Scanline pScanline = pW->GetScanline(nY);
605  Scanline pScanlineRead = pR->GetScanline(nY);
606  for( nX = 0; nX < nWidth; nX++ )
607  {
608  if( pR->GetPixelFromData( pScanlineRead, nX ) == aBlack )
609  {
610  aPixCol = pW->GetColor( nY, nX );
611  aPixCol.Merge(aFillCol, cTrans);
612  pW->SetPixelOnData(pScanline, nX, aPixCol);
613  }
614  }
615  }
616  }
617  }
618  }
619 
620  pR.reset();
621  pW.reset();
622 
623  DrawBitmap( aDstRect.TopLeft(), aPaint );
624 
625  EnableMapMode( bOldMap );
626 
627  if( mbLineColor )
628  {
630  SetFillColor();
631  DrawPolyPolygon( rPolyPoly );
632  Pop();
633  }
634  }
635  }
636  else
637  {
638  DrawPolyPolygon( rPolyPoly );
639  }
640  }
641  }
642 
643  mpMetaFile = pOldMetaFile;
644 
645  // #110958# Restore disabled alpha VDev
646  mpAlphaVDev = pOldAlphaVDev;
647 }
648 
650  sal_uInt16 nTransparencePercent )
651 {
652  assert(!is_double_buffered_window());
653 
654  // short circuit for drawing an opaque polygon
655  if( (nTransparencePercent < 1) || (mnDrawMode & DrawModeFlags::NoTransparency) )
656  {
657  DrawPolyPolygon( rPolyPoly );
658  return;
659  }
660 
661  // short circuit for drawing an invisible polygon
662  if( !mbFillColor || (nTransparencePercent >= 100) )
663  {
664  DrawInvisiblePolygon( rPolyPoly );
665  return; // tdf#84294: do not record it in metafile
666  }
667 
668  // handle metafile recording
669  if( mpMetaFile )
670  mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
671 
672  bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
673  if( bDrawn )
674  return;
675 
676  // get the device graphics as drawing target
677  if( !mpGraphics && !AcquireGraphics() )
678  return;
679 
680  // try hard to draw it directly, because the emulation layers are slower
681  bDrawn = DrawTransparentNatively( rPolyPoly, nTransparencePercent );
682  if( bDrawn )
683  return;
684 
685  EmulateDrawTransparent( rPolyPoly, nTransparencePercent );
686 
687  // #110958# Apply alpha value also to VDev alpha channel
688  if( mpAlphaVDev )
689  {
690  const Color aFillCol( mpAlphaVDev->GetFillColor() );
691  mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
692  sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
693  sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) );
694 
695  mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent );
696 
697  mpAlphaVDev->SetFillColor( aFillCol );
698  }
699 }
700 
701 void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
702  const Size& rSize, const Gradient& rTransparenceGradient )
703 {
704  assert(!is_double_buffered_window());
705 
706  const Color aBlack( COL_BLACK );
707 
708  if( mpMetaFile )
709  {
710  // missing here is to map the data using the DeviceTransformation
711  mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) );
712  }
713 
714  if ( !IsDeviceOutputNecessary() )
715  return;
716 
717  if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) ||
719  {
720  const_cast<GDIMetaFile&>(rMtf).WindStart();
721  const_cast<GDIMetaFile&>(rMtf).Play( this, rPos, rSize );
722  const_cast<GDIMetaFile&>(rMtf).WindStart();
723  }
724  else
725  {
726  GDIMetaFile* pOldMetaFile = mpMetaFile;
727  tools::Rectangle aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) );
728  Point aPoint;
729  tools::Rectangle aDstRect( aPoint, GetOutputSizePixel() );
730 
731  mpMetaFile = nullptr;
732  aDstRect.Intersection( aOutRect );
733 
734  ClipToPaintRegion( aDstRect );
735 
736  if( !aDstRect.IsEmpty() )
737  {
739 
740  xVDev->mnDPIX = mnDPIX;
741  xVDev->mnDPIY = mnDPIY;
742 
743  if( xVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
744  {
746  {
747  // #i102109#
748  // For MetaFile replay (see task) it may now be necessary to take
749  // into account that the content is AntiAlialiased and needs to be masked
750  // like that. Instead of masking, i will use a copy-modify-paste cycle
751  // here (as i already use in the VclPrimiziveRenderer with success)
752  xVDev->SetAntialiasing(GetAntialiasing());
753 
754  // create MapMode for buffer (offset needed) and set
756  const Point aOutPos(PixelToLogic(aDstRect.TopLeft()));
757  aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y()));
758  xVDev->SetMapMode(aMap);
759 
760  // copy MapMode state and disable for target
761  const bool bOrigMapModeEnabled(IsMapModeEnabled());
762  EnableMapMode(false);
763 
764  // copy MapMode state and disable for buffer
765  const bool bBufferMapModeEnabled(xVDev->IsMapModeEnabled());
766  xVDev->EnableMapMode(false);
767 
768  // copy content from original to buffer
769  xVDev->DrawOutDev( aPoint, xVDev->GetOutputSizePixel(), // dest
770  aDstRect.TopLeft(), xVDev->GetOutputSizePixel(), // source
771  *this);
772 
773  // draw MetaFile to buffer
774  xVDev->EnableMapMode(bBufferMapModeEnabled);
775  const_cast<GDIMetaFile&>(rMtf).WindStart();
776  const_cast<GDIMetaFile&>(rMtf).Play(xVDev.get(), rPos, rSize);
777  const_cast<GDIMetaFile&>(rMtf).WindStart();
778 
779  // get content bitmap from buffer
780  xVDev->EnableMapMode(false);
781 
782  const Bitmap aPaint(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
783 
784  // create alpha mask from gradient and get as Bitmap
785  xVDev->EnableMapMode(bBufferMapModeEnabled);
786  xVDev->SetDrawMode(DrawModeFlags::GrayGradient);
787  xVDev->DrawGradient(tools::Rectangle(rPos, rSize), rTransparenceGradient);
788  xVDev->SetDrawMode(DrawModeFlags::Default);
789  xVDev->EnableMapMode(false);
790 
791  const AlphaMask aAlpha(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
792 
793  xVDev.disposeAndClear();
794 
795  // draw masked content to target and restore MapMode
796  DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
797  EnableMapMode(bOrigMapModeEnabled);
798  }
799  else
800  {
801  Bitmap aPaint, aMask;
802  AlphaMask aAlpha;
803  MapMode aMap( GetMapMode() );
804  Point aOutPos( PixelToLogic( aDstRect.TopLeft() ) );
805  const bool bOldMap = mbMap;
806 
807  aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) );
808  xVDev->SetMapMode( aMap );
809  const bool bVDevOldMap = xVDev->IsMapModeEnabled();
810 
811  // create paint bitmap
812  const_cast<GDIMetaFile&>(rMtf).WindStart();
813  const_cast<GDIMetaFile&>(rMtf).Play( xVDev.get(), rPos, rSize );
814  const_cast<GDIMetaFile&>(rMtf).WindStart();
815  xVDev->EnableMapMode( false );
816  aPaint = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
817  xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
818 
819  // create mask bitmap
820  xVDev->SetLineColor( COL_BLACK );
821  xVDev->SetFillColor( COL_BLACK );
822  xVDev->DrawRect( tools::Rectangle( xVDev->PixelToLogic( Point() ), xVDev->GetOutputSize() ) );
825  const_cast<GDIMetaFile&>(rMtf).WindStart();
826  const_cast<GDIMetaFile&>(rMtf).Play( xVDev.get(), rPos, rSize );
827  const_cast<GDIMetaFile&>(rMtf).WindStart();
828  xVDev->EnableMapMode( false );
829  aMask = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
830  xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
831 
832  // create alpha mask from gradient
833  xVDev->SetDrawMode( DrawModeFlags::GrayGradient );
834  xVDev->DrawGradient( tools::Rectangle( rPos, rSize ), rTransparenceGradient );
835  xVDev->SetDrawMode( DrawModeFlags::Default );
836  xVDev->EnableMapMode( false );
837  xVDev->DrawMask( Point(), xVDev->GetOutputSizePixel(), aMask, COL_WHITE );
838 
839  aAlpha = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
840 
841  xVDev.disposeAndClear();
842 
843  EnableMapMode( false );
844  DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) );
845  EnableMapMode( bOldMap );
846  }
847  }
848  }
849 
850  mpMetaFile = pOldMetaFile;
851  }
852 }
853 
854 /* 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:650
double getHeight() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
long FRound(double fVal)
Scanline GetScanline(long nY) const
DrawModeFlags
Definition: outdev.hxx:200
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:1676
bool mbOutputClipped
Definition: outdev.hxx:381
SAL_DLLPRIVATE bool is_double_buffered_window() const
const MapMode & GetMapMode() const
Definition: outdev.hxx:1681
sal_Int32 mnDPIY
Definition: outdev.hxx:348
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: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:598
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
int nCount
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:925
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
int i
ScanlineFormat GetScanlineFormat() const
bool IsLineColor() const
Definition: outdev.hxx:625
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: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:601
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:1179
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:934
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:229
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:543
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
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:550
RasterOp GetRasterOp() const
Definition: outdev.hxx:610
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:630
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:595
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:629
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:319
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)