Return value of ExtSelectClipRgn should consider visible region.
[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 "wownt32.h"
25 #include "wine/winuser16.h"
26 #include "gdi.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
30
31
32 /***********************************************************************
33  *           CLIPPING_UpdateGCRegion
34  *
35  * Update the GC clip region when the ClipRgn or VisRgn have changed.
36  */
37 void CLIPPING_UpdateGCRegion( DC * dc )
38 {
39     if (!dc->hGCClipRgn) dc->hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 );
40
41     if (!dc->hVisRgn)
42     {
43         ERR("hVisRgn is zero. Please report this.\n" );
44         exit(1);
45     }
46
47     if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
48
49     if (!dc->hClipRgn)
50         CombineRgn( dc->hGCClipRgn, dc->hVisRgn, 0, RGN_COPY );
51     else
52         CombineRgn(dc->hGCClipRgn, dc->hClipRgn, dc->hVisRgn, RGN_AND);
53     if (dc->funcs->pSetDeviceClipping)
54         dc->funcs->pSetDeviceClipping( dc->physDev, dc->hGCClipRgn );
55 }
56
57
58 /***********************************************************************
59  *           SelectClipRgn    (GDI32.@)
60  */
61 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
62 {
63     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
64 }
65
66
67 /******************************************************************************
68  *              ExtSelectClipRgn        [GDI32.@]
69  */
70 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
71 {
72     INT retval;
73     RECT rect;
74     DC * dc = DC_GetDCUpdate( hdc );
75     if (!dc) return ERROR;
76
77     TRACE("%p %p %d\n", hdc, hrgn, fnMode );
78
79     if (dc->funcs->pExtSelectClipRgn)
80     {
81         retval = dc->funcs->pExtSelectClipRgn( dc->physDev, hrgn, fnMode );
82         GDI_ReleaseObj( hdc );
83         return retval;
84     }
85
86     if (!hrgn)
87     {
88         if (fnMode == RGN_COPY)
89         {
90             if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
91             dc->hClipRgn = 0;
92         }
93         else
94         {
95             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
96             GDI_ReleaseObj( hdc );
97             return ERROR;
98         }
99     }
100     else
101     {
102         if (!dc->hClipRgn)
103         {
104             RECT rect;
105             GetRgnBox( dc->hVisRgn, &rect );
106             dc->hClipRgn = CreateRectRgnIndirect( &rect );
107         }
108
109         if(fnMode == RGN_COPY)
110             CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
111         else
112             CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
113     }
114
115     CLIPPING_UpdateGCRegion( dc );
116     GDI_ReleaseObj( hdc );
117
118     return GetClipBox(hdc, &rect);
119 }
120
121 /***********************************************************************
122  *           SelectVisRgn   (GDI.105)
123  */
124 INT16 WINAPI SelectVisRgn16( HDC16 hdc16, HRGN16 hrgn )
125 {
126     int retval;
127     HDC hdc = HDC_32( hdc16 );
128     DC * dc;
129
130     if (!hrgn) return ERROR;
131     if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
132
133     TRACE("%p %04x\n", hdc, hrgn );
134
135     dc->flags &= ~DC_DIRTY;
136
137     retval = CombineRgn( dc->hVisRgn, HRGN_32(hrgn), 0, RGN_COPY );
138     CLIPPING_UpdateGCRegion( dc );
139     GDI_ReleaseObj( hdc );
140     return retval;
141 }
142
143
144 /***********************************************************************
145  *           OffsetClipRgn    (GDI32.@)
146  */
147 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
148 {
149     INT ret = SIMPLEREGION;
150     DC *dc = DC_GetDCUpdate( hdc );
151     if (!dc) return ERROR;
152
153     TRACE("%p %d,%d\n", hdc, x, y );
154
155     if(dc->funcs->pOffsetClipRgn)
156         ret = dc->funcs->pOffsetClipRgn( dc->physDev, x, y );
157     else if (dc->hClipRgn) {
158         ret = OffsetRgn( dc->hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y));
159         CLIPPING_UpdateGCRegion( dc );
160     }
161     GDI_ReleaseObj( hdc );
162     return ret;
163 }
164
165
166 /***********************************************************************
167  *           OffsetVisRgn    (GDI.102)
168  */
169 INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y )
170 {
171     INT16 retval;
172     HDC hdc = HDC_32( hdc16 );
173     DC * dc = DC_GetDCUpdate( hdc );
174     if (!dc) return ERROR;
175     TRACE("%p %d,%d\n", hdc, x, y );
176     retval = OffsetRgn( dc->hVisRgn, x, y );
177     CLIPPING_UpdateGCRegion( dc );
178     GDI_ReleaseObj( hdc );
179     return retval;
180 }
181
182
183 /***********************************************************************
184  *           ExcludeClipRect    (GDI32.@)
185  */
186 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
187                                 INT right, INT bottom )
188 {
189     HRGN newRgn;
190     INT ret;
191     DC *dc = DC_GetDCUpdate( hdc );
192     if (!dc) return ERROR;
193
194     TRACE("%p %dx%d,%dx%d\n", hdc, left, top, right, bottom );
195
196     if(dc->funcs->pExcludeClipRect)
197         ret = dc->funcs->pExcludeClipRect( dc->physDev, left, top, right, bottom );
198     else
199     {
200         POINT pt[2];
201
202         pt[0].x = left;
203         pt[0].y = top;
204         pt[1].x = right;
205         pt[1].y = bottom;
206         LPtoDP( hdc, pt, 2 );
207         if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
208         else
209         {
210             if (!dc->hClipRgn)
211             {
212                 dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
213                 CombineRgn( dc->hClipRgn, dc->hVisRgn, 0, RGN_COPY );
214             }
215             ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_DIFF );
216             DeleteObject( newRgn );
217         }
218         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
219     }
220     GDI_ReleaseObj( hdc );
221     return ret;
222 }
223
224
225 /***********************************************************************
226  *           IntersectClipRect    (GDI32.@)
227  */
228 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
229 {
230     INT ret;
231     DC *dc = DC_GetDCUpdate( hdc );
232     if (!dc) return ERROR;
233
234     TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
235
236     if(dc->funcs->pIntersectClipRect)
237         ret = dc->funcs->pIntersectClipRect( dc->physDev, left, top, right, bottom );
238     else
239     {
240         POINT pt[2];
241
242         pt[0].x = left;
243         pt[0].y = top;
244         pt[1].x = right;
245         pt[1].y = bottom;
246
247         LPtoDP( hdc, pt, 2 );
248
249         if (!dc->hClipRgn)
250         {
251             dc->hClipRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y );
252             ret = SIMPLEREGION;
253         }
254         else
255         {
256             HRGN newRgn;
257
258             if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
259             else
260             {
261                 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND );
262                 DeleteObject( newRgn );
263             }
264         }
265         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
266     }
267     GDI_ReleaseObj( hdc );
268     return ret;
269 }
270
271
272 /***********************************************************************
273  *           ExcludeVisRect   (GDI.73)
274  */
275 INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
276 {
277     HRGN tempRgn;
278     INT16 ret;
279     POINT pt[2];
280     HDC hdc = HDC_32( hdc16 );
281     DC * dc = DC_GetDCUpdate( hdc );
282     if (!dc) return ERROR;
283
284     pt[0].x = left;
285     pt[0].y = top;
286     pt[1].x = right;
287     pt[1].y = bottom;
288
289     LPtoDP( hdc, pt, 2 );
290
291     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
292
293     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
294     else
295     {
296         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_DIFF );
297         DeleteObject( tempRgn );
298     }
299     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
300     GDI_ReleaseObj( hdc );
301     return ret;
302 }
303
304
305 /***********************************************************************
306  *           IntersectVisRect   (GDI.98)
307  */
308 INT16 WINAPI IntersectVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
309 {
310     HRGN tempRgn;
311     INT16 ret;
312     POINT pt[2];
313     HDC hdc = HDC_32( hdc16 );
314     DC * dc = DC_GetDCUpdate( hdc );
315     if (!dc) return ERROR;
316
317     pt[0].x = left;
318     pt[0].y = top;
319     pt[1].x = right;
320     pt[1].y = bottom;
321
322     LPtoDP( hdc, pt, 2 );
323
324     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
325
326
327     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
328     else
329     {
330         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_AND );
331         DeleteObject( tempRgn );
332     }
333     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
334     GDI_ReleaseObj( hdc );
335     return ret;
336 }
337
338
339 /***********************************************************************
340  *           PtVisible    (GDI32.@)
341  */
342 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
343 {
344     BOOL ret = FALSE;
345     DC *dc = DC_GetDCUpdate( hdc );
346
347     TRACE("%p %d,%d\n", hdc, x, y );
348     if (!dc) return FALSE;
349     if (dc->hGCClipRgn)
350     {
351         POINT pt;
352
353         pt.x = x;
354         pt.y = y;
355         LPtoDP( hdc, &pt, 1 );
356         ret = PtInRegion( dc->hGCClipRgn, pt.x, pt.y );
357     }
358     GDI_ReleaseObj( hdc );
359     return ret;
360 }
361
362
363 /***********************************************************************
364  *           RectVisible    (GDI32.@)
365  */
366 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
367 {
368     BOOL ret = FALSE;
369     DC *dc = DC_GetDCUpdate( hdc );
370     if (!dc) return FALSE;
371     TRACE("%p %ld,%ldx%ld,%ld\n", hdc, rect->left, rect->top, rect->right, rect->bottom );
372     if (dc->hGCClipRgn)
373     {
374         POINT pt[2];
375         RECT tmpRect;
376
377         pt[0].x = rect->left;
378         pt[0].y = rect->top;
379         pt[1].x = rect->right;
380         pt[1].y = rect->bottom;
381         LPtoDP( hdc, pt, 2 );
382         tmpRect.left    = pt[0].x;
383         tmpRect.top     = pt[0].y;
384         tmpRect.right   = pt[1].x;
385         tmpRect.bottom  = pt[1].y;
386         ret = RectInRegion( dc->hGCClipRgn, &tmpRect );
387     }
388     GDI_ReleaseObj( hdc );
389     return ret;
390 }
391
392
393 /***********************************************************************
394  *           GetClipBox    (GDI32.@)
395  */
396 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
397 {
398     INT ret;
399     DC *dc = DC_GetDCUpdate( hdc );
400     if (!dc) return ERROR;
401     ret = GetRgnBox( dc->hGCClipRgn, rect );
402     DPtoLP( hdc, (LPPOINT)rect, 2 );
403     GDI_ReleaseObj( hdc );
404     return ret;
405 }
406
407
408 /***********************************************************************
409  *           GetClipRgn  (GDI32.@)
410  */
411 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
412 {
413     INT ret = -1;
414     DC * dc;
415     if (hRgn && (dc = DC_GetDCPtr( hdc )))
416     {
417       if( dc->hClipRgn )
418       {
419           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1;
420       }
421       else ret = 0;
422       GDI_ReleaseObj( hdc );
423     }
424     return ret;
425 }
426
427 /***********************************************************************
428  *           SaveVisRgn   (GDI.129)
429  */
430 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc16 )
431 {
432     HRGN copy;
433     GDIOBJHDR *obj, *copyObj;
434     HDC hdc = HDC_32( hdc16 );
435     DC *dc = DC_GetDCUpdate( hdc );
436
437     if (!dc) return 0;
438     TRACE("%p\n", hdc );
439
440     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC )))
441     {
442         GDI_ReleaseObj( hdc );
443         return 0;
444     }
445     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
446     {
447         GDI_ReleaseObj( dc->hVisRgn );
448         GDI_ReleaseObj( hdc );
449         return 0;
450     }
451     CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY );
452     if (!(copyObj = GDI_GetObjPtr( copy, REGION_MAGIC )))
453     {
454         DeleteObject( copy );
455         GDI_ReleaseObj( dc->hVisRgn );
456         GDI_ReleaseObj( hdc );
457         return 0;
458     }
459     copyObj->hNext = obj->hNext;
460     obj->hNext = HRGN_16(copy);
461     GDI_ReleaseObj( copy );
462     GDI_ReleaseObj( dc->hVisRgn );
463     GDI_ReleaseObj( hdc );
464     return HRGN_16(copy);
465 }
466
467
468 /***********************************************************************
469  *           RestoreVisRgn   (GDI.130)
470  */
471 INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 )
472 {
473     HRGN saved;
474     GDIOBJHDR *obj, *savedObj;
475     HDC hdc = HDC_32( hdc16 );
476     DC *dc = DC_GetDCPtr( hdc );
477     INT16 ret = ERROR;
478
479     if (!dc) return ERROR;
480
481     TRACE("%p\n", hdc );
482
483     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done;
484     saved = HRGN_32(obj->hNext);
485
486     if ((savedObj = GDI_GetObjPtr( saved, REGION_MAGIC )))
487     {
488         ret = CombineRgn( dc->hVisRgn, saved, 0, RGN_COPY );
489         obj->hNext = savedObj->hNext;
490         GDI_ReleaseObj( saved );
491         DeleteObject( saved );
492         dc->flags &= ~DC_DIRTY;
493         CLIPPING_UpdateGCRegion( dc );
494     }
495     GDI_ReleaseObj( dc->hVisRgn );
496  done:
497     GDI_ReleaseObj( hdc );
498     return ret;
499 }