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;