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