2 * DC clipping functions
4 * Copyright 1993 Alexandre Julliard
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.
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.
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
27 #include "gdi_private.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(clipping
);
33 /***********************************************************************
36 * Return the total clip region (if any).
38 static inline HRGN
get_clip_region( DC
* dc
)
40 if (dc
->hMetaClipRgn
) return dc
->hMetaClipRgn
;
41 if (dc
->hMetaRgn
) return dc
->hMetaRgn
;
46 /***********************************************************************
47 * CLIPPING_UpdateGCRegion
49 * Update the GC clip region when the ClipRgn or VisRgn have changed.
51 void CLIPPING_UpdateGCRegion( DC
* dc
)
57 ERR("hVisRgn is zero. Please report this.\n" );
61 if (dc
->flags
& DC_DIRTY
) ERR( "DC is dirty. Please report this.\n" );
63 /* update the intersection of meta and clip regions */
64 if (dc
->hMetaRgn
&& dc
->hClipRgn
)
66 if (!dc
->hMetaClipRgn
) dc
->hMetaClipRgn
= CreateRectRgn( 0, 0, 0, 0 );
67 CombineRgn( dc
->hMetaClipRgn
, dc
->hClipRgn
, dc
->hMetaRgn
, RGN_AND
);
68 clip_rgn
= dc
->hMetaClipRgn
;
70 else /* only one is set, no need for an intersection */
72 if (dc
->hMetaClipRgn
) DeleteObject( dc
->hMetaClipRgn
);
74 clip_rgn
= dc
->hMetaRgn
? dc
->hMetaRgn
: dc
->hClipRgn
;
77 if (dc
->funcs
->pSetDeviceClipping
)
78 dc
->funcs
->pSetDeviceClipping( dc
->physDev
, dc
->hVisRgn
, clip_rgn
);
81 /***********************************************************************
82 * create_default_clip_region
84 * Create a default clipping region when none already exists.
86 static inline void create_default_clip_region( DC
* dc
)
90 if (GDIMAGIC( dc
->header
.wMagic
) == MEMORY_DC_MAGIC
)
94 GetObjectW( dc
->hBitmap
, sizeof(bitmap
), &bitmap
);
95 width
= bitmap
.bmWidth
;
96 height
= bitmap
.bmHeight
;
100 width
= GetDeviceCaps( dc
->hSelf
, DESKTOPHORZRES
);
101 height
= GetDeviceCaps( dc
->hSelf
, DESKTOPVERTRES
);
103 dc
->hClipRgn
= CreateRectRgn( 0, 0, width
, height
);
107 /***********************************************************************
108 * SelectClipRgn (GDI32.@)
110 INT WINAPI
SelectClipRgn( HDC hdc
, HRGN hrgn
)
112 return ExtSelectClipRgn( hdc
, hrgn
, RGN_COPY
);
116 /******************************************************************************
117 * ExtSelectClipRgn [GDI32.@]
119 INT WINAPI
ExtSelectClipRgn( HDC hdc
, HRGN hrgn
, INT fnMode
)
123 DC
* dc
= DC_GetDCUpdate( hdc
);
124 if (!dc
) return ERROR
;
126 TRACE("%p %p %d\n", hdc
, hrgn
, fnMode
);
128 if (dc
->funcs
->pExtSelectClipRgn
)
130 retval
= dc
->funcs
->pExtSelectClipRgn( dc
->physDev
, hrgn
, fnMode
);
131 DC_ReleaseDCPtr( dc
);
137 if (fnMode
== RGN_COPY
)
139 if (dc
->hClipRgn
) DeleteObject( dc
->hClipRgn
);
144 FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode
);
145 DC_ReleaseDCPtr( dc
);
152 create_default_clip_region( dc
);
154 if(fnMode
== RGN_COPY
)
155 CombineRgn( dc
->hClipRgn
, hrgn
, 0, fnMode
);
157 CombineRgn( dc
->hClipRgn
, dc
->hClipRgn
, hrgn
, fnMode
);
160 CLIPPING_UpdateGCRegion( dc
);
161 DC_ReleaseDCPtr( dc
);
163 return GetClipBox(hdc
, &rect
);
166 /***********************************************************************
167 * SelectVisRgn (GDI.105)
169 INT16 WINAPI
SelectVisRgn16( HDC16 hdc16
, HRGN16 hrgn
)
172 HDC hdc
= HDC_32( hdc16
);
175 if (!hrgn
) return ERROR
;
176 if (!(dc
= DC_GetDCPtr( hdc
))) return ERROR
;
178 TRACE("%p %04x\n", hdc
, hrgn
);
180 dc
->flags
&= ~DC_DIRTY
;
182 retval
= CombineRgn( dc
->hVisRgn
, HRGN_32(hrgn
), 0, RGN_COPY
);
183 CLIPPING_UpdateGCRegion( dc
);
184 DC_ReleaseDCPtr( dc
);
189 /***********************************************************************
190 * OffsetClipRgn (GDI32.@)
192 INT WINAPI
OffsetClipRgn( HDC hdc
, INT x
, INT y
)
194 INT ret
= SIMPLEREGION
;
195 DC
*dc
= DC_GetDCUpdate( hdc
);
196 if (!dc
) return ERROR
;
198 TRACE("%p %d,%d\n", hdc
, x
, y
);
200 if(dc
->funcs
->pOffsetClipRgn
)
202 ret
= dc
->funcs
->pOffsetClipRgn( dc
->physDev
, x
, y
);
203 /* FIXME: ret is just a success flag, we should return a proper value */
205 else if (dc
->hClipRgn
) {
206 ret
= OffsetRgn( dc
->hClipRgn
, MulDiv( x
, dc
->vportExtX
, dc
->wndExtX
),
207 MulDiv( y
, dc
->vportExtY
, dc
->wndExtY
) );
208 CLIPPING_UpdateGCRegion( dc
);
210 DC_ReleaseDCPtr( dc
);
215 /***********************************************************************
216 * OffsetVisRgn (GDI.102)
218 INT16 WINAPI
OffsetVisRgn16( HDC16 hdc16
, INT16 x
, INT16 y
)
221 HDC hdc
= HDC_32( hdc16
);
222 DC
* dc
= DC_GetDCUpdate( hdc
);
223 if (!dc
) return ERROR
;
224 TRACE("%p %d,%d\n", hdc
, x
, y
);
225 retval
= OffsetRgn( dc
->hVisRgn
, x
, y
);
226 CLIPPING_UpdateGCRegion( dc
);
227 DC_ReleaseDCPtr( dc
);
232 /***********************************************************************
233 * ExcludeClipRect (GDI32.@)
235 INT WINAPI
ExcludeClipRect( HDC hdc
, INT left
, INT top
,
236 INT right
, INT bottom
)
240 DC
*dc
= DC_GetDCUpdate( hdc
);
241 if (!dc
) return ERROR
;
243 TRACE("%p %dx%d,%dx%d\n", hdc
, left
, top
, right
, bottom
);
245 if(dc
->funcs
->pExcludeClipRect
)
247 ret
= dc
->funcs
->pExcludeClipRect( dc
->physDev
, left
, top
, right
, bottom
);
248 /* FIXME: ret is just a success flag, we should return a proper value */
258 LPtoDP( hdc
, pt
, 2 );
259 if (!(newRgn
= CreateRectRgn( pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
))) ret
= ERROR
;
263 create_default_clip_region( dc
);
264 ret
= CombineRgn( dc
->hClipRgn
, dc
->hClipRgn
, newRgn
, RGN_DIFF
);
265 DeleteObject( newRgn
);
267 if (ret
!= ERROR
) CLIPPING_UpdateGCRegion( dc
);
269 DC_ReleaseDCPtr( dc
);
274 /***********************************************************************
275 * IntersectClipRect (GDI32.@)
277 INT WINAPI
IntersectClipRect( HDC hdc
, INT left
, INT top
, INT right
, INT bottom
)
280 DC
*dc
= DC_GetDCUpdate( hdc
);
281 if (!dc
) return ERROR
;
283 TRACE("%p %d,%d - %d,%d\n", hdc
, left
, top
, right
, bottom
);
285 if(dc
->funcs
->pIntersectClipRect
)
287 ret
= dc
->funcs
->pIntersectClipRect( dc
->physDev
, left
, top
, right
, bottom
);
288 /* FIXME: ret is just a success flag, we should return a proper value */
299 LPtoDP( hdc
, pt
, 2 );
303 dc
->hClipRgn
= CreateRectRgn( pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
);
310 if (!(newRgn
= CreateRectRgn( pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
))) ret
= ERROR
;
313 ret
= CombineRgn( dc
->hClipRgn
, dc
->hClipRgn
, newRgn
, RGN_AND
);
314 DeleteObject( newRgn
);
317 if (ret
!= ERROR
) CLIPPING_UpdateGCRegion( dc
);
319 DC_ReleaseDCPtr( dc
);
324 /***********************************************************************
325 * ExcludeVisRect (GDI.73)
327 INT16 WINAPI
ExcludeVisRect16( HDC16 hdc16
, INT16 left
, INT16 top
, INT16 right
, INT16 bottom
)
332 HDC hdc
= HDC_32( hdc16
);
333 DC
* dc
= DC_GetDCUpdate( hdc
);
334 if (!dc
) return ERROR
;
341 LPtoDP( hdc
, pt
, 2 );
343 TRACE("%p %d,%d - %d,%d\n", hdc
, pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
);
345 if (!(tempRgn
= CreateRectRgn( pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
))) ret
= ERROR
;
348 ret
= CombineRgn( dc
->hVisRgn
, dc
->hVisRgn
, tempRgn
, RGN_DIFF
);
349 DeleteObject( tempRgn
);
351 if (ret
!= ERROR
) CLIPPING_UpdateGCRegion( dc
);
352 DC_ReleaseDCPtr( dc
);
357 /***********************************************************************
358 * IntersectVisRect (GDI.98)
360 INT16 WINAPI
IntersectVisRect16( HDC16 hdc16
, INT16 left
, INT16 top
, INT16 right
, INT16 bottom
)
365 HDC hdc
= HDC_32( hdc16
);
366 DC
* dc
= DC_GetDCUpdate( hdc
);
367 if (!dc
) return ERROR
;
374 LPtoDP( hdc
, pt
, 2 );
376 TRACE("%p %d,%d - %d,%d\n", hdc
, pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
);
379 if (!(tempRgn
= CreateRectRgn( pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
))) ret
= ERROR
;
382 ret
= CombineRgn( dc
->hVisRgn
, dc
->hVisRgn
, tempRgn
, RGN_AND
);
383 DeleteObject( tempRgn
);
385 if (ret
!= ERROR
) CLIPPING_UpdateGCRegion( dc
);
386 DC_ReleaseDCPtr( dc
);
391 /***********************************************************************
392 * PtVisible (GDI32.@)
394 BOOL WINAPI
PtVisible( HDC hdc
, INT x
, INT y
)
399 DC
*dc
= DC_GetDCUpdate( hdc
);
401 TRACE("%p %d,%d\n", hdc
, x
, y
);
402 if (!dc
) return FALSE
;
406 LPtoDP( hdc
, &pt
, 1 );
407 ret
= PtInRegion( dc
->hVisRgn
, pt
.x
, pt
.y
);
408 if (ret
&& (clip
= get_clip_region(dc
))) ret
= PtInRegion( clip
, pt
.x
, pt
.y
);
409 DC_ReleaseDCPtr( dc
);
414 /***********************************************************************
415 * RectVisible (GDI32.@)
417 BOOL WINAPI
RectVisible( HDC hdc
, const RECT
* rect
)
422 DC
*dc
= DC_GetDCUpdate( hdc
);
423 if (!dc
) return FALSE
;
424 TRACE("%p %d,%dx%d,%d\n", hdc
, rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
427 LPtoDP( hdc
, (POINT
*)&tmpRect
, 2 );
429 if ((clip
= get_clip_region(dc
)))
431 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
432 CombineRgn( hrgn
, dc
->hVisRgn
, clip
, RGN_AND
);
433 ret
= RectInRegion( hrgn
, &tmpRect
);
434 DeleteObject( hrgn
);
436 else ret
= RectInRegion( dc
->hVisRgn
, &tmpRect
);
437 DC_ReleaseDCPtr( dc
);
442 /***********************************************************************
443 * GetClipBox (GDI32.@)
445 INT WINAPI
GetClipBox( HDC hdc
, LPRECT rect
)
449 DC
*dc
= DC_GetDCUpdate( hdc
);
450 if (!dc
) return ERROR
;
451 if ((clip
= get_clip_region(dc
)))
453 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
454 CombineRgn( hrgn
, dc
->hVisRgn
, clip
, RGN_AND
);
455 ret
= GetRgnBox( hrgn
, rect
);
456 DeleteObject( hrgn
);
458 else ret
= GetRgnBox( dc
->hVisRgn
, rect
);
459 DPtoLP( hdc
, (LPPOINT
)rect
, 2 );
460 DC_ReleaseDCPtr( dc
);
465 /***********************************************************************
466 * GetClipRgn (GDI32.@)
468 INT WINAPI
GetClipRgn( HDC hdc
, HRGN hRgn
)
472 if (hRgn
&& (dc
= DC_GetDCPtr( hdc
)))
476 if( CombineRgn(hRgn
, dc
->hClipRgn
, 0, RGN_COPY
) != ERROR
) ret
= 1;
479 DC_ReleaseDCPtr( dc
);
485 /***********************************************************************
486 * GetMetaRgn (GDI32.@)
488 INT WINAPI
GetMetaRgn( HDC hdc
, HRGN hRgn
)
491 DC
* dc
= DC_GetDCPtr( hdc
);
495 if (dc
->hMetaRgn
&& CombineRgn( hRgn
, dc
->hMetaRgn
, 0, RGN_COPY
) != ERROR
)
497 DC_ReleaseDCPtr( dc
);
503 /***********************************************************************
504 * SaveVisRgn (GDI.129)
506 HRGN16 WINAPI
SaveVisRgn16( HDC16 hdc16
)
508 struct saved_visrgn
*saved
;
509 HDC hdc
= HDC_32( hdc16
);
510 DC
*dc
= DC_GetDCUpdate( hdc
);
515 if (!(saved
= HeapAlloc( GetProcessHeap(), 0, sizeof(*saved
) ))) goto error
;
516 if (!(saved
->hrgn
= CreateRectRgn( 0, 0, 0, 0 ))) goto error
;
517 CombineRgn( saved
->hrgn
, dc
->hVisRgn
, 0, RGN_COPY
);
518 saved
->next
= dc
->saved_visrgn
;
519 dc
->saved_visrgn
= saved
;
520 DC_ReleaseDCPtr( dc
);
521 return HRGN_16(saved
->hrgn
);
524 DC_ReleaseDCPtr( dc
);
525 HeapFree( GetProcessHeap(), 0, saved
);
530 /***********************************************************************
531 * RestoreVisRgn (GDI.130)
533 INT16 WINAPI
RestoreVisRgn16( HDC16 hdc16
)
535 struct saved_visrgn
*saved
;
536 HDC hdc
= HDC_32( hdc16
);
537 DC
*dc
= DC_GetDCPtr( hdc
);
540 if (!dc
) return ERROR
;
544 if (!(saved
= dc
->saved_visrgn
)) goto done
;
546 ret
= CombineRgn( dc
->hVisRgn
, saved
->hrgn
, 0, RGN_COPY
);
547 dc
->saved_visrgn
= saved
->next
;
548 DeleteObject( saved
->hrgn
);
549 HeapFree( GetProcessHeap(), 0, saved
);
550 dc
->flags
&= ~DC_DIRTY
;
551 CLIPPING_UpdateGCRegion( dc
);
553 DC_ReleaseDCPtr( dc
);
558 /***********************************************************************
559 * GetRandomRgn [GDI32.@]
562 * This function is documented in MSDN online for the case of
563 * iCode == SYSRGN (4).
565 * For iCode == 1 it should return the clip region
566 * 2 " " " the meta region
567 * 3 " " " the intersection of the clip with
568 * the meta region (== 'Rao' region).
570 * See http://www.codeproject.com/gdi/cliprgnguide.asp
572 INT WINAPI
GetRandomRgn(HDC hDC
, HRGN hRgn
, INT iCode
)
575 DC
*dc
= DC_GetDCPtr( hDC
);
588 rgn
= dc
->hMetaClipRgn
;
589 if(!rgn
) rgn
= dc
->hClipRgn
;
590 if(!rgn
) rgn
= dc
->hMetaRgn
;
592 case SYSRGN
: /* == 4 */
596 WARN("Unknown code %d\n", iCode
);
597 DC_ReleaseDCPtr( dc
);
600 if (rgn
) CombineRgn( hRgn
, rgn
, 0, RGN_COPY
);
601 DC_ReleaseDCPtr( dc
);
603 /* On Windows NT/2000, the SYSRGN returned is in screen coordinates */
604 if (iCode
== SYSRGN
&& !(GetVersion() & 0x80000000))
607 GetDCOrgEx( hDC
, &org
);
608 OffsetRgn( hRgn
, org
.x
, org
.y
);
614 /***********************************************************************
615 * SetMetaRgn (GDI32.@)
617 INT WINAPI
SetMetaRgn( HDC hdc
)
621 DC
*dc
= DC_GetDCPtr( hdc
);
623 if (!dc
) return ERROR
;
625 if (dc
->hMetaClipRgn
)
627 /* the intersection becomes the new meta region */
628 DeleteObject( dc
->hMetaRgn
);
629 DeleteObject( dc
->hClipRgn
);
630 dc
->hMetaRgn
= dc
->hMetaClipRgn
;
632 dc
->hMetaClipRgn
= 0;
634 else if (dc
->hClipRgn
)
636 dc
->hMetaRgn
= dc
->hClipRgn
;
639 /* else nothing to do */
641 /* Note: no need to call CLIPPING_UpdateGCRegion, the overall clip region hasn't changed */
643 ret
= GetRgnBox( dc
->hMetaRgn
, &dummy
);
644 DC_ReleaseDCPtr( dc
);