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