diff --git a/dlls/gdi/enhmetafile.c b/dlls/gdi/enhmetafile.c index c97e4cadd96..8725f9b5b75 100644 --- a/dlls/gdi/enhmetafile.c +++ b/dlls/gdi/enhmetafile.c @@ -595,6 +595,33 @@ static void EMF_SetMapMode(HDC hdc, enum_emh_data *info) } } +/*********************************************************************** + * EMF_FixIsotropic + * + * Fix viewport extensions for isotropic mode. + */ + +static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info) +{ + double xdim = fabs((double)info->vportExtX * GetDeviceCaps( hdc, HORZSIZE ) / + (GetDeviceCaps( hdc, HORZRES ) * info->wndExtX)); + double ydim = fabs((double)info->vportExtY * GetDeviceCaps( hdc, VERTSIZE ) / + (GetDeviceCaps( hdc, VERTRES ) * info->wndExtY)); + + if (xdim > ydim) + { + INT mincx = (info->vportExtX >= 0) ? 1 : -1; + info->vportExtX = floor(info->vportExtX * ydim / xdim + 0.5); + if (!info->vportExtX) info->vportExtX = mincx; + } + else + { + INT mincy = (info->vportExtY >= 0) ? 1 : -1; + info->vportExtY = floor(info->vportExtY * xdim / ydim + 0.5); + if (!info->vportExtY) info->vportExtY = mincy; + } +} + /***************************************************************************** * emr_produces_output * @@ -829,6 +856,8 @@ BOOL WINAPI PlayEnhMetaFileRecord( break; info->wndExtX = pSetWindowExtEx->szlExtent.cx; info->wndExtY = pSetWindowExtEx->szlExtent.cy; + if (info->mode == MM_ISOTROPIC) + EMF_FixIsotropic(hdc, info); TRACE("SetWindowExtEx: %d,%d\n",info->wndExtX,info->wndExtY); break; @@ -852,6 +881,8 @@ BOOL WINAPI PlayEnhMetaFileRecord( break; info->vportExtX = pSetViewportExtEx->szlExtent.cx; info->vportExtY = pSetViewportExtEx->szlExtent.cy; + if (info->mode == MM_ISOTROPIC) + EMF_FixIsotropic(hdc, info); TRACE("SetViewportExtEx: %d,%d\n",info->vportExtX,info->vportExtY); break; } @@ -1316,8 +1347,7 @@ BOOL WINAPI PlayEnhMetaFileRecord( if (info->vportExtX == 0) info->vportExtX = 1; if (info->vportExtY == 0) info->vportExtY = 1; if (info->mode == MM_ISOTROPIC) - FIXME("EMRSCALEVIEWPORTEXTEX MM_ISOTROPIC mapping\n"); - /* MAPPING_FixIsotropic( dc ); */ + EMF_FixIsotropic(hdc, info); TRACE("EMRSCALEVIEWPORTEXTEX %ld/%ld %ld/%ld\n", lpScaleViewportExtEx->xNum,lpScaleViewportExtEx->xDenom, @@ -1342,8 +1372,7 @@ BOOL WINAPI PlayEnhMetaFileRecord( if (info->wndExtX == 0) info->wndExtX = 1; if (info->wndExtY == 0) info->wndExtY = 1; if (info->mode == MM_ISOTROPIC) - FIXME("EMRSCALEWINDOWEXTEX MM_ISOTROPIC mapping\n"); - /* MAPPING_FixIsotropic( dc ); */ + EMF_FixIsotropic(hdc, info); TRACE("EMRSCALEWINDOWEXTEX %ld/%ld %ld/%ld\n", lpScaleWindowExtEx->xNum,lpScaleWindowExtEx->xDenom, diff --git a/dlls/gdi/mapping.c b/dlls/gdi/mapping.c index 507c78989fd..7a1b9473d08 100644 --- a/dlls/gdi/mapping.c +++ b/dlls/gdi/mapping.c @@ -33,19 +33,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdi); */ void MAPPING_FixIsotropic( DC * dc ) { - double xdim = (double)dc->vportExtX * GetDeviceCaps( dc->hSelf, HORZSIZE ) / - (GetDeviceCaps( dc->hSelf, HORZRES ) * dc->wndExtX); - double ydim = (double)dc->vportExtY * GetDeviceCaps( dc->hSelf, VERTSIZE ) / - (GetDeviceCaps( dc->hSelf, VERTRES ) * dc->wndExtY); + double xdim = fabs((double)dc->vportExtX * GetDeviceCaps( dc->hSelf, HORZSIZE ) / + (GetDeviceCaps( dc->hSelf, HORZRES ) * dc->wndExtX)); + double ydim = fabs((double)dc->vportExtY * GetDeviceCaps( dc->hSelf, VERTSIZE ) / + (GetDeviceCaps( dc->hSelf, VERTRES ) * dc->wndExtY)); + if (xdim > ydim) { - dc->vportExtX = floor(dc->vportExtX * fabs( ydim / xdim ) + 0.5); - if (!dc->vportExtX) dc->vportExtX = 1; + INT mincx = (dc->vportExtX >= 0) ? 1 : -1; + dc->vportExtX = floor(dc->vportExtX * ydim / xdim + 0.5); + if (!dc->vportExtX) dc->vportExtX = mincx; } else { - dc->vportExtY = floor(dc->vportExtY * fabs( xdim / ydim ) + 0.5); - if (!dc->vportExtY) dc->vportExtY = 1; + INT mincy = (dc->vportExtY >= 0) ? 1 : -1; + dc->vportExtY = floor(dc->vportExtY * xdim / ydim + 0.5); + if (!dc->vportExtY) dc->vportExtY = mincy; } } @@ -326,7 +329,10 @@ BOOL WINAPI SetWindowExtEx( HDC hdc, INT x, INT y, LPSIZE size ) } dc->wndExtX = x; dc->wndExtY = y; - /* Windows fixes MM_ISOTROPIC mode only in SetViewportExtEx() */ + /* The API docs say that you should call SetWindowExtEx before + SetViewportExtEx. This advice does not imply that Windows + doesn't ensure the isotropic mapping after SetWindowExtEx! */ + if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc ); DC_UpdateXforms( dc ); done: GDI_ReleaseObj( hdc ); diff --git a/dlls/gdi/tests/mapping.c b/dlls/gdi/tests/mapping.c index a7fdda92e60..0dbc89aac36 100644 --- a/dlls/gdi/tests/mapping.c +++ b/dlls/gdi/tests/mapping.c @@ -53,7 +53,108 @@ void test_modify_world_transform(void) ReleaseDC(0, hdc); } +void test_SetWindowExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy) +{ + SIZE windowExt, viewportExt; + POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter; + + GetWindowOrgEx(hdc, &windowOrg); + GetViewportOrgEx(hdc, &viewportOrg); + + SetWindowExtEx(hdc, cx, cy, NULL); + GetWindowExtEx(hdc, &windowExt); + ok(windowExt.cx == cx && windowExt.cy == cy, + "Window extension: Expected %ldx%ld, got %ldx%ld\n", + cx, cy, windowExt.cx, windowExt.cy); + + GetViewportExtEx(hdc, &viewportExt); + ok(viewportExt.cx == expected_vp_cx && viewportExt.cy == expected_vp_cy, + "Viewport extents have not been properly adjusted: Expected %ldx%ld, got %ldx%ld\n", + expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy); + + GetWindowOrgEx(hdc, &windowOrgAfter); + ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y, + "Window origin changed from (%ld,%ld) to (%ld,%ld)\n", + windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y); + + GetViewportOrgEx(hdc, &viewportOrgAfter); + ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y, + "Viewport origin changed from (%ld,%ld) to (%ld,%ld)\n", + viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y); +} + +void test_SetViewportExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy) +{ + SIZE windowExt, windowExtAfter, viewportExt; + POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter; + + GetWindowOrgEx(hdc, &windowOrg); + GetViewportOrgEx(hdc, &viewportOrg); + GetWindowExtEx(hdc, &windowExt); + + SetViewportExtEx(hdc, cx, cy, NULL); + GetViewportExtEx(hdc, &viewportExt); + ok(viewportExt.cx == expected_vp_cx && viewportExt.cy == expected_vp_cy, + "Viewport extents have not been properly adjusted: Expected %ldx%ld, got %ldx%ld\n", + expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy); + + GetWindowExtEx(hdc, &windowExtAfter); + ok(windowExt.cx == windowExtAfter.cx && windowExt.cy == windowExtAfter.cy, + "Window extension changed from %ldx%ld to %ldx%ld\n", + windowExt.cx, windowExt.cy, windowExtAfter.cx, windowExtAfter.cy); + + GetWindowOrgEx(hdc, &windowOrgAfter); + ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y, + "Window origin changed from (%ld,%ld) to (%ld,%ld)\n", + windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y); + + GetViewportOrgEx(hdc, &viewportOrgAfter); + ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y, + "Viewport origin changed from (%ld,%ld) to (%ld,%ld)\n", + viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y); +} + +void test_isotropic_mapping(void) +{ + SIZE win, vp; + HDC hdc = GetDC(0); + + SetMapMode(hdc, MM_ISOTROPIC); + + /* MM_ISOTROPIC is set up like MM_LOMETRIC. + Initial values after SetMapMode(): + (1 inch = 25.4 mm) + + Windows 9x: Windows NT: + Window Ext: 254 x -254 HORZSIZE*10 x VERTSIZE*10 + Viewport Ext: LOGPIXELSX x LOGPIXELSY HORZRES x -VERTRES + + To test without rounding errors, we have to use multiples of + these values! + */ + + GetWindowExtEx(hdc, &win); + GetViewportExtEx(hdc, &vp); + + test_SetViewportExt(hdc, 10 * vp.cx, 10 * vp.cy, 10 * vp.cx, 10 * vp.cy); + test_SetWindowExt(hdc, win.cx, win.cy, 10 * vp.cx, 10 * vp.cy); + test_SetWindowExt(hdc, 2 * win.cx, win.cy, 10 * vp.cx, 5 * vp.cy); + test_SetWindowExt(hdc, win.cx, win.cy, 5 * vp.cx, 5 * vp.cy); + test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy); + test_SetViewportExt(hdc, vp.cx, 2 * vp.cy, vp.cx, vp.cy); + test_SetViewportExt(hdc, 2 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy); + test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy); + test_SetWindowExt(hdc, 4 * win.cx, 2 * win.cy, 2 * vp.cx, vp.cy); + test_SetViewportExt(hdc, -2 * vp.cx, -4 * vp.cy, -2 * vp.cx, -vp.cy); + test_SetViewportExt(hdc, -2 * vp.cx, -1 * vp.cy, -2 * vp.cx, -vp.cy); + test_SetWindowExt(hdc, -4 * win.cx, -2 * win.cy, -2 * vp.cx, -vp.cy); + test_SetWindowExt(hdc, 4 * win.cx, -4 * win.cy, -vp.cx, -vp.cy); + + ReleaseDC(0, hdc); +} + START_TEST(mapping) { test_modify_world_transform(); + test_isotropic_mapping(); }