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