xref: /aoo42x/main/vcl/win/source/gdi/salgdi2.cxx (revision cdf0e10c)
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