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