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
26 #include "gdi_private.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(clipping
);
32 /***********************************************************************
35 * Compute a clip rectangle from its logical coordinates.
37 static inline RECT
get_clip_rect( DC
* dc
, int left
, int top
, int right
, int bottom
)
45 LPtoDP( dc
->hSelf
, (POINT
*)&rect
, 2 );
46 if (dc
->layout
& LAYOUT_RTL
)
49 rect
.left
= rect
.right
+ 1;
55 /***********************************************************************
58 * Get the clipping rectangle in device coordinates.
60 int get_clip_box( DC
*dc
, RECT
*rect
)
63 HRGN rgn
, clip
= get_clip_region( dc
);
65 if (!clip
) return GetRgnBox( dc
->hVisRgn
, rect
);
67 if ((rgn
= CreateRectRgn( 0, 0, 0, 0 )))
69 CombineRgn( rgn
, dc
->hVisRgn
, clip
, RGN_AND
);
70 ret
= GetRgnBox( rgn
, rect
);
76 /***********************************************************************
77 * CLIPPING_UpdateGCRegion
79 * Update the GC clip region when the ClipRgn or VisRgn have changed.
81 void CLIPPING_UpdateGCRegion( DC
* dc
)
84 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetDeviceClipping
);
86 /* update the intersection of meta and clip regions */
87 if (dc
->hMetaRgn
&& dc
->hClipRgn
)
89 if (!dc
->hMetaClipRgn
) dc
->hMetaClipRgn
= CreateRectRgn( 0, 0, 0, 0 );
90 CombineRgn( dc
->hMetaClipRgn
, dc
->hClipRgn
, dc
->hMetaRgn
, RGN_AND
);
91 clip_rgn
= dc
->hMetaClipRgn
;
93 else /* only one is set, no need for an intersection */
95 if (dc
->hMetaClipRgn
) DeleteObject( dc
->hMetaClipRgn
);
97 clip_rgn
= dc
->hMetaRgn
? dc
->hMetaRgn
: dc
->hClipRgn
;
99 physdev
->funcs
->pSetDeviceClipping( physdev
, dc
->hVisRgn
, clip_rgn
);
102 /***********************************************************************
103 * create_default_clip_region
105 * Create a default clipping region when none already exists.
107 static inline void create_default_clip_region( DC
* dc
)
111 if (dc
->header
.type
== OBJ_MEMDC
)
115 GetObjectW( dc
->hBitmap
, sizeof(bitmap
), &bitmap
);
116 width
= bitmap
.bmWidth
;
117 height
= bitmap
.bmHeight
;
121 width
= GetDeviceCaps( dc
->hSelf
, DESKTOPHORZRES
);
122 height
= GetDeviceCaps( dc
->hSelf
, DESKTOPVERTRES
);
124 dc
->hClipRgn
= CreateRectRgn( 0, 0, width
, height
);
128 /***********************************************************************
129 * null driver fallback implementations
132 INT
nulldrv_ExtSelectClipRgn( PHYSDEV dev
, HRGN rgn
, INT mode
)
134 DC
*dc
= get_nulldrv_dc( dev
);
139 if (mode
!= RGN_COPY
)
141 FIXME("Unimplemented: hrgn NULL in mode: %d\n", mode
);
144 if (dc
->hClipRgn
) DeleteObject( dc
->hClipRgn
);
152 if (dc
->layout
& LAYOUT_RTL
)
154 if (!(mirrored
= CreateRectRgn( 0, 0, 0, 0 ))) return ERROR
;
155 mirror_region( mirrored
, rgn
, dc
->vis_rect
.right
- dc
->vis_rect
.left
);
160 create_default_clip_region( dc
);
162 if (mode
== RGN_COPY
)
163 ret
= CombineRgn( dc
->hClipRgn
, rgn
, 0, mode
);
165 ret
= CombineRgn( dc
->hClipRgn
, dc
->hClipRgn
, rgn
, mode
);
167 if (mirrored
) DeleteObject( mirrored
);
169 CLIPPING_UpdateGCRegion( dc
);
173 INT
nulldrv_ExcludeClipRect( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
175 DC
*dc
= get_nulldrv_dc( dev
);
176 RECT rect
= get_clip_rect( dc
, left
, top
, right
, bottom
);
180 if (!(rgn
= CreateRectRgnIndirect( &rect
))) return ERROR
;
181 if (!dc
->hClipRgn
) create_default_clip_region( dc
);
182 ret
= CombineRgn( dc
->hClipRgn
, dc
->hClipRgn
, rgn
, RGN_DIFF
);
184 if (ret
!= ERROR
) CLIPPING_UpdateGCRegion( dc
);
188 INT
nulldrv_IntersectClipRect( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
190 DC
*dc
= get_nulldrv_dc( dev
);
191 RECT rect
= get_clip_rect( dc
, left
, top
, right
, bottom
);
197 dc
->hClipRgn
= CreateRectRgnIndirect( &rect
);
202 if (!(rgn
= CreateRectRgnIndirect( &rect
))) return ERROR
;
203 ret
= CombineRgn( dc
->hClipRgn
, dc
->hClipRgn
, rgn
, RGN_AND
);
206 if (ret
!= ERROR
) CLIPPING_UpdateGCRegion( dc
);
210 INT
nulldrv_OffsetClipRgn( PHYSDEV dev
, INT x
, INT y
)
212 DC
*dc
= get_nulldrv_dc( dev
);
213 INT ret
= NULLREGION
;
217 x
= MulDiv( x
, dc
->vportExtX
, dc
->wndExtX
);
218 y
= MulDiv( y
, dc
->vportExtY
, dc
->wndExtY
);
219 if (dc
->layout
& LAYOUT_RTL
) x
= -x
;
220 ret
= OffsetRgn( dc
->hClipRgn
, x
, y
);
221 CLIPPING_UpdateGCRegion( dc
);
227 /***********************************************************************
228 * SelectClipRgn (GDI32.@)
230 INT WINAPI
SelectClipRgn( HDC hdc
, HRGN hrgn
)
232 return ExtSelectClipRgn( hdc
, hrgn
, RGN_COPY
);
236 /******************************************************************************
237 * ExtSelectClipRgn [GDI32.@]
239 INT WINAPI
ExtSelectClipRgn( HDC hdc
, HRGN hrgn
, INT fnMode
)
242 DC
* dc
= get_dc_ptr( hdc
);
244 TRACE("%p %p %d\n", hdc
, hrgn
, fnMode
);
248 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pExtSelectClipRgn
);
250 retval
= physdev
->funcs
->pExtSelectClipRgn( physdev
, hrgn
, fnMode
);
251 release_dc_ptr( dc
);
256 /***********************************************************************
257 * __wine_set_visible_region (GDI32.@)
259 void CDECL
__wine_set_visible_region( HDC hdc
, HRGN hrgn
, const RECT
*vis_rect
)
263 if (!(dc
= get_dc_ptr( hdc
))) return;
265 TRACE( "%p %p %s\n", hdc
, hrgn
, wine_dbgstr_rect(vis_rect
) );
267 /* map region to DC coordinates */
268 OffsetRgn( hrgn
, -vis_rect
->left
, -vis_rect
->top
);
270 DeleteObject( dc
->hVisRgn
);
272 dc
->vis_rect
= *vis_rect
;
274 DC_UpdateXforms( dc
);
275 CLIPPING_UpdateGCRegion( dc
);
276 release_dc_ptr( dc
);
280 /***********************************************************************
281 * OffsetClipRgn (GDI32.@)
283 INT WINAPI
OffsetClipRgn( HDC hdc
, INT x
, INT y
)
286 DC
*dc
= get_dc_ptr( hdc
);
288 TRACE("%p %d,%d\n", hdc
, x
, y
);
292 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pOffsetClipRgn
);
294 ret
= physdev
->funcs
->pOffsetClipRgn( physdev
, x
, y
);
295 release_dc_ptr( dc
);
301 /***********************************************************************
302 * ExcludeClipRect (GDI32.@)
304 INT WINAPI
ExcludeClipRect( HDC hdc
, INT left
, INT top
,
305 INT right
, INT bottom
)
308 DC
*dc
= get_dc_ptr( hdc
);
310 TRACE("%p %d,%d-%d,%d\n", hdc
, left
, top
, right
, bottom
);
314 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pExcludeClipRect
);
316 ret
= physdev
->funcs
->pExcludeClipRect( physdev
, left
, top
, right
, bottom
);
317 release_dc_ptr( dc
);
323 /***********************************************************************
324 * IntersectClipRect (GDI32.@)
326 INT WINAPI
IntersectClipRect( HDC hdc
, INT left
, INT top
, INT right
, INT bottom
)
329 DC
*dc
= get_dc_ptr( hdc
);
331 TRACE("%p %d,%d - %d,%d\n", hdc
, left
, top
, right
, bottom
);
335 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pIntersectClipRect
);
337 ret
= physdev
->funcs
->pIntersectClipRect( physdev
, left
, top
, right
, bottom
);
338 release_dc_ptr( dc
);
344 /***********************************************************************
345 * PtVisible (GDI32.@)
347 BOOL WINAPI
PtVisible( HDC hdc
, INT x
, INT y
)
352 DC
*dc
= get_dc_ptr( hdc
);
354 TRACE("%p %d,%d\n", hdc
, x
, y
);
355 if (!dc
) return FALSE
;
359 LPtoDP( hdc
, &pt
, 1 );
361 ret
= PtInRegion( dc
->hVisRgn
, pt
.x
, pt
.y
);
362 if (ret
&& (clip
= get_clip_region(dc
))) ret
= PtInRegion( clip
, pt
.x
, pt
.y
);
363 release_dc_ptr( dc
);
368 /***********************************************************************
369 * RectVisible (GDI32.@)
371 BOOL WINAPI
RectVisible( HDC hdc
, const RECT
* rect
)
376 DC
*dc
= get_dc_ptr( hdc
);
377 if (!dc
) return FALSE
;
378 TRACE("%p %s\n", hdc
, wine_dbgstr_rect( rect
));
381 LPtoDP( hdc
, (POINT
*)&tmpRect
, 2 );
384 if ((clip
= get_clip_region(dc
)))
386 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
387 CombineRgn( hrgn
, dc
->hVisRgn
, clip
, RGN_AND
);
388 ret
= RectInRegion( hrgn
, &tmpRect
);
389 DeleteObject( hrgn
);
391 else ret
= RectInRegion( dc
->hVisRgn
, &tmpRect
);
392 release_dc_ptr( dc
);
397 /***********************************************************************
398 * GetClipBox (GDI32.@)
400 INT WINAPI
GetClipBox( HDC hdc
, LPRECT rect
)
403 DC
*dc
= get_dc_ptr( hdc
);
404 if (!dc
) return ERROR
;
407 ret
= get_clip_box( dc
, rect
);
408 if (dc
->layout
& LAYOUT_RTL
)
410 int tmp
= rect
->left
;
411 rect
->left
= rect
->right
- 1;
412 rect
->right
= tmp
- 1;
414 DPtoLP( hdc
, (LPPOINT
)rect
, 2 );
415 release_dc_ptr( dc
);
416 TRACE("%p => %d %s\n", hdc
, ret
, wine_dbgstr_rect( rect
));
421 /***********************************************************************
422 * GetClipRgn (GDI32.@)
424 INT WINAPI
GetClipRgn( HDC hdc
, HRGN hRgn
)
428 if ((dc
= get_dc_ptr( hdc
)))
432 if( CombineRgn(hRgn
, dc
->hClipRgn
, 0, RGN_COPY
) != ERROR
)
435 if (dc
->layout
& LAYOUT_RTL
)
436 mirror_region( hRgn
, hRgn
, dc
->vis_rect
.right
- dc
->vis_rect
.left
);
440 release_dc_ptr( dc
);
446 /***********************************************************************
447 * GetMetaRgn (GDI32.@)
449 INT WINAPI
GetMetaRgn( HDC hdc
, HRGN hRgn
)
452 DC
* dc
= get_dc_ptr( hdc
);
456 if (dc
->hMetaRgn
&& CombineRgn( hRgn
, dc
->hMetaRgn
, 0, RGN_COPY
) != ERROR
)
459 if (dc
->layout
& LAYOUT_RTL
)
460 mirror_region( hRgn
, hRgn
, dc
->vis_rect
.right
- dc
->vis_rect
.left
);
462 release_dc_ptr( dc
);
468 /***********************************************************************
469 * GetRandomRgn [GDI32.@]
472 * This function is documented in MSDN online for the case of
473 * iCode == SYSRGN (4).
475 * For iCode == 1 it should return the clip region
476 * 2 " " " the meta region
477 * 3 " " " the intersection of the clip with
478 * the meta region (== 'Rao' region).
480 * See http://www.codeproject.com/gdi/cliprgnguide.asp
482 INT WINAPI
GetRandomRgn(HDC hDC
, HRGN hRgn
, INT iCode
)
485 DC
*dc
= get_dc_ptr( hDC
);
498 rgn
= dc
->hMetaClipRgn
;
499 if(!rgn
) rgn
= dc
->hClipRgn
;
500 if(!rgn
) rgn
= dc
->hMetaRgn
;
502 case SYSRGN
: /* == 4 */
507 WARN("Unknown code %d\n", iCode
);
508 release_dc_ptr( dc
);
511 if (rgn
) CombineRgn( hRgn
, rgn
, 0, RGN_COPY
);
512 release_dc_ptr( dc
);
514 /* On Windows NT/2000, the SYSRGN returned is in screen coordinates */
515 if (iCode
== SYSRGN
&& !(GetVersion() & 0x80000000))
516 OffsetRgn( hRgn
, dc
->vis_rect
.left
, dc
->vis_rect
.top
);
522 /***********************************************************************
523 * SetMetaRgn (GDI32.@)
525 INT WINAPI
SetMetaRgn( HDC hdc
)
529 DC
*dc
= get_dc_ptr( hdc
);
531 if (!dc
) return ERROR
;
533 if (dc
->hMetaClipRgn
)
535 /* the intersection becomes the new meta region */
536 DeleteObject( dc
->hMetaRgn
);
537 DeleteObject( dc
->hClipRgn
);
538 dc
->hMetaRgn
= dc
->hMetaClipRgn
;
540 dc
->hMetaClipRgn
= 0;
542 else if (dc
->hClipRgn
)
544 dc
->hMetaRgn
= dc
->hClipRgn
;
547 /* else nothing to do */
549 /* Note: no need to call CLIPPING_UpdateGCRegion, the overall clip region hasn't changed */
551 ret
= GetRgnBox( dc
->hMetaRgn
, &dummy
);
552 release_dc_ptr( dc
);