From 02792d0328c8568cfaf404f8038441cc20974052 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 18 Oct 2024 07:34:05 +1100 Subject: [PATCH] Added win32u-NtGdiExtTextOutW-rotation patchset --- ...device-world-width-height-converters.patch | 232 ++++++++++++++++++ ...extOutW-should-translate-x-y-from-lo.patch | 55 +++++ .../definition | 3 + 3 files changed, 290 insertions(+) create mode 100644 patches/win32u-NtGdiExtTextOutW-rotation/0001-win32u-Fix-device-world-width-height-converters.patch create mode 100644 patches/win32u-NtGdiExtTextOutW-rotation/0002-win32u-NtGdiExtTextOutW-should-translate-x-y-from-lo.patch create mode 100644 patches/win32u-NtGdiExtTextOutW-rotation/definition diff --git a/patches/win32u-NtGdiExtTextOutW-rotation/0001-win32u-Fix-device-world-width-height-converters.patch b/patches/win32u-NtGdiExtTextOutW-rotation/0001-win32u-Fix-device-world-width-height-converters.patch new file mode 100644 index 00000000..b9b7a032 --- /dev/null +++ b/patches/win32u-NtGdiExtTextOutW-rotation/0001-win32u-Fix-device-world-width-height-converters.patch @@ -0,0 +1,232 @@ +From de25c3d088ef5feba4c45ca9e885451604781749 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 7 Feb 2024 19:14:29 +0300 +Subject: [PATCH 1/2] win32u: Fix device<->world width/height converters. + +Signed-off-by: Dmitry Timoshkov +--- + dlls/win32u/font.c | 130 +++++++++++++++++++++------------------------ + 1 file changed, 60 insertions(+), 70 deletions(-) + +diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c +index 62a4dc51035..8fbd8dc3f01 100644 +--- a/dlls/win32u/font.c ++++ b/dlls/win32u/font.c +@@ -229,12 +229,10 @@ static inline int facename_compare( const WCHAR *str1, const WCHAR *str2, SIZE_T + */ + static inline INT INTERNAL_XDSTOWS(DC *dc, INT width) + { +- double floatWidth; ++ float scale_x; + +- /* Perform operation with floating point */ +- floatWidth = (double)width * dc->xformVport2World.eM11; +- /* Round to integers */ +- return GDI_ROUND(floatWidth); ++ scale_x = hypotf(dc->xformWorld2Vport.eM11, dc->xformWorld2Vport.eM12); ++ return GDI_ROUND( (float)width / scale_x ); + } + + /* Performs a device to world transformation on the specified size (which +@@ -242,34 +240,26 @@ static inline INT INTERNAL_XDSTOWS(DC *dc, INT width) + */ + static inline INT INTERNAL_YDSTOWS(DC *dc, INT height) + { +- double floatHeight; ++ float scale_y; + +- /* Perform operation with floating point */ +- floatHeight = (double)height * dc->xformVport2World.eM22; +- /* Round to integers */ +- return GDI_ROUND(floatHeight); ++ scale_y = hypotf(dc->xformWorld2Vport.eM21, dc->xformWorld2Vport.eM22); ++ return GDI_ROUND( (float)height / scale_y ); + } + +-/* scale width and height but don't mirror them */ +- +-static inline INT width_to_LP( DC *dc, INT width ) ++static inline INT INTERNAL_XWSTODS(DC *dc, INT width) + { +- return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 )); +-} ++ float scale_x; + +-static inline INT height_to_LP( DC *dc, INT height ) +-{ +- return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 )); ++ scale_x = hypotf(dc->xformWorld2Vport.eM11, dc->xformWorld2Vport.eM12); ++ return GDI_ROUND( (float)width / scale_x ); + } + + static inline INT INTERNAL_YWSTODS(DC *dc, INT height) + { +- POINT pt[2]; +- pt[0].x = pt[0].y = 0; +- pt[1].x = 0; +- pt[1].y = height; +- lp_to_dp(dc, pt, 2); +- return pt[1].y - pt[0].y; ++ float scale_y; ++ ++ scale_y = hypotf(dc->xformWorld2Vport.eM21, dc->xformWorld2Vport.eM22); ++ return GDI_ROUND( (float)height / scale_y ); + } + + static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer ); +@@ -4215,8 +4205,8 @@ static void scale_outline_font_metrics( const struct gdi_font *font, OUTLINETEXT + else + scale_x = font->scale_y; + +- scale_x *= fabs(font->matrix.eM11); +- scale_y = font->scale_y * fabs(font->matrix.eM22); ++ scale_x *= hypotf(font->matrix.eM11, font->matrix.eM12); ++ scale_y = font->scale_y * hypotf(font->matrix.eM21, font->matrix.eM22); + + /* Windows scales these values as signed integers even if they are unsigned */ + #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x)) +@@ -4430,8 +4420,8 @@ static void scale_font_metrics( struct gdi_font *font, TEXTMETRICW *tm ) + else + scale_x = font->scale_y; + +- scale_x *= fabs(font->matrix.eM11); +- scale_y = font->scale_y * fabs(font->matrix.eM22); ++ scale_x *= hypotf(font->matrix.eM11, font->matrix.eM12); ++ scale_y = font->scale_y * hypotf(font->matrix.eM21, font->matrix.eM22); + + #define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x) + #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y) +@@ -5400,14 +5390,14 @@ BOOL WINAPI NtGdiGetTextMetricsW( HDC hdc, TEXTMETRICW *metrics, ULONG flags ) + + metrics->tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX); + metrics->tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY); +- metrics->tmHeight = height_to_LP( dc, metrics->tmHeight ); +- metrics->tmAscent = height_to_LP( dc, metrics->tmAscent ); +- metrics->tmDescent = height_to_LP( dc, metrics->tmDescent ); +- metrics->tmInternalLeading = height_to_LP( dc, metrics->tmInternalLeading ); +- metrics->tmExternalLeading = height_to_LP( dc, metrics->tmExternalLeading ); +- metrics->tmAveCharWidth = width_to_LP( dc, metrics->tmAveCharWidth ); +- metrics->tmMaxCharWidth = width_to_LP( dc, metrics->tmMaxCharWidth ); +- metrics->tmOverhang = width_to_LP( dc, metrics->tmOverhang ); ++ metrics->tmHeight = INTERNAL_YDSTOWS( dc, metrics->tmHeight ); ++ metrics->tmAscent = INTERNAL_YDSTOWS( dc, metrics->tmAscent ); ++ metrics->tmDescent = INTERNAL_YDSTOWS( dc, metrics->tmDescent ); ++ metrics->tmInternalLeading = INTERNAL_YDSTOWS( dc, metrics->tmInternalLeading ); ++ metrics->tmExternalLeading = INTERNAL_YDSTOWS( dc, metrics->tmExternalLeading ); ++ metrics->tmAveCharWidth = INTERNAL_XDSTOWS( dc, metrics->tmAveCharWidth ); ++ metrics->tmMaxCharWidth = INTERNAL_XDSTOWS( dc, metrics->tmMaxCharWidth ); ++ metrics->tmOverhang = INTERNAL_XDSTOWS( dc, metrics->tmOverhang ); + ret = TRUE; + + TRACE("text metrics:\n" +@@ -5463,38 +5453,38 @@ UINT WINAPI NtGdiGetOutlineTextMetricsInternalW( HDC hdc, UINT cbData, + { + output->otmTextMetrics.tmDigitizedAspectX = NtGdiGetDeviceCaps(hdc, LOGPIXELSX); + output->otmTextMetrics.tmDigitizedAspectY = NtGdiGetDeviceCaps(hdc, LOGPIXELSY); +- output->otmTextMetrics.tmHeight = height_to_LP( dc, output->otmTextMetrics.tmHeight ); +- output->otmTextMetrics.tmAscent = height_to_LP( dc, output->otmTextMetrics.tmAscent ); +- output->otmTextMetrics.tmDescent = height_to_LP( dc, output->otmTextMetrics.tmDescent ); +- output->otmTextMetrics.tmInternalLeading = height_to_LP( dc, output->otmTextMetrics.tmInternalLeading ); +- output->otmTextMetrics.tmExternalLeading = height_to_LP( dc, output->otmTextMetrics.tmExternalLeading ); +- output->otmTextMetrics.tmAveCharWidth = width_to_LP( dc, output->otmTextMetrics.tmAveCharWidth ); +- output->otmTextMetrics.tmMaxCharWidth = width_to_LP( dc, output->otmTextMetrics.tmMaxCharWidth ); +- output->otmTextMetrics.tmOverhang = width_to_LP( dc, output->otmTextMetrics.tmOverhang ); +- output->otmAscent = height_to_LP( dc, output->otmAscent); +- output->otmDescent = height_to_LP( dc, output->otmDescent); ++ output->otmTextMetrics.tmHeight = INTERNAL_YDSTOWS( dc, output->otmTextMetrics.tmHeight ); ++ output->otmTextMetrics.tmAscent = INTERNAL_YDSTOWS( dc, output->otmTextMetrics.tmAscent ); ++ output->otmTextMetrics.tmDescent = INTERNAL_YDSTOWS( dc, output->otmTextMetrics.tmDescent ); ++ output->otmTextMetrics.tmInternalLeading = INTERNAL_YDSTOWS( dc, output->otmTextMetrics.tmInternalLeading ); ++ output->otmTextMetrics.tmExternalLeading = INTERNAL_YDSTOWS( dc, output->otmTextMetrics.tmExternalLeading ); ++ output->otmTextMetrics.tmAveCharWidth = INTERNAL_XDSTOWS( dc, output->otmTextMetrics.tmAveCharWidth ); ++ output->otmTextMetrics.tmMaxCharWidth = INTERNAL_XDSTOWS( dc, output->otmTextMetrics.tmMaxCharWidth ); ++ output->otmTextMetrics.tmOverhang = INTERNAL_XDSTOWS( dc, output->otmTextMetrics.tmOverhang ); ++ output->otmAscent = INTERNAL_YDSTOWS( dc, output->otmAscent); ++ output->otmDescent = INTERNAL_YDSTOWS( dc, output->otmDescent); + output->otmLineGap = INTERNAL_YDSTOWS(dc, output->otmLineGap); + output->otmsCapEmHeight = INTERNAL_YDSTOWS(dc, output->otmsCapEmHeight); + output->otmsXHeight = INTERNAL_YDSTOWS(dc, output->otmsXHeight); +- output->otmrcFontBox.top = height_to_LP( dc, output->otmrcFontBox.top); +- output->otmrcFontBox.bottom = height_to_LP( dc, output->otmrcFontBox.bottom); +- output->otmrcFontBox.left = width_to_LP( dc, output->otmrcFontBox.left); +- output->otmrcFontBox.right = width_to_LP( dc, output->otmrcFontBox.right); +- output->otmMacAscent = height_to_LP( dc, output->otmMacAscent); +- output->otmMacDescent = height_to_LP( dc, output->otmMacDescent); ++ output->otmrcFontBox.top = INTERNAL_YDSTOWS( dc, output->otmrcFontBox.top); ++ output->otmrcFontBox.bottom = INTERNAL_YDSTOWS( dc, output->otmrcFontBox.bottom); ++ output->otmrcFontBox.left = INTERNAL_XDSTOWS( dc, output->otmrcFontBox.left); ++ output->otmrcFontBox.right = INTERNAL_XDSTOWS( dc, output->otmrcFontBox.right); ++ output->otmMacAscent = INTERNAL_YDSTOWS( dc, output->otmMacAscent); ++ output->otmMacDescent = INTERNAL_YDSTOWS( dc, output->otmMacDescent); + output->otmMacLineGap = INTERNAL_YDSTOWS(dc, output->otmMacLineGap); +- output->otmptSubscriptSize.x = width_to_LP( dc, output->otmptSubscriptSize.x); +- output->otmptSubscriptSize.y = height_to_LP( dc, output->otmptSubscriptSize.y); +- output->otmptSubscriptOffset.x = width_to_LP( dc, output->otmptSubscriptOffset.x); +- output->otmptSubscriptOffset.y = height_to_LP( dc, output->otmptSubscriptOffset.y); +- output->otmptSuperscriptSize.x = width_to_LP( dc, output->otmptSuperscriptSize.x); +- output->otmptSuperscriptSize.y = height_to_LP( dc, output->otmptSuperscriptSize.y); +- output->otmptSuperscriptOffset.x = width_to_LP( dc, output->otmptSuperscriptOffset.x); +- output->otmptSuperscriptOffset.y = height_to_LP( dc, output->otmptSuperscriptOffset.y); ++ output->otmptSubscriptSize.x = INTERNAL_XDSTOWS( dc, output->otmptSubscriptSize.x); ++ output->otmptSubscriptSize.y = INTERNAL_YDSTOWS( dc, output->otmptSubscriptSize.y); ++ output->otmptSubscriptOffset.x = INTERNAL_XDSTOWS( dc, output->otmptSubscriptOffset.x); ++ output->otmptSubscriptOffset.y = INTERNAL_YDSTOWS( dc, output->otmptSubscriptOffset.y); ++ output->otmptSuperscriptSize.x = INTERNAL_XDSTOWS( dc, output->otmptSuperscriptSize.x); ++ output->otmptSuperscriptSize.y = INTERNAL_YDSTOWS( dc, output->otmptSuperscriptSize.y); ++ output->otmptSuperscriptOffset.x = INTERNAL_XDSTOWS( dc, output->otmptSuperscriptOffset.x); ++ output->otmptSuperscriptOffset.y = INTERNAL_YDSTOWS( dc, output->otmptSuperscriptOffset.y); + output->otmsStrikeoutSize = INTERNAL_YDSTOWS(dc, output->otmsStrikeoutSize); +- output->otmsStrikeoutPosition = height_to_LP( dc, output->otmsStrikeoutPosition); +- output->otmsUnderscoreSize = height_to_LP( dc, output->otmsUnderscoreSize); +- output->otmsUnderscorePosition = height_to_LP( dc, output->otmsUnderscorePosition); ++ output->otmsStrikeoutPosition = INTERNAL_YDSTOWS( dc, output->otmsStrikeoutPosition); ++ output->otmsUnderscoreSize = INTERNAL_YDSTOWS( dc, output->otmsUnderscoreSize); ++ output->otmsUnderscorePosition = INTERNAL_YDSTOWS( dc, output->otmsUnderscorePosition); + + if(output != lpOTM) + { +@@ -5554,7 +5544,7 @@ BOOL WINAPI NtGdiGetCharWidthW( HDC hdc, UINT first, UINT last, WCHAR *chars, + INT *buffer = buf; + /* convert device units to logical */ + for (i = 0; i < count; i++) +- buffer[i] = width_to_LP( dc, buffer[i] ); ++ buffer[i] = INTERNAL_XDSTOWS( dc, buffer[i] ); + } + else + { +@@ -5853,7 +5843,7 @@ BOOL nulldrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect + */ + static inline int get_line_width( DC *dc, int metric_size ) + { +- int width = abs( INTERNAL_YWSTODS( dc, metric_size )); ++ int width = abs( INTERNAL_XWSTODS( dc, metric_size )); + if (width == 0) width = 1; + if (metric_size < 0) width = -width; + return width; +@@ -6287,9 +6277,9 @@ BOOL WINAPI NtGdiGetCharABCWidthsW( HDC hdc, UINT first, UINT last, WCHAR *chars + /* convert device units to logical */ + for (i = 0; i < count; i++) + { +- abc[i].abcA = width_to_LP( dc, abc[i].abcA ); +- abc[i].abcB = width_to_LP( dc, abc[i].abcB ); +- abc[i].abcC = width_to_LP( dc, abc[i].abcC ); ++ abc[i].abcA = INTERNAL_XDSTOWS( dc, abc[i].abcA ); ++ abc[i].abcB = INTERNAL_XDSTOWS( dc, abc[i].abcB ); ++ abc[i].abcC = INTERNAL_XDSTOWS( dc, abc[i].abcC ); + } + } + else +@@ -7078,8 +7068,8 @@ BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info ) + + if (ret) + { +- info->lsb = width_to_LP( dc, info->lsb ); +- info->rsb = width_to_LP( dc, info->rsb ); ++ info->lsb = INTERNAL_XDSTOWS( dc, info->lsb ); ++ info->rsb = INTERNAL_XDSTOWS( dc, info->rsb ); + } + release_dc_ptr(dc); + return ret; +-- +2.46.0 + diff --git a/patches/win32u-NtGdiExtTextOutW-rotation/0002-win32u-NtGdiExtTextOutW-should-translate-x-y-from-lo.patch b/patches/win32u-NtGdiExtTextOutW-rotation/0002-win32u-NtGdiExtTextOutW-should-translate-x-y-from-lo.patch new file mode 100644 index 00000000..4292c2c9 --- /dev/null +++ b/patches/win32u-NtGdiExtTextOutW-rotation/0002-win32u-NtGdiExtTextOutW-should-translate-x-y-from-lo.patch @@ -0,0 +1,55 @@ +From 33d132644a7398e4a3a17f1745dcb626ea6694af Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 22 Nov 2023 11:51:23 +0300 +Subject: [PATCH 2/2] win32u: NtGdiExtTextOutW() should translate x,y from + logical to device units at the last step. + +Bug: https://bugs.winehq.org/show_bug.cgi?id=33190 + +Signed-off-by: Dmitry Timoshkov +--- + dlls/win32u/font.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c +index 8fbd8dc3f01..f32becbe669 100644 +--- a/dlls/win32u/font.c ++++ b/dlls/win32u/font.c +@@ -5972,12 +5972,6 @@ BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lpr + goto done; + } + +- pt.x = x; +- pt.y = y; +- lp_to_dp(dc, &pt, 1); +- x = pt.x; +- y = pt.y; +- + char_extra = dc->attr->char_extra; + if (char_extra && lpDx && NtGdiGetDeviceCaps( hdc, TECHNOLOGY ) == DT_RASPRINTER) + char_extra = 0; /* Printer drivers don't add char_extra if lpDx is supplied */ +@@ -6074,8 +6068,6 @@ BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lpr + width = desired[1]; + } + +- tm.tmAscent = abs(INTERNAL_YWSTODS(dc, tm.tmAscent)); +- tm.tmDescent = abs(INTERNAL_YWSTODS(dc, tm.tmDescent)); + switch( align & (TA_LEFT | TA_RIGHT | TA_CENTER) ) + { + case TA_LEFT: +@@ -6143,6 +6135,12 @@ BOOL WINAPI NtGdiExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *lpr + } + } + ++ pt.x = x; ++ pt.y = y; ++ lp_to_dp(dc, &pt, 1); ++ x = pt.x; ++ y = pt.y; ++ + ret = physdev->funcs->pExtTextOut( physdev, x, y, (flags & ~ETO_OPAQUE), &rc, + str, count, (INT*)deltas ); + +-- +2.46.0 + diff --git a/patches/win32u-NtGdiExtTextOutW-rotation/definition b/patches/win32u-NtGdiExtTextOutW-rotation/definition new file mode 100644 index 00000000..baad6c4c --- /dev/null +++ b/patches/win32u-NtGdiExtTextOutW-rotation/definition @@ -0,0 +1,3 @@ +Fixes [33190]: win32u - Fix rendering of the rotated and scaled text. + +# Merge Request !5068 \ No newline at end of file