[PATCH v2 6/6] gdi32: Reselect font and pen when changing world transforms for enhanced metafiles.

Zhiyi Zhang zzhang at codeweavers.com
Mon Apr 19 02:29:10 CDT 2021


Reselect font and pen into enhanced metafile device contexts after world transform is changed so
that content can be drawn using the correct size. Also modifying the world transform for enhanced
metafiles doesn't generate EMR_SELECTOBJECT records according to winedump outputs.

Fix an issue that Tally may produce a print preview with a too large font or with a black side bar.

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/gdi32/dc.c                      |  2 +-
 dlls/gdi32/enhmfdrv/dc.c             | 78 ++++++++++++++++++++++++----
 dlls/gdi32/enhmfdrv/enhmetafiledrv.h |  1 +
 dlls/gdi32/enhmfdrv/init.c           |  1 +
 dlls/gdi32/enhmfdrv/objects.c        |  2 +
 dlls/gdi32/tests/metafile.c          |  1 -
 6 files changed, 72 insertions(+), 13 deletions(-)

diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index eb9dbf85668..1b9138e6529 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -364,7 +364,7 @@ void DC_UpdateXforms( DC *dc )
     /* Reselect the font and pen back into the dc so that the size
        gets updated. */
     if (linear_xform_cmp( &oldworld2vport, &dc->xformWorld2Vport ) &&
-        !GdiIsMetaFileDC(dc->hSelf))
+        GetObjectType( dc->hSelf ) != OBJ_METADC)
     {
         SelectObject(dc->hSelf, dc->hFont);
         SelectObject(dc->hSelf, dc->hPen);
diff --git a/dlls/gdi32/enhmfdrv/dc.c b/dlls/gdi32/enhmfdrv/dc.c
index 72b6afeee8b..1c87643ea96 100644
--- a/dlls/gdi32/enhmfdrv/dc.c
+++ b/dlls/gdi32/enhmfdrv/dc.c
@@ -235,19 +235,27 @@ INT CDECL EMFDRV_ExtSelectClipRgn( PHYSDEV dev, HRGN hrgn, INT mode )
 INT CDECL EMFDRV_SetMapMode( PHYSDEV dev, INT mode )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetMapMode );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETMAPMODE emr;
+    INT ret;
+
     emr.emr.iType = EMR_SETMAPMODE;
     emr.emr.nSize = sizeof(emr);
     emr.iMode = mode;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return 0;
-    return next->funcs->pSetMapMode( next, mode );
+    physDev->modifying_transform++;
+    ret = next->funcs->pSetMapMode( next, mode );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_SetViewportExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetViewportExtEx );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETVIEWPORTEXTEX emr;
+    BOOL ret;
 
     emr.emr.iType = EMR_SETVIEWPORTEXTEX;
     emr.emr.nSize = sizeof(emr);
@@ -255,13 +263,18 @@ BOOL CDECL EMFDRV_SetViewportExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
     emr.szlExtent.cy = cy;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pSetViewportExtEx( next, cx, cy, size );
+    physDev->modifying_transform++;
+    ret = next->funcs->pSetViewportExtEx( next, cx, cy, size );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_SetWindowExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetWindowExtEx );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETWINDOWEXTEX emr;
+    BOOL ret;
 
     emr.emr.iType = EMR_SETWINDOWEXTEX;
     emr.emr.nSize = sizeof(emr);
@@ -269,13 +282,18 @@ BOOL CDECL EMFDRV_SetWindowExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
     emr.szlExtent.cy = cy;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pSetWindowExtEx( next, cx, cy, size );
+    physDev->modifying_transform++;
+    ret = next->funcs->pSetWindowExtEx( next, cx, cy, size );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_SetViewportOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetViewportOrgEx );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETVIEWPORTORGEX emr;
+    BOOL ret;
 
     emr.emr.iType = EMR_SETVIEWPORTORGEX;
     emr.emr.nSize = sizeof(emr);
@@ -283,13 +301,18 @@ BOOL CDECL EMFDRV_SetViewportOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
     emr.ptlOrigin.y = y;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pSetViewportOrgEx( next, x, y, pt );
+    physDev->modifying_transform++;
+    ret = next->funcs->pSetViewportOrgEx( next, x, y, pt );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_SetWindowOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetWindowOrgEx );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETWINDOWORGEX emr;
+    BOOL ret;
 
     emr.emr.iType = EMR_SETWINDOWORGEX;
     emr.emr.nSize = sizeof(emr);
@@ -297,13 +320,18 @@ BOOL CDECL EMFDRV_SetWindowOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
     emr.ptlOrigin.y = y;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pSetWindowOrgEx( next, x, y, pt );
+    physDev->modifying_transform++;
+    ret = next->funcs->pSetWindowOrgEx( next, x, y, pt );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_ScaleViewportExtEx( PHYSDEV dev, INT xNum, INT xDenom, INT yNum, INT yDenom, SIZE *size )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pScaleViewportExtEx );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSCALEVIEWPORTEXTEX emr;
+    BOOL ret;
 
     emr.emr.iType = EMR_SCALEVIEWPORTEXTEX;
     emr.emr.nSize = sizeof(emr);
@@ -313,7 +341,10 @@ BOOL CDECL EMFDRV_ScaleViewportExtEx( PHYSDEV dev, INT xNum, INT xDenom, INT yNu
     emr.yDenom    = yDenom;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pScaleViewportExtEx( next, xNum, xDenom, yNum, yDenom, size );
+    physDev->modifying_transform++;
+    ret = next->funcs->pScaleViewportExtEx( next, xNum, xDenom, yNum, yDenom, size );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_ScaleWindowExtEx( PHYSDEV dev, INT xNum, INT xDenom, INT yNum, INT yDenom, SIZE *size )
@@ -335,32 +366,44 @@ BOOL CDECL EMFDRV_ScaleWindowExtEx( PHYSDEV dev, INT xNum, INT xDenom, INT yNum,
 DWORD CDECL EMFDRV_SetLayout( PHYSDEV dev, DWORD layout )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetMapMode );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETLAYOUT emr;
+    DWORD ret;
 
     emr.emr.iType = EMR_SETLAYOUT;
     emr.emr.nSize = sizeof(emr);
     emr.iMode = layout;
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return GDI_ERROR;
-    return next->funcs->pSetLayout( next, layout );
+    physDev->modifying_transform++;
+    ret = next->funcs->pSetLayout( next, layout );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_SetWorldTransform( PHYSDEV dev, const XFORM *xform)
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetWorldTransform );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETWORLDTRANSFORM emr;
+    BOOL ret;
 
     emr.emr.iType = EMR_SETWORLDTRANSFORM;
     emr.emr.nSize = sizeof(emr);
     emr.xform = *xform;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pSetWorldTransform( next, xform );
+    physDev->modifying_transform++;
+    ret = next->funcs->pSetWorldTransform( next, xform );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_ModifyWorldTransform( PHYSDEV dev, const XFORM *xform, DWORD mode)
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pModifyWorldTransform );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRMODIFYWORLDTRANSFORM emr;
+    BOOL ret;
 
     emr.emr.iType = EMR_MODIFYWORLDTRANSFORM;
     emr.emr.nSize = sizeof(emr);
@@ -380,14 +423,19 @@ BOOL CDECL EMFDRV_ModifyWorldTransform( PHYSDEV dev, const XFORM *xform, DWORD m
     emr.iMode = mode;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pModifyWorldTransform( next, xform, mode );
+    physDev->modifying_transform++;
+    ret = next->funcs->pModifyWorldTransform( next, xform, mode );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_OffsetViewportOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pOffsetViewportOrgEx );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETVIEWPORTORGEX emr;
     POINT prev;
+    BOOL ret;
 
     GetViewportOrgEx( dev->hdc, &prev );
 
@@ -397,14 +445,19 @@ BOOL CDECL EMFDRV_OffsetViewportOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
     emr.ptlOrigin.y = prev.y + y;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pOffsetViewportOrgEx( next, x, y, pt );
+    physDev->modifying_transform++;
+    ret = next->funcs->pOffsetViewportOrgEx( next, x, y, pt );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 BOOL CDECL EMFDRV_OffsetWindowOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
 {
     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pOffsetWindowOrgEx );
+    EMFDRV_PDEVICE *physDev = get_emf_physdev( dev );
     EMRSETWINDOWORGEX emr;
     POINT prev;
+    BOOL ret;
 
     GetWindowOrgEx( dev->hdc, &prev );
 
@@ -414,7 +467,10 @@ BOOL CDECL EMFDRV_OffsetWindowOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
     emr.ptlOrigin.y = prev.y + y;
 
     if (!EMFDRV_WriteRecord( dev, &emr.emr )) return FALSE;
-    return next->funcs->pOffsetWindowOrgEx( next, x, y, pt );
+    physDev->modifying_transform++;
+    ret = next->funcs->pOffsetWindowOrgEx( next, x, y, pt );
+    physDev->modifying_transform--;
+    return ret;
 }
 
 DWORD CDECL EMFDRV_SetMapperFlags( PHYSDEV dev, DWORD flags )
diff --git a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
index 253f96cd8ec..fd463bd29e3 100644
--- a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
+++ b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
@@ -41,6 +41,7 @@ typedef struct
     HBRUSH     dc_brush;
     HPEN       dc_pen;
     INT        restoring;          /* RestoreDC counter */
+    INT        modifying_transform;/* Counter for functions that can change world transform */
     BOOL       path;
     INT        dev_caps[COLORMGMTCAPS + 1];
 } EMFDRV_PDEVICE;
diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c
index 07416db265e..6c41aa88feb 100644
--- a/dlls/gdi32/enhmfdrv/init.c
+++ b/dlls/gdi32/enhmfdrv/init.c
@@ -372,6 +372,7 @@ HDC WINAPI CreateEnhMetaFileW(
     physDev->dc_brush = 0;
     physDev->dc_pen = 0;
     physDev->restoring = 0;
+    physDev->modifying_transform = 0;
     physDev->path = FALSE;
 
     if (hdc)  /* if no ref, use current display */
diff --git a/dlls/gdi32/enhmfdrv/objects.c b/dlls/gdi32/enhmfdrv/objects.c
index e21dfe2a47a..a60ca1a3b82 100644
--- a/dlls/gdi32/enhmfdrv/objects.c
+++ b/dlls/gdi32/enhmfdrv/objects.c
@@ -285,6 +285,7 @@ HFONT CDECL EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont, UINT *aa_flags )
     int i;
 
     if (physDev->restoring) goto done;  /* don't output SelectObject records during RestoreDC */
+    if (physDev->modifying_transform) goto done; /* don't output SelectObject records when modifying the world transform */
 
     /* If the object is a stock font object, do not need to create it.
      * See definitions in  wingdi.h for range of stock fonts.
@@ -370,6 +371,7 @@ HPEN CDECL EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen, const struct brush_pattern *
     int i;
 
     if (physDev->restoring) return hPen;  /* don't output SelectObject records during RestoreDC */
+    if (physDev->modifying_transform) return hPen; /* don't output SelectObject records when modifying the world transform */
 
     /* If the object is a stock pen object, do not need to create it.
      * See definitions in  wingdi.h for range of stock pens.
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index f9bd5259ab9..584ff7cd7ed 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -5060,7 +5060,6 @@ static void test_emf_text_extents(void)
     ok(ret, "GetTextExtentPoint32W failed, error %d\n", GetLastError());
     ret = GetTextExtentPoint32W(emf_dc, L"W", 1, &size2);
     ok(ret, "GetTextExtentPoint32W failed, error %d\n", GetLastError());
-todo_wine
     ok(size2.cx == size.cx && size2.cy == size.cy, "Expected size %dx%d, got %dx%d\n",
        size.cx, size.cy, size2.cx, size2.cy);
 
-- 
2.27.0



More information about the wine-devel mailing list