gdi32: Add a GetTextMetrics test, make it pass under Wine

Dmitry Timoshkov dmitry at codeweavers.com
Fri Mar 9 06:46:00 CST 2007


Hello,

this patch should partially resolve a problem reported in the bug 5783.

In Wine GetTextMetricsW returns wrong tmFirstChar/tmLastChar, and
GetFontUnicodeRanges returns wrong ranges for fonts with SYMBOL_CHARSET.

Changelog:
    gdi32: Add a GetTextMetrics test, make it pass under Wine.

---
 dlls/gdi32/font.c       |    9 ++-
 dlls/gdi32/freetype.c   |    4 +-
 dlls/gdi32/tests/font.c |  141 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 149 insertions(+), 5 deletions(-)

diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 1b1d8b4..785a990 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -287,10 +287,12 @@ static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
     ptmA->tmOverhang = ptmW->tmOverhang;
     ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
     ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
-    ptmA->tmFirstChar = ptmW->tmFirstChar > 255 ? 255 : ptmW->tmFirstChar;
+    ptmA->tmBreakChar = ptmW->tmBreakChar > 255 ? 255 : ptmW->tmBreakChar;
+    /* This appears to be what Windows does */
+    ptmA->tmFirstChar = ptmW->tmBreakChar;
+    if (ptmA->tmFirstChar >= 2) ptmA->tmFirstChar -= 2;
     ptmA->tmLastChar = ptmW->tmLastChar > 255 ? 255 : ptmW->tmLastChar;
     ptmA->tmDefaultChar = ptmW->tmDefaultChar > 255 ? 255 : ptmW->tmDefaultChar;
-    ptmA->tmBreakChar = ptmW->tmBreakChar > 255 ? 255 : ptmW->tmBreakChar;
     ptmA->tmItalic = ptmW->tmItalic;
     ptmA->tmUnderlined = ptmW->tmUnderlined;
     ptmA->tmStruckOut = ptmW->tmStruckOut;
@@ -1366,6 +1368,9 @@ BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
     /* device layer returns values in device units
      * therefore we have to convert them to logical */
 
+        metrics->tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
+        metrics->tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
+
 #define WDPTOLP(x) ((x<0)?					\
 		(-abs(INTERNAL_XDSTOWS(dc, (x)))):		\
 		(abs(INTERNAL_XDSTOWS(dc, (x)))))
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index db990fa..03adfe5 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -4480,7 +4480,7 @@ static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
 {
     DWORD num_ranges = 0;
 
-    if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
+    if (pFT_Get_First_Char)
     {
         FT_UInt glyph_code;
         FT_ULong char_code, char_code_prev;
@@ -4488,7 +4488,7 @@ static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
         glyph_code = 0;
         char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
 
-        TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
+        TRACE("number of glyphs %ld, first glyph %u, first char %04lx\n",
                face->num_glyphs, glyph_code, char_code);
 
         if (!glyph_code) return 0;
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 43e9c3a..a996ff0 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -408,7 +408,7 @@ static void test_GdiGetCharDimensions(void)
 
     if (!pGdiGetCharDimensions)
     {
-        skip("GetFontUnicodeRanges not available on this platform\n");
+        skip("GdiGetCharDimensions not available on this platform\n");
         return;
     }
 
@@ -1149,6 +1149,7 @@ static void test_GetFontUnicodeRanges(void)
 
     size = pGetFontUnicodeRanges(hdc, gs);
     ok(size, "GetFontUnicodeRanges failed\n");
+    ok(gs->cRanges != 0, "GetFontUnicodeRanges returned empty ranges\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);
@@ -1397,6 +1398,143 @@ else
     ReleaseDC(0, hdc);
 }
 
+static void test_text_metrics(const LOGFONTA *lf)
+{
+    HDC hdc;
+    HFONT hfont, hfont_old;
+    TEXTMETRICA tmA;
+    TEXTMETRICW tmW;
+    UINT first_unicode_char = 0, last_unicode_char = 0;
+    INT ret, test_char;
+    const char *font_name = lf->lfFaceName;
+
+    trace("Testing font metrics for %s, charset %d\n", font_name, lf->lfCharSet);
+
+    hdc = GetDC(0);
+
+    SetLastError(0xdeadbeef);
+    hfont = CreateFontIndirectA(lf);
+    ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
+
+    hfont_old = SelectObject(hdc, hfont);
+
+    if (pGetFontUnicodeRanges)
+    {
+        DWORD size;
+        GLYPHSET *gs;
+
+        size = pGetFontUnicodeRanges(hdc, NULL);
+        ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
+
+        gs = HeapAlloc(GetProcessHeap(), 0, size);
+
+        size = pGetFontUnicodeRanges(hdc, gs);
+        ok(size, "GetFontUnicodeRanges failed\n");
+        ok(gs->cRanges != 0, "GetFontUnicodeRanges returned empty ranges\n");
+
+        first_unicode_char = gs->ranges[0].wcLow;
+        last_unicode_char = gs->ranges[gs->cRanges - 1].wcLow + gs->ranges[gs->cRanges - 1].cGlyphs - 1;
+        trace("for %s first char %x, last char %x\n", font_name,
+               first_unicode_char, last_unicode_char);
+
+        HeapFree(GetProcessHeap(), 0, gs);
+    }
+
+    SetLastError(0xdeadbeef);
+    ret = GetTextMetricsA(hdc, &tmA);
+    ok(ret, "GetTextMetricsA error %u\n", GetLastError());
+
+    trace("A: first %x, last %x, default %x, break %x\n",
+          tmA.tmFirstChar, tmA.tmLastChar, tmA.tmDefaultChar, tmA.tmBreakChar);
+
+    SetLastError(0xdeadbeef);
+    ret = GetTextMetricsW(hdc, &tmW);
+    ok(ret, "GetTextMetricsA error %u\n", GetLastError());
+
+    trace("W: first %x, last %x, default %x, break %x\n",
+          tmW.tmFirstChar, tmW.tmLastChar, tmW.tmDefaultChar, tmW.tmBreakChar);
+
+    /* This appears to be what Windows does */
+    test_char = tmW.tmBreakChar;
+    if (test_char >= 2) test_char -= 2;
+    if (test_char > 255) test_char = 255;
+    ok(tmA.tmFirstChar == test_char, "tmFirstChar for %s %02x != %02x\n",
+       font_name, tmA.tmFirstChar, test_char);
+
+    /* This test failes for Marlett, Wingdings 2 and Wingdings 3, but succeeds
+     * for all other 327 truetype fonts on my system. 
+     */
+#if 0
+    test_char = tmW.tmLastChar > 255 ? 255 : tmW.tmLastChar;
+    ok(tmA.tmLastChar == test_char, "tmLastChar for %s %02x != %02x\n",
+       font_name, tmA.tmLastChar, test_char);
+#endif
+    if (pGetFontUnicodeRanges)
+    {
+        ok(tmW.tmFirstChar == first_unicode_char, "tmFirstChar for %s %02x != %02x\n",
+           font_name, tmW.tmFirstChar, first_unicode_char);
+/* FIXME: remove completely once Wine is fixed
+ * GetFontUnicodeRanges in Wine returns wrong data for fonts with
+ * SYMBOL_CHARSET.
+ */
+if (tmW.tmLastChar != last_unicode_char)
+todo_wine  ok(tmW.tmLastChar == last_unicode_char, "tmLastChar for %s %02x != %02x\n",
+           font_name, tmW.tmLastChar, last_unicode_char);
+else
+        ok(tmW.tmLastChar == last_unicode_char, "tmLastChar for %s %02x != %02x\n",
+           font_name, tmW.tmLastChar, last_unicode_char);
+    }
+
+    ret = GetDeviceCaps(hdc, LOGPIXELSX);
+    ok(tmW.tmDigitizedAspectX == ret, "tmDigitizedAspectX %u != %u\n",
+       tmW.tmDigitizedAspectX, ret);
+    ret = GetDeviceCaps(hdc, LOGPIXELSY);
+    ok(tmW.tmDigitizedAspectX == ret, "tmDigitizedAspectY %u != %u\n",
+       tmW.tmDigitizedAspectX, ret);
+
+    SelectObject(hdc, hfont_old);
+    DeleteObject(hfont);
+
+    ReleaseDC(0, hdc);
+}
+
+static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
+{
+    INT *enumed = (INT *)lParam;
+
+    if (type == TRUETYPE_FONTTYPE)
+    {
+        (*enumed)++;
+        test_text_metrics(lf);
+    }
+    return 1;
+}
+
+static void test_GetTextMetrics(void)
+{
+    LOGFONTA lf;
+    HDC hdc;
+    INT enumed;
+
+    SetLastError(0xdeadbeef);
+    GetTextMetricsW(0, NULL);
+    if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("Skipping GetTextMetrics test on a Win9x platform\n");
+        return;
+    }
+
+    hdc = GetDC(0);
+
+    memset(&lf, 0, sizeof(lf));
+    lf.lfCharSet = DEFAULT_CHARSET;
+    enumed = 0;
+    EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
+    trace("Tested metrics of %d truetype fonts\n", enumed);
+
+    ReleaseDC(0, hdc);
+}
+
 START_TEST(font)
 {
     init();
@@ -1427,4 +1565,5 @@ START_TEST(font)
     }
     else
         skip("Arial Black or Symbol/Wingdings is not installed\n");
+    test_GetTextMetrics();
 }
-- 
1.5.0.2






More information about the wine-patches mailing list