Added a possibility to let the internal debugger use a separate
[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 "debug.h"
11 #include "wine/winuser16.h"
12
13 DECLARE_DEBUG_CHANNEL(clipping)
14 DECLARE_DEBUG_CHANNEL(region)
15
16 #define UPDATE_DIRTY_DC(dc) \
17  do { \
18    if ((dc)->hookProc && !((dc)->w.flags & (DC_SAVED | DC_MEMORY))) \
19      (dc)->hookProc( (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  *              ExtSelectClipRgn        [GDI32.97]
72  */
73 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
74 {
75     INT retval;
76     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
77     if (!dc) return ERROR;
78
79     TRACE( clipping, "%04x %04x %d\n", hdc, hrgn, fnMode );
80
81     if (!hrgn)
82     {
83         if (fnMode == RGN_COPY)
84         {
85             if (dc->w.hClipRgn) DeleteObject16( dc->w.hClipRgn );
86             dc->w.hClipRgn = 0;
87             retval = SIMPLEREGION; /* Clip region == whole DC */
88         }
89         else
90         {
91             FIXME(clipping, "Unimplemented: hrgn NULL in mode: %d\n", fnMode); 
92             return ERROR;
93         }
94     }
95     else 
96     {
97         if (!dc->w.hClipRgn)
98         {
99             RECT rect;
100             GetRgnBox( dc->w.hVisRgn, &rect );
101             dc->w.hClipRgn = CreateRectRgnIndirect( &rect );
102         }
103
104         OffsetRgn( dc->w.hClipRgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
105         if(fnMode == RGN_COPY)
106             retval = CombineRgn( dc->w.hClipRgn, hrgn, 0, fnMode );
107         else
108             retval = CombineRgn( dc->w.hClipRgn, dc->w.hClipRgn, hrgn, fnMode);
109         OffsetRgn( dc->w.hClipRgn, dc->w.DCOrgX, dc->w.DCOrgY );
110     }
111
112
113     CLIPPING_UpdateGCRegion( dc );
114     GDI_HEAP_UNLOCK( hdc );
115     return retval;
116 }
117
118 /***********************************************************************
119  *           SelectVisRgn    (GDI.105)
120  */
121 INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn )
122 {
123     int retval;
124     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
125     if (!dc || !hrgn) return ERROR;
126
127     TRACE(clipping, "%04x %04x\n", hdc, hrgn );
128
129     dc->w.flags &= ~DC_DIRTY;
130
131     retval = CombineRgn16( dc->w.hVisRgn, hrgn, 0, RGN_COPY );
132     CLIPPING_UpdateGCRegion( dc );
133     GDI_HEAP_UNLOCK( 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  *           OffsetClipRgn32    (GDI32.255)
149  */
150 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
151 {
152     INT ret = SIMPLEREGION;
153     DC *dc = DC_GetDCPtr( hdc );
154     if (!dc) return ERROR;
155
156     TRACE(clipping, "%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->w.hClipRgn) {
161         ret = OffsetRgn( dc->w.hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y));
162         CLIPPING_UpdateGCRegion( dc );
163     }
164     GDI_HEAP_UNLOCK( 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 *) GDI_GetObjPtr( hdc, DC_MAGIC );
176     if (!dc) return ERROR;    
177     TRACE(clipping, "%04x %d,%d\n", hdc, x, y );
178     retval = OffsetRgn( dc->w.hVisRgn, x, y );
179     CLIPPING_UpdateGCRegion( dc );
180     GDI_HEAP_UNLOCK( 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->w.DCOrgX;
199     right  += dc->w.DCOrgX;
200     top    += dc->w.DCOrgY;
201     bottom += dc->w.DCOrgY;
202
203     if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) return ERROR;
204     if (!dc->w.hClipRgn)
205     {
206        if( flags & CLIP_INTERSECT )
207        {
208            dc->w.hClipRgn = newRgn;
209            CLIPPING_UpdateGCRegion( dc );
210            return SIMPLEREGION;
211        }
212        else if( flags & CLIP_EXCLUDE )
213        {
214            dc->w.hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
215            CombineRgn( dc->w.hClipRgn, dc->w.hVisRgn, 0, RGN_COPY );
216        }
217        else WARN(clipping,"No hClipRgn and flags are %x\n",flags);
218     }
219
220     ret = CombineRgn( newRgn, dc->w.hClipRgn, newRgn, 
221                         (flags & CLIP_EXCLUDE) ? RGN_DIFF : RGN_AND );
222     if (ret != ERROR)
223     {
224         if (!(flags & CLIP_KEEPRGN)) DeleteObject( dc->w.hClipRgn );
225         dc->w.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  *           ExcludeClipRect32    (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_GetDCPtr( hdc );
251     if (!dc) return ERROR;
252
253     TRACE(clipping, "%04x %dx%d,%dx%d\n",
254             hdc, left, top, right, bottom );
255
256     if(dc->funcs->pExcludeClipRect)
257         ret = dc->funcs->pExcludeClipRect( dc, left, top, right, bottom );
258     else {
259         left   = XLPTODP( dc, left );
260         right  = XLPTODP( dc, right );
261         top    = YLPTODP( dc, top );
262         bottom = YLPTODP( dc, bottom );
263
264         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_EXCLUDE );
265     }
266     GDI_HEAP_UNLOCK( hdc );
267     return ret;
268 }
269
270
271 /***********************************************************************
272  *           IntersectClipRect16    (GDI.22)
273  */
274 INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
275                                   INT16 right, INT16 bottom )
276 {
277     return (INT16)IntersectClipRect( hdc, left, top, right, bottom );
278 }
279
280
281 /***********************************************************************
282  *           IntersectClipRect32    (GDI32.245)
283  */
284 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top,
285                                   INT right, INT bottom )
286 {
287     INT ret;
288     DC *dc = DC_GetDCPtr( hdc );
289     if (!dc) return ERROR;
290
291     TRACE(clipping, "%04x %dx%d,%dx%d\n",
292           hdc, left, top, right, bottom );
293
294     if(dc->funcs->pIntersectClipRect)
295         ret = dc->funcs->pIntersectClipRect( dc, left, top, right, bottom );
296     else {
297         left   = XLPTODP( dc, left );
298         right  = XLPTODP( dc, right );
299         top    = YLPTODP( dc, top );
300         bottom = YLPTODP( dc, bottom );
301
302         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_INTERSECT );
303     }
304     GDI_HEAP_UNLOCK( hdc );
305     return ret;
306 }
307
308
309 /***********************************************************************
310  *           CLIPPING_IntersectVisRect
311  *
312  * Helper function for {Intersect,Exclude}VisRect, can be called from
313  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
314  * coordinate conversion.
315  */
316 INT CLIPPING_IntersectVisRect( DC * dc, INT left, INT top,
317                                  INT right, INT bottom,
318                                  BOOL exclude )
319 {
320     HRGN tempRgn, newRgn;
321     INT ret;
322
323     left   += dc->w.DCOrgX;
324     right  += dc->w.DCOrgX;
325     top    += dc->w.DCOrgY;
326     bottom += dc->w.DCOrgY;
327
328     if (!(newRgn = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR;
329     if (!(tempRgn = CreateRectRgn( left, top, right, bottom )))
330     {
331         DeleteObject( newRgn );
332         return ERROR;
333     }
334     ret = CombineRgn( newRgn, dc->w.hVisRgn, tempRgn,
335                         exclude ? RGN_DIFF : RGN_AND );
336     DeleteObject( tempRgn );
337
338     if (ret != ERROR)
339     {
340         RGNOBJ *newObj  = (RGNOBJ*)GDI_GetObjPtr( newRgn, REGION_MAGIC);
341         RGNOBJ *prevObj = (RGNOBJ*)GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC);
342         if (newObj && prevObj) newObj->header.hNext = prevObj->header.hNext;
343         DeleteObject( dc->w.hVisRgn );
344         dc->w.hVisRgn = newRgn;    
345         CLIPPING_UpdateGCRegion( dc );
346         GDI_HEAP_UNLOCK( newRgn );
347     }
348     else DeleteObject( newRgn );
349     return ret;
350 }
351
352
353 /***********************************************************************
354  *           ExcludeVisRect    (GDI.73)
355  */
356 INT16 WINAPI ExcludeVisRect16( HDC16 hdc, INT16 left, INT16 top,
357                              INT16 right, INT16 bottom )
358 {
359     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
360     if (!dc) return ERROR;    
361
362     left   = XLPTODP( dc, left );
363     right  = XLPTODP( dc, right );
364     top    = YLPTODP( dc, top );
365     bottom = YLPTODP( dc, bottom );
366
367     TRACE(clipping, "%04x %dx%d,%dx%d\n",
368             hdc, left, top, right, bottom );
369
370     return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, TRUE );
371 }
372
373
374 /***********************************************************************
375  *           IntersectVisRect    (GDI.98)
376  */
377 INT16 WINAPI IntersectVisRect16( HDC16 hdc, INT16 left, INT16 top,
378                                INT16 right, INT16 bottom )
379 {
380     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
381     if (!dc) return ERROR;    
382
383     left   = XLPTODP( dc, left );
384     right  = XLPTODP( dc, right );
385     top    = YLPTODP( dc, top );
386     bottom = YLPTODP( dc, bottom );
387
388     TRACE(clipping, "%04x %dx%d,%dx%d\n",
389             hdc, left, top, right, bottom );
390
391     return CLIPPING_IntersectVisRect( dc, left, top, right, bottom, FALSE );
392 }
393
394
395 /***********************************************************************
396  *           PtVisible16    (GDI.103)
397  */
398 BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
399 {
400     return PtVisible( hdc, x, y );
401 }
402
403
404 /***********************************************************************
405  *           PtVisible32    (GDI32.279)
406  */
407 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
408 {
409     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
410     if (!dc) return ERROR;    
411
412     TRACE(clipping, "%04x %d,%d\n", hdc, x, y );
413     if (!dc->w.hGCClipRgn) return FALSE;
414
415     if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
416     dc->w.flags &= ~DC_DIRTY;
417
418     return PtInRegion( dc->w.hGCClipRgn, XLPTODP(dc,x) + dc->w.DCOrgX, 
419                                            YLPTODP(dc,y) + dc->w.DCOrgY );
420 }
421
422
423 /***********************************************************************
424  *           RectVisible16    (GDI.104)
425  */
426 BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect )
427 {
428     RECT16 tmpRect;
429     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
430     if (!dc) return FALSE;
431     TRACE(clipping,"%04x %d,%dx%d,%d\n",
432                      hdc, rect->left, rect->top, rect->right, rect->bottom );
433     if (!dc->w.hGCClipRgn) return FALSE;
434     /* copy rectangle to avoid overwriting by LPtoDP */
435     tmpRect = *rect;
436     LPtoDP16( hdc, (LPPOINT16)&tmpRect, 2 );
437     OffsetRect16( &tmpRect, dc->w.DCOrgX, dc->w.DCOrgY );
438     return RectInRegion16( dc->w.hGCClipRgn, &tmpRect );
439 }
440
441
442 /***********************************************************************
443  *           RectVisible32    (GDI32.282)
444  */
445 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
446 {
447     RECT16 rect16;
448     CONV_RECT32TO16( rect, &rect16 );
449     return RectVisible16( (HDC16)hdc, &rect16 );
450 }
451
452
453 /***********************************************************************
454  *           GetClipBox16    (GDI.77)
455  */
456 INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
457 {
458     int ret;
459     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
460     if (!dc) return ERROR;    
461     ret = GetRgnBox16( dc->w.hGCClipRgn, rect );
462     OffsetRect16( rect, -dc->w.DCOrgX, -dc->w.DCOrgY );
463     DPtoLP16( hdc, (LPPOINT16)rect, 2 );
464     TRACE(clipping, "%d,%d-%d,%d\n", 
465             rect->left,rect->top,rect->right,rect->bottom );
466     return ret;
467 }
468
469
470 /***********************************************************************
471  *           GetClipBox32    (GDI32.162)
472  */
473 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
474 {
475     INT ret;
476     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
477     if (!dc) return ERROR;    
478     ret = GetRgnBox( dc->w.hGCClipRgn, rect );
479     OffsetRect( rect, -dc->w.DCOrgX, -dc->w.DCOrgY );
480     DPtoLP( hdc, (LPPOINT)rect, 2 );
481     return ret;
482 }
483
484
485 /***********************************************************************
486  *           GetClipRgn32  (GDI32.163)
487  */
488 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
489 {
490     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
491     if( dc && hRgn )
492     {
493       if( dc->w.hClipRgn )
494       { 
495         /* this assumes that dc->w.hClipRgn is in coordinates
496            relative to the device (not DC origin) */
497
498         if( CombineRgn(hRgn, dc->w.hClipRgn, 0, RGN_COPY) != ERROR )
499         {
500             OffsetRgn( hRgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
501             return 1;
502         }
503       }
504       else return 0;
505     }
506     return -1;
507 }
508
509 /***********************************************************************
510  *           SaveVisRgn    (GDI.129)
511  */
512 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc )
513 {
514     HRGN copy;
515     RGNOBJ *obj, *copyObj;
516     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
517     if (!dc) return 0;
518     TRACE(clipping, "%04x\n", hdc );
519     if (!dc->w.hVisRgn)
520     {
521         ERR(region, "hVisRgn is zero. Please report this.\n" );
522         exit(1);
523     }
524     if( dc->w.flags & DC_DIRTY ) UPDATE_DIRTY_DC(dc);
525     dc->w.flags &= ~DC_DIRTY;
526
527     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
528     {
529         GDI_HEAP_UNLOCK( hdc );
530         return 0;
531     }
532     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
533     {
534         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
535         GDI_HEAP_UNLOCK( hdc );
536         return 0;
537     }  
538     CombineRgn( copy, dc->w.hVisRgn, 0, RGN_COPY );
539     if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC )))
540     {
541         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
542         GDI_HEAP_UNLOCK( hdc );
543         return 0;
544     }
545     copyObj->header.hNext = obj->header.hNext;
546     obj->header.hNext = copy;
547     GDI_HEAP_UNLOCK( dc->w.hVisRgn );
548     GDI_HEAP_UNLOCK( hdc );
549     GDI_HEAP_UNLOCK( copy );
550     return copy;
551 }
552
553
554 /***********************************************************************
555  *           RestoreVisRgn    (GDI.130)
556  */
557 INT16 WINAPI RestoreVisRgn16( HDC16 hdc )
558 {
559     HRGN saved;
560     RGNOBJ *obj, *savedObj;
561     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
562     INT16 ret;
563
564     if (!dc) return ERROR;    
565     if (!dc->w.hVisRgn)
566     {
567         GDI_HEAP_UNLOCK( hdc );
568         return ERROR;    
569     }
570     TRACE(clipping, "%04x\n", hdc );
571     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hVisRgn, REGION_MAGIC )))
572     {
573         GDI_HEAP_UNLOCK( hdc );
574         return ERROR;
575     }
576     if (!(saved = obj->header.hNext)) 
577     {
578         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
579         GDI_HEAP_UNLOCK( hdc );
580         return ERROR;
581     }
582     if (!(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC )))
583     {
584         GDI_HEAP_UNLOCK( dc->w.hVisRgn );
585         GDI_HEAP_UNLOCK( hdc );
586         return ERROR;
587     }
588     DeleteObject( dc->w.hVisRgn );
589     dc->w.hVisRgn = saved;
590     CLIPPING_UpdateGCRegion( dc );
591     GDI_HEAP_UNLOCK( hdc );
592     ret = savedObj->rgn->type; /* FIXME */
593     GDI_HEAP_UNLOCK( saved );
594     return ret;
595 }