LibreOffice Module vcl (master)  1
outdev/bitmap.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <vcl/bitmap.hxx>
23 #include <vcl/bitmapex.hxx>
24 #include <vcl/bitmapaccess.hxx>
25 #include <vcl/canvastools.hxx>
26 #include <vcl/gdimtf.hxx>
27 #include <vcl/metaact.hxx>
28 #include <config_features.h>
29 #if HAVE_FEATURE_OPENGL
31 #endif
32 #include <vcl/outdev.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vcl/image.hxx>
36 
37 #include <bmpfast.hxx>
38 #include <salgdi.hxx>
39 #include <salbmp.hxx>
40 
42 #include <memory>
43 #include <comphelper/lok.hxx>
44 #include <bitmapwriteaccess.hxx>
45 #include <sal/log.hxx>
46 #include <osl/diagnose.h>
47 #include <tools/helpers.hxx>
48 #include <tools/debug.hxx>
49 
50 void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
51 {
52  assert(!is_double_buffered_window());
53 
54  const Size aSizePix( rBitmap.GetSizePixel() );
55  DrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, MetaActionType::BMP );
56 }
57 
58 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
59 {
60  assert(!is_double_buffered_window());
61 
62  DrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, MetaActionType::BMPSCALE );
63 }
64 
65 
66 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize,
67  const Point& rSrcPtPixel, const Size& rSrcSizePixel,
68  const Bitmap& rBitmap, const MetaActionType nAction )
69 {
70  assert(!is_double_buffered_window());
71 
72  if( ImplIsRecordLayout() )
73  return;
74 
76  {
77  DrawRect( tools::Rectangle( rDestPt, rDestSize ) );
78  return;
79  }
80 
81  Bitmap aBmp( rBitmap );
82 
85  {
87  {
88  sal_uInt8 cCmpVal;
89 
91  cCmpVal = 0;
92  else
93  cCmpVal = 255;
94 
95  Color aCol( cCmpVal, cCmpVal, cCmpVal );
97  SetLineColor( aCol );
98  SetFillColor( aCol );
99  DrawRect( tools::Rectangle( rDestPt, rDestSize ) );
100  Pop();
101  return;
102  }
103  else if( !!aBmp )
104  {
107  }
108  }
109 
110  if ( mpMetaFile )
111  {
112  switch( nAction )
113  {
114  case MetaActionType::BMP:
115  mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) );
116  break;
117 
119  mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
120  break;
121 
124  rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) );
125  break;
126 
127  default: break;
128  }
129  }
130 
131  if ( !IsDeviceOutputNecessary() )
132  return;
133 
134  if ( !mpGraphics && !AcquireGraphics() )
135  return;
136 
137  if ( mbInitClipRegion )
138  InitClipRegion();
139 
140  if ( mbOutputClipped )
141  return;
142 
143  if( !aBmp.IsEmpty() )
144  {
145  SalTwoRect aPosAry(rSrcPtPixel.X(), rSrcPtPixel.Y(), rSrcSizePixel.Width(), rSrcSizePixel.Height(),
146  ImplLogicXToDevicePixel(rDestPt.X()), ImplLogicYToDevicePixel(rDestPt.Y()),
147  ImplLogicWidthToDevicePixel(rDestSize.Width()),
148  ImplLogicHeightToDevicePixel(rDestSize.Height()));
149 
150  if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
151  {
152  const BmpMirrorFlags nMirrFlags = AdjustTwoRect( aPosAry, aBmp.GetSizePixel() );
153 
154  if ( nMirrFlags != BmpMirrorFlags::NONE )
155  aBmp.Mirror( nMirrFlags );
156 
157  if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
158  {
159  if ( nAction == MetaActionType::BMPSCALE )
160  ScaleBitmap (aBmp, aPosAry);
161 
162  mpGraphics->DrawBitmap( aPosAry, *aBmp.ImplGetSalBitmap(), this );
163  }
164  }
165  }
166 
167  if( mpAlphaVDev )
168  {
169  // #i32109#: Make bitmap area opaque
170  mpAlphaVDev->ImplFillOpaqueRectangle( tools::Rectangle(rDestPt, rDestSize) );
171  }
172 }
173 
175  const Point& rSrcPt, const Size& rSrcSz,
176  const Bitmap& rBmp, long nMaxBmpDPIX, long nMaxBmpDPIY )
177 {
178  Bitmap aBmp( rBmp );
179 
180  if( !aBmp.IsEmpty() )
181  {
182  const tools::Rectangle aBmpRect( Point(), aBmp.GetSizePixel() );
183  tools::Rectangle aSrcRect( rSrcPt, rSrcSz );
184 
185  // do cropping if necessary
186  if( aSrcRect.Intersection( aBmpRect ) != aBmpRect )
187  {
188  if( !aSrcRect.IsEmpty() )
189  aBmp.Crop( aSrcRect );
190  else
191  aBmp.SetEmpty();
192  }
193 
194  if( !aBmp.IsEmpty() )
195  {
196  // do downsampling if necessary
197  Size aDstSizeTwip( PixelToLogic(LogicToPixel(rDstSz), MapMode(MapUnit::MapTwip)) );
198 
199  // #103209# Normalize size (mirroring has to happen outside of this method)
200  aDstSizeTwip = Size( labs(aDstSizeTwip.Width()), labs(aDstSizeTwip.Height()) );
201 
202  const Size aBmpSize( aBmp.GetSizePixel() );
203  const double fBmpPixelX = aBmpSize.Width();
204  const double fBmpPixelY = aBmpSize.Height();
205  const double fMaxPixelX = aDstSizeTwip.Width() * nMaxBmpDPIX / 1440.0;
206  const double fMaxPixelY = aDstSizeTwip.Height() * nMaxBmpDPIY / 1440.0;
207 
208  // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
209  if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
210  ( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) &&
211  ( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) )
212  {
213  // do scaling
214  Size aNewBmpSize;
215  const double fBmpWH = fBmpPixelX / fBmpPixelY;
216  const double fMaxWH = fMaxPixelX / fMaxPixelY;
217 
218  if( fBmpWH < fMaxWH )
219  {
220  aNewBmpSize.setWidth( FRound( fMaxPixelY * fBmpWH ) );
221  aNewBmpSize.setHeight( FRound( fMaxPixelY ) );
222  }
223  else if( fBmpWH > 0.0 )
224  {
225  aNewBmpSize.setWidth( FRound( fMaxPixelX ) );
226  aNewBmpSize.setHeight( FRound( fMaxPixelX / fBmpWH) );
227  }
228 
229  if( aNewBmpSize.Width() && aNewBmpSize.Height() )
230  aBmp.Scale( aNewBmpSize );
231  else
232  aBmp.SetEmpty();
233  }
234  }
235  }
236 
237  return aBmp;
238 }
239 
240 void OutputDevice::DrawBitmapEx( const Point& rDestPt,
241  const BitmapEx& rBitmapEx )
242 {
243  assert(!is_double_buffered_window());
244 
245  if( ImplIsRecordLayout() )
246  return;
247 
248  if( TransparentType::NONE == rBitmapEx.GetTransparentType() )
249  {
250  DrawBitmap( rDestPt, rBitmapEx.GetBitmap() );
251  }
252  else
253  {
254  const Size aSizePix( rBitmapEx.GetSizePixel() );
255  DrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, MetaActionType::BMPEX );
256  }
257 }
258 
259 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
260  const BitmapEx& rBitmapEx )
261 {
262  assert(!is_double_buffered_window());
263 
264  if( ImplIsRecordLayout() )
265  return;
266 
267  if ( TransparentType::NONE == rBitmapEx.GetTransparentType() )
268  {
269  DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() );
270  }
271  else
272  {
273  DrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, MetaActionType::BMPEXSCALE );
274  }
275 }
276 
277 
278 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
279  const Point& rSrcPtPixel, const Size& rSrcSizePixel,
280  const BitmapEx& rBitmapEx, const MetaActionType nAction )
281 {
282  assert(!is_double_buffered_window());
283 
284  if( ImplIsRecordLayout() )
285  return;
286 
287  if( TransparentType::NONE == rBitmapEx.GetTransparentType() )
288  {
289  DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() );
290  }
291  else
292  {
293  if ( RasterOp::Invert == meRasterOp )
294  {
295  DrawRect( tools::Rectangle( rDestPt, rDestSize ) );
296  return;
297  }
298 
299  BitmapEx aBmpEx( rBitmapEx );
300 
303  {
305  {
306  Bitmap aColorBmp( aBmpEx.GetSizePixel(), 1 );
307  sal_uInt8 cCmpVal;
308 
310  cCmpVal = 0;
311  else
312  cCmpVal = 255;
313 
314  aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
315 
316  if( aBmpEx.IsAlpha() )
317  {
318  // Create one-bit mask out of alpha channel, by
319  // thresholding it at alpha=0.5. As
320  // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
321  // output, having alpha-induced grey levels is not
322  // acceptable.
323  BitmapEx aMaskEx(aBmpEx.GetAlpha().GetBitmap());
325  aBmpEx = BitmapEx(aColorBmp, aMaskEx.GetBitmap());
326  }
327  else
328  {
329  aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
330  }
331  }
332  else if( !!aBmpEx )
333  {
336  }
337  }
338 
339  if ( mpMetaFile )
340  {
341  switch( nAction )
342  {
344  mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
345  break;
346 
348  mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
349  break;
350 
352  mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
353  rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
354  break;
355 
356  default: break;
357  }
358  }
359 
360  if ( !IsDeviceOutputNecessary() )
361  return;
362 
363  if ( !mpGraphics && !AcquireGraphics() )
364  return;
365 
366  if ( mbInitClipRegion )
367  InitClipRegion();
368 
369  if ( mbOutputClipped )
370  return;
371 
372  DrawDeviceBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmpEx );
373  }
374 }
375 
376 Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
377 {
378  Bitmap aBmp;
379  long nX = ImplLogicXToDevicePixel( rSrcPt.X() );
380  long nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
381  long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
382  long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
383 
384  if ( mpGraphics || AcquireGraphics() )
385  {
386  if ( nWidth > 0 && nHeight > 0 && nX <= (mnOutWidth + mnOutOffX) && nY <= (mnOutHeight + mnOutOffY))
387  {
388  tools::Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
389  bool bClipped = false;
390 
391  // X-Coordinate outside of draw area?
392  if ( nX < mnOutOffX )
393  {
394  nWidth -= ( mnOutOffX - nX );
395  nX = mnOutOffX;
396  bClipped = true;
397  }
398 
399  // Y-Coordinate outside of draw area?
400  if ( nY < mnOutOffY )
401  {
402  nHeight -= ( mnOutOffY - nY );
403  nY = mnOutOffY;
404  bClipped = true;
405  }
406 
407  // Width outside of draw area?
408  if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
409  {
410  nWidth = mnOutOffX + mnOutWidth - nX;
411  bClipped = true;
412  }
413 
414  // Height outside of draw area?
415  if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
416  {
417  nHeight = mnOutOffY + mnOutHeight - nY;
418  bClipped = true;
419  }
420 
421  if ( bClipped )
422  {
423  // If the visible part has been clipped, we have to create a
424  // Bitmap with the correct size in which we copy the clipped
425  // Bitmap to the correct position.
427 
428  if ( aVDev->SetOutputSizePixel( aRect.GetSize() ) )
429  {
430  if ( aVDev->mpGraphics || aVDev->AcquireGraphics() )
431  {
432  if ( (nWidth > 0) && (nHeight > 0) )
433  {
434  SalTwoRect aPosAry(nX, nY, nWidth, nHeight,
435  (aRect.Left() < mnOutOffX) ? (mnOutOffX - aRect.Left()) : 0L,
436  (aRect.Top() < mnOutOffY) ? (mnOutOffY - aRect.Top()) : 0L,
437  nWidth, nHeight);
438  aVDev->mpGraphics->CopyBits( aPosAry, mpGraphics, this, this );
439  }
440  else
441  {
442  OSL_ENSURE(false, "CopyBits with zero or negative width or height");
443  }
444 
445  aBmp = aVDev->GetBitmap( Point(), aVDev->GetOutputSizePixel() );
446  }
447  else
448  bClipped = false;
449  }
450  else
451  bClipped = false;
452  }
453 
454  if ( !bClipped )
455  {
456  std::shared_ptr<SalBitmap> pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
457 
458  if( pSalBmp )
459  {
460  aBmp.ImplSetSalBitmap(pSalBmp);
461  }
462  }
463  }
464  }
465 
466  return aBmp;
467 }
468 
469 BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
470 {
471 
472  // #110958# Extract alpha value from VDev, if any
473  if( mpAlphaVDev )
474  {
475  Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
476 
477  // ensure 8 bit alpha
478  if( aAlphaBitmap.GetBitCount() > 8 )
479  aAlphaBitmap.Convert( BmpConversion::N8BitGreys );
480 
481  return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
482  }
483  else
484  return BitmapEx(GetBitmap( rSrcPt, rSize ));
485 }
486 
487 void OutputDevice::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
488  const Point& rSrcPtPixel, const Size& rSrcSizePixel,
489  BitmapEx& rBitmapEx )
490 {
491  assert(!is_double_buffered_window());
492 
493  if (rBitmapEx.IsAlpha())
494  {
495  DrawDeviceAlphaBitmap(rBitmapEx.GetBitmap(), rBitmapEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel);
496  }
497  else if (!!rBitmapEx)
498  {
499  SalTwoRect aPosAry(rSrcPtPixel.X(), rSrcPtPixel.Y(), rSrcSizePixel.Width(), rSrcSizePixel.Height(),
500  ImplLogicXToDevicePixel(rDestPt.X()), ImplLogicYToDevicePixel(rDestPt.Y()),
501  ImplLogicWidthToDevicePixel(rDestSize.Width()),
502  ImplLogicHeightToDevicePixel(rDestSize.Height()));
503 
504  const BmpMirrorFlags nMirrFlags = AdjustTwoRect(aPosAry, rBitmapEx.GetSizePixel());
505 
506  if (aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight)
507  {
508 
509  if (nMirrFlags != BmpMirrorFlags::NONE)
510  rBitmapEx.Mirror(nMirrFlags);
511 
512  const SalBitmap* pSalSrcBmp = rBitmapEx.ImplGetBitmapSalBitmap().get();
513  std::shared_ptr<SalBitmap> xMaskBmp = rBitmapEx.ImplGetMaskSalBitmap();
514 
515  if (xMaskBmp)
516  {
517  bool bTryDirectPaint(pSalSrcBmp);
518 
519  if (bTryDirectPaint && mpGraphics->DrawAlphaBitmap(aPosAry, *pSalSrcBmp, *xMaskBmp, this))
520  {
521  // tried to paint as alpha directly. If tis worked, we are done (except
522  // alpha, see below)
523  }
524  else
525  {
526  // #4919452# reduce operation area to bounds of
527  // cliprect. since masked transparency involves
528  // creation of a large vdev and copying the screen
529  // content into that (slooow read from framebuffer),
530  // that should considerably increase performance for
531  // large bitmaps and small clippings.
532 
533  // Note that this optimization is a workaround for a
534  // Writer peculiarity, namely, to decompose background
535  // graphics into myriads of disjunct, tiny
536  // rectangles. That otherwise kills us here, since for
537  // transparent output, SAL always prepares the whole
538  // bitmap, if aPosAry contains the whole bitmap (and
539  // it's _not_ to blame for that).
540 
541  // Note the call to ImplPixelToDevicePixel(), since
542  // aPosAry already contains the mnOutOff-offsets, they
543  // also have to be applied to the region
544  tools::Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
545 
546  // TODO: Also respect scaling (that's a bit tricky,
547  // since the source points have to move fractional
548  // amounts (which is not possible, thus has to be
549  // emulated by increases copy area)
550  // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
551  // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
552 
553  // for now, only identity scales allowed
554  if (!aClipRegionBounds.IsEmpty() &&
555  aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
556  aPosAry.mnDestHeight == aPosAry.mnSrcHeight)
557  {
558  // now intersect dest rect with clip region
559  aClipRegionBounds.Intersection(tools::Rectangle(aPosAry.mnDestX,
560  aPosAry.mnDestY,
561  aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
562  aPosAry.mnDestY + aPosAry.mnDestHeight - 1));
563 
564  // Note: I could theoretically optimize away the
565  // DrawBitmap below, if the region is empty
566  // here. Unfortunately, cannot rule out that
567  // somebody relies on the side effects.
568  if (!aClipRegionBounds.IsEmpty())
569  {
570  aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
571  aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
572  aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
573  aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
574 
575  aPosAry.mnDestX = aClipRegionBounds.Left();
576  aPosAry.mnDestY = aClipRegionBounds.Top();
577  aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
578  aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
579  }
580  }
581 
582  mpGraphics->DrawBitmap(aPosAry, *pSalSrcBmp, *xMaskBmp, this);
583  }
584 
585  // #110958# Paint mask to alpha channel. Luckily, the
586  // black and white representation of the mask maps to
587  // the alpha channel
588 
589  // #i25167# Restrict mask painting to _opaque_ areas
590  // of the mask, otherwise we spoil areas where no
591  // bitmap content was ever visible. Interestingly
592  // enough, this can be achieved by taking the mask as
593  // the transparency mask of itself
594  if (mpAlphaVDev)
595  mpAlphaVDev->DrawBitmapEx(rDestPt,
596  rDestSize,
597  BitmapEx(rBitmapEx.GetMask(),
598  rBitmapEx.GetMask()));
599  }
600  else
601  {
602  mpGraphics->DrawBitmap(aPosAry, *pSalSrcBmp, this);
603 
604  if (mpAlphaVDev)
605  {
606  // #i32109#: Make bitmap area opaque
607  mpAlphaVDev->ImplFillOpaqueRectangle( tools::Rectangle(rDestPt, rDestSize) );
608  }
609  }
610  }
611  }
612 }
613 
614 void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& rAlpha,
615  const Point& rDestPt, const Size& rDestSize,
616  const Point& rSrcPtPixel, const Size& rSrcSizePixel )
617 {
618  assert(!is_double_buffered_window());
619 
620  Point aOutPt(LogicToPixel(rDestPt));
621  Size aOutSz(LogicToPixel(rDestSize));
623 
624  const bool bHMirr = aOutSz.Width() < 0;
625  const bool bVMirr = aOutSz.Height() < 0;
626 
627  ClipToPaintRegion(aDstRect);
628 
629  if (bHMirr)
630  {
631  aOutSz.setWidth( -aOutSz.Width() );
632  aOutPt.AdjustX( -(aOutSz.Width() - 1) );
633  }
634 
635  if (bVMirr)
636  {
637  aOutSz.setHeight( -aOutSz.Height() );
638  aOutPt.AdjustY( -(aOutSz.Height() - 1) );
639  }
640 
641  if (!aDstRect.Intersection(tools::Rectangle(aOutPt, aOutSz)).IsEmpty())
642  {
643  static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
644  // #i83087# Naturally, system alpha blending cannot work with
645  // separate alpha VDev
646 
647  // Not clear how the above comment relates to the following declaration and initialisation
648  // of bTryDirectPaint. Does bTryDirectPaint being true mean that we can use "system alpha
649  // blending"? Or that we can't? Or are the two not related at all, and should the above
650  // comment actually be better located below, before the "if (mpAlphaVDev)" test?
651 
652  bool bTryDirectPaint(!pDisableNative && !bHMirr && !bVMirr);
653 
654  if (bTryDirectPaint)
655  {
656  Point aRelPt = aOutPt + Point(mnOutOffX, mnOutOffY);
657  SalTwoRect aTR(
658  rSrcPtPixel.X(), rSrcPtPixel.Y(),
659  rSrcSizePixel.Width(), rSrcSizePixel.Height(),
660  aRelPt.X(), aRelPt.Y(),
661  aOutSz.Width(), aOutSz.Height());
662 
663  SalBitmap* pSalSrcBmp = rBmp.ImplGetSalBitmap().get();
664  SalBitmap* pSalAlphaBmp = rAlpha.ImplGetSalBitmap().get();
665 
666  // try to blend the alpha bitmap with the alpha virtual device
667  if (mpAlphaVDev)
668  {
669  Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aRelPt, aOutSz ) );
670  if (aAlphaBitmap.ImplGetSalBitmap())
671  {
672  SalBitmap* pSalAlphaBmp2 = aAlphaBitmap.ImplGetSalBitmap().get();
673  if (mpGraphics->BlendAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, *pSalAlphaBmp2, this))
674  {
675  mpAlphaVDev->BlendBitmap(aTR, rAlpha);
676  return;
677  }
678  }
679  }
680  else
681  {
682  if (mpGraphics->DrawAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, this))
683  return;
684  }
685  }
686 
687  // we need to make sure OpenGL never reaches this slow code path
688 
689 #if HAVE_FEATURE_OPENGL
691 #endif
692  tools::Rectangle aBmpRect(Point(), rBmp.GetSizePixel());
693  if (!aBmpRect.Intersection(tools::Rectangle(rSrcPtPixel, rSrcSizePixel)).IsEmpty())
694  {
695  Point auxOutPt(LogicToPixel(rDestPt));
696  Size auxOutSz(LogicToPixel(rDestSize));
697 
698  DrawDeviceAlphaBitmapSlowPath(rBmp, rAlpha, aDstRect, aBmpRect, auxOutSz, auxOutPt);
699  }
700  }
701 }
702 
703 namespace
704 {
705 
706 struct LinearScaleContext
707 {
708  std::unique_ptr<long[]> mpMapX;
709  std::unique_ptr<long[]> mpMapY;
710 
711  std::unique_ptr<long[]> mpMapXOffset;
712  std::unique_ptr<long[]> mpMapYOffset;
713 
714  LinearScaleContext(tools::Rectangle const & aDstRect, tools::Rectangle const & aBitmapRect,
715  Size const & aOutSize, long nOffX, long nOffY)
716 
717  : mpMapX(new long[aDstRect.GetWidth()])
718  , mpMapY(new long[aDstRect.GetHeight()])
719  , mpMapXOffset(new long[aDstRect.GetWidth()])
720  , mpMapYOffset(new long[aDstRect.GetHeight()])
721  {
722  const long nSrcWidth = aBitmapRect.GetWidth();
723  const long nSrcHeight = aBitmapRect.GetHeight();
724 
725  generateSimpleMap(
726  nSrcWidth, aDstRect.GetWidth(), aBitmapRect.Left(),
727  aOutSize.Width(), nOffX, mpMapX.get(), mpMapXOffset.get());
728 
729  generateSimpleMap(
730  nSrcHeight, aDstRect.GetHeight(), aBitmapRect.Top(),
731  aOutSize.Height(), nOffY, mpMapY.get(), mpMapYOffset.get());
732  }
733 
734 private:
735 
736  static void generateSimpleMap(long nSrcDimension, long nDstDimension, long nDstLocation,
737  long nOutDimention, long nOffset, long* pMap, long* pMapOffset)
738  {
739 
740  const double fReverseScale = (std::abs(nOutDimention) > 1) ? (nSrcDimension - 1) / double(std::abs(nOutDimention) - 1) : 0.0;
741 
742  long nSampleRange = std::max(0L, nSrcDimension - 2);
743 
744  for (long i = 0; i < nDstDimension; i++)
745  {
746  double fTemp = std::abs((nOffset + i) * fReverseScale);
747 
748  pMap[i] = MinMax(nDstLocation + long(fTemp), 0, nSampleRange);
749  pMapOffset[i] = static_cast<long>((fTemp - pMap[i]) * 128.0);
750  }
751  }
752 
753 public:
754  bool blendBitmap(
755  const BitmapWriteAccess* pDestination,
756  const BitmapReadAccess* pSource,
757  const BitmapReadAccess* pSourceAlpha,
758  const long nDstWidth,
759  const long nDstHeight)
760  {
761  if (pSource && pSourceAlpha && pDestination)
762  {
763  ScanlineFormat nSourceFormat = pSource->GetScanlineFormat();
764  ScanlineFormat nDestinationFormat = pDestination->GetScanlineFormat();
765 
766  switch (nSourceFormat)
767  {
770  {
771  if ( (nSourceFormat == ScanlineFormat::N24BitTcBgr && nDestinationFormat == ScanlineFormat::N32BitTcBgra)
772  || (nSourceFormat == ScanlineFormat::N24BitTcRgb && nDestinationFormat == ScanlineFormat::N32BitTcRgba))
773  {
774  blendBitmap24(pDestination, pSource, pSourceAlpha, nDstWidth, nDstHeight);
775  return true;
776  }
777  }
778  break;
779  default: break;
780  }
781  }
782  return false;
783  }
784 
785  void blendBitmap24(
786  const BitmapWriteAccess* pDestination,
787  const BitmapReadAccess* pSource,
788  const BitmapReadAccess* pSourceAlpha,
789  const long nDstWidth,
790  const long nDstHeight)
791  {
792  Scanline pLine0, pLine1;
793  Scanline pLineAlpha0, pLineAlpha1;
794  Scanline pColorSample1, pColorSample2;
795  Scanline pDestScanline;
796 
797  long nColor1Line1, nColor2Line1, nColor3Line1;
798  long nColor1Line2, nColor2Line2, nColor3Line2;
799  long nAlphaLine1, nAlphaLine2;
800 
801  sal_uInt8 nColor1, nColor2, nColor3, nAlpha;
802 
803  for (long nY = 0; nY < nDstHeight; nY++)
804  {
805  const long nMapY = mpMapY[nY];
806  const long nMapFY = mpMapYOffset[nY];
807 
808  pLine0 = pSource->GetScanline(nMapY);
809  // tdf#95481 guard nMapY + 1 to be within bounds
810  pLine1 = (nMapY + 1 < pSource->Height()) ? pSource->GetScanline(nMapY + 1) : pLine0;
811 
812  pLineAlpha0 = pSourceAlpha->GetScanline(nMapY);
813  // tdf#95481 guard nMapY + 1 to be within bounds
814  pLineAlpha1 = (nMapY + 1 < pSourceAlpha->Height()) ? pSourceAlpha->GetScanline(nMapY + 1) : pLineAlpha0;
815 
816  pDestScanline = pDestination->GetScanline(nY);
817 
818  for (long nX = 0; nX < nDstWidth; nX++)
819  {
820  const long nMapX = mpMapX[nX];
821  const long nMapFX = mpMapXOffset[nX];
822 
823  pColorSample1 = pLine0 + 3 * nMapX;
824  pColorSample2 = (nMapX + 1 < pSource->Width()) ? pColorSample1 + 3 : pColorSample1;
825  nColor1Line1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
826 
827  pColorSample1++;
828  pColorSample2++;
829  nColor2Line1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
830 
831  pColorSample1++;
832  pColorSample2++;
833  nColor3Line1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
834 
835  pColorSample1 = pLine1 + 3 * nMapX;
836  pColorSample2 = (nMapX + 1 < pSource->Width()) ? pColorSample1 + 3 : pColorSample1;
837  nColor1Line2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
838 
839  pColorSample1++;
840  pColorSample2++;
841  nColor2Line2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
842 
843  pColorSample1++;
844  pColorSample2++;
845  nColor3Line2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
846 
847  pColorSample1 = pLineAlpha0 + nMapX;
848  pColorSample2 = (nMapX + 1 < pSourceAlpha->Width()) ? pColorSample1 + 1 : pColorSample1;
849  nAlphaLine1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
850 
851  pColorSample1 = pLineAlpha1 + nMapX;
852  pColorSample2 = (nMapX + 1 < pSourceAlpha->Width()) ? pColorSample1 + 1 : pColorSample1;
853  nAlphaLine2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
854 
855  nColor1 = (nColor1Line1 + nMapFY * ((nColor1Line2 >> 7) - (nColor1Line1 >> 7))) >> 7;
856  nColor2 = (nColor2Line1 + nMapFY * ((nColor2Line2 >> 7) - (nColor2Line1 >> 7))) >> 7;
857  nColor3 = (nColor3Line1 + nMapFY * ((nColor3Line2 >> 7) - (nColor3Line1 >> 7))) >> 7;
858 
859  nAlpha = (nAlphaLine1 + nMapFY * ((nAlphaLine2 >> 7) - (nAlphaLine1 >> 7))) >> 7;
860 
861  *pDestScanline = ColorChannelMerge(*pDestScanline, nColor1, nAlpha);
862  pDestScanline++;
863  *pDestScanline = ColorChannelMerge(*pDestScanline, nColor2, nAlpha);
864  pDestScanline++;
865  *pDestScanline = ColorChannelMerge(*pDestScanline, nColor3, nAlpha);
866  pDestScanline++;
867  pDestScanline++;
868  }
869  }
870  }
871 };
872 
873 struct TradScaleContext
874 {
875  std::unique_ptr<long[]> mpMapX;
876  std::unique_ptr<long[]> mpMapY;
877 
878  TradScaleContext(tools::Rectangle const & aDstRect, tools::Rectangle const & aBitmapRect,
879  Size const & aOutSize, long nOffX, long nOffY)
880 
881  : mpMapX(new long[aDstRect.GetWidth()])
882  , mpMapY(new long[aDstRect.GetHeight()])
883  {
884  const long nSrcWidth = aBitmapRect.GetWidth();
885  const long nSrcHeight = aBitmapRect.GetHeight();
886 
887  const bool bHMirr = aOutSize.Width() < 0;
888  const bool bVMirr = aOutSize.Height() < 0;
889 
890  generateSimpleMap(
891  nSrcWidth, aDstRect.GetWidth(), aBitmapRect.Left(),
892  aOutSize.Width(), nOffX, bHMirr, mpMapX.get());
893 
894  generateSimpleMap(
895  nSrcHeight, aDstRect.GetHeight(), aBitmapRect.Top(),
896  aOutSize.Height(), nOffY, bVMirr, mpMapY.get());
897  }
898 
899 private:
900 
901  static void generateSimpleMap(long nSrcDimension, long nDstDimension, long nDstLocation,
902  long nOutDimention, long nOffset, bool bMirror, long* pMap)
903  {
904  long nMirrorOffset = 0;
905 
906  if (bMirror)
907  nMirrorOffset = (nDstLocation << 1) + nSrcDimension - 1;
908 
909  for (long i = 0; i < nDstDimension; ++i, ++nOffset)
910  {
911  pMap[i] = nDstLocation + nOffset * nSrcDimension / nOutDimention;
912  if (bMirror)
913  pMap[i] = nMirrorOffset - pMap[i];
914  }
915  }
916 };
917 
918 
919 } // end anonymous namespace
920 
922  const AlphaMask& rAlpha, tools::Rectangle aDstRect, tools::Rectangle aBmpRect, Size const & aOutSize, Point const & aOutPoint)
923 {
924  assert(!is_double_buffered_window());
925 
926  VirtualDevice* pOldVDev = mpAlphaVDev;
927 
928  const bool bHMirr = aOutSize.Width() < 0;
929  const bool bVMirr = aOutSize.Height() < 0;
930 
931  // The scaling in this code path produces really ugly results - it
932  // does the most trivial scaling with no smoothing.
933  GDIMetaFile* pOldMetaFile = mpMetaFile;
934  const bool bOldMap = mbMap;
935 
936  mpMetaFile = nullptr; // fdo#55044 reset before GetBitmap!
937  mbMap = false;
938 
939  Bitmap aBmp(GetBitmap(aDstRect.TopLeft(), aDstRect.GetSize()));
940 
941  // #109044# The generated bitmap need not necessarily be
942  // of aDstRect dimensions, it's internally clipped to
943  // window bounds. Thus, we correct the dest size here,
944  // since we later use it (in nDstWidth/Height) for pixel
945  // access)
946  // #i38887# reading from screen may sometimes fail
947  if (aBmp.ImplGetSalBitmap())
948  {
949  aDstRect.SetSize(aBmp.GetSizePixel());
950  }
951 
952  const long nDstWidth = aDstRect.GetWidth();
953  const long nDstHeight = aDstRect.GetHeight();
954 
955  // calculate offset in original bitmap
956  // in RTL case this is a little more complicated since the contents of the
957  // bitmap is not mirrored (it never is), however the paint region and bmp region
958  // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
959  // is content wise somewhere else and needs to take mirroring into account
960  const long nOffX = IsRTLEnabled()
961  ? aOutSize.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPoint.X())
962  : aDstRect.Left() - aOutPoint.X();
963 
964  const long nOffY = aDstRect.Top() - aOutPoint.Y();
965 
966  TradScaleContext aTradContext(aDstRect, aBmpRect, aOutSize, nOffX, nOffY);
967 
968  Bitmap::ScopedReadAccess pBitmapReadAccess(const_cast<Bitmap&>(rBitmap));
969  AlphaMask::ScopedReadAccess pAlphaReadAccess(const_cast<AlphaMask&>(rAlpha));
970 
971  DBG_ASSERT( pAlphaReadAccess->GetScanlineFormat() == ScanlineFormat::N8BitPal ||
972  pAlphaReadAccess->GetScanlineFormat() == ScanlineFormat::N8BitTcMask,
973  "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
974 
975  // #i38887# reading from screen may sometimes fail
976  if (aBmp.ImplGetSalBitmap())
977  {
978  Bitmap aNewBitmap;
979 
980  if (mpAlphaVDev)
981  {
982  aNewBitmap = BlendBitmapWithAlpha(
983  aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(),
984  aDstRect,
985  nOffY, nDstHeight,
986  nOffX, nDstWidth,
987  aTradContext.mpMapX.get(), aTradContext.mpMapY.get() );
988  }
989  else
990  {
991  LinearScaleContext aLinearContext(aDstRect, aBmpRect, aOutSize, nOffX, nOffY);
992 
993  if (aLinearContext.blendBitmap( BitmapScopedWriteAccess(aBmp).get(), pBitmapReadAccess.get(), pAlphaReadAccess.get(),
994  nDstWidth, nDstHeight))
995  {
996  aNewBitmap = aBmp;
997  }
998  else
999  {
1000  aNewBitmap = BlendBitmap(
1001  aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(),
1002  nOffY, nDstHeight,
1003  nOffX, nDstWidth,
1004  aBmpRect, aOutSize,
1005  bHMirr, bVMirr,
1006  aTradContext.mpMapX.get(), aTradContext.mpMapY.get() );
1007  }
1008  }
1009 
1010  // #110958# Disable alpha VDev, we're doing the necessary
1011  // stuff explicitly further below
1012  if (mpAlphaVDev)
1013  mpAlphaVDev = nullptr;
1014 
1015  DrawBitmap(aDstRect.TopLeft(), aNewBitmap);
1016 
1017  // #110958# Enable alpha VDev again
1018  mpAlphaVDev = pOldVDev;
1019  }
1020 
1021  mbMap = bOldMap;
1022  mpMetaFile = pOldMetaFile;
1023 }
1024 
1026 {
1027  const double nScaleX = rPosAry.mnDestWidth / static_cast<double>( rPosAry.mnSrcWidth );
1028  const double nScaleY = rPosAry.mnDestHeight / static_cast<double>( rPosAry.mnSrcHeight );
1029 
1030  // If subsampling, use Bitmap::Scale for subsampling for better quality.
1031  if ( nScaleX < 1.0 || nScaleY < 1.0 )
1032  {
1033  rBmp.Scale ( nScaleX, nScaleY );
1034  rPosAry.mnSrcWidth = rPosAry.mnDestWidth;
1035  rPosAry.mnSrcHeight = rPosAry.mnDestHeight;
1036  }
1037 }
1038 
1040  const basegfx::B2DHomMatrix& aFullTransform,
1041  const BitmapEx& rBitmapEx)
1042 {
1043  assert(!is_double_buffered_window());
1044 
1045  bool bDone = false;
1046 
1047  // try to paint directly
1048  const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0));
1049  const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0));
1050  const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0));
1051  SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetSalBitmap().get();
1052  SalBitmap* pSalAlphaBmp = nullptr;
1053 
1054  if(rBitmapEx.IsTransparent())
1055  {
1056  if(rBitmapEx.IsAlpha())
1057  {
1058  pSalAlphaBmp = rBitmapEx.GetAlpha().ImplGetSalBitmap().get();
1059  }
1060  else
1061  {
1062  pSalAlphaBmp = rBitmapEx.GetMask().ImplGetSalBitmap().get();
1063  }
1064  }
1065 
1067  aNull,
1068  aTopX,
1069  aTopY,
1070  *pSalSrcBmp,
1071  pSalAlphaBmp,
1072  this);
1073 
1074  return bDone;
1075 };
1076 
1078  const basegfx::B2DHomMatrix& aFullTransform,
1079  basegfx::B2DRange &aVisibleRange,
1080  double &fMaximumArea)
1081 {
1082  // limit TargetRange to existing pixels (if pixel device)
1083  // first get discrete range of object
1084  basegfx::B2DRange aFullPixelRange(aVisibleRange);
1085 
1086  aFullPixelRange.transform(aFullTransform);
1087 
1088  if(basegfx::fTools::equalZero(aFullPixelRange.getWidth()) || basegfx::fTools::equalZero(aFullPixelRange.getHeight()))
1089  {
1090  // object is outside of visible area
1091  return false;
1092  }
1093 
1094  // now get discrete target pixels; start with OutDev pixel size and evtl.
1095  // intersect with active clipping area
1096  basegfx::B2DRange aOutPixel(
1097  0.0,
1098  0.0,
1101 
1102  if(IsClipRegion())
1103  {
1104  tools::Rectangle aRegionRectangle(GetActiveClipRegion().GetBoundRect());
1105 
1106  // caution! Range from rectangle, one too much (!)
1107  aRegionRectangle.AdjustRight(-1);
1108  aRegionRectangle.AdjustBottom(-1);
1109  aOutPixel.intersect( vcl::unotools::b2DRectangleFromRectangle(aRegionRectangle) );
1110  }
1111 
1112  if(aOutPixel.isEmpty())
1113  {
1114  // no active output area
1115  return false;
1116  }
1117 
1118  // if aFullPixelRange is not completely inside of aOutPixel,
1119  // reduction of target pixels is possible
1120  basegfx::B2DRange aVisiblePixelRange(aFullPixelRange);
1121 
1122  if(!aOutPixel.isInside(aFullPixelRange))
1123  {
1124  aVisiblePixelRange.intersect(aOutPixel);
1125 
1126  if(aVisiblePixelRange.isEmpty())
1127  {
1128  // nothing in visible part, reduces to nothing
1129  return false;
1130  }
1131 
1132  // aVisiblePixelRange contains the reduced output area in
1133  // discrete coordinates. To make it useful everywhere, make it relative to
1134  // the object range
1135  basegfx::B2DHomMatrix aMakeVisibleRangeRelative;
1136 
1137  aVisibleRange = aVisiblePixelRange;
1138  aMakeVisibleRangeRelative.translate(
1139  -aFullPixelRange.getMinX(),
1140  -aFullPixelRange.getMinY());
1141  aMakeVisibleRangeRelative.scale(
1142  1.0 / aFullPixelRange.getWidth(),
1143  1.0 / aFullPixelRange.getHeight());
1144  aVisibleRange.transform(aMakeVisibleRangeRelative);
1145  }
1146 
1147  // for pixel devices, do *not* limit size, else OutputDevice::DrawDeviceAlphaBitmap
1148  // will create another, badly scaled bitmap to do the job. Nonetheless, do a
1149  // maximum clipping of something big (1600x1280x2). Add 1.0 to avoid rounding
1150  // errors in rough estimations
1151  const double fNewMaxArea(aVisiblePixelRange.getWidth() * aVisiblePixelRange.getHeight());
1152 
1153  fMaximumArea = std::min(4096000.0, fNewMaxArea + 1.0);
1154 
1155  return true;
1156 }
1157 
1159  const basegfx::B2DHomMatrix& rTransformation,
1160  const BitmapEx& rBitmapEx)
1161 {
1162  assert(!is_double_buffered_window());
1163 
1164  if( ImplIsRecordLayout() )
1165  return;
1166 
1167  if(rBitmapEx.IsEmpty())
1168  return;
1169 
1170  // decompose matrix to check rotation and shear
1171  basegfx::B2DVector aScale, aTranslate;
1172  double fRotate, fShearX;
1173  rTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
1174  const bool bRotated(!basegfx::fTools::equalZero(fRotate));
1175  const bool bSheared(!basegfx::fTools::equalZero(fShearX));
1176  const bool bMirroredX(basegfx::fTools::less(aScale.getX(), 0.0));
1177  const bool bMirroredY(basegfx::fTools::less(aScale.getY(), 0.0));
1178 
1179  const bool bMetafile = mpMetaFile != nullptr;
1180 
1181  if(!bRotated && !bSheared && !bMirroredX && !bMirroredY)
1182  {
1183  // with no rotation, shear or mirroring it can be mapped to DrawBitmapEx
1184  // do *not* execute the mirroring here, it's done in the fallback
1185  // #i124580# the correct DestSize needs to be calculated based on MaxXY values
1186  Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
1187  const Size aDestSize(
1188  basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
1189  basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
1190  const Point aOrigin = GetMapMode().GetOrigin();
1191  if (!bMetafile && comphelper::LibreOfficeKit::isActive() && GetMapMode().GetMapUnit() != MapUnit::MapPixel)
1192  {
1193  aDestPt.Move(aOrigin.getX(), aOrigin.getY());
1194  EnableMapMode(false);
1195  }
1196 
1197  DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
1198  if (!bMetafile && comphelper::LibreOfficeKit::isActive() && GetMapMode().GetMapUnit() != MapUnit::MapPixel)
1199  {
1200  EnableMapMode();
1201  aDestPt.Move(-aOrigin.getX(), -aOrigin.getY());
1202  }
1203  return;
1204  }
1205 
1206  // we have rotation,shear or mirror, check if some crazy mode needs the
1207  // created transformed bitmap
1208  const bool bInvert(RasterOp::Invert == meRasterOp);
1210  bool bDone(false);
1211  const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
1212  const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile );
1213 
1214  if(bTryDirectPaint)
1215  {
1216  bDone = DrawTransformBitmapExDirect(aFullTransform, rBitmapEx);
1217  }
1218 
1219  if(!bDone)
1220  {
1221  // take the fallback when no rotate and shear, but mirror (else we would have done this above)
1222  if(!bRotated && !bSheared)
1223  {
1224  // with no rotation or shear it can be mapped to DrawBitmapEx
1225  // do *not* execute the mirroring here, it's done in the fallback
1226  // #i124580# the correct DestSize needs to be calculated based on MaxXY values
1227  const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
1228  const Size aDestSize(
1229  basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
1230  basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
1231 
1232  DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
1233  return;
1234  }
1235 
1236  assert(bSheared || bRotated); // at this point we are either sheared or rotated or both
1237 
1238  // fallback; create transformed bitmap the hard way (back-transform
1239  // the pixels) and paint
1240  basegfx::B2DRange aVisibleRange(0.0, 0.0, 1.0, 1.0);
1241 
1242  // limit maximum area to something looking good for non-pixel-based targets (metafile, printer)
1243  // by using a fixed minimum (allow at least, but no need to utilize) for good smoothing and an area
1244  // dependent of original size for good quality when e.g. rotated/sheared. Still, limit to a maximum
1245  // to avoid crashes/resource problems (ca. 1500x3000 here)
1246  const Size& rOriginalSizePixel(rBitmapEx.GetSizePixel());
1247  const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5);
1248  const double fOrigAreaScaled(fOrigArea * 1.44);
1249  double fMaximumArea(std::min(4500000.0, std::max(1000000.0, fOrigAreaScaled)));
1250 
1251  if(!bMetafile)
1252  {
1253  if ( !TransformAndReduceBitmapExToTargetRange( aFullTransform, aVisibleRange, fMaximumArea ) )
1254  return;
1255  }
1256 
1257  if(!aVisibleRange.isEmpty())
1258  {
1259  BitmapEx aTransformed(rBitmapEx);
1260 
1261  // #122923# when the result needs an alpha channel due to being rotated or sheared
1262  // and thus uncovering areas, add these channels so that the own transformer (used
1263  // in getTransformed) also creates a transformed alpha channel
1264  if(!aTransformed.IsTransparent() && (bSheared || bRotated))
1265  {
1266  // parts will be uncovered, extend aTransformed with a mask bitmap
1267  const Bitmap aContent(aTransformed.GetBitmap());
1268 
1269  AlphaMask aMaskBmp(aContent.GetSizePixel());
1270  aMaskBmp.Erase(0);
1271 
1272  aTransformed = BitmapEx(aContent, aMaskBmp);
1273  }
1274 
1275  aTransformed = aTransformed.getTransformed(
1276  aFullTransform,
1277  aVisibleRange,
1278  fMaximumArea);
1279  basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
1280 
1281  // get logic object target range
1282  aTargetRange.transform(rTransformation);
1283 
1284  // get from unified/relative VisibleRange to logoc one
1285  aVisibleRange.transform(
1287  aTargetRange.getRange(),
1288  aTargetRange.getMinimum()));
1289 
1290  // extract point and size; do not remove size, the bitmap may have been prepared reduced by purpose
1291  // #i124580# the correct DestSize needs to be calculated based on MaxXY values
1292  const Point aDestPt(basegfx::fround(aVisibleRange.getMinX()), basegfx::fround(aVisibleRange.getMinY()));
1293  const Size aDestSize(
1294  basegfx::fround(aVisibleRange.getMaxX()) - aDestPt.X(),
1295  basegfx::fround(aVisibleRange.getMaxY()) - aDestPt.Y());
1296 
1297  DrawBitmapEx(aDestPt, aDestSize, aTransformed);
1298  }
1299  }
1300 }
1301 
1303  const BitmapEx& rBitmapEx,
1304  ::Color aShadowColor)
1305 {
1306  Bitmap::ScopedReadAccess pReadAccess(const_cast<Bitmap&>(rBitmapEx.maBitmap));
1307 
1308  if(!pReadAccess)
1309  return;
1310 
1311  for(long y(0); y < pReadAccess->Height(); y++)
1312  {
1313  for(long x(0); x < pReadAccess->Width(); x++)
1314  {
1315  const BitmapColor aColor = pReadAccess->GetColor(y, x);
1316  sal_uInt16 nLuminance(static_cast<sal_uInt16>(aColor.GetLuminance()) + 1);
1317  const Color aDestColor(
1318  static_cast<sal_uInt8>((nLuminance * static_cast<sal_uInt16>(aShadowColor.GetRed())) >> 8),
1319  static_cast<sal_uInt8>((nLuminance * static_cast<sal_uInt16>(aShadowColor.GetGreen())) >> 8),
1320  static_cast<sal_uInt8>((nLuminance * static_cast<sal_uInt16>(aShadowColor.GetBlue())) >> 8));
1321  DrawPixel(Point(x,y), aDestColor);
1322  }
1323  }
1324 }
1325 
1326 void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, DrawImageFlags nStyle )
1327 {
1328  assert(!is_double_buffered_window());
1329 
1330  DrawImage( rPos, Size(), rImage, nStyle );
1331 }
1332 
1333 void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
1334  const Image& rImage, DrawImageFlags nStyle )
1335 {
1336  assert(!is_double_buffered_window());
1337 
1338  bool bIsSizeValid = rSize.getWidth() != 0 && rSize.getHeight() != 0;
1339 
1340  if (!ImplIsRecordLayout())
1341  {
1342  Image& rNonConstImage = const_cast<Image&>(rImage);
1343  if (bIsSizeValid)
1344  rNonConstImage.Draw(this, rPos, nStyle, &rSize);
1345  else
1346  rNonConstImage.Draw(this, rPos, nStyle);
1347  }
1348 }
1349 
1350 namespace
1351 {
1352  // Co = Cs + Cd*(1-As) premultiplied alpha -or-
1353  // Co = (AsCs + AdCd*(1-As)) / Ao
1354  sal_uInt8 CalcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceAlpha,
1355  const sal_uInt8 nDstAlpha, const sal_uInt8 nResAlpha, const sal_uInt8 nDestColor )
1356  {
1357  int c = nResAlpha ? ( static_cast<int>(nSourceAlpha)*nSourceColor + static_cast<int>(nDstAlpha)*nDestColor -
1358  static_cast<int>(nDstAlpha)*nDestColor*nSourceAlpha/255 ) / static_cast<int>(nResAlpha) : 0;
1359  return sal_uInt8( c );
1360  }
1361 
1362  BitmapColor AlphaBlend( int nX, int nY,
1363  const long nMapX,
1364  const long nMapY,
1365  BitmapReadAccess const * pP,
1366  BitmapReadAccess const * pA,
1367  BitmapReadAccess const * pB,
1368  BitmapWriteAccess const * pAlphaW,
1369  sal_uInt8& nResAlpha )
1370  {
1371  BitmapColor aDstCol,aSrcCol;
1372  aSrcCol = pP->GetColor( nMapY, nMapX );
1373  aDstCol = pB->GetColor( nY, nX );
1374 
1375  // vcl stores transparency, not alpha - invert it
1376  const sal_uInt8 nSrcAlpha = 255 - pA->GetPixelIndex( nMapY, nMapX );
1377  const sal_uInt8 nDstAlpha = 255 - pAlphaW->GetPixelIndex( nY, nX );
1378 
1379  // Perform porter-duff compositing 'over' operation
1380 
1381  // Co = Cs + Cd*(1-As)
1382  // Ad = As + Ad*(1-As)
1383  nResAlpha = static_cast<int>(nSrcAlpha) + static_cast<int>(nDstAlpha) - static_cast<int>(nDstAlpha)*nSrcAlpha/255;
1384 
1385  aDstCol.SetRed( CalcColor( aSrcCol.GetRed(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetRed() ) );
1386  aDstCol.SetBlue( CalcColor( aSrcCol.GetBlue(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetBlue() ) );
1387  aDstCol.SetGreen( CalcColor( aSrcCol.GetGreen(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetGreen() ) );
1388 
1389  return aDstCol;
1390  }
1391 }
1392 
1394  const SalTwoRect& rPosAry,
1395  const Bitmap& rBmp )
1396 {
1397  mpGraphics->BlendBitmap( rPosAry, *rBmp.ImplGetSalBitmap(), this );
1398 }
1399 
1401  Bitmap& aBmp,
1402  BitmapReadAccess const * pP,
1403  BitmapReadAccess const * pA,
1404  const tools::Rectangle& aDstRect,
1405  const sal_Int32 nOffY,
1406  const sal_Int32 nDstHeight,
1407  const sal_Int32 nOffX,
1408  const sal_Int32 nDstWidth,
1409  const long* pMapX,
1410  const long* pMapY )
1411 
1412 {
1413  BitmapColor aDstCol;
1414  Bitmap res;
1415  int nX, nY;
1416  sal_uInt8 nResAlpha;
1417 
1418  SAL_WARN_IF( !mpAlphaVDev, "vcl.gdi", "BlendBitmapWithAlpha(): call me only with valid alpha VirtualDevice!" );
1419 
1420  bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
1421  mpAlphaVDev->EnableMapMode(false);
1422 
1423  Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1424  BitmapScopedWriteAccess pAlphaW(aAlphaBitmap);
1425 
1426  if( GetBitCount() <= 8 )
1427  {
1428  Bitmap aDither( aBmp.GetSizePixel(), 8 );
1429  BitmapColor aIndex( 0 );
1430  Bitmap::ScopedReadAccess pB(aBmp);
1431  BitmapScopedWriteAccess pW(aDither);
1432 
1433  if (pB && pP && pA && pW && pAlphaW)
1434  {
1435  int nOutY;
1436 
1437  for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1438  {
1439  const long nMapY = pMapY[ nY ];
1440  const long nModY = ( nOutY & 0x0FL ) << 4;
1441  int nOutX;
1442 
1443  Scanline pScanline = pW->GetScanline(nY);
1444  Scanline pScanlineAlpha = pAlphaW->GetScanline(nY);
1445  for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1446  {
1447  const long nMapX = pMapX[ nX ];
1448  const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1449 
1450  aDstCol = AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB.get(), pAlphaW.get(), nResAlpha );
1451 
1452  aIndex.SetIndex( static_cast<sal_uInt8>( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16 ] +
1453  nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16 ] +
1454  nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16 ] ) );
1455  pW->SetPixelOnData( pScanline, nX, aIndex );
1456 
1457  aIndex.SetIndex( static_cast<sal_uInt8>( nVCLRLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16 ] +
1458  nVCLGLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16 ] +
1459  nVCLBLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16 ] ) );
1460  pAlphaW->SetPixelOnData( pScanlineAlpha, nX, aIndex );
1461  }
1462  }
1463  }
1464  pB.reset();
1465  pW.reset();
1466  res = aDither;
1467  }
1468  else
1469  {
1470  BitmapScopedWriteAccess pB(aBmp);
1471  if (pB && pP && pA && pAlphaW)
1472  {
1473  for( nY = 0; nY < nDstHeight; nY++ )
1474  {
1475  const long nMapY = pMapY[ nY ];
1476  Scanline pScanlineB = pB->GetScanline(nY);
1477  Scanline pScanlineAlpha = pAlphaW->GetScanline(nY);
1478 
1479  for( nX = 0; nX < nDstWidth; nX++ )
1480  {
1481  const long nMapX = pMapX[ nX ];
1482  aDstCol = AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB.get(), pAlphaW.get(), nResAlpha );
1483 
1484  pB->SetPixelOnData(pScanlineB, nX, pB->GetBestMatchingColor(aDstCol));
1485  pAlphaW->SetPixelOnData(pScanlineAlpha, nX, pB->GetBestMatchingColor(Color(255L-nResAlpha, 255L-nResAlpha, 255L-nResAlpha)));
1486  }
1487  }
1488  }
1489  pB.reset();
1490  res = aBmp;
1491  }
1492 
1493  pAlphaW.reset();
1494  mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
1495  mpAlphaVDev->EnableMapMode( bOldMapMode );
1496 
1497  return res;
1498 }
1499 
1501  Bitmap& aBmp,
1502  BitmapReadAccess const * pP,
1503  BitmapReadAccess const * pA,
1504  const sal_Int32 nOffY,
1505  const sal_Int32 nDstHeight,
1506  const sal_Int32 nOffX,
1507  const sal_Int32 nDstWidth,
1508  const tools::Rectangle& aBmpRect,
1509  const Size& aOutSz,
1510  const bool bHMirr,
1511  const bool bVMirr,
1512  const long* pMapX,
1513  const long* pMapY )
1514 {
1515  BitmapColor aDstCol;
1516  Bitmap res;
1517  int nX, nY;
1518 
1519  if( GetBitCount() <= 8 )
1520  {
1521  Bitmap aDither( aBmp.GetSizePixel(), 8 );
1522  BitmapColor aIndex( 0 );
1523  Bitmap::ScopedReadAccess pB(aBmp);
1524  BitmapScopedWriteAccess pW(aDither);
1525 
1526  if( pB && pP && pA && pW )
1527  {
1528  int nOutY;
1529 
1530  for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1531  {
1532  long nMapY = pMapY[ nY ];
1533  if (bVMirr)
1534  {
1535  nMapY = aBmpRect.Bottom() - nMapY;
1536  }
1537  const long nModY = ( nOutY & 0x0FL ) << 4;
1538  int nOutX;
1539 
1540  Scanline pScanline = pW->GetScanline(nY);
1541  Scanline pScanlineAlpha = pA->GetScanline(nMapY);
1542  for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1543  {
1544  long nMapX = pMapX[ nX ];
1545  if (bHMirr)
1546  {
1547  nMapX = aBmpRect.Right() - nMapX;
1548  }
1549  const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1550 
1551  aDstCol = pB->GetColor( nY, nX );
1552  aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pA->GetIndexFromData( pScanlineAlpha, nMapX ) );
1553  aIndex.SetIndex( static_cast<sal_uInt8>( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16 ] +
1554  nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16 ] +
1555  nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16 ] ) );
1556  pW->SetPixelOnData( pScanline, nX, aIndex );
1557  }
1558  }
1559  }
1560 
1561  pB.reset();
1562  pW.reset();
1563  res = aDither;
1564  }
1565  else
1566  {
1567  BitmapScopedWriteAccess pB(aBmp);
1568 
1569  bool bFastBlend = false;
1570  if( pP && pA && pB && !bHMirr && !bVMirr )
1571  {
1572  SalTwoRect aTR(aBmpRect.Left(), aBmpRect.Top(), aBmpRect.GetWidth(), aBmpRect.GetHeight(),
1573  nOffX, nOffY, aOutSz.Width(), aOutSz.Height());
1574 
1575  bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
1576  }
1577 
1578  if( pP && pA && pB && !bFastBlend )
1579  {
1580  switch( pP->GetScanlineFormat() )
1581  {
1583  {
1584  for( nY = 0; nY < nDstHeight; nY++ )
1585  {
1586  long nMapY = pMapY[ nY ];
1587  if ( bVMirr )
1588  {
1589  nMapY = aBmpRect.Bottom() - nMapY;
1590  }
1591  Scanline pPScan = pP->GetScanline( nMapY );
1592  Scanline pAScan = pA->GetScanline( nMapY );
1593  Scanline pBScan = pB->GetScanline( nY );
1594 
1595  for( nX = 0; nX < nDstWidth; nX++ )
1596  {
1597  long nMapX = pMapX[ nX ];
1598 
1599  if ( bHMirr )
1600  {
1601  nMapX = aBmpRect.Right() - nMapX;
1602  }
1603  aDstCol = pB->GetPixelFromData( pBScan, nX );
1604  aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ), pAScan[ nMapX ] );
1605  pB->SetPixelOnData( pBScan, nX, aDstCol );
1606  }
1607  }
1608  }
1609  break;
1610 
1611  default:
1612  {
1613 
1614  for( nY = 0; nY < nDstHeight; nY++ )
1615  {
1616  long nMapY = pMapY[ nY ];
1617 
1618  if ( bVMirr )
1619  {
1620  nMapY = aBmpRect.Bottom() - nMapY;
1621  }
1622  Scanline pAScan = pA->GetScanline( nMapY );
1623  Scanline pBScan = pB->GetScanline(nY);
1624  for( nX = 0; nX < nDstWidth; nX++ )
1625  {
1626  long nMapX = pMapX[ nX ];
1627 
1628  if ( bHMirr )
1629  {
1630  nMapX = aBmpRect.Right() - nMapX;
1631  }
1632  aDstCol = pB->GetPixelFromData( pBScan, nX );
1633  aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pAScan[ nMapX ] );
1634  pB->SetPixelOnData( pBScan, nX, aDstCol );
1635  }
1636  }
1637  }
1638  break;
1639  }
1640  }
1641 
1642  pB.reset();
1643  res = aBmp;
1644  }
1645 
1646  return res;
1647 }
1648 
1649 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Point TopLeft() const
long Width() const
long mnOutOffX
Output offset for device output in pixel (pseudo window offset within window system's frames) ...
Definition: outdev.hxx:342
long mnSrcWidth
Definition: salgtype.hxx:52
Bitmap GetMask() const
Definition: bitmapex.cxx:258
long GetWidth() const
bool DrawAlphaBitmap(const SalTwoRect &, const SalBitmap &rSourceBitmap, const SalBitmap &rAlphaBitmap, const OutputDevice *pOutDev)
long GetHeight() const
sal_uInt8 GetRed() const
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:657
void SetBlue(sal_uInt8 nBlue)
void DrawImage(const Point &rPos, const Image &rImage, DrawImageFlags nStyle=DrawImageFlags::NONE)
This is an overloaded member function, provided for convenience. It differs from the above function o...
long mnSrcHeight
Definition: salgtype.hxx:53
double getHeight() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
long FRound(double fVal)
Scanline GetScanline(long nY) const
long AdjustX(long nHorzMove)
const sal_uLong nVCLLut[256]
virtual void ClipToPaintRegion(tools::Rectangle &rDstRect)
void Merge(const Color &rMergeColor, sal_uInt8 cTransparency)
long Height() const
long mnOutOffY
Output offset for device output in pixel (pseudo window offset within window system's frames) ...
Definition: outdev.hxx:344
void DrawBitmapEx(const Point &rDestPt, const BitmapEx &rBitmapEx)
This is an overloaded member function, provided for convenience. It differs from the above function o...
DrawModeFlags mnDrawMode
Definition: outdev.hxx:355
const std::shared_ptr< SalBitmap > & ImplGetSalBitmap() const
Definition: bitmap.hxx:518
Bitmap const & GetBitmap() const
Definition: alpha.cxx:70
sal_uIntPtr sal_uLong
BmpMirrorFlags AdjustTwoRect(SalTwoRect &rTwoRect, const Size &rSizePix)
Definition: rect.cxx:317
sal_uInt8 GetLuminance() const
bool IsMapModeEnabled() const
Definition: outdev.hxx:1668
vcl::Region maRegion
Definition: outdev.hxx:361
double getX() const
SAL_DLLPRIVATE Bitmap GetDownsampledBitmap(const Size &rDstSz, const Point &rSrcPt, const Size &rSrcSz, const Bitmap &rBmp, long nMaxBmpDPIX, long nMaxBmpDPIY)
Retrieve downsampled and cropped bitmap.
BitmapEx getTransformed(const basegfx::B2DHomMatrix &rTransformation, const basegfx::B2DRange &rVisibleRange, double fMaximumArea) const
Create transformed Bitmap.
Definition: bitmapex.cxx:902
bool mbOutputClipped
Definition: outdev.hxx:381
const sal_uLong nVCLBLut[6]
SAL_DLLPRIVATE bool is_double_buffered_window() const
const MapMode & GetMapMode() const
Definition: outdev.hxx:1673
double getY() const
B2DVector getRange() const
long mnDestWidth
Definition: salgtype.hxx:56
long mnSrcX
Definition: salgtype.hxx:50
void EnableMapMode(bool bEnable=true)
Definition: map.cxx:647
Size GetSizePixel() const
long Width() const
bool mbMap
Definition: outdev.hxx:376
sal_uInt8 GetPixelIndex(long nY, long nX) const
float x
double getMaxX() const
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: bitmapex.cxx:454
const sal_uLong nVCLRLut[6]
long AdjustBottom(long nVertMoveDelta)
void Draw(OutputDevice *pOutDev, const Point &rPos, DrawImageFlags nStyle, const Size *pSize=nullptr)
Definition: Image.cxx:105
bool IsEmpty() const
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
long mnDestY
Definition: salgtype.hxx:55
ScanlineFormat
Definition: Scanline.hxx:28
SAL_DLLPRIVATE void DrawDeviceAlphaBitmapSlowPath(const Bitmap &rBitmap, const AlphaMask &rAlpha, tools::Rectangle aDstRect, tools::Rectangle aBmpRect, Size const &aOutSz, Point const &aOutPt)
bool IsAlpha() const
Definition: bitmapex.cxx:226
long Right() const
bool Mirror(BmpMirrorFlags nMirrorFlags)
Mirror the bitmap.
double getWidth() const
bool isInside(const B2DTuple &rTuple) const
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
SAL_DLLPRIVATE void BlendBitmap(const SalTwoRect &rPosAry, const Bitmap &rBmp)
static bool Filter(BitmapEx &rBmpEx, BitmapFilter const &rFilter)
virtual Bitmap GetBitmap(const Point &rSrcPt, const Size &rSize) const
B2DHomMatrix createScaleTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fTranslateX, double fTranslateY)
MetaActionType
void SetPixelOnData(sal_uInt8 *pData, long nX, const BitmapColor &rBitmapColor)
long Top() const
double getMaxY() const
sal_uInt8 GetBlue() const
SAL_DLLPRIVATE long ImplLogicXToDevicePixel(long nX) const
Convert a logical X coordinate to a device pixel's X coordinate.
Definition: map.cxx:410
B2IRange fround(const B2DRange &rRange)
void DrawBitmap(const SalTwoRect &rPosAry, const SalBitmap &rSalBitmap, const OutputDevice *pOutDev)
void DrawRect(const tools::Rectangle &rRect)
Definition: rect.cxx:32
static bool less(const double &rfValA, const double &rfValB)
float y
bool Mirror(BmpMirrorFlags nMirrorFlags)
Mirror the bitmap.
Definition: bitmapex.cxx:333
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:316
Bitmap GetBitmap(const Color *pTransReplaceColor=nullptr) const
Definition: bitmapex.cxx:236
void DrawShadowBitmapEx(const BitmapEx &rBitmapEx,::Color aShadowColor)
bool isEmpty() const
bool IsEmpty() const
Definition: bitmapex.cxx:203
void SetLineColor()
Bitmap maBitmap
Definition: bitmapex.hxx:480
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
SAL_DLLPRIVATE long ImplLogicYToDevicePixel(long nY) const
Convert a logical Y coordinate to a device pixel's Y coordinate.
Definition: map.cxx:420
bool IsRTLEnabled() const
Definition: outdev.hxx:1353
bool BlendBitmap(const SalTwoRect &rPosAry, const SalBitmap &rSalBitmap, const OutputDevice *pOutDev)
constexpr sal_uInt8 ColorChannelMerge(sal_uInt8 nDst, sal_uInt8 nSrc, sal_uInt8 nSrcTrans)
#define DBG_ASSERT(sCon, aError)
void Erase(sal_uInt8 cTransparency)
Definition: alpha.cxx:75
bool IsClipRegion() const
Definition: outdev.hxx:662
long AdjustY(long nVertMove)
ScanlineFormat GetScanlineFormat() const
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
bool DrawTransformedBitmap(const basegfx::B2DPoint &rNull, const basegfx::B2DPoint &rX, const basegfx::B2DPoint &rY, const SalBitmap &rSourceBitmap, const SalBitmap *pAlphaBitmap, const OutputDevice *pOutDev)
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
bool BlendAlphaBitmap(const SalTwoRect &rPosAry, const SalBitmap &rSalSrcBitmap, const SalBitmap &rSalMaskBitmap, const SalBitmap &rSalAlphaBitmap, const OutputDevice *pOutDev)
void SetSize(const Size &rSize)
int i
static bool equalZero(const double &rfVal)
void SetFillColor()
const sal_uLong nVCLDitherLut[256]
SAL_DLLPRIVATE void ImplFillOpaqueRectangle(const tools::Rectangle &rRect)
Used for alpha VDev, to set areas to opaque.
Definition: virdev.cxx:340
void SetRed(sal_uInt8 nRed)
TransparentType GetTransparentType() const
Definition: bitmapex.hxx:73
long Bottom() const
void scale(double fX, double fY)
bool ImplFastBitmapBlending(BitmapWriteAccess const &rDstWA, const BitmapReadAccess &rSrcRA, const BitmapReadAccess &rMskRA, const SalTwoRect &rTR)
Definition: bmpfast.cxx:656
BmpMirrorFlags
Definition: bitmap.hxx:36
RasterOp meRasterOp
Definition: outdev.hxx:368
Size GetOutputSizePixel() const
Definition: outdev.hxx:441
virtual sal_uInt16 GetBitCount() const
Definition: outdev.cxx:305
bool IsTransparent() const
Definition: bitmapex.cxx:221
void DrawBitmap(const Point &rDestPt, const Bitmap &rBitmap)
This is an overloaded member function, provided for convenience. It differs from the above function o...
SAL_DLLPRIVATE void DrawDeviceAlphaBitmap(const Bitmap &rBmp, const AlphaMask &rAlpha, const Point &rDestPt, const Size &rDestSize, const Point &rSrcPtPixel, const Size &rSrcSizePixel)
void intersect(const B2DRange &rRange)
void DrawPixel(const Point &rPt)
Definition: pixel.cxx:54
long X() const
Size GetSize() const
void DrawTransformedBitmapEx(const basegfx::B2DHomMatrix &rTransformation, const BitmapEx &rBitmapEx)
Draw BitmapEx transformed.
void SetIndex(sal_uInt8 cIndex)
Definition: BitmapColor.hxx:66
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
MapUnit GetMapUnit()
long mnSrcY
Definition: salgtype.hxx:51
SAL_DLLPRIVATE std::shared_ptr< SalBitmap > const & ImplGetMaskSalBitmap() const
Definition: bitmapex.hxx:466
void SetEmpty()
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1185
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:940
SAL_DLLPRIVATE std::shared_ptr< SalBitmap > const & ImplGetBitmapSalBitmap() const
Definition: bitmapex.hxx:465
sal_uInt8 GetGreen() const
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:331
SAL_DLLPRIVATE vcl::Region ImplPixelToDevicePixel(const vcl::Region &rRegion) const
Convert a region in pixel units to a region in device pixel units and coords.
Definition: map.cxx:637
double getMinY() const
const sal_uLong nVCLGLut[6]
AlphaMask GetAlpha() const
Definition: bitmapex.cxx:268
long AdjustRight(long nHorzMoveDelta)
long Height() const
#define SAL_WARN_IF(condition, area, stream)
unsigned char sal_uInt8
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
Scale the bitmap.
Definition: bitmap3.cxx:818
long mnDestX
Definition: salgtype.hxx:54
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: bitmap3.cxx:226
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:539
BitmapColor GetColor(long nY, long nX) const
void SetGreen(sal_uInt8 nGreen)
virtual vcl::Region GetActiveClipRegion() const
bool mbInitClipRegion
Definition: outdev.hxx:388
Definition: image.hxx:51
virtual void ScaleBitmap(Bitmap &rBmp, SalTwoRect &rPosAry)
virtual void DrawDeviceBitmap(const Point &rDestPt, const Size &rDestSize, const Point &rSrcPtPixel, const Size &rSrcSizePixel, BitmapEx &rBitmapEx)
B2DPoint getMinimum() const
virtual void InitClipRegion()
bool IsEmpty() const
Definition: bitmap.hxx:551
const Point & GetOrigin() const
Definition: mapmod.cxx:165
SAL_DLLPRIVATE long ImplLogicWidthToDevicePixel(long nWidth) const
Convert a logical width to a width in units of device pixels.
Definition: map.cxx:430
long Left() const
void translate(double fX, double fY)
BitmapColor GetPixelFromData(const sal_uInt8 *pData, long nX) const
SAL_DLLPRIVATE long ImplLogicHeightToDevicePixel(long nHeight) const
Convert a logical height to a height in units of device pixels.
Definition: map.cxx:440
long mnOutWidth
Definition: outdev.hxx:345
bool Erase(const Color &rFillColor)
Fill the entire bitmap with the given color.
Definition: bitmappaint.cxx:34
long mnDestHeight
Definition: salgtype.hxx:57
BitmapEx GetBitmapEx(const Point &rSrcPt, const Size &rSize) const
Query extended bitmap (with alpha channel, if available).
virtual bool TransformAndReduceBitmapExToTargetRange(const basegfx::B2DHomMatrix &aFullTransform, basegfx::B2DRange &aVisibleRange, double &fMaximumArea)
Transform and reduce the area that needs to be drawn of the bitmap and return the new visible range a...
void Move(long nHorzMove, long nVertMove)
double getMinX() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
virtual bool DrawTransformBitmapExDirect(const basegfx::B2DHomMatrix &aFullTransform, const BitmapEx &rBitmapEx)
Transform and draw a bitmap directly.
long getHeight() const
std::shared_ptr< SalBitmap > GetBitmap(long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev)
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, long nMin, long nMax)
const Size & GetSizePixel() const
Definition: bitmapex.hxx:83
static bool isVCLOpenGLEnabled()
Returns true if VCL has OpenGL rendering enabled.
long mnOutHeight
Definition: outdev.hxx:346
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:589
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:60
long getWidth() const
basegfx::B2DHomMatrix GetViewTransformation() const
Definition: map.cxx:853
void setWidth(long nWidth)
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor)
DrawImageFlags
Definition: outdev.hxx:172
long Y() const
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:319
SAL_DLLPRIVATE void ImplSetSalBitmap(const std::shared_ptr< SalBitmap > &xImpBmp)
SAL_DLLPRIVATE Bitmap BlendBitmapWithAlpha(Bitmap &aBmp, BitmapReadAccess const *pP, BitmapReadAccess const *pA, const tools::Rectangle &aDstRect, const sal_Int32 nOffY, const sal_Int32 nDstHeight, const sal_Int32 nOffX, const sal_Int32 nDstWidth, const long *pMapX, const long *pMapY)
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, long nX) const
void setHeight(long nHeight)