gdi32: Add an extensive EnumFontFamilies test, fix some failures when running under Wine

Dmitry Timoshkov dmitry at codeweavers.com
Tue Mar 6 05:14:25 CST 2007


Hello,

Changelog:
    gdi32: Add an extensive EnumFontFamilies test, fix some failures
    when running under Wine.

---
 dlls/gdi32/font.c       |   18 +++-
 dlls/gdi32/tests/font.c |  273 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 286 insertions(+), 5 deletions(-)

diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 3fc4420..1b1d8b4 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -877,7 +877,11 @@ INT16 WINAPI EnumFontFamilies16( HDC16 hDC, LPCSTR lpFamily,
     LOGFONT16	lf;
 
     lf.lfCharSet = DEFAULT_CHARSET;
-    if( lpFamily ) lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
+    if (lpFamily)
+    {
+        if (!*lpFamily) return 1;
+        lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
+    }
     else lf.lfFaceName[0] = '\0';
 
     return EnumFontFamiliesEx16( hDC, &lf, efproc, lpData, 0 );
@@ -892,7 +896,11 @@ INT WINAPI EnumFontFamiliesA( HDC hDC, LPCSTR lpFamily,
     LOGFONTA	lf;
 
     lf.lfCharSet = DEFAULT_CHARSET;
-    if( lpFamily ) lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
+    if (lpFamily)
+    {
+        if (!*lpFamily) return 1;
+        lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
+    }
     else lf.lfFaceName[0] = lf.lfFaceName[1] = '\0';
 
     return EnumFontFamiliesExA( hDC, &lf, efproc, lpData, 0 );
@@ -907,7 +915,11 @@ INT WINAPI EnumFontFamiliesW( HDC hDC, LPCWSTR lpFamily,
     LOGFONTW  lf;
 
     lf.lfCharSet = DEFAULT_CHARSET;
-    if( lpFamily ) lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
+    if (lpFamily)
+    {
+        if (!*lpFamily) return 1;
+        lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
+    }
     else lf.lfFaceName[0] = 0;
 
     return EnumFontFamiliesExW( hDC, &lf, efproc, lpData, 0 );
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index ce8d2fa..43e9c3a 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -49,6 +49,25 @@ static void init(void)
     pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
 }
 
+static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
+{
+    if (type != TRUETYPE_FONTTYPE) return 1;
+
+    return 0;
+}
+
+static BOOL is_truetype_font_installed(const char *name)
+{
+    HDC hdc = GetDC(0);
+    BOOL ret = FALSE;
+
+    if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
+        ret = TRUE;
+
+    ReleaseDC(0, hdc);
+    return ret;
+}
+
 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
 {
     return 0;
@@ -1104,7 +1123,7 @@ static void test_GetFontUnicodeRanges(void)
     LOGFONTA lf;
     HDC hdc;
     HFONT hfont, hfont_old;
-    DWORD size, i;
+    DWORD size;
     GLYPHSET *gs;
 
     if (!pGetFontUnicodeRanges)
@@ -1130,9 +1149,10 @@ static void test_GetFontUnicodeRanges(void)
 
     size = pGetFontUnicodeRanges(hdc, gs);
     ok(size, "GetFontUnicodeRanges failed\n");
-
+#if 0
     for (i = 0; i < gs->cRanges; i++)
         trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
+#endif
     trace("found %u ranges\n", gs->cRanges);
 
     HeapFree(GetProcessHeap(), 0, gs);
@@ -1142,6 +1162,241 @@ static void test_GetFontUnicodeRanges(void)
     ReleaseDC(NULL, hdc);
 }
 
+#define MAX_ENUM_FONTS 256
+
+struct enum_font_data
+{
+    int total;
+    LOGFONT lf[MAX_ENUM_FONTS];
+};
+
+static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
+{
+    struct enum_font_data *efd = (struct enum_font_data *)lParam;
+
+    if (type != TRUETYPE_FONTTYPE) return 1;
+#if 0
+    trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
+          lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
+#endif
+    if (efd->total < MAX_ENUM_FONTS)
+        efd->lf[efd->total++] = *lf;
+
+    return 1;
+}
+
+static void get_charset_stats(struct enum_font_data *efd,
+                              int *ansi_charset, int *symbol_charset,
+                              int *russian_charset)
+{
+    int i;
+
+    *ansi_charset = 0;
+    *symbol_charset = 0;
+    *russian_charset = 0;
+
+    for (i = 0; i < efd->total; i++)
+    {
+        switch (efd->lf[i].lfCharSet)
+        {
+        case ANSI_CHARSET:
+            (*ansi_charset)++;
+            break;
+        case SYMBOL_CHARSET:
+            (*symbol_charset)++;
+            break;
+        case RUSSIAN_CHARSET:
+            (*russian_charset)++;
+            break;
+        }
+    }
+}
+
+static void test_EnumFontFamilies(const char *font_name, INT font_charset)
+{
+    struct enum_font_data efd;
+    LOGFONT lf;
+    HDC hdc;
+    int i, ret, ansi_charset, symbol_charset, russian_charset;
+
+    trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
+
+    if (*font_name && !is_truetype_font_installed(font_name))
+    {
+        skip("%s is not installed\n", font_name);
+        return;
+    }
+
+    hdc = GetDC(0);
+
+    /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
+     * while EnumFontFamiliesEx doesn't.
+     */
+    if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
+    {
+        efd.total = 0;
+        SetLastError(0xdeadbeef);
+        ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
+        ok(ret, "EnumFontFamilies error %u\n", GetLastError());
+        get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
+        trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
+              ansi_charset, symbol_charset, russian_charset);
+        ok(efd.total > 0, "no fonts enumerated: NULL\n");
+        ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
+        ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
+        ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
+    }
+
+    efd.total = 0;
+    SetLastError(0xdeadbeef);
+    ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
+    ok(ret, "EnumFontFamilies error %u\n", GetLastError());
+    get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
+    trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
+          ansi_charset, symbol_charset, russian_charset,
+          *font_name ? font_name : "<empty>");
+    if (*font_name)
+        ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
+    else
+        ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
+    for (i = 0; i < efd.total; i++)
+    {
+/* FIXME: remove completely once Wine is fixed */
+if (efd.lf[i].lfCharSet != font_charset)
+{
+todo_wine
+    ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
+}
+else
+        ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
+        ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
+           font_name, efd.lf[i].lfFaceName);
+    }
+
+    memset(&lf, 0, sizeof(lf));
+    lf.lfCharSet = ANSI_CHARSET;
+    lstrcpy(lf.lfFaceName, font_name);
+    efd.total = 0;
+    SetLastError(0xdeadbeef);
+    ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
+    ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
+    get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
+    trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
+          ansi_charset, symbol_charset, russian_charset,
+          *font_name ? font_name : "<empty>");
+    if (font_charset == SYMBOL_CHARSET)
+    {
+        if (*font_name)
+            ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
+        else
+            ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
+    }
+    else
+    {
+        ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
+        for (i = 0; i < efd.total; i++)
+        {
+            ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
+            if (*font_name)
+                ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
+                   font_name, efd.lf[i].lfFaceName);
+        }
+    }
+
+    /* DEFAULT_CHARSET should enumerate all available charsets */
+    memset(&lf, 0, sizeof(lf));
+    lf.lfCharSet = DEFAULT_CHARSET;
+    lstrcpy(lf.lfFaceName, font_name);
+    efd.total = 0;
+    SetLastError(0xdeadbeef);
+    EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
+    ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
+    get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
+    trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
+          ansi_charset, symbol_charset, russian_charset,
+          *font_name ? font_name : "<empty>");
+    ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
+    for (i = 0; i < efd.total; i++)
+    {
+        if (*font_name)
+            ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
+               font_name, efd.lf[i].lfFaceName);
+    }
+    if (*font_name)
+    {
+        switch (font_charset)
+        {
+        case ANSI_CHARSET:
+            ok(ansi_charset > 0,
+               "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
+            ok(!symbol_charset,
+               "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
+            ok(russian_charset > 0,
+               "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
+            break;
+        case SYMBOL_CHARSET:
+            ok(!ansi_charset,
+               "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
+            ok(symbol_charset,
+               "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
+            ok(!russian_charset,
+               "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
+            break;
+        case DEFAULT_CHARSET:
+            ok(ansi_charset > 0,
+               "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
+            ok(symbol_charset > 0,
+               "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
+            ok(russian_charset > 0,
+               "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
+            break;
+        }
+    }
+    else
+    {
+        ok(ansi_charset > 0,
+           "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
+        ok(symbol_charset > 0,
+           "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
+        ok(russian_charset > 0,
+           "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
+    }
+
+    memset(&lf, 0, sizeof(lf));
+    lf.lfCharSet = SYMBOL_CHARSET;
+    lstrcpy(lf.lfFaceName, font_name);
+    efd.total = 0;
+    SetLastError(0xdeadbeef);
+    EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
+    ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
+    get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
+    trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
+          ansi_charset, symbol_charset, russian_charset,
+          *font_name ? font_name : "<empty>");
+    if (*font_name && font_charset == ANSI_CHARSET)
+        ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
+    else
+    {
+        ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
+        for (i = 0; i < efd.total; i++)
+        {
+            ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
+            if (*font_name)
+                ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
+                   font_name, efd.lf[i].lfFaceName);
+        }
+
+        ok(!ansi_charset,
+           "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
+        ok(symbol_charset > 0,
+           "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
+        ok(!russian_charset,
+           "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
+    }
+
+    ReleaseDC(0, hdc);
+}
+
 START_TEST(font)
 {
     init();
@@ -1158,4 +1413,18 @@ START_TEST(font)
     test_SetTextJustification();
     test_font_charset();
     test_GetFontUnicodeRanges();
+    /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
+     * I'd like to avoid them in this test.
+     */
+    test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
+    test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
+    if (is_truetype_font_installed("Arial Black") &&
+        (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
+    {
+        test_EnumFontFamilies("", ANSI_CHARSET);
+        test_EnumFontFamilies("", SYMBOL_CHARSET);
+        test_EnumFontFamilies("", DEFAULT_CHARSET);
+    }
+    else
+        skip("Arial Black or Symbol/Wingdings is not installed\n");
 }
-- 
1.5.0.2






More information about the wine-patches mailing list