Removed obsolete SHMDATA parameter in GLOBAL_CreateBlock.
[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 "windef.h"
12 #include "wingdi.h"
13 #include "wine/winuser16.h"
14
15 DEFAULT_DEBUG_CHANNEL(clipping)
16 DECLARE_DEBUG_CHANNEL(region)
17
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)
23
24
25
26 /***********************************************************************
27  *           CLIPPING_UpdateGCRegion
28  *
29  * Update the GC clip region when the ClipRgn or VisRgn have changed.
30  */
31 void CLIPPING_UpdateGCRegion( DC * dc )
32 {
33     if (!dc->w.hGCClipRgn) dc->w.hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 );
34
35     if (!dc->w.hVisRgn)
36     {
37         ERR_(region)("hVisRgn is zero. Please report this.\n" );
38         exit(1);
39     }
40
41     if (dc->w.flags & DC_DIRTY)
42     {
43         UPDATE_DIRTY_DC(dc);
44         dc->w.flags &= ~DC_DIRTY;
45     }
46
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 );
52 }
53
54
55 /***********************************************************************
56  *           SelectClipRgn16    (GDI.44)
57  */
58 INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn )
59 {
60     return (INT16)SelectClipRgn( hdc, hrgn );
61 }
62
63
64 /***********************************************************************
65  *           SelectClipRgn    (GDI32.297)
66  */
67 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
68 {
69     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
70 }
71
72 /******************************************************************************
73  *              ExtSelectClipRgn16      [GDI.508]
74  */
75 INT16 WINAPI ExtSelectClipRgn16( HDC16 hdc, HRGN16 hrgn, INT16 fnMode )
76 {
77   return (INT16) ExtSelectClipRgn((HDC) hdc, (HRGN) hrgn, fnMode);
78 }
79
80 /******************************************************************************
81  *              ExtSelectClipRgn        [GDI32.97]
82  */
83 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
84 {
85     INT retval;
86     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
87     if (!dc) return ERROR;
88
89     TRACE("%04x %04x %d\n", hdc, hrgn, fnMode );
90
91     if (!hrgn)
92     {
93         if (fnMode == RGN_COPY)
94         {
95             if (dc->w.hClipRgn) DeleteObject16( dc->w.hClipRgn );
96             dc->w.hClipRgn = 0;
97             retval = SIMPLEREGION; /* Clip region == whole DC */
98         }
99         else
100         {
101             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode); 
102             return ERROR;
103         }
104     }
105     else 
106     {
107         if (!dc->w.hClipRgn)
108         {
109             RECT rect;
110             GetRgnBox( dc->w.hVisRgn, &rect );
111             dc->w.hClipRgn = CreateRectRgnIndirect( &rect );
112         }
113
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 );
120     }
121
122
123     CLIPPING_UpdateGCRegion( dc );
124     GDI_HEAP_UNLOCK( hdc );
125     return retval;
126 }
127
128 /***********************************************************************
129  *           SelectVisRgn    (GDI.105)
130  */
131 INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn )
132 {
133     int retval;
134     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
135     if (!dc || !hrgn) return ERROR;
136
137     TRACE("%04x %04x\n", hdc, hrgn );
138
139     dc->w.flags &= ~DC_DIRTY;
140
141     retval = CombineRgn16( dc->w.hVisRgn, hrgn, 0, RGN_COPY );
142     CLIPPING_UpdateGCRegion( dc );
143     GDI_HEAP_UNLOCK( hdc );
144     return retval;
145 }
146
147
148 /***********************************************************************
149  *           OffsetClipRgn16    (GDI.32)
150  */
151 INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y )
152 {
153     return (INT16)OffsetClipRgn( hdc, x, y );
154 }
155
156
157 /***********************************************************************
158  *           OffsetClipRgn    (GDI32.255)
159  */
160 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
161 {
162     INT ret = SIMPLEREGION;
163     DC *dc = DC_GetDCPtr( hdc );
164     if (!dc) return ERROR;
165
166     TRACE("%04x %d,%d\n", hdc, x, y );
167
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 );
173     }
174     GDI_HEAP_UNLOCK( hdc );
175     return ret;
176 }
177
178
179 /***********************************************************************
180  *           OffsetVisRgn    (GDI.102)
181  */
182 INT16 WINAPI OffsetVisRgn16( HDC16 hdc, INT16 x, INT16 y )
183 {
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;
192 }
193
194
195 /***********************************************************************
196  *           CLIPPING_IntersectClipRect
197  *
198  * Helper function for {Intersect,Exclude}ClipRect, can be called from
199  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
200  * coordinate conversion.
201  */
202 INT CLIPPING_IntersectClipRect( DC * dc, INT left, INT top,
203                                   INT right, INT bottom, UINT flags )
204 {
205     HRGN newRgn;
206     INT ret;
207
208     left   += dc->w.DCOrgX;
209     right  += dc->w.DCOrgX;
210     top    += dc->w.DCOrgY;
211     bottom += dc->w.DCOrgY;
212
213     if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) return ERROR;
214     if (!dc->w.hClipRgn)
215     {
216        if( flags & CLIP_INTERSECT )
217        {
218            dc->w.hClipRgn = newRgn;
219            CLIPPING_UpdateGCRegion( dc );
220            return SIMPLEREGION;
221        }
222        else if( flags & CLIP_EXCLUDE )
223        {
224            dc->w.hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
225            CombineRgn( dc->w.hClipRgn, dc->w.hVisRgn, 0, RGN_COPY );
226        }
227        else WARN("No hClipRgn and flags are %x\n",flags);
228     }
229
230     ret = CombineRgn( newRgn, dc->w.hClipRgn, newRgn, 
231                         (flags & CLIP_EXCLUDE) ? RGN_DIFF : RGN_AND );
232     if (ret != ERROR)
233     {
234         if (!(flags & CLIP_KEEPRGN)) DeleteObject( dc->w.hClipRgn );
235         dc->w.hClipRgn = newRgn;    
236         CLIPPING_UpdateGCRegion( dc );
237     }
238     else DeleteObject( newRgn );
239     return ret;
240 }
241
242
243 /***********************************************************************
244  *           ExcludeClipRect16    (GDI.21)
245  */
246 INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top,
247                                 INT16 right, INT16 bottom )
248 {
249     return (INT16)ExcludeClipRect( hdc, left, top, right, bottom );
250 }
251
252
253 /***********************************************************************
254  *           ExcludeClipRect    (GDI32.92)
255  */
256 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
257                                 INT right, INT bottom )
258 {
259     INT ret;
260     DC *dc = DC_GetDCPtr( hdc );
261     if (!dc) return ERROR;
262
263     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
264
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 );
272
273         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_EXCLUDE );
274     }
275     GDI_HEAP_UNLOCK( hdc );
276     return ret;
277 }
278
279
280 /***********************************************************************
281  *           IntersectClipRect16    (GDI.22)
282  */
283 INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
284                                   INT16 right, INT16 bottom )
285 {
286     return (INT16)IntersectClipRect( hdc, left, top, right, bottom );
287 }
288
289
290 /***********************************************************************
291  *           IntersectClipRect    (GDI32.245)
292  */
293 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top,
294                                   INT right, INT bottom )
295 {
296     INT ret;
297     DC *dc = DC_GetDCPtr( hdc );
298     if (!dc) return ERROR;
299
300     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
301
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 );
309
310         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_INTERSECT );
311     }
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("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
376
377     return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, TRUE );
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     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
388     if (!dc) return ERROR;    
389
390     left   = XLPTODP( dc, left );
391     right  = XLPTODP( dc, right );
392     top    = YLPTODP( dc, top );
393     bottom = YLPTODP( dc, bottom );
394
395     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
396
397     return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, FALSE );
398 }
399
400
401 /***********************************************************************
402  *           PtVisible16    (GDI.103)
403  */
404 BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
405 {
406     return PtVisible( hdc, x, y );
407 }
408
409
410 /***********************************************************************
411  *           PtVisible    (GDI32.279)
412  */
413 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
414 {
415     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
416     if (!dc) return ERROR;    
417
418     TRACE("%04x %d,%d\n", hdc, x, y );
419     if (!dc->w.hGCClipRgn) return FALSE;
420
421     if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
422     dc->w.flags &= ~DC_DIRTY;
423
424     return PtInRegion( dc->w.hGCClipRgn, XLPTODP(dc,x) + dc->w.DCOrgX, 
425                                            YLPTODP(dc,y) + dc->w.DCOrgY );
426 }
427
428
429 /***********************************************************************
430  *           RectVisible16    (GDI.104)
431  */
432 BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect )
433 {
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 );
448 }
449
450
451 /***********************************************************************
452  *           RectVisible    (GDI32.282)
453  */
454 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
455 {
456     RECT16 rect16;
457     CONV_RECT32TO16( rect, &rect16 );
458     return RectVisible16( (HDC16)hdc, &rect16 );
459 }
460
461
462 /***********************************************************************
463  *           GetClipBox16    (GDI.77)
464  */
465 INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
466 {
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;
478 }
479
480
481 /***********************************************************************
482  *           GetClipBox    (GDI32.162)
483  */
484 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
485 {
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;
496 }
497
498
499 /***********************************************************************
500  *           GetClipRgn  (GDI32.163)
501  */
502 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
503 {
504     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
505     if( dc && hRgn )
506     {
507       if( dc->w.hClipRgn )
508       { 
509         /* this assumes that dc->w.hClipRgn is in coordinates
510            relative to the device (not DC origin) */
511
512         if( CombineRgn(hRgn, dc->w.hClipRgn, 0, RGN_COPY) != ERROR )
513         {
514             OffsetRgn( hRgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
515             return 1;
516         }
517       }
518       else return 0;
519     }
520     return -1;
521 }
522
523 /***********************************************************************
524  *           SaveVisRgn    (GDI.129)
525  */
526 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc )
527 {
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)
534     {
535         ERR_(region)("hVisRgn is zero. Please report this.\n" );
536         exit(1);
537     }
538     if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
539     dc->w.flags &= ~DC_DIRTY;
540
541     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
542     {
543         GDI_HEAP_UNLOCK( hdc );
544         return 0;
545     }
546     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
547     {
548         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
549         GDI_HEAP_UNLOCK( hdc );
550         return 0;
551     }  
552     CombineRgn( copy, dc->w.hVisRgn, 0, RGN_COPY );
553     if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC )))
554     {
555         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
556         GDI_HEAP_UNLOCK( hdc );
557         return 0;
558     }
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;
565 }
566
567
568 /***********************************************************************
569  *           RestoreVisRgn    (GDI.130)
570  */
571 INT16 WINAPI RestoreVisRgn16( HDC16 hdc )
572 {
573     HRGN saved;
574     RGNOBJ *obj, *savedObj;
575     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
576     INT16 ret;
577
578     if (!dc) return ERROR;    
579     if (!dc->w.hVisRgn)
580     {
581         GDI_HEAP_UNLOCK( hdc );
582         return ERROR;    
583     }
584     TRACE("%04x\n", hdc );
585     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
586     {
587         GDI_HEAP_UNLOCK( hdc );
588         return ERROR;
589     }
590     if (!(saved = obj->header.hNext)) 
591     {
592         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
593         GDI_HEAP_UNLOCK( hdc );
594         return ERROR;
595     }
596     if (!(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC )))
597     {
598         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
599         GDI_HEAP_UNLOCK( hdc );
600         return ERROR;
601     }
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;
609 }