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