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