Changed typo va_list to valist.
[wine] / objects / clipping.c
1 /*
2  * DC clipping functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include "windef.h"
9 #include "wingdi.h"
10 #include "wine/winuser16.h"
11 #include "gdi.h"
12 #include "region.h"
13 #include "debugtools.h"
14
15 DEFAULT_DEBUG_CHANNEL(clipping);
16
17
18 /***********************************************************************
19  *           CLIPPING_UpdateGCRegion
20  *
21  * Update the GC clip region when the ClipRgn or VisRgn have changed.
22  */
23 void CLIPPING_UpdateGCRegion( DC * dc )
24 {
25     if (!dc->hGCClipRgn) dc->hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 );
26
27     if (!dc->hVisRgn)
28     {
29         ERR("hVisRgn is zero. Please report this.\n" );
30         exit(1);
31     }
32
33     if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
34
35     if (!dc->hClipRgn)
36         CombineRgn( dc->hGCClipRgn, dc->hVisRgn, 0, RGN_COPY );
37     else
38         CombineRgn(dc->hGCClipRgn, dc->hClipRgn, dc->hVisRgn, RGN_AND);
39     if (dc->funcs->pSetDeviceClipping) dc->funcs->pSetDeviceClipping( dc );
40 }
41
42
43 /***********************************************************************
44  *           SelectClipRgn16    (GDI.44)
45  */
46 INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn )
47 {
48     return (INT16)SelectClipRgn( hdc, hrgn );
49 }
50
51
52 /***********************************************************************
53  *           SelectClipRgn    (GDI32.297)
54  */
55 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
56 {
57     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
58 }
59
60 /******************************************************************************
61  *              ExtSelectClipRgn16      [GDI.508]
62  */
63 INT16 WINAPI ExtSelectClipRgn16( HDC16 hdc, HRGN16 hrgn, INT16 fnMode )
64 {
65   return (INT16) ExtSelectClipRgn((HDC) hdc, (HRGN) hrgn, fnMode);
66 }
67
68 /******************************************************************************
69  *              ExtSelectClipRgn        [GDI32.97]
70  */
71 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
72 {
73     INT retval;
74     DC * dc = DC_GetDCUpdate( hdc );
75     if (!dc) return ERROR;
76
77     TRACE("%04x %04x %d\n", hdc, hrgn, fnMode );
78
79     if (!hrgn)
80     {
81         if (fnMode == RGN_COPY)
82         {
83             if (dc->hClipRgn) DeleteObject16( dc->hClipRgn );
84             dc->hClipRgn = 0;
85             retval = SIMPLEREGION; /* Clip region == whole DC */
86         }
87         else
88         {
89             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode); 
90             GDI_ReleaseObj( hdc );
91             return ERROR;
92         }
93     }
94     else 
95     {
96         if (!dc->hClipRgn)
97         {
98             RECT rect;
99             GetRgnBox( dc->hVisRgn, &rect );
100             dc->hClipRgn = CreateRectRgnIndirect( &rect );
101         }
102
103         OffsetRgn( dc->hClipRgn, -dc->DCOrgX, -dc->DCOrgY );
104         if(fnMode == RGN_COPY)
105             retval = CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
106         else
107             retval = CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
108         OffsetRgn( dc->hClipRgn, dc->DCOrgX, dc->DCOrgY );
109     }
110
111     CLIPPING_UpdateGCRegion( dc );
112     GDI_ReleaseObj( hdc );
113     return retval;
114 }
115
116 /***********************************************************************
117  *           SelectVisRgn    (GDI.105)
118  */
119 INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn )
120 {
121     int retval;
122     DC * dc;
123
124     if (!hrgn) return ERROR;
125     if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
126
127     TRACE("%04x %04x\n", hdc, hrgn );
128
129     dc->flags &= ~DC_DIRTY;
130
131     retval = CombineRgn16( dc->hVisRgn, hrgn, 0, RGN_COPY );
132     CLIPPING_UpdateGCRegion( dc );
133     GDI_ReleaseObj( hdc );
134     return retval;
135 }
136
137
138 /***********************************************************************
139  *           OffsetClipRgn16    (GDI.32)
140  */
141 INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y )
142 {
143     return (INT16)OffsetClipRgn( hdc, x, y );
144 }
145
146
147 /***********************************************************************
148  *           OffsetClipRgn    (GDI32.255)
149  */
150 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
151 {
152     INT ret = SIMPLEREGION;
153     DC *dc = DC_GetDCUpdate( hdc );
154     if (!dc) return ERROR;
155
156     TRACE("%04x %d,%d\n", hdc, x, y );
157
158     if(dc->funcs->pOffsetClipRgn)
159         ret = dc->funcs->pOffsetClipRgn( dc, x, y );
160     else if (dc->hClipRgn) {
161         ret = OffsetRgn( dc->hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y));
162         CLIPPING_UpdateGCRegion( dc );
163     }
164     GDI_ReleaseObj( hdc );
165     return ret;
166 }
167
168
169 /***********************************************************************
170  *           OffsetVisRgn    (GDI.102)
171  */
172 INT16 WINAPI OffsetVisRgn16( HDC16 hdc, INT16 x, INT16 y )
173 {
174     INT16 retval;
175     DC * dc = DC_GetDCUpdate( hdc );
176     if (!dc) return ERROR;    
177     TRACE("%04x %d,%d\n", hdc, x, y );
178     retval = OffsetRgn( dc->hVisRgn, x, y );
179     CLIPPING_UpdateGCRegion( dc );
180     GDI_ReleaseObj( hdc );
181     return retval;
182 }
183
184
185 /***********************************************************************
186  *           CLIPPING_IntersectClipRect
187  *
188  * Helper function for {Intersect,Exclude}ClipRect, can be called from
189  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
190  * coordinate conversion.
191  */
192 INT CLIPPING_IntersectClipRect( DC * dc, INT left, INT top,
193                                   INT right, INT bottom, UINT flags )
194 {
195     HRGN newRgn;
196     INT ret;
197
198     left   += dc->DCOrgX;
199     right  += dc->DCOrgX;
200     top    += dc->DCOrgY;
201     bottom += dc->DCOrgY;
202
203     if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) return ERROR;
204     if (!dc->hClipRgn)
205     {
206        if( flags & CLIP_INTERSECT )
207        {
208            dc->hClipRgn = newRgn;
209            CLIPPING_UpdateGCRegion( dc );
210            return SIMPLEREGION;
211        }
212        else if( flags & CLIP_EXCLUDE )
213        {
214            dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
215            CombineRgn( dc->hClipRgn, dc->hVisRgn, 0, RGN_COPY );
216        }
217        else WARN("No hClipRgn and flags are %x\n",flags);
218     }
219
220     ret = CombineRgn( newRgn, dc->hClipRgn, newRgn, 
221                         (flags & CLIP_EXCLUDE) ? RGN_DIFF : RGN_AND );
222     if (ret != ERROR)
223     {
224         if (!(flags & CLIP_KEEPRGN)) DeleteObject( dc->hClipRgn );
225         dc->hClipRgn = newRgn;    
226         CLIPPING_UpdateGCRegion( dc );
227     }
228     else DeleteObject( newRgn );
229     return ret;
230 }
231
232
233 /***********************************************************************
234  *           ExcludeClipRect16    (GDI.21)
235  */
236 INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top,
237                                 INT16 right, INT16 bottom )
238 {
239     return (INT16)ExcludeClipRect( hdc, left, top, right, bottom );
240 }
241
242
243 /***********************************************************************
244  *           ExcludeClipRect    (GDI32.92)
245  */
246 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
247                                 INT right, INT bottom )
248 {
249     INT ret;
250     DC *dc = DC_GetDCUpdate( hdc );
251     if (!dc) return ERROR;
252
253     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
254
255     if(dc->funcs->pExcludeClipRect)
256         ret = dc->funcs->pExcludeClipRect( dc, left, top, right, bottom );
257     else {
258         left   = XLPTODP( dc, left );
259         right  = XLPTODP( dc, right );
260         top    = YLPTODP( dc, top );
261         bottom = YLPTODP( dc, bottom );
262
263         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_EXCLUDE );
264     }
265     GDI_ReleaseObj( hdc );
266     return ret;
267 }
268
269
270 /***********************************************************************
271  *           IntersectClipRect16    (GDI.22)
272  */
273 INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
274                                   INT16 right, INT16 bottom )
275 {
276     return (INT16)IntersectClipRect( hdc, left, top, right, bottom );
277 }
278
279
280 /***********************************************************************
281  *           IntersectClipRect    (GDI32.245)
282  */
283 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top,
284                                   INT right, INT bottom )
285 {
286     INT ret;
287     DC *dc = DC_GetDCUpdate( hdc );
288     if (!dc) return ERROR;
289
290     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
291
292     if(dc->funcs->pIntersectClipRect)
293         ret = dc->funcs->pIntersectClipRect( dc, left, top, right, bottom );
294     else {
295         left   = XLPTODP( dc, left );
296         right  = XLPTODP( dc, right );
297         top    = YLPTODP( dc, top );
298         bottom = YLPTODP( dc, bottom );
299
300         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_INTERSECT );
301     }
302     GDI_ReleaseObj( hdc );
303     return ret;
304 }
305
306
307 /***********************************************************************
308  *           CLIPPING_IntersectVisRect
309  *
310  * Helper function for {Intersect,Exclude}VisRect, can be called from
311  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
312  * coordinate conversion.
313  */
314 INT CLIPPING_IntersectVisRect( DC * dc, INT left, INT top,
315                                  INT right, INT bottom,
316                                  BOOL exclude )
317 {
318     HRGN tempRgn, newRgn;
319     INT ret;
320
321     left   += dc->DCOrgX;
322     right  += dc->DCOrgX;
323     top    += dc->DCOrgY;
324     bottom += dc->DCOrgY;
325
326     if (!(newRgn = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR;
327     if (!(tempRgn = CreateRectRgn( left, top, right, bottom )))
328     {
329         DeleteObject( newRgn );
330         return ERROR;
331     }
332     ret = CombineRgn( newRgn, dc->hVisRgn, tempRgn,
333                         exclude ? RGN_DIFF : RGN_AND );
334     DeleteObject( tempRgn );
335
336     if (ret != ERROR)
337     {
338         RGNOBJ *newObj  = (RGNOBJ*)GDI_GetObjPtr( newRgn, REGION_MAGIC);
339         if (newObj)
340         {
341             RGNOBJ *prevObj = (RGNOBJ*)GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC);
342             if (prevObj)
343             {
344                 newObj->header.hNext = prevObj->header.hNext;
345                 GDI_ReleaseObj( dc->hVisRgn );
346             }
347             GDI_ReleaseObj( newRgn );
348         }
349         DeleteObject( dc->hVisRgn );
350         dc->hVisRgn = newRgn;    
351         CLIPPING_UpdateGCRegion( dc );
352     }
353     else DeleteObject( newRgn );
354     return ret;
355 }
356
357
358 /***********************************************************************
359  *           ExcludeVisRect    (GDI.73)
360  */
361 INT16 WINAPI ExcludeVisRect16( HDC16 hdc, INT16 left, INT16 top,
362                              INT16 right, INT16 bottom )
363 {
364     INT16 ret;
365     DC * dc = DC_GetDCUpdate( hdc );
366     if (!dc) return ERROR;    
367
368     left   = XLPTODP( dc, left );
369     right  = XLPTODP( dc, right );
370     top    = YLPTODP( dc, top );
371     bottom = YLPTODP( dc, bottom );
372
373     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
374
375     ret = CLIPPING_IntersectVisRect( dc, left, top, right, bottom, TRUE );
376     GDI_ReleaseObj( hdc );
377     return ret;
378 }
379
380
381 /***********************************************************************
382  *           IntersectVisRect    (GDI.98)
383  */
384 INT16 WINAPI IntersectVisRect16( HDC16 hdc, INT16 left, INT16 top,
385                                INT16 right, INT16 bottom )
386 {
387     INT16 ret;
388     DC * dc = DC_GetDCUpdate( hdc );
389     if (!dc) return ERROR;    
390
391     left   = XLPTODP( dc, left );
392     right  = XLPTODP( dc, right );
393     top    = YLPTODP( dc, top );
394     bottom = YLPTODP( dc, bottom );
395
396     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
397
398     ret = CLIPPING_IntersectVisRect( dc, left, top, right, bottom, FALSE );
399     GDI_ReleaseObj( hdc );
400     return ret;
401 }
402
403
404 /***********************************************************************
405  *           PtVisible16    (GDI.103)
406  */
407 BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
408 {
409     return PtVisible( hdc, x, y );
410 }
411
412
413 /***********************************************************************
414  *           PtVisible    (GDI32.279)
415  */
416 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
417 {
418     BOOL ret = FALSE;
419     DC *dc = DC_GetDCUpdate( hdc );
420
421     TRACE("%04x %d,%d\n", hdc, x, y );
422     if (!dc) return FALSE;
423     if (dc->hGCClipRgn)
424     {
425         ret = PtInRegion( dc->hGCClipRgn, XLPTODP(dc,x) + dc->DCOrgX, 
426                                            YLPTODP(dc,y) + dc->DCOrgY );
427 }
428     GDI_ReleaseObj( hdc );
429     return ret;
430 }
431
432
433 /***********************************************************************
434  *           RectVisible16    (GDI.104)
435  */
436 BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect )
437 {
438     BOOL ret = FALSE;
439     RECT16 tmpRect;
440     DC *dc = DC_GetDCUpdate( hdc );
441     if (!dc) return FALSE;
442     TRACE("%04x %d,%dx%d,%d\n",
443           hdc, rect->left, rect->top, rect->right, rect->bottom );
444     if (dc->hGCClipRgn)
445     {
446         /* copy rectangle to avoid overwriting by LPtoDP */
447         tmpRect = *rect;
448         LPtoDP16( hdc, (LPPOINT16)&tmpRect, 2 );
449         tmpRect.left   += dc->DCOrgX;
450         tmpRect.right  += dc->DCOrgX;
451         tmpRect.top    += dc->DCOrgY;
452         tmpRect.bottom += dc->DCOrgY;
453         ret = RectInRegion16( dc->hGCClipRgn, &tmpRect );
454     }
455     GDI_ReleaseObj( hdc );
456     return ret;
457 }
458
459
460 /***********************************************************************
461  *           RectVisible    (GDI32.282)
462  */
463 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
464 {
465     RECT16 rect16;
466     CONV_RECT32TO16( rect, &rect16 );
467     return RectVisible16( (HDC16)hdc, &rect16 );
468 }
469
470
471 /***********************************************************************
472  *           GetClipBox16    (GDI.77)
473  */
474 INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
475 {
476     int ret;
477     DC *dc = DC_GetDCPtr( hdc );
478     if (!dc) return ERROR;    
479     ret = GetRgnBox16( dc->hGCClipRgn, rect );
480     rect->left   -= dc->DCOrgX;
481     rect->right  -= dc->DCOrgX;
482     rect->top    -= dc->DCOrgY;
483     rect->bottom -= dc->DCOrgY;
484     DPtoLP16( hdc, (LPPOINT16)rect, 2 );
485     TRACE("%d,%d-%d,%d\n", rect->left,rect->top,rect->right,rect->bottom );
486     GDI_ReleaseObj( hdc );
487     return ret;
488 }
489
490
491 /***********************************************************************
492  *           GetClipBox    (GDI32.162)
493  */
494 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
495 {
496     INT ret;
497     DC *dc = DC_GetDCPtr( hdc );
498     if (!dc) return ERROR;    
499     ret = GetRgnBox( dc->hGCClipRgn, rect );
500     rect->left   -= dc->DCOrgX;
501     rect->right  -= dc->DCOrgX;
502     rect->top    -= dc->DCOrgY;
503     rect->bottom -= dc->DCOrgY;
504     DPtoLP( hdc, (LPPOINT)rect, 2 );
505     GDI_ReleaseObj( hdc );
506     return ret;
507 }
508
509
510 /***********************************************************************
511  *           GetClipRgn  (GDI32.163)
512  */
513 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
514 {
515     INT ret = -1;
516     DC * dc;
517     if (hRgn && (dc = DC_GetDCPtr( hdc )))
518     {
519       if( dc->hClipRgn )
520       { 
521         /* this assumes that dc->hClipRgn is in coordinates
522            relative to the device (not DC origin) */
523
524         if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR )
525         {
526             OffsetRgn( hRgn, -dc->DCOrgX, -dc->DCOrgY );
527             ret = 1;
528         }
529       }
530       else ret = 0;
531       GDI_ReleaseObj( hdc );
532     }
533     return ret;
534 }
535
536 /***********************************************************************
537  *           SaveVisRgn    (GDI.129)
538  */
539 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc )
540 {
541     HRGN copy;
542     RGNOBJ *obj, *copyObj;
543     DC *dc = DC_GetDCUpdate( hdc );
544
545     if (!dc) return 0;
546     TRACE("%04x\n", hdc );
547
548     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC )))
549     {
550         GDI_ReleaseObj( hdc );
551         return 0;
552     }
553     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
554     {
555         GDI_ReleaseObj( dc->hVisRgn );
556         GDI_ReleaseObj( hdc );
557         return 0;
558     }  
559     CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY );
560     if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC )))
561     {
562         DeleteObject( copy );
563         GDI_ReleaseObj( dc->hVisRgn );
564         GDI_ReleaseObj( hdc );
565         return 0;
566     }
567     copyObj->header.hNext = obj->header.hNext;
568     obj->header.hNext = copy;
569     GDI_ReleaseObj( copy );
570     GDI_ReleaseObj( dc->hVisRgn );
571     GDI_ReleaseObj( hdc );
572     return copy;
573 }
574
575
576 /***********************************************************************
577  *           RestoreVisRgn    (GDI.130)
578  */
579 INT16 WINAPI RestoreVisRgn16( HDC16 hdc )
580 {
581     HRGN saved;
582     RGNOBJ *obj, *savedObj;
583     DC *dc = DC_GetDCPtr( hdc );
584     INT16 ret = ERROR;
585
586     if (!dc) return ERROR;    
587     if (!dc->hVisRgn) goto done;
588     TRACE("%04x\n", hdc );
589     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done;
590
591     saved = obj->header.hNext;
592     GDI_ReleaseObj( dc->hVisRgn );
593     if (!saved || !(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC ))) goto done;
594
595     DeleteObject( dc->hVisRgn );
596     dc->hVisRgn = saved;
597     dc->flags &= ~DC_DIRTY;
598     CLIPPING_UpdateGCRegion( dc );
599     ret = savedObj->rgn->type; /* FIXME */
600     GDI_ReleaseObj( saved );
601  done:
602     GDI_ReleaseObj( hdc );
603     return ret;
604 }