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