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