Calling either SetViewportExtEx or SetWindowExtEx fixes the viewport(MAPPING_FixIsotropic), but if both are called then it is fixed twice. Then the mapping matrix will be incorrect and will not be calculated using the values of viewport and wnd.
From: Haoyang Chen chenhaoyang@kylinos.cn
Calling either SetViewportExtEx or SetWindowExtEx fixes the viewport(MAPPING_FixIsotropic), but if both are called then it is fixed twice. Then the mapping matrix will be incorrect and will not be calculated using the values of viewport and wnd. --- dlls/gdi32/dc.c | 3 +++ dlls/win32u/mapping.c | 24 ++++++++++++++++++++---- include/ntgdi.h | 4 ++++ 3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 0a57d74485e..c999ff95e15 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -1171,6 +1171,7 @@ BOOL WINAPI SetWindowExtEx( HDC hdc, INT x, INT y, SIZE *size ) if (!x || !y) return FALSE; dc_attr->wnd_ext.cx = x; dc_attr->wnd_ext.cy = y; + dc_attr->vp_wnd_bits |= NTGDI_SETWND; return NtGdiComputeXformCoefficients( hdc ); }
@@ -1226,6 +1227,7 @@ BOOL WINAPI GetViewportExtEx( HDC hdc, SIZE *size ) { DC_ATTR *dc_attr; if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; + if (0 != dc_attr->vp_wnd_bits) NtGdiComputeXformCoefficients( hdc ); *size = dc_attr->vport_ext; return TRUE; } @@ -1246,6 +1248,7 @@ BOOL WINAPI SetViewportExtEx( HDC hdc, INT x, INT y, LPSIZE size ) if (!x || !y) return FALSE; dc_attr->vport_ext.cx = x; dc_attr->vport_ext.cy = y; + dc_attr->vp_wnd_bits |= NTGDI_SETVIEWPORT; return NtGdiComputeXformCoefficients( hdc ); }
diff --git a/dlls/win32u/mapping.c b/dlls/win32u/mapping.c index 65f276e853f..7a5c729854f 100644 --- a/dlls/win32u/mapping.c +++ b/dlls/win32u/mapping.c @@ -90,10 +90,22 @@ static void MAPPING_FixIsotropic( DC * dc ) { SIZE virtual_size = get_dc_virtual_size( dc ); SIZE virtual_res = get_dc_virtual_res( dc ); - double xdim = fabs((double)dc->attr->vport_ext.cx * virtual_size.cx / - (virtual_res.cx * dc->attr->wnd_ext.cx)); - double ydim = fabs((double)dc->attr->vport_ext.cy * virtual_size.cy / - (virtual_res.cy * dc->attr->wnd_ext.cy)); + double xdim, ydim; + + if ((NTGDI_SETVIEWPORT | NTGDI_SETWND) == dc->attr->vp_wnd_bits) + { + xdim = fabs((double)dc->attr->old_vport_ext.cx / dc->attr->wnd_ext.cx); + ydim = fabs((double)dc->attr->old_vport_ext.cy / dc->attr->wnd_ext.cy); + dc->attr->vport_ext = dc->attr->old_vport_ext; + } + else + { + xdim = fabs((double)dc->attr->vport_ext.cx * virtual_size.cx / + (virtual_res.cx * dc->attr->wnd_ext.cx)); + ydim = fabs((double)dc->attr->vport_ext.cy * virtual_size.cy / + (virtual_res.cy * dc->attr->wnd_ext.cy)); + dc->attr->old_vport_ext = dc->attr->vport_ext; + }
if (xdim > ydim) { @@ -107,6 +119,9 @@ static void MAPPING_FixIsotropic( DC * dc ) dc->attr->vport_ext.cy = GDI_ROUND( dc->attr->vport_ext.cy * xdim / ydim ); if (!dc->attr->vport_ext.cy) dc->attr->vport_ext.cy = mincy; } + + if (NTGDI_SETWND & dc->attr->vp_wnd_bits) + dc->attr->vp_wnd_bits = 0; }
@@ -133,6 +148,7 @@ BOOL set_map_mode( DC *dc, int mode ) dc->attr->wnd_ext.cy = virtual_size.cy * 10; dc->attr->vport_ext.cx = virtual_res.cx; dc->attr->vport_ext.cy = -virtual_res.cy; + dc->attr->vp_wnd_bits = 0; break; case MM_HIMETRIC: virtual_size = get_dc_virtual_size( dc ); diff --git a/include/ntgdi.h b/include/ntgdi.h index 50973535c7a..9f9f852bc6b 100644 --- a/include/ntgdi.h +++ b/include/ntgdi.h @@ -171,6 +171,8 @@ enum /* structs not compatible with native Windows */ #ifdef __WINESRC__
+#define NTGDI_SETVIEWPORT 0x01 +#define NTGDI_SETWND 0x02 typedef struct DC_ATTR { UINT hdc; /* handle to self */ @@ -198,8 +200,10 @@ typedef struct DC_ATTR POINT brush_org; /* brush origin */ POINT wnd_org; /* window origin */ SIZE wnd_ext; /* window extent */ + SIZE old_vport_ext; /* last viewport extent */ POINT vport_org; /* viewport origin */ SIZE vport_ext; /* viewport extent */ + WORD vp_wnd_bits; /* According to msdn, SetWindowExtEx and SetViewportExtEx need to be used together */ SIZE virtual_res; SIZE virtual_size; UINT font_code_page;
From: Haoyang Chen chenhaoyang@kylinos.cn
--- dlls/gdi32/tests/mapping.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/dlls/gdi32/tests/mapping.c b/dlls/gdi32/tests/mapping.c index 78c83907a7e..192c87c33b6 100644 --- a/dlls/gdi32/tests/mapping.c +++ b/dlls/gdi32/tests/mapping.c @@ -487,6 +487,23 @@ static void test_SetViewportExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y); }
+static void test_SetWindowExtEx(INT vp_cx, INT vp_cy, INT cx, INT cy, INT expect_cx, INT expect_cy) +{ + SIZE viewportExt = {0}; + HDC hdc = GetDC(0); + + SetMapMode(hdc, MM_ISOTROPIC); + + SetViewportExtEx(hdc, vp_cx, vp_cy, NULL); + SetWindowExtEx(hdc, cx, cy, NULL); + GetViewportExtEx(hdc, &viewportExt); + + ok(viewportExt.cx == expect_cx && viewportExt.cy == expect_cy, "Expected %dx%d got %ldx%ld\n", + expect_cx, expect_cy, viewportExt.cx, viewportExt.cy); + + ReleaseDC(0, hdc); +} + static void test_isotropic_mapping(void) { SIZE win, vp; @@ -524,6 +541,13 @@ static void test_isotropic_mapping(void) test_SetWindowExt(hdc, 4 * win.cx, -4 * win.cy, -vp.cx, -vp.cy);
ReleaseDC(0, hdc); + + test_SetWindowExtEx(400, 600, 400*2, 600*2, 400, 600); + test_SetWindowExtEx(500, 500, 1234, 4567, 500*1234/4567, 500); + test_SetWindowExtEx(500, 500, 1234, 600, 500, 500*600/1234); + test_SetWindowExtEx(500, 500, 1234, 1234, 500, 500); + test_SetWindowExtEx(-500, 500, 111, 111, -500, 500); + test_SetWindowExtEx(500, -500, 1500, 1500, 500, -500); }
static void test_setvirtualresolution(void)