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