Francois Methot (Macadamian)
[wine/multimedia.git] / objects / clipping.c
blob3f83d3284d2cbd65db48aa65e15f41eeec3d8b6e
1 /*
2 * DC clipping functions
4 * Copyright 1993 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include "dc.h"
9 #include "region.h"
10 #include "debugtools.h"
11 #include "windef.h"
12 #include "wingdi.h"
13 #include "wine/winuser16.h"
15 DEFAULT_DEBUG_CHANNEL(clipping)
16 DECLARE_DEBUG_CHANNEL(region)
18 #define UPDATE_DIRTY_DC(dc) \
19 do { \
20 if ((dc)->hookThunk && !((dc)->w.flags & (DC_SAVED | DC_MEMORY))) \
21 (dc)->hookThunk( (dc)->hSelf, DCHC_INVALIDVISRGN, (dc)->dwHookData, 0 ); \
22 } while(0)
26 /***********************************************************************
27 * CLIPPING_UpdateGCRegion
29 * Update the GC clip region when the ClipRgn or VisRgn have changed.
31 void CLIPPING_UpdateGCRegion( DC * dc )
33 if (!dc->w.hGCClipRgn) dc->w.hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 );
35 if (!dc->w.hVisRgn)
37 ERR_(region)("hVisRgn is zero. Please report this.\n" );
38 exit(1);
41 if (dc->w.flags & DC_DIRTY)
43 UPDATE_DIRTY_DC(dc);
44 dc->w.flags &= ~DC_DIRTY;
47 if (!dc->w.hClipRgn)
48 CombineRgn( dc->w.hGCClipRgn, dc->w.hVisRgn, 0, RGN_COPY );
49 else
50 CombineRgn(dc->w.hGCClipRgn, dc->w.hClipRgn, dc->w.hVisRgn, RGN_AND);
51 if (dc->funcs->pSetDeviceClipping) dc->funcs->pSetDeviceClipping( dc );
55 /***********************************************************************
56 * SelectClipRgn16 (GDI.44)
58 INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn )
60 return (INT16)SelectClipRgn( hdc, hrgn );
64 /***********************************************************************
65 * SelectClipRgn (GDI32.297)
67 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
69 return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
72 /******************************************************************************
73 * ExtSelectClipRgn16 [GDI.508]
75 INT16 WINAPI ExtSelectClipRgn16( HDC16 hdc, HRGN16 hrgn, INT16 fnMode )
77 return (INT16) ExtSelectClipRgn((HDC) hdc, (HRGN) hrgn, fnMode);
80 /******************************************************************************
81 * ExtSelectClipRgn [GDI32.97]
83 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
85 INT retval;
86 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
87 if (!dc) return ERROR;
89 TRACE("%04x %04x %d\n", hdc, hrgn, fnMode );
91 if (!hrgn)
93 if (fnMode == RGN_COPY)
95 if (dc->w.hClipRgn) DeleteObject16( dc->w.hClipRgn );
96 dc->w.hClipRgn = 0;
97 retval = SIMPLEREGION; /* Clip region == whole DC */
99 else
101 FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
102 return ERROR;
105 else
107 if (!dc->w.hClipRgn)
109 RECT rect;
110 GetRgnBox( dc->w.hVisRgn, &rect );
111 dc->w.hClipRgn = CreateRectRgnIndirect( &rect );
114 OffsetRgn( dc->w.hClipRgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
115 if(fnMode == RGN_COPY)
116 retval = CombineRgn( dc->w.hClipRgn, hrgn, 0, fnMode );
117 else
118 retval = CombineRgn( dc->w.hClipRgn, dc->w.hClipRgn, hrgn, fnMode);
119 OffsetRgn( dc->w.hClipRgn, dc->w.DCOrgX, dc->w.DCOrgY );
123 CLIPPING_UpdateGCRegion( dc );
124 GDI_HEAP_UNLOCK( hdc );
125 return retval;
128 /***********************************************************************
129 * SelectVisRgn (GDI.105)
131 INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn )
133 int retval;
134 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
135 if (!dc || !hrgn) return ERROR;
137 TRACE("%04x %04x\n", hdc, hrgn );
139 dc->w.flags &= ~DC_DIRTY;
141 retval = CombineRgn16( dc->w.hVisRgn, hrgn, 0, RGN_COPY );
142 CLIPPING_UpdateGCRegion( dc );
143 GDI_HEAP_UNLOCK( hdc );
144 return retval;
148 /***********************************************************************
149 * OffsetClipRgn16 (GDI.32)
151 INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y )
153 return (INT16)OffsetClipRgn( hdc, x, y );
157 /***********************************************************************
158 * OffsetClipRgn (GDI32.255)
160 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
162 INT ret = SIMPLEREGION;
163 DC *dc = DC_GetDCPtr( hdc );
164 if (!dc) return ERROR;
166 TRACE("%04x %d,%d\n", hdc, x, y );
168 if(dc->funcs->pOffsetClipRgn)
169 ret = dc->funcs->pOffsetClipRgn( dc, x, y );
170 else if (dc->w.hClipRgn) {
171 ret = OffsetRgn( dc->w.hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y));
172 CLIPPING_UpdateGCRegion( dc );
174 GDI_HEAP_UNLOCK( hdc );
175 return ret;
179 /***********************************************************************
180 * OffsetVisRgn (GDI.102)
182 INT16 WINAPI OffsetVisRgn16( HDC16 hdc, INT16 x, INT16 y )
184 INT16 retval;
185 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
186 if (!dc) return ERROR;
187 TRACE("%04x %d,%d\n", hdc, x, y );
188 retval = OffsetRgn( dc->w.hVisRgn, x, y );
189 CLIPPING_UpdateGCRegion( dc );
190 GDI_HEAP_UNLOCK( hdc );
191 return retval;
195 /***********************************************************************
196 * CLIPPING_IntersectClipRect
198 * Helper function for {Intersect,Exclude}ClipRect, can be called from
199 * elsewhere (like ExtTextOut()) to skip redundant metafile update and
200 * coordinate conversion.
202 INT CLIPPING_IntersectClipRect( DC * dc, INT left, INT top,
203 INT right, INT bottom, UINT flags )
205 HRGN newRgn;
206 INT ret;
208 left += dc->w.DCOrgX;
209 right += dc->w.DCOrgX;
210 top += dc->w.DCOrgY;
211 bottom += dc->w.DCOrgY;
213 if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) return ERROR;
214 if (!dc->w.hClipRgn)
216 if( flags & CLIP_INTERSECT )
218 dc->w.hClipRgn = newRgn;
219 CLIPPING_UpdateGCRegion( dc );
220 return SIMPLEREGION;
222 else if( flags & CLIP_EXCLUDE )
224 dc->w.hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
225 CombineRgn( dc->w.hClipRgn, dc->w.hVisRgn, 0, RGN_COPY );
227 else WARN("No hClipRgn and flags are %x\n",flags);
230 ret = CombineRgn( newRgn, dc->w.hClipRgn, newRgn,
231 (flags & CLIP_EXCLUDE) ? RGN_DIFF : RGN_AND );
232 if (ret != ERROR)
234 if (!(flags & CLIP_KEEPRGN)) DeleteObject( dc->w.hClipRgn );
235 dc->w.hClipRgn = newRgn;
236 CLIPPING_UpdateGCRegion( dc );
238 else DeleteObject( newRgn );
239 return ret;
243 /***********************************************************************
244 * ExcludeClipRect16 (GDI.21)
246 INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top,
247 INT16 right, INT16 bottom )
249 return (INT16)ExcludeClipRect( hdc, left, top, right, bottom );
253 /***********************************************************************
254 * ExcludeClipRect (GDI32.92)
256 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
257 INT right, INT bottom )
259 INT ret;
260 DC *dc = DC_GetDCPtr( hdc );
261 if (!dc) return ERROR;
263 TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
265 if(dc->funcs->pExcludeClipRect)
266 ret = dc->funcs->pExcludeClipRect( dc, left, top, right, bottom );
267 else {
268 left = XLPTODP( dc, left );
269 right = XLPTODP( dc, right );
270 top = YLPTODP( dc, top );
271 bottom = YLPTODP( dc, bottom );
273 ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_EXCLUDE );
275 GDI_HEAP_UNLOCK( hdc );
276 return ret;
280 /***********************************************************************
281 * IntersectClipRect16 (GDI.22)
283 INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
284 INT16 right, INT16 bottom )
286 return (INT16)IntersectClipRect( hdc, left, top, right, bottom );
290 /***********************************************************************
291 * IntersectClipRect (GDI32.245)
293 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top,
294 INT right, INT bottom )
296 INT ret;
297 DC *dc = DC_GetDCPtr( hdc );
298 if (!dc) return ERROR;
300 TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
302 if(dc->funcs->pIntersectClipRect)
303 ret = dc->funcs->pIntersectClipRect( dc, left, top, right, bottom );
304 else {
305 left = XLPTODP( dc, left );
306 right = XLPTODP( dc, right );
307 top = YLPTODP( dc, top );
308 bottom = YLPTODP( dc, bottom );
310 ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_INTERSECT );
312 GDI_HEAP_UNLOCK( hdc );
313 return ret;
317 /***********************************************************************
318 * CLIPPING_IntersectVisRect
320 * Helper function for {Intersect,Exclude}VisRect, can be called from
321 * elsewhere (like ExtTextOut()) to skip redundant metafile update and
322 * coordinate conversion.
324 INT CLIPPING_IntersectVisRect( DC * dc, INT left, INT top,
325 INT right, INT bottom,
326 BOOL exclude )
328 HRGN tempRgn, newRgn;
329 INT ret;
331 left += dc->w.DCOrgX;
332 right += dc->w.DCOrgX;
333 top += dc->w.DCOrgY;
334 bottom += dc->w.DCOrgY;
336 if (!(newRgn = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR;
337 if (!(tempRgn = CreateRectRgn( left, top, right, bottom )))
339 DeleteObject( newRgn );
340 return ERROR;
342 ret = CombineRgn( newRgn, dc->w.hVisRgn, tempRgn,
343 exclude ? RGN_DIFF : RGN_AND );
344 DeleteObject( tempRgn );
346 if (ret != ERROR)
348 RGNOBJ *newObj = (RGNOBJ*)GDI_GetObjPtr( newRgn, REGION_MAGIC);
349 RGNOBJ *prevObj = (RGNOBJ*)GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC);
350 if (newObj && prevObj) newObj->header.hNext = prevObj->header.hNext;
351 DeleteObject( dc->w.hVisRgn );
352 dc->w.hVisRgn = newRgn;
353 CLIPPING_UpdateGCRegion( dc );
354 GDI_HEAP_UNLOCK( newRgn );
356 else DeleteObject( newRgn );
357 return ret;
361 /***********************************************************************
362 * ExcludeVisRect (GDI.73)
364 INT16 WINAPI ExcludeVisRect16( HDC16 hdc, INT16 left, INT16 top,
365 INT16 right, INT16 bottom )
367 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
368 if (!dc) return ERROR;
370 left = XLPTODP( dc, left );
371 right = XLPTODP( dc, right );
372 top = YLPTODP( dc, top );
373 bottom = YLPTODP( dc, bottom );
375 TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
377 return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, TRUE );
381 /***********************************************************************
382 * IntersectVisRect (GDI.98)
384 INT16 WINAPI IntersectVisRect16( HDC16 hdc, INT16 left, INT16 top,
385 INT16 right, INT16 bottom )
387 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
388 if (!dc) return ERROR;
390 left = XLPTODP( dc, left );
391 right = XLPTODP( dc, right );
392 top = YLPTODP( dc, top );
393 bottom = YLPTODP( dc, bottom );
395 TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
397 return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, FALSE );
401 /***********************************************************************
402 * PtVisible16 (GDI.103)
404 BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
406 return PtVisible( hdc, x, y );
410 /***********************************************************************
411 * PtVisible (GDI32.279)
413 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
415 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
416 if (!dc) return ERROR;
418 TRACE("%04x %d,%d\n", hdc, x, y );
419 if (!dc->w.hGCClipRgn) return FALSE;
421 if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
422 dc->w.flags &= ~DC_DIRTY;
424 return PtInRegion( dc->w.hGCClipRgn, XLPTODP(dc,x) + dc->w.DCOrgX,
425 YLPTODP(dc,y) + dc->w.DCOrgY );
429 /***********************************************************************
430 * RectVisible16 (GDI.104)
432 BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect )
434 RECT16 tmpRect;
435 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
436 if (!dc) return FALSE;
437 TRACE("%04x %d,%dx%d,%d\n",
438 hdc, rect->left, rect->top, rect->right, rect->bottom );
439 if (!dc->w.hGCClipRgn) return FALSE;
440 /* copy rectangle to avoid overwriting by LPtoDP */
441 tmpRect = *rect;
442 LPtoDP16( hdc, (LPPOINT16)&tmpRect, 2 );
443 tmpRect.left += dc->w.DCOrgX;
444 tmpRect.right += dc->w.DCOrgX;
445 tmpRect.top += dc->w.DCOrgY;
446 tmpRect.bottom += dc->w.DCOrgY;
447 return RectInRegion16( dc->w.hGCClipRgn, &tmpRect );
451 /***********************************************************************
452 * RectVisible (GDI32.282)
454 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
456 RECT16 rect16;
457 CONV_RECT32TO16( rect, &rect16 );
458 return RectVisible16( (HDC16)hdc, &rect16 );
462 /***********************************************************************
463 * GetClipBox16 (GDI.77)
465 INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
467 int ret;
468 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
469 if (!dc) return ERROR;
470 ret = GetRgnBox16( dc->w.hGCClipRgn, rect );
471 rect->left -= dc->w.DCOrgX;
472 rect->right -= dc->w.DCOrgX;
473 rect->top -= dc->w.DCOrgY;
474 rect->bottom -= dc->w.DCOrgY;
475 DPtoLP16( hdc, (LPPOINT16)rect, 2 );
476 TRACE("%d,%d-%d,%d\n", rect->left,rect->top,rect->right,rect->bottom );
477 return ret;
481 /***********************************************************************
482 * GetClipBox (GDI32.162)
484 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
486 INT ret;
487 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
488 if (!dc) return ERROR;
489 ret = GetRgnBox( dc->w.hGCClipRgn, rect );
490 rect->left -= dc->w.DCOrgX;
491 rect->right -= dc->w.DCOrgX;
492 rect->top -= dc->w.DCOrgY;
493 rect->bottom -= dc->w.DCOrgY;
494 DPtoLP( hdc, (LPPOINT)rect, 2 );
495 return ret;
499 /***********************************************************************
500 * GetClipRgn (GDI32.163)
502 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
504 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
505 if( dc && hRgn )
507 if( dc->w.hClipRgn )
509 /* this assumes that dc->w.hClipRgn is in coordinates
510 relative to the device (not DC origin) */
512 if( CombineRgn(hRgn, dc->w.hClipRgn, 0, RGN_COPY) != ERROR )
514 OffsetRgn( hRgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
515 return 1;
518 else return 0;
520 return -1;
523 /***********************************************************************
524 * SaveVisRgn (GDI.129)
526 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc )
528 HRGN copy;
529 RGNOBJ *obj, *copyObj;
530 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
531 if (!dc) return 0;
532 TRACE("%04x\n", hdc );
533 if (!dc->w.hVisRgn)
535 ERR_(region)("hVisRgn is zero. Please report this.\n" );
536 exit(1);
538 if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
539 dc->w.flags &= ~DC_DIRTY;
541 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
543 GDI_HEAP_UNLOCK( hdc );
544 return 0;
546 if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
548 GDI_HEAP_UNLOCK( dc->w.hVisRgn );
549 GDI_HEAP_UNLOCK( hdc );
550 return 0;
552 CombineRgn( copy, dc->w.hVisRgn, 0, RGN_COPY );
553 if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC )))
555 GDI_HEAP_UNLOCK( dc->w.hVisRgn );
556 GDI_HEAP_UNLOCK( hdc );
557 return 0;
559 copyObj->header.hNext = obj->header.hNext;
560 obj->header.hNext = copy;
561 GDI_HEAP_UNLOCK( dc->w.hVisRgn );
562 GDI_HEAP_UNLOCK( hdc );
563 GDI_HEAP_UNLOCK( copy );
564 return copy;
568 /***********************************************************************
569 * RestoreVisRgn (GDI.130)
571 INT16 WINAPI RestoreVisRgn16( HDC16 hdc )
573 HRGN saved;
574 RGNOBJ *obj, *savedObj;
575 DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
576 INT16 ret;
578 if (!dc) return ERROR;
579 if (!dc->w.hVisRgn)
581 GDI_HEAP_UNLOCK( hdc );
582 return ERROR;
584 TRACE("%04x\n", hdc );
585 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
587 GDI_HEAP_UNLOCK( hdc );
588 return ERROR;
590 if (!(saved = obj->header.hNext))
592 GDI_HEAP_UNLOCK( dc->w.hVisRgn );
593 GDI_HEAP_UNLOCK( hdc );
594 return ERROR;
596 if (!(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC )))
598 GDI_HEAP_UNLOCK( dc->w.hVisRgn );
599 GDI_HEAP_UNLOCK( hdc );
600 return ERROR;
602 DeleteObject( dc->w.hVisRgn );
603 dc->w.hVisRgn = saved;
604 CLIPPING_UpdateGCRegion( dc );
605 GDI_HEAP_UNLOCK( hdc );
606 ret = savedObj->rgn->type; /* FIXME */
607 GDI_HEAP_UNLOCK( saved );
608 return ret;