Fix an RPC server startup race introduced by me.
[wine/dcerpc.git] / dlls / gdi / clipping.c
blob0f69be7c725064c8aef8738870fabdcdd7ebaac9
1 /*
2 * DC clipping functions
4 * Copyright 1993 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "wownt32.h"
27 #include "wine/winuser16.h"
28 #include "gdi.h"
29 #include "gdi_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
35 /***********************************************************************
36 * get_clip_region
38 * Return the total clip region (if any).
40 static inline HRGN get_clip_region( DC * dc )
42 if (dc->hMetaClipRgn) return dc->hMetaClipRgn;
43 if (dc->hMetaRgn) return dc->hMetaRgn;
44 return dc->hClipRgn;
48 /***********************************************************************
49 * CLIPPING_UpdateGCRegion
51 * Update the GC clip region when the ClipRgn or VisRgn have changed.
53 void CLIPPING_UpdateGCRegion( DC * dc )
55 HRGN clip_rgn;
57 if (!dc->hVisRgn)
59 ERR("hVisRgn is zero. Please report this.\n" );
60 exit(1);
63 if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
65 /* update the intersection of meta and clip regions */
66 if (dc->hMetaRgn && dc->hClipRgn)
68 if (!dc->hMetaClipRgn) dc->hMetaClipRgn = CreateRectRgn( 0, 0, 0, 0 );
69 CombineRgn( dc->hMetaClipRgn, dc->hClipRgn, dc->hMetaRgn, RGN_AND );
70 clip_rgn = dc->hMetaClipRgn;
72 else /* only one is set, no need for an intersection */
74 if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
75 dc->hMetaClipRgn = 0;
76 clip_rgn = dc->hMetaRgn ? dc->hMetaRgn : dc->hClipRgn;
79 if (dc->funcs->pSetDeviceClipping)
80 dc->funcs->pSetDeviceClipping( dc->physDev, dc->hVisRgn, clip_rgn );
83 /***********************************************************************
84 * create_default_clip_region
86 * Create a default clipping region when none already exists.
88 static inline void create_default_clip_region( DC * dc )
90 dc->hClipRgn = CreateRectRgn(0, 0,
91 GetDeviceCaps( dc->hSelf, HORZRES ),
92 GetDeviceCaps( dc->hSelf, VERTRES ));
96 /***********************************************************************
97 * SelectClipRgn (GDI32.@)
99 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
101 return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
105 /******************************************************************************
106 * ExtSelectClipRgn [GDI32.@]
108 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
110 INT retval;
111 RECT rect;
112 DC * dc = DC_GetDCUpdate( hdc );
113 if (!dc) return ERROR;
115 TRACE("%p %p %d\n", hdc, hrgn, fnMode );
117 if (dc->funcs->pExtSelectClipRgn)
119 retval = dc->funcs->pExtSelectClipRgn( dc->physDev, hrgn, fnMode );
120 GDI_ReleaseObj( hdc );
121 return retval;
124 if (!hrgn)
126 if (fnMode == RGN_COPY)
128 if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
129 dc->hClipRgn = 0;
131 else
133 FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
134 GDI_ReleaseObj( hdc );
135 return ERROR;
138 else
140 if (!dc->hClipRgn)
141 create_default_clip_region( dc );
143 if(fnMode == RGN_COPY)
144 CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
145 else
146 CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
149 CLIPPING_UpdateGCRegion( dc );
150 GDI_ReleaseObj( hdc );
152 return GetClipBox(hdc, &rect);
155 /***********************************************************************
156 * SelectVisRgn (GDI.105)
158 INT16 WINAPI SelectVisRgn16( HDC16 hdc16, HRGN16 hrgn )
160 int retval;
161 HDC hdc = HDC_32( hdc16 );
162 DC * dc;
164 if (!hrgn) return ERROR;
165 if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
167 TRACE("%p %04x\n", hdc, hrgn );
169 dc->flags &= ~DC_DIRTY;
171 retval = CombineRgn( dc->hVisRgn, HRGN_32(hrgn), 0, RGN_COPY );
172 CLIPPING_UpdateGCRegion( dc );
173 GDI_ReleaseObj( hdc );
174 return retval;
178 /***********************************************************************
179 * OffsetClipRgn (GDI32.@)
181 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
183 INT ret = SIMPLEREGION;
184 DC *dc = DC_GetDCUpdate( hdc );
185 if (!dc) return ERROR;
187 TRACE("%p %d,%d\n", hdc, x, y );
189 if(dc->funcs->pOffsetClipRgn)
190 ret = dc->funcs->pOffsetClipRgn( dc->physDev, x, y );
191 else if (dc->hClipRgn) {
192 ret = OffsetRgn( dc->hClipRgn, MulDiv( x, dc->vportExtX, dc->wndExtX ),
193 MulDiv( y, dc->vportExtY, dc->wndExtY ) );
194 CLIPPING_UpdateGCRegion( dc );
196 GDI_ReleaseObj( hdc );
197 return ret;
201 /***********************************************************************
202 * OffsetVisRgn (GDI.102)
204 INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y )
206 INT16 retval;
207 HDC hdc = HDC_32( hdc16 );
208 DC * dc = DC_GetDCUpdate( hdc );
209 if (!dc) return ERROR;
210 TRACE("%p %d,%d\n", hdc, x, y );
211 retval = OffsetRgn( dc->hVisRgn, x, y );
212 CLIPPING_UpdateGCRegion( dc );
213 GDI_ReleaseObj( hdc );
214 return retval;
218 /***********************************************************************
219 * ExcludeClipRect (GDI32.@)
221 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
222 INT right, INT bottom )
224 HRGN newRgn;
225 INT ret;
226 DC *dc = DC_GetDCUpdate( hdc );
227 if (!dc) return ERROR;
229 TRACE("%p %dx%d,%dx%d\n", hdc, left, top, right, bottom );
231 if(dc->funcs->pExcludeClipRect)
232 ret = dc->funcs->pExcludeClipRect( dc->physDev, left, top, right, bottom );
233 else
235 POINT pt[2];
237 pt[0].x = left;
238 pt[0].y = top;
239 pt[1].x = right;
240 pt[1].y = bottom;
241 LPtoDP( hdc, pt, 2 );
242 if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
243 else
245 if (!dc->hClipRgn)
246 create_default_clip_region( dc );
247 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_DIFF );
248 DeleteObject( newRgn );
250 if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
252 GDI_ReleaseObj( hdc );
253 return ret;
257 /***********************************************************************
258 * IntersectClipRect (GDI32.@)
260 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
262 INT ret;
263 DC *dc = DC_GetDCUpdate( hdc );
264 if (!dc) return ERROR;
266 TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
268 if(dc->funcs->pIntersectClipRect)
269 ret = dc->funcs->pIntersectClipRect( dc->physDev, left, top, right, bottom );
270 else
272 POINT pt[2];
274 pt[0].x = left;
275 pt[0].y = top;
276 pt[1].x = right;
277 pt[1].y = bottom;
279 LPtoDP( hdc, pt, 2 );
281 if (!dc->hClipRgn)
283 dc->hClipRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y );
284 ret = SIMPLEREGION;
286 else
288 HRGN newRgn;
290 if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
291 else
293 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND );
294 DeleteObject( newRgn );
297 if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
299 GDI_ReleaseObj( hdc );
300 return ret;
304 /***********************************************************************
305 * ExcludeVisRect (GDI.73)
307 INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
309 HRGN tempRgn;
310 INT16 ret;
311 POINT pt[2];
312 HDC hdc = HDC_32( hdc16 );
313 DC * dc = DC_GetDCUpdate( hdc );
314 if (!dc) return ERROR;
316 pt[0].x = left;
317 pt[0].y = top;
318 pt[1].x = right;
319 pt[1].y = bottom;
321 LPtoDP( hdc, pt, 2 );
323 TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
325 if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
326 else
328 ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_DIFF );
329 DeleteObject( tempRgn );
331 if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
332 GDI_ReleaseObj( hdc );
333 return ret;
337 /***********************************************************************
338 * IntersectVisRect (GDI.98)
340 INT16 WINAPI IntersectVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
342 HRGN tempRgn;
343 INT16 ret;
344 POINT pt[2];
345 HDC hdc = HDC_32( hdc16 );
346 DC * dc = DC_GetDCUpdate( hdc );
347 if (!dc) return ERROR;
349 pt[0].x = left;
350 pt[0].y = top;
351 pt[1].x = right;
352 pt[1].y = bottom;
354 LPtoDP( hdc, pt, 2 );
356 TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
359 if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
360 else
362 ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_AND );
363 DeleteObject( tempRgn );
365 if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
366 GDI_ReleaseObj( hdc );
367 return ret;
371 /***********************************************************************
372 * PtVisible (GDI32.@)
374 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
376 POINT pt;
377 BOOL ret;
378 HRGN clip;
379 DC *dc = DC_GetDCUpdate( hdc );
381 TRACE("%p %d,%d\n", hdc, x, y );
382 if (!dc) return FALSE;
384 pt.x = x;
385 pt.y = y;
386 LPtoDP( hdc, &pt, 1 );
387 ret = PtInRegion( dc->hVisRgn, pt.x, pt.y );
388 if (ret && (clip = get_clip_region(dc))) ret = PtInRegion( clip, pt.x, pt.y );
389 GDI_ReleaseObj( hdc );
390 return ret;
394 /***********************************************************************
395 * RectVisible (GDI32.@)
397 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
399 RECT tmpRect;
400 BOOL ret;
401 HRGN clip;
402 DC *dc = DC_GetDCUpdate( hdc );
403 if (!dc) return FALSE;
404 TRACE("%p %ld,%ldx%ld,%ld\n", hdc, rect->left, rect->top, rect->right, rect->bottom );
406 tmpRect = *rect;
407 LPtoDP( hdc, (POINT *)&tmpRect, 2 );
409 if ((clip = get_clip_region(dc)))
411 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
412 CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
413 ret = RectInRegion( hrgn, &tmpRect );
414 DeleteObject( hrgn );
416 else ret = RectInRegion( dc->hVisRgn, &tmpRect );
417 GDI_ReleaseObj( hdc );
418 return ret;
422 /***********************************************************************
423 * GetClipBox (GDI32.@)
425 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
427 INT ret;
428 HRGN clip;
429 DC *dc = DC_GetDCUpdate( hdc );
430 if (!dc) return ERROR;
431 if ((clip = get_clip_region(dc)))
433 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
434 CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
435 ret = GetRgnBox( hrgn, rect );
436 DeleteObject( hrgn );
438 else ret = GetRgnBox( dc->hVisRgn, rect );
439 DPtoLP( hdc, (LPPOINT)rect, 2 );
440 GDI_ReleaseObj( hdc );
441 return ret;
445 /***********************************************************************
446 * GetClipRgn (GDI32.@)
448 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
450 INT ret = -1;
451 DC * dc;
452 if (hRgn && (dc = DC_GetDCPtr( hdc )))
454 if( dc->hClipRgn )
456 if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1;
458 else ret = 0;
459 GDI_ReleaseObj( hdc );
461 return ret;
465 /***********************************************************************
466 * GetMetaRgn (GDI32.@)
468 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
470 INT ret = 0;
471 DC * dc = DC_GetDCPtr( hdc );
473 if (dc)
475 if (dc->hMetaRgn && CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY ) != ERROR)
476 ret = 1;
477 GDI_ReleaseObj( hdc );
479 return ret;
483 /***********************************************************************
484 * SaveVisRgn (GDI.129)
486 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc16 )
488 struct saved_visrgn *saved;
489 HDC hdc = HDC_32( hdc16 );
490 DC *dc = DC_GetDCUpdate( hdc );
492 if (!dc) return 0;
493 TRACE("%p\n", hdc );
495 if (!(saved = HeapAlloc( GetProcessHeap(), 0, sizeof(*saved) ))) goto error;
496 if (!(saved->hrgn = CreateRectRgn( 0, 0, 0, 0 ))) goto error;
497 CombineRgn( saved->hrgn, dc->hVisRgn, 0, RGN_COPY );
498 saved->next = dc->saved_visrgn;
499 dc->saved_visrgn = saved;
500 GDI_ReleaseObj( hdc );
501 return HRGN_16(saved->hrgn);
503 error:
504 GDI_ReleaseObj( hdc );
505 HeapFree( GetProcessHeap(), 0, saved );
506 return 0;
510 /***********************************************************************
511 * RestoreVisRgn (GDI.130)
513 INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 )
515 struct saved_visrgn *saved;
516 HDC hdc = HDC_32( hdc16 );
517 DC *dc = DC_GetDCPtr( hdc );
518 INT16 ret = ERROR;
520 if (!dc) return ERROR;
522 TRACE("%p\n", hdc );
524 if (!(saved = dc->saved_visrgn)) goto done;
526 ret = CombineRgn( dc->hVisRgn, saved->hrgn, 0, RGN_COPY );
527 dc->saved_visrgn = saved->next;
528 DeleteObject( saved->hrgn );
529 HeapFree( GetProcessHeap(), 0, saved );
530 dc->flags &= ~DC_DIRTY;
531 CLIPPING_UpdateGCRegion( dc );
532 done:
533 GDI_ReleaseObj( hdc );
534 return ret;
538 /***********************************************************************
539 * GetRandomRgn [GDI32.@]
541 * NOTES
542 * This function is documented in MSDN online for the case of
543 * iCode == SYSRGN (4).
545 * For iCode == 1 it should return the clip region
546 * 2 " " " the meta region
547 * 3 " " " the intersection of the clip with
548 * the meta region (== 'Rao' region).
550 * See http://www.codeproject.com/gdi/cliprgnguide.asp
552 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, INT iCode)
554 HRGN rgn;
555 DC *dc = DC_GetDCPtr( hDC );
557 if (!dc) return -1;
559 switch (iCode)
561 case 1:
562 rgn = dc->hClipRgn;
563 break;
564 case 2:
565 rgn = dc->hMetaRgn;
566 break;
567 case 3:
568 rgn = dc->hMetaClipRgn;
569 break;
570 case SYSRGN: /* == 4 */
571 rgn = dc->hVisRgn;
572 break;
573 default:
574 WARN("Unknown code %d\n", iCode);
575 GDI_ReleaseObj( hDC );
576 return -1;
578 if (rgn) CombineRgn( hRgn, rgn, 0, RGN_COPY );
579 GDI_ReleaseObj( hDC );
581 /* On Windows NT/2000, the region returned is in screen coordinates */
582 if (!(GetVersion() & 0x80000000))
584 POINT org;
585 GetDCOrgEx( hDC, &org );
586 OffsetRgn( hRgn, org.x, org.y );
588 return (rgn != 0);
592 /***********************************************************************
593 * SetMetaRgn (GDI32.@)
595 INT WINAPI SetMetaRgn( HDC hdc )
597 INT ret;
598 RECT dummy;
599 DC *dc = DC_GetDCPtr( hdc );
601 if (!dc) return ERROR;
603 if (dc->hMetaClipRgn)
605 /* the intersection becomes the new meta region */
606 DeleteObject( dc->hMetaRgn );
607 DeleteObject( dc->hClipRgn );
608 dc->hMetaRgn = dc->hMetaClipRgn;
609 dc->hClipRgn = 0;
610 dc->hMetaClipRgn = 0;
612 else if (dc->hClipRgn)
614 dc->hMetaRgn = dc->hClipRgn;
615 dc->hClipRgn = 0;
617 /* else nothing to do */
619 /* Note: no need to call CLIPPING_UpdateGCRegion, the overall clip region hasn't changed */
621 ret = GetRgnBox( dc->hMetaRgn, &dummy );
622 GDI_ReleaseObj( hdc );
623 return ret;