twain_32: Mark some functions static and other internal ones hidden.
[wine] / dlls / gdi32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "gdi_private.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
30
31
32 /***********************************************************************
33  *           get_clip_rect
34  *
35  * Compute a clip rectangle from its logical coordinates.
36  */
37 static inline RECT get_clip_rect( DC * dc, int left, int top, int right, int bottom )
38 {
39     RECT rect;
40
41     rect.left   = left;
42     rect.top    = top;
43     rect.right  = right;
44     rect.bottom = bottom;
45     LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
46     if (dc->layout & LAYOUT_RTL)
47     {
48         int tmp = rect.left;
49         rect.left = rect.right + 1;
50         rect.right = tmp + 1;
51     }
52     return rect;
53 }
54
55 /***********************************************************************
56  *           CLIPPING_UpdateGCRegion
57  *
58  * Update the GC clip region when the ClipRgn or VisRgn have changed.
59  */
60 void CLIPPING_UpdateGCRegion( DC * dc )
61 {
62     HRGN clip_rgn;
63     PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDeviceClipping );
64
65     /* update the intersection of meta and clip regions */
66     if (dc->hMetaRgn && dc->hClipRgn)
67     {
68         if (!dc->hMetaClipRgn) dc->hMetaClipRgn = CreateRectRgn( 0, 0, 0, 0 );
69         CombineRgn( dc->hMetaClipRgn, dc->hClipRgn, dc->hMetaRgn, RGN_AND );
70         clip_rgn = dc->hMetaClipRgn;
71     }
72     else  /* only one is set, no need for an intersection */
73     {
74         if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
75         dc->hMetaClipRgn = 0;
76         clip_rgn = dc->hMetaRgn ? dc->hMetaRgn : dc->hClipRgn;
77     }
78     physdev->funcs->pSetDeviceClipping( physdev, dc->hVisRgn, clip_rgn );
79 }
80
81 /***********************************************************************
82  *           create_default_clip_region
83  *
84  * Create a default clipping region when none already exists.
85  */
86 static inline void create_default_clip_region( DC * dc )
87 {
88     UINT width, height;
89
90     if (dc->header.type == OBJ_MEMDC)
91     {
92         BITMAP bitmap;
93
94         GetObjectW( dc->hBitmap, sizeof(bitmap), &bitmap );
95         width = bitmap.bmWidth;
96         height = bitmap.bmHeight;
97     }
98     else
99     {
100         width = GetDeviceCaps( dc->hSelf, DESKTOPHORZRES );
101         height = GetDeviceCaps( dc->hSelf, DESKTOPVERTRES );
102     }
103     dc->hClipRgn = CreateRectRgn( 0, 0, width, height );
104 }
105
106
107 /***********************************************************************
108  *           null driver fallback implementations
109  */
110
111 INT CDECL nulldrv_ExtSelectClipRgn( PHYSDEV dev, HRGN rgn, INT mode )
112 {
113     DC *dc = get_nulldrv_dc( dev );
114     INT ret;
115
116     if (!rgn)
117     {
118         if (mode != RGN_COPY)
119         {
120             FIXME("Unimplemented: hrgn NULL in mode: %d\n", mode);
121             return ERROR;
122         }
123         if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
124         dc->hClipRgn = 0;
125         ret = SIMPLEREGION;
126     }
127     else
128     {
129         HRGN mirrored = 0;
130
131         if (dc->layout & LAYOUT_RTL)
132         {
133             if (!(mirrored = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR;
134             mirror_region( mirrored, rgn, dc->vis_rect.right - dc->vis_rect.left );
135             rgn = mirrored;
136         }
137
138         if (!dc->hClipRgn)
139             create_default_clip_region( dc );
140
141         if (mode == RGN_COPY)
142             ret = CombineRgn( dc->hClipRgn, rgn, 0, mode );
143         else
144             ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, rgn, mode);
145
146         if (mirrored) DeleteObject( mirrored );
147     }
148     CLIPPING_UpdateGCRegion( dc );
149     return ret;
150 }
151
152 INT CDECL nulldrv_ExcludeClipRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
153 {
154     DC *dc = get_nulldrv_dc( dev );
155     RECT rect = get_clip_rect( dc, left, top, right, bottom );
156     INT ret;
157     HRGN rgn;
158
159     if (!(rgn = CreateRectRgnIndirect( &rect ))) return ERROR;
160     if (!dc->hClipRgn) create_default_clip_region( dc );
161     ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, rgn, RGN_DIFF );
162     DeleteObject( rgn );
163     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
164     return ret;
165 }
166
167 INT CDECL nulldrv_IntersectClipRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
168 {
169     DC *dc = get_nulldrv_dc( dev );
170     RECT rect = get_clip_rect( dc, left, top, right, bottom );
171     INT ret;
172     HRGN rgn;
173
174     if (!dc->hClipRgn)
175     {
176         dc->hClipRgn = CreateRectRgnIndirect( &rect );
177         ret = SIMPLEREGION;
178     }
179     else
180     {
181         if (!(rgn = CreateRectRgnIndirect( &rect ))) return ERROR;
182         ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, rgn, RGN_AND );
183         DeleteObject( rgn );
184     }
185     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
186     return ret;
187 }
188
189 INT CDECL nulldrv_OffsetClipRgn( PHYSDEV dev, INT x, INT y )
190 {
191     DC *dc = get_nulldrv_dc( dev );
192     INT ret = NULLREGION;
193
194     if (dc->hClipRgn)
195     {
196         x = MulDiv( x, dc->vportExtX, dc->wndExtX );
197         y = MulDiv( y, dc->vportExtY, dc->wndExtY );
198         if (dc->layout & LAYOUT_RTL) x = -x;
199         ret = OffsetRgn( dc->hClipRgn, x, y );
200         CLIPPING_UpdateGCRegion( dc );
201     }
202     return ret;
203 }
204
205
206 /***********************************************************************
207  *           SelectClipRgn    (GDI32.@)
208  */
209 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
210 {
211     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
212 }
213
214
215 /******************************************************************************
216  *              ExtSelectClipRgn        [GDI32.@]
217  */
218 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
219 {
220     INT retval = ERROR;
221     DC * dc = get_dc_ptr( hdc );
222
223     TRACE("%p %p %d\n", hdc, hrgn, fnMode );
224
225     if (dc)
226     {
227         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pExtSelectClipRgn );
228         update_dc( dc );
229         retval = physdev->funcs->pExtSelectClipRgn( physdev, hrgn, fnMode );
230         release_dc_ptr( dc );
231     }
232     return retval;
233 }
234
235 /***********************************************************************
236  *           __wine_set_visible_region   (GDI32.@)
237  */
238 void CDECL __wine_set_visible_region( HDC hdc, HRGN hrgn, const RECT *vis_rect )
239 {
240     DC * dc;
241
242     if (!(dc = get_dc_ptr( hdc ))) return;
243
244     TRACE( "%p %p %s\n", hdc, hrgn, wine_dbgstr_rect(vis_rect) );
245
246     /* map region to DC coordinates */
247     OffsetRgn( hrgn, -vis_rect->left, -vis_rect->top );
248
249     DeleteObject( dc->hVisRgn );
250     dc->dirty = 0;
251     dc->vis_rect = *vis_rect;
252     dc->hVisRgn = hrgn;
253     DC_UpdateXforms( dc );
254     CLIPPING_UpdateGCRegion( dc );
255     release_dc_ptr( dc );
256 }
257
258
259 /***********************************************************************
260  *           OffsetClipRgn    (GDI32.@)
261  */
262 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
263 {
264     INT ret = ERROR;
265     DC *dc = get_dc_ptr( hdc );
266
267     TRACE("%p %d,%d\n", hdc, x, y );
268
269     if (dc)
270     {
271         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pOffsetClipRgn );
272         update_dc( dc );
273         ret = physdev->funcs->pOffsetClipRgn( physdev, x, y );
274         release_dc_ptr( dc );
275     }
276     return ret;
277 }
278
279
280 /***********************************************************************
281  *           ExcludeClipRect    (GDI32.@)
282  */
283 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
284                                 INT right, INT bottom )
285 {
286     INT ret = ERROR;
287     DC *dc = get_dc_ptr( hdc );
288
289     TRACE("%p %d,%d-%d,%d\n", hdc, left, top, right, bottom );
290
291     if (dc)
292     {
293         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pExcludeClipRect );
294         update_dc( dc );
295         ret = physdev->funcs->pExcludeClipRect( physdev, left, top, right, bottom );
296         release_dc_ptr( dc );
297     }
298     return ret;
299 }
300
301
302 /***********************************************************************
303  *           IntersectClipRect    (GDI32.@)
304  */
305 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
306 {
307     INT ret = ERROR;
308     DC *dc = get_dc_ptr( hdc );
309
310     TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
311
312     if (dc)
313     {
314         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pIntersectClipRect );
315         update_dc( dc );
316         ret = physdev->funcs->pIntersectClipRect( physdev, left, top, right, bottom );
317         release_dc_ptr( dc );
318     }
319     return ret;
320 }
321
322
323 /***********************************************************************
324  *           PtVisible    (GDI32.@)
325  */
326 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
327 {
328     POINT pt;
329     BOOL ret;
330     HRGN clip;
331     DC *dc = get_dc_ptr( hdc );
332
333     TRACE("%p %d,%d\n", hdc, x, y );
334     if (!dc) return FALSE;
335
336     pt.x = x;
337     pt.y = y;
338     LPtoDP( hdc, &pt, 1 );
339     update_dc( dc );
340     ret = PtInRegion( dc->hVisRgn, pt.x, pt.y );
341     if (ret && (clip = get_clip_region(dc))) ret = PtInRegion( clip, pt.x, pt.y );
342     release_dc_ptr( dc );
343     return ret;
344 }
345
346
347 /***********************************************************************
348  *           RectVisible    (GDI32.@)
349  */
350 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
351 {
352     RECT tmpRect;
353     BOOL ret;
354     HRGN clip;
355     DC *dc = get_dc_ptr( hdc );
356     if (!dc) return FALSE;
357     TRACE("%p %s\n", hdc, wine_dbgstr_rect( rect ));
358
359     tmpRect = *rect;
360     LPtoDP( hdc, (POINT *)&tmpRect, 2 );
361
362     update_dc( dc );
363     if ((clip = get_clip_region(dc)))
364     {
365         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
366         CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
367         ret = RectInRegion( hrgn, &tmpRect );
368         DeleteObject( hrgn );
369     }
370     else ret = RectInRegion( dc->hVisRgn, &tmpRect );
371     release_dc_ptr( dc );
372     return ret;
373 }
374
375
376 /***********************************************************************
377  *           GetClipBox    (GDI32.@)
378  */
379 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
380 {
381     INT ret;
382     HRGN clip;
383     DC *dc = get_dc_ptr( hdc );
384     if (!dc) return ERROR;
385
386     update_dc( dc );
387     if ((clip = get_clip_region(dc)))
388     {
389         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
390         CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
391         ret = GetRgnBox( hrgn, rect );
392         DeleteObject( hrgn );
393     }
394     else ret = GetRgnBox( dc->hVisRgn, rect );
395     if (dc->layout & LAYOUT_RTL)
396     {
397         int tmp = rect->left;
398         rect->left = rect->right - 1;
399         rect->right = tmp - 1;
400     }
401     DPtoLP( hdc, (LPPOINT)rect, 2 );
402     release_dc_ptr( dc );
403     TRACE("%p => %d %s\n", hdc, ret, wine_dbgstr_rect( rect ));
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 ((dc = get_dc_ptr( hdc )))
416     {
417       if( dc->hClipRgn )
418       {
419           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR )
420           {
421               ret = 1;
422               if (dc->layout & LAYOUT_RTL)
423                   mirror_region( hRgn, hRgn, dc->vis_rect.right - dc->vis_rect.left );
424           }
425       }
426       else ret = 0;
427       release_dc_ptr( dc );
428     }
429     return ret;
430 }
431
432
433 /***********************************************************************
434  *           GetMetaRgn    (GDI32.@)
435  */
436 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
437 {
438     INT ret = 0;
439     DC * dc = get_dc_ptr( hdc );
440
441     if (dc)
442     {
443         if (dc->hMetaRgn && CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY ) != ERROR)
444         {
445             ret = 1;
446             if (dc->layout & LAYOUT_RTL)
447                 mirror_region( hRgn, hRgn, dc->vis_rect.right - dc->vis_rect.left );
448         }
449         release_dc_ptr( dc );
450     }
451     return ret;
452 }
453
454
455 /***********************************************************************
456  * GetRandomRgn [GDI32.@]
457  *
458  * NOTES
459  *     This function is documented in MSDN online for the case of
460  *     iCode == SYSRGN (4).
461  *
462  *     For iCode == 1 it should return the clip region
463  *                  2 "    "       "   the meta region
464  *                  3 "    "       "   the intersection of the clip with
465  *                                     the meta region (== 'Rao' region).
466  *
467  *     See http://www.codeproject.com/gdi/cliprgnguide.asp
468  */
469 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, INT iCode)
470 {
471     HRGN rgn;
472     DC *dc = get_dc_ptr( hDC );
473
474     if (!dc) return -1;
475
476     switch (iCode)
477     {
478     case 1:
479         rgn = dc->hClipRgn;
480         break;
481     case 2:
482         rgn = dc->hMetaRgn;
483         break;
484     case 3:
485         rgn = dc->hMetaClipRgn;
486         if(!rgn) rgn = dc->hClipRgn;
487         if(!rgn) rgn = dc->hMetaRgn;
488         break;
489     case SYSRGN: /* == 4 */
490         update_dc( dc );
491         rgn = dc->hVisRgn;
492         break;
493     default:
494         WARN("Unknown code %d\n", iCode);
495         release_dc_ptr( dc );
496         return -1;
497     }
498     if (rgn) CombineRgn( hRgn, rgn, 0, RGN_COPY );
499     release_dc_ptr( dc );
500
501     /* On Windows NT/2000, the SYSRGN returned is in screen coordinates */
502     if (iCode == SYSRGN && !(GetVersion() & 0x80000000))
503         OffsetRgn( hRgn, dc->vis_rect.left, dc->vis_rect.top );
504
505     return (rgn != 0);
506 }
507
508
509 /***********************************************************************
510  *           SetMetaRgn    (GDI32.@)
511  */
512 INT WINAPI SetMetaRgn( HDC hdc )
513 {
514     INT ret;
515     RECT dummy;
516     DC *dc = get_dc_ptr( hdc );
517
518     if (!dc) return ERROR;
519
520     if (dc->hMetaClipRgn)
521     {
522         /* the intersection becomes the new meta region */
523         DeleteObject( dc->hMetaRgn );
524         DeleteObject( dc->hClipRgn );
525         dc->hMetaRgn = dc->hMetaClipRgn;
526         dc->hClipRgn = 0;
527         dc->hMetaClipRgn = 0;
528     }
529     else if (dc->hClipRgn)
530     {
531         dc->hMetaRgn = dc->hClipRgn;
532         dc->hClipRgn = 0;
533     }
534     /* else nothing to do */
535
536     /* Note: no need to call CLIPPING_UpdateGCRegion, the overall clip region hasn't changed */
537
538     ret = GetRgnBox( dc->hMetaRgn, &dummy );
539     release_dc_ptr( dc );
540     return ret;
541 }