Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
April 2021
- 70 participants
- 697 discussions
[PATCH v4 5/5] gdi32: Reselect font and pen when changing world transforms for enhanced metafiles.
by Zhiyi Zhang 19 Apr '21
by Zhiyi Zhang 19 Apr '21
19 Apr '21
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(a)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 545cdef69b6..ab823dd443d 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
1
0
[PATCH v4 4/5] gdi32: Move common SetLayout() code to nulldrv_SetLayout().
by Zhiyi Zhang 19 Apr '21
by Zhiyi Zhang 19 Apr '21
19 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/dc.c | 12 +-----------
dlls/gdi32/driver.c | 13 ++++++++++++-
dlls/gdi32/enhmfdrv/dc.c | 4 +++-
3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index 830fabf6e78..eb9dbf85668 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -1922,17 +1922,7 @@ DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
if (dc)
{
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetLayout );
- layout = physdev->funcs->pSetLayout( physdev, layout );
- if (layout != GDI_ERROR)
- {
- oldlayout = dc->layout;
- dc->layout = layout;
- if (layout != oldlayout)
- {
- if (layout & LAYOUT_RTL) dc->MapMode = MM_ANISOTROPIC;
- DC_UpdateXforms( dc );
- }
- }
+ oldlayout = physdev->funcs->pSetLayout( physdev, layout );
release_dc_ptr( dc );
}
diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index 09b051cd6fa..a2ebd018bca 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -795,7 +795,18 @@ static void CDECL nulldrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
static DWORD CDECL nulldrv_SetLayout( PHYSDEV dev, DWORD layout )
{
- return layout;
+ DC *dc = get_nulldrv_dc( dev );
+ DWORD old_layout;
+
+ old_layout = dc->layout;
+ dc->layout = layout;
+ if (layout != old_layout)
+ {
+ if (layout & LAYOUT_RTL) dc->MapMode = MM_ANISOTROPIC;
+ DC_UpdateXforms( dc );
+ }
+
+ return old_layout;
}
static BOOL CDECL nulldrv_SetDeviceGammaRamp( PHYSDEV dev, void *ramp )
diff --git a/dlls/gdi32/enhmfdrv/dc.c b/dlls/gdi32/enhmfdrv/dc.c
index 2a749418829..72b6afeee8b 100644
--- a/dlls/gdi32/enhmfdrv/dc.c
+++ b/dlls/gdi32/enhmfdrv/dc.c
@@ -334,12 +334,14 @@ 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 );
EMRSETLAYOUT emr;
emr.emr.iType = EMR_SETLAYOUT;
emr.emr.nSize = sizeof(emr);
emr.iMode = layout;
- return EMFDRV_WriteRecord( dev, &emr.emr ) ? layout : GDI_ERROR;
+ if (!EMFDRV_WriteRecord( dev, &emr.emr )) return GDI_ERROR;
+ return next->funcs->pSetLayout( next, layout );
}
BOOL CDECL EMFDRV_SetWorldTransform( PHYSDEV dev, const XFORM *xform)
--
2.27.0
1
0
19 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/tests/metafile.c | 51 +++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index 9340e20444a..545cdef69b6 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -5023,6 +5023,56 @@ static void test_emf_AlphaBlend(void)
ReleaseDC(0, hdc);
}
+static void test_emf_text_extents(void)
+{
+ static const XFORM xform = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f};
+ HFONT font, old_font, old_font2;
+ LOGFONTW logfont = {0};
+ HENHMETAFILE emf;
+ SIZE size, size2;
+ HDC dc, emf_dc;
+ BOOL ret;
+
+ dc = GetDC(0);
+ emf_dc = CreateEnhMetaFileW(dc, NULL, NULL, NULL);
+ ok(!!emf_dc, "CreateEnhMetaFileW failed, error %d\n", GetLastError());
+
+ logfont.lfWeight = FW_NORMAL;
+ logfont.lfHeight = 20;
+ lstrcpyW(logfont.lfFaceName, L"Tahoma");
+ font = CreateFontIndirectW(&logfont);
+ ok(!!font, "CreateFontIndirectW failed, error %d\n", GetLastError());
+
+ old_font = SelectObject(dc, font);
+ old_font2 = SelectObject(emf_dc, font);
+
+ ret = SetGraphicsMode(dc, GM_ADVANCED);
+ ok(ret, "SetGraphicsMode failed, error %d\n", GetLastError());
+ ret = SetGraphicsMode(emf_dc, GM_ADVANCED);
+ ok(ret, "SetGraphicsMode failed, error %d\n", GetLastError());
+
+ ret = ModifyWorldTransform(dc, &xform, MWT_RIGHTMULTIPLY);
+ ok(ret, "ModifyWorldTransform failed, error %d\n", GetLastError());
+ ret = ModifyWorldTransform(emf_dc, &xform, MWT_RIGHTMULTIPLY);
+ ok(ret, "ModifyWorldTransform failed, error %d\n", GetLastError());
+
+ ret = GetTextExtentPoint32W(dc, L"W", 1, &size);
+ 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);
+
+ SelectObject(emf_dc, old_font2);
+ SelectObject(dc, old_font);
+ DeleteObject(font);
+ emf = CloseEnhMetaFile(emf_dc);
+ ok(!!emf, "CloseEnhMetaFile failed, error %d\n", GetLastError());
+ DeleteEnhMetaFile(emf);
+ ReleaseDC(0, dc);
+}
+
START_TEST(metafile)
{
init_function_pointers();
@@ -5041,6 +5091,7 @@ START_TEST(metafile)
test_emf_PolyPolyline();
test_emf_GradientFill();
test_emf_WorldTransform();
+ test_emf_text_extents();
/* For win-format metafiles (mfdrv) */
test_mf_SaveDC();
--
2.27.0
1
0
19 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v2: Supersede 203796~203800. Added SetLayout tests for Windows Metafiles to show that
world transform changes shouldn't generate META_SELECTOBJECT records. So in patch 6/6,
only the condition check for emf is removed. For wmf, if we need to remove the same
limit, we need to avoid generating META_SELECTOBJECT records when changing world
transform similar to emf. However, wmf can only change world transform via SetLayout
and MFDRV_SetLayout is not implemented at the moment.
v3: Supersede 204064~204069. Remove the SetLayout tests due to failures on Wine.
I will resubmit them with a MFDRV_SetLayout implementation later.
v4: Supersede 204082~204087. Use pGetImage for EMFDRV_AlphaBlend to make it compatible with
display drivers.
dlls/gdi32/tests/metafile.c | 713 +++++++++++++++++++++++++++++++++++-
1 file changed, 712 insertions(+), 1 deletion(-)
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index 648e9369803..ec9c7894574 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -991,7 +991,7 @@ static void test_mf_SaveDC(void)
/* with the nominal results. */
/* Maximum size of sample metafiles in bytes. */
-#define MF_BUFSIZE 1024
+#define MF_BUFSIZE 2048
/* 8x8 bitmap data for a pattern brush */
static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
@@ -4315,6 +4315,716 @@ static void test_emf_WorldTransform(void)
}
}
+static const unsigned char EMF_ALPHABLEND_1BIT[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_ALPHABLEND_4BIT[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xc8, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x68, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_ALPHABLEND_8BIT[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0x88, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x28, 0x04, 0x00, 0x00, 0x94, 0x04, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_ALPHABLEND_16BIT[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xa4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0xe0, 0x03, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00,
+ 0xe0, 0x07, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_ALPHABLEND_16BIT_555[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xa4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_ALPHABLEND_24BIT[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xa8, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_ALPHABLEND_32BIT_888[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xc4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_ALPHABLEND_32BIT[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xc4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x07, 0x00,
+ 0xb9, 0xf0, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x62, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xa3, 0x3b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0xd7, 0x23, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+ 0x90, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xe0, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00
+};
+
+static void test_emf_AlphaBlend(void)
+{
+ static const XFORM xform = {0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
+ static const BLENDFUNCTION blend = {AC_SRC_OVER, 0, 128, 0};
+ static const int bitmap_width = 4, bitmap_height = 4;
+ unsigned char bmi_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
+ BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
+ HDC hdc, hdc_emf, hdc_emf2, hdc_bitmap;
+ HBITMAP hbitmap, old_hbitmap;
+ HENHMETAFILE hemf, hemf2;
+ int ret, test_idx;
+ char comment[64];
+ void *bits;
+
+ static const struct
+ {
+ WORD bpp;
+ WORD compression;
+ const void *bits;
+ size_t bits_count;
+ DWORD used_color_count;
+ DWORD color_count;
+ RGBQUAD colors[3];
+ }
+ tests[] =
+ {
+ {1, BI_RGB, EMF_ALPHABLEND_1BIT, sizeof(EMF_ALPHABLEND_1BIT), 1, 1, {{0xff, 0xff, 0xff}}},
+ {4, BI_RGB, EMF_ALPHABLEND_4BIT, sizeof(EMF_ALPHABLEND_4BIT), 1, 1, {{0xff, 0xff, 0xff}}},
+ {8, BI_RGB, EMF_ALPHABLEND_8BIT, sizeof(EMF_ALPHABLEND_8BIT), 1, 1, {{0xff, 0xff, 0xff}}},
+ {16, BI_RGB, EMF_ALPHABLEND_16BIT_555, sizeof(EMF_ALPHABLEND_16BIT_555)},
+ {24, BI_RGB, EMF_ALPHABLEND_24BIT, sizeof(EMF_ALPHABLEND_24BIT)},
+ {32, BI_RGB, EMF_ALPHABLEND_32BIT_888, sizeof(EMF_ALPHABLEND_32BIT_888)},
+ {16, BI_BITFIELDS, EMF_ALPHABLEND_16BIT, sizeof(EMF_ALPHABLEND_16BIT), 0, 3, {{0x00, 0xf8, 0x00}, {0xe0, 0x07, 0x00}, {0x1f, 0x00, 0x00}}},
+ {32, BI_BITFIELDS, EMF_ALPHABLEND_32BIT, sizeof(EMF_ALPHABLEND_32BIT), 0, 3, {{0x00, 0x00, 0xff}, {0xe0, 0xff, 0x00}, {0xff, 0x00, 0x00}}},
+ };
+
+ hdc = GetDC(0);
+
+ /* Test that source DC cannot be an enhanced metafile */
+ hdc_emf = CreateEnhMetaFileW(hdc, NULL, NULL, NULL);
+ ok(!!hdc_emf, "CreateEnhMetaFileW failed, error %d\n", GetLastError());
+ hdc_emf2 = CreateEnhMetaFileW(hdc, NULL, NULL, NULL);
+ ok(!!hdc_emf2, "CreateEnhMetaFileW failed, error %d\n", GetLastError());
+
+ ret = GdiAlphaBlend(hdc_emf, 0, 0, 1, 1, hdc_emf2, 0, 0, 1, 1, blend);
+ ok(!ret, "GdiAlphaBlend succeeded\n");
+
+ hemf2 = CloseEnhMetaFile(hdc_emf2);
+ ok(!!hemf2, "CloseEnhMetaFile failed, error %d\n", GetLastError());
+ hemf = CloseEnhMetaFile(hdc_emf);
+ ok(!!hemf, "CloseEnhMetaFile failed, error %d\n", GetLastError());
+ DeleteEnhMetaFile(hemf2);
+ DeleteEnhMetaFile(hemf);
+
+ /* Test AlphaBlend with different format of bitmaps */
+ for (test_idx = 0; test_idx < ARRAY_SIZE(tests); ++test_idx)
+ {
+ memset(bmi_buffer, 0, sizeof(bmi_buffer));
+ bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
+ bmi->bmiHeader.biHeight = bitmap_width;
+ bmi->bmiHeader.biWidth = bitmap_height;
+ bmi->bmiHeader.biBitCount = tests[test_idx].bpp;
+ bmi->bmiHeader.biPlanes = 1;
+ bmi->bmiHeader.biCompression = tests[test_idx].compression;
+ bmi->bmiHeader.biClrUsed = tests[test_idx].used_color_count;
+ memcpy(bmi->bmiColors, tests[test_idx].colors, sizeof(RGBQUAD) * tests[test_idx].color_count);
+
+ hbitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+ ok(!!hbitmap, "Test %d: CreateDIBSection failed, error %d\n", test_idx, GetLastError());
+ hdc_bitmap = CreateCompatibleDC(hdc);
+ ok(!!hdc_bitmap, "Test %d: CreateCompatibleDC failed, error %d\n", test_idx, GetLastError());
+ old_hbitmap = SelectObject(hdc_bitmap, hbitmap);
+
+ SetBkColor(hdc_bitmap, RGB(0xff, 0xff, 0xff));
+ ret = SetGraphicsMode(hdc_bitmap, GM_ADVANCED);
+ ok(ret, "Test %d: SetGraphicsMode failed, error %d\n", test_idx, GetLastError());
+ ret = SetWorldTransform(hdc_bitmap, &xform);
+ ok(ret, "Test %d: SetWorldTransform failed, error %d\n", test_idx, GetLastError());
+ ret = SetMapMode(hdc_bitmap, MM_ANISOTROPIC);
+ ok(ret, "Test %d: SetMapMode failed, error %d\n", test_idx, GetLastError());
+ ret = SetWindowOrgEx(hdc_bitmap, 0, 0, NULL);
+ ok(ret, "Test %d: SetWindowOrgEx failed, error %d\n", test_idx, GetLastError());
+ ret = SetWindowExtEx(hdc_bitmap, 400, 400, NULL);
+ ok(ret, "Test %d: SetWindowExtEx failed, error %d\n", test_idx, GetLastError());
+ ret = SetViewportOrgEx(hdc_bitmap, 0, 0, NULL);
+ ok(ret, "Test %d: SetViewportOrgEx failed, error %d\n", test_idx, GetLastError());
+ ret = SetViewportExtEx(hdc_bitmap, bitmap_width, bitmap_height, NULL);
+ ok(ret, "Test %d: SetViewportExtEx failed, error %d\n", test_idx, GetLastError());
+
+ hdc_emf = CreateEnhMetaFileW(hdc, NULL, NULL, NULL);
+ ok(!!hdc_emf, "Test %d: CreateEnhMetaFileW failed, error %d\n", test_idx, GetLastError());
+
+ ret = BitBlt(hdc_emf, 0, 0, bitmap_width, bitmap_height, 0, 0, 0, WHITENESS);
+ ok(ret, "Test %d: BitBlt failed, error %d\n", test_idx, GetLastError());
+ ret = BitBlt(hdc_bitmap, 0, 0, bitmap_width, bitmap_height, 0, 0, 0, BLACKNESS);
+ ok(ret, "Test %d: BitBlt failed, error %d\n", test_idx, GetLastError());
+ ret = GdiAlphaBlend(hdc_emf, 0, 0, bitmap_width, bitmap_height, hdc_bitmap, 0, 0, 400, 400, blend);
+ todo_wine
+ ok(ret, "Test %d: GdiAlphaBlend failed, error %d\n", test_idx, GetLastError());
+
+ hemf = CloseEnhMetaFile(hdc_emf);
+ ok(!!hemf, "Test %d: CloseEnhMetaFile failed, %d\n", test_idx, GetLastError());
+
+ sprintf(comment, "test_emf_AlphaBlend() test %d", test_idx);
+ if (ret)
+ ret = compare_emf_bits(hemf, tests[test_idx].bits, tests[test_idx].bits_count, comment, FALSE);
+ if (ret)
+ {
+ dump_emf_bits(hemf, comment);
+ dump_emf_records(hemf, comment);
+ }
+
+ DeleteEnhMetaFile(hemf);
+ SelectObject(hdc_bitmap, old_hbitmap);
+ DeleteDC(hdc_bitmap);
+ DeleteObject(hbitmap);
+ }
+
+ ReleaseDC(0, hdc);
+}
+
START_TEST(metafile)
{
init_function_pointers();
@@ -4323,6 +5033,7 @@ START_TEST(metafile)
test_ExtTextOut();
test_ExtTextOutScale();
test_SaveDC();
+ test_emf_AlphaBlend();
test_emf_BitBlt();
test_emf_DCBrush();
test_emf_ExtTextOut_on_path();
--
2.27.0
1
0
19 Apr '21
As some thread may use a different desktop from their process.
This fixes the user32 win tests, which leaks a desktop that never gets
closed. The test_shell_window test creates a new desktop, which spawns
explorer.exe process, incrementing the desktop user count to 1, then
associates the desktop to a thread, which closes it on exit.
Never the user count is incremented to 2, and closing the thread desktop
doesn't either check whether the desktop process should be terminated.
Reversely, it is possible to create a desktop, associate it with a
thread /and/ a process, and this time the desktop process would be
terminated when the process exits, although the thread may still be
using it.
Tracking the users per thread is more robust and fixes the problem as
set_thread_desktop increments the desktop user count, and thread exit
decrements it.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
server/process.c | 3 +++
server/thread.c | 10 +++++++-
server/user.h | 2 ++
server/winstation.c | 62 +++++++++++++++++++++++++++------------------
4 files changed, 51 insertions(+), 26 deletions(-)
diff --git a/server/process.c b/server/process.c
index 8ad5a59a20b..9a3da5672a0 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1503,6 +1503,7 @@ DECL_HANDLER(get_process_idle_event)
DECL_HANDLER(make_process_system)
{
struct process *process = current->process;
+ struct thread *thread;
if (!shutdown_event)
{
@@ -1516,6 +1517,8 @@ DECL_HANDLER(make_process_system)
if (!process->is_system)
{
process->is_system = 1;
+ LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
+ close_thread_desktop( thread );
close_process_desktop( process );
if (!--user_processes && !shutdown_stage && master_socket_timeout != TIMEOUT_INFINITE)
shutdown_timeout = add_timeout_user( master_socket_timeout, server_shutdown_timeout, NULL );
diff --git a/server/thread.c b/server/thread.c
index fe9f9bdec37..5375b055758 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -306,6 +306,7 @@ static struct context *create_thread_context( struct thread *thread )
/* create a new thread */
struct thread *create_thread( int fd, struct process *process, const struct security_descriptor *sd )
{
+ struct desktop *desktop;
struct thread *thread;
int request_pipe[2];
@@ -342,7 +343,7 @@ struct thread *create_thread( int fd, struct process *process, const struct secu
init_thread_structure( thread );
thread->process = (struct process *)grab_object( process );
- thread->desktop = process->desktop;
+ thread->desktop = 0;
thread->affinity = process->affinity;
if (!current) current = thread;
@@ -369,6 +370,13 @@ struct thread *create_thread( int fd, struct process *process, const struct secu
return NULL;
}
+ if (process->desktop && (desktop = get_desktop_obj( process, process->desktop, 0 )))
+ {
+ set_thread_default_desktop( process, thread, desktop, process->desktop );
+ release_object( desktop );
+ }
+ clear_error(); /* ignore errors */
+
set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */
add_process_thread( thread->process, thread );
return thread;
diff --git a/server/user.h b/server/user.h
index 6267f3e2881..a5f906cea51 100644
--- a/server/user.h
+++ b/server/user.h
@@ -185,6 +185,8 @@ extern struct winstation *get_process_winstation( struct process *process, unsig
extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access );
extern void connect_process_winstation( struct process *process, struct thread *parent_thread,
struct process *parent_process );
+extern void set_thread_default_desktop( struct process *process, struct thread *thread,
+ struct desktop *desktop, obj_handle_t handle );
extern void set_process_default_desktop( struct process *process, struct desktop *desktop,
obj_handle_t handle );
extern void close_process_desktop( struct process *process );
diff --git a/server/winstation.c b/server/winstation.c
index 1c7552f0687..94527899311 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -324,15 +324,23 @@ static void add_desktop_user( struct desktop *desktop )
/* remove a user of the desktop and start the close timeout if necessary */
static void remove_desktop_user( struct desktop *desktop )
{
+ struct process *process;
assert( desktop->users > 0 );
desktop->users--;
/* if we have one remaining user, it has to be the manager of the desktop window */
- if (desktop->users == 1 && get_top_window_owner( desktop ))
- {
- assert( !desktop->close_timeout );
+ if ((process = get_top_window_owner( desktop )) && desktop->users == process->running_threads && !desktop->close_timeout)
desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop );
- }
+}
+
+/* set the thread desktop to the process default desktop */
+void set_thread_default_desktop( struct process *process, struct thread *thread,
+ struct desktop *desktop, obj_handle_t handle )
+{
+ if (thread->desktop || thread->desktop == handle) return; /* nothing to do */
+ thread->desktop = handle;
+
+ if (!process->is_system) add_desktop_user( desktop );
}
/* set the process default desktop handle */
@@ -340,24 +348,13 @@ void set_process_default_desktop( struct process *process, struct desktop *deskt
obj_handle_t handle )
{
struct thread *thread;
- struct desktop *old_desktop;
if (process->desktop == handle) return; /* nothing to do */
-
- if (!(old_desktop = get_desktop_obj( process, process->desktop, 0 ))) clear_error();
process->desktop = handle;
/* set desktop for threads that don't have one yet */
LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
- if (!thread->desktop) thread->desktop = handle;
-
- if (!process->is_system && desktop != old_desktop)
- {
- add_desktop_user( desktop );
- if (old_desktop) remove_desktop_user( old_desktop );
- }
-
- if (old_desktop) release_object( old_desktop );
+ set_thread_default_desktop( process, thread, desktop, handle );
}
/* connect a process to its window station */
@@ -413,23 +410,31 @@ done:
/* close the desktop of a given process */
void close_process_desktop( struct process *process )
{
- struct desktop *desktop;
+ obj_handle_t handle;
- if (process->desktop && (desktop = get_desktop_obj( process, process->desktop, 0 )))
- {
- remove_desktop_user( desktop );
- release_object( desktop );
- }
- clear_error(); /* ignore errors */
+ if (!(handle = process->desktop)) return;
+ process->desktop = 0;
+
+ close_handle( process, handle );
}
/* close the desktop of a given thread */
void close_thread_desktop( struct thread *thread )
{
- obj_handle_t handle = thread->desktop;
+ struct desktop *desktop;
+ obj_handle_t handle;
+ if (!(handle = thread->desktop)) return;
thread->desktop = 0;
- if (handle) close_handle( thread->process, handle );
+
+ if (!thread->process->is_system && (desktop = get_desktop_obj( thread->process, handle, 0 )))
+ {
+ remove_desktop_user( desktop );
+ release_object( desktop );
+ }
+ clear_error(); /* ignore errors */
+
+ close_handle( thread->process, handle );
}
/* create a window station */
@@ -624,7 +629,14 @@ DECL_HANDLER(set_thread_desktop)
if (old_desktop != new_desktop && current->desktop_users > 0)
set_error( STATUS_DEVICE_BUSY );
else
+ {
current->desktop = req->handle; /* FIXME: should we close the old one? */
+ if (!current->process->is_system && old_desktop != new_desktop)
+ {
+ add_desktop_user( new_desktop );
+ if (old_desktop) remove_desktop_user( old_desktop );
+ }
+ }
if (!current->process->desktop)
set_process_default_desktop( current->process, new_desktop, req->handle );
--
2.31.0
1
1
Fix a bug that Tally produces a blank print preview when images have to be scaled.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/enhmfdrv/bitblt.c | 85 ++++++++++++++++++++++++++++
dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 +
dlls/gdi32/enhmfdrv/init.c | 2 +-
dlls/gdi32/tests/metafile.c | 4 +-
4 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c
index 1fc5c0b1040..f0be2b52fc0 100644
--- a/dlls/gdi32/enhmfdrv/bitblt.c
+++ b/dlls/gdi32/enhmfdrv/bitblt.c
@@ -27,6 +27,91 @@
#include "enhmetafiledrv.h"
#include "wine/debug.h"
+BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst, PHYSDEV dev_src,
+ struct bitblt_coords *src, BLENDFUNCTION func )
+{
+ UINT bits_size, bmi_size, emr_size, size, bpp;
+ BITMAPINFOHEADER *bmih;
+ EMRALPHABLEND *emr;
+ HBITMAP hbitmap;
+ BITMAP bitmap;
+ BOOL ret;
+
+ /* can't use a metafile DC as source */
+ if (dev_src->funcs == dev_dst->funcs)
+ return FALSE;
+
+ hbitmap = GetCurrentObject(dev_src->hdc, OBJ_BITMAP);
+ if (GetObjectW(hbitmap, sizeof(BITMAP), &bitmap) != sizeof(BITMAP))
+ return FALSE;
+
+ bpp = bitmap.bmPlanes * bitmap.bmBitsPixel;
+ bits_size = get_dib_stride(bitmap.bmWidth, bpp) * bitmap.bmHeight;
+ if (bpp <= 8)
+ bmi_size = sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD);
+ else if (bpp == 16 || bpp == 32)
+ bmi_size = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
+ else
+ bmi_size = sizeof(BITMAPINFOHEADER);
+ emr_size = sizeof(EMRALPHABLEND);
+ size = emr_size + bmi_size + bits_size;
+
+ emr = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!emr)
+ return FALSE;
+
+ emr->emr.iType = EMR_ALPHABLEND;
+ emr->emr.nSize = size;
+ emr->rclBounds.left = dst->log_x;
+ emr->rclBounds.top = dst->log_y;
+ emr->rclBounds.right = dst->log_x + dst->log_width - 1;
+ emr->rclBounds.bottom = dst->log_y + dst->log_height - 1;
+ emr->xDest = dst->log_x;
+ emr->yDest = dst->log_y;
+ emr->cxDest = dst->log_width;
+ emr->cyDest = dst->log_height;
+ emr->xSrc = src->log_x;
+ emr->ySrc = src->log_y;
+ emr->cxSrc = src->log_width;
+ emr->cySrc = src->log_height;
+ emr->dwRop = *(DWORD *)&func;
+ GetTransform(dev_src->hdc, 0x204, &emr->xformSrc);
+ emr->crBkColorSrc = GetBkColor(dev_src->hdc);
+ emr->iUsageSrc = DIB_RGB_COLORS;
+ emr->offBmiSrc = emr_size;
+ emr->cbBmiSrc = bmi_size;
+ emr->offBitsSrc = emr_size + bmi_size;
+ emr->cbBitsSrc = bits_size;
+
+ bmih = (BITMAPINFOHEADER *)((BYTE *)emr + emr->offBmiSrc);
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = bitmap.bmWidth;
+ bmih->biHeight = bitmap.bmHeight;
+ bmih->biPlanes = bitmap.bmPlanes;
+ bmih->biBitCount = bpp;
+ bmih->biCompression = (bpp == 16 || bpp == 32) ? BI_BITFIELDS : BI_RGB;
+ bmih->biSizeImage = bits_size;
+ bmih->biYPelsPerMeter = 0;
+ bmih->biXPelsPerMeter = 0;
+ bmih->biClrUsed = bpp <= 8 ? 1 << bpp : 0;
+ bmih->biClrImportant = 0;
+
+ if (GetDIBits(dev_src->hdc, hbitmap, 0, (UINT)bmih->biHeight, (BYTE *)emr + emr->offBitsSrc,
+ (BITMAPINFO *)bmih, DIB_RGB_COLORS))
+ {
+ ret = EMFDRV_WriteRecord(dev_dst, (EMR *)emr);
+ if (ret)
+ EMFDRV_UpdateBBox(dev_dst, &emr->rclBounds);
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ HeapFree(GetProcessHeap(), 0, emr);
+ return ret;
+}
+
BOOL CDECL EMFDRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
{
EMRBITBLT emr;
diff --git a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
index ec83d29c735..253f96cd8ec 100644
--- a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
+++ b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
@@ -58,6 +58,8 @@ extern DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush ) DECLSPEC_H
/* Metafile driver functions */
extern BOOL CDECL EMFDRV_AbortPath( PHYSDEV dev ) DECLSPEC_HIDDEN;
+extern BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst,
+ PHYSDEV dev_src, struct bitblt_coords *src, BLENDFUNCTION func ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_Arc( PHYSDEV dev, INT left, INT top, INT right,
INT bottom, INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c
index cf9fb923633..07416db265e 100644
--- a/dlls/gdi32/enhmfdrv/init.c
+++ b/dlls/gdi32/enhmfdrv/init.c
@@ -38,7 +38,7 @@ static const struct gdi_dc_funcs emfdrv_driver =
{
NULL, /* pAbortDoc */
EMFDRV_AbortPath, /* pAbortPath */
- NULL, /* pAlphaBlend */
+ EMFDRV_AlphaBlend, /* pAlphaBlend */
EMFDRV_AngleArc, /* pAngleArc */
EMFDRV_Arc, /* pArc */
EMFDRV_ArcTo, /* pArcTo */
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index ec9c7894574..9340e20444a 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -5001,15 +5001,13 @@ static void test_emf_AlphaBlend(void)
ret = BitBlt(hdc_bitmap, 0, 0, bitmap_width, bitmap_height, 0, 0, 0, BLACKNESS);
ok(ret, "Test %d: BitBlt failed, error %d\n", test_idx, GetLastError());
ret = GdiAlphaBlend(hdc_emf, 0, 0, bitmap_width, bitmap_height, hdc_bitmap, 0, 0, 400, 400, blend);
- todo_wine
ok(ret, "Test %d: GdiAlphaBlend failed, error %d\n", test_idx, GetLastError());
hemf = CloseEnhMetaFile(hdc_emf);
ok(!!hemf, "Test %d: CloseEnhMetaFile failed, %d\n", test_idx, GetLastError());
sprintf(comment, "test_emf_AlphaBlend() test %d", test_idx);
- if (ret)
- ret = compare_emf_bits(hemf, tests[test_idx].bits, tests[test_idx].bits_count, comment, FALSE);
+ ret = compare_emf_bits(hemf, tests[test_idx].bits, tests[test_idx].bits_count, comment, FALSE);
if (ret)
{
dump_emf_bits(hemf, comment);
--
2.27.0
2
3
[PATCH v3 5/5] gdi32: Reselect font and pen when changing world transforms for enhanced metafiles.
by Zhiyi Zhang 19 Apr '21
by Zhiyi Zhang 19 Apr '21
19 Apr '21
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(a)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 545cdef69b6..ab823dd443d 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
1
0
[PATCH v3 4/5] gdi32: Move common SetLayout() code to nulldrv_SetLayout().
by Zhiyi Zhang 19 Apr '21
by Zhiyi Zhang 19 Apr '21
19 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/dc.c | 12 +-----------
dlls/gdi32/driver.c | 13 ++++++++++++-
dlls/gdi32/enhmfdrv/dc.c | 4 +++-
3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index 830fabf6e78..eb9dbf85668 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -1922,17 +1922,7 @@ DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
if (dc)
{
PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetLayout );
- layout = physdev->funcs->pSetLayout( physdev, layout );
- if (layout != GDI_ERROR)
- {
- oldlayout = dc->layout;
- dc->layout = layout;
- if (layout != oldlayout)
- {
- if (layout & LAYOUT_RTL) dc->MapMode = MM_ANISOTROPIC;
- DC_UpdateXforms( dc );
- }
- }
+ oldlayout = physdev->funcs->pSetLayout( physdev, layout );
release_dc_ptr( dc );
}
diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index 09b051cd6fa..a2ebd018bca 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -795,7 +795,18 @@ static void CDECL nulldrv_SetDeviceClipping( PHYSDEV dev, HRGN rgn )
static DWORD CDECL nulldrv_SetLayout( PHYSDEV dev, DWORD layout )
{
- return layout;
+ DC *dc = get_nulldrv_dc( dev );
+ DWORD old_layout;
+
+ old_layout = dc->layout;
+ dc->layout = layout;
+ if (layout != old_layout)
+ {
+ if (layout & LAYOUT_RTL) dc->MapMode = MM_ANISOTROPIC;
+ DC_UpdateXforms( dc );
+ }
+
+ return old_layout;
}
static BOOL CDECL nulldrv_SetDeviceGammaRamp( PHYSDEV dev, void *ramp )
diff --git a/dlls/gdi32/enhmfdrv/dc.c b/dlls/gdi32/enhmfdrv/dc.c
index 2a749418829..72b6afeee8b 100644
--- a/dlls/gdi32/enhmfdrv/dc.c
+++ b/dlls/gdi32/enhmfdrv/dc.c
@@ -334,12 +334,14 @@ 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 );
EMRSETLAYOUT emr;
emr.emr.iType = EMR_SETLAYOUT;
emr.emr.nSize = sizeof(emr);
emr.iMode = layout;
- return EMFDRV_WriteRecord( dev, &emr.emr ) ? layout : GDI_ERROR;
+ if (!EMFDRV_WriteRecord( dev, &emr.emr )) return GDI_ERROR;
+ return next->funcs->pSetLayout( next, layout );
}
BOOL CDECL EMFDRV_SetWorldTransform( PHYSDEV dev, const XFORM *xform)
--
2.27.0
1
0
19 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/tests/metafile.c | 51 +++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index 9340e20444a..545cdef69b6 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -5023,6 +5023,56 @@ static void test_emf_AlphaBlend(void)
ReleaseDC(0, hdc);
}
+static void test_emf_text_extents(void)
+{
+ static const XFORM xform = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f};
+ HFONT font, old_font, old_font2;
+ LOGFONTW logfont = {0};
+ HENHMETAFILE emf;
+ SIZE size, size2;
+ HDC dc, emf_dc;
+ BOOL ret;
+
+ dc = GetDC(0);
+ emf_dc = CreateEnhMetaFileW(dc, NULL, NULL, NULL);
+ ok(!!emf_dc, "CreateEnhMetaFileW failed, error %d\n", GetLastError());
+
+ logfont.lfWeight = FW_NORMAL;
+ logfont.lfHeight = 20;
+ lstrcpyW(logfont.lfFaceName, L"Tahoma");
+ font = CreateFontIndirectW(&logfont);
+ ok(!!font, "CreateFontIndirectW failed, error %d\n", GetLastError());
+
+ old_font = SelectObject(dc, font);
+ old_font2 = SelectObject(emf_dc, font);
+
+ ret = SetGraphicsMode(dc, GM_ADVANCED);
+ ok(ret, "SetGraphicsMode failed, error %d\n", GetLastError());
+ ret = SetGraphicsMode(emf_dc, GM_ADVANCED);
+ ok(ret, "SetGraphicsMode failed, error %d\n", GetLastError());
+
+ ret = ModifyWorldTransform(dc, &xform, MWT_RIGHTMULTIPLY);
+ ok(ret, "ModifyWorldTransform failed, error %d\n", GetLastError());
+ ret = ModifyWorldTransform(emf_dc, &xform, MWT_RIGHTMULTIPLY);
+ ok(ret, "ModifyWorldTransform failed, error %d\n", GetLastError());
+
+ ret = GetTextExtentPoint32W(dc, L"W", 1, &size);
+ 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);
+
+ SelectObject(emf_dc, old_font2);
+ SelectObject(dc, old_font);
+ DeleteObject(font);
+ emf = CloseEnhMetaFile(emf_dc);
+ ok(!!emf, "CloseEnhMetaFile failed, error %d\n", GetLastError());
+ DeleteEnhMetaFile(emf);
+ ReleaseDC(0, dc);
+}
+
START_TEST(metafile)
{
init_function_pointers();
@@ -5041,6 +5091,7 @@ START_TEST(metafile)
test_emf_PolyPolyline();
test_emf_GradientFill();
test_emf_WorldTransform();
+ test_emf_text_extents();
/* For win-format metafiles (mfdrv) */
test_mf_SaveDC();
--
2.27.0
1
0
Fix a bug that Tally produces a blank print preview when images have to be scaled.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/enhmfdrv/bitblt.c | 85 ++++++++++++++++++++++++++++
dlls/gdi32/enhmfdrv/enhmetafiledrv.h | 2 +
dlls/gdi32/enhmfdrv/init.c | 2 +-
dlls/gdi32/tests/metafile.c | 4 +-
4 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/gdi32/enhmfdrv/bitblt.c b/dlls/gdi32/enhmfdrv/bitblt.c
index 1fc5c0b1040..f0be2b52fc0 100644
--- a/dlls/gdi32/enhmfdrv/bitblt.c
+++ b/dlls/gdi32/enhmfdrv/bitblt.c
@@ -27,6 +27,91 @@
#include "enhmetafiledrv.h"
#include "wine/debug.h"
+BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst, PHYSDEV dev_src,
+ struct bitblt_coords *src, BLENDFUNCTION func )
+{
+ UINT bits_size, bmi_size, emr_size, size, bpp;
+ BITMAPINFOHEADER *bmih;
+ EMRALPHABLEND *emr;
+ HBITMAP hbitmap;
+ BITMAP bitmap;
+ BOOL ret;
+
+ /* can't use a metafile DC as source */
+ if (dev_src->funcs == dev_dst->funcs)
+ return FALSE;
+
+ hbitmap = GetCurrentObject(dev_src->hdc, OBJ_BITMAP);
+ if (GetObjectW(hbitmap, sizeof(BITMAP), &bitmap) != sizeof(BITMAP))
+ return FALSE;
+
+ bpp = bitmap.bmPlanes * bitmap.bmBitsPixel;
+ bits_size = get_dib_stride(bitmap.bmWidth, bpp) * bitmap.bmHeight;
+ if (bpp <= 8)
+ bmi_size = sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD);
+ else if (bpp == 16 || bpp == 32)
+ bmi_size = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
+ else
+ bmi_size = sizeof(BITMAPINFOHEADER);
+ emr_size = sizeof(EMRALPHABLEND);
+ size = emr_size + bmi_size + bits_size;
+
+ emr = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!emr)
+ return FALSE;
+
+ emr->emr.iType = EMR_ALPHABLEND;
+ emr->emr.nSize = size;
+ emr->rclBounds.left = dst->log_x;
+ emr->rclBounds.top = dst->log_y;
+ emr->rclBounds.right = dst->log_x + dst->log_width - 1;
+ emr->rclBounds.bottom = dst->log_y + dst->log_height - 1;
+ emr->xDest = dst->log_x;
+ emr->yDest = dst->log_y;
+ emr->cxDest = dst->log_width;
+ emr->cyDest = dst->log_height;
+ emr->xSrc = src->log_x;
+ emr->ySrc = src->log_y;
+ emr->cxSrc = src->log_width;
+ emr->cySrc = src->log_height;
+ emr->dwRop = *(DWORD *)&func;
+ GetTransform(dev_src->hdc, 0x204, &emr->xformSrc);
+ emr->crBkColorSrc = GetBkColor(dev_src->hdc);
+ emr->iUsageSrc = DIB_RGB_COLORS;
+ emr->offBmiSrc = emr_size;
+ emr->cbBmiSrc = bmi_size;
+ emr->offBitsSrc = emr_size + bmi_size;
+ emr->cbBitsSrc = bits_size;
+
+ bmih = (BITMAPINFOHEADER *)((BYTE *)emr + emr->offBmiSrc);
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = bitmap.bmWidth;
+ bmih->biHeight = bitmap.bmHeight;
+ bmih->biPlanes = bitmap.bmPlanes;
+ bmih->biBitCount = bpp;
+ bmih->biCompression = (bpp == 16 || bpp == 32) ? BI_BITFIELDS : BI_RGB;
+ bmih->biSizeImage = bits_size;
+ bmih->biYPelsPerMeter = 0;
+ bmih->biXPelsPerMeter = 0;
+ bmih->biClrUsed = bpp <= 8 ? 1 << bpp : 0;
+ bmih->biClrImportant = 0;
+
+ if (GetDIBits(dev_src->hdc, hbitmap, 0, (UINT)bmih->biHeight, (BYTE *)emr + emr->offBitsSrc,
+ (BITMAPINFO *)bmih, DIB_RGB_COLORS))
+ {
+ ret = EMFDRV_WriteRecord(dev_dst, (EMR *)emr);
+ if (ret)
+ EMFDRV_UpdateBBox(dev_dst, &emr->rclBounds);
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ HeapFree(GetProcessHeap(), 0, emr);
+ return ret;
+}
+
BOOL CDECL EMFDRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
{
EMRBITBLT emr;
diff --git a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
index ec83d29c735..253f96cd8ec 100644
--- a/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
+++ b/dlls/gdi32/enhmfdrv/enhmetafiledrv.h
@@ -58,6 +58,8 @@ extern DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush ) DECLSPEC_H
/* Metafile driver functions */
extern BOOL CDECL EMFDRV_AbortPath( PHYSDEV dev ) DECLSPEC_HIDDEN;
+extern BOOL CDECL EMFDRV_AlphaBlend( PHYSDEV dev_dst, struct bitblt_coords *dst,
+ PHYSDEV dev_src, struct bitblt_coords *src, BLENDFUNCTION func ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep ) DECLSPEC_HIDDEN;
extern BOOL CDECL EMFDRV_Arc( PHYSDEV dev, INT left, INT top, INT right,
INT bottom, INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c
index cf9fb923633..07416db265e 100644
--- a/dlls/gdi32/enhmfdrv/init.c
+++ b/dlls/gdi32/enhmfdrv/init.c
@@ -38,7 +38,7 @@ static const struct gdi_dc_funcs emfdrv_driver =
{
NULL, /* pAbortDoc */
EMFDRV_AbortPath, /* pAbortPath */
- NULL, /* pAlphaBlend */
+ EMFDRV_AlphaBlend, /* pAlphaBlend */
EMFDRV_AngleArc, /* pAngleArc */
EMFDRV_Arc, /* pArc */
EMFDRV_ArcTo, /* pArcTo */
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index ec9c7894574..9340e20444a 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -5001,15 +5001,13 @@ static void test_emf_AlphaBlend(void)
ret = BitBlt(hdc_bitmap, 0, 0, bitmap_width, bitmap_height, 0, 0, 0, BLACKNESS);
ok(ret, "Test %d: BitBlt failed, error %d\n", test_idx, GetLastError());
ret = GdiAlphaBlend(hdc_emf, 0, 0, bitmap_width, bitmap_height, hdc_bitmap, 0, 0, 400, 400, blend);
- todo_wine
ok(ret, "Test %d: GdiAlphaBlend failed, error %d\n", test_idx, GetLastError());
hemf = CloseEnhMetaFile(hdc_emf);
ok(!!hemf, "Test %d: CloseEnhMetaFile failed, %d\n", test_idx, GetLastError());
sprintf(comment, "test_emf_AlphaBlend() test %d", test_idx);
- if (ret)
- ret = compare_emf_bits(hemf, tests[test_idx].bits, tests[test_idx].bits_count, comment, FALSE);
+ ret = compare_emf_bits(hemf, tests[test_idx].bits, tests[test_idx].bits_count, comment, FALSE);
if (ret)
{
dump_emf_bits(hemf, comment);
--
2.27.0
1
0