xref: /trunk/main/vcl/win/source/gdi/salgdi2.cxx (revision 86e1cf34)
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                 // subtract 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 running 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