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