xref: /trunk/main/vcl/source/gdi/outdev2.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <tools/debug.hxx>
32 
33 #include <vcl/bitmap.hxx>
34 #include <vcl/bitmapex.hxx>
35 #include <vcl/window.hxx>
36 #include <vcl/metaact.hxx>
37 #include <vcl/gdimtf.hxx>
38 #include <vcl/virdev.hxx>
39 #include <vcl/bmpacc.hxx>
40 #include <vcl/outdev.hxx>
41 #include <vcl/window.hxx>
42 #include <vcl/image.hxx>
43 
44 #include <bmpfast.hxx>
45 #include <salbmp.hxx>
46 #include <salgdi.hxx>
47 #include <impbmp.hxx>
48 #include <sallayout.hxx>
49 #include <image.h>
50 #include <outdev.h>
51 #include <window.h>
52 #include <region.h>
53 #include <outdata.hxx>
54 
55 #define BAND_MAX_SIZE 512000
56 
57 // =======================================================================
58 
59 DBG_NAMEEX( OutputDevice )
60 
61 // =======================================================================
62 
63 // -----------
64 // - Defines -
65 // -----------
66 
67 #define OUTDEV_INIT()                       \
68 {                                           \
69     if ( !IsDeviceOutputNecessary() )       \
70         return;                             \
71                                             \
72     if ( !mpGraphics )                      \
73         if ( !ImplGetGraphics() )           \
74             return;                         \
75                                             \
76     if ( mbInitClipRegion )                 \
77         ImplInitClipRegion();               \
78                                             \
79     if ( mbOutputClipped )                  \
80         return;                             \
81 }
82 
83 #define TwoRect     SalTwoRect
84 
85 // -------------
86 // - externals -
87 // -------------
88 
89 extern sal_uLong nVCLRLut[ 6 ];
90 extern sal_uLong nVCLGLut[ 6 ];
91 extern sal_uLong nVCLBLut[ 6 ];
92 extern sal_uLong nVCLDitherLut[ 256 ];
93 extern sal_uLong nVCLLut[ 256 ];
94 
95 // =======================================================================
96 
97 sal_uLong ImplAdjustTwoRect( TwoRect& rTwoRect, const Size& rSizePix )
98 {
99     sal_uLong nMirrFlags = 0;
100 
101     if ( rTwoRect.mnDestWidth < 0 )
102     {
103         rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth;
104         rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth;
105         rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1;
106         nMirrFlags |= BMP_MIRROR_HORZ;
107     }
108 
109     if ( rTwoRect.mnDestHeight < 0 )
110     {
111         rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight;
112         rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight;
113         rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1;
114         nMirrFlags |= BMP_MIRROR_VERT;
115     }
116 
117     if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) ||
118         ( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) ||
119         ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) ||
120         ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) )
121     {
122         const Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
123                                      Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
124         Rectangle       aCropRect( aSourceRect );
125 
126         aCropRect.Intersection( Rectangle( Point(), rSizePix ) );
127 
128         if( aCropRect.IsEmpty() )
129             rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
130         else
131         {
132             const double    fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? (double) ( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
133             const double    fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? (double) ( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
134 
135             const long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
136             const long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
137             const long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
138             const long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
139 
140             rTwoRect.mnSrcX = aCropRect.Left();
141             rTwoRect.mnSrcY = aCropRect.Top();
142             rTwoRect.mnSrcWidth = aCropRect.GetWidth();
143             rTwoRect.mnSrcHeight = aCropRect.GetHeight();
144             rTwoRect.mnDestX = nDstX1;
145             rTwoRect.mnDestY = nDstY1;
146             rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
147             rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
148         }
149     }
150 
151     return nMirrFlags;
152 }
153 
154 // =======================================================================
155 
156 void OutputDevice::ImplDrawOutDevDirect( const OutputDevice* pSrcDev, void* pVoidPosAry )
157 {
158     TwoRect*            pPosAry = (TwoRect*)pVoidPosAry;
159     SalGraphics*        pGraphics2;
160 
161     if ( pPosAry->mnSrcWidth && pPosAry->mnSrcHeight && pPosAry->mnDestWidth && pPosAry->mnDestHeight )
162     {
163         if ( this == pSrcDev )
164             pGraphics2 = NULL;
165         else
166         {
167             if ( (GetOutDevType() != pSrcDev->GetOutDevType()) ||
168                  (GetOutDevType() != OUTDEV_WINDOW) )
169             {
170                 if ( !pSrcDev->mpGraphics )
171                 {
172                     if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
173                         return;
174                 }
175                 pGraphics2 = pSrcDev->mpGraphics;
176             }
177             else
178             {
179                 if ( ((Window*)this)->mpWindowImpl->mpFrameWindow == ((Window*)pSrcDev)->mpWindowImpl->mpFrameWindow )
180                     pGraphics2 = NULL;
181                 else
182                 {
183                     if ( !pSrcDev->mpGraphics )
184                     {
185                         if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
186                             return;
187                     }
188                     pGraphics2 = pSrcDev->mpGraphics;
189 
190                     if ( !mpGraphics )
191                     {
192                         if ( !ImplGetGraphics() )
193                             return;
194                     }
195                     DBG_ASSERT( mpGraphics && pSrcDev->mpGraphics,
196                                 "OutputDevice::DrawOutDev(): We need more than one Graphics" );
197                 }
198             }
199         }
200 
201         // #102532# Offset only has to be pseudo window offset
202         Rectangle   aSrcOutRect( Point( pSrcDev->mnOutOffX, pSrcDev->mnOutOffY ),
203                                  Size( pSrcDev->mnOutWidth, pSrcDev->mnOutHeight ) );
204         Rectangle   aSrcRect( Point( pPosAry->mnSrcX, pPosAry->mnSrcY ),
205                               Size( pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) );
206         const long  nOldRight = aSrcRect.Right();
207         const long  nOldBottom = aSrcRect.Bottom();
208 
209         if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
210         {
211             if ( (pPosAry->mnSrcX+pPosAry->mnSrcWidth-1) > aSrcOutRect.Right() )
212             {
213                 const long nOldWidth = pPosAry->mnSrcWidth;
214                 pPosAry->mnSrcWidth -= (nOldRight - aSrcRect.Right());
215                 pPosAry->mnDestWidth = pPosAry->mnDestWidth * pPosAry->mnSrcWidth / nOldWidth;
216             }
217 
218             if ( (pPosAry->mnSrcY+pPosAry->mnSrcHeight-1) > aSrcOutRect.Bottom() )
219             {
220                 const long nOldHeight = pPosAry->mnSrcHeight;
221                 pPosAry->mnSrcHeight -= (nOldBottom - aSrcRect.Bottom());
222                 pPosAry->mnDestHeight = pPosAry->mnDestHeight * pPosAry->mnSrcHeight / nOldHeight;
223             }
224 
225             // --- RTL --- if this is no window, but pSrcDev is a window
226             // mirroring may be required
227             // because only windows have a SalGraphicsLayout
228             // mirroring is performed here
229             if( (GetOutDevType() != OUTDEV_WINDOW) && pGraphics2 && (pGraphics2->GetLayout() & SAL_LAYOUT_BIDI_RTL) )
230             {
231                 SalTwoRect pPosAry2 = *pPosAry;
232                 pGraphics2->mirror( pPosAry2.mnSrcX, pPosAry2.mnSrcWidth, pSrcDev );
233                 mpGraphics->CopyBits( &pPosAry2, pGraphics2, this, pSrcDev );
234             }
235             else
236                 mpGraphics->CopyBits( pPosAry, pGraphics2, this, pSrcDev );
237         }
238     }
239 }
240 
241 // ------------------------------------------------------------------
242 
243 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
244                                const Point& rSrcPt,  const Size& rSrcSize )
245 {
246     DBG_TRACE( "OutputDevice::DrawOutDev()" );
247     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
248     DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
249 
250     if( ImplIsRecordLayout() )
251         return;
252 
253     if ( meOutDevType == OUTDEV_PRINTER )
254         return;
255 
256     if ( ROP_INVERT == meRasterOp )
257     {
258         DrawRect( Rectangle( rDestPt, rDestSize ) );
259         return;
260     }
261 
262     if ( mpMetaFile )
263     {
264         const Bitmap aBmp( GetBitmap( rSrcPt, rSrcSize ) );
265         mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
266     }
267 
268     OUTDEV_INIT();
269 
270     TwoRect aPosAry;
271     aPosAry.mnSrcWidth   = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
272     aPosAry.mnSrcHeight  = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
273     aPosAry.mnDestWidth  = ImplLogicWidthToDevicePixel( rDestSize.Width() );
274     aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
275 
276     if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
277     {
278         aPosAry.mnSrcX       = ImplLogicXToDevicePixel( rSrcPt.X() );
279         aPosAry.mnSrcY       = ImplLogicYToDevicePixel( rSrcPt.Y() );
280         aPosAry.mnDestX      = ImplLogicXToDevicePixel( rDestPt.X() );
281         aPosAry.mnDestY      = ImplLogicYToDevicePixel( rDestPt.Y() );
282 
283         Rectangle   aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
284                                  Size( mnOutWidth, mnOutHeight ) );
285         Rectangle   aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
286                               Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
287         long        nOldRight = aSrcRect.Right();
288         long        nOldBottom = aSrcRect.Bottom();
289 
290         if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
291         {
292             if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
293             {
294                 long nOldWidth = aPosAry.mnSrcWidth;
295                 aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
296                 aPosAry.mnDestWidth = aPosAry.mnDestWidth*aPosAry.mnSrcWidth/nOldWidth;
297             }
298 
299             if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
300             {
301                 long nOldHeight = aPosAry.mnSrcHeight;
302                 aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
303                 aPosAry.mnDestHeight = aPosAry.mnDestHeight*aPosAry.mnSrcHeight/nOldHeight;
304             }
305 
306             mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
307         }
308     }
309 
310     if( mpAlphaVDev )
311         mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize );
312 }
313 
314 // ------------------------------------------------------------------
315 
316 void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
317                                const Point& rSrcPt,  const Size& rSrcSize,
318                                const OutputDevice& rOutDev )
319 {
320     DBG_TRACE( "OutputDevice::DrawOutDev()" );
321     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
322     DBG_CHKOBJ( &rOutDev, OutputDevice, ImplDbgCheckOutputDevice );
323     DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
324     DBG_ASSERT( rOutDev.meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
325 
326     if ( (meOutDevType == OUTDEV_PRINTER) || (rOutDev.meOutDevType == OUTDEV_PRINTER) || ImplIsRecordLayout() )
327         return;
328 
329     if ( ROP_INVERT == meRasterOp )
330     {
331         DrawRect( Rectangle( rDestPt, rDestSize ) );
332         return;
333     }
334 
335     if ( mpMetaFile )
336     {
337         const Bitmap aBmp( rOutDev.GetBitmap( rSrcPt, rSrcSize ) );
338         mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
339     }
340 
341     OUTDEV_INIT();
342 
343     TwoRect aPosAry;
344     aPosAry.mnSrcX       = rOutDev.ImplLogicXToDevicePixel( rSrcPt.X() );
345     aPosAry.mnSrcY       = rOutDev.ImplLogicYToDevicePixel( rSrcPt.Y() );
346     aPosAry.mnSrcWidth   = rOutDev.ImplLogicWidthToDevicePixel( rSrcSize.Width() );
347     aPosAry.mnSrcHeight  = rOutDev.ImplLogicHeightToDevicePixel( rSrcSize.Height() );
348     aPosAry.mnDestX      = ImplLogicXToDevicePixel( rDestPt.X() );
349     aPosAry.mnDestY      = ImplLogicYToDevicePixel( rDestPt.Y() );
350     aPosAry.mnDestWidth  = ImplLogicWidthToDevicePixel( rDestSize.Width() );
351     aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
352 
353     if( mpAlphaVDev )
354     {
355         if( rOutDev.mpAlphaVDev )
356         {
357             // alpha-blend source over destination
358             DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
359 
360             // This would be mode SOURCE:
361             // copy source alpha channel to our alpha channel
362             //mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize, *rOutDev.mpAlphaVDev );
363         }
364         else
365         {
366             ImplDrawOutDevDirect( &rOutDev, &aPosAry );
367 
368             // #i32109#: make destination rectangle opaque - source has no alpha
369             mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
370         }
371     }
372     else
373     {
374         if( rOutDev.mpAlphaVDev )
375         {
376             // alpha-blend source over destination
377             DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
378         }
379         else
380         {
381             // no alpha at all, neither in source nor destination device
382             ImplDrawOutDevDirect( &rOutDev, &aPosAry );
383         }
384     }
385 }
386 
387 // ------------------------------------------------------------------
388 
389 void OutputDevice::CopyArea( const Point& rDestPt,
390                              const Point& rSrcPt,  const Size& rSrcSize,
391                              sal_uInt16 nFlags )
392 {
393     DBG_TRACE( "OutputDevice::CopyArea()" );
394     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
395     DBG_ASSERT( meOutDevType != OUTDEV_PRINTER, "Don't use OutputDevice::CopyArea(...) with printer devices!" );
396 
397     if ( meOutDevType == OUTDEV_PRINTER || ImplIsRecordLayout() )
398         return;
399 
400     RasterOp eOldRop = GetRasterOp();
401     SetRasterOp( ROP_OVERPAINT );
402 
403     OUTDEV_INIT();
404 
405     TwoRect aPosAry;
406     aPosAry.mnSrcWidth   = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
407     aPosAry.mnSrcHeight  = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
408 
409     if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight )
410     {
411         aPosAry.mnSrcX       = ImplLogicXToDevicePixel( rSrcPt.X() );
412         aPosAry.mnSrcY       = ImplLogicYToDevicePixel( rSrcPt.Y() );
413         aPosAry.mnDestX      = ImplLogicXToDevicePixel( rDestPt.X() );
414         aPosAry.mnDestY      = ImplLogicYToDevicePixel( rDestPt.Y() );
415 
416         Rectangle   aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
417                                  Size( mnOutWidth, mnOutHeight ) );
418         Rectangle   aSrcRect( Point( aPosAry.mnSrcX, aPosAry.mnSrcY ),
419                               Size( aPosAry.mnSrcWidth, aPosAry.mnSrcHeight ) );
420         long        nOldRight = aSrcRect.Right();
421         long        nOldBottom = aSrcRect.Bottom();
422 
423         if ( !aSrcRect.Intersection( aSrcOutRect ).IsEmpty() )
424         {
425             if ( (aPosAry.mnSrcX+aPosAry.mnSrcWidth-1) > aSrcOutRect.Right() )
426                 aPosAry.mnSrcWidth -= nOldRight-aSrcRect.Right();
427 
428             if ( (aPosAry.mnSrcY+aPosAry.mnSrcHeight-1) > aSrcOutRect.Bottom() )
429                 aPosAry.mnSrcHeight -= nOldBottom-aSrcRect.Bottom();
430 
431             if ( (meOutDevType == OUTDEV_WINDOW) && (nFlags & COPYAREA_WINDOWINVALIDATE) )
432             {
433                 ((Window*)this)->ImplMoveAllInvalidateRegions( aSrcRect,
434                                                                aPosAry.mnDestX-aPosAry.mnSrcX,
435                                                                aPosAry.mnDestY-aPosAry.mnSrcY,
436                                                                sal_False );
437 
438                 mpGraphics->CopyArea( aPosAry.mnDestX, aPosAry.mnDestY,
439                                       aPosAry.mnSrcX, aPosAry.mnSrcY,
440                                       aPosAry.mnSrcWidth, aPosAry.mnSrcHeight,
441                                       SAL_COPYAREA_WINDOWINVALIDATE, this );
442             }
443             else
444             {
445                 aPosAry.mnDestWidth  = aPosAry.mnSrcWidth;
446                 aPosAry.mnDestHeight = aPosAry.mnSrcHeight;
447                 mpGraphics->CopyBits( &aPosAry, NULL, this, NULL );
448             }
449         }
450     }
451 
452     SetRasterOp( eOldRop );
453 
454     if( mpAlphaVDev )
455         mpAlphaVDev->CopyArea( rDestPt, rSrcPt, rSrcSize, nFlags );
456 }
457 
458 // ------------------------------------------------------------------
459 
460 void OutputDevice::ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
461                                      const OutputDevice& rOutDev, const Region& rRegion )
462 {
463     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
464 
465     GDIMetaFile*    pOldMetaFile = mpMetaFile;
466     sal_Bool            bOldMap = mbMap;
467     RasterOp        eOldROP = GetRasterOp();
468     mpMetaFile = NULL;
469     mbMap = sal_False;
470     SetRasterOp( ROP_OVERPAINT );
471 
472     if ( !IsDeviceOutputNecessary() )
473         return;
474 
475     if ( !mpGraphics )
476     {
477         if ( !ImplGetGraphics() )
478             return;
479     }
480 
481     // ClipRegion zuruecksetzen
482     if ( rRegion.IsNull() )
483         mpGraphics->ResetClipRegion();
484     else
485         ImplSelectClipRegion( rRegion );
486 
487     TwoRect aPosAry;
488     aPosAry.mnSrcX       = rDevPt.X();
489     aPosAry.mnSrcY       = rDevPt.Y();
490     aPosAry.mnSrcWidth   = rDevSize.Width();
491     aPosAry.mnSrcHeight  = rDevSize.Height();
492     aPosAry.mnDestX      = rPt.X();
493     aPosAry.mnDestY      = rPt.Y();
494     aPosAry.mnDestWidth  = rDevSize.Width();
495     aPosAry.mnDestHeight = rDevSize.Height();
496     ImplDrawOutDevDirect( &rOutDev, &aPosAry );
497 
498     // Dafuer sorgen, das ClipRegion neu berechnet und gesetzt wird
499     mbInitClipRegion = sal_True;
500 
501     SetRasterOp( eOldROP );
502     mbMap = bOldMap;
503     mpMetaFile = pOldMetaFile;
504 }
505 
506 // ------------------------------------------------------------------
507 
508 void OutputDevice::ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
509                                     OutputDevice& rDev )
510 {
511     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
512 
513     sal_Bool bOldMap = mbMap;
514     mbMap = sal_False;
515     rDev.DrawOutDev( rDevPt, rDevSize, rPt, rDevSize, *this );
516     mbMap = bOldMap;
517 }
518 
519 // ------------------------------------------------------------------
520 
521 void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
522 {
523     DBG_TRACE( "OutputDevice::DrawBitmap()" );
524 
525     if( ImplIsRecordLayout() )
526         return;
527 
528     const Size aSizePix( rBitmap.GetSizePixel() );
529     ImplDrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION );
530 
531     if( mpAlphaVDev )
532     {
533         // #i32109#: Make bitmap area opaque
534         mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, PixelToLogic( aSizePix )) );
535     }
536 }
537 
538 // ------------------------------------------------------------------
539 
540 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
541 {
542     DBG_TRACE( "OutputDevice::DrawBitmap( Size )" );
543 
544     if( ImplIsRecordLayout() )
545         return;
546 
547     ImplDrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION );
548 
549     if( mpAlphaVDev )
550     {
551         // #i32109#: Make bitmap area opaque
552         mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
553     }
554 }
555 
556 // ------------------------------------------------------------------
557 
558 void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize,
559                                const Point& rSrcPtPixel, const Size& rSrcSizePixel,
560                                const Bitmap& rBitmap )
561 {
562     DBG_TRACE( "OutputDevice::DrawBitmap( Point, Size )" );
563 
564     if( ImplIsRecordLayout() )
565         return;
566 
567     ImplDrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, META_BMPSCALEPART_ACTION );
568 
569     if( mpAlphaVDev )
570     {
571         // #i32109#: Make bitmap area opaque
572         mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
573     }
574 }
575 
576 // -----------------------------------------------------------------------------
577 
578 void OutputDevice::ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize,
579                                    const Point& rSrcPtPixel, const Size& rSrcSizePixel,
580                                    const Bitmap& rBitmap, const sal_uLong nAction )
581 {
582     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
583 
584     Bitmap aBmp( rBitmap );
585 
586     if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) )
587         return;
588     else if ( ROP_INVERT == meRasterOp )
589     {
590         DrawRect( Rectangle( rDestPt, rDestSize ) );
591         return;
592     }
593     else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
594                              DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
595     {
596         if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
597         {
598             sal_uInt8 cCmpVal;
599 
600             if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
601                 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
602             else
603                 cCmpVal = 255;
604 
605             Color aCol( cCmpVal, cCmpVal, cCmpVal );
606             Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
607             SetLineColor( aCol );
608             SetFillColor( aCol );
609             DrawRect( Rectangle( rDestPt, rDestSize ) );
610             Pop();
611             return;
612         }
613         else if( !!aBmp )
614         {
615             if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
616                 aBmp.Convert( BMP_CONVERSION_8BIT_GREYS );
617 
618             if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
619                 aBmp.Convert( BMP_CONVERSION_GHOSTED );
620         }
621     }
622 
623     if ( mpMetaFile )
624     {
625         switch( nAction )
626         {
627             case( META_BMP_ACTION ):
628                 mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) );
629             break;
630 
631             case( META_BMPSCALE_ACTION ):
632                 mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
633             break;
634 
635             case( META_BMPSCALEPART_ACTION ):
636                 mpMetaFile->AddAction( new MetaBmpScalePartAction(
637                     rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) );
638             break;
639         }
640     }
641 
642     OUTDEV_INIT();
643 
644     if( !aBmp.IsEmpty() )
645     {
646         TwoRect aPosAry;
647 
648         aPosAry.mnSrcX = rSrcPtPixel.X();
649         aPosAry.mnSrcY = rSrcPtPixel.Y();
650         aPosAry.mnSrcWidth = rSrcSizePixel.Width();
651         aPosAry.mnSrcHeight = rSrcSizePixel.Height();
652         aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
653         aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
654         aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
655         aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
656 
657         const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmp.GetSizePixel() );
658 
659         if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
660         {
661             if ( nMirrFlags )
662                 aBmp.Mirror( nMirrFlags );
663 
664             /* #i75264# (corrected with #i81576#)
665             * sometimes a bitmap is scaled to a ridiculous size and drawn
666             * to a quite normal VDev, so only a very small part of
667             * the scaled bitmap will be visible. However actually scaling
668             * the bitmap will use so much memory that we end with a crash.
669             * Workaround: since only a small part of the scaled bitmap will
670             * be actually drawn anyway (because of clipping on the device
671             * boundary), limit the destination and source rectangles so
672             * that the destination rectangle will overlap the device but only
673             * be reasonably (say factor 2) larger than the device itself.
674             */
675             if( aPosAry.mnDestWidth > 2048 || aPosAry.mnDestHeight > 2048 )
676             {
677                  if( meOutDevType == OUTDEV_WINDOW ||
678                      (meOutDevType == OUTDEV_VIRDEV && mpPDFWriter == 0 ) )
679                 {
680                     // #i81576# do the following trick only if there is overlap at all
681                     // else the formulae don't work
682                     // theoretically in this case we wouldn't need to draw the bitmap at all
683                     // however there are some esoteric case where that is needed
684                     if( aPosAry.mnDestX + aPosAry.mnDestWidth >= 0
685                         && aPosAry.mnDestX < mnOutWidth
686                         && aPosAry.mnDestY + aPosAry.mnDestHeight >= 0
687                         && aPosAry.mnDestY < mnOutHeight )
688                     {
689                         // reduce scaling to something reasonable taking into account the output size
690                         if( aPosAry.mnDestWidth > 3*mnOutWidth && aPosAry.mnSrcWidth )
691                         {
692                             const double nScaleX = aPosAry.mnDestWidth/double(aPosAry.mnSrcWidth);
693 
694                             if( aPosAry.mnDestX + aPosAry.mnDestWidth > mnOutWidth )
695                             {
696                                 aPosAry.mnDestWidth = Max(long(0),mnOutWidth-aPosAry.mnDestX);
697                             }
698                             if( aPosAry.mnDestX < 0 )
699                             {
700                                 aPosAry.mnDestWidth += aPosAry.mnDestX;
701                                 aPosAry.mnSrcX -= sal::static_int_cast<long>(aPosAry.mnDestX / nScaleX);
702                                 aPosAry.mnDestX = 0;
703                             }
704 
705                             aPosAry.mnSrcWidth = sal::static_int_cast<long>(aPosAry.mnDestWidth / nScaleX);
706                         }
707 
708                         if( aPosAry.mnDestHeight > 3*mnOutHeight && aPosAry.mnSrcHeight != 0 )
709                         {
710                             const double nScaleY = aPosAry.mnDestHeight/double(aPosAry.mnSrcHeight);
711 
712                             if( aPosAry.mnDestY + aPosAry.mnDestHeight > mnOutHeight )
713                             {
714                                 aPosAry.mnDestHeight = Max(long(0),mnOutHeight-aPosAry.mnDestY);
715                             }
716                             if( aPosAry.mnDestY < 0 )
717                             {
718                                 aPosAry.mnDestHeight += aPosAry.mnDestY;
719                                 aPosAry.mnSrcY -= sal::static_int_cast<long>(aPosAry.mnDestY / nScaleY);
720                                 aPosAry.mnDestY = 0;
721                             }
722 
723                             aPosAry.mnSrcHeight = sal::static_int_cast<long>(aPosAry.mnDestHeight / nScaleY);
724                         }
725                     }
726                 }
727             }
728 
729             if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
730                 mpGraphics->DrawBitmap( &aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap(), this );
731         }
732     }
733 }
734 
735 // ------------------------------------------------------------------
736 
737 void OutputDevice::DrawBitmapEx( const Point& rDestPt,
738                                  const BitmapEx& rBitmapEx )
739 {
740     DBG_TRACE( "OutputDevice::DrawBitmapEx()" );
741 
742     if( ImplIsRecordLayout() )
743         return;
744 
745     if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
746         DrawBitmap( rDestPt, rBitmapEx.GetBitmap() );
747     else
748     {
749         const Size aSizePix( rBitmapEx.GetSizePixel() );
750         ImplDrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION );
751     }
752 }
753 
754 // ------------------------------------------------------------------
755 
756 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
757                                  const BitmapEx& rBitmapEx )
758 {
759     DBG_TRACE( "OutputDevice::DrawBitmapEx( Size )" );
760 
761     if( ImplIsRecordLayout() )
762         return;
763 
764     if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
765         DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() );
766     else
767         ImplDrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION );
768 }
769 
770 // ------------------------------------------------------------------
771 
772 void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
773                                  const Point& rSrcPtPixel, const Size& rSrcSizePixel,
774                                  const BitmapEx& rBitmapEx )
775 {
776     DBG_TRACE( "OutputDevice::DrawBitmapEx( Point, Size )" );
777 
778     if( ImplIsRecordLayout() )
779         return;
780 
781     if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
782         DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() );
783     else
784         ImplDrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx, META_BMPEXSCALEPART_ACTION );
785 }
786 
787 // ------------------------------------------------------------------
788 
789 void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
790                                      const Point& rSrcPtPixel, const Size& rSrcSizePixel,
791                                      const BitmapEx& rBitmapEx, const sal_uLong nAction )
792 {
793     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
794 
795     BitmapEx aBmpEx( rBitmapEx );
796 
797     if ( mnDrawMode & DRAWMODE_NOBITMAP )
798         return;
799     else if ( ROP_INVERT == meRasterOp )
800     {
801         DrawRect( Rectangle( rDestPt, rDestSize ) );
802         return;
803     }
804     else if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
805                              DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
806     {
807         if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
808         {
809             Bitmap  aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 );
810             sal_uInt8   cCmpVal;
811 
812             if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
813                 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
814             else
815                 cCmpVal = 255;
816 
817             aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
818 
819             if( aBmpEx.IsAlpha() )
820             {
821                 // Create one-bit mask out of alpha channel, by
822                 // thresholding it at alpha=0.5. As
823                 // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
824                 // output, having alpha-induced grey levels is not
825                 // acceptable.
826                 Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() );
827                 aMask.MakeMono( 128 );
828                 aBmpEx = BitmapEx( aColorBmp, aMask );
829             }
830             else
831             {
832                 aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
833             }
834         }
835         else if( !!aBmpEx )
836         {
837             if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
838                 aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
839 
840             if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
841                 aBmpEx.Convert( BMP_CONVERSION_GHOSTED );
842         }
843     }
844 
845     if ( mpMetaFile )
846     {
847         switch( nAction )
848         {
849             case( META_BMPEX_ACTION ):
850                 mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
851             break;
852 
853             case( META_BMPEXSCALE_ACTION ):
854                 mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
855             break;
856 
857             case( META_BMPEXSCALEPART_ACTION ):
858                 mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
859                                                                      rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
860             break;
861         }
862     }
863 
864     OUTDEV_INIT();
865 
866     if( OUTDEV_PRINTER == meOutDevType )
867     {
868         if( aBmpEx.IsAlpha() )
869         {
870             // #107169# For true alpha bitmaps, no longer masking the
871             // bitmap, but perform a full alpha blend against a white
872             // background here.
873             Bitmap aBmp( aBmpEx.GetBitmap() );
874             aBmp.Blend( aBmpEx.GetAlpha(), Color( COL_WHITE) );
875             DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
876         }
877         else
878         {
879             Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() );
880             aBmp.Replace( aMask, Color( COL_WHITE ) );
881             ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
882         }
883         return;
884     }
885     else if( aBmpEx.IsAlpha() )
886     {
887         ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
888         return;
889     }
890 
891     if( !( !aBmpEx ) )
892     {
893         TwoRect aPosAry;
894 
895         aPosAry.mnSrcX = rSrcPtPixel.X();
896         aPosAry.mnSrcY = rSrcPtPixel.Y();
897         aPosAry.mnSrcWidth = rSrcSizePixel.Width();
898         aPosAry.mnSrcHeight = rSrcSizePixel.Height();
899         aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
900         aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
901         aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
902         aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
903 
904         const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() );
905 
906         if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
907         {
908 
909             if( nMirrFlags )
910                 aBmpEx.Mirror( nMirrFlags );
911 
912             const ImpBitmap* pImpBmp = aBmpEx.ImplGetBitmapImpBitmap();
913             const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap();
914 
915             if ( pMaskBmp )
916             {
917                 // #4919452# reduce operation area to bounds of
918                 // cliprect. since masked transparency involves
919                 // creation of a large vdev and copying the screen
920                 // content into that (slooow read from framebuffer),
921                 // that should considerably increase performance for
922                 // large bitmaps and small clippings.
923 
924                 // Note that this optimisation is a workaround for a
925                 // Writer peculiarity, namely, to decompose background
926                 // graphics into myriads of disjunct, tiny
927                 // rectangles. That otherwise kills us here, since for
928                 // transparent output, SAL always prepares the whole
929                 // bitmap, if aPosAry contains the whole bitmap (and
930                 // it's _not_ to blame for that).
931 
932                 // Note the call to ImplPixelToDevicePixel(), since
933                 // aPosAry already contains the mnOutOff-offsets, they
934                 // also have to be applied to the region
935                 Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
936 
937                 // TODO: Also respect scaling (that's a bit tricky,
938                 // since the source points have to move fractional
939                 // amounts (which is not possible, thus has to be
940                 // emulated by increases copy area)
941                 // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
942                 // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
943 
944                 // for now, only identity scales allowed
945                 if( !aClipRegionBounds.IsEmpty() &&
946                     aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
947                     aPosAry.mnDestHeight == aPosAry.mnSrcHeight )
948                 {
949                     // now intersect dest rect with clip region
950                     aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX,
951                                                                aPosAry.mnDestY,
952                                                                aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
953                                                                aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) );
954 
955                     // Note: I could theoretically optimize away the
956                     // DrawBitmap below, if the region is empty
957                     // here. Unfortunately, cannot rule out that
958                     // somebody relies on the side effects.
959                     if( !aClipRegionBounds.IsEmpty() )
960                     {
961                         aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
962                         aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
963                         aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
964                         aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
965 
966                         aPosAry.mnDestX = aClipRegionBounds.Left();
967                         aPosAry.mnDestY = aClipRegionBounds.Top();
968                         aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
969                         aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
970                     }
971                 }
972 
973                 mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
974                                         *pMaskBmp->ImplGetSalBitmap(),
975                                         this );
976 
977                 // #110958# Paint mask to alpha channel. Luckily, the
978                 // black and white representation of the mask maps to
979                 // the alpha channel
980 
981                 // #i25167# Restrict mask painting to _opaque_ areas
982                 // of the mask, otherwise we spoil areas where no
983                 // bitmap content was ever visible. Interestingly
984                 // enough, this can be achieved by taking the mask as
985                 // the transparency mask of itself
986                 if( mpAlphaVDev )
987                     mpAlphaVDev->DrawBitmapEx( rDestPt,
988                                                rDestSize,
989                                                BitmapEx( aBmpEx.GetMask(),
990                                                          aBmpEx.GetMask() ) );
991             }
992             else
993             {
994                 mpGraphics->DrawBitmap( &aPosAry, *pImpBmp->ImplGetSalBitmap(), this );
995 
996                 if( mpAlphaVDev )
997                 {
998                     // #i32109#: Make bitmap area opaque
999                     mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
1000                 }
1001             }
1002         }
1003     }
1004 }
1005 
1006 // ------------------------------------------------------------------
1007 
1008 void OutputDevice::DrawMask( const Point& rDestPt,
1009                              const Bitmap& rBitmap, const Color& rMaskColor )
1010 {
1011     DBG_TRACE( "OutputDevice::DrawMask()" );
1012 
1013     if( ImplIsRecordLayout() )
1014         return;
1015 
1016     const Size aSizePix( rBitmap.GetSizePixel() );
1017     ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION );
1018 
1019     if( mpAlphaVDev )
1020     {
1021         const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1022 
1023         // #i25167# Restrict mask painting to _opaque_ areas
1024         // of the mask, otherwise we spoil areas where no
1025         // bitmap content was ever visible. Interestingly
1026         // enough, this can be achieved by taking the mask as
1027         // the transparency mask of itself
1028         mpAlphaVDev->DrawBitmapEx( rDestPt,
1029                                    PixelToLogic( aSizePix ),
1030                                    BitmapEx( rMask, rMask ) );
1031     }
1032 }
1033 
1034 // ------------------------------------------------------------------
1035 
1036 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1037                              const Bitmap& rBitmap, const Color& rMaskColor )
1038 {
1039     DBG_TRACE( "OutputDevice::DrawMask( Size )" );
1040 
1041     if( ImplIsRecordLayout() )
1042         return;
1043 
1044     ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION );
1045 
1046     // TODO: Use mask here
1047     if( mpAlphaVDev )
1048     {
1049         const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1050 
1051         // #i25167# Restrict mask painting to _opaque_ areas
1052         // of the mask, otherwise we spoil areas where no
1053         // bitmap content was ever visible. Interestingly
1054         // enough, this can be achieved by taking the mask as
1055         // the transparency mask of itself
1056         mpAlphaVDev->DrawBitmapEx( rDestPt,
1057                                    rDestSize,
1058                                    BitmapEx( rMask, rMask ) );
1059     }
1060 }
1061 
1062 // ------------------------------------------------------------------
1063 
1064 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1065                              const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1066                              const Bitmap& rBitmap, const Color& rMaskColor )
1067 {
1068     DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" );
1069 
1070     if( ImplIsRecordLayout() )
1071         return;
1072 
1073     ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION );
1074 
1075     // TODO: Use mask here
1076     if( mpAlphaVDev )
1077     {
1078         const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1079 
1080         // #i25167# Restrict mask painting to _opaque_ areas
1081         // of the mask, otherwise we spoil areas where no
1082         // bitmap content was ever visible. Interestingly
1083         // enough, this can be achieved by taking the mask as
1084         // the transparency mask of itself
1085         mpAlphaVDev->DrawBitmapEx( rDestPt,
1086                                    rDestSize,
1087                                    rSrcPtPixel,
1088                                    rSrcSizePixel,
1089                                    BitmapEx( rMask, rMask ) );
1090     }
1091 }
1092 
1093 // ------------------------------------------------------------------
1094 
1095 void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize,
1096                                  const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1097                                  const Bitmap& rBitmap, const Color& rMaskColor,
1098                                  const sal_uLong nAction )
1099 {
1100     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1101 
1102     if( ROP_INVERT == meRasterOp )
1103     {
1104         DrawRect( Rectangle( rDestPt, rDestSize ) );
1105         return;
1106     }
1107 
1108     if ( mpMetaFile )
1109     {
1110         switch( nAction )
1111         {
1112             case( META_MASK_ACTION ):
1113                 mpMetaFile->AddAction( new MetaMaskAction( rDestPt,
1114                     rBitmap, rMaskColor ) );
1115             break;
1116 
1117             case( META_MASKSCALE_ACTION ):
1118                 mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt,
1119                     rDestSize, rBitmap, rMaskColor ) );
1120             break;
1121 
1122             case( META_MASKSCALEPART_ACTION ):
1123                 mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize,
1124                     rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) );
1125             break;
1126         }
1127     }
1128 
1129     OUTDEV_INIT();
1130 
1131     if ( OUTDEV_PRINTER == meOutDevType )
1132     {
1133         ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
1134         return;
1135     }
1136 
1137     const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
1138     if ( pImpBmp )
1139     {
1140         TwoRect aPosAry;
1141 
1142         aPosAry.mnSrcX = rSrcPtPixel.X();
1143         aPosAry.mnSrcY = rSrcPtPixel.Y();
1144         aPosAry.mnSrcWidth = rSrcSizePixel.Width();
1145         aPosAry.mnSrcHeight = rSrcSizePixel.Height();
1146         aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
1147         aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
1148         aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
1149         aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
1150 
1151         // spiegeln via Koordinaten wollen wir nicht
1152         const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() );
1153 
1154         // check if output is necessary
1155         if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
1156         {
1157 
1158             if( nMirrFlags )
1159             {
1160                 Bitmap aTmp( rBitmap );
1161                 aTmp.Mirror( nMirrFlags );
1162                 mpGraphics->DrawMask( &aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(),
1163                                       ImplColorToSal( rMaskColor ) , this);
1164             }
1165             else
1166                 mpGraphics->DrawMask( &aPosAry, *pImpBmp->ImplGetSalBitmap(),
1167                                       ImplColorToSal( rMaskColor ), this );
1168 
1169         }
1170     }
1171 }
1172 
1173 // ------------------------------------------------------------------
1174 
1175 void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, sal_uInt16 nStyle )
1176 {
1177     DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1178 
1179     if( !rImage.mpImplData || ImplIsRecordLayout() )
1180         return;
1181 
1182     switch( rImage.mpImplData->meType )
1183     {
1184         case IMAGETYPE_BITMAP:
1185             DrawBitmap( rPos, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1186         break;
1187 
1188         case IMAGETYPE_IMAGE:
1189         {
1190             ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1191 
1192             if( !pData->mpImageBitmap )
1193             {
1194                 const Size aSize( pData->maBmpEx.GetSizePixel() );
1195 
1196                 pData->mpImageBitmap = new ImplImageBmp;
1197                 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1198             }
1199 
1200             pData->mpImageBitmap->Draw( 0, this, rPos, nStyle );
1201         }
1202         break;
1203 
1204         default:
1205         break;
1206     }
1207 }
1208 
1209 // ------------------------------------------------------------------
1210 
1211 void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
1212                               const Image& rImage, sal_uInt16 nStyle )
1213 {
1214     DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1215 
1216     if( rImage.mpImplData && !ImplIsRecordLayout() )
1217     {
1218         switch( rImage.mpImplData->meType )
1219         {
1220             case IMAGETYPE_BITMAP:
1221                 DrawBitmap( rPos, rSize, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1222             break;
1223 
1224             case IMAGETYPE_IMAGE:
1225             {
1226                 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1227 
1228                 if ( !pData->mpImageBitmap )
1229                 {
1230                     const Size aSize( pData->maBmpEx.GetSizePixel() );
1231 
1232                     pData->mpImageBitmap = new ImplImageBmp;
1233                     pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1234                 }
1235 
1236                 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize );
1237             }
1238             break;
1239 
1240             default:
1241             break;
1242         }
1243     }
1244 }
1245 
1246 // ------------------------------------------------------------------
1247 
1248 Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1249 {
1250     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1251 
1252     Bitmap  aBmp;
1253     long    nX = ImplLogicXToDevicePixel( rSrcPt.X() );
1254     long    nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
1255     long    nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
1256     long    nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
1257 
1258     if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() )
1259     {
1260         if ( nWidth && nHeight )
1261         {
1262             Rectangle   aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
1263             sal_Bool        bClipped = sal_False;
1264 
1265             // X-Koordinate ausserhalb des Bereichs?
1266             if ( nX < mnOutOffX )
1267             {
1268                 nWidth -= ( mnOutOffX - nX );
1269                 nX = mnOutOffX;
1270                 bClipped = sal_True;
1271             }
1272 
1273             // Y-Koordinate ausserhalb des Bereichs?
1274             if ( nY < mnOutOffY )
1275             {
1276                 nHeight -= ( mnOutOffY - nY );
1277                 nY = mnOutOffY;
1278                 bClipped = sal_True;
1279             }
1280 
1281             // Breite ausserhalb des Bereichs?
1282             if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
1283             {
1284                 nWidth  = mnOutOffX + mnOutWidth - nX;
1285                 bClipped = sal_True;
1286             }
1287 
1288             // Hoehe ausserhalb des Bereichs?
1289             if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
1290             {
1291                 nHeight = mnOutOffY + mnOutHeight - nY;
1292                 bClipped = sal_True;
1293             }
1294 
1295             if ( bClipped )
1296             {
1297                 // Falls auf den sichtbaren Bereich geclipped wurde,
1298                 // muessen wir eine Bitmap in der rchtigen Groesse
1299                 // erzeugen, in die die geclippte Bitmap an die angepasste
1300                 // Position kopiert wird
1301                 VirtualDevice aVDev( *this );
1302 
1303                 if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) )
1304                 {
1305                     if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() )
1306                     {
1307                         TwoRect aPosAry;
1308 
1309                         aPosAry.mnSrcX = nX;
1310                         aPosAry.mnSrcY = nY;
1311                         aPosAry.mnSrcWidth = nWidth;
1312                         aPosAry.mnSrcHeight = nHeight;
1313                         aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L;
1314                         aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L;
1315                         aPosAry.mnDestWidth = nWidth;
1316                         aPosAry.mnDestHeight = nHeight;
1317 
1318                         if ( (nWidth > 0) && (nHeight > 0) )
1319                             (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( &aPosAry, mpGraphics, this, this );
1320 
1321                         aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
1322                      }
1323                      else
1324                         bClipped = sal_False;
1325                 }
1326                 else
1327                     bClipped = sal_False;
1328             }
1329 
1330             if ( !bClipped )
1331             {
1332                 SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
1333 
1334                 if( pSalBmp )
1335                 {
1336                     ImpBitmap* pImpBmp = new ImpBitmap;
1337                     pImpBmp->ImplSetSalBitmap( pSalBmp );
1338                     aBmp.ImplSetImpBitmap( pImpBmp );
1339                 }
1340             }
1341         }
1342     }
1343 
1344     return aBmp;
1345 }
1346 
1347 // ------------------------------------------------------------------
1348 
1349 BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
1350 {
1351     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1352 
1353     // #110958# Extract alpha value from VDev, if any
1354     if( mpAlphaVDev )
1355     {
1356         Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
1357 
1358         // ensure 8 bit alpha
1359         if( aAlphaBitmap.GetBitCount() > 8 )
1360             aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
1361 
1362         return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
1363     }
1364     else
1365         return GetBitmap( rSrcPt, rSize );
1366 }
1367 
1368 // ------------------------------------------------------------------
1369 
1370 void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize,
1371                                        Bitmap& rBitmap ) const
1372 {
1373     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1374 
1375     sal_Bool bOldMap = mbMap;
1376     ((OutputDevice*)this)->mbMap = sal_False;
1377     rBitmap = GetBitmap( rDestPt, rSize );
1378     ((OutputDevice*)this)->mbMap = bOldMap;
1379 }
1380 
1381 // ------------------------------------------------------------------
1382 
1383 Color OutputDevice::GetPixel( const Point& rPt ) const
1384 {
1385     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1386 
1387     Color aColor;
1388 
1389     if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1390     {
1391         if ( mbInitClipRegion )
1392             ((OutputDevice*)this)->ImplInitClipRegion();
1393 
1394         if ( !mbOutputClipped )
1395         {
1396             const long      nX = ImplLogicXToDevicePixel( rPt.X() );
1397             const long      nY = ImplLogicYToDevicePixel( rPt.Y() );
1398             const SalColor  aSalCol = mpGraphics->GetPixel( nX, nY, this );
1399             aColor.SetRed( SALCOLOR_RED( aSalCol ) );
1400             aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1401             aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1402         }
1403     }
1404     return aColor;
1405 }
1406 
1407 // ------------------------------------------------------------------
1408 
1409 Color* OutputDevice::GetPixel( const Polygon& rPts ) const
1410 {
1411     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1412 
1413     Color*          pColors = NULL;
1414     const sal_uInt16    nSize = rPts.GetSize();
1415 
1416     if( nSize )
1417     {
1418         if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1419         {
1420             if ( mbInitClipRegion )
1421                 ((OutputDevice*)this)->ImplInitClipRegion();
1422 
1423             if ( !mbOutputClipped )
1424             {
1425                 pColors = new Color[ nSize ];
1426 
1427                 for( sal_uInt16 i = 0; i < nSize; i++ )
1428                 {
1429                     Color&          rCol = pColors[ i ];
1430                     const Point&    rPt = rPts[ i ];
1431                     const SalColor  aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ),
1432                                                                    ImplLogicYToDevicePixel( rPt.Y() ) , this) );
1433 
1434                     rCol.SetRed( SALCOLOR_RED( aSalCol ) );
1435                     rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1436                     rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1437                 }
1438             }
1439         }
1440     }
1441 
1442     return pColors;
1443 }
1444 
1445 // -----------------------------------------------------------------------
1446 
1447 void OutputDevice::DrawPixel( const Point& rPt )
1448 {
1449     DBG_TRACE( "OutputDevice::DrawPixel()" );
1450     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1451 
1452     if ( mpMetaFile )
1453         mpMetaFile->AddAction( new MetaPointAction( rPt ) );
1454 
1455     if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
1456         return;
1457 
1458     Point aPt = ImplLogicToDevicePixel( rPt );
1459 
1460     // we need a graphics
1461     if ( !mpGraphics )
1462     {
1463         if ( !ImplGetGraphics() )
1464             return;
1465     }
1466 
1467     if ( mbInitClipRegion )
1468         ImplInitClipRegion();
1469     if ( mbOutputClipped )
1470         return;
1471 
1472     if ( mbInitLineColor )
1473         ImplInitLineColor();
1474 
1475     mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );
1476 
1477     if( mpAlphaVDev )
1478         mpAlphaVDev->DrawPixel( rPt );
1479 }
1480 
1481 // -----------------------------------------------------------------------
1482 
1483 void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
1484 {
1485     DBG_TRACE( "OutputDevice::DrawPixel()" );
1486     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1487 
1488     Color aColor( rColor );
1489 
1490     if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
1491                        DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
1492                        DRAWMODE_SETTINGSLINE ) )
1493     {
1494         if( !ImplIsColorTransparent( aColor ) )
1495         {
1496             if( mnDrawMode & DRAWMODE_BLACKLINE )
1497             {
1498                 aColor = Color( COL_BLACK );
1499             }
1500             else if( mnDrawMode & DRAWMODE_WHITELINE )
1501             {
1502                 aColor = Color( COL_WHITE );
1503             }
1504             else if( mnDrawMode & DRAWMODE_GRAYLINE )
1505             {
1506                 const sal_uInt8 cLum = aColor.GetLuminance();
1507                 aColor = Color( cLum, cLum, cLum );
1508             }
1509             else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
1510             {
1511                 aColor = GetSettings().GetStyleSettings().GetFontColor();
1512             }
1513 
1514             if( mnDrawMode & DRAWMODE_GHOSTEDLINE )
1515             {
1516                 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
1517                                 ( aColor.GetGreen() >> 1 ) | 0x80,
1518                                 ( aColor.GetBlue() >> 1 ) | 0x80 );
1519             }
1520         }
1521     }
1522 
1523     if ( mpMetaFile )
1524         mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );
1525 
1526     if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
1527         return;
1528 
1529     Point aPt = ImplLogicToDevicePixel( rPt );
1530 
1531     // we need a graphics
1532     if ( !mpGraphics )
1533     {
1534         if ( !ImplGetGraphics() )
1535             return;
1536     }
1537 
1538     if ( mbInitClipRegion )
1539         ImplInitClipRegion();
1540     if ( mbOutputClipped )
1541         return;
1542 
1543     mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );
1544 
1545     if( mpAlphaVDev )
1546         mpAlphaVDev->DrawPixel( rPt );
1547 }
1548 
1549 // -----------------------------------------------------------------------
1550 
1551 void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
1552 {
1553     if ( !pColors )
1554         DrawPixel( rPts, GetLineColor() );
1555     else
1556     {
1557         DBG_TRACE( "OutputDevice::DrawPixel()" );
1558         DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1559         DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );
1560 
1561         const sal_uInt16 nSize = rPts.GetSize();
1562 
1563         if ( nSize )
1564         {
1565             if ( mpMetaFile )
1566                 for ( sal_uInt16 i = 0; i < nSize; i++ )
1567                     mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );
1568 
1569             if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1570                 return;
1571 
1572             // we need a graphics
1573             if ( mpGraphics || ImplGetGraphics() )
1574             {
1575                 if ( mbInitClipRegion )
1576                     ImplInitClipRegion();
1577 
1578                 if ( mbOutputClipped )
1579                     return;
1580 
1581                 for ( sal_uInt16 i = 0; i < nSize; i++ )
1582                 {
1583                     const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
1584                     mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
1585                 }
1586             }
1587         }
1588     }
1589 
1590     if( mpAlphaVDev )
1591         mpAlphaVDev->DrawPixel( rPts, pColors );
1592 }
1593 
1594 // -----------------------------------------------------------------------
1595 
1596 void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
1597 {
1598     if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
1599     {
1600         const sal_uInt16    nSize = rPts.GetSize();
1601         Color*          pColArray = new Color[ nSize ];
1602 
1603         for( sal_uInt16 i = 0; i < nSize; i++ )
1604             pColArray[ i ] = rColor;
1605 
1606         DrawPixel( rPts, pColArray );
1607         delete[] pColArray;
1608     }
1609 
1610     if( mpAlphaVDev )
1611         mpAlphaVDev->DrawPixel( rPts, rColor );
1612 }
1613 
1614 // ------------------------------------------------------------------------
1615 
1616 namespace
1617 {
1618     sal_uInt8 lcl_calcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceOpaq, const sal_uInt8 nDestColor )
1619     {
1620         int c = ( (int)nDestColor * ( 255 - nSourceOpaq ) )
1621             +     (int)nSourceOpaq * (int)nSourceColor;
1622         return sal_uInt8( c / 255 );
1623     }
1624 }
1625 
1626 // ------------------------------------------------------------------------
1627 
1628 Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap              aBmp,
1629                                          BitmapReadAccess*   pP,
1630                                          BitmapReadAccess*   pA,
1631                                          const Rectangle&    aDstRect,
1632                                          const sal_Int32     nOffY,
1633                                          const sal_Int32     nDstHeight,
1634                                          const sal_Int32     nOffX,
1635                                          const sal_Int32     nDstWidth,
1636                                          const long*         pMapX,
1637                                          const long*         pMapY )
1638 {
1639     BitmapColor aDstCol,aSrcCol;
1640     Bitmap      res;
1641     int         nX, nOutX, nY, nOutY;
1642 
1643     OSL_ENSURE(mpAlphaVDev,
1644                "ImplBlendWithAlpha(): call me only with valid alpha VDev!" );
1645 
1646     sal_Bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
1647     mpAlphaVDev->EnableMapMode(sal_False);
1648 
1649     Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1650     BitmapWriteAccess*  pAlphaW = aAlphaBitmap.AcquireWriteAccess();
1651 
1652     if( GetBitCount() <= 8 )
1653     {
1654         Bitmap              aDither( aBmp.GetSizePixel(), 8 );
1655         BitmapColor         aIndex( 0 );
1656         BitmapReadAccess*   pB = aBmp.AcquireReadAccess();
1657         BitmapWriteAccess*  pW = aDither.AcquireWriteAccess();
1658 
1659         if( pB && pP && pA && pW && pAlphaW )
1660         {
1661             for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1662             {
1663                 const long nMapY = pMapY[ nY ];
1664                 const long nModY = ( nOutY & 0x0FL ) << 4L;
1665 
1666                 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1667                 {
1668                     const long  nMapX = pMapX[ nX ];
1669                     const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1670 
1671                     aSrcCol = pP->GetColor( nMapY, nMapX );
1672                     aDstCol = pB->GetColor( nY, nX );
1673                     const sal_uInt8 nSrcOpaq = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
1674                     const sal_uInt8 nDstOpaq  = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
1675 
1676                     aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
1677                     aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
1678                     aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
1679 
1680                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1681                                               nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1682                                               nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1683                     pW->SetPixel( nY, nX, aIndex );
1684 
1685                     // Have to perform the compositing 'algebra' in
1686                     // the inverse alpha space (with 255 meaning
1687                     // opaque), otherwise, transitivity is not
1688                     // achieved.
1689                     const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq );
1690 
1691                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1692                                               nVCLGLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1693                                               nVCLBLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] ) );
1694                     pAlphaW->SetPixel( nY, nX, aIndex );
1695                 }
1696             }
1697         }
1698 
1699         aBmp.ReleaseAccess( pB );
1700         aDither.ReleaseAccess( pW );
1701         res = aDither;
1702     }
1703     else
1704     {
1705         BitmapWriteAccess*  pB = aBmp.AcquireWriteAccess();
1706         if( pP && pA && pB )
1707         {
1708             for( nY = 0; nY < nDstHeight; nY++ )
1709             {
1710                 const long  nMapY = pMapY[ nY ];
1711 
1712                 for( nX = 0; nX < nDstWidth; nX++ )
1713                 {
1714                     const long nMapX = pMapX[ nX ];
1715 
1716                     aSrcCol = pP->GetColor( nMapY, nMapX );
1717                     aDstCol = pB->GetColor( nY, nX );
1718                     const sal_uInt8 nSrcOpaq  = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
1719                     const sal_uInt8 nDstOpaq  = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
1720 
1721                     aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
1722                     aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
1723                     aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
1724 
1725                     pB->SetPixel( nY, nX, aDstCol );
1726 
1727                     // Have to perform the compositing 'algebra' in
1728                     // the inverse alpha space (with 255 meaning
1729                     // opaque), otherwise, transitivity is not
1730                     // achieved.
1731                     const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq );
1732 
1733                     pAlphaW->SetPixel( nY, nX, Color(nSrcAlpha, nSrcAlpha, nSrcAlpha) );
1734                 }
1735             }
1736         }
1737 
1738         aBmp.ReleaseAccess( pB );
1739         res = aBmp;
1740     }
1741 
1742     aAlphaBitmap.ReleaseAccess( pAlphaW );
1743     mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
1744     mpAlphaVDev->EnableMapMode( bOldMapMode );
1745 
1746     return res;
1747 }
1748 
1749 // ------------------------------------------------------------------------
1750 
1751 Bitmap OutputDevice::ImplBlend( Bitmap              aBmp,
1752                                 BitmapReadAccess*   pP,
1753                                 BitmapReadAccess*   pA,
1754                                 const sal_Int32     nOffY,
1755                                 const sal_Int32     nDstHeight,
1756                                 const sal_Int32     nOffX,
1757                                 const sal_Int32     nDstWidth,
1758                                 const Rectangle&    aBmpRect,
1759                                 const Size&         aOutSz,
1760                                 const bool          bHMirr,
1761                                 const bool          bVMirr,
1762                                 const long*         pMapX,
1763                                 const long*         pMapY )
1764 {
1765     BitmapColor aDstCol;
1766     Bitmap      res;
1767     int         nX, nOutX, nY, nOutY;
1768 
1769     if( GetBitCount() <= 8 )
1770     {
1771         Bitmap              aDither( aBmp.GetSizePixel(), 8 );
1772         BitmapColor         aIndex( 0 );
1773         BitmapReadAccess*   pB = aBmp.AcquireReadAccess();
1774         BitmapWriteAccess*  pW = aDither.AcquireWriteAccess();
1775 
1776         if( pB && pP && pA && pW )
1777         {
1778             for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1779             {
1780                 const long nMapY = pMapY[ nY ];
1781                 const long nModY = ( nOutY & 0x0FL ) << 4L;
1782 
1783                 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1784                 {
1785                     const long  nMapX = pMapX[ nX ];
1786                     const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1787 
1788                     aDstCol = pB->GetColor( nY, nX );
1789                     aDstCol.Merge( pP->GetColor( nMapY, nMapX ), (sal_uInt8) pA->GetPixel( nMapY, nMapX ) );
1790                     aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1791                                               nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1792                                               nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1793                     pW->SetPixel( nY, nX, aIndex );
1794                 }
1795             }
1796         }
1797 
1798         aBmp.ReleaseAccess( pB );
1799         aDither.ReleaseAccess( pW );
1800         res = aDither;
1801     }
1802     else
1803     {
1804         BitmapWriteAccess*  pB = aBmp.AcquireWriteAccess();
1805 
1806         bool bFastBlend = false;
1807         if( pP && pA && pB )
1808         {
1809             SalTwoRect aTR;
1810             aTR.mnSrcX      = aBmpRect.Left();
1811             aTR.mnSrcY      = aBmpRect.Top();
1812             aTR.mnSrcWidth  = aBmpRect.GetWidth();
1813             aTR.mnSrcHeight = aBmpRect.GetHeight();
1814             aTR.mnDestX     = nOffX;
1815             aTR.mnDestY     = nOffY;
1816             aTR.mnDestWidth = aOutSz.Width();
1817             aTR.mnDestHeight= aOutSz.Height();
1818 
1819             if( !bHMirr || !bVMirr )
1820                 bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
1821         }
1822 
1823         if( pP && pA && pB && !bFastBlend )
1824         {
1825             switch( pP->GetScanlineFormat() )
1826             {
1827                 case( BMP_FORMAT_8BIT_PAL ):
1828                     {
1829                         for( nY = 0; nY < nDstHeight; nY++ )
1830                         {
1831                             const long  nMapY = pMapY[ nY ];
1832                             Scanline    pPScan = pP->GetScanline( nMapY );
1833                             Scanline    pAScan = pA->GetScanline( nMapY );
1834 
1835                             for( nX = 0; nX < nDstWidth; nX++ )
1836                             {
1837                                 const long nMapX = pMapX[ nX ];
1838                                 aDstCol = pB->GetPixel( nY, nX );
1839                                 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ),
1840                                                                      pAScan[ nMapX ] ) );
1841                             }
1842                         }
1843                     }
1844                     break;
1845 
1846                 case( BMP_FORMAT_24BIT_TC_BGR ):
1847                     {
1848                         for( nY = 0; nY < nDstHeight; nY++ )
1849                         {
1850                             const long  nMapY = pMapY[ nY ];
1851                             Scanline    pPScan = pP->GetScanline( nMapY );
1852                             Scanline    pAScan = pA->GetScanline( nMapY );
1853 
1854                             for( nX = 0; nX < nDstWidth; nX++ )
1855                             {
1856                                 const long  nMapX = pMapX[ nX ];
1857                                 Scanline    pTmp = pPScan + nMapX * 3;
1858 
1859                                 aDstCol = pB->GetPixel( nY, nX );
1860                                 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
1861                                                                      pAScan[ nMapX ] ) );
1862                             }
1863                         }
1864                     }
1865                     break;
1866 
1867                 case( BMP_FORMAT_24BIT_TC_RGB ):
1868                     {
1869                         for( nY = 0; nY < nDstHeight; nY++ )
1870                         {
1871                             const long  nMapY = pMapY[ nY ];
1872                             Scanline    pPScan = pP->GetScanline( nMapY );
1873                             Scanline    pAScan = pA->GetScanline( nMapY );
1874 
1875                             for( nX = 0; nX < nDstWidth; nX++ )
1876                             {
1877                                 const long  nMapX = pMapX[ nX ];
1878                                 Scanline    pTmp = pPScan + nMapX * 3;
1879 
1880                                 aDstCol = pB->GetPixel( nY, nX );
1881                                 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
1882                                                                      pAScan[ nMapX ] ) );
1883                             }
1884                         }
1885                     }
1886                     break;
1887 
1888                 default:
1889                 {
1890                     for( nY = 0; nY < nDstHeight; nY++ )
1891                     {
1892                         const long  nMapY = pMapY[ nY ];
1893                         Scanline    pAScan = pA->GetScanline( nMapY );
1894 
1895                         for( nX = 0; nX < nDstWidth; nX++ )
1896                         {
1897                             const long nMapX = pMapX[ nX ];
1898                             aDstCol = pB->GetPixel( nY, nX );
1899                             pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ),
1900                                                                  pAScan[ nMapX ] ) );
1901                         }
1902                     }
1903                 }
1904                 break;
1905             }
1906         }
1907 
1908         aBmp.ReleaseAccess( pB );
1909         res = aBmp;
1910     }
1911 
1912     return res;
1913 }
1914 
1915 // ------------------------------------------------------------------------
1916 
1917 void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha,
1918                                   const Point& rDestPt, const Size& rDestSize,
1919                                   const Point& rSrcPtPixel, const Size& rSrcSizePixel )
1920 {
1921     const Point aNullPt;
1922     Point       aOutPt( LogicToPixel( rDestPt ) );
1923     Size        aOutSz( LogicToPixel( rDestSize ) );
1924     Rectangle   aDstRect( aNullPt, GetOutputSizePixel() );
1925     const sal_Bool  bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0;
1926 
1927     if( OUTDEV_WINDOW == meOutDevType )
1928     {
1929         const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
1930 
1931         if( !aPaintRgn.IsNull() )
1932             aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) );
1933     }
1934 
1935     if( bHMirr )
1936     {
1937         aOutSz.Width() = -aOutSz.Width();
1938         aOutPt.X() -= ( aOutSz.Width() - 1L );
1939     }
1940 
1941     if( bVMirr )
1942     {
1943         aOutSz.Height() = -aOutSz.Height();
1944         aOutPt.Y() -= ( aOutSz.Height() - 1L );
1945     }
1946 
1947     if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
1948     {
1949         bool bNativeAlpha = false;
1950         static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
1951         // #i83087# Naturally, system alpha blending cannot work with
1952         // separate alpha VDev
1953         if( !mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr )
1954         {
1955             Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
1956             SalTwoRect aTR = {
1957                 rSrcPtPixel.X(), rSrcPtPixel.Y(),
1958                 rSrcSizePixel.Width(), rSrcSizePixel.Height(),
1959                 aRelPt.X(), aRelPt.Y(),
1960                 aOutSz.Width(), aOutSz.Height()
1961             };
1962             SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
1963             SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
1964             bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this );
1965         }
1966 
1967         VirtualDevice* pOldVDev = mpAlphaVDev;
1968 
1969         Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() );
1970         if( !bNativeAlpha
1971                 &&  !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() )
1972         {
1973             GDIMetaFile*    pOldMetaFile = mpMetaFile; mpMetaFile = NULL;
1974             const sal_Bool      bOldMap = mbMap; mbMap = sal_False;
1975             Bitmap          aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1976 
1977             // #109044# The generated bitmap need not necessarily be
1978             // of aDstRect dimensions, it's internally clipped to
1979             // window bounds. Thus, we correct the dest size here,
1980             // since we later use it (in nDstWidth/Height) for pixel
1981             // access)
1982             // #i38887# reading from screen may sometimes fail
1983             if( aBmp.ImplGetImpBitmap() )
1984                 aDstRect.SetSize( aBmp.GetSizePixel() );
1985 
1986             BitmapColor     aDstCol;
1987             const long      nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
1988             const long      nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
1989             const long      nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
1990             // calculate offset in original bitmap
1991             // in RTL case this is a little more complicated since the contents of the
1992             // bitmap is not mirrored (it never is), however the paint region and bmp region
1993             // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
1994             // is content wise somewhere else and needs to take mirroring into account
1995             const long      nOffX = IsRTLEnabled()
1996                                     ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X())
1997                                     : aDstRect.Left() - aOutPt.X(),
1998                             nOffY = aDstRect.Top() - aOutPt.Y();
1999             long            nX, nOutX, nY, nOutY;
2000             long            nMirrOffX = 0;
2001             long            nMirrOffY = 0;
2002             long*           pMapX = new long[ nDstWidth ];
2003             long*           pMapY = new long[ nDstHeight ];
2004 
2005             // create horizontal mapping table
2006             if( bHMirr )
2007                 nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
2008 
2009             for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
2010             {
2011                 pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
2012                 if( bHMirr )
2013                     pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
2014             }
2015 
2016             // create vertical mapping table
2017             if( bVMirr )
2018                 nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
2019 
2020             for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
2021             {
2022                 pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
2023 
2024                 if( bVMirr )
2025                     pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
2026             }
2027 
2028             BitmapReadAccess*   pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
2029             BitmapReadAccess*   pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
2030 
2031             DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
2032                         pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
2033                         "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
2034 
2035             // #i38887# reading from screen may sometimes fail
2036             if( aBmp.ImplGetImpBitmap() )
2037             {
2038                 Bitmap aTmp;
2039 
2040                 if( mpAlphaVDev )
2041                 {
2042                     aTmp = ImplBlendWithAlpha(
2043                         aBmp,pP,pA,
2044                         aDstRect,
2045                         nOffY,nDstHeight,
2046                         nOffX,nDstWidth,
2047                         pMapX,pMapY );
2048                 }
2049                 else
2050                 {
2051                     aTmp = ImplBlend(
2052                         aBmp,pP,pA,
2053                         nOffY,nDstHeight,
2054                         nOffX,nDstWidth,
2055                         aBmpRect,aOutSz,
2056                         bHMirr,bVMirr,
2057                         pMapX,pMapY );
2058                 }
2059 
2060                 // #110958# Disable alpha VDev, we're doing the necessary
2061                 // stuff explicitely furher below
2062                 if( mpAlphaVDev )
2063                     mpAlphaVDev = NULL;
2064 
2065                 DrawBitmap( aDstRect.TopLeft(),
2066                             aTmp );
2067 
2068                 // #110958# Enable alpha VDev again
2069                 mpAlphaVDev = pOldVDev;
2070             }
2071 
2072             ( (Bitmap&) rBmp ).ReleaseAccess( pP );
2073             ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
2074 
2075             delete[] pMapX;
2076             delete[] pMapY;
2077             mbMap = bOldMap;
2078             mpMetaFile = pOldMetaFile;
2079         }
2080     }
2081 }
2082 
2083 // ------------------------------------------------------------------------
2084 
2085 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
2086                                          const Point& rDestPt, const Size& rDestSize,
2087                                          const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2088 {
2089     Point       aPt;
2090     Point       aDestPt( LogicToPixel( rDestPt ) );
2091     Size        aDestSz( LogicToPixel( rDestSize ) );
2092     Rectangle   aSrcRect( rSrcPtPixel, rSrcSizePixel );
2093 
2094     aSrcRect.Justify();
2095 
2096     if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2097     {
2098         Bitmap  aPaint( rBmp ), aMask( rMask );
2099         sal_uLong   nMirrFlags = 0UL;
2100 
2101         if( aMask.GetBitCount() > 1 )
2102             aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2103 
2104         // mirrored horizontically
2105         if( aDestSz.Width() < 0L )
2106         {
2107             aDestSz.Width() = -aDestSz.Width();
2108             aDestPt.X() -= ( aDestSz.Width() - 1L );
2109             nMirrFlags |= BMP_MIRROR_HORZ;
2110         }
2111 
2112         // mirrored vertically
2113         if( aDestSz.Height() < 0L )
2114         {
2115             aDestSz.Height() = -aDestSz.Height();
2116             aDestPt.Y() -= ( aDestSz.Height() - 1L );
2117             nMirrFlags |= BMP_MIRROR_VERT;
2118         }
2119 
2120         // source cropped?
2121         if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) )
2122         {
2123             aPaint.Crop( aSrcRect );
2124             aMask.Crop( aSrcRect );
2125         }
2126 
2127         // destination mirrored
2128         if( nMirrFlags )
2129         {
2130             aPaint.Mirror( nMirrFlags );
2131             aMask.Mirror( nMirrFlags );
2132         }
2133 
2134         // we always want to have a mask
2135         if( aMask.IsEmpty() )
2136         {
2137             aMask = Bitmap( aSrcRect.GetSize(), 1 );
2138             aMask.Erase( Color( COL_BLACK ) );
2139         }
2140 
2141         // do painting
2142         const long      nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2143         long            nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2144         long*           pMapX = new long[ nSrcWidth + 1 ];
2145         long*           pMapY = new long[ nSrcHeight + 1 ];
2146         const sal_Bool      bOldMap = mbMap;
2147 
2148         mbMap = sal_False;
2149 
2150         // create forward mapping tables
2151         for( nX = 0L; nX <= nSrcWidth; nX++ )
2152             pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2153 
2154         for( nY = 0L; nY <= nSrcHeight; nY++ )
2155             pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2156 
2157         // walk through all rectangles of mask
2158         Region          aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2159         ImplRegionInfo  aInfo;
2160         sal_Bool            bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2161 
2162         while( bRgnRect )
2163         {
2164             Bitmap          aBandBmp( aPaint );
2165             const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) );
2166             const Point     aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2167             const Size      aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2168 
2169             aBandBmp.Crop( aBandRect );
2170             ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION );
2171             bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2172         }
2173 
2174         mbMap = bOldMap;
2175 
2176         delete[] pMapX;
2177         delete[] pMapY;
2178     }
2179 }
2180 
2181 // ------------------------------------------------------------------------
2182 
2183 void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor,
2184                                   const Point& rDestPt, const Size& rDestSize,
2185                                   const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2186 {
2187     Point       aPt;
2188     Point       aDestPt( LogicToPixel( rDestPt ) );
2189     Size        aDestSz( LogicToPixel( rDestSize ) );
2190     Rectangle   aSrcRect( rSrcPtPixel, rSrcSizePixel );
2191 
2192     aSrcRect.Justify();
2193 
2194     if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2195     {
2196         Bitmap  aMask( rMask );
2197         sal_uLong   nMirrFlags = 0UL;
2198 
2199         if( aMask.GetBitCount() > 1 )
2200             aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2201 
2202         // mirrored horizontically
2203         if( aDestSz.Width() < 0L )
2204         {
2205             aDestSz.Width() = -aDestSz.Width();
2206             aDestPt.X() -= ( aDestSz.Width() - 1L );
2207             nMirrFlags |= BMP_MIRROR_HORZ;
2208         }
2209 
2210         // mirrored vertically
2211         if( aDestSz.Height() < 0L )
2212         {
2213             aDestSz.Height() = -aDestSz.Height();
2214             aDestPt.Y() -= ( aDestSz.Height() - 1L );
2215             nMirrFlags |= BMP_MIRROR_VERT;
2216         }
2217 
2218         // source cropped?
2219         if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) )
2220             aMask.Crop( aSrcRect );
2221 
2222         // destination mirrored
2223         if( nMirrFlags )
2224             aMask.Mirror( nMirrFlags );
2225 
2226         // do painting
2227         const long      nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2228         long            nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2229         long*           pMapX = new long[ nSrcWidth + 1 ];
2230         long*           pMapY = new long[ nSrcHeight + 1 ];
2231         GDIMetaFile*    pOldMetaFile = mpMetaFile;
2232         const sal_Bool      bOldMap = mbMap;
2233 
2234         mpMetaFile = NULL;
2235         mbMap = sal_False;
2236         Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
2237         SetLineColor( rMaskColor );
2238         SetFillColor( rMaskColor );
2239         ImplInitLineColor();
2240         ImplInitFillColor();
2241 
2242         // create forward mapping tables
2243         for( nX = 0L; nX <= nSrcWidth; nX++ )
2244             pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2245 
2246         for( nY = 0L; nY <= nSrcHeight; nY++ )
2247             pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2248 
2249         // walk through all rectangles of mask
2250         Region          aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2251         ImplRegionInfo  aInfo;
2252         sal_Bool            bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2253 
2254         while( bRgnRect )
2255         {
2256             const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2257             const Size  aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2258 
2259             DrawRect( Rectangle( aMapPt, aMapSz ) );
2260             bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2261         }
2262 
2263         Pop();
2264         delete[] pMapX;
2265         delete[] pMapY;
2266         mbMap = bOldMap;
2267         mpMetaFile = pOldMetaFile;
2268     }
2269 }
2270