I tested it out on a couple machines and found many failure cases. (output attached) As a sanity check, I copied the deja vu family of fonts to a windows box and they passed the tests there. On 3/9/07, Dmitry Timoshkov <dmitry(a)codeweavers.com> wrote:
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