These patches make a test case attached to the bug https://bugs.winehq.org/show_bug.cgi?id=33190 work.
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/win32u/font.c | 48 ++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 23 deletions(-)
diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index 9ee89f1b5c4..1726165e778 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -228,12 +228,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 = sqrtf(dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM11 + dc->xformWorld2Vport.eM12 * dc->xformWorld2Vport.eM12); + return GDI_ROUND( (float)width / scale_x ); }
/* Performs a device to world transformation on the specified size (which @@ -241,34 +239,38 @@ 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 = sqrtf(dc->xformWorld2Vport.eM21 * dc->xformWorld2Vport.eM21 + dc->xformWorld2Vport.eM22 * 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 ) { - return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 )); + return INTERNAL_XDSTOWS( dc, width ); }
static inline INT height_to_LP( DC *dc, INT height ) { - return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 )); + return INTERNAL_YDSTOWS( dc, height ); +} + +static inline INT INTERNAL_XWSTODS(DC *dc, INT width) +{ + float scale_x; + + scale_x = sqrtf(dc->xformVport2World.eM11 * dc->xformVport2World.eM11 + dc->xformVport2World.eM12 * dc->xformVport2World.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 = sqrtf(dc->xformVport2World.eM21 * dc->xformVport2World.eM21 + dc->xformVport2World.eM22 * dc->xformVport2World.eM22); + return GDI_ROUND( (float)height / scale_y ); }
static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer ); @@ -4195,8 +4197,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 *= sqrtf(font->matrix.eM11 * font->matrix.eM11 + font->matrix.eM12 * font->matrix.eM12); + scale_y = font->scale_y * sqrtf(font->matrix.eM21 * font->matrix.eM21 + font->matrix.eM22 * 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)) @@ -4410,8 +4412,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 *= sqrtf(font->matrix.eM11 * font->matrix.eM11 + font->matrix.eM12 * font->matrix.eM12); + scale_y = font->scale_y * sqrtf(font->matrix.eM21 * font->matrix.eM21 + font->matrix.eM22 * font->matrix.eM22);
#define SCALE_X(x) (x) = GDI_ROUND((x) * scale_x) #define SCALE_Y(y) (y) = GDI_ROUND((y) * scale_y) @@ -5838,7 +5840,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;
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- 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 1726165e778..561dd99b085 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -5969,12 +5969,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 */ @@ -6071,8 +6065,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: @@ -6140,6 +6132,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 );
Is there any hope to get a review of these patches?
Huw Davies (@huw) commented about dlls/win32u/font.c:
}
/* scale width and height but don't mirror them */
static inline INT width_to_LP( DC *dc, INT width ) {
- return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
- return INTERNAL_XDSTOWS( dc, width );
}
static inline INT height_to_LP( DC *dc, INT height ) {
- return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
- return INTERNAL_YDSTOWS( dc, height );
+}
So now `INTERNAL_XDSTOWS()` and `width_to_LP()` are the same. If this is really what we want we should unify them before changing the implementation.
Also, `hypot()` may be useful here.
On Mon Mar 4 14:12:00 2024 +0000, Huw Davies wrote:
So now `INTERNAL_XDSTOWS()` and `width_to_LP()` are the same. If this is really what we want we should unify them before changing the implementation. Also, `hypot()` may be useful here.
Hi Huw,
thanks for the review.
/* scale width and height but don't mirror them */
static inline INT width_to_LP( DC *dc, INT width ) {
- return GDI_ROUND( (double)width * fabs( dc->xformVport2World.eM11 ));
- return INTERNAL_XDSTOWS( dc, width );
}
static inline INT height_to_LP( DC *dc, INT height ) {
- return GDI_ROUND( (double)height * fabs( dc->xformVport2World.eM22 ));
- return INTERNAL_YDSTOWS( dc, height );
+}
So now `INTERNAL_XDSTOWS()` and `width_to_LP()` are the same. If this is really what we want we should unify them before changing the implementation.
Do you mean by unifying adding a patch that replaces width_to_LP() by INTERNAL_XDSTOWS() and height_to_LP() by INTERNAL_YDSTOWS()? If yes, then with current implementation this leads to test failures.
Also, `hypot()` may be useful here.
Thanks.