xref: /trunk/main/vcl/win/source/gdi/salgdi2.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <string.h>
32 #include <stdlib.h>
33 
34 #include <tools/svwin.h>
35 #include <tools/debug.hxx>
36 
37 #include <win/wincomp.hxx>
38 #include <win/salbmp.h>
39 #include <win/saldata.hxx>
40 #include <win/salids.hrc>
41 #include <win/salgdi.h>
42 #include <win/salframe.h>
43 
44 bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const
45 {
46     static bool bAllowForTest(true);
47     bool bRet = false;
48 
49     switch( eType )
50     {
51     case OutDevSupport_TransparentRect:
52         bRet = mbVirDev || mbWindow;
53         break;
54     case OutDevSupport_B2DClip:
55         bRet = true;
56         break;
57     case OutDevSupport_B2DDraw:
58         bRet = bAllowForTest;
59     default: break;
60     }
61     return bRet;
62 }
63 
64 // =======================================================================
65 
66 void WinSalGraphics::copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics )
67 {
68     HDC     hSrcDC;
69     DWORD   nRop;
70 
71     if ( pSrcGraphics )
72         hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->mhDC;
73     else
74         hSrcDC = mhDC;
75 
76     if ( mbXORMode )
77         nRop = SRCINVERT;
78     else
79         nRop = SRCCOPY;
80 
81     if ( (pPosAry->mnSrcWidth  == pPosAry->mnDestWidth) &&
82          (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
83     {
84         BitBlt( mhDC,
85                 (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
86                 (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
87                 hSrcDC,
88                 (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
89                 nRop );
90     }
91     else
92     {
93         int nOldStretchMode = SetStretchBltMode( mhDC, STRETCH_DELETESCANS );
94         StretchBlt( mhDC,
95                     (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
96                     (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
97                     hSrcDC,
98                     (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
99                     (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
100                     nRop );
101         SetStretchBltMode( mhDC, nOldStretchMode );
102     }
103 }
104 
105 // -----------------------------------------------------------------------
106 
107 void ImplCalcOutSideRgn( const RECT& rSrcRect,
108                          int nLeft, int nTop, int nRight, int nBottom,
109                          HRGN& rhInvalidateRgn )
110 {
111     HRGN hTempRgn;
112 
113     // Bereiche ausserhalb des sichtbaren Bereiches berechnen
114     if ( rSrcRect.left < nLeft )
115     {
116         if ( !rhInvalidateRgn )
117             rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
118         hTempRgn = CreateRectRgn( -31999, 0, nLeft, 31999 );
119         CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
120         DeleteRegion( hTempRgn );
121     }
122     if ( rSrcRect.top < nTop )
123     {
124         if ( !rhInvalidateRgn )
125             rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
126         hTempRgn = CreateRectRgn( 0, -31999, 31999, nTop );
127         CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
128         DeleteRegion( hTempRgn );
129     }
130     if ( rSrcRect.right > nRight )
131     {
132         if ( !rhInvalidateRgn )
133             rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
134         hTempRgn = CreateRectRgn( nRight, 0, 31999, 31999 );
135         CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
136         DeleteRegion( hTempRgn );
137     }
138     if ( rSrcRect.bottom > nBottom )
139     {
140         if ( !rhInvalidateRgn )
141             rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
142         hTempRgn = CreateRectRgn( 0, nBottom, 31999, 31999 );
143         CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
144         DeleteRegion( hTempRgn );
145     }
146 }
147 
148 // -----------------------------------------------------------------------
149 
150 void WinSalGraphics::copyArea( long nDestX, long nDestY,
151                             long nSrcX, long nSrcY,
152                             long nSrcWidth, long nSrcHeight,
153                             sal_uInt16 nFlags )
154 {
155     bool    bRestoreClipRgn = false;
156     HRGN    hOldClipRgn = 0;
157     int     nOldClipRgnType = ERROR;
158     HRGN    hInvalidateRgn = 0;
159 
160     // Muessen die ueberlappenden Bereiche auch invalidiert werden?
161     if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mbWindow )
162     {
163         // compute and invalidate those parts that were either off-screen or covered by other windows
164         //  while performing the above BitBlt
165         // those regions then have to be invalidated as they contain useless/wrong data
166         RECT    aSrcRect;
167         RECT    aClipRect;
168         RECT    aTempRect;
169         RECT    aTempRect2;
170         HRGN    hTempRgn;
171         HWND    hWnd;
172         int     nRgnType;
173 
174         // restrict srcRect to this window (calc intersection)
175         aSrcRect.left   = (int)nSrcX;
176         aSrcRect.top    = (int)nSrcY;
177         aSrcRect.right  = aSrcRect.left+(int)nSrcWidth;
178         aSrcRect.bottom = aSrcRect.top+(int)nSrcHeight;
179         GetClientRect( mhWnd, &aClipRect );
180         if ( IntersectRect( &aSrcRect, &aSrcRect, &aClipRect ) )
181         {
182             // transform srcRect to screen coordinates
183             POINT aPt;
184             aPt.x = 0;
185             aPt.y = 0;
186             ClientToScreen( mhWnd, &aPt );
187             aSrcRect.left   += aPt.x;
188             aSrcRect.top    += aPt.y;
189             aSrcRect.right  += aPt.x;
190             aSrcRect.bottom += aPt.y;
191             hInvalidateRgn = 0;
192 
193             // compute the parts that are off screen (ie invisible)
194             RECT theScreen;
195             ImplSalGetWorkArea( NULL, &theScreen, NULL );  // find the screen area taking multiple monitors into account
196             ImplCalcOutSideRgn( aSrcRect, theScreen.left, theScreen.top, theScreen.right, theScreen.bottom, hInvalidateRgn );
197 
198             // Bereiche die von anderen Fenstern ueberlagert werden berechnen
199             HRGN hTempRgn2 = 0;
200             HWND hWndTopWindow = mhWnd;
201             // Find the TopLevel Window, because only Windows which are in
202             // in the foreground of our TopLevel window must be considered
203             if ( GetWindowStyle( hWndTopWindow ) & WS_CHILD )
204             {
205                 RECT aTempRect3 = aSrcRect;
206                 do
207                 {
208                     hWndTopWindow = ::GetParent( hWndTopWindow );
209 
210                     // Test, if the Parent clips our window
211                     GetClientRect( hWndTopWindow, &aTempRect );
212                     POINT aPt2;
213                     aPt2.x = 0;
214                     aPt2.y = 0;
215                     ClientToScreen( hWndTopWindow, &aPt2 );
216                     aTempRect.left   += aPt2.x;
217                     aTempRect.top    += aPt2.y;
218                     aTempRect.right  += aPt2.x;
219                     aTempRect.bottom += aPt2.y;
220                     IntersectRect( &aTempRect3, &aTempRect3, &aTempRect );
221                 }
222                 while ( GetWindowStyle( hWndTopWindow ) & WS_CHILD );
223 
224                 // If one or more Parents clip our window, than we must
225                 // calculate the outside area
226                 if ( !EqualRect( &aSrcRect, &aTempRect3 ) )
227                 {
228                     ImplCalcOutSideRgn( aSrcRect,
229                                         aTempRect3.left, aTempRect3.top,
230                                         aTempRect3.right, aTempRect3.bottom,
231                                         hInvalidateRgn );
232                 }
233             }
234             // retrieve the top-most (z-order) child window
235             hWnd = GetWindow( GetDesktopWindow(), GW_CHILD );
236             while ( hWnd )
237             {
238                 if ( hWnd == hWndTopWindow )
239                     break;
240                 if ( IsWindowVisible( hWnd ) && !IsIconic( hWnd ) )
241                 {
242                     GetWindowRect( hWnd, &aTempRect );
243                     if ( IntersectRect( &aTempRect2, &aSrcRect, &aTempRect ) )
244                     {
245                         // hWnd covers part or all of aSrcRect
246                         if ( !hInvalidateRgn )
247                             hInvalidateRgn = CreateRectRgnIndirect( &aSrcRect );
248 
249                         // get full bounding box of hWnd
250                         hTempRgn = CreateRectRgnIndirect( &aTempRect );
251 
252                         // get region of hWnd (the window may be shaped)
253                         if ( !hTempRgn2 )
254                             hTempRgn2 = CreateRectRgn( 0, 0, 0, 0 );
255                         nRgnType = GetWindowRgn( hWnd, hTempRgn2 );
256                         if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) )
257                         {
258                             // convert window region to screen coordinates
259                             OffsetRgn( hTempRgn2, aTempRect.left, aTempRect.top );
260                             // and intersect with the window's bounding box
261                             CombineRgn( hTempRgn, hTempRgn, hTempRgn2, RGN_AND );
262                         }
263                         // finally compute that part of aSrcRect which is not covered by any parts of hWnd
264                         CombineRgn( hInvalidateRgn, hInvalidateRgn, hTempRgn, RGN_DIFF );
265                         DeleteRegion( hTempRgn );
266                     }
267                 }
268                 // retrieve the next window in the z-order, i.e. the window below hwnd
269                 hWnd = GetWindow( hWnd, GW_HWNDNEXT );
270             }
271             if ( hTempRgn2 )
272                 DeleteRegion( hTempRgn2 );
273             if ( hInvalidateRgn )
274             {
275                 // hInvalidateRgn contains the fully visible parts of the original srcRect
276                 hTempRgn = CreateRectRgnIndirect( &aSrcRect );
277                 // substract it from the original rect to get the occluded parts
278                 nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_DIFF );
279                 DeleteRegion( hTempRgn );
280 
281                 if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) )
282                 {
283                     // move the occluded parts to the destination pos
284                     int nOffX = (int)(nDestX-nSrcX);
285                     int nOffY = (int)(nDestY-nSrcY);
286                     OffsetRgn( hInvalidateRgn, nOffX-aPt.x, nOffY-aPt.y );
287 
288                     // by excluding hInvalidateRgn from the system's clip region
289                     // we will prevent bitblt from copying useless data
290                     // epsecially now shadows from overlapping windows will appear (#i36344)
291                     hOldClipRgn = CreateRectRgn( 0, 0, 0, 0 );
292                     nOldClipRgnType = GetClipRgn( mhDC, hOldClipRgn );
293 
294                     bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate
295                     ExtSelectClipRgn( mhDC, hInvalidateRgn, RGN_DIFF );
296                 }
297             }
298         }
299     }
300 
301     BitBlt( mhDC,
302             (int)nDestX, (int)nDestY,
303             (int)nSrcWidth, (int)nSrcHeight,
304             mhDC,
305             (int)nSrcX, (int)nSrcY,
306             SRCCOPY );
307 
308     if( bRestoreClipRgn )
309     {
310         // restore old clip region
311         if( nOldClipRgnType != ERROR )
312             SelectClipRgn( mhDC, hOldClipRgn);
313         DeleteRegion( hOldClipRgn );
314 
315         // invalidate regions that were not copied
316         bool    bInvalidate = true;
317 
318         // Combine Invalidate Region with existing ClipRegion
319         HRGN    hTempRgn = CreateRectRgn( 0, 0, 0, 0 );
320         if ( GetClipRgn( mhDC, hTempRgn ) == 1 )
321         {
322             int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_AND );
323             if ( (nRgnType == ERROR) || (nRgnType == NULLREGION) )
324                 bInvalidate = false;
325         }
326         DeleteRegion( hTempRgn );
327 
328         if ( bInvalidate )
329         {
330             InvalidateRgn( mhWnd, hInvalidateRgn, TRUE );
331             // Hier loesen wir nur ein Update aus, wenn es der
332             // MainThread ist, damit es beim Bearbeiten der
333             // Paint-Message keinen Deadlock gibt, da der
334             // SolarMutex durch diesen Thread schon gelockt ist
335             SalData*    pSalData = GetSalData();
336             DWORD       nCurThreadId = GetCurrentThreadId();
337             if ( pSalData->mnAppThreadId == nCurThreadId )
338                 UpdateWindow( mhWnd );
339         }
340 
341         DeleteRegion( hInvalidateRgn );
342     }
343 
344 }
345 
346 // -----------------------------------------------------------------------
347 
348 void ImplDrawBitmap( HDC hDC,
349                      const SalTwoRect* pPosAry, const WinSalBitmap& rSalBitmap,
350                      sal_Bool bPrinter, int nDrawMode )
351 {
352     if( hDC )
353     {
354         HGLOBAL     hDrawDIB;
355         HBITMAP     hDrawDDB = rSalBitmap.ImplGethDDB();
356         WinSalBitmap*   pTmpSalBmp = NULL;
357         sal_Bool        bPrintDDB = ( bPrinter && hDrawDDB );
358 
359         if( bPrintDDB )
360         {
361             pTmpSalBmp = new WinSalBitmap;
362             pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() );
363             hDrawDIB = pTmpSalBmp->ImplGethDIB();
364         }
365         else
366             hDrawDIB = rSalBitmap.ImplGethDIB();
367 
368         if( hDrawDIB )
369         {
370             PBITMAPINFO         pBI = (PBITMAPINFO) GlobalLock( hDrawDIB );
371             PBITMAPINFOHEADER   pBIH = (PBITMAPINFOHEADER) pBI;
372             PBYTE               pBits = (PBYTE) pBI + *(DWORD*) pBI +
373                                         rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
374             const int           nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
375 
376             StretchDIBits( hDC,
377                            (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
378                            (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
379                            (int)pPosAry->mnSrcX, (int)(pBIH->biHeight - pPosAry->mnSrcHeight - pPosAry->mnSrcY),
380                            (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
381                            pBits, pBI, DIB_RGB_COLORS, nDrawMode );
382 
383             GlobalUnlock( hDrawDIB );
384             SetStretchBltMode( hDC, nOldStretchMode );
385         }
386         else if( hDrawDDB && !bPrintDDB )
387         {
388             HDC         hBmpDC = ImplGetCachedDC( CACHED_HDC_DRAW, hDrawDDB );
389             COLORREF    nOldBkColor = RGB(0xFF,0xFF,0xFF);
390             COLORREF    nOldTextColor = RGB(0,0,0);
391             sal_Bool        bMono = ( rSalBitmap.GetBitCount() == 1 );
392 
393             if( bMono )
394             {
395                 nOldBkColor = SetBkColor( hDC, RGB( 0xFF, 0xFF, 0xFF ) );
396                 nOldTextColor = ::SetTextColor( hDC, RGB( 0x00, 0x00, 0x00 ) );
397             }
398 
399             if ( (pPosAry->mnSrcWidth  == pPosAry->mnDestWidth) &&
400                  (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
401             {
402                 BitBlt( hDC,
403                         (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
404                         (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
405                         hBmpDC,
406                         (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
407                         nDrawMode );
408             }
409             else
410             {
411                 const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
412 
413                 StretchBlt( hDC,
414                             (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
415                             (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
416                             hBmpDC,
417                             (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
418                             (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
419                             nDrawMode );
420 
421                 SetStretchBltMode( hDC, nOldStretchMode );
422             }
423 
424             if( bMono )
425             {
426                 SetBkColor( hDC, nOldBkColor );
427                 ::SetTextColor( hDC, nOldTextColor );
428             }
429 
430             ImplReleaseCachedDC( CACHED_HDC_DRAW );
431         }
432 
433         if( bPrintDDB )
434             delete pTmpSalBmp;
435     }
436 }
437 
438 // -----------------------------------------------------------------------
439 
440 void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
441                               const SalBitmap& rSalBitmap )
442 {
443     ImplDrawBitmap( mhDC, pPosAry, static_cast<const WinSalBitmap&>(rSalBitmap),
444                     mbPrinter,
445                     mbXORMode ? SRCINVERT : SRCCOPY );
446 }
447 
448 // -----------------------------------------------------------------------
449 
450 void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
451                               const SalBitmap& rSSalBitmap,
452                               SalColor nTransparentColor )
453 {
454     DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
455 
456     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
457 
458     WinSalBitmap*   pMask = new WinSalBitmap;
459     const Point aPoint;
460     const Size  aSize( rSalBitmap.GetSize() );
461     HBITMAP     hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL );
462     HDC         hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap );
463     const BYTE  cRed = SALCOLOR_RED( nTransparentColor );
464     const BYTE  cGreen = SALCOLOR_GREEN( nTransparentColor );
465     const BYTE  cBlue = SALCOLOR_BLUE( nTransparentColor );
466 
467     if( rSalBitmap.ImplGethDDB() )
468     {
469         HDC         hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() );
470         COLORREF    aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
471 
472         BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
473 
474         SetBkColor( hSrcDC, aOldCol );
475         ImplReleaseCachedDC( CACHED_HDC_2 );
476     }
477     else
478     {
479         WinSalBitmap*   pTmpSalBmp = new WinSalBitmap;
480 
481         if( pTmpSalBmp->Create( rSalBitmap, this ) )
482         {
483             HDC         hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() );
484             COLORREF    aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
485 
486             BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
487 
488             SetBkColor( hSrcDC, aOldCol );
489             ImplReleaseCachedDC( CACHED_HDC_2 );
490         }
491 
492         delete pTmpSalBmp;
493     }
494 
495     ImplReleaseCachedDC( CACHED_HDC_1 );
496 
497     // hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE )
498     if( pMask->Create( hMaskBitmap, FALSE, FALSE ) )
499         drawBitmap( pPosAry, rSalBitmap, *pMask );
500 
501     delete pMask;
502 }
503 
504 // -----------------------------------------------------------------------
505 
506 void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
507                               const SalBitmap& rSSalBitmap,
508                               const SalBitmap& rSTransparentBitmap )
509 {
510     DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
511 
512     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
513     const WinSalBitmap& rTransparentBitmap = static_cast<const WinSalBitmap&>(rSTransparentBitmap);
514 
515     SalTwoRect  aPosAry = *pPosAry;
516     int         nDstX = (int)aPosAry.mnDestX;
517     int         nDstY = (int)aPosAry.mnDestY;
518     int         nDstWidth = (int)aPosAry.mnDestWidth;
519     int         nDstHeight = (int)aPosAry.mnDestHeight;
520     HDC         hDC = mhDC;
521     HBITMAP     hMemBitmap = 0;
522     HBITMAP     hMaskBitmap = 0;
523 
524     if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) )
525     {
526         hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
527         hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
528     }
529 
530     HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap );
531     HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap );
532 
533     aPosAry.mnDestX = aPosAry.mnDestY = 0;
534     BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY );
535 
536     // bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
537     // die Farben der Maske richtig auf die Palette abzubilden,
538     // wenn wir die DIB direkt ausgeben => DDB-Ausgabe
539     if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 )
540     {
541         WinSalBitmap aTmp;
542 
543         if( aTmp.Create( rTransparentBitmap, this ) )
544             ImplDrawBitmap( hMaskDC, &aPosAry, aTmp, FALSE, SRCCOPY );
545     }
546     else
547         ImplDrawBitmap( hMaskDC, &aPosAry, rTransparentBitmap, FALSE, SRCCOPY );
548 
549     // now MemDC contains background, MaskDC the transparency mask
550 
551     // #105055# Respect XOR mode
552     if( mbXORMode )
553     {
554         ImplDrawBitmap( hMaskDC, &aPosAry, rSalBitmap, FALSE, SRCERASE );
555         // now MaskDC contains the bitmap area with black background
556         BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT );
557         // now MemDC contains background XORed bitmap area ontop
558     }
559     else
560     {
561         BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND );
562         // now MemDC contains background with masked-out bitmap area
563         ImplDrawBitmap( hMaskDC, &aPosAry, rSalBitmap, FALSE, SRCERASE );
564         // now MaskDC contains the bitmap area with black background
565         BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT );
566         // now MemDC contains background and bitmap merged together
567     }
568     // copy to output DC
569     BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY );
570 
571     ImplReleaseCachedDC( CACHED_HDC_1 );
572     ImplReleaseCachedDC( CACHED_HDC_2 );
573 
574     // hMemBitmap != 0 ==> hMaskBitmap != 0
575     if( hMemBitmap )
576     {
577         DeleteObject( hMemBitmap );
578         DeleteObject( hMaskBitmap );
579     }
580 }
581 
582 // -----------------------------------------------------------------------
583 
584 bool WinSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
585                       const SalBitmap&  rSrcBitmap,
586                       const SalBitmap&  rAlphaBmp )
587 {
588     (void)rTR; (void)rSrcBitmap; (void)rAlphaBmp;
589 
590     // TODO(P3): implement alpha bmp blits. Catch: Windows only
591     // handles 32bpp, premultiplied bitmaps
592     return false;
593 }
594 
595 // -----------------------------------------------------------------------
596 
597 bool WinSalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
598                                     long nHeight, sal_uInt8 nTransparency )
599 {
600     if( mbPen || !mbBrush || mbXORMode )
601         return false; // can only perform solid fills without XOR.
602 
603     HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 );
604     SetPixel( hMemDC, (int)0, (int)0, mnBrushColor );
605 
606     BLENDFUNCTION aFunc = {
607         AC_SRC_OVER,
608         0,
609         255 - 255L*nTransparency/100,
610         0
611     };
612 
613     // hMemDC contains a 1x1 bitmap of the right color - stretch-blit
614     // that to dest hdc
615     bool bRet = AlphaBlend( mhDC, nX, nY, nWidth, nHeight,
616                             hMemDC, 0,0,1,1,
617                             aFunc ) == TRUE;
618 
619     ImplReleaseCachedDC( CACHED_HDC_1 );
620 
621     return bRet;
622 }
623 
624 // -----------------------------------------------------------------------
625 
626 void WinSalGraphics::drawMask( const SalTwoRect* pPosAry,
627                             const SalBitmap& rSSalBitmap,
628                             SalColor nMaskColor )
629 {
630     DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
631 
632     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
633 
634     SalTwoRect  aPosAry = *pPosAry;
635     const BYTE  cRed = SALCOLOR_RED( nMaskColor );
636     const BYTE  cGreen = SALCOLOR_GREEN( nMaskColor );
637     const BYTE  cBlue = SALCOLOR_BLUE( nMaskColor );
638     HDC         hDC = mhDC;
639     HBRUSH      hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) );
640     HBRUSH      hOldBrush = SelectBrush( hDC, hMaskBrush );
641 
642     // bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
643     // die Farben der Maske richtig auf die Palette abzubilden,
644     // wenn wir die DIB direkt ausgeben => DDB-Ausgabe
645     if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 )
646     {
647         WinSalBitmap aTmp;
648 
649         if( aTmp.Create( rSalBitmap, this ) )
650             ImplDrawBitmap( hDC, &aPosAry, aTmp, FALSE, 0x00B8074AUL );
651     }
652     else
653         ImplDrawBitmap( hDC, &aPosAry, rSalBitmap, FALSE, 0x00B8074AUL );
654 
655     SelectBrush( hDC, hOldBrush );
656     DeleteBrush( hMaskBrush );
657 }
658 
659 // -----------------------------------------------------------------------
660 
661 SalBitmap* WinSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
662 {
663     DBG_ASSERT( !mbPrinter, "No ::GetBitmap() from printer possible!" );
664 
665     WinSalBitmap* pSalBitmap = NULL;
666 
667     nDX = labs( nDX );
668     nDY = labs( nDY );
669 
670     HDC     hDC = mhDC;
671     HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
672     HDC     hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
673     sal_Bool    bRet;
674     DWORD err = 0;
675 
676     bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE;
677     ImplReleaseCachedDC( CACHED_HDC_1 );
678 
679     if( bRet )
680     {
681         pSalBitmap = new WinSalBitmap;
682 
683         if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) )
684         {
685             delete pSalBitmap;
686             pSalBitmap = NULL;
687         }
688     }
689     else
690     {
691         err = GetLastError();
692         // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers)
693         DeleteBitmap( hBmpBitmap );
694     }
695 
696     return pSalBitmap;
697 }
698 
699 // -----------------------------------------------------------------------
700 
701 SalColor WinSalGraphics::getPixel( long nX, long nY )
702 {
703     COLORREF aWinCol = ::GetPixel( mhDC, (int) nX, (int) nY );
704 
705     if ( CLR_INVALID == aWinCol )
706         return MAKE_SALCOLOR( 0, 0, 0 );
707     else
708         return MAKE_SALCOLOR( GetRValue( aWinCol ),
709                               GetGValue( aWinCol ),
710                               GetBValue( aWinCol ) );
711 }
712 
713 // -----------------------------------------------------------------------
714 
715 void WinSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
716 {
717     if ( nFlags & SAL_INVERT_TRACKFRAME )
718     {
719         HPEN    hDotPen = CreatePen( PS_DOT, 0, 0 );
720         HPEN    hOldPen = SelectPen( mhDC, hDotPen );
721         HBRUSH  hOldBrush = SelectBrush( mhDC, GetStockBrush( NULL_BRUSH ) );
722         int     nOldROP = SetROP2( mhDC, R2_NOT );
723 
724         WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
725 
726         SetROP2( mhDC, nOldROP );
727         SelectPen( mhDC, hOldPen );
728         SelectBrush( mhDC, hOldBrush );
729         DeletePen( hDotPen );
730     }
731     else if ( nFlags & SAL_INVERT_50 )
732     {
733         SalData* pSalData = GetSalData();
734         if ( !pSalData->mh50Brush )
735         {
736             if ( !pSalData->mh50Bmp )
737                 pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
738             pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
739         }
740 
741         COLORREF nOldTextColor = ::SetTextColor( mhDC, 0 );
742         HBRUSH hOldBrush = SelectBrush( mhDC, pSalData->mh50Brush );
743         PatBlt( mhDC, nX, nY, nWidth, nHeight, PATINVERT );
744         ::SetTextColor( mhDC, nOldTextColor );
745         SelectBrush( mhDC, hOldBrush );
746     }
747     else
748     {
749          RECT aRect;
750          aRect.left      = (int)nX;
751          aRect.top       = (int)nY;
752          aRect.right     = (int)nX+nWidth;
753          aRect.bottom    = (int)nY+nHeight;
754          ::InvertRect( mhDC, &aRect );
755     }
756 }
757 
758 // -----------------------------------------------------------------------
759 
760 void WinSalGraphics::invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nSalFlags )
761 {
762     HPEN        hPen;
763     HPEN        hOldPen;
764     HBRUSH      hBrush;
765     HBRUSH      hOldBrush = 0;
766     COLORREF    nOldTextColor RGB(0,0,0);
767     int         nOldROP = SetROP2( mhDC, R2_NOT );
768 
769     if ( nSalFlags & SAL_INVERT_TRACKFRAME )
770         hPen = CreatePen( PS_DOT, 0, 0 );
771     else
772     {
773 
774         if ( nSalFlags & SAL_INVERT_50 )
775         {
776             SalData* pSalData = GetSalData();
777             if ( !pSalData->mh50Brush )
778             {
779                 if ( !pSalData->mh50Bmp )
780                     pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
781                 pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
782             }
783 
784             hBrush = pSalData->mh50Brush;
785         }
786         else
787             hBrush = GetStockBrush( BLACK_BRUSH );
788 
789         hPen = GetStockPen( NULL_PEN );
790         nOldTextColor = ::SetTextColor( mhDC, 0 );
791         hOldBrush = SelectBrush( mhDC, hBrush );
792     }
793     hOldPen = SelectPen( mhDC, hPen );
794 
795     POINT* pWinPtAry;
796     // Unter NT koennen wir das Array direkt weiterreichen
797     DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
798                 "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
799 
800     pWinPtAry = (POINT*)pPtAry;
801     // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
802     // von Punkten
803     if ( nSalFlags & SAL_INVERT_TRACKFRAME )
804     {
805         if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
806             Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
807     }
808     else
809     {
810         if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
811             WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
812     }
813 
814     SetROP2( mhDC, nOldROP );
815     SelectPen( mhDC, hOldPen );
816 
817     if ( nSalFlags & SAL_INVERT_TRACKFRAME )
818         DeletePen( hPen );
819     else
820     {
821         ::SetTextColor( mhDC, nOldTextColor );
822         SelectBrush( mhDC, hOldBrush );
823     }
824 }
825