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