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