#include "wine/test.h"
+/* Do not allow more than 1 deviation here */
+#define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
+
#define near_match(a, b) (abs((a) - (b)) <= 6)
#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
-LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
-BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
-BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
-DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
-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);
-BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
+static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
+static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
+static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
+static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
+static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
+static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
+static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
+static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
+static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
+static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
+static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
+static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
static HMODULE hgdi32 = 0;
+static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
static void init(void)
{
hgdi32 = GetModuleHandleA("gdi32.dll");
pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
+ pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
+ pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
+ pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
+ pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
+ pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
}
static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
INT width_orig, height_orig, lfWidth;
XFORM xform;
GLYPHMETRICS gm;
- MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
POINT pt;
INT ret;
int weight, height, ascent, descent, int_leading, ext_leading;
int ave_char_width, max_char_width, dpi;
DWORD ansi_bitfield;
+ WORD skip_lang_id;
} fd[] =
{
{ "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
{ "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
{ "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
-/*
- * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
- * require a new system.sfd for that font
- */
- { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
+ { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
{ "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
{ "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
{ "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
{ "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
{ "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
- { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
+ { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1, LANG_ARABIC },
{ "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
{ "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
- { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
+ { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1, LANG_ARABIC },
{ "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
+ { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_ARABIC },
{ "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
- { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
+ { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1, LANG_ARABIC },
{ "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
+ { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_ARABIC },
{ "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
- { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
+ { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
{ "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
+ { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, FS_ARABIC },
{ "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
- { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
+ { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
+ { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, FS_ARABIC },
{ "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
{ "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
HFONT hfont, old_hfont;
TEXTMETRIC tm;
INT ret, i;
+ WORD system_lang_id;
+
+ system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
hdc = CreateCompatibleDC(0);
assert(hdc);
{
DWORD fs[2];
CHARSETINFO csi;
+ BOOL bRet;
fs[0] = 1L << bit;
fs[1] = 0;
hfont = create_font(lf.lfFaceName, &lf);
old_hfont = SelectObject(hdc, hfont);
- ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
+ bRet = GetTextMetrics(hdc, &tm);
+ ok(bRet, "GetTextMetrics error %d\n", GetLastError());
if(fd[i].dpi == tm.tmDigitizedAspectX)
{
trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
- ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
- ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
- ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
- ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
- ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
- ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
- ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
-
- /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
- that make the max width bigger */
- if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
- ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
+ if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
+ {
+ ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
+ ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
+ ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
+ ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
+ ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
+ ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
+ ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
+
+ /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
+ that make the max width bigger */
+ if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
+ ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
+ }
+ else
+ skip("Skipping font metrics test for system langid 0x%x\n",
+ system_lang_id);
}
SelectObject(hdc, old_hfont);
DeleteObject(hfont);
DeleteDC(hdc);
}
+static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
+ const TEXTMETRIC *lpntme,
+ DWORD FontType, LPARAM lParam)
+{
+ if (FontType & TRUETYPE_FONTTYPE)
+ {
+ HFONT hfont;
+
+ hfont = CreateFontIndirect(lpelfe);
+ if (hfont)
+ {
+ *(HFONT *)lParam = hfont;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
static void test_GetCharABCWidths(void)
{
static const WCHAR str[] = {'a',0};
ABC abc[1];
WORD glyphs[1];
DWORD nb;
+ static const struct
+ {
+ UINT first;
+ UINT last;
+ } range[] =
+ {
+ {0xff, 0xff},
+ {0x100, 0x100},
+ {0xff, 0x100},
+ {0x1ff, 0xff00},
+ {0xffff, 0xffff},
+ {0x10000, 0x10000},
+ {0xffff, 0x10000},
+ {0xffffff, 0xffffff},
+ {0x1000000, 0x1000000},
+ {0xffffff, 0x1000000},
+ {0xffffffff, 0xffffffff}
+ };
+ static const struct
+ {
+ UINT cs;
+ UINT a;
+ UINT w;
+ BOOL r[sizeof range / sizeof range[0]];
+ } c[] =
+ {
+ {ANSI_CHARSET, 0x30, 0x30, {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
+ {SHIFTJIS_CHARSET, 0x82a0, 0x3042, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
+ {HANGEUL_CHARSET, 0x8141, 0xac02, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
+ {JOHAB_CHARSET, 0x8446, 0x3135, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
+ {GB2312_CHARSET, 0x8141, 0x4e04, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
+ {CHINESEBIG5_CHARSET, 0xa142, 0x3001, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}}
+ };
+ UINT i;
- if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
+ if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsI)
{
- win_skip("GetCharABCWidthsW/I not available on this platform\n");
+ win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
return;
}
hfont = SelectObject(hdc, hfont);
DeleteObject(hfont);
+
+ for (i = 0; i < sizeof c / sizeof c[0]; ++i)
+ {
+ ABC a[2], w[2];
+ ABC full[256];
+ UINT code = 0x41, j;
+
+ lf.lfFaceName[0] = '\0';
+ lf.lfCharSet = c[i].cs;
+ lf.lfPitchAndFamily = 0;
+ if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
+ {
+ skip("TrueType font for charset %u is not installed\n", c[i].cs);
+ continue;
+ }
+
+ memset(a, 0, sizeof a);
+ memset(w, 0, sizeof w);
+ hfont = SelectObject(hdc, hfont);
+ ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
+ pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
+ memcmp(a, w, sizeof a) == 0,
+ "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
+
+ memset(a, 0xbb, sizeof a);
+ ret = pGetCharABCWidthsA(hdc, code, code, a);
+ ok(ret, "GetCharABCWidthsA should have succeeded\n");
+ memset(full, 0xcc, sizeof full);
+ ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
+ ok(ret, "GetCharABCWidthsA should have succeeded\n");
+ ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
+ "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
+
+ for (j = 0; j < sizeof range / sizeof range[0]; ++j)
+ {
+ ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
+ ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
+ range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
+ }
+
+ hfont = SelectObject(hdc, hfont);
+ DeleteObject(hfont);
+ }
+
ReleaseDC(NULL, hdc);
}
hdc = GetDC(0);
+ memset(&lf, 0, sizeof(lf));
+ strcpy(lf.lfFaceName, "System");
+ lf.lfHeight = 16;
+ lf.lfCharSet = ANSI_CHARSET;
+
+ hfont = CreateFontIndirectA(&lf);
+ ok(hfont != 0, "CreateFontIndirectEx failed\n");
ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
- flags |= GGI_MARK_NONEXISTING_GLYPHS;
- charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
- ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
- ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
- flags = 0;
- charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
- ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
- ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
- textm.tmDefaultChar, glyphs[4]);
+ if (textm.tmCharSet == ANSI_CHARSET)
+ {
+ flags |= GGI_MARK_NONEXISTING_GLYPHS;
+ charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
+ ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
+ ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
+ flags = 0;
+ charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
+ ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
+ ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
+ textm.tmDefaultChar, glyphs[4]);
+ }
+ else
+ /* FIXME: Write tests for non-ANSI charsets. */
+ skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
if(!is_font_installed("Tahoma"))
{
for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
{
OUTLINETEXTMETRICW otm;
+ UINT uiRet;
if (!is_font_installed(kd[i].face_name))
{
SetLastError(0xdeadbeef);
otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
- ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
+ uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
+ ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
- ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
+ ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
- ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
+ ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
kd[i].otmLineGap, otm.otmLineGap);
ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
kd[i].otmMacDescent, otm.otmMacDescent);
+ ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
+ kd[i].otmMacAscent, otm.otmMacAscent);
todo_wine {
ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
kd[i].otmsXHeight, otm.otmsXHeight);
- ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
- kd[i].otmMacAscent, otm.otmMacAscent);
/* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
kd[i].otmMacLineGap, otm.otmMacLineGap);
ReleaseDC(0, hdc);
}
+static void test_height_selection(void)
+{
+ static const struct font_data
+ {
+ const char face_name[LF_FACESIZE];
+ int requested_height;
+ int weight, height, ascent, descent, int_leading, ext_leading, dpi;
+ } fd[] =
+ {
+ {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
+ {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
+ {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
+ {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
+ {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
+ {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
+ {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
+ {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
+ {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
+ {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
+ };
+ HDC hdc;
+ LOGFONT lf;
+ HFONT hfont, old_hfont;
+ TEXTMETRIC tm;
+ INT ret, i;
+
+ hdc = CreateCompatibleDC(0);
+ assert(hdc);
+
+ for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
+ {
+ if (!is_truetype_font_installed(fd[i].face_name))
+ {
+ skip("%s is not installed\n", fd[i].face_name);
+ continue;
+ }
+
+ memset(&lf, 0, sizeof(lf));
+ lf.lfHeight = fd[i].requested_height;
+ lf.lfWeight = fd[i].weight;
+ strcpy(lf.lfFaceName, fd[i].face_name);
+
+ hfont = CreateFontIndirect(&lf);
+ assert(hfont);
+
+ old_hfont = SelectObject(hdc, hfont);
+ ret = GetTextMetrics(hdc, &tm);
+ ok(ret, "GetTextMetrics error %d\n", GetLastError());
+ if(fd[i].dpi == tm.tmDigitizedAspectX)
+ {
+ trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
+ ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
+ ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
+ ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
+ ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
+#if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
+ ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
+#endif
+ ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
+ }
+
+ SelectObject(hdc, old_hfont);
+ DeleteObject(hfont);
+ }
+
+ DeleteDC(hdc);
+}
+
static void test_GetOutlineTextMetrics(void)
{
OUTLINETEXTMETRIC *otm;
static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
{
- INT x, y,
+ INT y,
breakCount,
justifiedWidth = 0, /* to test GetTextExtentExPointW() */
areaWidth = clientArea->right - clientArea->left,
}
else lastExtent = TRUE;
- x = clientArea->left;
-
/* catch errors and report them */
if (!lastExtent && (justifiedWidth != areaWidth))
{
}
ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
+ if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
+ {
+ skip("Font code page %d, looking for code page %d\n",
+ pGdiGetCodePage(hdc), code_page);
+ ReleaseDC(0, hdc);
+ return FALSE;
+ }
+
if (unicode)
{
char ansi_buf[128];
SetLastError(0xdeadbeef);
ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
- ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
+ ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
+ count, ret, GetLastError());
}
else
{
SetLastError(0xdeadbeef);
ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
- ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
+ ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
+ count, ret, GetLastError());
}
SelectObject(hdc, hfont_old);
break;
}
}
- 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*sizeof(WORD)), "%d: indices don't match\n", i);
+ if (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*sizeof(WORD)), "%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");
ReleaseDC(0, hdc);
}
+static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
+{
+ struct enum_font_data *efd = (struct enum_font_data *)lParam;
+
+ if (type != TRUETYPE_FONTTYPE) return 1;
+
+ if (efd->total < MAX_ENUM_FONTS)
+ efd->lf[efd->total++] = *lf;
+ else
+ trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
+
+ return 1;
+}
+
+static void test_EnumFontFamiliesEx_default_charset(void)
+{
+ struct enum_font_data efd;
+ LOGFONT gui_font, enum_font;
+ DWORD ret;
+ HDC hdc;
+
+ ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
+ ok(ret, "GetObject failed.\n");
+ if (!ret)
+ return;
+
+ efd.total = 0;
+
+ hdc = GetDC(0);
+ memset(&enum_font, 0, sizeof(enum_font));
+ lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
+ enum_font.lfCharSet = DEFAULT_CHARSET;
+ EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
+ ReleaseDC(0, hdc);
+
+ if (efd.total == 0) {
+ skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
+ return;
+ }
+ trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
+
+ ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
+ "(%s) got charset %d expected %d\n",
+ efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
+
+ return;
+}
+
static void test_negative_width(HDC hdc, const LOGFONTA *lf)
{
HFONT hfont, hfont_prev;
GLYPHMETRICS gm1, gm2;
LOGFONTA lf2 = *lf;
WORD idx;
- MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
if(!pGetGlyphIndicesA)
return;
((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
#define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
#define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
+#define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
typedef struct
{
static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
{
- ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
+ ok((tmA->tmPitchAndFamily & 0xf0) == family ||
+ broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
+ "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
os2->panose.bWeight, os2->panose.bProportion);
}
return r;
}
+#define TT_PLATFORM_MICROSOFT 3
+#define TT_MS_ID_UNICODE_CS 1
+#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
+#define TT_NAME_ID_FULL_NAME 4
+
+static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
+{
+ struct sfnt_name_header
+ {
+ USHORT format;
+ USHORT number_of_record;
+ USHORT storage_offset;
+ } *header;
+ struct sfnt_name
+ {
+ USHORT platform_id;
+ USHORT encoding_id;
+ USHORT language_id;
+ USHORT name_id;
+ USHORT length;
+ USHORT offset;
+ } *entry;
+ BOOL r = FALSE;
+ LONG size, offset, length;
+ LONG c, ret;
+ WCHAR *name;
+ BYTE *data;
+ USHORT i;
+
+ size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
+ ok(size != GDI_ERROR, "no name table found\n");
+ if(size == GDI_ERROR) return FALSE;
+
+ data = HeapAlloc(GetProcessHeap(), 0, size);
+ ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
+ ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
+
+ header = (void *)data;
+ header->format = GET_BE_WORD(header->format);
+ header->number_of_record = GET_BE_WORD(header->number_of_record);
+ header->storage_offset = GET_BE_WORD(header->storage_offset);
+ if (header->format != 0)
+ {
+ trace("got format %u\n", header->format);
+ goto out;
+ }
+ if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
+ {
+ trace("number records out of range: %d\n", header->number_of_record);
+ goto out;
+ }
+ if (header->storage_offset >= size)
+ {
+ trace("storage_offset %u > size %u\n", header->storage_offset, size);
+ goto out;
+ }
+
+ entry = (void *)&header[1];
+ for (i = 0; i < header->number_of_record; i++)
+ {
+ if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
+ GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
+ GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
+ GET_BE_WORD(entry[i].name_id) != name_id)
+ {
+ continue;
+ }
+
+ offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
+ length = GET_BE_WORD(entry[i].length);
+ if (offset + length > size)
+ {
+ trace("entry %d is out of range\n", i);
+ break;
+ }
+ if (length >= out_size)
+ {
+ trace("buffer too small for entry %d\n", i);
+ break;
+ }
+
+ name = (WCHAR *)(data + offset);
+ for (c = 0; c < length / 2; c++)
+ out_buf[c] = GET_BE_WORD(name[c]);
+ out_buf[c] = 0;
+
+ r = TRUE;
+ break;
+ }
+
+out:
+ HeapFree(GetProcessHeap(), 0, data);
+ return r;
+}
+
static void test_text_metrics(const LOGFONTA *lf)
{
HDC hdc;
const char *font_name = lf->lfFaceName;
DWORD cmap_first = 0, cmap_last = 0;
cmap_type cmap_type;
+ BOOL sys_lang_non_english;
+ sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
hdc = GetDC(0);
SetLastError(0xdeadbeef);
ok(tmA.tmFirstChar == expect_first_A ||
tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
"A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
- ok(tmA.tmLastChar == expect_last_A ||
- tmA.tmLastChar == 0xff /* win9x */,
- "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
+ if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
+ ok(tmA.tmLastChar == expect_last_A ||
+ tmA.tmLastChar == 0xff /* win9x */,
+ "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
+ else
+ skip("tmLastChar is DBCS lead byte\n");
ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
font_name, tmA.tmBreakChar, expect_break_A);
- ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
+ ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
+ "A: tmDefaultChar for %s got %02x expected %02x\n",
font_name, tmA.tmDefaultChar, expect_default_A);
font_name, tmW.tmLastChar, expect_last_W);
ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
font_name, tmW.tmBreakChar, expect_break_W);
- ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
+ ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
+ "W: tmDefaultChar for %s got %02x expected %02x\n",
font_name, tmW.tmDefaultChar, expect_default_W);
/* Test the aspect ratio while we have tmW */
!lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
"Got %s\n", buf);
cs = GetTextCharset(hdc);
- ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
+ ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
DeleteObject(SelectObject(hdc, hfont));
memset(&lf, 0, sizeof(lf));
!lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
"got %s for font %s\n", buf, font_subst[i].name);
cs = GetTextCharset(hdc);
- ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
+ ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
DeleteObject(SelectObject(hdc, hfont));
}
DeleteDC(hdc);
}
+static void test_oemcharset(void)
+{
+ HDC hdc;
+ LOGFONTA lf, clf;
+ HFONT hfont, old_hfont;
+ int charset;
+
+ hdc = CreateCompatibleDC(0);
+ ZeroMemory(&lf, sizeof(lf));
+ lf.lfHeight = 12;
+ lf.lfCharSet = OEM_CHARSET;
+ lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
+ lstrcpyA(lf.lfFaceName, "Terminal");
+ hfont = CreateFontIndirectA(&lf);
+ old_hfont = SelectObject(hdc, hfont);
+ charset = GetTextCharset(hdc);
+todo_wine
+ ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
+ hfont = SelectObject(hdc, old_hfont);
+ GetObjectA(hfont, sizeof(clf), &clf);
+ ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
+ ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
+ ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
+ ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
+ DeleteObject(hfont);
+ DeleteDC(hdc);
+}
+
static void test_GetGlyphOutline(void)
{
- MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
HDC hdc;
- GLYPHMETRICS gm;
+ GLYPHMETRICS gm, gm2;
LOGFONTA lf;
HFONT hfont, old_hfont;
- INT ret;
+ INT ret, ret2;
+ static const struct
+ {
+ UINT cs;
+ UINT a;
+ UINT w;
+ } c[] =
+ {
+ {ANSI_CHARSET, 0x30, 0x30},
+ {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
+ {HANGEUL_CHARSET, 0x8141, 0xac02},
+ {JOHAB_CHARSET, 0x8446, 0x3135},
+ {GB2312_CHARSET, 0x8141, 0x4e04},
+ {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
+ };
+ UINT i;
if (!is_truetype_font_installed("Tahoma"))
{
SelectObject(hdc, old_hfont);
DeleteObject(hfont);
+
+ for (i = 0; i < sizeof c / sizeof c[0]; ++i)
+ {
+ lf.lfFaceName[0] = '\0';
+ lf.lfCharSet = c[i].cs;
+ lf.lfPitchAndFamily = 0;
+ if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
+ {
+ skip("TrueType font for charset %u is not installed\n", c[i].cs);
+ continue;
+ }
+
+ old_hfont = SelectObject(hdc, hfont);
+
+ /* expected to ignore superfluous bytes (sigle-byte character) */
+ ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
+ ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
+ ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
+
+ ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
+ ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
+ "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
+
+ /* expected to ignore superfluous bytes (double-byte character) */
+ ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
+ ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
+ ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
+ "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
+
+ /* expected to match wide-char version results */
+ ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
+ ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
+
+ hfont = SelectObject(hdc, old_hfont);
+ DeleteObject(hfont);
+ }
+
DeleteDC(hdc);
}
DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
DEFAULT_QUALITY, VARIABLE_PITCH,
fontname);
- ok( hf != NULL, "CreateFontA failed\n");
+ ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
of = SelectObject( hdc, hf);
ret = GetTextMetricsA( hdc, &tm);
ok(ret, "GetTextMetricsA error %u\n", GetLastError());
SelectObject(hdc, of);
DeleteObject(hf);
- if (tm.tmAveCharWidth == ave_width || width / height > 200)
+ if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
break;
}
ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
}
-void test_CreateFontIndirect(void)
+static void test_CreateFontIndirect(void)
{
LOGFONTA lf, getobj_lf;
- int ret;
+ int ret, i;
HFONT hfont;
+ char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
memset(&lf, 0, sizeof(lf));
-
lf.lfCharSet = ANSI_CHARSET;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfHeight = 16;
lf.lfWidth = 16;
lf.lfQuality = DEFAULT_QUALITY;
-
lf.lfItalic = FALSE;
lf.lfWeight = FW_DONTCARE;
- lstrcpyA(lf.lfFaceName, "Arial");
- hfont = CreateFontIndirectA(&lf);
- ok(hfont != 0, "CreateFontIndirectA failed\n");
- ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
- ok(lf.lfWeight == getobj_lf.lfWeight ||
- broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
- "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
- ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
- ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
- broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
- "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
- DeleteObject(hfont);
- lf.lfItalic = FALSE;
- lf.lfWeight = FW_DONTCARE;
- lstrcpyA(lf.lfFaceName, "Arial Bold");
- hfont = CreateFontIndirectA(&lf);
- ok(hfont != 0, "CreateFontIndirectA failed\n");
- ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
- ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
- ok(lf.lfWeight == getobj_lf.lfWeight ||
- broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
- "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
- ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
- broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
- "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
+ for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
+ {
+ lstrcpyA(lf.lfFaceName, TestName[i]);
+ hfont = CreateFontIndirectA(&lf);
+ ok(hfont != 0, "CreateFontIndirectA failed\n");
+ SetLastError(0xdeadbeef);
+ ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
+ ok(ret, "GetObject failed: %d\n", GetLastError());
+ ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
+ ok(lf.lfWeight == getobj_lf.lfWeight ||
+ broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
+ "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
+ ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
+ broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
+ "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
+ DeleteObject(hfont);
+ }
+}
+
+static void test_CreateFontIndirectEx(void)
+{
+ ENUMLOGFONTEXDVA lfex;
+ HFONT hfont;
+
+ if (!pCreateFontIndirectExA)
+ {
+ win_skip("CreateFontIndirectExA is not available\n");
+ return;
+ }
+
+ if (!is_truetype_font_installed("Arial"))
+ {
+ skip("Arial is not installed\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ hfont = pCreateFontIndirectExA(NULL);
+ ok(hfont == NULL, "got %p\n", hfont);
+ ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
+
+ memset(&lfex, 0, sizeof(lfex));
+ lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
+ hfont = pCreateFontIndirectExA(&lfex);
+ ok(hfont != 0, "CreateFontIndirectEx failed\n");
+ if (hfont)
+ check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
DeleteObject(hfont);
+}
+
+static void free_font(void *font)
+{
+ UnmapViewOfFile(font);
+}
+
+static void *load_font(const char *font_name, DWORD *font_size)
+{
+ char file_name[MAX_PATH];
+ HANDLE file, mapping;
+ void *font;
+
+ if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
+ strcat(file_name, "\\fonts\\");
+ strcat(file_name, font_name);
+
+ file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
+ if (file == INVALID_HANDLE_VALUE) return NULL;
+
+ *font_size = GetFileSize(file, NULL);
+
+ mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (!mapping)
+ {
+ CloseHandle(file);
+ return NULL;
+ }
+
+ font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+
+ CloseHandle(file);
+ CloseHandle(mapping);
+ return font;
+}
+
+static void test_AddFontMemResource(void)
+{
+ void *font;
+ DWORD font_size, num_fonts;
+ HANDLE ret;
+ BOOL bRet;
+
+ if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
+ {
+ win_skip("AddFontMemResourceEx is not available on this platform\n");
+ return;
+ }
+
+ font = load_font("sserife.fon", &font_size);
+ if (!font)
+ {
+ skip("Unable to locate and load font sserife.fon\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+
+ num_fonts = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+ ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
+
+ if (0) /* hangs under windows 2000 */
+ {
+ num_fonts = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == 0xdeadbeef,
+ "Expected GetLastError() to return 0xdeadbeef, got %u\n",
+ GetLastError());
+ ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
+ }
+
+ num_fonts = 0xdeadbeef;
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
+ ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
+ ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
+ ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
+
+ free_font(font);
+
+ SetLastError(0xdeadbeef);
+ bRet = pRemoveFontMemResourceEx(ret);
+ ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
+
+ /* test invalid pointer to number of loaded fonts */
+ font = load_font("sserife.fon", &font_size);
+ ok(font != NULL, "Unable to locate and load font sserife.fon\n");
+
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == 0xdeadbeef,
+ "Expected GetLastError() to return 0xdeadbeef, got %u\n",
+ GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
+ ok(!ret, "AddFontMemResourceEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
+ GetLastError());
+
+ free_font(font);
+}
+
+static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
+{
+ LOGFONT *lf;
+
+ if (type != TRUETYPE_FONTTYPE) return 1;
+
+ ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
+
+ lf = (LOGFONT *)lparam;
+ *lf = *elf;
+ return 0;
+}
+
+static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
+{
+ int ret;
+ LOGFONT *lf;
+
+ if (type != TRUETYPE_FONTTYPE) return 1;
+
+ lf = (LOGFONT *)lparam;
+ ret = strcmp(lf->lfFaceName, elf->lfFaceName);
+ if(ret == 0)
+ {
+ ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
+ *lf = *elf;
+ return 0;
+ }
+ return 1;
+}
+
+static void test_EnumFonts(void)
+{
+ int ret;
+ LOGFONT lf;
+ HDC hdc;
+
+ if (!is_truetype_font_installed("Arial"))
+ {
+ skip("Arial is not installed\n");
+ return;
+ }
+
+ /* Windows uses localized font face names, so Arial Bold won't be found */
+ if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
+ {
+ skip("User locale is not English, skipping the test\n");
+ return;
+ }
+
+ hdc = CreateCompatibleDC(0);
+
+ ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
+ ok(!ret, "font Arial is not enumerated\n");
+ ret = strcmp(lf.lfFaceName, "Arial");
+ ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
+ ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
+
+ lstrcpy(lf.lfFaceName, "Arial");
+ ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
+ ok(!ret, "font Arial is not enumerated\n");
+ ret = strcmp(lf.lfFaceName, "Arial");
+ ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
+ ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
+
+ ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
+ ok(!ret, "font Arial Bold is not enumerated\n");
+ ret = strcmp(lf.lfFaceName, "Arial");
+ ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
+ ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
+
+ lstrcpy(lf.lfFaceName, "Arial Bold");
+ ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
+ ok(ret, "font Arial Bold should not be enumerated\n");
+
+ ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
+ ok(!ret, "font Arial Bold Italic is not enumerated\n");
+ ret = strcmp(lf.lfFaceName, "Arial");
+ ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
+ ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
+
+ lstrcpy(lf.lfFaceName, "Arial Bold Italic");
+ ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
+ ok(ret, "font Arial Bold Italic should not be enumerated\n");
+
+ ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
+ ok(ret, "font Arial Italic Bold should not be enumerated\n");
+
+ lstrcpy(lf.lfFaceName, "Arial Italic Bold");
+ ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
+ ok(ret, "font Arial Italic Bold should not be enumerated\n");
+
+ DeleteDC(hdc);
+}
+
+static void test_fullname(void)
+{
+ static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic"};
+ char buf[LF_FULLFACESIZE];
+ HFONT hfont, of;
+ LOGFONTA lf;
+ HDC hdc;
+ int i;
+
+ /* Lucida Sans comes with XP SP2 or later */
+ if (!is_truetype_font_installed("Lucida Sans"))
+ {
+ skip("Lucida Sans is not installed\n");
+ return;
+ }
+
+ hdc = CreateCompatibleDC(0);
+ ok(hdc != NULL, "CreateCompatibleDC failed\n");
+
+ memset(&lf, 0, sizeof(lf));
+ lf.lfCharSet = ANSI_CHARSET;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfHeight = 16;
+ lf.lfWidth = 16;
+ lf.lfQuality = DEFAULT_QUALITY;
lf.lfItalic = FALSE;
lf.lfWeight = FW_DONTCARE;
- lstrcpyA(lf.lfFaceName, "Arial Italic");
- hfont = CreateFontIndirectA(&lf);
- ok(hfont != 0, "CreateFontIndirectA failed\n");
- ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
- ok(lf.lfWeight == getobj_lf.lfWeight ||
- broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
- "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
- ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
- ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
- broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
- "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
- DeleteObject(hfont);
+
+ for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
+ {
+ lstrcpyA(lf.lfFaceName, TestName[i]);
+ hfont = CreateFontIndirectA(&lf);
+ ok(hfont != 0, "CreateFontIndirectA failed\n");
+
+ of = SelectObject(hdc, hfont);
+ buf[0] = 0;
+ ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
+ "face full name could not be read\n");
+ ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
+ SelectObject(hdc, of);
+ DeleteObject(hfont);
+ }
+ DeleteDC(hdc);
}
START_TEST(font)
{
init();
+
test_logfont();
test_bitmap_font();
test_outline_font();
test_GetFontUnicodeRanges();
test_nonexistent_font();
test_orientation();
+ test_height_selection();
+ test_AddFontMemResource();
+ test_EnumFonts();
/* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
* I'd like to avoid them in this test.
}
else
skip("Arial Black or Symbol/Wingdings is not installed\n");
+ test_EnumFontFamiliesEx_default_charset();
test_GetTextMetrics();
test_GdiRealizationInfo();
test_GetTextFace();
test_GetTextMetrics2("Arial", -55);
test_GetTextMetrics2("Arial", -110);
test_CreateFontIndirect();
+ test_CreateFontIndirectEx();
+ test_oemcharset();
+ test_fullname();
}