Added regedit unit test, a couple minor changes to regedit.
[wine] / objects / clipping.c
1 /*
2  * DC clipping functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdlib.h>
22 #include "windef.h"
23 #include "wingdi.h"
24 #include "wine/winuser16.h"
25 #include "gdi.h"
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
29
30
31 /***********************************************************************
32  *           CLIPPING_UpdateGCRegion
33  *
34  * Update the GC clip region when the ClipRgn or VisRgn have changed.
35  */
36 void CLIPPING_UpdateGCRegion( DC * dc )
37 {
38     if (!dc->hGCClipRgn) dc->hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 );
39
40     if (!dc->hVisRgn)
41     {
42         ERR("hVisRgn is zero. Please report this.\n" );
43         exit(1);
44     }
45
46     if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
47
48     if (!dc->hClipRgn)
49         CombineRgn( dc->hGCClipRgn, dc->hVisRgn, 0, RGN_COPY );
50     else
51         CombineRgn(dc->hGCClipRgn, dc->hClipRgn, dc->hVisRgn, RGN_AND);
52     if (dc->funcs->pSetDeviceClipping)
53         dc->funcs->pSetDeviceClipping( dc->physDev, dc->hGCClipRgn );
54 }
55
56
57 /***********************************************************************
58  *           SelectClipRgn    (GDI.44)
59  */
60 INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn )
61 {
62     return (INT16)SelectClipRgn( hdc, hrgn );
63 }
64
65
66 /***********************************************************************
67  *           SelectClipRgn    (GDI32.@)
68  */
69 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
70 {
71     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
72 }
73
74 /******************************************************************************
75  *              ExtSelectClipRgn        [GDI.508]
76  */
77 INT16 WINAPI ExtSelectClipRgn16( HDC16 hdc, HRGN16 hrgn, INT16 fnMode )
78 {
79   return (INT16) ExtSelectClipRgn((HDC) hdc, (HRGN) hrgn, fnMode);
80 }
81
82 /******************************************************************************
83  *              ExtSelectClipRgn        [GDI32.@]
84  */
85 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
86 {
87     INT retval;
88     DC * dc = DC_GetDCUpdate( hdc );
89     if (!dc) return ERROR;
90
91     TRACE("%04x %04x %d\n", hdc, hrgn, fnMode );
92
93     if (dc->funcs->pExtSelectClipRgn)
94     {
95         retval = dc->funcs->pExtSelectClipRgn( dc->physDev, hrgn, fnMode );
96         GDI_ReleaseObj( hdc );
97         return retval;
98     }
99
100     if (!hrgn)
101     {
102         if (fnMode == RGN_COPY)
103         {
104             if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
105             dc->hClipRgn = 0;
106             retval = SIMPLEREGION; /* Clip region == whole DC */
107         }
108         else
109         {
110             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
111             GDI_ReleaseObj( hdc );
112             return ERROR;
113         }
114     }
115     else
116     {
117         if (!dc->hClipRgn)
118         {
119             RECT rect;
120             GetRgnBox( dc->hVisRgn, &rect );
121             dc->hClipRgn = CreateRectRgnIndirect( &rect );
122         }
123
124         if(fnMode == RGN_COPY)
125             retval = CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
126         else
127             retval = CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
128     }
129
130     CLIPPING_UpdateGCRegion( dc );
131     GDI_ReleaseObj( hdc );
132     return retval;
133 }
134
135 /***********************************************************************
136  *           SelectVisRgn    (GDI.105)
137  */
138 INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn )
139 {
140     int retval;
141     DC * dc;
142
143     if (!hrgn) return ERROR;
144     if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
145
146     TRACE("%04x %04x\n", hdc, hrgn );
147
148     dc->flags &= ~DC_DIRTY;
149
150     retval = CombineRgn16( dc->hVisRgn, hrgn, 0, RGN_COPY );
151     CLIPPING_UpdateGCRegion( dc );
152     GDI_ReleaseObj( hdc );
153     return retval;
154 }
155
156
157 /***********************************************************************
158  *           OffsetClipRgn    (GDI.32)
159  */
160 INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y )
161 {
162     return (INT16)OffsetClipRgn( hdc, x, y );
163 }
164
165
166 /***********************************************************************
167  *           OffsetClipRgn    (GDI32.@)
168  */
169 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
170 {
171     INT ret = SIMPLEREGION;
172     DC *dc = DC_GetDCUpdate( hdc );
173     if (!dc) return ERROR;
174
175     TRACE("%04x %d,%d\n", hdc, x, y );
176
177     if(dc->funcs->pOffsetClipRgn)
178         ret = dc->funcs->pOffsetClipRgn( dc->physDev, x, y );
179     else if (dc->hClipRgn) {
180         ret = OffsetRgn( dc->hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y));
181         CLIPPING_UpdateGCRegion( dc );
182     }
183     GDI_ReleaseObj( hdc );
184     return ret;
185 }
186
187
188 /***********************************************************************
189  *           OffsetVisRgn    (GDI.102)
190  */
191 INT16 WINAPI OffsetVisRgn16( HDC16 hdc, INT16 x, INT16 y )
192 {
193     INT16 retval;
194     DC * dc = DC_GetDCUpdate( hdc );
195     if (!dc) return ERROR;
196     TRACE("%04x %d,%d\n", hdc, x, y );
197     retval = OffsetRgn( dc->hVisRgn, x, y );
198     CLIPPING_UpdateGCRegion( dc );
199     GDI_ReleaseObj( hdc );
200     return retval;
201 }
202
203
204 /***********************************************************************
205  *           ExcludeClipRect    (GDI.21)
206  */
207 INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top,
208                                 INT16 right, INT16 bottom )
209 {
210     return (INT16)ExcludeClipRect( hdc, left, top, right, bottom );
211 }
212
213
214 /***********************************************************************
215  *           ExcludeClipRect    (GDI32.@)
216  */
217 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
218                                 INT right, INT bottom )
219 {
220     HRGN newRgn;
221     INT ret;
222     DC *dc = DC_GetDCUpdate( hdc );
223     if (!dc) return ERROR;
224
225     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
226
227     if(dc->funcs->pExcludeClipRect)
228         ret = dc->funcs->pExcludeClipRect( dc->physDev, left, top, right, bottom );
229     else
230     {
231         left   = XLPTODP( dc, left );
232         right  = XLPTODP( dc, right );
233         top    = YLPTODP( dc, top );
234         bottom = YLPTODP( dc, bottom );
235
236         if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) ret = ERROR;
237         else
238         {
239             if (!dc->hClipRgn)
240             {
241                 dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
242                 CombineRgn( dc->hClipRgn, dc->hVisRgn, 0, RGN_COPY );
243             }
244             ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_DIFF );
245             DeleteObject( newRgn );
246         }
247         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
248     }
249     GDI_ReleaseObj( hdc );
250     return ret;
251 }
252
253
254 /***********************************************************************
255  *           IntersectClipRect    (GDI.22)
256  */
257 INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
258                                   INT16 right, INT16 bottom )
259 {
260     return (INT16)IntersectClipRect( hdc, left, top, right, bottom );
261 }
262
263
264 /***********************************************************************
265  *           IntersectClipRect    (GDI32.@)
266  */
267 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top,
268                                   INT right, INT bottom )
269 {
270     INT ret;
271     DC *dc = DC_GetDCUpdate( hdc );
272     if (!dc) return ERROR;
273
274     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
275
276     if(dc->funcs->pIntersectClipRect)
277         ret = dc->funcs->pIntersectClipRect( dc->physDev, left, top, right, bottom );
278     else
279     {
280         left   = XLPTODP( dc, left );
281         right  = XLPTODP( dc, right );
282         top    = YLPTODP( dc, top );
283         bottom = YLPTODP( dc, bottom );
284
285         if (!dc->hClipRgn)
286         {
287             dc->hClipRgn = CreateRectRgn( left, top, right, bottom );
288             ret = SIMPLEREGION;
289         }
290         else
291         {
292             HRGN newRgn;
293
294             if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) ret = ERROR;
295             else
296             {
297                 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND );
298                 DeleteObject( newRgn );
299             }
300         }
301         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
302     }
303     GDI_ReleaseObj( hdc );
304     return ret;
305 }
306
307
308 /***********************************************************************
309  *           ExcludeVisRect    (GDI.73)
310  */
311 INT16 WINAPI ExcludeVisRect16( HDC16 hdc, INT16 left, INT16 top,
312                              INT16 right, INT16 bottom )
313 {
314     HRGN tempRgn;
315     INT16 ret;
316     DC * dc = DC_GetDCUpdate( hdc );
317     if (!dc) return ERROR;
318
319     left   = XLPTODP( dc, left );
320     right  = XLPTODP( dc, right );
321     top    = YLPTODP( dc, top );
322     bottom = YLPTODP( dc, bottom );
323
324     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
325
326     if (!(tempRgn = CreateRectRgn( left, top, right, bottom ))) ret = ERROR;
327     else
328     {
329         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_DIFF );
330         DeleteObject( tempRgn );
331     }
332     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
333     GDI_ReleaseObj( hdc );
334     return ret;
335 }
336
337
338 /***********************************************************************
339  *           IntersectVisRect    (GDI.98)
340  */
341 INT16 WINAPI IntersectVisRect16( HDC16 hdc, INT16 left, INT16 top,
342                                INT16 right, INT16 bottom )
343 {
344     HRGN tempRgn;
345     INT16 ret;
346     DC * dc = DC_GetDCUpdate( hdc );
347     if (!dc) return ERROR;
348
349     left   = XLPTODP( dc, left );
350     right  = XLPTODP( dc, right );
351     top    = YLPTODP( dc, top );
352     bottom = YLPTODP( dc, bottom );
353
354     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
355
356     if (!(tempRgn = CreateRectRgn( left, top, right, bottom ))) ret = ERROR;
357     else
358     {
359         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_AND );
360         DeleteObject( tempRgn );
361     }
362     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
363     GDI_ReleaseObj( hdc );
364     return ret;
365 }
366
367
368 /***********************************************************************
369  *           PtVisible    (GDI.103)
370  */
371 BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
372 {
373     return PtVisible( hdc, x, y );
374 }
375
376
377 /***********************************************************************
378  *           PtVisible    (GDI32.@)
379  */
380 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
381 {
382     BOOL ret = FALSE;
383     DC *dc = DC_GetDCUpdate( hdc );
384
385     TRACE("%04x %d,%d\n", hdc, x, y );
386     if (!dc) return FALSE;
387     if (dc->hGCClipRgn)
388     {
389         ret = PtInRegion( dc->hGCClipRgn, XLPTODP(dc,x), YLPTODP(dc,y) );
390     }
391     GDI_ReleaseObj( hdc );
392     return ret;
393 }
394
395
396 /***********************************************************************
397  *           RectVisible    (GDI.465)
398  *           RectVisibleOld (GDI.104)
399  */
400 BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect16 )
401 {
402     RECT rect;
403     CONV_RECT16TO32( rect16, &rect );
404     return RectVisible( hdc, &rect );
405 }
406
407
408 /***********************************************************************
409  *           RectVisible    (GDI32.@)
410  */
411 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
412 {
413     BOOL ret = FALSE;
414     RECT tmpRect;
415     DC *dc = DC_GetDCUpdate( hdc );
416     if (!dc) return FALSE;
417     TRACE("%04x %d,%dx%d,%d\n",
418           hdc, rect->left, rect->top, rect->right, rect->bottom );
419     if (dc->hGCClipRgn)
420     {
421         /* copy rectangle to avoid overwriting by LPtoDP */
422         tmpRect = *rect;
423         LPtoDP( hdc, (LPPOINT)&tmpRect, 2 );
424         ret = RectInRegion( dc->hGCClipRgn, &tmpRect );
425     }
426     GDI_ReleaseObj( hdc );
427     return ret;
428 }
429
430
431 /***********************************************************************
432  *           GetClipBox    (GDI.77)
433  */
434 INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
435 {
436     int ret;
437     DC *dc = DC_GetDCUpdate( hdc );
438     if (!dc) return ERROR;
439     ret = GetRgnBox16( dc->hGCClipRgn, rect );
440     DPtoLP16( hdc, (LPPOINT16)rect, 2 );
441     TRACE("%d,%d-%d,%d\n", rect->left,rect->top,rect->right,rect->bottom );
442     GDI_ReleaseObj( hdc );
443     return ret;
444 }
445
446
447 /***********************************************************************
448  *           GetClipBox    (GDI32.@)
449  */
450 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
451 {
452     INT ret;
453     DC *dc = DC_GetDCUpdate( hdc );
454     if (!dc) return ERROR;
455     ret = GetRgnBox( dc->hGCClipRgn, rect );
456     DPtoLP( hdc, (LPPOINT)rect, 2 );
457     GDI_ReleaseObj( hdc );
458     return ret;
459 }
460
461
462 /***********************************************************************
463  *           GetClipRgn  (GDI32.@)
464  */
465 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
466 {
467     INT ret = -1;
468     DC * dc;
469     if (hRgn && (dc = DC_GetDCPtr( hdc )))
470     {
471       if( dc->hClipRgn )
472       {
473           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1;
474       }
475       else ret = 0;
476       GDI_ReleaseObj( hdc );
477     }
478     return ret;
479 }
480
481 /***********************************************************************
482  *           SaveVisRgn    (GDI.129)
483  */
484 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc )
485 {
486     HRGN copy;
487     GDIOBJHDR *obj, *copyObj;
488     DC *dc = DC_GetDCUpdate( hdc );
489
490     if (!dc) return 0;
491     TRACE("%04x\n", hdc );
492
493     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC )))
494     {
495         GDI_ReleaseObj( hdc );
496         return 0;
497     }
498     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
499     {
500         GDI_ReleaseObj( dc->hVisRgn );
501         GDI_ReleaseObj( hdc );
502         return 0;
503     }
504     CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY );
505     if (!(copyObj = GDI_GetObjPtr( copy, REGION_MAGIC )))
506     {
507         DeleteObject( copy );
508         GDI_ReleaseObj( dc->hVisRgn );
509         GDI_ReleaseObj( hdc );
510         return 0;
511     }
512     copyObj->hNext = obj->hNext;
513     obj->hNext = copy;
514     GDI_ReleaseObj( copy );
515     GDI_ReleaseObj( dc->hVisRgn );
516     GDI_ReleaseObj( hdc );
517     return copy;
518 }
519
520
521 /***********************************************************************
522  *           RestoreVisRgn    (GDI.130)
523  */
524 INT16 WINAPI RestoreVisRgn16( HDC16 hdc )
525 {
526     HRGN saved;
527     GDIOBJHDR *obj, *savedObj;
528     DC *dc = DC_GetDCPtr( hdc );
529     INT16 ret = ERROR;
530
531     if (!dc) return ERROR;
532
533     TRACE("%04x\n", hdc );
534
535     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done;
536     saved = obj->hNext;
537
538     if ((savedObj = GDI_GetObjPtr( saved, REGION_MAGIC )))
539     {
540         ret = CombineRgn( dc->hVisRgn, saved, 0, RGN_COPY );
541         obj->hNext = savedObj->hNext;
542         GDI_ReleaseObj( saved );
543         DeleteObject( saved );
544         dc->flags &= ~DC_DIRTY;
545         CLIPPING_UpdateGCRegion( dc );
546     }
547     GDI_ReleaseObj( dc->hVisRgn );
548  done:
549     GDI_ReleaseObj( hdc );
550     return ret;
551 }