diff --git a/dlls/gdi32/clipping.c b/dlls/gdi32/clipping.c index dfbc0caf996..b71ecf60b49 100644 --- a/dlls/gdi32/clipping.c +++ b/dlls/gdi32/clipping.c @@ -42,6 +42,29 @@ static inline HRGN get_clip_region( DC * dc ) } +/*********************************************************************** + * get_clip_rect + * + * Compute a clip rectangle from its logical coordinates. + */ +static inline RECT get_clip_rect( DC * dc, int left, int top, int right, int bottom ) +{ + RECT rect; + + rect.left = left; + rect.top = top; + rect.right = right; + rect.bottom = bottom; + LPtoDP( dc->hSelf, (POINT *)&rect, 2 ); + if (dc->layout & LAYOUT_RTL) + { + int tmp = rect.left; + rect.left = rect.right + 1; + rect.right = tmp + 1; + } + return rect; +} + /*********************************************************************** * CLIPPING_UpdateGCRegion * @@ -140,6 +163,19 @@ INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode ) } else { + HRGN mirrored = 0; + + if (dc->layout & LAYOUT_RTL) + { + if (!(mirrored = CreateRectRgn( 0, 0, 0, 0 ))) + { + release_dc_ptr( dc ); + return ERROR; + } + mirror_region( mirrored, hrgn, dc->vis_rect.right - dc->vis_rect.left ); + hrgn = mirrored; + } + if (!dc->hClipRgn) create_default_clip_region( dc ); @@ -147,6 +183,8 @@ INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode ) CombineRgn( dc->hClipRgn, hrgn, 0, fnMode ); else CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode); + + if (mirrored) DeleteObject( mirrored ); } CLIPPING_UpdateGCRegion( dc ); @@ -196,8 +234,10 @@ INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y ) /* FIXME: ret is just a success flag, we should return a proper value */ } else if (dc->hClipRgn) { - ret = OffsetRgn( dc->hClipRgn, MulDiv( x, dc->vportExtX, dc->wndExtX ), - MulDiv( y, dc->vportExtY, dc->wndExtY ) ); + x = MulDiv( x, dc->vportExtX, dc->wndExtX ); + y = MulDiv( y, dc->vportExtY, dc->wndExtY ); + if (dc->layout & LAYOUT_RTL) x = -x; + ret = OffsetRgn( dc->hClipRgn, x, y ); CLIPPING_UpdateGCRegion( dc ); } release_dc_ptr( dc ); @@ -226,14 +266,9 @@ INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top, } else { - POINT pt[2]; + RECT rect = get_clip_rect( dc, left, top, right, bottom ); - pt[0].x = left; - pt[0].y = top; - pt[1].x = right; - pt[1].y = bottom; - LPtoDP( hdc, pt, 2 ); - if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR; + if (!(newRgn = CreateRectRgnIndirect( &rect ))) ret = ERROR; else { if (!dc->hClipRgn) @@ -267,25 +302,18 @@ INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom } else { - POINT pt[2]; - - pt[0].x = left; - pt[0].y = top; - pt[1].x = right; - pt[1].y = bottom; - - LPtoDP( hdc, pt, 2 ); + RECT rect = get_clip_rect( dc, left, top, right, bottom ); if (!dc->hClipRgn) { - dc->hClipRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ); + dc->hClipRgn = CreateRectRgnIndirect( &rect ); ret = SIMPLEREGION; } else { HRGN newRgn; - if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR; + if (!(newRgn = CreateRectRgnIndirect( &rect ))) ret = ERROR; else { ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND ); @@ -388,7 +416,12 @@ INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn ) { if( dc->hClipRgn ) { - if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1; + if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) + { + ret = 1; + if (dc->layout & LAYOUT_RTL) + mirror_region( hRgn, hRgn, dc->vis_rect.right - dc->vis_rect.left ); + } } else ret = 0; release_dc_ptr( dc ); @@ -408,7 +441,11 @@ INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn ) if (dc) { if (dc->hMetaRgn && CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY ) != ERROR) + { ret = 1; + if (dc->layout & LAYOUT_RTL) + mirror_region( hRgn, hRgn, dc->vis_rect.right - dc->vis_rect.left ); + } release_dc_ptr( dc ); } return ret; diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index e09cf2b4487..ee44af51ddc 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -490,6 +490,7 @@ extern UINT WINAPI GDIRealizePalette( HDC hdc ); extern HPALETTE PALETTE_Init(void) DECLSPEC_HIDDEN; /* region.c */ +extern INT mirror_region( HRGN dst, HRGN src, INT width ) DECLSPEC_HIDDEN; extern BOOL REGION_FrameRgn( HRGN dest, HRGN src, INT x, INT y ) DECLSPEC_HIDDEN; /* Undocumented value for DIB's iUsage: Indicates a mono DIB w/o pal entries */ diff --git a/dlls/gdi32/region.c b/dlls/gdi32/region.c index d6dec1f7687..1f281c4986e 100644 --- a/dlls/gdi32/region.c +++ b/dlls/gdi32/region.c @@ -1458,6 +1458,63 @@ static BOOL REGION_CopyRegion(WINEREGION *dst, WINEREGION *src) return TRUE; } +/*********************************************************************** + * REGION_MirrorRegion + */ +static BOOL REGION_MirrorRegion( WINEREGION *dst, WINEREGION *src, int width ) +{ + int i, start, end; + RECT extents; + RECT *rects = HeapAlloc( GetProcessHeap(), 0, src->numRects * sizeof(RECT) ); + + if (!rects) return FALSE; + + extents.left = width - src->extents.right; + extents.right = width - src->extents.left; + extents.top = src->extents.top; + extents.bottom = src->extents.bottom; + + for (start = 0; start < src->numRects; start = end) + { + /* find the end of the current band */ + for (end = start + 1; end < src->numRects; end++) + if (src->rects[end].top != src->rects[end - 1].top) break; + + for (i = 0; i < end - start; i++) + { + rects[start + i].left = width - src->rects[end - i - 1].right; + rects[start + i].right = width - src->rects[end - i - 1].left; + rects[start + i].top = src->rects[end - i - 1].top; + rects[start + i].bottom = src->rects[end - i - 1].bottom; + } + } + + HeapFree( GetProcessHeap(), 0, dst->rects ); + dst->rects = rects; + dst->size = src->numRects; + dst->numRects = src->numRects; + dst->extents = extents; + return TRUE; +} + +/*********************************************************************** + * mirror_region + */ +INT mirror_region( HRGN dst, HRGN src, INT width ) +{ + RGNOBJ *src_rgn, *dst_rgn; + INT ret = ERROR; + + if (!(src_rgn = GDI_GetObjPtr( src, OBJ_REGION ))) return ERROR; + if ((dst_rgn = GDI_GetObjPtr( dst, OBJ_REGION ))) + { + if (REGION_MirrorRegion( &dst_rgn->rgn, &src_rgn->rgn, width )) ret = get_region_type( dst_rgn ); + GDI_ReleaseObj( dst_rgn ); + } + GDI_ReleaseObj( src_rgn ); + return ret; +} + /*********************************************************************** * REGION_Coalesce * diff --git a/dlls/gdi32/tests/mapping.c b/dlls/gdi32/tests/mapping.c index 0b823a7c4ae..c4a97acb5dd 100644 --- a/dlls/gdi32/tests/mapping.c +++ b/dlls/gdi32/tests/mapping.c @@ -31,6 +31,7 @@ static DWORD (WINAPI *pSetLayout)(HDC hdc, DWORD layout); static DWORD (WINAPI *pGetLayout)(HDC hdc); +static INT (WINAPI *pGetRandomRgn)(HDC hDC, HRGN hRgn, INT iCode); static BOOL (WINAPI *pGetTransform)(HDC, DWORD, XFORM *); static DWORD (WINAPI *pSetVirtualResolution)(HDC, DWORD, DWORD, DWORD, DWORD); @@ -228,7 +229,9 @@ static void test_dc_layout(void) SIZE size; POINT pt; HBITMAP bitmap; + RECT rc, ret_rc; HDC hdc; + HRGN hrgn; if (!pGetLayout || !pSetLayout) { @@ -287,6 +290,57 @@ static void test_dc_layout(void) ok( xform.eDy == 0.0, "got %f\n", xform.eDy ); } + SetRect( &rc, 10, 10, 20, 20 ); + IntersectClipRect( hdc, 10, 10, 20, 20 ); + hrgn = CreateRectRgn( 0, 0, 0, 0 ); + GetClipRgn( hdc, hrgn ); + GetRgnBox( hrgn, &ret_rc ); + ok( EqualRect( &rc, &ret_rc ), "wrong clip box %d,%d - %d,%d\n", + ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom ); + pSetLayout( hdc, LAYOUT_LTR ); + SetRect( &rc, 80, 10, 90, 20 ); + GetClipRgn( hdc, hrgn ); + GetRgnBox( hrgn, &ret_rc ); + ok( EqualRect( &rc, &ret_rc ), "wrong clip box %d,%d - %d,%d\n", + ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom ); + GetClipBox( hdc, &ret_rc ); + ok( EqualRect( &rc, &ret_rc ), "wrong clip box %d,%d - %d,%d\n", + ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom ); + IntersectClipRect( hdc, 80, 10, 85, 20 ); + pSetLayout( hdc, LAYOUT_RTL ); + SetRect( &rc, 15, 10, 20, 20 ); + GetClipRgn( hdc, hrgn ); + GetRgnBox( hrgn, &ret_rc ); + ok( EqualRect( &rc, &ret_rc ), "wrong clip box %d,%d - %d,%d\n", + ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom ); + SetRectRgn( hrgn, 60, 10, 80, 20 ); + pSetLayout( hdc, LAYOUT_LTR ); + ExtSelectClipRgn( hdc, hrgn, RGN_OR ); + pSetLayout( hdc, LAYOUT_RTL ); + SetRect( &rc, 15, 10, 40, 20 ); + GetClipRgn( hdc, hrgn ); + GetRgnBox( hrgn, &ret_rc ); + ok( EqualRect( &rc, &ret_rc ), "wrong clip box %d,%d - %d,%d\n", + ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom ); + + /* OffsetClipRgn mirrors too */ + OffsetClipRgn( hdc, 5, 5 ); + OffsetRect( &rc, 5, 5 ); + GetClipRgn( hdc, hrgn ); + GetRgnBox( hrgn, &ret_rc ); + ok( EqualRect( &rc, &ret_rc ), "wrong clip box %d,%d - %d,%d\n", + ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom ); + + /* GetRandomRgn returns the raw region */ + if (pGetRandomRgn) + { + SetRect( &rc, 55, 15, 80, 25 ); + pGetRandomRgn( hdc, hrgn, 1 ); + GetRgnBox( hrgn, &ret_rc ); + ok( EqualRect( &rc, &ret_rc ), "wrong clip box %d,%d - %d,%d\n", + ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom ); + } + SetMapMode(hdc, MM_LOMETRIC); ret = GetMapMode( hdc ); ok(ret == MM_ANISOTROPIC, "expected MM_ANISOTROPIC, got %d\n", ret); @@ -656,6 +710,7 @@ START_TEST(mapping) HMODULE mod = GetModuleHandleA("gdi32.dll"); pGetLayout = (void *)GetProcAddress( mod, "GetLayout" ); pSetLayout = (void *)GetProcAddress( mod, "SetLayout" ); + pGetRandomRgn = (void *)GetProcAddress( mod, "GetRandomRgn" ); pGetTransform = (void *)GetProcAddress( mod, "GetTransform" ); pSetVirtualResolution = (void *)GetProcAddress( mod, "SetVirtualResolution" );