Update ooo320-m1
[ooovba.git] / vcl / source / gdi / outdev2.cxx
blob92f78ac442be1bf982244567bcc5d9ecccacb615
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: outdev2.cxx,v $
10 * $Revision: 1.43 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #ifndef _SV_SVSYS_HXX
35 #include <svsys.h>
36 #endif
37 #include <vcl/salbmp.hxx>
38 #include <vcl/salgdi.hxx>
39 #include <vcl/impbmp.hxx>
40 #include <tools/debug.hxx>
41 #include <vcl/bitmap.hxx>
42 #include <vcl/bitmapex.hxx>
43 #include <vcl/window.hxx>
44 #include <vcl/metaact.hxx>
45 #include <vcl/gdimtf.hxx>
46 #include <vcl/virdev.hxx>
47 #include <vcl/outdata.hxx>
48 #include <vcl/outdev.h>
49 #include <vcl/bmpacc.hxx>
50 #include <vcl/region.h>
51 #include <vcl/outdev.hxx>
52 #include <vcl/window.hxx>
53 #include <vcl/window.h>
54 #include <vcl/sallayout.hxx>
55 #include <vcl/image.h>
56 #include <vcl/image.hxx>
57 #include <vcl/bmpfast.hxx>
59 #define BAND_MAX_SIZE 512000
61 // =======================================================================
63 DBG_NAMEEX( OutputDevice )
65 // =======================================================================
67 // -----------
68 // - Defines -
69 // -----------
71 #define OUTDEV_INIT() \
72 { \
73 if ( !IsDeviceOutputNecessary() ) \
74 return; \
76 if ( !mpGraphics ) \
77 if ( !ImplGetGraphics() ) \
78 return; \
80 if ( mbInitClipRegion ) \
81 ImplInitClipRegion(); \
83 if ( mbOutputClipped ) \
84 return; \
87 #define TwoRect SalTwoRect
89 // -------------
90 // - externals -
91 // -------------
93 extern ULONG nVCLRLut[ 6 ];
94 extern ULONG nVCLGLut[ 6 ];
95 extern ULONG nVCLBLut[ 6 ];
96 extern ULONG nVCLDitherLut[ 256 ];
97 extern ULONG nVCLLut[ 256 ];
99 // =======================================================================
101 ULONG ImplAdjustTwoRect( TwoRect& rTwoRect, const Size& rSizePix )
103 ULONG nMirrFlags = 0;
105 if ( rTwoRect.mnDestWidth < 0 )
107 rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth;
108 rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth;
109 rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1;
110 nMirrFlags |= BMP_MIRROR_HORZ;
113 if ( rTwoRect.mnDestHeight < 0 )
115 rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight;
116 rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight;
117 rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1;
118 nMirrFlags |= BMP_MIRROR_VERT;
121 if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) ||
122 ( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) ||
123 ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) ||
124 ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) )
126 const Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
127 Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
128 Rectangle aCropRect( aSourceRect );
130 aCropRect.Intersection( Rectangle( Point(), rSizePix ) );
132 if( aCropRect.IsEmpty() )
133 rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
134 else
136 const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? (double) ( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
137 const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? (double) ( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
139 const long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
140 const long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
141 const long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
142 const long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
144 rTwoRect.mnSrcX = aCropRect.Left();
145 rTwoRect.mnSrcY = aCropRect.Top();
146 rTwoRect.mnSrcWidth = aCropRect.GetWidth();
147 rTwoRect.mnSrcHeight = aCropRect.GetHeight();
148 rTwoRect.mnDestX = nDstX1;
149 rTwoRect.mnDestY = nDstY1;
150 rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
151 rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
155 return nMirrFlags;
158 // =======================================================================
160 void OutputDevice::ImplDrawOutDevDirect( const OutputDevice* pSrcDev, void* pVoidPosAry )
162 TwoRect* pPosAry = (TwoRect*)pVoidPosAry;
163 SalGraphics* pGraphics2;
165 if ( pPosAry->mnSrcWidth && pPosAry->mnSrcHeight && pPosAry->mnDestWidth && pPosAry->mnDestHeight )
167 if ( this == pSrcDev )
168 pGraphics2 = NULL;
169 else
171 if ( (GetOutDevType() != pSrcDev->GetOutDevType()) ||
172 (GetOutDevType() != OUTDEV_WINDOW) )
174 if ( !pSrcDev->mpGraphics )
176 if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
177 return;
179 pGraphics2 = pSrcDev->mpGraphics;
181 else
183 if ( ((Window*)this)->mpWindowImpl->mpFrameWindow == ((Window*)pSrcDev)->mpWindowImpl->mpFrameWindow )
184 pGraphics2 = NULL;
185 else
187 if ( !pSrcDev->mpGraphics )
189 if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
190 return;
192 pGraphics2 = pSrcDev->mpGraphics;
194 if ( !mpGraphics )
196 if ( !ImplGetGraphics() )
197 return;
199 DBG_ASSERT( mpGraphics && pSrcDev->mpGraphics,
200 "OutputDevice::DrawOutDev(): We need more than one Graphics" );
205 // #102532# Offset only has to be pseudo window offset
206 Rectangle aSrcOutRect( Point( pSrcDev->mnOutOffX, pSrcDev->mnOutOffY ),
207 Size( pSrcDev->mnOutWidth, pSrcDev->mnOutHeight ) );
208 Rectangle aSrcRect( Point( pPosAry->mnSrcX, pPosAry->mnSrcY ),
209 Size( pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) );
210 const long nOldRight = aSrcRect.Right();
211 const long nOldBottom = aSrcRect.Bottom();
213 if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
215 if ( (pPosAry->mnSrcX+pPosAry->mnSrcWidth-1) > aSrcOutRect.Right() )
217 const long nOldWidth = pPosAry->mnSrcWidth;
218 pPosAry->mnSrcWidth -= (nOldRight - aSrcRect.Right());
219 pPosAry->mnDestWidth = pPosAry->mnDestWidth * pPosAry->mnSrcWidth / nOldWidth;
222 if ( (pPosAry->mnSrcY+pPosAry->mnSrcHeight-1) > aSrcOutRect.Bottom() )
224 const long nOldHeight = pPosAry->mnSrcHeight;
225 pPosAry->mnSrcHeight -= (nOldBottom - aSrcRect.Bottom());
226 pPosAry->mnDestHeight = pPosAry->mnDestHeight * pPosAry->mnSrcHeight / nOldHeight;
229 // --- RTL --- if this is no window, but pSrcDev is a window
230 // mirroring may be required
231 // because only windows have a SalGraphicsLayout
232 // mirroring is performed here
233 if( (GetOutDevType() != OUTDEV_WINDOW) && pGraphics2 && (pGraphics2->GetLayout() & SAL_LAYOUT_BIDI_RTL) )
235 SalTwoRect pPosAry2 = *pPosAry;
236 pGraphics2->mirror( pPosAry2.mnSrcX, pPosAry2.mnSrcWidth, pSrcDev );
237 mpGraphics->CopyBits( &pPosAry2, pGraphics2, this, pSrcDev );
239 else
240 mpGraphics->CopyBits( pPosAry, pGraphics2, this, pSrcDev );
245 // ------------------------------------------------------------------
247 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
248 const Point& rSrcPt, const Size& rSrcSize )
250 DBG_TRACE( "OutputDevice::DrawOutDev()" );
251 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
252 DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
254 if( ImplIsRecordLayout() )
255 return;
257 if ( meOutDevType == OUTDEV_PRINTER )
258 return;
260 if ( ROP_INVERT == meRasterOp )
262 DrawRect( Rectangle( rDestPt, rDestSize ) );
263 return;
266 if ( mpMetaFile )
268 const Bitmap aBmp( GetBitmap( rSrcPt, rSrcSize ) );
269 mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
272 OUTDEV_INIT();
274 TwoRect aPosAry;
275 aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
276 aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
277 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
278 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
280 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
282 aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() );
283 aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() );
284 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
285 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
287 Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
288 Size( mnOutWidth, mnOutHeight ) );
289 Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
290 Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
291 long nOldRight = aSrcRect.Right();
292 long nOldBottom = aSrcRect.Bottom();
294 if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
296 if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
298 long nOldWidth = aPosAry.mnSrcWidth;
299 aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
300 aPosAry.mnDestWidth = aPosAry.mnDestWidth*aPosAry.mnSrcWidth/nOldWidth;
303 if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
305 long nOldHeight = aPosAry.mnSrcHeight;
306 aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
307 aPosAry.mnDestHeight = aPosAry.mnDestHeight*aPosAry.mnSrcHeight/nOldHeight;
310 mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
314 if( mpAlphaVDev )
315 mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize );
318 // ------------------------------------------------------------------
320 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
321 const Point& rSrcPt, const Size& rSrcSize,
322 const OutputDevice& rOutDev )
324 DBG_TRACE( "OutputDevice::DrawOutDev()" );
325 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
326 DBG_CHKOBJ( &rOutDev, OutputDevice, ImplDbgCheckOutputDevice );
327 DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
328 DBG_ASSERT( rOutDev.meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
330 if ( (meOutDevType == OUTDEV_PRINTER) || (rOutDev.meOutDevType == OUTDEV_PRINTER) || ImplIsRecordLayout() )
331 return;
333 if ( ROP_INVERT == meRasterOp )
335 DrawRect( Rectangle( rDestPt, rDestSize ) );
336 return;
339 if ( mpMetaFile )
341 const Bitmap aBmp( rOutDev.GetBitmap( rSrcPt, rSrcSize ) );
342 mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
345 OUTDEV_INIT();
347 TwoRect aPosAry;
348 aPosAry.mnSrcX = rOutDev.ImplLogicXToDevicePixel( rSrcPt.X() );
349 aPosAry.mnSrcY = rOutDev.ImplLogicYToDevicePixel( rSrcPt.Y() );
350 aPosAry.mnSrcWidth = rOutDev.ImplLogicWidthToDevicePixel( rSrcSize.Width() );
351 aPosAry.mnSrcHeight = rOutDev.ImplLogicHeightToDevicePixel( rSrcSize.Height() );
352 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
353 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
354 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
355 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
357 if( mpAlphaVDev )
359 if( rOutDev.mpAlphaVDev )
361 // alpha-blend source over destination
362 DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
364 // This would be mode SOURCE:
365 // copy source alpha channel to our alpha channel
366 //mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize, *rOutDev.mpAlphaVDev );
368 else
370 ImplDrawOutDevDirect( &rOutDev, &aPosAry );
372 // #i32109#: make destination rectangle opaque - source has no alpha
373 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
376 else
378 if( rOutDev.mpAlphaVDev )
380 // alpha-blend source over destination
381 DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
383 else
385 // no alpha at all, neither in source nor destination device
386 ImplDrawOutDevDirect( &rOutDev, &aPosAry );
391 // ------------------------------------------------------------------
393 void OutputDevice::CopyArea( const Point& rDestPt,
394 const Point& rSrcPt, const Size& rSrcSize,
395 USHORT nFlags )
397 DBG_TRACE( "OutputDevice::CopyArea()" );
398 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
399 DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::CopyArea(...) with printer devices!" );
401 if ( meOutDevType == OUTDEV_PRINTER || ImplIsRecordLayout() )
402 return;
404 RasterOp eOldRop = GetRasterOp();
405 SetRasterOp( ROP_OVERPAINT );
407 OUTDEV_INIT();
409 TwoRect aPosAry;
410 aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
411 aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
413 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight )
415 aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() );
416 aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() );
417 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
418 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
420 Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
421 Size( mnOutWidth, mnOutHeight ) );
422 Rectangle aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
423 Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
424 long nOldRight = aSrcRect.Right();
425 long nOldBottom = aSrcRect.Bottom();
427 if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
429 if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
430 aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
432 if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
433 aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
435 if ( (meOutDevType == OUTDEV_WINDOW) && (nFlags & COPYAREA_WINDOWINVALIDATE) )
437 ((Window*)this)->ImplMoveAllInvalidateRegions( aSrcRect,
438 aPosAry.mnDestX-aPosAry.mnSrcX,
439 aPosAry.mnDestY-aPosAry.mnSrcY,
440 FALSE );
442 mpGraphics->CopyArea( aPosAry.mnDestX, aPosAry.mnDestY,
443 aPosAry.mnSrcX, aPosAry.mnSrcY,
444 aPosAry.mnSrcWidth, aPosAry.mnSrcHeight,
445 SAL_COPYAREA_WINDOWINVALIDATE, this );
447 else
449 aPosAry.mnDestWidth = aPosAry.mnSrcWidth;
450 aPosAry.mnDestHeight = aPosAry.mnSrcHeight;
451 mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
456 SetRasterOp( eOldRop );
458 if( mpAlphaVDev )
459 mpAlphaVDev->CopyArea( rDestPt, rSrcPt, rSrcSize, nFlags );
462 // ------------------------------------------------------------------
464 void OutputDevice::ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
465 const OutputDevice& rOutDev, const Region& rRegion )
467 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
469 GDIMetaFile* pOldMetaFile = mpMetaFile;
470 BOOL bOldMap = mbMap;
471 RasterOp eOldROP = GetRasterOp();
472 mpMetaFile = NULL;
473 mbMap = FALSE;
474 SetRasterOp( ROP_OVERPAINT );
476 if ( !IsDeviceOutputNecessary() )
477 return;
479 if ( !mpGraphics )
481 if ( !ImplGetGraphics() )
482 return;
485 // ClipRegion zuruecksetzen
486 if ( rRegion.IsNull() )
487 mpGraphics->ResetClipRegion();
488 else
489 ImplSelectClipRegion( rRegion );
491 TwoRect aPosAry;
492 aPosAry.mnSrcX = rDevPt.X();
493 aPosAry.mnSrcY = rDevPt.Y();
494 aPosAry.mnSrcWidth = rDevSize.Width();
495 aPosAry.mnSrcHeight = rDevSize.Height();
496 aPosAry.mnDestX = rPt.X();
497 aPosAry.mnDestY = rPt.Y();
498 aPosAry.mnDestWidth = rDevSize.Width();
499 aPosAry.mnDestHeight = rDevSize.Height();
500 ImplDrawOutDevDirect( &rOutDev, &aPosAry );
502 // Dafuer sorgen, das ClipRegion neu berechnet und gesetzt wird
503 mbInitClipRegion = TRUE;
505 SetRasterOp( eOldROP );
506 mbMap = bOldMap;
507 mpMetaFile = pOldMetaFile;
510 // ------------------------------------------------------------------
512 void OutputDevice::ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
513 OutputDevice& rDev )
515 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
517 BOOL bOldMap = mbMap;
518 mbMap = FALSE;
519 rDev.DrawOutDev( rDevPt, rDevSize, rPt, rDevSize, *this );
520 mbMap = bOldMap;
523 // ------------------------------------------------------------------
525 void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
527 DBG_TRACE( "OutputDevice::DrawBitmap()" );
529 if( ImplIsRecordLayout() )
530 return;
532 const Size aSizePix( rBitmap.GetSizePixel() );
533 ImplDrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION );
535 if( mpAlphaVDev )
537 // #i32109#: Make bitmap area opaque
538 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, PixelToLogic( aSizePix )) );
542 // ------------------------------------------------------------------
544 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
546 DBG_TRACE( "OutputDevice::DrawBitmap( Size )" );
548 if( ImplIsRecordLayout() )
549 return;
551 ImplDrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION );
553 if( mpAlphaVDev )
555 // #i32109#: Make bitmap area opaque
556 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
560 // ------------------------------------------------------------------
562 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize,
563 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
564 const Bitmap& rBitmap )
566 DBG_TRACE( "OutputDevice::DrawBitmap( Point, Size )" );
568 if( ImplIsRecordLayout() )
569 return;
571 ImplDrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, META_BMPSCALEPART_ACTION );
573 if( mpAlphaVDev )
575 // #i32109#: Make bitmap area opaque
576 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
580 // -----------------------------------------------------------------------------
582 void OutputDevice::ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize,
583 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
584 const Bitmap& rBitmap, const ULONG nAction )
586 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
588 Bitmap aBmp( rBitmap );
590 if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) )
591 return;
592 else if ( ROP_INVERT == meRasterOp )
594 DrawRect( Rectangle( rDestPt, rDestSize ) );
595 return;
597 else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
598 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
600 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
602 BYTE cCmpVal;
604 if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
605 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
606 else
607 cCmpVal = 255;
609 Color aCol( cCmpVal, cCmpVal, cCmpVal );
610 Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
611 SetLineColor( aCol );
612 SetFillColor( aCol );
613 DrawRect( Rectangle( rDestPt, rDestSize ) );
614 Pop();
615 return;
617 else if( !!aBmp )
619 if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
620 aBmp.Convert( BMP_CONVERSION_8BIT_GREYS );
622 if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
623 aBmp.Convert( BMP_CONVERSION_GHOSTED );
627 if ( mpMetaFile )
629 switch( nAction )
631 case( META_BMP_ACTION ):
632 mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) );
633 break;
635 case( META_BMPSCALE_ACTION ):
636 mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
637 break;
639 case( META_BMPSCALEPART_ACTION ):
640 mpMetaFile->AddAction( new MetaBmpScalePartAction(
641 rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) );
642 break;
646 OUTDEV_INIT();
648 if( !aBmp.IsEmpty() )
650 TwoRect aPosAry;
652 aPosAry.mnSrcX = rSrcPtPixel.X();
653 aPosAry.mnSrcY = rSrcPtPixel.Y();
654 aPosAry.mnSrcWidth = rSrcSizePixel.Width();
655 aPosAry.mnSrcHeight = rSrcSizePixel.Height();
656 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
657 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
658 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
659 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
661 const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmp.GetSizePixel() );
663 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
665 if ( nMirrFlags )
666 aBmp.Mirror( nMirrFlags );
668 /* #i75264# (corrected with #i81576#)
669 * sometimes a bitmap is scaled to a ridiculous size and drawn
670 * to a quite normal VDev, so only a very small part of
671 * the scaled bitmap will be visible. However actually scaling
672 * the bitmap will use so much memory that we end with a crash.
673 * Workaround: since only a small part of the scaled bitmap will
674 * be actually drawn anyway (because of clipping on the device
675 * boundary), limit the destination and source rectangles so
676 * that the destination rectangle will overlap the device but only
677 * be reasonably (say factor 2) larger than the device itself.
679 if( aPosAry.mnDestWidth > 2048 || aPosAry.mnDestHeight > 2048 )
681 if( meOutDevType == OUTDEV_WINDOW ||
682 (meOutDevType == OUTDEV_VIRDEV && mpPDFWriter == 0 ) )
684 // #i81576# do the following trick only if there is overlap at all
685 // else the formulae don't work
686 // theoretically in this case we wouldn't need to draw the bitmap at all
687 // however there are some esoteric case where that is needed
688 if( aPosAry.mnDestX + aPosAry.mnDestWidth >= 0
689 && aPosAry.mnDestX < mnOutWidth
690 && aPosAry.mnDestY + aPosAry.mnDestHeight >= 0
691 && aPosAry.mnDestY < mnOutHeight )
693 // reduce scaling to something reasonable taking into account the output size
694 if( aPosAry.mnDestWidth > 3*mnOutWidth && aPosAry.mnSrcWidth )
696 const double nScaleX = aPosAry.mnDestWidth/double(aPosAry.mnSrcWidth);
698 if( aPosAry.mnDestX + aPosAry.mnDestWidth > mnOutWidth )
700 aPosAry.mnDestWidth = Max(long(0),mnOutWidth-aPosAry.mnDestX);
702 if( aPosAry.mnDestX < 0 )
704 aPosAry.mnDestWidth += aPosAry.mnDestX;
705 aPosAry.mnSrcX -= sal::static_int_cast<long>(aPosAry.mnDestX / nScaleX);
706 aPosAry.mnDestX = 0;
709 aPosAry.mnSrcWidth = sal::static_int_cast<long>(aPosAry.mnDestWidth / nScaleX);
712 if( aPosAry.mnDestHeight > 3*mnOutHeight && aPosAry.mnSrcHeight != 0 )
714 const double nScaleY = aPosAry.mnDestHeight/double(aPosAry.mnSrcHeight);
716 if( aPosAry.mnDestY + aPosAry.mnDestHeight > mnOutHeight )
718 aPosAry.mnDestHeight = Max(long(0),mnOutHeight-aPosAry.mnDestY);
720 if( aPosAry.mnDestY < 0 )
722 aPosAry.mnDestHeight += aPosAry.mnDestY;
723 aPosAry.mnSrcY -= sal::static_int_cast<long>(aPosAry.mnDestY / nScaleY);
724 aPosAry.mnDestY = 0;
727 aPosAry.mnSrcHeight = sal::static_int_cast<long>(aPosAry.mnDestHeight / nScaleY);
733 if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
734 mpGraphics->DrawBitmap( &aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap(), this );
739 // ------------------------------------------------------------------
741 void OutputDevice::DrawBitmapEx( const Point& rDestPt,
742 const BitmapEx& rBitmapEx )
744 DBG_TRACE( "OutputDevice::DrawBitmapEx()" );
746 if( ImplIsRecordLayout() )
747 return;
749 if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
750 DrawBitmap( rDestPt, rBitmapEx.GetBitmap() );
751 else
753 const Size aSizePix( rBitmapEx.GetSizePixel() );
754 ImplDrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION );
758 // ------------------------------------------------------------------
760 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
761 const BitmapEx& rBitmapEx )
763 DBG_TRACE( "OutputDevice::DrawBitmapEx( Size )" );
765 if( ImplIsRecordLayout() )
766 return;
768 if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
769 DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() );
770 else
771 ImplDrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION );
774 // ------------------------------------------------------------------
776 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
777 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
778 const BitmapEx& rBitmapEx )
780 DBG_TRACE( "OutputDevice::DrawBitmapEx( Point, Size )" );
782 if( ImplIsRecordLayout() )
783 return;
785 if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
786 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() );
787 else
788 ImplDrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx, META_BMPEXSCALEPART_ACTION );
791 // ------------------------------------------------------------------
793 void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
794 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
795 const BitmapEx& rBitmapEx, const ULONG nAction )
797 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
799 BitmapEx aBmpEx( rBitmapEx );
801 if ( mnDrawMode & DRAWMODE_NOBITMAP )
802 return;
803 else if ( ROP_INVERT == meRasterOp )
805 DrawRect( Rectangle( rDestPt, rDestSize ) );
806 return;
808 else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
809 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
811 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
813 Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 );
814 BYTE cCmpVal;
816 if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
817 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
818 else
819 cCmpVal = 255;
821 aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
823 if( aBmpEx.IsAlpha() )
825 // Create one-bit mask out of alpha channel, by
826 // thresholding it at alpha=0.5. As
827 // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
828 // output, having alpha-induced grey levels is not
829 // acceptable.
830 Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() );
831 aMask.MakeMono( 128 );
832 aBmpEx = BitmapEx( aColorBmp, aMask );
834 else
836 aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
839 else if( !!aBmpEx )
841 if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
842 aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
844 if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
845 aBmpEx.Convert( BMP_CONVERSION_GHOSTED );
849 if ( mpMetaFile )
851 switch( nAction )
853 case( META_BMPEX_ACTION ):
854 mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
855 break;
857 case( META_BMPEXSCALE_ACTION ):
858 mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
859 break;
861 case( META_BMPEXSCALEPART_ACTION ):
862 mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
863 rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
864 break;
868 OUTDEV_INIT();
870 if( OUTDEV_PRINTER == meOutDevType )
872 if( aBmpEx.IsAlpha() )
874 // #107169# For true alpha bitmaps, no longer masking the
875 // bitmap, but perform a full alpha blend against a white
876 // background here.
877 Bitmap aBmp( aBmpEx.GetBitmap() );
878 aBmp.Blend( aBmpEx.GetAlpha(), Color( COL_WHITE) );
879 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
881 else
883 Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() );
884 aBmp.Replace( aMask, Color( COL_WHITE ) );
885 ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
887 return;
889 else if( aBmpEx.IsAlpha() )
891 ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
892 return;
895 if( !( !aBmpEx ) )
897 TwoRect aPosAry;
899 aPosAry.mnSrcX = rSrcPtPixel.X();
900 aPosAry.mnSrcY = rSrcPtPixel.Y();
901 aPosAry.mnSrcWidth = rSrcSizePixel.Width();
902 aPosAry.mnSrcHeight = rSrcSizePixel.Height();
903 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
904 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
905 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
906 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
908 const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() );
910 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
913 if( nMirrFlags )
914 aBmpEx.Mirror( nMirrFlags );
916 const ImpBitmap* pImpBmp = aBmpEx.ImplGetBitmapImpBitmap();
917 const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap();
919 if ( pMaskBmp )
921 // #4919452# reduce operation area to bounds of
922 // cliprect. since masked transparency involves
923 // creation of a large vdev and copying the screen
924 // content into that (slooow read from framebuffer),
925 // that should considerably increase performance for
926 // large bitmaps and small clippings.
928 // Note that this optimisation is a workaround for a
929 // Writer peculiarity, namely, to decompose background
930 // graphics into myriads of disjunct, tiny
931 // rectangles. That otherwise kills us here, since for
932 // transparent output, SAL always prepares the whole
933 // bitmap, if aPosAry contains the whole bitmap (and
934 // it's _not_ to blame for that).
936 // Note the call to ImplPixelToDevicePixel(), since
937 // aPosAry already contains the mnOutOff-offsets, they
938 // also have to be applied to the region
939 Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
941 // TODO: Also respect scaling (that's a bit tricky,
942 // since the source points have to move fractional
943 // amounts (which is not possible, thus has to be
944 // emulated by increases copy area)
945 // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
946 // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
948 // for now, only identity scales allowed
949 if( !aClipRegionBounds.IsEmpty() &&
950 aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
951 aPosAry.mnDestHeight == aPosAry.mnSrcHeight )
953 // now intersect dest rect with clip region
954 aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX,
955 aPosAry.mnDestY,
956 aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
957 aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) );
959 // Note: I could theoretically optimize away the
960 // DrawBitmap below, if the region is empty
961 // here. Unfortunately, cannot rule out that
962 // somebody relies on the side effects.
963 if( !aClipRegionBounds.IsEmpty() )
965 aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
966 aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
967 aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
968 aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
970 aPosAry.mnDestX = aClipRegionBounds.Left();
971 aPosAry.mnDestY = aClipRegionBounds.Top();
972 aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
973 aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
977 mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
978 *pMaskBmp->ImplGetSalBitmap(),
979 this );
981 // #110958# Paint mask to alpha channel. Luckily, the
982 // black and white representation of the mask maps to
983 // the alpha channel
985 // #i25167# Restrict mask painting to _opaque_ areas
986 // of the mask, otherwise we spoil areas where no
987 // bitmap content was ever visible. Interestingly
988 // enough, this can be achieved by taking the mask as
989 // the transparency mask of itself
990 if( mpAlphaVDev )
991 mpAlphaVDev->DrawBitmapEx( rDestPt,
992 rDestSize,
993 BitmapEx( aBmpEx.GetMask(),
994 aBmpEx.GetMask() ) );
996 else
998 mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(), this );
1000 if( mpAlphaVDev )
1002 // #i32109#: Make bitmap area opaque
1003 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
1010 // ------------------------------------------------------------------
1012 void OutputDevice::DrawMask( const Point& rDestPt,
1013 const Bitmap& rBitmap, const Color& rMaskColor )
1015 DBG_TRACE( "OutputDevice::DrawMask()" );
1017 if( ImplIsRecordLayout() )
1018 return;
1020 const Size aSizePix( rBitmap.GetSizePixel() );
1021 ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION );
1023 if( mpAlphaVDev )
1025 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1027 // #i25167# Restrict mask painting to _opaque_ areas
1028 // of the mask, otherwise we spoil areas where no
1029 // bitmap content was ever visible. Interestingly
1030 // enough, this can be achieved by taking the mask as
1031 // the transparency mask of itself
1032 mpAlphaVDev->DrawBitmapEx( rDestPt,
1033 PixelToLogic( aSizePix ),
1034 BitmapEx( rMask, rMask ) );
1038 // ------------------------------------------------------------------
1040 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1041 const Bitmap& rBitmap, const Color& rMaskColor )
1043 DBG_TRACE( "OutputDevice::DrawMask( Size )" );
1045 if( ImplIsRecordLayout() )
1046 return;
1048 ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION );
1050 // TODO: Use mask here
1051 if( mpAlphaVDev )
1053 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1055 // #i25167# Restrict mask painting to _opaque_ areas
1056 // of the mask, otherwise we spoil areas where no
1057 // bitmap content was ever visible. Interestingly
1058 // enough, this can be achieved by taking the mask as
1059 // the transparency mask of itself
1060 mpAlphaVDev->DrawBitmapEx( rDestPt,
1061 rDestSize,
1062 BitmapEx( rMask, rMask ) );
1066 // ------------------------------------------------------------------
1068 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1069 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1070 const Bitmap& rBitmap, const Color& rMaskColor )
1072 DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" );
1074 if( ImplIsRecordLayout() )
1075 return;
1077 ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION );
1079 // TODO: Use mask here
1080 if( mpAlphaVDev )
1082 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1084 // #i25167# Restrict mask painting to _opaque_ areas
1085 // of the mask, otherwise we spoil areas where no
1086 // bitmap content was ever visible. Interestingly
1087 // enough, this can be achieved by taking the mask as
1088 // the transparency mask of itself
1089 mpAlphaVDev->DrawBitmapEx( rDestPt,
1090 rDestSize,
1091 rSrcPtPixel,
1092 rSrcSizePixel,
1093 BitmapEx( rMask, rMask ) );
1097 // ------------------------------------------------------------------
1099 void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize,
1100 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1101 const Bitmap& rBitmap, const Color& rMaskColor,
1102 const ULONG nAction )
1104 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1106 if( ROP_INVERT == meRasterOp )
1108 DrawRect( Rectangle( rDestPt, rDestSize ) );
1109 return;
1112 if ( mpMetaFile )
1114 switch( nAction )
1116 case( META_MASK_ACTION ):
1117 mpMetaFile->AddAction( new MetaMaskAction( rDestPt,
1118 rBitmap, rMaskColor ) );
1119 break;
1121 case( META_MASKSCALE_ACTION ):
1122 mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt,
1123 rDestSize, rBitmap, rMaskColor ) );
1124 break;
1126 case( META_MASKSCALEPART_ACTION ):
1127 mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize,
1128 rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) );
1129 break;
1133 OUTDEV_INIT();
1135 if ( OUTDEV_PRINTER == meOutDevType )
1137 ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
1138 return;
1141 const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
1142 if ( pImpBmp )
1144 TwoRect aPosAry;
1146 aPosAry.mnSrcX = rSrcPtPixel.X();
1147 aPosAry.mnSrcY = rSrcPtPixel.Y();
1148 aPosAry.mnSrcWidth = rSrcSizePixel.Width();
1149 aPosAry.mnSrcHeight = rSrcSizePixel.Height();
1150 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
1151 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
1152 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
1153 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
1155 // spiegeln via Koordinaten wollen wir nicht
1156 const ULONG nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() );
1158 // check if output is necessary
1159 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
1162 if( nMirrFlags )
1164 Bitmap aTmp( rBitmap );
1165 aTmp.Mirror( nMirrFlags );
1166 mpGraphics->DrawMask( &aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(),
1167 ImplColorToSal( rMaskColor ) , this);
1169 else
1170 mpGraphics->DrawMask( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
1171 ImplColorToSal( rMaskColor ), this );
1177 // ------------------------------------------------------------------
1179 void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, USHORT nStyle )
1181 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1183 if( !rImage.mpImplData || ImplIsRecordLayout() )
1184 return;
1186 switch( rImage.mpImplData->meType )
1188 case IMAGETYPE_BITMAP:
1189 DrawBitmap( rPos, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1190 break;
1192 case IMAGETYPE_IMAGE:
1194 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1196 if( !pData->mpImageBitmap )
1198 const Size aSize( pData->maBmpEx.GetSizePixel() );
1200 pData->mpImageBitmap = new ImplImageBmp;
1201 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1204 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle );
1206 break;
1208 default:
1209 break;
1213 // ------------------------------------------------------------------
1215 void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
1216 const Image& rImage, USHORT nStyle )
1218 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1220 if( rImage.mpImplData && !ImplIsRecordLayout() )
1222 switch( rImage.mpImplData->meType )
1224 case IMAGETYPE_BITMAP:
1225 DrawBitmap( rPos, rSize, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1226 break;
1228 case IMAGETYPE_IMAGE:
1230 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1232 if ( !pData->mpImageBitmap )
1234 const Size aSize( pData->maBmpEx.GetSizePixel() );
1236 pData->mpImageBitmap = new ImplImageBmp;
1237 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1240 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize );
1242 break;
1244 default:
1245 break;
1250 // ------------------------------------------------------------------
1252 Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1254 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1256 Bitmap aBmp;
1257 long nX = ImplLogicXToDevicePixel( rSrcPt.X() );
1258 long nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
1259 long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
1260 long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
1262 if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() )
1264 if ( nWidth && nHeight )
1266 Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
1267 BOOL bClipped = FALSE;
1269 // X-Koordinate ausserhalb des Bereichs?
1270 if ( nX < mnOutOffX )
1272 nWidth -= ( mnOutOffX - nX );
1273 nX = mnOutOffX;
1274 bClipped = TRUE;
1277 // Y-Koordinate ausserhalb des Bereichs?
1278 if ( nY < mnOutOffY )
1280 nHeight -= ( mnOutOffY - nY );
1281 nY = mnOutOffY;
1282 bClipped = TRUE;
1285 // Breite ausserhalb des Bereichs?
1286 if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
1288 nWidth = mnOutOffX + mnOutWidth - nX;
1289 bClipped = TRUE;
1292 // Hoehe ausserhalb des Bereichs?
1293 if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
1295 nHeight = mnOutOffY + mnOutHeight - nY;
1296 bClipped = TRUE;
1299 if ( bClipped )
1301 // Falls auf den sichtbaren Bereich geclipped wurde,
1302 // muessen wir eine Bitmap in der rchtigen Groesse
1303 // erzeugen, in die die geclippte Bitmap an die angepasste
1304 // Position kopiert wird
1305 VirtualDevice aVDev( *this );
1307 if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) )
1309 if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() )
1311 TwoRect aPosAry;
1313 aPosAry.mnSrcX = nX;
1314 aPosAry.mnSrcY = nY;
1315 aPosAry.mnSrcWidth = nWidth;
1316 aPosAry.mnSrcHeight = nHeight;
1317 aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L;
1318 aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L;
1319 aPosAry.mnDestWidth = nWidth;
1320 aPosAry.mnDestHeight = nHeight;
1322 if ( (nWidth > 0) && (nHeight > 0) )
1323 (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( &aPosAry, mpGraphics, this, this );
1325 aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
1327 else
1328 bClipped = FALSE;
1330 else
1331 bClipped = FALSE;
1334 if ( !bClipped )
1336 SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
1338 if( pSalBmp )
1340 ImpBitmap* pImpBmp = new ImpBitmap;
1341 pImpBmp->ImplSetSalBitmap( pSalBmp );
1342 aBmp.ImplSetImpBitmap( pImpBmp );
1348 return aBmp;
1351 // ------------------------------------------------------------------
1353 BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
1355 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1357 // #110958# Extract alpha value from VDev, if any
1358 if( mpAlphaVDev )
1360 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
1362 // ensure 8 bit alpha
1363 if( aAlphaBitmap.GetBitCount() > 8 )
1364 aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
1366 return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
1368 else
1369 return GetBitmap( rSrcPt, rSize );
1372 // ------------------------------------------------------------------
1374 void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize,
1375 Bitmap& rBitmap ) const
1377 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1379 BOOL bOldMap = mbMap;
1380 ((OutputDevice*)this)->mbMap = FALSE;
1381 rBitmap = GetBitmap( rDestPt, rSize );
1382 ((OutputDevice*)this)->mbMap = bOldMap;
1385 // ------------------------------------------------------------------
1387 Color OutputDevice::GetPixel( const Point& rPt ) const
1389 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1391 Color aColor;
1393 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1395 if ( mbInitClipRegion )
1396 ((OutputDevice*)this)->ImplInitClipRegion();
1398 if ( !mbOutputClipped )
1400 const long nX = ImplLogicXToDevicePixel( rPt.X() );
1401 const long nY = ImplLogicYToDevicePixel( rPt.Y() );
1402 const SalColor aSalCol = mpGraphics->GetPixel( nX, nY, this );
1403 aColor.SetRed( SALCOLOR_RED( aSalCol ) );
1404 aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1405 aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1408 return aColor;
1411 // ------------------------------------------------------------------
1413 Color* OutputDevice::GetPixel( const Polygon& rPts ) const
1415 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1417 Color* pColors = NULL;
1418 const USHORT nSize = rPts.GetSize();
1420 if( nSize )
1422 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1424 if ( mbInitClipRegion )
1425 ((OutputDevice*)this)->ImplInitClipRegion();
1427 if ( !mbOutputClipped )
1429 pColors = new Color[ nSize ];
1431 for( USHORT i = 0; i < nSize; i++ )
1433 Color& rCol = pColors[ i ];
1434 const Point& rPt = rPts[ i ];
1435 const SalColor aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ),
1436 ImplLogicYToDevicePixel( rPt.Y() ) , this) );
1438 rCol.SetRed( SALCOLOR_RED( aSalCol ) );
1439 rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1440 rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1446 return pColors;
1449 // -----------------------------------------------------------------------
1451 void OutputDevice::DrawPixel( const Point& rPt )
1453 DBG_TRACE( "OutputDevice::DrawPixel()" );
1454 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1456 if ( mpMetaFile )
1457 mpMetaFile->AddAction( new MetaPointAction( rPt ) );
1459 if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
1460 return;
1462 Point aPt = ImplLogicToDevicePixel( rPt );
1464 // we need a graphics
1465 if ( !mpGraphics )
1467 if ( !ImplGetGraphics() )
1468 return;
1471 if ( mbInitClipRegion )
1472 ImplInitClipRegion();
1473 if ( mbOutputClipped )
1474 return;
1476 if ( mbInitLineColor )
1477 ImplInitLineColor();
1479 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );
1481 if( mpAlphaVDev )
1482 mpAlphaVDev->DrawPixel( rPt );
1485 // -----------------------------------------------------------------------
1487 void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
1489 DBG_TRACE( "OutputDevice::DrawPixel()" );
1490 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1492 Color aColor( rColor );
1494 if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
1495 DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
1496 DRAWMODE_SETTINGSLINE ) )
1498 if( !ImplIsColorTransparent( aColor ) )
1500 if( mnDrawMode & DRAWMODE_BLACKLINE )
1502 aColor = Color( COL_BLACK );
1504 else if( mnDrawMode & DRAWMODE_WHITELINE )
1506 aColor = Color( COL_WHITE );
1508 else if( mnDrawMode & DRAWMODE_GRAYLINE )
1510 const UINT8 cLum = aColor.GetLuminance();
1511 aColor = Color( cLum, cLum, cLum );
1513 else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
1515 aColor = GetSettings().GetStyleSettings().GetFontColor();
1518 if( mnDrawMode & DRAWMODE_GHOSTEDLINE )
1520 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
1521 ( aColor.GetGreen() >> 1 ) | 0x80,
1522 ( aColor.GetBlue() >> 1 ) | 0x80 );
1527 if ( mpMetaFile )
1528 mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );
1530 if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
1531 return;
1533 Point aPt = ImplLogicToDevicePixel( rPt );
1535 // we need a graphics
1536 if ( !mpGraphics )
1538 if ( !ImplGetGraphics() )
1539 return;
1542 if ( mbInitClipRegion )
1543 ImplInitClipRegion();
1544 if ( mbOutputClipped )
1545 return;
1547 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );
1549 if( mpAlphaVDev )
1550 mpAlphaVDev->DrawPixel( rPt );
1553 // -----------------------------------------------------------------------
1555 void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
1557 if ( !pColors )
1558 DrawPixel( rPts, GetLineColor() );
1559 else
1561 DBG_TRACE( "OutputDevice::DrawPixel()" );
1562 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1563 DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );
1565 const USHORT nSize = rPts.GetSize();
1567 if ( nSize )
1569 if ( mpMetaFile )
1570 for ( USHORT i = 0; i < nSize; i++ )
1571 mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );
1573 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1574 return;
1576 // we need a graphics
1577 if ( mpGraphics || ImplGetGraphics() )
1579 if ( mbInitClipRegion )
1580 ImplInitClipRegion();
1582 if ( mbOutputClipped )
1583 return;
1585 for ( USHORT i = 0; i < nSize; i++ )
1587 const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
1588 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
1594 if( mpAlphaVDev )
1595 mpAlphaVDev->DrawPixel( rPts, pColors );
1598 // -----------------------------------------------------------------------
1600 void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
1602 if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
1604 const USHORT nSize = rPts.GetSize();
1605 Color* pColArray = new Color[ nSize ];
1607 for( USHORT i = 0; i < nSize; i++ )
1608 pColArray[ i ] = rColor;
1610 DrawPixel( rPts, pColArray );
1611 delete[] pColArray;
1614 if( mpAlphaVDev )
1615 mpAlphaVDev->DrawPixel( rPts, rColor );
1618 // ------------------------------------------------------------------------
1620 Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap aBmp,
1621 BitmapReadAccess* pP,
1622 BitmapReadAccess* pA,
1623 const Rectangle& aDstRect,
1624 const sal_Int32 nOffY,
1625 const sal_Int32 nDstHeight,
1626 const sal_Int32 nOffX,
1627 const sal_Int32 nDstWidth,
1628 const long* pMapX,
1629 const long* pMapY )
1631 BitmapColor aDstCol,aSrcCol;
1632 BYTE nSrcAlpha, nDstAlpha;
1633 Bitmap res;
1634 int nX, nOutX, nY, nOutY;
1636 OSL_ENSURE(mpAlphaVDev,
1637 "ImplBlendWithAlpha(): call me only with valid alpha VDev!" );
1639 BOOL bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
1640 mpAlphaVDev->EnableMapMode(FALSE);
1642 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1643 BitmapWriteAccess* pAlphaW = aAlphaBitmap.AcquireWriteAccess();
1645 if( GetBitCount() <= 8 )
1647 Bitmap aDither( aBmp.GetSizePixel(), 8 );
1648 BitmapColor aIndex( 0 );
1649 BitmapReadAccess* pB = aBmp.AcquireReadAccess();
1650 BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
1652 if( pB && pP && pA && pW && pAlphaW )
1654 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1656 const long nMapY = pMapY[ nY ];
1657 const long nModY = ( nOutY & 0x0FL ) << 4L;
1659 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1661 const long nMapX = pMapX[ nX ];
1662 const ULONG nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1664 aSrcCol = pP->GetColor( nMapY, nMapX );
1665 aDstCol = pB->GetColor( nY, nX );
1666 nSrcAlpha = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
1667 nDstAlpha = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
1669 if( nSrcAlpha + nDstAlpha == 0 )
1671 // #i70653# zero alpha -> zero color values
1672 aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ 0 ] + nD ) >> 16UL ] +
1673 nVCLGLut[ ( nVCLLut[ 0 ] + nD ) >> 16UL ] +
1674 nVCLBLut[ ( nVCLLut[ 0 ] + nD ) >> 16UL ] ) );
1676 else
1678 aDstCol.SetRed( (BYTE)(((int)(aSrcCol.GetRed())*nSrcAlpha + (int)(aDstCol.GetRed())*nDstAlpha) /
1679 (nSrcAlpha+nDstAlpha)) );
1680 aDstCol.SetGreen( (BYTE)(((int)(aSrcCol.GetGreen())*nSrcAlpha + (int)(aDstCol.GetGreen())*nDstAlpha) /
1681 (nSrcAlpha+nDstAlpha)) );
1682 aDstCol.SetBlue( (BYTE)(((int)(aSrcCol.GetBlue())*nSrcAlpha + (int)(aDstCol.GetBlue())*nDstAlpha) /
1683 (nSrcAlpha+nDstAlpha)) );
1685 aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1686 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1687 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1689 pW->SetPixel( nY, nX, aIndex );
1691 // Have to perform the compositing 'algebra' in
1692 // the inverse alpha space (with 255 meaning
1693 // opaque), otherwise, transitivity is not
1694 // achieved.
1695 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (BYTE)nDstAlpha, nSrcAlpha );
1697 aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1698 nVCLGLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1699 nVCLBLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] ) );
1700 pAlphaW->SetPixel( nY, nX, aIndex );
1705 aBmp.ReleaseAccess( pB );
1706 aDither.ReleaseAccess( pW );
1707 res = aDither;
1709 else
1711 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
1712 if( pP && pA && pB )
1714 for( nY = 0; nY < nDstHeight; nY++ )
1716 const long nMapY = pMapY[ nY ];
1718 for( nX = 0; nX < nDstWidth; nX++ )
1720 const long nMapX = pMapX[ nX ];
1722 aSrcCol = pP->GetColor( nMapY, nMapX );
1723 aDstCol = pB->GetColor( nY, nX );
1724 nSrcAlpha = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
1725 nDstAlpha = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
1727 if( nSrcAlpha + nDstAlpha == 0 )
1729 // #i70653# zero alpha -> zero color values
1730 aDstCol.SetRed(0);
1731 aDstCol.SetGreen(0);
1732 aDstCol.SetBlue(0);
1734 else
1736 aDstCol.SetRed( (BYTE)(((int)(aSrcCol.GetRed())*nSrcAlpha + (int)(aDstCol.GetRed())*nDstAlpha) /
1737 (nSrcAlpha+nDstAlpha)) );
1738 aDstCol.SetGreen( (BYTE)(((int)(aSrcCol.GetGreen())*nSrcAlpha + (int)(aDstCol.GetGreen())*nDstAlpha) /
1739 (nSrcAlpha+nDstAlpha)) );
1740 aDstCol.SetBlue( (BYTE)(((int)(aSrcCol.GetBlue())*nSrcAlpha + (int)(aDstCol.GetBlue())*nDstAlpha) /
1741 (nSrcAlpha+nDstAlpha)) );
1744 pB->SetPixel( nY, nX, aDstCol );
1746 // Have to perform the compositing 'algebra' in
1747 // the inverse alpha space (with 255 meaning
1748 // opaque), otherwise, transitivity is not
1749 // achieved.
1750 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (BYTE)nDstAlpha, nSrcAlpha );
1752 pAlphaW->SetPixel( nY, nX, Color(nSrcAlpha, nSrcAlpha, nSrcAlpha) );
1757 aBmp.ReleaseAccess( pB );
1758 res = aBmp;
1761 aAlphaBitmap.ReleaseAccess( pAlphaW );
1762 mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
1763 mpAlphaVDev->EnableMapMode( bOldMapMode );
1765 return res;
1768 // ------------------------------------------------------------------------
1770 Bitmap OutputDevice::ImplBlend( Bitmap aBmp,
1771 BitmapReadAccess* pP,
1772 BitmapReadAccess* pA,
1773 const sal_Int32 nOffY,
1774 const sal_Int32 nDstHeight,
1775 const sal_Int32 nOffX,
1776 const sal_Int32 nDstWidth,
1777 const Rectangle& aBmpRect,
1778 const Size& aOutSz,
1779 const bool bHMirr,
1780 const bool bVMirr,
1781 const long* pMapX,
1782 const long* pMapY )
1784 BitmapColor aDstCol;
1785 Bitmap res;
1786 int nX, nOutX, nY, nOutY;
1788 if( GetBitCount() <= 8 )
1790 Bitmap aDither( aBmp.GetSizePixel(), 8 );
1791 BitmapColor aIndex( 0 );
1792 BitmapReadAccess* pB = aBmp.AcquireReadAccess();
1793 BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
1795 if( pB && pP && pA && pW )
1797 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1799 const long nMapY = pMapY[ nY ];
1800 const long nModY = ( nOutY & 0x0FL ) << 4L;
1802 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1804 const long nMapX = pMapX[ nX ];
1805 const ULONG nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1807 aDstCol = pB->GetColor( nY, nX );
1808 aDstCol.Merge( pP->GetColor( nMapY, nMapX ), (BYTE) pA->GetPixel( nMapY, nMapX ) );
1809 aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1810 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1811 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1812 pW->SetPixel( nY, nX, aIndex );
1817 aBmp.ReleaseAccess( pB );
1818 aDither.ReleaseAccess( pW );
1819 res = aDither;
1821 else
1823 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
1825 bool bFastBlend = false;
1826 if( pP && pA && pB )
1828 SalTwoRect aTR;
1829 aTR.mnSrcX = aBmpRect.Left();
1830 aTR.mnSrcY = aBmpRect.Top();
1831 aTR.mnSrcWidth = aBmpRect.GetWidth();
1832 aTR.mnSrcHeight = aBmpRect.GetHeight();
1833 aTR.mnDestX = nOffX;
1834 aTR.mnDestY = nOffY;
1835 aTR.mnDestWidth = aOutSz.Width();
1836 aTR.mnDestHeight= aOutSz.Height();
1838 if( !bHMirr || !bVMirr )
1839 bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
1842 if( pP && pA && pB && !bFastBlend )
1844 switch( pP->GetScanlineFormat() )
1846 case( BMP_FORMAT_8BIT_PAL ):
1848 for( nY = 0; nY < nDstHeight; nY++ )
1850 const long nMapY = pMapY[ nY ];
1851 Scanline pPScan = pP->GetScanline( nMapY );
1852 Scanline pAScan = pA->GetScanline( nMapY );
1854 for( nX = 0; nX < nDstWidth; nX++ )
1856 const long nMapX = pMapX[ nX ];
1857 aDstCol = pB->GetPixel( nY, nX );
1858 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ),
1859 pAScan[ nMapX ] ) );
1863 break;
1865 case( BMP_FORMAT_24BIT_TC_BGR ):
1867 for( nY = 0; nY < nDstHeight; nY++ )
1869 const long nMapY = pMapY[ nY ];
1870 Scanline pPScan = pP->GetScanline( nMapY );
1871 Scanline pAScan = pA->GetScanline( nMapY );
1873 for( nX = 0; nX < nDstWidth; nX++ )
1875 const long nMapX = pMapX[ nX ];
1876 Scanline pTmp = pPScan + nMapX * 3;
1878 aDstCol = pB->GetPixel( nY, nX );
1879 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
1880 pAScan[ nMapX ] ) );
1884 break;
1886 case( BMP_FORMAT_24BIT_TC_RGB ):
1888 for( nY = 0; nY < nDstHeight; nY++ )
1890 const long nMapY = pMapY[ nY ];
1891 Scanline pPScan = pP->GetScanline( nMapY );
1892 Scanline pAScan = pA->GetScanline( nMapY );
1894 for( nX = 0; nX < nDstWidth; nX++ )
1896 const long nMapX = pMapX[ nX ];
1897 Scanline pTmp = pPScan + nMapX * 3;
1899 aDstCol = pB->GetPixel( nY, nX );
1900 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
1901 pAScan[ nMapX ] ) );
1905 break;
1907 default:
1909 for( nY = 0; nY < nDstHeight; nY++ )
1911 const long nMapY = pMapY[ nY ];
1912 Scanline pAScan = pA->GetScanline( nMapY );
1914 for( nX = 0; nX < nDstWidth; nX++ )
1916 const long nMapX = pMapX[ nX ];
1917 aDstCol = pB->GetPixel( nY, nX );
1918 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ),
1919 pAScan[ nMapX ] ) );
1923 break;
1927 aBmp.ReleaseAccess( pB );
1928 res = aBmp;
1931 return res;
1934 // ------------------------------------------------------------------------
1936 void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha,
1937 const Point& rDestPt, const Size& rDestSize,
1938 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
1940 const Point aNullPt;
1941 Point aOutPt( LogicToPixel( rDestPt ) );
1942 Size aOutSz( LogicToPixel( rDestSize ) );
1943 Rectangle aDstRect( aNullPt, GetOutputSizePixel() );
1944 const BOOL bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0;
1946 if( OUTDEV_WINDOW == meOutDevType )
1948 const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
1950 if( !aPaintRgn.IsNull() )
1951 aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) );
1954 if( bHMirr )
1956 aOutSz.Width() = -aOutSz.Width();
1957 aOutPt.X() -= ( aOutSz.Width() - 1L );
1960 if( bVMirr )
1962 aOutSz.Height() = -aOutSz.Height();
1963 aOutPt.Y() -= ( aOutSz.Height() - 1L );
1966 if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
1968 bool bNativeAlpha = false;
1969 static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
1970 // #i83087# Naturally, system alpha blending cannot work with
1971 // separate alpha VDev
1972 if( !mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr )
1974 Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
1975 SalTwoRect aTR = {
1976 rSrcPtPixel.X(), rSrcPtPixel.Y(),
1977 rSrcSizePixel.Width(), rSrcSizePixel.Height(),
1978 aRelPt.X(), aRelPt.Y(),
1979 aOutSz.Width(), aOutSz.Height()
1981 SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
1982 SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
1983 bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this );
1986 VirtualDevice* pOldVDev = mpAlphaVDev;
1988 Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() );
1989 if( !bNativeAlpha
1990 && !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() )
1992 GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = NULL;
1993 const BOOL bOldMap = mbMap; mbMap = FALSE;
1994 Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1996 // #109044# The generated bitmap need not necessarily be
1997 // of aDstRect dimensions, it's internally clipped to
1998 // window bounds. Thus, we correct the dest size here,
1999 // since we later use it (in nDstWidth/Height) for pixel
2000 // access)
2001 // #i38887# reading from screen may sometimes fail
2002 if( aBmp.ImplGetImpBitmap() )
2003 aDstRect.SetSize( aBmp.GetSizePixel() );
2005 BitmapColor aDstCol;
2006 const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
2007 const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
2008 const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
2009 const long nOffX = aDstRect.Left() - aOutPt.X(), nOffY = aDstRect.Top() - aOutPt.Y();
2010 long nX, nOutX, nY, nOutY;
2011 long nMirrOffX = 0;
2012 long nMirrOffY = 0;
2013 long* pMapX = new long[ nDstWidth ];
2014 long* pMapY = new long[ nDstHeight ];
2016 // create horizontal mapping table
2017 if( bHMirr )
2018 nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
2020 for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
2022 pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
2024 if( bHMirr )
2025 pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
2028 // create vertical mapping table
2029 if( bVMirr )
2030 nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
2032 for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
2034 pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
2036 if( bVMirr )
2037 pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
2040 BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
2041 BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
2043 DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
2044 pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
2045 "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
2047 // #i38887# reading from screen may sometimes fail
2048 if( aBmp.ImplGetImpBitmap() )
2050 Bitmap aTmp;
2052 if( mpAlphaVDev )
2054 aTmp = ImplBlendWithAlpha(
2055 aBmp,pP,pA,
2056 aDstRect,
2057 nOffY,nDstHeight,
2058 nOffX,nDstWidth,
2059 pMapX,pMapY );
2061 else
2063 aTmp = ImplBlend(
2064 aBmp,pP,pA,
2065 nOffY,nDstHeight,
2066 nOffX,nDstWidth,
2067 aBmpRect,aOutSz,
2068 bHMirr,bVMirr,
2069 pMapX,pMapY );
2072 // #110958# Disable alpha VDev, we're doing the necessary
2073 // stuff explicitely furher below
2074 if( mpAlphaVDev )
2075 mpAlphaVDev = NULL;
2077 DrawBitmap( aDstRect.TopLeft(),
2078 aTmp );
2080 // #110958# Enable alpha VDev again
2081 mpAlphaVDev = pOldVDev;
2084 ( (Bitmap&) rBmp ).ReleaseAccess( pP );
2085 ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
2087 delete[] pMapX;
2088 delete[] pMapY;
2089 mbMap = bOldMap;
2090 mpMetaFile = pOldMetaFile;
2095 // ------------------------------------------------------------------------
2097 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
2098 const Point& rDestPt, const Size& rDestSize,
2099 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2101 Point aPt;
2102 Point aDestPt( LogicToPixel( rDestPt ) );
2103 Size aDestSz( LogicToPixel( rDestSize ) );
2104 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
2106 aSrcRect.Justify();
2108 if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2110 Bitmap aPaint( rBmp ), aMask( rMask );
2111 ULONG nMirrFlags = 0UL;
2113 if( aMask.GetBitCount() > 1 )
2114 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2116 // mirrored horizontically
2117 if( aDestSz.Width() < 0L )
2119 aDestSz.Width() = -aDestSz.Width();
2120 aDestPt.X() -= ( aDestSz.Width() - 1L );
2121 nMirrFlags |= BMP_MIRROR_HORZ;
2124 // mirrored vertically
2125 if( aDestSz.Height() < 0L )
2127 aDestSz.Height() = -aDestSz.Height();
2128 aDestPt.Y() -= ( aDestSz.Height() - 1L );
2129 nMirrFlags |= BMP_MIRROR_VERT;
2132 // source cropped?
2133 if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) )
2135 aPaint.Crop( aSrcRect );
2136 aMask.Crop( aSrcRect );
2139 // destination mirrored
2140 if( nMirrFlags )
2142 aPaint.Mirror( nMirrFlags );
2143 aMask.Mirror( nMirrFlags );
2146 // we always want to have a mask
2147 if( aMask.IsEmpty() )
2149 aMask = Bitmap( aSrcRect.GetSize(), 1 );
2150 aMask.Erase( Color( COL_BLACK ) );
2153 // do painting
2154 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2155 long nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2156 long* pMapX = new long[ nSrcWidth + 1 ];
2157 long* pMapY = new long[ nSrcHeight + 1 ];
2158 const BOOL bOldMap = mbMap;
2160 mbMap = FALSE;
2162 // create forward mapping tables
2163 for( nX = 0L; nX <= nSrcWidth; nX++ )
2164 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2166 for( nY = 0L; nY <= nSrcHeight; nY++ )
2167 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2169 // walk through all rectangles of mask
2170 Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2171 ImplRegionInfo aInfo;
2172 BOOL bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2174 while( bRgnRect )
2176 Bitmap aBandBmp( aPaint );
2177 const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) );
2178 const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2179 const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2181 aBandBmp.Crop( aBandRect );
2182 ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION );
2183 bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2186 mbMap = bOldMap;
2188 delete[] pMapX;
2189 delete[] pMapY;
2193 // ------------------------------------------------------------------------
2195 void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor,
2196 const Point& rDestPt, const Size& rDestSize,
2197 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2199 Point aPt;
2200 Point aDestPt( LogicToPixel( rDestPt ) );
2201 Size aDestSz( LogicToPixel( rDestSize ) );
2202 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
2204 aSrcRect.Justify();
2206 if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2208 Bitmap aMask( rMask );
2209 ULONG nMirrFlags = 0UL;
2211 if( aMask.GetBitCount() > 1 )
2212 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2214 // mirrored horizontically
2215 if( aDestSz.Width() < 0L )
2217 aDestSz.Width() = -aDestSz.Width();
2218 aDestPt.X() -= ( aDestSz.Width() - 1L );
2219 nMirrFlags |= BMP_MIRROR_HORZ;
2222 // mirrored vertically
2223 if( aDestSz.Height() < 0L )
2225 aDestSz.Height() = -aDestSz.Height();
2226 aDestPt.Y() -= ( aDestSz.Height() - 1L );
2227 nMirrFlags |= BMP_MIRROR_VERT;
2230 // source cropped?
2231 if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) )
2232 aMask.Crop( aSrcRect );
2234 // destination mirrored
2235 if( nMirrFlags )
2236 aMask.Mirror( nMirrFlags );
2238 // do painting
2239 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2240 long nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2241 long* pMapX = new long[ nSrcWidth + 1 ];
2242 long* pMapY = new long[ nSrcHeight + 1 ];
2243 GDIMetaFile* pOldMetaFile = mpMetaFile;
2244 const BOOL bOldMap = mbMap;
2246 mpMetaFile = NULL;
2247 mbMap = FALSE;
2248 Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
2249 SetLineColor( rMaskColor );
2250 SetFillColor( rMaskColor );
2251 ImplInitLineColor();
2252 ImplInitFillColor();
2254 // create forward mapping tables
2255 for( nX = 0L; nX <= nSrcWidth; nX++ )
2256 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2258 for( nY = 0L; nY <= nSrcHeight; nY++ )
2259 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2261 // walk through all rectangles of mask
2262 Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2263 ImplRegionInfo aInfo;
2264 BOOL bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2266 while( bRgnRect )
2268 const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2269 const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2271 DrawRect( Rectangle( aMapPt, aMapSz ) );
2272 bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2275 Pop();
2276 delete[] pMapX;
2277 delete[] pMapY;
2278 mbMap = bOldMap;
2279 mpMetaFile = pOldMetaFile;