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