xref: /aoo42x/main/vcl/win/source/gdi/salgdi2.cxx (revision 9f62ea84)
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 
40 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 
62 void WinSalGraphics::copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics )
63 {
64 	HDC 	hSrcDC;
65 	DWORD	nRop;
66 
67 	if ( pSrcGraphics )
68 		hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->mhDC;
69 	else
70 		hSrcDC = mhDC;
71 
72 	if ( mbXORMode )
73 		nRop = SRCINVERT;
74 	else
75 		nRop = SRCCOPY;
76 
77 	if ( (pPosAry->mnSrcWidth  == pPosAry->mnDestWidth) &&
78 		 (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
79 	{
80 		BitBlt( mhDC,
81 				(int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
82 				(int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
83 				hSrcDC,
84 				(int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
85 				nRop );
86 	}
87 	else
88 	{
89 		int nOldStretchMode = SetStretchBltMode( mhDC, STRETCH_DELETESCANS );
90 		StretchBlt( mhDC,
91 					(int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
92 					(int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
93 					hSrcDC,
94 					(int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
95 					(int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
96 					nRop );
97 		SetStretchBltMode( mhDC, nOldStretchMode );
98 	}
99 }
100 
101 // -----------------------------------------------------------------------
102 
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 
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( mhDC, hOldClipRgn );
289 
290                     bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate
291                     ExtSelectClipRgn( mhDC, hInvalidateRgn, RGN_DIFF );
292 				}
293 			}
294 		}
295 	}
296 
297 	BitBlt( mhDC,
298 			(int)nDestX, (int)nDestY,
299 			(int)nSrcWidth, (int)nSrcHeight,
300 			mhDC,
301 			(int)nSrcX, (int)nSrcY,
302 			SRCCOPY );
303 
304     if( bRestoreClipRgn )
305     {
306         // restore old clip region
307         if( nOldClipRgnType != ERROR )
308             SelectClipRgn( mhDC, 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( mhDC, 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 
344 void ImplDrawBitmap( HDC hDC,
345 					 const SalTwoRect* pPosAry, 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)pPosAry->mnDestX, (int)pPosAry->mnDestY,
374                            (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
375                            (int)pPosAry->mnSrcX, (int)(pBIH->biHeight - pPosAry->mnSrcHeight - pPosAry->mnSrcY),
376                            (int)pPosAry->mnSrcWidth, (int)pPosAry->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 ( (pPosAry->mnSrcWidth  == pPosAry->mnDestWidth) &&
396 				 (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
397 			{
398 				BitBlt( hDC,
399 						(int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
400 						(int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
401 						hBmpDC,
402 						(int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
403 						nDrawMode );
404 			}
405 			else
406 			{
407 				const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
408 
409 				StretchBlt( hDC,
410 							(int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
411 							(int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
412 							hBmpDC,
413 							(int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
414 							(int)pPosAry->mnSrcWidth, (int)pPosAry->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 
436 void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
437 							  const SalBitmap& rSalBitmap )
438 {
439 	ImplDrawBitmap( mhDC, pPosAry, static_cast<const WinSalBitmap&>(rSalBitmap),
440 					mbPrinter,
441 					mbXORMode ? SRCINVERT : SRCCOPY );
442 }
443 
444 // -----------------------------------------------------------------------
445 
446 void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
447 							  const SalBitmap& rSSalBitmap,
448 							  SalColor nTransparentColor )
449 {
450 	DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
451 
452     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
453 
454 	WinSalBitmap*	pMask = new WinSalBitmap;
455 	const Point aPoint;
456 	const Size	aSize( rSalBitmap.GetSize() );
457 	HBITMAP 	hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL );
458 	HDC 		hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap );
459 	const BYTE	cRed = SALCOLOR_RED( nTransparentColor );
460 	const BYTE	cGreen = SALCOLOR_GREEN( nTransparentColor );
461 	const BYTE	cBlue = SALCOLOR_BLUE( nTransparentColor );
462 
463 	if( rSalBitmap.ImplGethDDB() )
464 	{
465 		HDC 		hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() );
466 		COLORREF	aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
467 
468 		BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
469 
470 		SetBkColor( hSrcDC, aOldCol );
471 		ImplReleaseCachedDC( CACHED_HDC_2 );
472 	}
473 	else
474 	{
475 		WinSalBitmap*	pTmpSalBmp = new WinSalBitmap;
476 
477 		if( pTmpSalBmp->Create( rSalBitmap, this ) )
478 		{
479 			HDC 		hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() );
480 			COLORREF	aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
481 
482 			BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
483 
484 			SetBkColor( hSrcDC, aOldCol );
485 			ImplReleaseCachedDC( CACHED_HDC_2 );
486 		}
487 
488 		delete pTmpSalBmp;
489 	}
490 
491 	ImplReleaseCachedDC( CACHED_HDC_1 );
492 
493 	// hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE )
494 	if( pMask->Create( hMaskBitmap, FALSE, FALSE ) )
495 		drawBitmap( pPosAry, rSalBitmap, *pMask );
496 
497 	delete pMask;
498 }
499 
500 // -----------------------------------------------------------------------
501 
502 void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
503 							  const SalBitmap& rSSalBitmap,
504 							  const SalBitmap& rSTransparentBitmap )
505 {
506 	DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
507 
508     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
509     const WinSalBitmap& rTransparentBitmap = static_cast<const WinSalBitmap&>(rSTransparentBitmap);
510 
511 	SalTwoRect	aPosAry = *pPosAry;
512 	int 		nDstX = (int)aPosAry.mnDestX;
513 	int 		nDstY = (int)aPosAry.mnDestY;
514 	int 		nDstWidth = (int)aPosAry.mnDestWidth;
515 	int 		nDstHeight = (int)aPosAry.mnDestHeight;
516 	HDC 		hDC = mhDC;
517 	HBITMAP 	hMemBitmap = 0;
518 	HBITMAP 	hMaskBitmap = 0;
519 
520 	if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) )
521 	{
522 		hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
523 		hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
524 	}
525 
526 	HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap );
527 	HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap );
528 
529 	aPosAry.mnDestX = aPosAry.mnDestY = 0;
530 	BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY );
531 
532 	// bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
533 	// die Farben der Maske richtig auf die Palette abzubilden,
534 	// wenn wir die DIB direkt ausgeben => DDB-Ausgabe
535 	if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 )
536 	{
537 		WinSalBitmap aTmp;
538 
539 		if( aTmp.Create( rTransparentBitmap, this ) )
540 			ImplDrawBitmap( hMaskDC, &aPosAry, aTmp, FALSE, SRCCOPY );
541 	}
542 	else
543 		ImplDrawBitmap( hMaskDC, &aPosAry, rTransparentBitmap, FALSE, SRCCOPY );
544 
545     // now MemDC contains background, MaskDC the transparency mask
546 
547     // #105055# Respect XOR mode
548     if( mbXORMode )
549     {
550         ImplDrawBitmap( hMaskDC, &aPosAry, rSalBitmap, FALSE, SRCERASE );
551         // now MaskDC contains the bitmap area with black background
552         BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT );
553         // now MemDC contains background XORed bitmap area ontop
554     }
555     else
556     {
557         BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND );
558         // now MemDC contains background with masked-out bitmap area
559         ImplDrawBitmap( hMaskDC, &aPosAry, rSalBitmap, FALSE, SRCERASE );
560         // now MaskDC contains the bitmap area with black background
561         BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT );
562         // now MemDC contains background and bitmap merged together
563     }
564     // copy to output DC
565     BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY );
566 
567 	ImplReleaseCachedDC( CACHED_HDC_1 );
568 	ImplReleaseCachedDC( CACHED_HDC_2 );
569 
570 	// hMemBitmap != 0 ==> hMaskBitmap != 0
571 	if( hMemBitmap )
572 	{
573 		DeleteObject( hMemBitmap );
574 		DeleteObject( hMaskBitmap );
575 	}
576 }
577 
578 // -----------------------------------------------------------------------
579 
580 bool WinSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
581 				      const SalBitmap&  rSrcBitmap,
582 				      const SalBitmap&  rAlphaBmp )
583 {
584     (void)rTR; (void)rSrcBitmap; (void)rAlphaBmp;
585 
586     // TODO(P3): implement alpha bmp blits. Catch: Windows only
587     // handles 32bpp, premultiplied bitmaps
588     return false;
589 }
590 
591 // -----------------------------------------------------------------------
592 
593 bool WinSalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
594                                     long nHeight, sal_uInt8 nTransparency )
595 {
596     if( mbPen || !mbBrush || mbXORMode )
597         return false; // can only perform solid fills without XOR.
598 
599 	HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 );
600     SetPixel( hMemDC, (int)0, (int)0, mnBrushColor );
601 
602     BLENDFUNCTION aFunc = {
603         AC_SRC_OVER,
604         0,
605         255 - 255L*nTransparency/100,
606         0
607     };
608 
609     // hMemDC contains a 1x1 bitmap of the right color - stretch-blit
610     // that to dest hdc
611     bool bRet = AlphaBlend( mhDC, nX, nY, nWidth, nHeight,
612                             hMemDC, 0,0,1,1,
613                             aFunc ) == TRUE;
614 
615 	ImplReleaseCachedDC( CACHED_HDC_1 );
616 
617     return bRet;
618 }
619 
620 // -----------------------------------------------------------------------
621 
622 void WinSalGraphics::drawMask( const SalTwoRect* pPosAry,
623 							const SalBitmap& rSSalBitmap,
624 							SalColor nMaskColor )
625 {
626 	DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
627 
628     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
629 
630 	SalTwoRect	aPosAry = *pPosAry;
631 	const BYTE	cRed = SALCOLOR_RED( nMaskColor );
632 	const BYTE	cGreen = SALCOLOR_GREEN( nMaskColor );
633 	const BYTE	cBlue = SALCOLOR_BLUE( nMaskColor );
634 	HDC 		hDC = mhDC;
635 	HBRUSH		hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) );
636 	HBRUSH		hOldBrush = SelectBrush( hDC, hMaskBrush );
637 
638 	// bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
639 	// die Farben der Maske richtig auf die Palette abzubilden,
640 	// wenn wir die DIB direkt ausgeben => DDB-Ausgabe
641 	if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 )
642 	{
643 		WinSalBitmap aTmp;
644 
645 		if( aTmp.Create( rSalBitmap, this ) )
646 			ImplDrawBitmap( hDC, &aPosAry, aTmp, FALSE, 0x00B8074AUL );
647 	}
648 	else
649 		ImplDrawBitmap( hDC, &aPosAry, rSalBitmap, FALSE, 0x00B8074AUL );
650 
651 	SelectBrush( hDC, hOldBrush );
652 	DeleteBrush( hMaskBrush );
653 }
654 
655 // -----------------------------------------------------------------------
656 
657 SalBitmap* WinSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
658 {
659 	DBG_ASSERT( !mbPrinter, "No ::GetBitmap() from printer possible!" );
660 
661 	WinSalBitmap* pSalBitmap = NULL;
662 
663 	nDX = labs( nDX );
664 	nDY = labs( nDY );
665 
666 	HDC 	hDC = mhDC;
667 	HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
668 	HDC 	hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
669 	sal_Bool	bRet;
670     DWORD err = 0;
671 
672 	bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE;
673 	ImplReleaseCachedDC( CACHED_HDC_1 );
674 
675 	if( bRet )
676 	{
677 		pSalBitmap = new WinSalBitmap;
678 
679 		if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) )
680 		{
681 			delete pSalBitmap;
682 			pSalBitmap = NULL;
683 		}
684 	}
685     else
686     {
687         err = GetLastError();
688         // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers)
689         DeleteBitmap( hBmpBitmap );
690     }
691 
692 	return pSalBitmap;
693 }
694 
695 // -----------------------------------------------------------------------
696 
697 SalColor WinSalGraphics::getPixel( long nX, long nY )
698 {
699 	COLORREF aWinCol = ::GetPixel( mhDC, (int) nX, (int) nY );
700 
701 	if ( CLR_INVALID == aWinCol )
702 		return MAKE_SALCOLOR( 0, 0, 0 );
703 	else
704 		return MAKE_SALCOLOR( GetRValue( aWinCol ),
705 							  GetGValue( aWinCol ),
706 							  GetBValue( aWinCol ) );
707 }
708 
709 // -----------------------------------------------------------------------
710 
711 void WinSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
712 {
713 	if ( nFlags & SAL_INVERT_TRACKFRAME )
714 	{
715 		HPEN	hDotPen = CreatePen( PS_DOT, 0, 0 );
716 		HPEN	hOldPen = SelectPen( mhDC, hDotPen );
717 		HBRUSH	hOldBrush = SelectBrush( mhDC, GetStockBrush( NULL_BRUSH ) );
718 		int 	nOldROP = SetROP2( mhDC, R2_NOT );
719 
720 		WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
721 
722 		SetROP2( mhDC, nOldROP );
723 		SelectPen( mhDC, hOldPen );
724 		SelectBrush( mhDC, hOldBrush );
725 		DeletePen( hDotPen );
726 	}
727 	else if ( nFlags & SAL_INVERT_50 )
728 	{
729 		SalData* pSalData = GetSalData();
730 		if ( !pSalData->mh50Brush )
731 		{
732 			if ( !pSalData->mh50Bmp )
733 				pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
734 			pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
735 		}
736 
737 		COLORREF nOldTextColor = ::SetTextColor( mhDC, 0 );
738 		HBRUSH hOldBrush = SelectBrush( mhDC, pSalData->mh50Brush );
739 		PatBlt( mhDC, nX, nY, nWidth, nHeight, PATINVERT );
740 		::SetTextColor( mhDC, nOldTextColor );
741 		SelectBrush( mhDC, hOldBrush );
742 	}
743 	else
744 	{
745 		 RECT aRect;
746 		 aRect.left 	 = (int)nX;
747 		 aRect.top		 = (int)nY;
748 		 aRect.right	 = (int)nX+nWidth;
749 		 aRect.bottom	 = (int)nY+nHeight;
750 		 ::InvertRect( mhDC, &aRect );
751 	}
752 }
753 
754 // -----------------------------------------------------------------------
755 
756 void WinSalGraphics::invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nSalFlags )
757 {
758 	HPEN		hPen;
759 	HPEN		hOldPen;
760 	HBRUSH		hBrush;
761 	HBRUSH		hOldBrush = 0;
762 	COLORREF	nOldTextColor RGB(0,0,0);
763 	int 		nOldROP = SetROP2( mhDC, R2_NOT );
764 
765 	if ( nSalFlags & SAL_INVERT_TRACKFRAME )
766 		hPen = CreatePen( PS_DOT, 0, 0 );
767 	else
768 	{
769 
770 		if ( nSalFlags & SAL_INVERT_50 )
771 		{
772 			SalData* pSalData = GetSalData();
773 			if ( !pSalData->mh50Brush )
774 			{
775 				if ( !pSalData->mh50Bmp )
776 					pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
777 				pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
778 			}
779 
780 			hBrush = pSalData->mh50Brush;
781 		}
782 		else
783 			hBrush = GetStockBrush( BLACK_BRUSH );
784 
785 		hPen = GetStockPen( NULL_PEN );
786 		nOldTextColor = ::SetTextColor( mhDC, 0 );
787 		hOldBrush = SelectBrush( mhDC, hBrush );
788 	}
789 	hOldPen = SelectPen( mhDC, hPen );
790 
791 	POINT* pWinPtAry;
792 	// Unter NT koennen wir das Array direkt weiterreichen
793 	DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
794 				"WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
795 
796 	pWinPtAry = (POINT*)pPtAry;
797 	// Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
798 	// von Punkten
799 	if ( nSalFlags & SAL_INVERT_TRACKFRAME )
800 	{
801 		if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
802 			Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
803 	}
804 	else
805 	{
806 		if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
807 			WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
808 	}
809 
810 	SetROP2( mhDC, nOldROP );
811 	SelectPen( mhDC, hOldPen );
812 
813 	if ( nSalFlags & SAL_INVERT_TRACKFRAME )
814 		DeletePen( hPen );
815 	else
816 	{
817 		::SetTextColor( mhDC, nOldTextColor );
818 		SelectBrush( mhDC, hOldBrush );
819 	}
820 }
821