From 37591409b28c2000e70bd0d3c654a3a7559a4a26 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Thu, 15 Feb 2007 15:52:33 +0800 Subject: [PATCH] gdi32: Revert 1440eb5a35dc95dea1836d9035b51e2b15d83703 and add the test showing that the change was wrong. --- dlls/gdi32/font.c | 79 ++++++++++++++++++++------ dlls/gdi32/tests/font.c | 121 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 179 insertions(+), 21 deletions(-) diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index ee57ba8303b..876e49a7f0f 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -342,17 +342,59 @@ static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRIC /*********************************************************************** * FONT_mbtowc * - * Returns a Unicode translation of str. If count is -1 then str is - * assumed to be '\0' terminated, otherwise it contains the number of - * bytes to convert. If plenW is non-NULL, on return it will point to - * the number of WCHARs that have been written. The caller should free - * the returned LPWSTR from the process heap itself. + * Returns a Unicode translation of str using the charset of the + * currently selected font in hdc. If count is -1 then str is assumed + * to be '\0' terminated, otherwise it contains the number of bytes to + * convert. If plenW is non-NULL, on return it will point to the + * number of WCHARs that have been written. If pCP is non-NULL, on + * return it will point to the codepage used in the conversion. The + * caller should free the returned LPWSTR from the process heap + * itself. */ -static LPWSTR FONT_mbtowc(LPCSTR str, INT count, INT *plenW) +static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP) { UINT cp = CP_ACP; INT lenW; LPWSTR strW; + CHARSETINFO csi; + int charset = GetTextCharset(hdc); + + /* Hmm, nicely designed api this one! */ + if(TranslateCharsetInfo((DWORD*)charset, &csi, TCI_SRCCHARSET)) + cp = csi.ciACP; + else { + switch(charset) { + case OEM_CHARSET: + cp = GetOEMCP(); + break; + case DEFAULT_CHARSET: + cp = GetACP(); + break; + + case VISCII_CHARSET: + case TCVN_CHARSET: + case KOI8_CHARSET: + case ISO3_CHARSET: + case ISO4_CHARSET: + case ISO10_CHARSET: + case CELTIC_CHARSET: + /* FIXME: These have no place here, but because x11drv + enumerates fonts with these (made up) charsets some apps + might use them and then the FIXME below would become + annoying. Now we could pick the intended codepage for + each of these, but since it's broken anyway we'll just + use CP_ACP and hope it'll go away... + */ + cp = CP_ACP; + break; + + default: + FIXME("Can't find codepage for charset %d\n", charset); + break; + } + } + + TRACE("charset %d => cp %d\n", charset, cp); if(count == -1) count = strlen(str); lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0); @@ -360,6 +402,7 @@ static LPWSTR FONT_mbtowc(LPCSTR str, INT count, INT *plenW) MultiByteToWideChar(cp, 0, str, count, strW, lenW); TRACE("mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW)); if(plenW) *plenW = lenW; + if(pCP) *pCP = cp; return strW; } @@ -1021,7 +1064,7 @@ BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count, { BOOL ret = FALSE; INT wlen; - LPWSTR p = FONT_mbtowc(str, count, &wlen); + LPWSTR p = FONT_mbtowc(hdc, str, count, &wlen, NULL); if (p) { ret = GetTextExtentPoint32W( hdc, p, wlen, size ); @@ -1130,7 +1173,7 @@ BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count, NULL == (walpDx = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT)))) return FALSE; - p = FONT_mbtowc(str, count, &wlen); + p = FONT_mbtowc(hdc, str, count, &wlen, NULL); ret = GetTextExtentExPointW( hdc, p, wlen, maxExt, lpnFit, walpDx, size); if (walpDx) { @@ -1663,7 +1706,7 @@ BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar, for(i = 0; i < count; i++) str[i] = (BYTE)(firstChar + i); - wstr = FONT_mbtowc(str, count, &wlen); + wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL); for(i = 0; i < wlen; i++) { @@ -1691,6 +1734,7 @@ BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx ) { INT wlen; + UINT codepage; LPWSTR p; BOOL ret; LPINT lpDxW = NULL; @@ -1698,14 +1742,14 @@ BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags, if (flags & ETO_GLYPH_INDEX) return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx ); - p = FONT_mbtowc(str, count, &wlen); + p = FONT_mbtowc(hdc, str, count, &wlen, &codepage); if (lpDx) { unsigned int i = 0, j = 0; lpDxW = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(INT)); while(i < count) { - if(IsDBCSLeadByte(str[i])) { + if(IsDBCSLeadByteEx(codepage, str[i])) { lpDxW[j++] = lpDx[i] + lpDx[i+1]; i = i + 2; } else { @@ -2310,7 +2354,7 @@ BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar, for(i = 0; i < count; i++) str[i] = (BYTE)(firstChar + i); - wstr = FONT_mbtowc(str, count, &wlen); + wstr = FONT_mbtowc(hdc, str, count, &wlen, NULL); for(i = 0; i < wlen; i++) { @@ -2448,7 +2492,7 @@ DWORD WINAPI GetGlyphOutlineA( HDC hdc, UINT uChar, UINT fuFormat, len = 1; mbchs[0] = (uChar & 0xff); } - p = FONT_mbtowc(mbchs, len, NULL); + p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL); c = p[0]; } else c = uChar; @@ -2754,7 +2798,7 @@ DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count, TRACE("(%p, %s, %d, %p, 0x%x)\n", hdc, debugstr_an(lpstr, count), count, pgi, flags); - lpstrW = FONT_mbtowc(lpstr, count, &countW); + lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL); ret = GetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags); HeapFree(GetProcessHeap(), 0, lpstrW); @@ -2799,6 +2843,7 @@ GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount, INT uCountW; GCP_RESULTSW resultsW; DWORD ret; + UINT font_cp; TRACE("%s, %d, %d, 0x%08x\n", debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags); @@ -2806,7 +2851,7 @@ GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount, /* both structs are equal in size */ memcpy(&resultsW, lpResults, sizeof(resultsW)); - lpStringW = FONT_mbtowc(lpString, uCount, &uCountW); + lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp); if(lpResults->lpOutString) resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW); @@ -2816,7 +2861,7 @@ GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount, lpResults->nMaxFit = resultsW.nMaxFit; if(lpResults->lpOutString) { - WideCharToMultiByte(CP_ACP, 0, resultsW.lpOutString, uCountW, + WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW, lpResults->lpOutString, uCount, NULL, NULL ); } @@ -2946,7 +2991,7 @@ BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT a for(i = 0; i < count; i++) str[i] = (BYTE)(first + i); - wstr = FONT_mbtowc(str, count, &wlen); + wstr = FONT_mbtowc( hdc, str, count, &wlen, NULL ); for (i = 0; i < wlen; i++) { diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 670ec36a1de..5dddf3a8c2e 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -26,9 +26,13 @@ #include "winbase.h" #include "wingdi.h" #include "winuser.h" +#include "winnls.h" #include "wine/test.h" +DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags); +DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags); + static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam) { return 0; @@ -432,7 +436,7 @@ static void test_text_extents(void) GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("Skipping remainder of text extents test on a Win9x platform\n"); + skip("Skipping remainder of text extents test on a Win9x platform\n"); hfont = SelectObject(hdc, hfont); DeleteObject(hfont); ReleaseDC(0, hdc); @@ -615,7 +619,7 @@ static void test_GetKerningPairs(void) GetKerningPairsW(hdc, 0, NULL); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("Skipping the GetKerningPairs test on a Win9x platform\n"); + skip("Skipping the GetKerningPairs test on a Win9x platform\n"); ReleaseDC(0, hdc); return; } @@ -740,14 +744,14 @@ static void test_GetOutlineTextMetrics(void) HDC hdc; DWORD ret, otm_size; - hdc = GetDC(0); - if (!is_font_installed("Arial")) { skip("Arial is not installed\n"); return; } + hdc = GetDC(0); + memset(&lf, 0, sizeof(lf)); strcpy(lf.lfFaceName, "Arial"); lf.lfHeight = -13; @@ -817,6 +821,114 @@ static void test_GetOutlineTextMetrics(void) ReleaseDC(0, hdc); } +static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode) +{ + HDC hdc; + LOGFONTA lf; + HFONT hfont, hfont_old; + CHARSETINFO csi; + INT cs; + DWORD i, ret; + + assert(count <= 128); + + memset(&lf, 0, sizeof(lf)); + + lf.lfCharSet = charset; + lf.lfHeight = 10; + lstrcpyA(lf.lfFaceName, "Arial"); + SetLastError(0xdeadbeef); + hfont = CreateFontIndirectA(&lf); + ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); + + hdc = GetDC(0); + hfont_old = SelectObject(hdc, hfont); + + cs = GetTextCharset(hdc); + ok(cs == charset, "expected %d, got %d\n", charset, cs); + + if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET)) + { + trace("Can't find codepage for charset %d\n", cs); + ReleaseDC(0, hdc); + return FALSE; + } + ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP); + + if (unicode) + { + char ansi_buf[128]; + WCHAR unicode_buf[128]; + + for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128); + + MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count); + + SetLastError(0xdeadbeef); + ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0); + ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError()); + } + else + { + char ansi_buf[128]; + + for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128); + + SetLastError(0xdeadbeef); + ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0); + ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError()); + } + + SelectObject(hdc, hfont_old); + DeleteObject(hfont); + + ReleaseDC(0, hdc); + + return TRUE; +} + +static void test_font_charset(void) +{ + static struct charset_data + { + INT charset; + UINT code_page; + WORD font_idxA[128], font_idxW[128]; + } cd[] = + { + { ANSI_CHARSET, 1252 }, + { SYMBOL_CHARSET, CP_SYMBOL }, + { RUSSIAN_CHARSET, 1251 } + }; + int i; + + pGetGlyphIndicesA = (void *)GetProcAddress(GetModuleHandle("gdi32.dll"), "GetGlyphIndicesA"); + pGetGlyphIndicesW = (void *)GetProcAddress(GetModuleHandle("gdi32.dll"), "GetGlyphIndicesW"); + + if (!pGetGlyphIndicesA || !pGetGlyphIndicesW) + { + skip("Skipping the font charset test on a Win9x platform\n"); + return; + } + + if (!is_font_installed("Arial")) + { + skip("Arial is not installed\n"); + return; + } + + for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++) + { + get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE); + get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE); + ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128), "%d: indices don't match\n", i); + } + + ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n"); + ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n"); + ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n"); +} + START_TEST(font) { test_logfont(); @@ -828,4 +940,5 @@ START_TEST(font) test_GetGlyphIndices(); test_GetKerningPairs(); test_GetOutlineTextMetrics(); + test_font_charset(); }