[PATCH v2 1/5] d3dx9: Handle vertical alignment in ID3DXFont_DrawText.

Matteo Bruni matteo.mystral at gmail.com
Tue Mar 24 08:08:53 CDT 2020


I spent a bunch of time tinkering with this, mostly to understand what
the tests check and thus the expected behavior. I came up with the
attached patch, based on top of this one: it isn't necessarily an
improvement, although it does get rid of the recursion (which I don't
like). I left all the debug traces in, it isn't a clean patch by any
means, but I think it shows a possible direction for the
implementation.
I haven't checked that it still works (or even that it still makes
sense) with the other patches in the series.
-------------- next part --------------
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c
index 56efb11dfd7..9133ae3bc5e 100644
--- a/dlls/d3dx9_36/font.c
+++ b/dlls/d3dx9_36/font.c
@@ -587,6 +587,7 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count,
             *count = 0;
         }
     }
+    TRACE("size.x %u, size.y %u, num_fit %u\n", size->cx, size->cy, num_fit);
 
     if (*count && str[i] == '\n')
     {
@@ -599,14 +600,52 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count,
     return NULL;
 }
 
+static void compute_rect(struct d3dx_font *font, const WCHAR *string, INT count, WCHAR *line, RECT *rect, DWORD format)
+{
+    unsigned int width, max_width = 0, y, lh;
+    SIZE size;
+
+    TRACE("rect %s.\n", wine_dbgstr_rect(rect));
+
+    y = rect->top;
+    lh = font->metrics.tmHeight;
+    width = rect->right - rect->left;
+    while (string)
+    {
+        unsigned int line_len;
+
+        string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size);
+        if (size.cx > max_width)
+            max_width = size.cx;
+        y += lh;
+        TRACE("y %u\n", y);
+        if (!(format & DT_NOCLIP) && (y > rect->bottom))
+            break;
+    }
+    if (format & DT_VCENTER)
+    {
+        rect->top = rect->top + (rect->bottom - y) / 2;
+        rect->bottom -= (rect->bottom - y) / 2;
+    }
+    else if (format & DT_BOTTOM)
+    {
+        rect->top += rect->bottom - y;
+    }
+    else
+    {
+        rect->bottom = y;
+    }
+    rect->right = rect->left + max_width;
+    TRACE("rect %s\n", wine_dbgstr_rect(rect));
+}
+
 static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
         const WCHAR *string, INT count, RECT *rect, DWORD format, D3DCOLOR color)
 {
     struct d3dx_font *font = impl_from_ID3DXFont(iface);
-    RECT calcrect, textrect = {0};
+    RECT r = {0}, *orig_rect = rect;
     ID3DXSprite *target = sprite;
     int lh, x, y, width;
-    int max_width = 0;
     int ret = 0;
     WCHAR *line;
     SIZE size;
@@ -629,46 +668,49 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
     if (format & DT_SINGLELINE)
         format &= ~DT_WORDBREAK;
 
-    if (!rect)
-    {
-        y = ID3DXFont_DrawTextW(iface, NULL, string, count, &textrect, format | DT_CALCRECT, 0);
-
-        if (format & DT_CALCRECT)
-            return y;
-    }
-    else
-    {
-        textrect = *rect;
-    }
-
-    calcrect = textrect;
+    line = heap_alloc(count * sizeof(*line));
+    if (!line)
+        return 0;
 
-    if (format & (DT_VCENTER | DT_BOTTOM))
+    if (!rect || format & (DT_CALCRECT | DT_VCENTER | DT_BOTTOM))
     {
-        y = ID3DXFont_DrawTextW(iface, NULL, string, count, &calcrect,
-                (format & ~DT_BOTTOM & ~DT_VCENTER) | DT_CALCRECT, 0);
+        DWORD flags = format;
 
-        if (format & DT_VCENTER)
+        if (!rect)
         {
-            calcrect.top = textrect.top + (textrect.bottom - textrect.top - y) / 2;
-            calcrect.bottom = calcrect.top + y;
+            orig_rect = &r;
+            flags |= DT_NOCLIP;
         }
-        else if (format & DT_BOTTOM)
+        else
+            r = *rect;
+
+        compute_rect(font, string, count, line, &r, flags);
+
+        if (format & DT_CALCRECT)
         {
-            calcrect.top = textrect.bottom - y;
+            if (rect)
+            {
+                ret = r.bottom - rect->top;
+                *rect = r;
+            }
+            else
+            {
+                ret = r.bottom - r.top;
+            }
+            return ret;
         }
+
+        rect = &r;
     }
 
-    x = calcrect.left;
-    y = calcrect.top;
-    width = calcrect.right - calcrect.left;
+    TRACE("rect %s\n", wine_dbgstr_rect(rect));
+    x = rect->left;
+    y = rect->top;
+    width = rect->right - rect->left;
+    TRACE("y %u\n", y);
 
     lh = font->metrics.tmHeight;
 
-    line = heap_alloc(count * sizeof(*line));
-    if (!line)
-        return 0;
-
     if (!(format & DT_CALCRECT) && !sprite)
     {
         D3DXCreateSprite(font->device, &target);
@@ -724,25 +766,14 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
             heap_free(results.lpCaretPos);
             heap_free(results.lpGlyphs);
         }
-        else if (size.cx > max_width)
-        {
-            max_width = size.cx;
-        }
 
         y += lh;
-        if (!(DT_NOCLIP & format) && (y > textrect.bottom))
+        TRACE("y %u\n", y);
+        if (!(DT_NOCLIP & format) && (y > rect->bottom))
             break;
     }
 
-    if (format & DT_CALCRECT)
-    {
-        *rect = calcrect;
-
-        rect->bottom = y;
-        rect->right = rect->left + max_width;
-    }
-
-    ret = y - textrect.top;
+    ret = y - orig_rect->top;
 
 cleanup:
     if (target != sprite)


More information about the wine-devel mailing list