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
>
>
>
>
>
>