[PATCH v3 1/4] d3dx9: Handle vertical alignment in ID3DXFont_DrawText.

Sven Baars sbaars at codeweavers.com
Fri Mar 27 11:31:29 CDT 2020


Signed-off-by: Sven Baars <sbaars at codeweavers.com>
---
 dlls/d3dx9_36/font.c       | 170 +++++++++++++++++++++++--------------
 dlls/d3dx9_36/tests/core.c | 152 ++++++++++++++++++++++++++++++++-
 2 files changed, 257 insertions(+), 65 deletions(-)

diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c
index 54b1574bb1..20757ae839 100644
--- a/dlls/d3dx9_36/font.c
+++ b/dlls/d3dx9_36/font.c
@@ -599,16 +599,56 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count,
     return NULL;
 }
 
+static int compute_rect(struct d3dx_font *font, const WCHAR *string, INT count, WCHAR *line, RECT *rect, DWORD format)
+{
+    int y, lh, width, top = rect->top;
+    int max_width = 0;
+    SIZE size;
+
+    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;
+        if (!(format & DT_NOCLIP) && (y > rect->bottom))
+            break;
+    }
+
+    rect->right = rect->left + max_width;
+    if (format & DT_VCENTER)
+    {
+        rect->top += (rect->bottom - y) / 2;
+        rect->bottom = rect->top + y - top;
+    }
+    else if (format & DT_BOTTOM)
+    {
+        rect->top += rect->bottom - y;
+    }
+    else
+    {
+        rect->bottom = y;
+    }
+
+    return rect->bottom - top;
+}
+
 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);
+    int lh, x, y, width, top, ret = 0;
     ID3DXSprite *target = sprite;
+    RECT r = {0};
     WCHAR *line;
-    RECT textrect = {0};
-    int lh, x, y, width;
-    int max_width = 0;
-    int ret = 0;
     SIZE size;
 
     TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x.\n",
@@ -629,20 +669,41 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
     if (format & DT_SINGLELINE)
         format &= ~DT_WORDBREAK;
 
-    if (rect)
-        textrect = *rect;
-
-    x = textrect.left;
-    y = textrect.top;
-    width = textrect.right - textrect.left;
-
-    lh = font->metrics.tmHeight;
-
     line = heap_alloc(count * sizeof(*line));
     if (!line)
         return 0;
 
-    if (!(format & DT_CALCRECT) && !sprite)
+    if (!rect || format & (DT_CALCRECT | DT_VCENTER | DT_BOTTOM))
+    {
+        if (!rect)
+        {
+            rect = &r;
+            format |= DT_NOCLIP;
+        }
+        else if (!(format & DT_CALCRECT))
+        {
+            r = *rect;
+            rect = &r;
+        }
+
+        top = rect->top;
+
+        ret = compute_rect(font, string, count, line, rect, format);
+
+        if (format & DT_CALCRECT)
+            goto cleanup;
+    }
+    else
+    {
+        top = rect->top;
+    }
+
+    x = rect->left;
+    y = rect->top;
+    lh = font->metrics.tmHeight;
+    width = rect->right - rect->left;
+
+    if (!sprite)
     {
         D3DXCreateSprite(font->device, &target);
         ID3DXSprite_Begin(target, 0);
@@ -650,72 +711,55 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
 
     while (string)
     {
-        unsigned int line_len;
+        unsigned int line_len, i;
+        GCP_RESULTSW results;
+        D3DXVECTOR3 pos;
 
         string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size);
 
-        if (!(format & DT_CALCRECT))
-        {
-            GCP_RESULTSW results;
-            D3DXVECTOR3 pos;
-            unsigned int i;
-
-            memset(&results, 0, sizeof(results));
-            results.nGlyphs = line_len;
+        memset(&results, 0, sizeof(results));
+        results.nGlyphs = line_len;
 
-            results.lpCaretPos = heap_alloc(line_len * sizeof(*results.lpCaretPos));
-            if (!results.lpCaretPos)
-                goto cleanup;
-
-            results.lpGlyphs = heap_alloc(line_len * sizeof(*results.lpGlyphs));
-            if (!results.lpGlyphs)
-            {
-                heap_free(results.lpCaretPos);
-                goto cleanup;
-            }
+        results.lpCaretPos = heap_alloc(line_len * sizeof(*results.lpCaretPos));
+        if (!results.lpCaretPos)
+            goto cleanup;
 
-            GetCharacterPlacementW(font->hdc, line, line_len, 0, &results, 0);
+        results.lpGlyphs = heap_alloc(line_len * sizeof(*results.lpGlyphs));
+        if (!results.lpGlyphs)
+        {
+            heap_free(results.lpCaretPos);
+            goto cleanup;
+        }
 
-            for (i = 0; i < results.nGlyphs; ++i)
-            {
-                IDirect3DTexture9 *texture;
-                POINT cell_inc;
-                RECT black_box;
+        GetCharacterPlacementW(font->hdc, line, line_len, 0, &results, 0);
 
-                ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, &black_box, &cell_inc);
+        for (i = 0; i < results.nGlyphs; ++i)
+        {
+            IDirect3DTexture9 *texture;
+            POINT cell_inc;
+            RECT black_box;
 
-                if (!texture)
-                    continue;
+            ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, &black_box, &cell_inc);
 
-                pos.x = cell_inc.x + x + results.lpCaretPos[i];
-                pos.y = cell_inc.y + y;
+            if (!texture)
+                continue;
 
-                ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color);
-                IDirect3DTexture9_Release(texture);
-            }
+            pos.x = cell_inc.x + x + results.lpCaretPos[i];
+            pos.y = cell_inc.y + y;
 
-            heap_free(results.lpCaretPos);
-            heap_free(results.lpGlyphs);
-        }
-        else if (size.cx > max_width)
-        {
-            max_width = size.cx;
+            ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color);
+            IDirect3DTexture9_Release(texture);
         }
 
+        heap_free(results.lpCaretPos);
+        heap_free(results.lpGlyphs);
+
         y += lh;
-        if (!(DT_NOCLIP & format) && (y > textrect.bottom))
+        if (!(DT_NOCLIP & format) && (y > rect->bottom))
             break;
     }
 
-    if (format & DT_CALCRECT && rect)
-    {
-        *rect = textrect;
-
-        rect->bottom = y;
-        rect->right = rect->left + max_width;
-    }
-
-    ret = y - textrect.top;
+    ret = y - top;
 
 cleanup:
     if (target != sprite)
diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c
index fb55a547a0..9de91b2b08 100644
--- a/dlls/d3dx9_36/tests/core.c
+++ b/dlls/d3dx9_36/tests/core.c
@@ -770,6 +770,9 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
     height = ID3DXFont_DrawTextW(font, NULL, long_textW, -1, &rect, DT_WORDBREAK | DT_NOCLIP, 0xff00ff);
     ok(height == 96, "Got unexpected height %d.\n", height);
 
+    height = ID3DXFont_DrawTextW(font, NULL, L"a\na", -1, NULL, 0, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+
     height = ID3DXFont_DrawTextW(font, NULL, L"a\na", -1, &rect, 0, 0xff00ff);
     ok(height == 24, "Got unexpected height %d.\n", height);
 
@@ -843,10 +846,10 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
     ok(height == 36, "Got unexpected height %d.\n", height);
 
     height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM, 0xff00ff);
-    todo_wine ok(height == 40, "Got unexpected height %d.\n", height);
+    ok(height == 40, "Got unexpected height %d.\n", height);
 
     height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER, 0xff00ff);
-    todo_wine ok(height == 32, "Got unexpected height %d.\n", height);
+    ok(height == 32, "Got unexpected height %d.\n", height);
 
     height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT, 0xff00ff);
     ok(height == 24, "Got unexpected height %d.\n", height);
@@ -859,6 +862,151 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
     ok(height == 24, "Got unexpected height %d.\n", height);
     check_rect(&rect, 10, 10, 30, 34);
 
+    SetRect(&rect, -10, 10, 30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, -10, 10, 10, 34);
+
+    SetRect(&rect, 10, -10, 50, 30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -10, 30, 14);
+
+    SetRect(&rect, 10, 10, -30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 10, 30, 34);
+
+    SetRect(&rect, 10, 10, 50, -30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 10, 30, 34);
+
+    SetRect(&rect, 10, 10, 50, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 10, 30, 34);
+
+    SetRect(&rect, -10, 10, 30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, -10, 10, 10, 34);
+
+    SetRect(&rect, 10, -10, 50, 30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -10, 30, 14);
+
+    SetRect(&rect, 10, 10, -30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 12, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 10, 53, 22);
+
+    SetRect(&rect, 10, 10, 50, -30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 24, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 10, 30, 34);
+
+    SetRect(&rect, 10, 10, 50, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 26, 30, 50);
+
+    SetRect(&rect, -10, 10, 30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, -10, 26, 10, 50);
+
+    SetRect(&rect, 10, -10, 50, 30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 6, 30, 30);
+
+    SetRect(&rect, 10, 10, -30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 26, 30, 50);
+
+    SetRect(&rect, 10, 10, 50, -30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff);
+    ok(height == -40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -54, 30, -30);
+
+    SetRect(&rect, 10, 10, 50, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 26, 30, 50);
+
+    SetRect(&rect, -10, 10, 30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, -10, 26, 10, 50);
+
+    SetRect(&rect, 10, -10, 50, 30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 6, 30, 30);
+
+    SetRect(&rect, 10, 10, -30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 38, 53, 50);
+
+    SetRect(&rect, 10, 10, 50, -30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == -40, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -54, 30, -30);
+
+    SetRect(&rect, 10, 10, 50, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff);
+    ok(height == 32, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 18, 30, 42);
+
+    SetRect(&rect, -10, 10, 30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff);
+    ok(height == 32, "Got unexpected height %d.\n", height);
+    check_rect(&rect, -10, 18, 10, 42);
+
+    SetRect(&rect, 10, -10, 50, 30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff);
+    ok(height == 32, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -2, 30, 22);
+
+    SetRect(&rect, 10, 10, -30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff);
+    ok(height == 32, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 18, 30, 42);
+
+    SetRect(&rect, 10, 10, 50, -30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff);
+    ok(height == -8, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -22, 30, 2);
+
+    SetRect(&rect, 10, 10, 50, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 32, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 18, 30, 42);
+
+    SetRect(&rect, -10, 10, 30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 32, "Got unexpected height %d.\n", height);
+    check_rect(&rect, -10, 18, 10, 42);
+
+    SetRect(&rect, 10, -10, 50, 30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 32, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -2, 30, 22);
+
+    SetRect(&rect, 10, 10, -30, 50);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == 26, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, 24, 53, 36);
+
+    SetRect(&rect, 10, 10, 50, -30);
+    height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff);
+    ok(height == -8, "Got unexpected height %d.\n", height);
+    check_rect(&rect, 10, -22, 30, 2);
+
     ID3DXFont_Release(font);
 }
 
-- 
2.24.0




More information about the wine-devel mailing list