mshtml: Get rid of PRUint16 type.
[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     PHYSDEV physdev;
254     INT retval;
255     DC * dc = get_dc_ptr( hdc );
256
257     TRACE("%p %p %d\n", hdc, hrgn, fnMode );
258
259     if (!dc) return ERROR;
260     update_dc( dc );
261     physdev = GET_DC_PHYSDEV( dc, pExtSelectClipRgn );
262     retval = physdev->funcs->pExtSelectClipRgn( physdev, hrgn, fnMode );
263     release_dc_ptr( dc );
264     return retval;
265 }
266
267 /***********************************************************************
268  *           __wine_set_visible_region   (GDI32.@)
269  */
270 void CDECL __wine_set_visible_region( HDC hdc, HRGN hrgn, const RECT *vis_rect, const RECT *device_rect,
271                                       struct window_surface *surface )
272 {
273     DC * dc;
274
275     if (!(dc = get_dc_ptr( hdc ))) return;
276
277     TRACE( "%p %p %s %s %p\n", hdc, hrgn,
278            wine_dbgstr_rect(vis_rect), wine_dbgstr_rect(device_rect), surface );
279
280     /* map region to DC coordinates */
281     OffsetRgn( hrgn, -vis_rect->left, -vis_rect->top );
282
283     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
284     dc->dirty = 0;
285     dc->vis_rect = *vis_rect;
286     dc->device_rect = *device_rect;
287     dc->hVisRgn = hrgn;
288     dibdrv_set_window_surface( dc, surface );
289     DC_UpdateXforms( dc );
290     update_dc_clipping( dc );
291     release_dc_ptr( dc );
292 }
293
294
295 /***********************************************************************
296  *           OffsetClipRgn    (GDI32.@)
297  */
298 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
299 {
300     PHYSDEV physdev;
301     INT ret;
302     DC *dc = get_dc_ptr( hdc );
303
304     TRACE("%p %d,%d\n", hdc, x, y );
305
306     if (!dc) return ERROR;
307     update_dc( dc );
308     physdev = GET_DC_PHYSDEV( dc, pOffsetClipRgn );
309     ret = physdev->funcs->pOffsetClipRgn( physdev, x, y );
310     release_dc_ptr( dc );
311     return ret;
312 }
313
314
315 /***********************************************************************
316  *           ExcludeClipRect    (GDI32.@)
317  */
318 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
319                                 INT right, INT bottom )
320 {
321     PHYSDEV physdev;
322     INT ret;
323     DC *dc = get_dc_ptr( hdc );
324
325     TRACE("%p %d,%d-%d,%d\n", hdc, left, top, right, bottom );
326
327     if (!dc) return ERROR;
328     update_dc( dc );
329     physdev = GET_DC_PHYSDEV( dc, pExcludeClipRect );
330     ret = physdev->funcs->pExcludeClipRect( physdev, left, top, right, bottom );
331     release_dc_ptr( dc );
332     return ret;
333 }
334
335
336 /***********************************************************************
337  *           IntersectClipRect    (GDI32.@)
338  */
339 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
340 {
341     PHYSDEV physdev;
342     INT ret;
343     DC *dc = get_dc_ptr( hdc );
344
345     TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
346
347     if (!dc) return ERROR;
348     update_dc( dc );
349     physdev = GET_DC_PHYSDEV( dc, pIntersectClipRect );
350     ret = physdev->funcs->pIntersectClipRect( physdev, left, top, right, bottom );
351     release_dc_ptr( dc );
352     return ret;
353 }
354
355
356 /***********************************************************************
357  *           PtVisible    (GDI32.@)
358  */
359 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
360 {
361     POINT pt;
362     RECT visrect;
363     BOOL ret;
364     DC *dc = get_dc_ptr( hdc );
365
366     TRACE("%p %d,%d\n", hdc, x, y );
367     if (!dc) return FALSE;
368
369     pt.x = x;
370     pt.y = y;
371     LPtoDP( hdc, &pt, 1 );
372     update_dc( dc );
373     ret = (!get_dc_device_rect( dc, &visrect ) ||
374            (pt.x >= visrect.left && pt.x < visrect.right &&
375             pt.y >= visrect.top && pt.y < visrect.bottom));
376     if (ret && get_dc_region( dc )) ret = PtInRegion( get_dc_region( dc ), pt.x, pt.y );
377     release_dc_ptr( dc );
378     return ret;
379 }
380
381
382 /***********************************************************************
383  *           RectVisible    (GDI32.@)
384  */
385 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
386 {
387     RECT tmpRect, visrect;
388     BOOL ret;
389     DC *dc = get_dc_ptr( hdc );
390     if (!dc) return FALSE;
391     TRACE("%p %s\n", hdc, wine_dbgstr_rect( rect ));
392
393     tmpRect = *rect;
394     LPtoDP( hdc, (POINT *)&tmpRect, 2 );
395     order_rect( &tmpRect );
396
397     update_dc( dc );
398     ret = (!get_dc_device_rect( dc, &visrect ) || intersect_rect( &visrect, &visrect, &tmpRect ));
399     if (ret && get_dc_region( dc )) ret = RectInRegion( get_dc_region( dc ), &tmpRect );
400     release_dc_ptr( dc );
401     return ret;
402 }
403
404
405 /***********************************************************************
406  *           GetClipBox    (GDI32.@)
407  */
408 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
409 {
410     RECT visrect;
411     INT ret;
412     DC *dc = get_dc_ptr( hdc );
413     if (!dc) return ERROR;
414
415     update_dc( dc );
416     if (get_dc_region( dc ))
417     {
418         ret = GetRgnBox( get_dc_region( dc ), rect );
419     }
420     else
421     {
422         ret = is_rect_empty( &dc->vis_rect ) ? ERROR : SIMPLEREGION;
423         *rect = dc->vis_rect;
424     }
425
426     if (get_dc_device_rect( dc, &visrect ) && !intersect_rect( rect, rect, &visrect )) ret = NULLREGION;
427
428     if (dc->layout & LAYOUT_RTL)
429     {
430         int tmp = rect->left;
431         rect->left = rect->right - 1;
432         rect->right = tmp - 1;
433     }
434     DPtoLP( hdc, (LPPOINT)rect, 2 );
435     release_dc_ptr( dc );
436     TRACE("%p => %d %s\n", hdc, ret, wine_dbgstr_rect( rect ));
437     return ret;
438 }
439
440
441 /***********************************************************************
442  *           GetClipRgn  (GDI32.@)
443  */
444 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
445 {
446     INT ret = -1;
447     DC * dc;
448     if ((dc = get_dc_ptr( hdc )))
449     {
450       if( dc->hClipRgn )
451       {
452           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR )
453           {
454               ret = 1;
455               if (dc->layout & LAYOUT_RTL)
456                   mirror_region( hRgn, hRgn, dc->vis_rect.right - dc->vis_rect.left );
457           }
458       }
459       else ret = 0;
460       release_dc_ptr( dc );
461     }
462     return ret;
463 }
464
465
466 /***********************************************************************
467  *           GetMetaRgn    (GDI32.@)
468  */
469 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
470 {
471     INT ret = 0;
472     DC * dc = get_dc_ptr( hdc );
473
474     if (dc)
475     {
476         if (dc->hMetaRgn && CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY ) != ERROR)
477         {
478             ret = 1;
479             if (dc->layout & LAYOUT_RTL)
480                 mirror_region( hRgn, hRgn, dc->vis_rect.right - dc->vis_rect.left );
481         }
482         release_dc_ptr( dc );
483     }
484     return ret;
485 }
486
487
488 /***********************************************************************
489  * GetRandomRgn [GDI32.@]
490  *
491  * NOTES
492  *     This function is documented in MSDN online for the case of
493  *     iCode == SYSRGN (4).
494  *
495  *     For iCode == 1 it should return the clip region
496  *                  2 "    "       "   the meta region
497  *                  3 "    "       "   the intersection of the clip with
498  *                                     the meta region (== 'Rao' region).
499  *
500  *     See http://www.codeproject.com/gdi/cliprgnguide.asp
501  */
502 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, INT iCode)
503 {
504     INT ret = 1;
505     DC *dc = get_dc_ptr( hDC );
506
507     if (!dc) return -1;
508
509     switch (iCode)
510     {
511     case 1:
512         if (dc->hClipRgn) CombineRgn( hRgn, dc->hClipRgn, 0, RGN_COPY );
513         else ret = 0;
514         break;
515     case 2:
516         if (dc->hMetaRgn) CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY );
517         else ret = 0;
518         break;
519     case 3:
520         if (dc->hClipRgn && dc->hMetaRgn) CombineRgn( hRgn, dc->hClipRgn, dc->hMetaRgn, RGN_AND );
521         else if (dc->hClipRgn) CombineRgn( hRgn, dc->hClipRgn, 0, RGN_COPY );
522         else if (dc->hMetaRgn) CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY );
523         else ret = 0;
524         break;
525     case SYSRGN: /* == 4 */
526         update_dc( dc );
527         if (dc->hVisRgn)
528         {
529             CombineRgn( hRgn, dc->hVisRgn, 0, RGN_COPY );
530             /* On Windows NT/2000, the SYSRGN returned is in screen coordinates */
531             if (!(GetVersion() & 0x80000000)) OffsetRgn( hRgn, dc->vis_rect.left, dc->vis_rect.top );
532         }
533         else if (!is_rect_empty( &dc->device_rect ))
534             SetRectRgn( hRgn, dc->device_rect.left, dc->device_rect.top,
535                         dc->device_rect.right, dc->device_rect.bottom );
536         else
537             ret = 0;
538         break;
539     default:
540         WARN("Unknown code %d\n", iCode);
541         ret = -1;
542         break;
543     }
544     release_dc_ptr( dc );
545     return ret;
546 }
547
548
549 /***********************************************************************
550  *           SetMetaRgn    (GDI32.@)
551  */
552 INT WINAPI SetMetaRgn( HDC hdc )
553 {
554     INT ret;
555     RECT dummy;
556     DC *dc = get_dc_ptr( hdc );
557
558     if (!dc) return ERROR;
559
560     if (dc->hClipRgn)
561     {
562         if (dc->hMetaRgn)
563         {
564             /* the intersection becomes the new meta region */
565             CombineRgn( dc->hMetaRgn, dc->hMetaRgn, dc->hClipRgn, RGN_AND );
566             DeleteObject( dc->hClipRgn );
567             dc->hClipRgn = 0;
568         }
569         else
570         {
571             dc->hMetaRgn = dc->hClipRgn;
572             dc->hClipRgn = 0;
573         }
574     }
575     /* else nothing to do */
576
577     /* Note: no need to call update_dc_clipping, the overall clip region hasn't changed */
578
579     ret = GetRgnBox( dc->hMetaRgn, &dummy );
580     release_dc_ptr( dc );
581     return ret;
582 }