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