Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <vcl/bitmap.hxx>
21 : #include <vcl/bitmapex.hxx>
22 : #include <vcl/bmpacc.hxx>
23 : #include <vcl/outdev.hxx>
24 : #include <vcl/virdev.hxx>
25 : #include <vcl/image.hxx>
26 :
27 : #include <bmpfast.hxx>
28 : #include <salgdi.hxx>
29 : #include <impbmp.hxx>
30 : #include <image.h>
31 :
32 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
33 : #include <boost/scoped_array.hpp>
34 :
35 :
36 234701 : void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
37 : {
38 234701 : const Size aSizePix( rBitmap.GetSizePixel() );
39 234701 : DrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION );
40 234701 : }
41 :
42 1676 : void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
43 : {
44 1676 : DrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION );
45 1676 : }
46 :
47 :
48 236377 : void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize,
49 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
50 : const Bitmap& rBitmap, const sal_uLong nAction )
51 : {
52 236377 : if( ImplIsRecordLayout() )
53 943 : return;
54 :
55 236377 : if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) )
56 : {
57 0 : return;
58 : }
59 236377 : if ( ROP_INVERT == meRasterOp )
60 : {
61 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
62 0 : return;
63 : }
64 :
65 236377 : Bitmap aBmp( rBitmap );
66 :
67 236377 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
68 : DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
69 : {
70 0 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
71 : {
72 : sal_uInt8 cCmpVal;
73 :
74 0 : if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
75 0 : cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
76 : else
77 0 : cCmpVal = 255;
78 :
79 0 : Color aCol( cCmpVal, cCmpVal, cCmpVal );
80 0 : Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
81 0 : SetLineColor( aCol );
82 0 : SetFillColor( aCol );
83 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
84 0 : Pop();
85 0 : return;
86 : }
87 0 : else if( !!aBmp )
88 : {
89 0 : if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
90 0 : aBmp.Convert( BMP_CONVERSION_8BIT_GREYS );
91 :
92 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
93 0 : aBmp.Convert( BMP_CONVERSION_GHOSTED );
94 : }
95 : }
96 :
97 236377 : if ( mpMetaFile )
98 : {
99 886 : switch( nAction )
100 : {
101 : case( META_BMP_ACTION ):
102 0 : mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) );
103 0 : break;
104 :
105 : case( META_BMPSCALE_ACTION ):
106 886 : mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
107 886 : break;
108 :
109 : case( META_BMPSCALEPART_ACTION ):
110 : mpMetaFile->AddAction( new MetaBmpScalePartAction(
111 0 : rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) );
112 0 : break;
113 : }
114 : }
115 :
116 236377 : if ( !IsDeviceOutputNecessary() )
117 943 : return;
118 :
119 235434 : if ( !mpGraphics )
120 0 : if ( !AcquireGraphics() )
121 0 : return;
122 :
123 235434 : if ( mbInitClipRegion )
124 11740 : InitClipRegion();
125 :
126 235434 : if ( mbOutputClipped )
127 0 : return;
128 :
129 235434 : if( !aBmp.IsEmpty() )
130 : {
131 : SalTwoRect aPosAry;
132 :
133 235396 : aPosAry.mnSrcX = rSrcPtPixel.X();
134 235396 : aPosAry.mnSrcY = rSrcPtPixel.Y();
135 235396 : aPosAry.mnSrcWidth = rSrcSizePixel.Width();
136 235396 : aPosAry.mnSrcHeight = rSrcSizePixel.Height();
137 235396 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
138 235396 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
139 235396 : aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
140 235396 : aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
141 :
142 235396 : if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
143 : {
144 235396 : const sal_uLong nMirrFlags = AdjustTwoRect( aPosAry, aBmp.GetSizePixel() );
145 :
146 235396 : if ( nMirrFlags )
147 0 : aBmp.Mirror( nMirrFlags );
148 :
149 235396 : if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
150 : {
151 235396 : if ( nAction == META_BMPSCALE_ACTION )
152 790 : ScaleBitmap (aBmp, aPosAry);
153 :
154 235396 : mpGraphics->DrawBitmap( aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap(), this );
155 : }
156 : }
157 : }
158 :
159 235434 : if( mpAlphaVDev )
160 : {
161 : // #i32109#: Make bitmap area opaque
162 0 : mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
163 235434 : }
164 : }
165 :
166 0 : Bitmap OutputDevice::GetDownsampledBitmap( const Size& rDstSz,
167 : const Point& rSrcPt, const Size& rSrcSz,
168 : const Bitmap& rBmp, long nMaxBmpDPIX, long nMaxBmpDPIY )
169 : {
170 0 : Bitmap aBmp( rBmp );
171 :
172 0 : if( !aBmp.IsEmpty() )
173 : {
174 0 : Point aPoint;
175 0 : const Rectangle aBmpRect( aPoint, aBmp.GetSizePixel() );
176 0 : Rectangle aSrcRect( rSrcPt, rSrcSz );
177 :
178 : // do cropping if necessary
179 0 : if( aSrcRect.Intersection( aBmpRect ) != aBmpRect )
180 : {
181 0 : if( !aSrcRect.IsEmpty() )
182 0 : aBmp.Crop( aSrcRect );
183 : else
184 0 : aBmp.SetEmpty();
185 : }
186 :
187 0 : if( !aBmp.IsEmpty() )
188 : {
189 : // do downsampling if necessary
190 0 : Size aDstSizeTwip( PixelToLogic( LogicToPixel( rDstSz ), MAP_TWIP ) );
191 :
192 : // #103209# Normalize size (mirroring has to happen outside of this method)
193 0 : aDstSizeTwip = Size( labs(aDstSizeTwip.Width()), labs(aDstSizeTwip.Height()) );
194 :
195 0 : const Size aBmpSize( aBmp.GetSizePixel() );
196 0 : const double fBmpPixelX = aBmpSize.Width();
197 0 : const double fBmpPixelY = aBmpSize.Height();
198 0 : const double fMaxPixelX = aDstSizeTwip.Width() * nMaxBmpDPIX / 1440.0;
199 0 : const double fMaxPixelY = aDstSizeTwip.Height() * nMaxBmpDPIY / 1440.0;
200 :
201 : // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
202 0 : if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
203 0 : ( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) &&
204 0 : ( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) )
205 : {
206 : // do scaling
207 0 : Size aNewBmpSize;
208 0 : const double fBmpWH = fBmpPixelX / fBmpPixelY;
209 0 : const double fMaxWH = fMaxPixelX / fMaxPixelY;
210 :
211 0 : if( fBmpWH < fMaxWH )
212 : {
213 0 : aNewBmpSize.Width() = FRound( fMaxPixelY * fBmpWH );
214 0 : aNewBmpSize.Height() = FRound( fMaxPixelY );
215 : }
216 0 : else if( fBmpWH > 0.0 )
217 : {
218 0 : aNewBmpSize.Width() = FRound( fMaxPixelX );
219 0 : aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH);
220 : }
221 :
222 0 : if( aNewBmpSize.Width() && aNewBmpSize.Height() )
223 0 : aBmp.Scale( aNewBmpSize );
224 : else
225 0 : aBmp.SetEmpty();
226 : }
227 : }
228 : }
229 :
230 0 : return aBmp;
231 : }
232 :
233 72206 : void OutputDevice::DrawBitmapEx( const Point& rDestPt,
234 : const BitmapEx& rBitmapEx )
235 : {
236 72206 : if( ImplIsRecordLayout() )
237 72206 : return;
238 :
239 72206 : if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
240 : {
241 10036 : DrawBitmap( rDestPt, rBitmapEx.GetBitmap() );
242 : }
243 : else
244 : {
245 62170 : const Size aSizePix( rBitmapEx.GetSizePixel() );
246 62170 : DrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION );
247 : }
248 : }
249 :
250 16116 : void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
251 : const BitmapEx& rBitmapEx )
252 : {
253 16116 : if( ImplIsRecordLayout() )
254 16116 : return;
255 :
256 16116 : if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
257 : {
258 948 : DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() );
259 : }
260 : else
261 : {
262 15168 : DrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION );
263 : }
264 : }
265 :
266 :
267 308066 : void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
268 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
269 : const BitmapEx& rBitmapEx, const sal_uLong nAction )
270 : {
271 :
272 308066 : if( ImplIsRecordLayout() )
273 0 : return;
274 :
275 308066 : if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
276 : {
277 0 : DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() );
278 : }
279 : else
280 : {
281 308066 : if ( mnDrawMode & DRAWMODE_NOBITMAP )
282 684 : return;
283 :
284 308066 : if ( ROP_INVERT == meRasterOp )
285 : {
286 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
287 0 : return;
288 : }
289 :
290 308066 : BitmapEx aBmpEx( rBitmapEx );
291 :
292 308066 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
293 : DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
294 : {
295 0 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
296 : {
297 0 : Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 );
298 : sal_uInt8 cCmpVal;
299 :
300 0 : if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
301 0 : cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
302 : else
303 0 : cCmpVal = 255;
304 :
305 0 : aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
306 :
307 0 : if( aBmpEx.IsAlpha() )
308 : {
309 : // Create one-bit mask out of alpha channel, by
310 : // thresholding it at alpha=0.5. As
311 : // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
312 : // output, having alpha-induced grey levels is not
313 : // acceptable.
314 0 : Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() );
315 0 : aMask.MakeMono( 129 );
316 0 : aBmpEx = BitmapEx( aColorBmp, aMask );
317 : }
318 : else
319 : {
320 0 : aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
321 0 : }
322 : }
323 0 : else if( !!aBmpEx )
324 : {
325 0 : if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
326 0 : aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
327 :
328 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
329 0 : aBmpEx.Convert( BMP_CONVERSION_GHOSTED );
330 : }
331 : }
332 :
333 308066 : if ( mpMetaFile )
334 : {
335 467 : switch( nAction )
336 : {
337 : case( META_BMPEX_ACTION ):
338 6 : mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
339 6 : break;
340 :
341 : case( META_BMPEXSCALE_ACTION ):
342 78 : mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
343 78 : break;
344 :
345 : case( META_BMPEXSCALEPART_ACTION ):
346 : mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
347 383 : rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
348 383 : break;
349 : }
350 : }
351 :
352 308066 : if ( !IsDeviceOutputNecessary() )
353 141 : return;
354 :
355 307925 : if ( !mpGraphics )
356 78 : if ( !AcquireGraphics() )
357 0 : return;
358 :
359 307925 : if ( mbInitClipRegion )
360 156908 : InitClipRegion();
361 :
362 307925 : if ( mbOutputClipped )
363 543 : return;
364 :
365 307382 : DrawDeviceBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmpEx );
366 : }
367 : }
368 :
369 251133 : Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
370 : {
371 251133 : Bitmap aBmp;
372 251133 : long nX = ImplLogicXToDevicePixel( rSrcPt.X() );
373 251133 : long nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
374 251133 : long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
375 251133 : long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
376 :
377 251133 : if ( mpGraphics || AcquireGraphics() )
378 : {
379 251133 : if ( nWidth > 0 && nHeight > 0 && nX <= (mnOutWidth + mnOutOffX) && nY <= (mnOutHeight + mnOutOffY))
380 : {
381 250977 : Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
382 250977 : bool bClipped = false;
383 :
384 : // X-Coordinate outside of draw area?
385 250977 : if ( nX < mnOutOffX )
386 : {
387 0 : nWidth -= ( mnOutOffX - nX );
388 0 : nX = mnOutOffX;
389 0 : bClipped = true;
390 : }
391 :
392 : // Y-Coordinate outside of draw area?
393 250977 : if ( nY < mnOutOffY )
394 : {
395 0 : nHeight -= ( mnOutOffY - nY );
396 0 : nY = mnOutOffY;
397 0 : bClipped = true;
398 : }
399 :
400 : // Width outside of draw area?
401 250977 : if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
402 : {
403 0 : nWidth = mnOutOffX + mnOutWidth - nX;
404 0 : bClipped = true;
405 : }
406 :
407 : // Height outside of draw area?
408 250977 : if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
409 : {
410 0 : nHeight = mnOutOffY + mnOutHeight - nY;
411 0 : bClipped = true;
412 : }
413 :
414 250977 : if ( bClipped )
415 : {
416 : // If the visible part has been clipped, we have to create a
417 : // Bitmap with the correct size in which we copy the clipped
418 : // Bitmap to the correct position.
419 0 : VirtualDevice aVDev( *this );
420 :
421 0 : if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) )
422 : {
423 0 : if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->AcquireGraphics() )
424 : {
425 : SalTwoRect aPosAry;
426 :
427 0 : aPosAry.mnSrcX = nX;
428 0 : aPosAry.mnSrcY = nY;
429 0 : aPosAry.mnSrcWidth = nWidth;
430 0 : aPosAry.mnSrcHeight = nHeight;
431 0 : aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L;
432 0 : aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L;
433 0 : aPosAry.mnDestWidth = nWidth;
434 0 : aPosAry.mnDestHeight = nHeight;
435 :
436 0 : if ( (nWidth > 0) && (nHeight > 0) )
437 : {
438 0 : (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( aPosAry, mpGraphics, this, this );
439 : }
440 : else
441 : {
442 : OSL_ENSURE(false, "CopyBits with negative width or height (!)");
443 : }
444 :
445 0 : aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
446 : }
447 : else
448 0 : bClipped = false;
449 : }
450 : else
451 0 : bClipped = false;
452 : }
453 :
454 250977 : if ( !bClipped )
455 : {
456 250977 : SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
457 :
458 250977 : if( pSalBmp )
459 : {
460 250977 : ImpBitmap* pImpBmp = new ImpBitmap;
461 250977 : pImpBmp->ImplSetSalBitmap( pSalBmp );
462 250977 : aBmp.ImplSetImpBitmap( pImpBmp );
463 : }
464 : }
465 : }
466 : }
467 :
468 251133 : return aBmp;
469 : }
470 :
471 6631 : BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
472 : {
473 :
474 : // #110958# Extract alpha value from VDev, if any
475 6631 : if( mpAlphaVDev )
476 : {
477 6631 : Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
478 :
479 : // ensure 8 bit alpha
480 6631 : if( aAlphaBitmap.GetBitCount() > 8 )
481 6593 : aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
482 :
483 6631 : return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
484 : }
485 : else
486 0 : return GetBitmap( rSrcPt, rSize );
487 : }
488 :
489 307382 : void OutputDevice::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
490 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
491 : BitmapEx& rBitmapEx )
492 : {
493 307382 : if (rBitmapEx.IsAlpha())
494 : {
495 288015 : DrawDeviceAlphaBitmap(rBitmapEx.GetBitmap(), rBitmapEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel);
496 : }
497 19367 : else if (!!rBitmapEx)
498 : {
499 : SalTwoRect aPosAry;
500 :
501 19367 : aPosAry.mnSrcX = rSrcPtPixel.X();
502 19367 : aPosAry.mnSrcY = rSrcPtPixel.Y();
503 19367 : aPosAry.mnSrcWidth = rSrcSizePixel.Width();
504 19367 : aPosAry.mnSrcHeight = rSrcSizePixel.Height();
505 19367 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
506 19367 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
507 19367 : aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
508 19367 : aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
509 :
510 19367 : const sal_uLong nMirrFlags = AdjustTwoRect(aPosAry, rBitmapEx.GetSizePixel());
511 :
512 19367 : if (aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight)
513 : {
514 :
515 19367 : if (nMirrFlags)
516 0 : rBitmapEx.Mirror(nMirrFlags);
517 :
518 19367 : const SalBitmap* pSalSrcBmp = rBitmapEx.ImplGetBitmapImpBitmap()->ImplGetSalBitmap();
519 19367 : const ImpBitmap* pMaskBmp = rBitmapEx.ImplGetMaskImpBitmap();
520 :
521 19367 : if (pMaskBmp)
522 : {
523 19367 : SalBitmap* pSalAlphaBmp = pMaskBmp->ImplGetSalBitmap();
524 19367 : bool bTryDirectPaint(pSalSrcBmp && pSalAlphaBmp);
525 :
526 19367 : if (bTryDirectPaint)
527 : {
528 : // only paint direct when no scaling and no MapMode, else the
529 : // more expensive conversions may be done for short-time Bitmap/BitmapEx
530 : // used for buffering only
531 19367 : if(!IsMapMode() && aPosAry.mnSrcWidth == aPosAry.mnDestWidth && aPosAry.mnSrcHeight == aPosAry.mnDestHeight)
532 : {
533 19277 : bTryDirectPaint = false;
534 : }
535 : }
536 :
537 19367 : if (bTryDirectPaint && mpGraphics->DrawAlphaBitmap(aPosAry, *pSalSrcBmp, *pSalAlphaBmp, this))
538 : {
539 : // tried to paint as alpha directly. If tis worked, we are done (except
540 : // alpha, see below)
541 : }
542 : else
543 : {
544 : // #4919452# reduce operation area to bounds of
545 : // cliprect. since masked transparency involves
546 : // creation of a large vdev and copying the screen
547 : // content into that (slooow read from framebuffer),
548 : // that should considerably increase performance for
549 : // large bitmaps and small clippings.
550 :
551 : // Note that this optimization is a workaround for a
552 : // Writer peculiarity, namely, to decompose background
553 : // graphics into myriads of disjunct, tiny
554 : // rectangles. That otherwise kills us here, since for
555 : // transparent output, SAL always prepares the whole
556 : // bitmap, if aPosAry contains the whole bitmap (and
557 : // it's _not_ to blame for that).
558 :
559 : // Note the call to ImplPixelToDevicePixel(), since
560 : // aPosAry already contains the mnOutOff-offsets, they
561 : // also have to be applied to the region
562 19367 : Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
563 :
564 : // TODO: Also respect scaling (that's a bit tricky,
565 : // since the source points have to move fractional
566 : // amounts (which is not possible, thus has to be
567 : // emulated by increases copy area)
568 : // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
569 : // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
570 :
571 : // for now, only identity scales allowed
572 39897 : if (!aClipRegionBounds.IsEmpty() &&
573 20518 : aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
574 1151 : aPosAry.mnDestHeight == aPosAry.mnSrcHeight)
575 : {
576 : // now intersect dest rect with clip region
577 : aClipRegionBounds.Intersection(Rectangle(aPosAry.mnDestX,
578 : aPosAry.mnDestY,
579 1151 : aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
580 2302 : aPosAry.mnDestY + aPosAry.mnDestHeight - 1));
581 :
582 : // Note: I could theoretically optimize away the
583 : // DrawBitmap below, if the region is empty
584 : // here. Unfortunately, cannot rule out that
585 : // somebody relies on the side effects.
586 1151 : if (!aClipRegionBounds.IsEmpty())
587 : {
588 1151 : aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
589 1151 : aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
590 1151 : aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
591 1151 : aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
592 :
593 1151 : aPosAry.mnDestX = aClipRegionBounds.Left();
594 1151 : aPosAry.mnDestY = aClipRegionBounds.Top();
595 1151 : aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
596 1151 : aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
597 : }
598 : }
599 :
600 : mpGraphics->DrawBitmap(aPosAry, *pSalSrcBmp,
601 19367 : *pMaskBmp->ImplGetSalBitmap(),
602 19367 : this);
603 : }
604 :
605 : // #110958# Paint mask to alpha channel. Luckily, the
606 : // black and white representation of the mask maps to
607 : // the alpha channel
608 :
609 : // #i25167# Restrict mask painting to _opaque_ areas
610 : // of the mask, otherwise we spoil areas where no
611 : // bitmap content was ever visible. Interestingly
612 : // enough, this can be achieved by taking the mask as
613 : // the transparency mask of itself
614 19367 : if (mpAlphaVDev)
615 : mpAlphaVDev->DrawBitmapEx(rDestPt,
616 : rDestSize,
617 : BitmapEx(rBitmapEx.GetMask(),
618 308 : rBitmapEx.GetMask()));
619 : }
620 : else
621 : {
622 0 : mpGraphics->DrawBitmap(aPosAry, *pSalSrcBmp, this);
623 :
624 0 : if (mpAlphaVDev)
625 : {
626 : // #i32109#: Make bitmap area opaque
627 0 : mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
628 : }
629 : }
630 : }
631 : }
632 307382 : }
633 :
634 288015 : void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& rAlpha,
635 : const Point& rDestPt, const Size& rDestSize,
636 : const Point& rSrcPtPixel, const Size& rSrcSizePixel )
637 : {
638 288015 : Point aOutPt( LogicToPixel( rDestPt ) );
639 288015 : Size aOutSz( LogicToPixel( rDestSize ) );
640 288015 : Rectangle aDstRect( Point(), GetOutputSizePixel() );
641 288015 : const bool bHMirr = aOutSz.Width() < 0;
642 288015 : const bool bVMirr = aOutSz.Height() < 0;
643 :
644 288015 : ClipToPaintRegion(aDstRect);
645 :
646 288015 : if( bHMirr )
647 : {
648 0 : aOutSz.Width() = -aOutSz.Width();
649 0 : aOutPt.X() -= ( aOutSz.Width() - 1L );
650 : }
651 :
652 288015 : if( bVMirr )
653 : {
654 0 : aOutSz.Height() = -aOutSz.Height();
655 0 : aOutPt.Y() -= ( aOutSz.Height() - 1L );
656 : }
657 :
658 288015 : if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
659 : {
660 211707 : bool bNativeAlpha = false;
661 211707 : static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
662 : // #i83087# Naturally, system alpha blending cannot work with
663 : // separate alpha VDev
664 211707 : bool bTryDirectPaint(!mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr);
665 :
666 : #ifdef WNT
667 : if(bTryDirectPaint)
668 : {
669 : // only paint direct when no scaling and no MapMode, else the
670 : // more expensive conversions may be done for short-time Bitmap/BitmapEx
671 : // used for buffering only
672 : if(!IsMapMode() && rSrcSizePixel.Width() == aOutSz.Width() && rSrcSizePixel.Height() == aOutSz.Height())
673 : {
674 : bTryDirectPaint = false;
675 : }
676 : }
677 : #endif
678 :
679 211707 : if(bTryDirectPaint)
680 : {
681 211632 : Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
682 : SalTwoRect aTR = {
683 423264 : rSrcPtPixel.X(), rSrcPtPixel.Y(),
684 423264 : rSrcSizePixel.Width(), rSrcSizePixel.Height(),
685 423264 : aRelPt.X(), aRelPt.Y(),
686 423264 : aOutSz.Width(), aOutSz.Height()
687 1693056 : };
688 211632 : SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
689 211632 : SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
690 211632 : bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this );
691 : }
692 :
693 211707 : VirtualDevice* pOldVDev = mpAlphaVDev;
694 :
695 211707 : Rectangle aBmpRect( Point(), rBmp.GetSizePixel() );
696 635121 : if( !bNativeAlpha
697 846828 : && !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() )
698 : {
699 : // The scaling in this code path produces really ugly results - it
700 : // does the most trivial scaling with no smoothing.
701 :
702 211707 : GDIMetaFile* pOldMetaFile = mpMetaFile;
703 211707 : const bool bOldMap = mbMap;
704 211707 : mpMetaFile = NULL; // fdo#55044 reset before GetBitmap!
705 211707 : mbMap = false;
706 211707 : Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
707 :
708 : // #109044# The generated bitmap need not necessarily be
709 : // of aDstRect dimensions, it's internally clipped to
710 : // window bounds. Thus, we correct the dest size here,
711 : // since we later use it (in nDstWidth/Height) for pixel
712 : // access)
713 : // #i38887# reading from screen may sometimes fail
714 211707 : if( aBmp.ImplGetImpBitmap() )
715 211707 : aDstRect.SetSize( aBmp.GetSizePixel() );
716 :
717 423414 : BitmapColor aDstCol;
718 211707 : const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
719 211707 : const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
720 211707 : const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
721 : // calculate offset in original bitmap
722 : // in RTL case this is a little more complicated since the contents of the
723 : // bitmap is not mirrored (it never is), however the paint region and bmp region
724 : // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
725 : // is content wise somewhere else and needs to take mirroring into account
726 211707 : const long nOffX = IsRTLEnabled()
727 39 : ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X())
728 211746 : : aDstRect.Left() - aOutPt.X(),
729 211707 : nOffY = aDstRect.Top() - aOutPt.Y();
730 : long nX, nOutX, nY, nOutY;
731 211707 : long nMirrOffX = 0;
732 211707 : long nMirrOffY = 0;
733 423414 : boost::scoped_array<long> pMapX(new long[ nDstWidth ]);
734 423414 : boost::scoped_array<long> pMapY(new long[ nDstHeight ]);
735 :
736 : // create horizontal mapping table
737 211707 : if( bHMirr )
738 0 : nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
739 :
740 8297159 : for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
741 : {
742 8085452 : pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
743 8085452 : if( bHMirr )
744 0 : pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
745 : }
746 :
747 : // create vertical mapping table
748 211707 : if( bVMirr )
749 0 : nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
750 :
751 7917610 : for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
752 : {
753 7705903 : pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
754 :
755 7705903 : if( bVMirr )
756 0 : pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
757 : }
758 :
759 211707 : BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
760 211707 : BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
761 :
762 : DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
763 : pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
764 : "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
765 :
766 : // #i38887# reading from screen may sometimes fail
767 211707 : if( aBmp.ImplGetImpBitmap() )
768 : {
769 211707 : Bitmap aTmp;
770 :
771 211707 : if( mpAlphaVDev )
772 : {
773 150 : aTmp = BlendBitmapWithAlpha(
774 : aBmp,pP,pA,
775 : aDstRect,
776 : nOffY,nDstHeight,
777 : nOffX,nDstWidth,
778 150 : pMapX.get(),pMapY.get() );
779 : }
780 : else
781 : {
782 423264 : aTmp = BlendBitmap(
783 : aBmp,pP,pA,
784 : nOffY,nDstHeight,
785 : nOffX,nDstWidth,
786 : aBmpRect,aOutSz,
787 : bHMirr,bVMirr,
788 423264 : pMapX.get(),pMapY.get() );
789 : }
790 :
791 : // #110958# Disable alpha VDev, we're doing the necessary
792 : // stuff explicitly furher below
793 211707 : if( mpAlphaVDev )
794 75 : mpAlphaVDev = NULL;
795 :
796 : DrawBitmap( aDstRect.TopLeft(),
797 211707 : aTmp );
798 :
799 : // #110958# Enable alpha VDev again
800 211707 : mpAlphaVDev = pOldVDev;
801 : }
802 :
803 211707 : ( (Bitmap&) rBmp ).ReleaseAccess( pP );
804 211707 : ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
805 :
806 211707 : mbMap = bOldMap;
807 423414 : mpMetaFile = pOldMetaFile;
808 : }
809 : }
810 288015 : }
811 :
812 790 : void OutputDevice::ScaleBitmap (Bitmap &rBmp, SalTwoRect &rPosAry)
813 : {
814 790 : const double nScaleX = rPosAry.mnDestWidth / static_cast<double>( rPosAry.mnSrcWidth );
815 790 : const double nScaleY = rPosAry.mnDestHeight / static_cast<double>( rPosAry.mnSrcHeight );
816 :
817 : // If subsampling, use Bitmap::Scale for subsampling for better quality.
818 790 : if ( nScaleX < 1.0 || nScaleY < 1.0 )
819 : {
820 94 : rBmp.Scale ( nScaleX, nScaleY );
821 94 : rPosAry.mnSrcWidth = rPosAry.mnDestWidth;
822 94 : rPosAry.mnSrcHeight = rPosAry.mnDestHeight;
823 : }
824 790 : }
825 :
826 34 : bool OutputDevice::DrawTransformBitmapExDirect(
827 : const basegfx::B2DHomMatrix& aFullTransform,
828 : const BitmapEx& rBitmapEx)
829 : {
830 34 : bool bDone = false;
831 :
832 : // try to paint directly
833 34 : const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0));
834 68 : const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0));
835 68 : const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0));
836 34 : SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetImpBitmap()->ImplGetSalBitmap();
837 34 : SalBitmap* pSalAlphaBmp = 0;
838 :
839 34 : if(rBitmapEx.IsTransparent())
840 : {
841 34 : if(rBitmapEx.IsAlpha())
842 : {
843 34 : pSalAlphaBmp = rBitmapEx.GetAlpha().ImplGetImpBitmap()->ImplGetSalBitmap();
844 : }
845 : else
846 : {
847 0 : pSalAlphaBmp = rBitmapEx.GetMask().ImplGetImpBitmap()->ImplGetSalBitmap();
848 : }
849 : }
850 :
851 : bDone = mpGraphics->DrawTransformedBitmap(
852 : aNull,
853 : aTopX,
854 : aTopY,
855 : *pSalSrcBmp,
856 : pSalAlphaBmp,
857 34 : this);
858 :
859 68 : return bDone;
860 : };
861 :
862 34 : bool OutputDevice::TransformAndReduceBitmapExToTargetRange(
863 : const basegfx::B2DHomMatrix& aFullTransform,
864 : basegfx::B2DRange &aVisibleRange,
865 : double &fMaximumArea)
866 : {
867 : // limit TargetRange to existing pixels (if pixel device)
868 : // first get discrete range of object
869 34 : basegfx::B2DRange aFullPixelRange(aVisibleRange);
870 :
871 34 : aFullPixelRange.transform(aFullTransform);
872 :
873 34 : if(basegfx::fTools::equalZero(aFullPixelRange.getWidth()) || basegfx::fTools::equalZero(aFullPixelRange.getHeight()))
874 : {
875 : // object is outside of visible area
876 0 : return false;
877 : }
878 :
879 : // now get discrete target pixels; start with OutDev pixel size and evtl.
880 : // intersect with active clipping area
881 : basegfx::B2DRange aOutPixel(
882 : 0.0,
883 : 0.0,
884 68 : GetOutputSizePixel().Width(),
885 102 : GetOutputSizePixel().Height());
886 :
887 34 : if(IsClipRegion())
888 : {
889 0 : const Rectangle aRegionRectangle(GetActiveClipRegion().GetBoundRect());
890 :
891 : aOutPixel.intersect( // caution! Range from rectangle, one too much (!)
892 : basegfx::B2DRange(
893 0 : aRegionRectangle.Left(),
894 0 : aRegionRectangle.Top(),
895 0 : aRegionRectangle.Right() + 1,
896 0 : aRegionRectangle.Bottom() + 1));
897 : }
898 :
899 34 : if(aOutPixel.isEmpty())
900 : {
901 : // no active output area
902 0 : return false;
903 : }
904 :
905 : // if aFullPixelRange is not completely inside of aOutPixel,
906 : // reduction of target pixels is possible
907 34 : basegfx::B2DRange aVisiblePixelRange(aFullPixelRange);
908 :
909 34 : if(!aOutPixel.isInside(aFullPixelRange))
910 : {
911 6 : aVisiblePixelRange.intersect(aOutPixel);
912 :
913 6 : if(aVisiblePixelRange.isEmpty())
914 : {
915 : // nothing in visible part, reduces to nothing
916 0 : return false;
917 : }
918 :
919 : // aVisiblePixelRange contains the reduced output area in
920 : // discrete coordinates. To make it useful everywhere, make it relative to
921 : // the object range
922 6 : basegfx::B2DHomMatrix aMakeVisibleRangeRelative;
923 :
924 6 : aVisibleRange = aVisiblePixelRange;
925 : aMakeVisibleRangeRelative.translate(
926 6 : -aFullPixelRange.getMinX(),
927 12 : -aFullPixelRange.getMinY());
928 : aMakeVisibleRangeRelative.scale(
929 6 : 1.0 / aFullPixelRange.getWidth(),
930 12 : 1.0 / aFullPixelRange.getHeight());
931 6 : aVisibleRange.transform(aMakeVisibleRangeRelative);
932 : }
933 :
934 : // for pixel devices, do *not* limit size, else OutputDevice::DrawDeviceAlphaBitmap
935 : // will create another, badly scaled bitmap to do the job. Nonetheless, do a
936 : // maximum clipping of something big (1600x1280x2). Add 1.0 to avoid rounding
937 : // errors in rough estimations
938 34 : const double fNewMaxArea(aVisiblePixelRange.getWidth() * aVisiblePixelRange.getHeight());
939 :
940 34 : fMaximumArea = std::min(4096000.0, fNewMaxArea + 1.0);
941 :
942 34 : return true;
943 : }
944 :
945 4214 : void OutputDevice::DrawTransformedBitmapEx(
946 : const basegfx::B2DHomMatrix& rTransformation,
947 : const BitmapEx& rBitmapEx)
948 : {
949 4214 : if( ImplIsRecordLayout() )
950 4180 : return;
951 :
952 4214 : if(rBitmapEx.IsEmpty())
953 0 : return;
954 :
955 4214 : if ( mnDrawMode & DRAWMODE_NOBITMAP )
956 0 : return;
957 :
958 : // decompose matrix to check rotation and shear
959 4248 : basegfx::B2DVector aScale, aTranslate;
960 : double fRotate, fShearX;
961 4214 : rTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
962 4214 : const bool bRotated(!basegfx::fTools::equalZero(fRotate));
963 4214 : const bool bSheared(!basegfx::fTools::equalZero(fShearX));
964 4214 : const bool bMirroredX(basegfx::fTools::less(aScale.getX(), 0.0));
965 4214 : const bool bMirroredY(basegfx::fTools::less(aScale.getY(), 0.0));
966 : static bool bForceToOwnTransformer(false);
967 :
968 4214 : if(!bForceToOwnTransformer && !bRotated && !bSheared && !bMirroredX && !bMirroredY)
969 : {
970 : // with no rotation, shear or mirroring it can be mapped to DrawBitmapEx
971 : // do *not* execute the mirroring here, it's done in the fallback
972 : // #i124580# the correct DestSize needs to be calculated based on MaxXY values
973 4178 : const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
974 : const Size aDestSize(
975 8356 : basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
976 12534 : basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
977 :
978 4178 : DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
979 4178 : return;
980 : }
981 :
982 : // we have rotation,shear or mirror, check if some crazy mode needs the
983 : // created transformed bitmap
984 36 : const bool bInvert(ROP_INVERT == meRasterOp);
985 36 : const bool bBitmapChangedColor(mnDrawMode & (DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP));
986 36 : const bool bMetafile(mpMetaFile);
987 36 : bool bDone(false);
988 70 : const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
989 36 : const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile );
990 :
991 36 : if(!bForceToOwnTransformer && bTryDirectPaint)
992 : {
993 34 : bDone = DrawTransformBitmapExDirect(aFullTransform, rBitmapEx);
994 : }
995 :
996 36 : if(!bDone)
997 : {
998 : // take the fallback when no rotate and shear, but mirror (else we would have done this above)
999 36 : if(!bForceToOwnTransformer && !bRotated && !bSheared)
1000 : {
1001 : // with no rotation or shear it can be mapped to DrawBitmapEx
1002 : // do *not* execute the mirroring here, it's done in the fallback
1003 : // #i124580# the correct DestSize needs to be calculated based on MaxXY values
1004 2 : const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
1005 : const Size aDestSize(
1006 4 : basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
1007 6 : basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
1008 :
1009 2 : DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
1010 2 : return;
1011 : }
1012 :
1013 : // fallback; create transformed bitmap the hard way (back-transform
1014 : // the pixels) and paint
1015 34 : basegfx::B2DRange aVisibleRange(0.0, 0.0, 1.0, 1.0);
1016 :
1017 : // limit maximum area to something looking good for non-pixel-based targets (metafile, printer)
1018 : // by using a fixed minimum (allow at least, but no need to utilize) for good smooting and an area
1019 : // dependent of original size for good quality when e.g. rotated/sheared. Still, limit to a maximum
1020 : // to avoid crashes/ressource problems (ca. 1500x3000 here)
1021 34 : const Size& rOriginalSizePixel(rBitmapEx.GetSizePixel());
1022 34 : const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5);
1023 34 : const double fOrigAreaScaled(bSheared || bRotated ? fOrigArea * 1.44 : fOrigArea);
1024 34 : double fMaximumArea(std::min(4500000.0, std::max(1000000.0, fOrigAreaScaled)));
1025 :
1026 34 : if(!bMetafile)
1027 : {
1028 34 : if ( !TransformAndReduceBitmapExToTargetRange( aFullTransform, aVisibleRange, fMaximumArea ) )
1029 0 : return;
1030 : }
1031 :
1032 34 : if(!aVisibleRange.isEmpty())
1033 : {
1034 : static bool bDoSmoothAtAll(true);
1035 34 : BitmapEx aTransformed(rBitmapEx);
1036 :
1037 : // #122923# when the result needs an alpha channel due to being rotated or sheared
1038 : // and thus uncovering areas, add these channels so that the own transformer (used
1039 : // in getTransformed) also creates a transformed alpha channel
1040 34 : if(!aTransformed.IsTransparent() && (bSheared || bRotated))
1041 : {
1042 : // parts will be uncovered, extend aTransformed with a mask bitmap
1043 0 : const Bitmap aContent(aTransformed.GetBitmap());
1044 :
1045 0 : AlphaMask aMaskBmp(aContent.GetSizePixel());
1046 0 : aMaskBmp.Erase(0);
1047 :
1048 0 : aTransformed = BitmapEx(aContent, aMaskBmp);
1049 : }
1050 :
1051 68 : aTransformed = aTransformed.getTransformed(
1052 : aFullTransform,
1053 : aVisibleRange,
1054 : fMaximumArea,
1055 34 : bDoSmoothAtAll);
1056 34 : basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
1057 :
1058 : // get logic object target range
1059 34 : aTargetRange.transform(rTransformation);
1060 :
1061 : // get from unified/relative VisibleRange to logoc one
1062 : aVisibleRange.transform(
1063 : basegfx::tools::createScaleTranslateB2DHomMatrix(
1064 : aTargetRange.getRange(),
1065 34 : aTargetRange.getMinimum()));
1066 :
1067 : // extract point and size; do not remove size, the bitmap may have been prepared reduced by purpose
1068 : // #i124580# the correct DestSize needs to be calculated based on MaxXY values
1069 34 : const Point aDestPt(basegfx::fround(aVisibleRange.getMinX()), basegfx::fround(aVisibleRange.getMinY()));
1070 : const Size aDestSize(
1071 68 : basegfx::fround(aVisibleRange.getMaxX()) - aDestPt.X(),
1072 102 : basegfx::fround(aVisibleRange.getMaxY()) - aDestPt.Y());
1073 :
1074 34 : DrawBitmapEx(aDestPt, aDestSize, aTransformed);
1075 : }
1076 34 : }
1077 : }
1078 :
1079 : namespace
1080 : {
1081 4 : BitmapEx makeDisabledBitmap(const Bitmap &rBitmap)
1082 : {
1083 4 : const Size aTotalSize( rBitmap.GetSizePixel() );
1084 4 : Bitmap aGrey( aTotalSize, 8, &Bitmap::GetGreyPalette( 256 ) );
1085 8 : AlphaMask aGreyAlphaMask( aTotalSize );
1086 4 : BitmapReadAccess* pBmp = const_cast<Bitmap&>(rBitmap).AcquireReadAccess();
1087 4 : BitmapWriteAccess* pGrey = aGrey.AcquireWriteAccess();
1088 4 : BitmapWriteAccess* pGreyAlphaMask = aGreyAlphaMask.AcquireWriteAccess();
1089 :
1090 4 : if( pBmp && pGrey && pGreyAlphaMask )
1091 : {
1092 4 : BitmapColor aGreyVal( 0 );
1093 8 : BitmapColor aGreyAlphaMaskVal( 0 );
1094 4 : const int nLeft = 0, nRight = aTotalSize.Width();
1095 4 : const int nTop = 0, nBottom = nTop + aTotalSize.Height();
1096 :
1097 68 : for( int nY = nTop; nY < nBottom; ++nY )
1098 : {
1099 1088 : for( int nX = nLeft; nX < nRight; ++nX )
1100 : {
1101 1024 : aGreyVal.SetIndex( pBmp->GetLuminance( nY, nX ) );
1102 1024 : pGrey->SetPixel( nY, nX, aGreyVal );
1103 :
1104 1024 : aGreyAlphaMaskVal.SetIndex( static_cast< sal_uInt8 >( 128ul ) );
1105 1024 : pGreyAlphaMask->SetPixel( nY, nX, aGreyAlphaMaskVal );
1106 : }
1107 4 : }
1108 : }
1109 :
1110 4 : const_cast<Bitmap&>(rBitmap).ReleaseAccess( pBmp );
1111 4 : aGrey.ReleaseAccess( pGrey );
1112 4 : aGreyAlphaMask.ReleaseAccess( pGreyAlphaMask );
1113 8 : return BitmapEx( aGrey, aGreyAlphaMask );
1114 : }
1115 : }
1116 :
1117 183822 : void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, sal_uInt16 nStyle )
1118 : {
1119 183822 : DrawImage( rPos, Size(), rImage, nStyle );
1120 183822 : }
1121 :
1122 190808 : void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
1123 : const Image& rImage, sal_uInt16 nStyle )
1124 : {
1125 190808 : bool bIsSizeValid = (rSize.getWidth() == 0 || rSize.getHeight() == 0) ? false : true;
1126 :
1127 190808 : if( rImage.mpImplData && !ImplIsRecordLayout() )
1128 : {
1129 187528 : switch( rImage.mpImplData->meType )
1130 : {
1131 : case IMAGETYPE_BITMAP:
1132 : {
1133 5575 : const Bitmap &rBitmap = *static_cast< Bitmap* >( rImage.mpImplData->mpData );
1134 5575 : if( nStyle & IMAGE_DRAW_DISABLE )
1135 : {
1136 4 : if ( bIsSizeValid )
1137 0 : DrawBitmapEx( rPos, rSize, makeDisabledBitmap(rBitmap) );
1138 : else
1139 4 : DrawBitmapEx( rPos, makeDisabledBitmap(rBitmap) );
1140 : }
1141 : else
1142 : {
1143 5571 : if ( bIsSizeValid )
1144 2 : DrawBitmap( rPos, rSize, rBitmap );
1145 : else
1146 5569 : DrawBitmap( rPos, rBitmap );
1147 : }
1148 : }
1149 5575 : break;
1150 :
1151 : case IMAGETYPE_IMAGE:
1152 : {
1153 181953 : ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1154 :
1155 181953 : if ( !pData->mpImageBitmap )
1156 : {
1157 87883 : const Size aSize( pData->maBmpEx.GetSizePixel() );
1158 :
1159 87883 : pData->mpImageBitmap = new ImplImageBmp;
1160 87883 : pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1161 : }
1162 :
1163 181953 : if ( bIsSizeValid )
1164 6984 : pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize );
1165 : else
1166 174969 : pData->mpImageBitmap->Draw( 0, this, rPos, nStyle );
1167 : }
1168 181953 : break;
1169 :
1170 : default:
1171 0 : break;
1172 : }
1173 : }
1174 190808 : }
1175 :
1176 : namespace
1177 : {
1178 : // Co = Cs + Cd*(1-As) premultiplied alpha -or-
1179 : // Co = (AsCs + AdCd*(1-As)) / Ao
1180 108405 : inline sal_uInt8 CalcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceAlpha,
1181 : const sal_uInt8 nDstAlpha, const sal_uInt8 nResAlpha, const sal_uInt8 nDestColor )
1182 : {
1183 216810 : int c = nResAlpha ? ( (int)nSourceAlpha*nSourceColor + (int)nDstAlpha*nDestColor -
1184 325215 : (int)nDstAlpha*nDestColor*nSourceAlpha/255 ) / (int)nResAlpha : 0;
1185 108405 : return sal_uInt8( c );
1186 : }
1187 :
1188 36135 : inline BitmapColor AlphaBlend( int nX, int nY,
1189 : const long nMapX,
1190 : const long nMapY,
1191 : BitmapReadAccess* pP,
1192 : BitmapReadAccess* pA,
1193 : BitmapReadAccess* pB,
1194 : BitmapWriteAccess* pAlphaW,
1195 : sal_uInt8& nResAlpha )
1196 : {
1197 72270 : BitmapColor aDstCol,aSrcCol;
1198 36135 : aSrcCol = pP->GetColor( nMapY, nMapX );
1199 36135 : aDstCol = pB->GetColor( nY, nX );
1200 :
1201 : // vcl stores transparency, not alpha - invert it
1202 36135 : const sal_uInt8 nSrcAlpha = 255 - pA->GetPixelIndex( nMapY, nMapX );
1203 36135 : const sal_uInt8 nDstAlpha = 255 - pAlphaW->GetPixelIndex( nY, nX );
1204 :
1205 : // Perform porter-duff compositing 'over' operation
1206 :
1207 : // Co = Cs + Cd*(1-As)
1208 : // Ad = As + Ad*(1-As)
1209 36135 : nResAlpha = (int)nSrcAlpha + (int)nDstAlpha - (int)nDstAlpha*nSrcAlpha/255;
1210 :
1211 36135 : aDstCol.SetRed( CalcColor( aSrcCol.GetRed(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetRed() ) );
1212 36135 : aDstCol.SetBlue( CalcColor( aSrcCol.GetBlue(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetBlue() ) );
1213 36135 : aDstCol.SetGreen( CalcColor( aSrcCol.GetGreen(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetGreen() ) );
1214 :
1215 72270 : return aDstCol;
1216 : }
1217 : }
1218 :
1219 75 : Bitmap OutputDevice::BlendBitmapWithAlpha(
1220 : Bitmap& aBmp,
1221 : BitmapReadAccess* pP,
1222 : BitmapReadAccess* pA,
1223 : const Rectangle& aDstRect,
1224 : const sal_Int32 nOffY,
1225 : const sal_Int32 nDstHeight,
1226 : const sal_Int32 nOffX,
1227 : const sal_Int32 nDstWidth,
1228 : const long* pMapX,
1229 : const long* pMapY )
1230 :
1231 : {
1232 75 : BitmapColor aDstCol;
1233 75 : Bitmap res;
1234 : int nX, nY;
1235 : sal_uInt8 nResAlpha;
1236 :
1237 : SAL_WARN_IF( !mpAlphaVDev, "vcl.gdi", "BlendBitmapWithAlpha(): call me only with valid alpha VirtualDevice!" );
1238 :
1239 75 : bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
1240 75 : mpAlphaVDev->EnableMapMode(false);
1241 :
1242 150 : Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1243 75 : BitmapWriteAccess* pAlphaW = aAlphaBitmap.AcquireWriteAccess();
1244 :
1245 75 : if( GetBitCount() <= 8 )
1246 : {
1247 0 : Bitmap aDither( aBmp.GetSizePixel(), 8 );
1248 0 : BitmapColor aIndex( 0 );
1249 0 : BitmapReadAccess* pB = aBmp.AcquireReadAccess();
1250 0 : BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
1251 :
1252 0 : if (pB && pP && pA && pW && pAlphaW)
1253 : {
1254 : int nOutY;
1255 :
1256 0 : for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1257 : {
1258 0 : const long nMapY = pMapY[ nY ];
1259 0 : const long nModY = ( nOutY & 0x0FL ) << 4L;
1260 : int nOutX;
1261 :
1262 0 : for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1263 : {
1264 0 : const long nMapX = pMapX[ nX ];
1265 0 : const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1266 :
1267 0 : aDstCol = AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB, pAlphaW, nResAlpha );
1268 :
1269 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1270 0 : nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1271 0 : nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1272 0 : pW->SetPixel( nY, nX, aIndex );
1273 :
1274 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16UL ] +
1275 0 : nVCLGLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16UL ] +
1276 0 : nVCLBLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16UL ] ) );
1277 0 : pAlphaW->SetPixel( nY, nX, aIndex );
1278 : }
1279 : }
1280 : }
1281 :
1282 0 : aBmp.ReleaseAccess( pB );
1283 0 : aDither.ReleaseAccess( pW );
1284 0 : res = aDither;
1285 : }
1286 : else
1287 : {
1288 75 : BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
1289 75 : if (pB && pP && pA && pAlphaW)
1290 : {
1291 1756 : for( nY = 0; nY < nDstHeight; nY++ )
1292 : {
1293 1681 : const long nMapY = pMapY[ nY ];
1294 :
1295 37816 : for( nX = 0; nX < nDstWidth; nX++ )
1296 : {
1297 36135 : const long nMapX = pMapX[ nX ];
1298 36135 : aDstCol = AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB, pAlphaW, nResAlpha );
1299 :
1300 36135 : pB->SetPixel( nY, nX, aDstCol );
1301 36135 : pAlphaW->SetPixel( nY, nX, Color(255L-nResAlpha, 255L-nResAlpha, 255L-nResAlpha) );
1302 : }
1303 : }
1304 : }
1305 :
1306 75 : aBmp.ReleaseAccess( pB );
1307 75 : res = aBmp;
1308 : }
1309 :
1310 75 : aAlphaBitmap.ReleaseAccess( pAlphaW );
1311 75 : mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
1312 75 : mpAlphaVDev->EnableMapMode( bOldMapMode );
1313 :
1314 150 : return res;
1315 : }
1316 :
1317 211632 : Bitmap OutputDevice::BlendBitmap(
1318 : Bitmap& aBmp,
1319 : BitmapReadAccess* pP,
1320 : BitmapReadAccess* pA,
1321 : const sal_Int32 nOffY,
1322 : const sal_Int32 nDstHeight,
1323 : const sal_Int32 nOffX,
1324 : const sal_Int32 nDstWidth,
1325 : const Rectangle& aBmpRect,
1326 : const Size& aOutSz,
1327 : const bool bHMirr,
1328 : const bool bVMirr,
1329 : const long* pMapX,
1330 : const long* pMapY )
1331 : {
1332 211632 : BitmapColor aDstCol;
1333 211632 : Bitmap res;
1334 : int nX, nY;
1335 :
1336 211632 : if( GetBitCount() <= 8 )
1337 : {
1338 0 : Bitmap aDither( aBmp.GetSizePixel(), 8 );
1339 0 : BitmapColor aIndex( 0 );
1340 0 : BitmapReadAccess* pB = aBmp.AcquireReadAccess();
1341 0 : BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
1342 :
1343 0 : if( pB && pP && pA && pW )
1344 : {
1345 : int nOutY;
1346 :
1347 0 : for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1348 : {
1349 0 : const long nMapY = pMapY[ nY ];
1350 0 : const long nModY = ( nOutY & 0x0FL ) << 4L;
1351 : int nOutX;
1352 :
1353 0 : for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1354 : {
1355 0 : const long nMapX = pMapX[ nX ];
1356 0 : const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1357 :
1358 0 : aDstCol = pB->GetColor( nY, nX );
1359 0 : aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pA->GetPixelIndex( nMapY, nMapX ) );
1360 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1361 0 : nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1362 0 : nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1363 0 : pW->SetPixel( nY, nX, aIndex );
1364 : }
1365 : }
1366 : }
1367 :
1368 0 : aBmp.ReleaseAccess( pB );
1369 0 : aDither.ReleaseAccess( pW );
1370 0 : res = aDither;
1371 : }
1372 : else
1373 : {
1374 211632 : BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
1375 :
1376 211632 : bool bFastBlend = false;
1377 211632 : if( pP && pA && pB )
1378 : {
1379 : SalTwoRect aTR;
1380 211632 : aTR.mnSrcX = aBmpRect.Left();
1381 211632 : aTR.mnSrcY = aBmpRect.Top();
1382 211632 : aTR.mnSrcWidth = aBmpRect.GetWidth();
1383 211632 : aTR.mnSrcHeight = aBmpRect.GetHeight();
1384 211632 : aTR.mnDestX = nOffX;
1385 211632 : aTR.mnDestY = nOffY;
1386 211632 : aTR.mnDestWidth = aOutSz.Width();
1387 211632 : aTR.mnDestHeight= aOutSz.Height();
1388 :
1389 211632 : if( !bHMirr && !bVMirr )
1390 211632 : bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
1391 : }
1392 :
1393 211632 : if( pP && pA && pB && !bFastBlend )
1394 : {
1395 120942 : switch( pP->GetScanlineFormat() )
1396 : {
1397 : case( BMP_FORMAT_8BIT_PAL ):
1398 : {
1399 1706284 : for( nY = 0; nY < nDstHeight; nY++ )
1400 : {
1401 1612113 : const long nMapY = pMapY[ nY ];
1402 1612113 : Scanline pPScan = pP->GetScanline( nMapY );
1403 1612113 : Scanline pAScan = pA->GetScanline( nMapY );
1404 :
1405 26980115 : for( nX = 0; nX < nDstWidth; nX++ )
1406 : {
1407 25368002 : const long nMapX = pMapX[ nX ];
1408 25368002 : aDstCol = pB->GetPixel( nY, nX );
1409 25368002 : pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ),
1410 50736004 : pAScan[ nMapX ] ) );
1411 : }
1412 : }
1413 : }
1414 94171 : break;
1415 :
1416 : case( BMP_FORMAT_24BIT_TC_BGR ):
1417 : {
1418 4264764 : for( nY = 0; nY < nDstHeight; nY++ )
1419 : {
1420 4237993 : const long nMapY = pMapY[ nY ];
1421 4237993 : Scanline pPScan = pP->GetScanline( nMapY );
1422 4237993 : Scanline pAScan = pA->GetScanline( nMapY );
1423 :
1424 144988936 : for( nX = 0; nX < nDstWidth; nX++ )
1425 : {
1426 140750943 : const long nMapX = pMapX[ nX ];
1427 140750943 : Scanline pTmp = pPScan + nMapX * 3;
1428 :
1429 140750943 : aDstCol = pB->GetPixel( nY, nX );
1430 422252829 : pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
1431 563003772 : pAScan[ nMapX ] ) );
1432 : }
1433 : }
1434 : }
1435 26771 : break;
1436 :
1437 : case( BMP_FORMAT_24BIT_TC_RGB ):
1438 : {
1439 0 : for( nY = 0; nY < nDstHeight; nY++ )
1440 : {
1441 0 : const long nMapY = pMapY[ nY ];
1442 0 : Scanline pPScan = pP->GetScanline( nMapY );
1443 0 : Scanline pAScan = pA->GetScanline( nMapY );
1444 :
1445 0 : for( nX = 0; nX < nDstWidth; nX++ )
1446 : {
1447 0 : const long nMapX = pMapX[ nX ];
1448 0 : Scanline pTmp = pPScan + nMapX * 3;
1449 :
1450 0 : aDstCol = pB->GetPixel( nY, nX );
1451 0 : pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
1452 0 : pAScan[ nMapX ] ) );
1453 : }
1454 : }
1455 : }
1456 0 : break;
1457 :
1458 : default:
1459 : {
1460 0 : for( nY = 0; nY < nDstHeight; nY++ )
1461 : {
1462 0 : const long nMapY = pMapY[ nY ];
1463 0 : Scanline pAScan = pA->GetScanline( nMapY );
1464 :
1465 0 : for( nX = 0; nX < nDstWidth; nX++ )
1466 : {
1467 0 : const long nMapX = pMapX[ nX ];
1468 0 : aDstCol = pB->GetPixel( nY, nX );
1469 : pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ),
1470 0 : pAScan[ nMapX ] ) );
1471 : }
1472 : }
1473 : }
1474 0 : break;
1475 : }
1476 : }
1477 :
1478 211632 : aBmp.ReleaseAccess( pB );
1479 211632 : res = aBmp;
1480 : }
1481 :
1482 211632 : return res;
1483 1233 : }
1484 :
1485 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|