1 /* 2 * Unit test suite for fonts 3 * 4 * Copyright 2002 Mike McCormack 5 * Copyright 2004 Dmitry Timoshkov 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "precomp.h" 23 24 #include <winnls.h> 25 26 static inline BOOL match_off_by_n(int a, int b, unsigned int n) 27 { 28 return abs(a - b) <= n; 29 } 30 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1) 31 #define near_match(a, b) match_off_by_n((a), (b), 6) 32 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) 33 34 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height); 35 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc); 36 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc); 37 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc); 38 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc); 39 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc); 40 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer); 41 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer); 42 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs); 43 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags); 44 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags); 45 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext, 46 LPINT nfit, LPINT dxs, LPSIZE size ); 47 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *); 48 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *); 49 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *); 50 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE); 51 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID); 52 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID); 53 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *); 54 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *); 55 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD); 56 57 static HMODULE hgdi32 = 0; 58 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; 59 static WORD system_lang_id; 60 61 #ifdef WORDS_BIGENDIAN 62 #define GET_BE_WORD(x) (x) 63 #define GET_BE_DWORD(x) (x) 64 #else 65 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) 66 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x))); 67 #endif 68 69 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \ 70 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ 71 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) 72 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2') 73 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p') 74 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e') 75 76 static void init(void) 77 { 78 hgdi32 = GetModuleHandleA("gdi32.dll"); 79 80 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions"); 81 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage"); 82 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI"); 83 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA"); 84 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW"); 85 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW"); 86 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A"); 87 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W"); 88 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges"); 89 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA"); 90 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW"); 91 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI"); 92 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo"); 93 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA"); 94 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx"); 95 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx"); 96 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA"); 97 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA"); 98 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo"); 99 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo"); 100 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData"); 101 102 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID()); 103 } 104 105 static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size) 106 { 107 return HeapAlloc(GetProcessHeap(), 0, size); 108 } 109 110 static inline void* __WINE_ALLOC_SIZE(2) heap_realloc(void *mem, size_t size) 111 { 112 if (!mem) return heap_alloc(size); 113 return HeapReAlloc(GetProcessHeap(), 0, mem, size); 114 } 115 116 static inline BOOL heap_free(void *mem) 117 { 118 return HeapFree(GetProcessHeap(), 0, mem); 119 } 120 121 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 122 { 123 if (type != TRUETYPE_FONTTYPE) return 1; 124 125 return 0; 126 } 127 128 static BOOL is_truetype_font_installed(const char *name) 129 { 130 HDC hdc = GetDC(0); 131 BOOL ret = FALSE; 132 133 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0)) 134 ret = TRUE; 135 136 ReleaseDC(0, hdc); 137 return ret; 138 } 139 140 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 141 { 142 return 0; 143 } 144 145 static BOOL is_font_installed(const char *name) 146 { 147 HDC hdc = GetDC(0); 148 BOOL ret = FALSE; 149 150 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0)) 151 ret = TRUE; 152 153 ReleaseDC(0, hdc); 154 return ret; 155 } 156 157 static void *get_res_data(const char *fontname, DWORD *rsrc_size) 158 { 159 HRSRC rsrc; 160 void *rsrc_data; 161 162 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA); 163 if (!rsrc) return NULL; 164 165 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc)); 166 if (!rsrc_data) return NULL; 167 168 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc); 169 if (!*rsrc_size) return NULL; 170 171 return rsrc_data; 172 } 173 174 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name ) 175 { 176 char tmp_path[MAX_PATH]; 177 HANDLE hfile; 178 BOOL ret; 179 180 GetTempPathA(MAX_PATH, tmp_path); 181 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name); 182 183 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 184 if (hfile == INVALID_HANDLE_VALUE) return FALSE; 185 186 ret = WriteFile(hfile, data, *size, size, NULL); 187 188 CloseHandle(hfile); 189 return ret; 190 } 191 192 static BOOL write_ttf_file(const char *fontname, char *tmp_name) 193 { 194 void *rsrc_data; 195 DWORD rsrc_size; 196 197 rsrc_data = get_res_data( fontname, &rsrc_size ); 198 if (!rsrc_data) return FALSE; 199 200 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name ); 201 } 202 203 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont) 204 { 205 LOGFONTA getobj_lf; 206 int ret, minlen = 0; 207 208 if (!hfont) 209 return; 210 211 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf); 212 /* NT4 tries to be clever and only returns the minimum length */ 213 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1) 214 minlen++; 215 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1; 216 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret); 217 ok(lf->lfHeight == getobj_lf.lfHeight || 218 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */ 219 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight); 220 ok(lf->lfWidth == getobj_lf.lfWidth || 221 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */ 222 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth); 223 ok(lf->lfEscapement == getobj_lf.lfEscapement || 224 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */ 225 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement); 226 ok(lf->lfOrientation == getobj_lf.lfOrientation || 227 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */ 228 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation); 229 ok(lf->lfWeight == getobj_lf.lfWeight || 230 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */ 231 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight); 232 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic); 233 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline); 234 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut); 235 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet); 236 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision); 237 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision); 238 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality); 239 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily); 240 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) || 241 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */ 242 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName); 243 } 244 245 static HFONT create_font(const char* test, const LOGFONTA* lf) 246 { 247 HFONT hfont = CreateFontIndirectA(lf); 248 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test); 249 if (hfont) 250 check_font(test, lf, hfont); 251 return hfont; 252 } 253 254 static void test_logfont(void) 255 { 256 LOGFONTA lf; 257 HFONT hfont; 258 259 memset(&lf, 0, sizeof lf); 260 261 lf.lfCharSet = ANSI_CHARSET; 262 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 263 lf.lfWeight = FW_DONTCARE; 264 lf.lfHeight = 16; 265 lf.lfWidth = 16; 266 lf.lfQuality = DEFAULT_QUALITY; 267 268 lstrcpyA(lf.lfFaceName, "Arial"); 269 hfont = create_font("Arial", &lf); 270 DeleteObject(hfont); 271 272 memset(&lf, 'A', sizeof(lf)); 273 hfont = CreateFontIndirectA(&lf); 274 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n"); 275 276 lf.lfFaceName[LF_FACESIZE - 1] = 0; 277 check_font("AAA...", &lf, hfont); 278 DeleteObject(hfont); 279 } 280 281 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 282 { 283 if (type & RASTER_FONTTYPE) 284 { 285 LOGFONTA *lf = (LOGFONTA *)lParam; 286 *lf = *elf; 287 return 0; /* stop enumeration */ 288 } 289 290 return 1; /* continue enumeration */ 291 } 292 293 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm) 294 { 295 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight); 296 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent); 297 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent); 298 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading); 299 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading); 300 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth); 301 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth); 302 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight); 303 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang); 304 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX); 305 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY); 306 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar); 307 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar); 308 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar); 309 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar); 310 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic); 311 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined); 312 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut); 313 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily); 314 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet); 315 } 316 317 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight, 318 LONG lfWidth, const char *test_str, 319 INT test_str_len, const TEXTMETRICA *tm_orig, 320 const SIZE *size_orig, INT width_of_A_orig, 321 INT scale_x, INT scale_y) 322 { 323 LOGFONTA lf; 324 OUTLINETEXTMETRICA otm; 325 TEXTMETRICA tm; 326 SIZE size; 327 INT width_of_A, cx, cy; 328 UINT ret; 329 330 if (!hfont) 331 return; 332 333 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n"); 334 335 GetObjectA(hfont, sizeof(lf), &lf); 336 337 if (GetOutlineTextMetricsA(hdc, 0, NULL)) 338 { 339 otm.otmSize = sizeof(otm) / 2; 340 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm); 341 ok(ret == sizeof(otm)/2 /* XP */ || 342 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret); 343 344 memset(&otm, 0x1, sizeof(otm)); 345 otm.otmSize = sizeof(otm); 346 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm); 347 ok(ret == sizeof(otm) /* XP */ || 348 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret); 349 350 memset(&tm, 0x2, sizeof(tm)); 351 ret = GetTextMetricsA(hdc, &tm); 352 ok(ret, "GetTextMetricsA failed\n"); 353 /* the structure size is aligned */ 354 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1)) 355 { 356 ok(0, "tm != otm\n"); 357 compare_tm(&tm, &otm.otmTextMetrics); 358 } 359 360 tm = otm.otmTextMetrics; 361 if (0) /* these metrics are scaled too, but with rounding errors */ 362 { 363 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent); 364 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent); 365 } 366 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent); 367 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n"); 368 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n"); 369 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n"); 370 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent); 371 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare); 372 } 373 else 374 { 375 ret = GetTextMetricsA(hdc, &tm); 376 ok(ret, "GetTextMetricsA failed\n"); 377 } 378 379 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth; 380 cy = tm.tmHeight / tm_orig->tmHeight; 381 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n", 382 lfHeight, scale_x, scale_y, cx, cy); 383 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y); 384 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y); 385 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y); 386 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x); 387 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x); 388 389 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight); 390 if (lf.lfHeight) 391 { 392 if (lf.lfWidth) 393 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth); 394 } 395 else 396 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth); 397 398 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size); 399 400 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x); 401 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y); 402 403 GetCharWidthA(hdc, 'A', 'A', &width_of_A); 404 405 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x); 406 } 407 408 /* Test how GDI scales bitmap font metrics */ 409 static void test_bitmap_font(void) 410 { 411 static const char test_str[11] = "Test String"; 412 HDC hdc; 413 LOGFONTA bitmap_lf; 414 HFONT hfont, old_hfont; 415 TEXTMETRICA tm_orig; 416 SIZE size_orig; 417 INT ret, i, width_orig, height_orig, scale, lfWidth; 418 419 hdc = CreateCompatibleDC(0); 420 421 /* "System" has only 1 pixel size defined, otherwise the test breaks */ 422 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf); 423 if (ret) 424 { 425 ReleaseDC(0, hdc); 426 trace("no bitmap fonts were found, skipping the test\n"); 427 return; 428 } 429 430 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight); 431 432 height_orig = bitmap_lf.lfHeight; 433 lfWidth = bitmap_lf.lfWidth; 434 435 hfont = create_font("bitmap", &bitmap_lf); 436 old_hfont = SelectObject(hdc, hfont); 437 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n"); 438 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n"); 439 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n"); 440 SelectObject(hdc, old_hfont); 441 DeleteObject(hfont); 442 443 bitmap_lf.lfHeight = 0; 444 bitmap_lf.lfWidth = 4; 445 hfont = create_font("bitmap", &bitmap_lf); 446 old_hfont = SelectObject(hdc, hfont); 447 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1); 448 SelectObject(hdc, old_hfont); 449 DeleteObject(hfont); 450 451 bitmap_lf.lfHeight = height_orig; 452 bitmap_lf.lfWidth = lfWidth; 453 454 /* test fractional scaling */ 455 for (i = 1; i <= height_orig * 6; i++) 456 { 457 INT nearest_height; 458 459 bitmap_lf.lfHeight = i; 460 hfont = create_font("fractional", &bitmap_lf); 461 scale = (i + height_orig - 1) / height_orig; 462 nearest_height = scale * height_orig; 463 /* Only jump to the next height if the difference <= 25% original height */ 464 if (scale > 2 && nearest_height - i > height_orig / 4) scale--; 465 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x, 466 so we'll not test this particular height. */ 467 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue; 468 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--; 469 old_hfont = SelectObject(hdc, hfont); 470 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale); 471 SelectObject(hdc, old_hfont); 472 DeleteObject(hfont); 473 } 474 475 /* test integer scaling 3x2 */ 476 bitmap_lf.lfHeight = height_orig * 2; 477 bitmap_lf.lfWidth *= 3; 478 hfont = create_font("3x2", &bitmap_lf); 479 old_hfont = SelectObject(hdc, hfont); 480 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2); 481 SelectObject(hdc, old_hfont); 482 DeleteObject(hfont); 483 484 /* test integer scaling 3x3 */ 485 bitmap_lf.lfHeight = height_orig * 3; 486 bitmap_lf.lfWidth = 0; 487 hfont = create_font("3x3", &bitmap_lf); 488 old_hfont = SelectObject(hdc, hfont); 489 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3); 490 SelectObject(hdc, old_hfont); 491 DeleteObject(hfont); 492 493 DeleteDC(hdc); 494 } 495 496 /* Test how GDI scales outline font metrics */ 497 static void test_outline_font(void) 498 { 499 static const char test_str[11] = "Test String"; 500 HDC hdc, hdc_2; 501 LOGFONTA lf; 502 HFONT hfont, old_hfont, old_hfont_2; 503 OUTLINETEXTMETRICA otm; 504 SIZE size_orig; 505 INT width_orig, height_orig, lfWidth; 506 XFORM xform; 507 GLYPHMETRICS gm; 508 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} }; 509 POINT pt; 510 INT ret; 511 512 if (!is_truetype_font_installed("Arial")) 513 { 514 skip("Arial is not installed\n"); 515 return; 516 } 517 518 hdc = CreateCompatibleDC(0); 519 520 memset(&lf, 0, sizeof(lf)); 521 strcpy(lf.lfFaceName, "Arial"); 522 lf.lfHeight = 72; 523 hfont = create_font("outline", &lf); 524 old_hfont = SelectObject(hdc, hfont); 525 otm.otmSize = sizeof(otm); 526 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n"); 527 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n"); 528 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n"); 529 530 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 531 SelectObject(hdc, old_hfont); 532 DeleteObject(hfont); 533 534 /* font of otmEMSquare height helps to avoid a lot of rounding errors */ 535 lf.lfHeight = otm.otmEMSquare; 536 lf.lfHeight = -lf.lfHeight; 537 hfont = create_font("outline", &lf); 538 old_hfont = SelectObject(hdc, hfont); 539 otm.otmSize = sizeof(otm); 540 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n"); 541 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n"); 542 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n"); 543 SelectObject(hdc, old_hfont); 544 DeleteObject(hfont); 545 546 height_orig = otm.otmTextMetrics.tmHeight; 547 lfWidth = otm.otmTextMetrics.tmAveCharWidth; 548 549 /* test integer scaling 3x2 */ 550 lf.lfHeight = height_orig * 2; 551 lf.lfWidth = lfWidth * 3; 552 hfont = create_font("3x2", &lf); 553 old_hfont = SelectObject(hdc, hfont); 554 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2); 555 SelectObject(hdc, old_hfont); 556 DeleteObject(hfont); 557 558 /* test integer scaling 3x3 */ 559 lf.lfHeight = height_orig * 3; 560 lf.lfWidth = lfWidth * 3; 561 hfont = create_font("3x3", &lf); 562 old_hfont = SelectObject(hdc, hfont); 563 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3); 564 SelectObject(hdc, old_hfont); 565 DeleteObject(hfont); 566 567 /* test integer scaling 1x1 */ 568 lf.lfHeight = height_orig * 1; 569 lf.lfWidth = lfWidth * 1; 570 hfont = create_font("1x1", &lf); 571 old_hfont = SelectObject(hdc, hfont); 572 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 573 SelectObject(hdc, old_hfont); 574 DeleteObject(hfont); 575 576 /* test integer scaling 1x1 */ 577 lf.lfHeight = height_orig; 578 lf.lfWidth = 0; 579 hfont = create_font("1x1", &lf); 580 old_hfont = SelectObject(hdc, hfont); 581 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 582 583 /* with an identity matrix */ 584 memset(&gm, 0, sizeof(gm)); 585 SetLastError(0xdeadbeef); 586 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 587 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 588 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 589 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig); 590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 591 /* with a custom matrix */ 592 memset(&gm, 0, sizeof(gm)); 593 SetLastError(0xdeadbeef); 594 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); 595 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 596 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 597 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2); 598 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 599 600 /* Test that changing the DC transformation affects only the font 601 * selected on this DC and doesn't affect the same font selected on 602 * another DC. 603 */ 604 hdc_2 = CreateCompatibleDC(0); 605 old_hfont_2 = SelectObject(hdc_2, hfont); 606 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 607 608 SetMapMode(hdc, MM_ANISOTROPIC); 609 610 /* font metrics on another DC should be unchanged */ 611 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 612 613 /* test restrictions of compatibility mode GM_COMPATIBLE */ 614 /* part 1: rescaling only X should not change font scaling on screen. 615 So compressing the X axis by 2 is not done, and this 616 appears as X scaling of 2 that no one requested. */ 617 SetWindowExtEx(hdc, 100, 100, NULL); 618 SetViewportExtEx(hdc, 50, 100, NULL); 619 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1); 620 /* font metrics on another DC should be unchanged */ 621 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 622 623 /* part 2: rescaling only Y should change font scaling. 624 As also X is scaled by a factor of 2, but this is not 625 requested by the DC transformation, we get a scaling factor 626 of 2 in the X coordinate. */ 627 SetViewportExtEx(hdc, 100, 200, NULL); 628 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1); 629 /* font metrics on another DC should be unchanged */ 630 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 631 632 /* restore scaling */ 633 SetMapMode(hdc, MM_TEXT); 634 635 /* font metrics on another DC should be unchanged */ 636 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 637 638 SelectObject(hdc_2, old_hfont_2); 639 DeleteDC(hdc_2); 640 641 if (!SetGraphicsMode(hdc, GM_ADVANCED)) 642 { 643 SelectObject(hdc, old_hfont); 644 DeleteObject(hfont); 645 DeleteDC(hdc); 646 skip("GM_ADVANCED is not supported on this platform\n"); 647 return; 648 } 649 650 xform.eM11 = 20.0f; 651 xform.eM12 = 0.0f; 652 xform.eM21 = 0.0f; 653 xform.eM22 = 20.0f; 654 xform.eDx = 0.0f; 655 xform.eDy = 0.0f; 656 657 SetLastError(0xdeadbeef); 658 ret = SetWorldTransform(hdc, &xform); 659 ok(ret, "SetWorldTransform error %u\n", GetLastError()); 660 661 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 662 663 /* with an identity matrix */ 664 memset(&gm, 0, sizeof(gm)); 665 SetLastError(0xdeadbeef); 666 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 667 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 668 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 669 pt.x = width_orig; pt.y = 0; 670 LPtoDP(hdc, &pt, 1); 671 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x); 672 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig); 673 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 674 /* with a custom matrix */ 675 memset(&gm, 0, sizeof(gm)); 676 SetLastError(0xdeadbeef); 677 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); 678 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 679 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 680 pt.x = width_orig; pt.y = 0; 681 LPtoDP(hdc, &pt, 1); 682 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2); 683 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig); 684 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 685 686 SetLastError(0xdeadbeef); 687 ret = SetMapMode(hdc, MM_LOMETRIC); 688 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError()); 689 690 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 691 692 /* with an identity matrix */ 693 memset(&gm, 0, sizeof(gm)); 694 SetLastError(0xdeadbeef); 695 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 696 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 697 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 698 pt.x = width_orig; pt.y = 0; 699 LPtoDP(hdc, &pt, 1); 700 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x); 701 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 702 /* with a custom matrix */ 703 memset(&gm, 0, sizeof(gm)); 704 SetLastError(0xdeadbeef); 705 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); 706 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 707 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 708 pt.x = width_orig; pt.y = 0; 709 LPtoDP(hdc, &pt, 1); 710 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2); 711 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 712 713 SetLastError(0xdeadbeef); 714 ret = SetMapMode(hdc, MM_TEXT); 715 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError()); 716 717 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); 718 719 /* with an identity matrix */ 720 memset(&gm, 0, sizeof(gm)); 721 SetLastError(0xdeadbeef); 722 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 723 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 724 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 725 pt.x = width_orig; pt.y = 0; 726 LPtoDP(hdc, &pt, 1); 727 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x); 728 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig); 729 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 730 /* with a custom matrix */ 731 memset(&gm, 0, sizeof(gm)); 732 SetLastError(0xdeadbeef); 733 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); 734 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); 735 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); 736 pt.x = width_orig; pt.y = 0; 737 LPtoDP(hdc, &pt, 1); 738 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2); 739 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig); 740 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); 741 742 SelectObject(hdc, old_hfont); 743 DeleteObject(hfont); 744 DeleteDC(hdc); 745 } 746 747 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 748 { 749 LOGFONTA *lf = (LOGFONTA *)lParam; 750 751 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName)) 752 { 753 *lf = *elf; 754 return 0; /* stop enumeration */ 755 } 756 return 1; /* continue enumeration */ 757 } 758 759 static BOOL is_CJK(void) 760 { 761 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN); 762 } 763 764 #define FH_SCALE 0x80000000 765 static void test_bitmap_font_metrics(void) 766 { 767 static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0}; 768 static const struct font_data 769 { 770 const char face_name[LF_FACESIZE]; 771 int weight, height, ascent, descent, int_leading, ext_leading; 772 int ave_char_width, max_char_width, dpi; 773 BYTE first_char, last_char, def_char, break_char; 774 DWORD ansi_bitfield; 775 const WORD *skip_lang_id; 776 int scaled_height; 777 } fd[] = 778 { 779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 }, 780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 }, 781 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 }, 782 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 }, 783 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 }, 784 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 }, 785 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 }, 786 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 }, 787 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 16 }, 788 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 }, 789 790 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 }, 791 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 }, 792 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 }, 793 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 }, 794 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 }, 795 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 }, 796 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 }, 797 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 }, 798 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 }, 799 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 }, 800 801 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 802 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 803 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 804 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 805 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 }, 806 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 }, 807 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 808 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 }, 809 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 }, 810 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 811 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 }, 812 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 }, 813 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 814 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 }, 815 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 }, 816 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 817 818 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 819 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 820 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 821 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 822 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 823 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 824 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 825 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 826 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 827 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 828 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 }, 829 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC }, 830 831 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 }, 832 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 833 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 834 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 }, 835 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 836 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 }, 837 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 838 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 }, 839 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 840 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 }, 841 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 }, 842 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 843 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 }, 844 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 }, 845 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 846 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 }, 847 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 848 849 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC }, 850 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 }, 851 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC }, 852 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 }, 853 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC }, 854 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 }, 855 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 }, 856 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 857 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 }, 858 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 859 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 860 861 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 862 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 863 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 864 865 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 866 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 867 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, 868 869 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 }, 870 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 871 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN }, 872 873 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 }, 874 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 875 876 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 }, 877 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 878 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN }, 879 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl}, 880 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 881 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN }, 882 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl}, 883 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 884 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC }, 885 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN }, 886 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl}, 887 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 888 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC }, 889 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN }, 890 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl}, 891 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 892 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC }, 893 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN }, 894 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl}, 895 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC }, 896 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN }, 897 898 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN }, 899 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 900 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN }, 901 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 902 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN }, 903 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC }, 904 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN }, 905 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 906 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN }, 907 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 908 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN }, 909 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 910 911 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 }, 912 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC }, 913 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN }, 914 915 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC } 916 917 /* FIXME: add "Terminal" */ 918 }; 919 static const int font_log_pixels[] = { 96, 120 }; 920 HDC hdc; 921 LOGFONTA lf; 922 HFONT hfont, old_hfont; 923 TEXTMETRICA tm; 924 INT ret, i, expected_cs, screen_log_pixels, diff, font_res; 925 char face_name[LF_FACESIZE]; 926 CHARSETINFO csi; 927 928 trace("system language id %04x\n", system_lang_id); 929 930 expected_cs = GetACP(); 931 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE)) 932 { 933 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs); 934 return; 935 } 936 expected_cs = csi.ciCharset; 937 trace("ACP %d -> charset %d\n", GetACP(), expected_cs); 938 939 hdc = CreateCompatibleDC(0); 940 ok(hdc != NULL, "failed to create hdc\n"); 941 942 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX), 943 GetDeviceCaps(hdc, LOGPIXELSY)); 944 945 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY); 946 diff = 32768; 947 font_res = 0; 948 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++) 949 { 950 int new_diff = abs(font_log_pixels[i] - screen_log_pixels); 951 if (new_diff < diff) 952 { 953 diff = new_diff; 954 font_res = font_log_pixels[i]; 955 } 956 } 957 trace("best font resolution is %d\n", font_res); 958 959 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++) 960 { 961 int bit, height; 962 963 memset(&lf, 0, sizeof(lf)); 964 965 height = fd[i].height & ~FH_SCALE; 966 lf.lfHeight = height; 967 strcpy(lf.lfFaceName, fd[i].face_name); 968 969 for(bit = 0; bit < 32; bit++) 970 { 971 GLYPHMETRICS gm; 972 DWORD fs[2]; 973 BOOL bRet; 974 975 fs[0] = 1L << bit; 976 fs[1] = 0; 977 if((fd[i].ansi_bitfield & fs[0]) == 0) continue; 978 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue; 979 980 lf.lfCharSet = csi.ciCharset; 981 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0); 982 if (fd[i].height & FH_SCALE) 983 ok(ret, "scaled font height %d should not be enumerated\n", height); 984 else 985 { 986 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs) 987 { 988 todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */ 989 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi); 990 } 991 } 992 if (ret && !(fd[i].height & FH_SCALE)) 993 continue; 994 995 hfont = create_font(lf.lfFaceName, &lf); 996 old_hfont = SelectObject(hdc, hfont); 997 998 SetLastError(0xdeadbeef); 999 ret = GetTextFaceA(hdc, sizeof(face_name), face_name); 1000 ok(ret, "GetTextFace error %u\n", GetLastError()); 1001 1002 if (strcmp(face_name, fd[i].face_name) != 0) 1003 { 1004 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n"); 1005 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs); 1006 SelectObject(hdc, old_hfont); 1007 DeleteObject(hfont); 1008 continue; 1009 } 1010 1011 memset(&gm, 0, sizeof(gm)); 1012 SetLastError(0xdeadbeef); 1013 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 1014 todo_wine { 1015 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n"); 1016 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError()); 1017 } 1018 1019 bRet = GetTextMetricsA(hdc, &tm); 1020 ok(bRet, "GetTextMetrics error %d\n", GetLastError()); 1021 1022 SetLastError(0xdeadbeef); 1023 ret = GetTextCharset(hdc); 1024 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET) 1025 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret); 1026 else 1027 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs); 1028 1029 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX); 1030 trace("expected %s, height %d scaled_height %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi); 1031 1032 if(fd[i].dpi == tm.tmDigitizedAspectX) 1033 { 1034 int skipme = 0; 1035 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi); 1036 if (fd[i].skip_lang_id) 1037 { 1038 int si = 0; 1039 skipme = 0; 1040 while(!skipme && fd[i].skip_lang_id[si]) 1041 if (fd[i].skip_lang_id[si++] == system_lang_id) 1042 skipme = 1; 1043 } 1044 if (!skipme) 1045 { 1046 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight); 1047 if (fd[i].height & FH_SCALE) 1048 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height); 1049 else 1050 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); 1051 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent); 1052 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent); 1053 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading); 1054 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading); 1055 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width); 1056 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar); 1057 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar); 1058 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204 1059 make default char test fail */ 1060 if (tm.tmCharSet == lf.lfCharSet) 1061 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar); 1062 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar); 1063 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs); 1064 1065 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font 1066 that make the max width bigger */ 1067 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96) 1068 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width); 1069 } 1070 else 1071 skip("Skipping font metrics test for system langid 0x%x\n", 1072 system_lang_id); 1073 } 1074 SelectObject(hdc, old_hfont); 1075 DeleteObject(hfont); 1076 } 1077 } 1078 1079 DeleteDC(hdc); 1080 } 1081 1082 static void test_GdiGetCharDimensions(void) 1083 { 1084 HDC hdc; 1085 TEXTMETRICW tm; 1086 LONG ret; 1087 SIZE size; 1088 LONG avgwidth, height; 1089 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 1090 1091 if (!pGdiGetCharDimensions) 1092 { 1093 win_skip("GdiGetCharDimensions not available on this platform\n"); 1094 return; 1095 } 1096 1097 hdc = CreateCompatibleDC(NULL); 1098 1099 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size); 1100 avgwidth = ((size.cx / 26) + 1) / 2; 1101 1102 ret = pGdiGetCharDimensions(hdc, &tm, &height); 1103 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret); 1104 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height); 1105 1106 ret = pGdiGetCharDimensions(hdc, &tm, NULL); 1107 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret); 1108 1109 ret = pGdiGetCharDimensions(hdc, NULL, NULL); 1110 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret); 1111 1112 height = 0; 1113 ret = pGdiGetCharDimensions(hdc, NULL, &height); 1114 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret); 1115 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height); 1116 1117 DeleteDC(hdc); 1118 } 1119 1120 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe, 1121 const TEXTMETRICA *lpntme, 1122 DWORD FontType, LPARAM lParam) 1123 { 1124 if (FontType & TRUETYPE_FONTTYPE) 1125 { 1126 HFONT hfont; 1127 1128 hfont = CreateFontIndirectA(lpelfe); 1129 if (hfont) 1130 { 1131 *(HFONT *)lParam = hfont; 1132 return 0; 1133 } 1134 } 1135 1136 return 1; 1137 } 1138 1139 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo) 1140 { 1141 ABC abc[1]; 1142 ABCFLOAT abcf[1]; 1143 BOOL ret = FALSE; 1144 1145 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc); 1146 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description); 1147 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description); 1148 todo_wine_if (todo) 1149 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description); 1150 todo_wine_if (todo) 1151 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description); 1152 1153 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc); 1154 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description); 1155 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description); 1156 todo_wine_if (todo) 1157 ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description); 1158 todo_wine_if (todo) 1159 ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description); 1160 1161 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf); 1162 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description); 1163 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description); 1164 todo_wine_if (todo) 1165 ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description); 1166 todo_wine_if (todo) 1167 ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description); 1168 } 1169 1170 static void test_GetCharABCWidths(void) 1171 { 1172 static const WCHAR str[] = {'i',0}; 1173 BOOL ret; 1174 HDC hdc; 1175 LOGFONTA lf; 1176 HFONT hfont; 1177 ABC abc[1]; 1178 ABC abcw[1]; 1179 ABCFLOAT abcf[1]; 1180 WORD glyphs[1]; 1181 DWORD nb; 1182 HWND hwnd; 1183 static const struct 1184 { 1185 UINT first; 1186 UINT last; 1187 } range[] = 1188 { 1189 {0xff, 0xff}, 1190 {0x100, 0x100}, 1191 {0xff, 0x100}, 1192 {0x1ff, 0xff00}, 1193 {0xffff, 0xffff}, 1194 {0x10000, 0x10000}, 1195 {0xffff, 0x10000}, 1196 {0xffffff, 0xffffff}, 1197 {0x1000000, 0x1000000}, 1198 {0xffffff, 0x1000000}, 1199 {0xffffffff, 0xffffffff}, 1200 {0x00, 0xff} 1201 }; 1202 static const struct 1203 { 1204 UINT cs; 1205 UINT a; 1206 UINT w; 1207 BOOL r[sizeof range / sizeof range[0]]; 1208 } c[] = 1209 { 1210 {ANSI_CHARSET, 0x30, 0x30, 1211 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}, 1212 {SHIFTJIS_CHARSET, 0x82a0, 0x3042, 1213 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}, 1214 {HANGEUL_CHARSET, 0x8141, 0xac02, 1215 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}, 1216 {GB2312_CHARSET, 0x8141, 0x4e04, 1217 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}, 1218 {CHINESEBIG5_CHARSET, 0xa142, 0x3001, 1219 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}} 1220 }; 1221 UINT i; 1222 1223 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI) 1224 { 1225 win_skip("GetCharABCWidthsA/W/I not available on this platform\n"); 1226 return; 1227 } 1228 1229 memset(&lf, 0, sizeof(lf)); 1230 strcpy(lf.lfFaceName, "System"); 1231 lf.lfHeight = 20; 1232 1233 hfont = CreateFontIndirectA(&lf); 1234 hdc = GetDC(0); 1235 hfont = SelectObject(hdc, hfont); 1236 1237 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0); 1238 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n"); 1239 1240 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc); 1241 ok(!ret, "GetCharABCWidthsI should have failed\n"); 1242 1243 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL); 1244 ok(!ret, "GetCharABCWidthsI should have failed\n"); 1245 1246 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc); 1247 ok(ret, "GetCharABCWidthsI should have succeeded\n"); 1248 1249 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc); 1250 ok(!ret, "GetCharABCWidthsW should have failed\n"); 1251 1252 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL); 1253 ok(!ret, "GetCharABCWidthsW should have failed\n"); 1254 1255 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc); 1256 ok(!ret, "GetCharABCWidthsW should have failed\n"); 1257 1258 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf); 1259 ok(!ret, "GetCharABCWidthsFloatW should have failed\n"); 1260 1261 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL); 1262 ok(!ret, "GetCharABCWidthsFloatW should have failed\n"); 1263 1264 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf); 1265 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n"); 1266 1267 hfont = SelectObject(hdc, hfont); 1268 DeleteObject(hfont); 1269 1270 for (i = 0; i < sizeof c / sizeof c[0]; ++i) 1271 { 1272 ABC a[2], w[2]; 1273 ABC full[256]; 1274 UINT code = 0x41, j; 1275 1276 lf.lfFaceName[0] = '\0'; 1277 lf.lfCharSet = c[i].cs; 1278 lf.lfPitchAndFamily = 0; 1279 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0)) 1280 { 1281 skip("TrueType font for charset %u is not installed\n", c[i].cs); 1282 continue; 1283 } 1284 1285 memset(a, 0, sizeof a); 1286 memset(w, 0, sizeof w); 1287 hfont = SelectObject(hdc, hfont); 1288 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) && 1289 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) && 1290 memcmp(a, w, sizeof a) == 0, 1291 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs); 1292 1293 memset(a, 0xbb, sizeof a); 1294 ret = pGetCharABCWidthsA(hdc, code, code, a); 1295 ok(ret, "GetCharABCWidthsA should have succeeded\n"); 1296 memset(full, 0xcc, sizeof full); 1297 ret = pGetCharABCWidthsA(hdc, 0x00, code, full); 1298 ok(ret, "GetCharABCWidthsA should have succeeded\n"); 1299 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0, 1300 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs); 1301 1302 for (j = 0; j < sizeof range / sizeof range[0]; ++j) 1303 { 1304 memset(full, 0xdd, sizeof full); 1305 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full); 1306 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n", 1307 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed"); 1308 if (ret) 1309 { 1310 UINT last = range[j].last - range[j].first; 1311 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a); 1312 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0, 1313 "GetCharABCWidthsA %x should match. codepage = %u\n", 1314 range[j].last, c[i].cs); 1315 } 1316 } 1317 1318 hfont = SelectObject(hdc, hfont); 1319 DeleteObject(hfont); 1320 } 1321 1322 memset(&lf, 0, sizeof(lf)); 1323 strcpy(lf.lfFaceName, "Tahoma"); 1324 lf.lfHeight = 200; 1325 hfont = CreateFontIndirectA(&lf); 1326 1327 /* test empty glyph's metrics */ 1328 hfont = SelectObject(hdc, hfont); 1329 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf); 1330 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n"); 1331 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB); 1332 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw); 1333 ok(ret, "GetCharABCWidthsW should have succeeded\n"); 1334 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB); 1335 1336 /* 1) prepare unrotated font metrics */ 1337 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw); 1338 ok(ret, "GetCharABCWidthsW should have succeeded\n"); 1339 DeleteObject(SelectObject(hdc, hfont)); 1340 1341 /* 2) get rotated font metrics */ 1342 lf.lfEscapement = lf.lfOrientation = 900; 1343 hfont = CreateFontIndirectA(&lf); 1344 hfont = SelectObject(hdc, hfont); 1345 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc); 1346 ok(ret, "GetCharABCWidthsW should have succeeded\n"); 1347 1348 /* 3) compare ABC results */ 1349 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE), 1350 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA); 1351 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE), 1352 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB); 1353 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE), 1354 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC); 1355 1356 DeleteObject(SelectObject(hdc, hfont)); 1357 ReleaseDC(NULL, hdc); 1358 1359 trace("ABC sign test for a variety of transforms:\n"); 1360 memset(&lf, 0, sizeof(lf)); 1361 strcpy(lf.lfFaceName, "Tahoma"); 1362 lf.lfHeight = 20; 1363 hfont = CreateFontIndirectA(&lf); 1364 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100, 1365 0, 0, 0, NULL); 1366 hdc = GetDC(hwnd); 1367 SetMapMode(hdc, MM_ANISOTROPIC); 1368 SelectObject(hdc, hfont); 1369 1370 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0); 1371 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n"); 1372 1373 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc); 1374 ok(ret, "GetCharABCWidthsI should have succeeded\n"); 1375 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw); 1376 ok(ret, "GetCharABCWidthsW should have succeeded\n"); 1377 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf); 1378 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n"); 1379 1380 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0); 1381 SetWindowExtEx(hdc, -1, -1, NULL); 1382 SetGraphicsMode(hdc, GM_COMPATIBLE); 1383 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0); 1384 SetGraphicsMode(hdc, GM_ADVANCED); 1385 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1); 1386 SetWindowExtEx(hdc, 1, 1, NULL); 1387 SetGraphicsMode(hdc, GM_COMPATIBLE); 1388 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0); 1389 SetGraphicsMode(hdc, GM_ADVANCED); 1390 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0); 1391 1392 ReleaseDC(hwnd, hdc); 1393 DestroyWindow(hwnd); 1394 1395 trace("RTL layout\n"); 1396 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100, 1397 0, 0, 0, NULL); 1398 hdc = GetDC(hwnd); 1399 SetMapMode(hdc, MM_ANISOTROPIC); 1400 SelectObject(hdc, hfont); 1401 1402 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0); 1403 SetWindowExtEx(hdc, -1, -1, NULL); 1404 SetGraphicsMode(hdc, GM_COMPATIBLE); 1405 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0); 1406 SetGraphicsMode(hdc, GM_ADVANCED); 1407 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0); 1408 SetWindowExtEx(hdc, 1, 1, NULL); 1409 SetGraphicsMode(hdc, GM_COMPATIBLE); 1410 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0); 1411 SetGraphicsMode(hdc, GM_ADVANCED); 1412 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1); 1413 1414 ReleaseDC(hwnd, hdc); 1415 DestroyWindow(hwnd); 1416 DeleteObject(hfont); 1417 } 1418 1419 static void test_text_extents(void) 1420 { 1421 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0}; 1422 static const WCHAR emptyW[] = {0}; 1423 LPINT extents; 1424 INT i, len, fit1, fit2, extents2[3]; 1425 LOGFONTA lf; 1426 TEXTMETRICA tm; 1427 HDC hdc; 1428 HFONT hfont; 1429 SIZE sz; 1430 SIZE sz1, sz2; 1431 BOOL ret; 1432 1433 memset(&lf, 0, sizeof(lf)); 1434 strcpy(lf.lfFaceName, "Arial"); 1435 lf.lfHeight = 20; 1436 1437 hfont = CreateFontIndirectA(&lf); 1438 hdc = GetDC(0); 1439 hfont = SelectObject(hdc, hfont); 1440 GetTextMetricsA(hdc, &tm); 1441 ret = GetTextExtentPointA(hdc, "o", 1, &sz); 1442 ok(ret, "got %d\n", ret); 1443 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight); 1444 1445 memset(&sz, 0xcc, sizeof(sz)); 1446 ret = GetTextExtentPointA(hdc, "o", 0, &sz); 1447 ok(ret, "got %d\n", ret); 1448 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy); 1449 1450 memset(&sz, 0xcc, sizeof(sz)); 1451 ret = GetTextExtentPointA(hdc, "", 0, &sz); 1452 ok(ret, "got %d\n", ret); 1453 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy); 1454 1455 SetLastError(0xdeadbeef); 1456 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1); 1457 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 1458 { 1459 win_skip("Skipping remainder of text extents test on a Win9x platform\n"); 1460 hfont = SelectObject(hdc, hfont); 1461 DeleteObject(hfont); 1462 ReleaseDC(0, hdc); 1463 return; 1464 } 1465 1466 memset(&sz, 0xcc, sizeof(sz)); 1467 ret = GetTextExtentPointW(hdc, wt, 0, &sz); 1468 ok(ret, "got %d\n", ret); 1469 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy); 1470 1471 memset(&sz, 0xcc, sizeof(sz)); 1472 ret = GetTextExtentPointW(hdc, emptyW, 0, &sz); 1473 ok(ret, "got %d\n", ret); 1474 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy); 1475 1476 len = lstrlenW(wt); 1477 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]); 1478 extents[0] = 1; /* So that the increasing sequence test will fail 1479 if the extents array is untouched. */ 1480 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1); 1481 GetTextExtentPointW(hdc, wt, len, &sz2); 1482 ok(sz1.cy == sz2.cy, 1483 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy); 1484 /* Because of the '\n' in the string GetTextExtentExPoint and 1485 GetTextExtentPoint return different widths under Win2k, but 1486 under WinXP they return the same width. So we don't test that 1487 here. */ 1488 1489 for (i = 1; i < len; ++i) 1490 ok(extents[i-1] <= extents[i], 1491 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n", 1492 i); 1493 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n"); 1494 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1); 1495 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n"); 1496 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2); 1497 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n"); 1498 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n"); 1499 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2); 1500 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n"); 1501 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2); 1502 ok(extents[0] == extents[2] && extents[1] == extents[3], 1503 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n"); 1504 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1); 1505 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, 1506 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n"); 1507 1508 /* extents functions fail with -ve counts (the interesting case being -1) */ 1509 ret = GetTextExtentPointA(hdc, "o", -1, &sz); 1510 ok(ret == FALSE, "got %d\n", ret); 1511 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz); 1512 ok(ret == FALSE, "got %d\n", ret); 1513 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1); 1514 ok(ret == FALSE, "got %d\n", ret); 1515 1516 /* max_extent = 0 succeeds and returns zero */ 1517 fit1 = fit2 = -215; 1518 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz); 1519 ok(ret == TRUE || 1520 broken(ret == FALSE), /* NT4, 2k */ 1521 "got %d\n", ret); 1522 ok(fit1 == 0 || 1523 broken(fit1 == -215), /* NT4, 2k */ 1524 "fit = %d\n", fit1); 1525 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1); 1526 ok(ret == TRUE, "got %d\n", ret); 1527 ok(fit2 == 0, "fit = %d\n", fit2); 1528 1529 /* max_extent = -1 is interpreted as a very large width that will 1530 * definitely fit our three characters */ 1531 fit1 = fit2 = -215; 1532 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz); 1533 ok(ret == TRUE, "got %d\n", ret); 1534 ok(fit1 == 3, "fit = %d\n", fit1); 1535 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz); 1536 ok(ret == TRUE, "got %d\n", ret); 1537 ok(fit2 == 3, "fit = %d\n", fit2); 1538 1539 /* max_extent = -2 is interpreted similarly, but the Ansi version 1540 * rejects it while the Unicode one accepts it */ 1541 fit1 = fit2 = -215; 1542 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz); 1543 ok(ret == FALSE, "got %d\n", ret); 1544 ok(fit1 == -215, "fit = %d\n", fit1); 1545 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz); 1546 ok(ret == TRUE, "got %d\n", ret); 1547 ok(fit2 == 3, "fit = %d\n", fit2); 1548 1549 hfont = SelectObject(hdc, hfont); 1550 DeleteObject(hfont); 1551 1552 /* non-MM_TEXT mapping mode */ 1553 lf.lfHeight = 2000; 1554 hfont = CreateFontIndirectA(&lf); 1555 hfont = SelectObject(hdc, hfont); 1556 1557 SetMapMode( hdc, MM_HIMETRIC ); 1558 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz); 1559 ok(ret, "got %d\n", ret); 1560 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]); 1561 1562 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2); 1563 ok(ret, "got %d\n", ret); 1564 ok(fit1 == 2, "got %d\n", fit1); 1565 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx); 1566 for(i = 0; i < 2; i++) 1567 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]); 1568 1569 hfont = SelectObject(hdc, hfont); 1570 DeleteObject(hfont); 1571 HeapFree(GetProcessHeap(), 0, extents); 1572 ReleaseDC(NULL, hdc); 1573 } 1574 1575 static void test_GetGlyphIndices(void) 1576 { 1577 HDC hdc; 1578 HFONT hfont; 1579 DWORD charcount; 1580 LOGFONTA lf; 1581 DWORD flags = 0; 1582 WCHAR testtext[] = {'T','e','s','t',0xffff,0}; 1583 WORD glyphs[(sizeof(testtext)/2)-1]; 1584 TEXTMETRICA textm; 1585 HFONT hOldFont; 1586 1587 if (!pGetGlyphIndicesW) { 1588 win_skip("GetGlyphIndicesW not available on platform\n"); 1589 return; 1590 } 1591 1592 hdc = GetDC(0); 1593 1594 memset(&lf, 0, sizeof(lf)); 1595 strcpy(lf.lfFaceName, "System"); 1596 lf.lfHeight = 16; 1597 lf.lfCharSet = ANSI_CHARSET; 1598 1599 hfont = CreateFontIndirectA(&lf); 1600 ok(hfont != 0, "CreateFontIndirectEx failed\n"); 1601 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n"); 1602 if (textm.tmCharSet == ANSI_CHARSET) 1603 { 1604 flags |= GGI_MARK_NONEXISTING_GLYPHS; 1605 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags); 1606 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount); 1607 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]); 1608 flags = 0; 1609 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags); 1610 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount); 1611 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n", 1612 textm.tmDefaultChar, glyphs[4]); 1613 } 1614 else 1615 /* FIXME: Write tests for non-ANSI charsets. */ 1616 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n"); 1617 1618 if(!is_font_installed("Tahoma")) 1619 { 1620 skip("Tahoma is not installed so skipping this test\n"); 1621 return; 1622 } 1623 memset(&lf, 0, sizeof(lf)); 1624 strcpy(lf.lfFaceName, "Tahoma"); 1625 lf.lfHeight = 20; 1626 1627 hfont = CreateFontIndirectA(&lf); 1628 hOldFont = SelectObject(hdc, hfont); 1629 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n"); 1630 flags |= GGI_MARK_NONEXISTING_GLYPHS; 1631 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags); 1632 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount); 1633 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]); 1634 flags = 0; 1635 testtext[0] = textm.tmDefaultChar; 1636 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags); 1637 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount); 1638 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]); 1639 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]); 1640 DeleteObject(SelectObject(hdc, hOldFont)); 1641 } 1642 1643 static void test_GetKerningPairs(void) 1644 { 1645 static const struct kerning_data 1646 { 1647 const char face_name[LF_FACESIZE]; 1648 LONG height; 1649 /* some interesting fields from OUTLINETEXTMETRIC */ 1650 LONG tmHeight, tmAscent, tmDescent; 1651 UINT otmEMSquare; 1652 INT otmAscent; 1653 INT otmDescent; 1654 UINT otmLineGap; 1655 UINT otmsCapEmHeight; 1656 UINT otmsXHeight; 1657 INT otmMacAscent; 1658 INT otmMacDescent; 1659 UINT otmMacLineGap; 1660 UINT otmusMinimumPPEM; 1661 /* small subset of kerning pairs to test */ 1662 DWORD total_kern_pairs; 1663 const KERNINGPAIR kern_pair[26]; 1664 } kd[] = 1665 { 1666 {"Arial", 12, 12, 9, 3, 1667 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9, 1668 26, 1669 { 1670 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1}, 1671 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0}, 1672 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0}, 1673 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0}, 1674 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1}, 1675 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1}, 1676 {933,970,+1},{933,972,-1} 1677 } 1678 }, 1679 {"Arial", -34, 39, 32, 7, 1680 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9, 1681 26, 1682 { 1683 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3}, 1684 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1}, 1685 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1}, 1686 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1}, 1687 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3}, 1688 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3}, 1689 {933,970,+2},{933,972,-3} 1690 } 1691 }, 1692 { "Arial", 120, 120, 97, 23, 1693 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9, 1694 26, 1695 { 1696 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8}, 1697 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4}, 1698 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2}, 1699 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4}, 1700 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8}, 1701 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8}, 1702 {933,970,+6},{933,972,-10} 1703 } 1704 }, 1705 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */ 1706 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194, 1707 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9, 1708 26, 1709 { 1710 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68}, 1711 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34}, 1712 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17}, 1713 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34}, 1714 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68}, 1715 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68}, 1716 {933,970,+54},{933,972,-83} 1717 } 1718 } 1719 #endif 1720 }; 1721 LOGFONTA lf; 1722 HFONT hfont, hfont_old; 1723 KERNINGPAIR *kern_pair; 1724 HDC hdc; 1725 DWORD total_kern_pairs, ret, i, n, matches; 1726 1727 hdc = GetDC(0); 1728 1729 /* GetKerningPairsA maps unicode set of kerning pairs to current code page 1730 * which may render this test unusable, so we're trying to avoid that. 1731 */ 1732 SetLastError(0xdeadbeef); 1733 GetKerningPairsW(hdc, 0, NULL); 1734 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 1735 { 1736 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n"); 1737 ReleaseDC(0, hdc); 1738 return; 1739 } 1740 1741 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++) 1742 { 1743 OUTLINETEXTMETRICW otm; 1744 UINT uiRet; 1745 1746 if (!is_font_installed(kd[i].face_name)) 1747 { 1748 trace("%s is not installed so skipping this test\n", kd[i].face_name); 1749 continue; 1750 } 1751 1752 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height); 1753 1754 memset(&lf, 0, sizeof(lf)); 1755 strcpy(lf.lfFaceName, kd[i].face_name); 1756 lf.lfHeight = kd[i].height; 1757 hfont = CreateFontIndirectA(&lf); 1758 ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name); 1759 1760 hfont_old = SelectObject(hdc, hfont); 1761 1762 SetLastError(0xdeadbeef); 1763 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */ 1764 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm); 1765 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError()); 1766 1767 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n", 1768 kd[i].tmHeight, otm.otmTextMetrics.tmHeight); 1769 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n", 1770 kd[i].tmAscent, otm.otmTextMetrics.tmAscent); 1771 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n", 1772 kd[i].tmDescent, otm.otmTextMetrics.tmDescent); 1773 1774 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n", 1775 kd[i].otmEMSquare, otm.otmEMSquare); 1776 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n", 1777 kd[i].otmAscent, otm.otmAscent); 1778 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n", 1779 kd[i].otmDescent, otm.otmDescent); 1780 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n", 1781 kd[i].otmLineGap, otm.otmLineGap); 1782 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n", 1783 kd[i].otmMacDescent, otm.otmMacDescent); 1784 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n", 1785 kd[i].otmMacAscent, otm.otmMacAscent); 1786 todo_wine { 1787 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n", 1788 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight); 1789 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n", 1790 kd[i].otmsXHeight, otm.otmsXHeight); 1791 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */ 1792 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n", 1793 kd[i].otmMacLineGap, otm.otmMacLineGap); 1794 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n", 1795 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM); 1796 } 1797 1798 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL); 1799 trace("total_kern_pairs %u\n", total_kern_pairs); 1800 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair)); 1801 1802 /* Win98 (GetKerningPairsA) and XP behave differently here, the test 1803 * passes on XP. 1804 */ 1805 SetLastError(0xdeadbeef); 1806 ret = GetKerningPairsW(hdc, 0, kern_pair); 1807 ok(GetLastError() == ERROR_INVALID_PARAMETER, 1808 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError()); 1809 ok(ret == 0, "got %u, expected 0\n", ret); 1810 1811 ret = GetKerningPairsW(hdc, 100, NULL); 1812 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs); 1813 1814 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair); 1815 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2); 1816 1817 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair); 1818 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs); 1819 1820 matches = 0; 1821 1822 for (n = 0; n < ret; n++) 1823 { 1824 DWORD j; 1825 /* Disabled to limit console spam */ 1826 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127) 1827 trace("{'%c','%c',%d},\n", 1828 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount); 1829 for (j = 0; j < kd[i].total_kern_pairs; j++) 1830 { 1831 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst && 1832 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond) 1833 { 1834 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount, 1835 "pair %d:%d got %d, expected %d\n", 1836 kern_pair[n].wFirst, kern_pair[n].wSecond, 1837 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount); 1838 matches++; 1839 } 1840 } 1841 } 1842 1843 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n", 1844 matches, kd[i].total_kern_pairs); 1845 1846 HeapFree(GetProcessHeap(), 0, kern_pair); 1847 1848 SelectObject(hdc, hfont_old); 1849 DeleteObject(hfont); 1850 } 1851 1852 ReleaseDC(0, hdc); 1853 } 1854 1855 struct font_data 1856 { 1857 const char face_name[LF_FACESIZE]; 1858 int requested_height; 1859 int weight, height, ascent, descent, int_leading, ext_leading, dpi; 1860 BOOL exact; 1861 }; 1862 1863 static void test_height( HDC hdc, const struct font_data *fd ) 1864 { 1865 LOGFONTA lf; 1866 HFONT hfont, old_hfont; 1867 TEXTMETRICA tm; 1868 INT ret, i; 1869 1870 for (i = 0; fd[i].face_name[0]; i++) 1871 { 1872 if (!is_truetype_font_installed(fd[i].face_name)) 1873 { 1874 skip("%s is not installed\n", fd[i].face_name); 1875 continue; 1876 } 1877 1878 memset(&lf, 0, sizeof(lf)); 1879 lf.lfHeight = fd[i].requested_height; 1880 lf.lfWeight = fd[i].weight; 1881 strcpy(lf.lfFaceName, fd[i].face_name); 1882 1883 hfont = CreateFontIndirectA(&lf); 1884 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name); 1885 1886 old_hfont = SelectObject(hdc, hfont); 1887 ret = GetTextMetricsA(hdc, &tm); 1888 ok(ret, "GetTextMetrics error %d\n", GetLastError()); 1889 if(fd[i].dpi == tm.tmDigitizedAspectX) 1890 { 1891 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); 1892 ok(match_off_by_1(tm.tmHeight, fd[i].height, fd[i].exact), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height); 1893 ok(match_off_by_1(tm.tmAscent, fd[i].ascent, fd[i].exact), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent); 1894 ok(match_off_by_1(tm.tmDescent, fd[i].descent, fd[i].exact), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent); 1895 ok(match_off_by_1(tm.tmInternalLeading, fd[i].int_leading, fd[i].exact), "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading); 1896 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); 1897 } 1898 1899 SelectObject(hdc, old_hfont); 1900 /* force GDI to use new font, otherwise Windows leaks the font reference */ 1901 GetTextMetricsA(hdc, &tm); 1902 DeleteObject(hfont); 1903 } 1904 } 1905 1906 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag ) 1907 { 1908 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2)); 1909 DWORD *table = (DWORD *)ttf + 3; 1910 1911 for (i = 0; i < num_tables; i++) 1912 { 1913 if (table[0] == tag) 1914 return (BYTE *)ttf + GET_BE_DWORD(table[2]); 1915 table += 4; 1916 } 1917 return NULL; 1918 } 1919 1920 static void test_height_selection_vdmx( HDC hdc ) 1921 { 1922 static const struct font_data charset_0[] = /* doesn't use VDMX */ 1923 { 1924 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE }, 1925 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE }, 1926 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE }, 1927 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE }, 1928 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE }, 1929 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE }, 1930 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE }, 1931 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE }, 1932 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE }, 1933 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE }, 1934 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE }, 1935 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE }, 1936 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE }, 1937 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE }, 1938 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE }, 1939 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE }, 1940 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE }, 1941 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE }, 1942 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE }, 1943 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE }, 1944 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE }, 1945 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE }, 1946 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE }, 1947 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE }, 1948 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE }, 1949 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE }, 1950 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE }, 1951 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE }, 1952 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE }, 1953 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE }, 1954 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE }, 1955 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE }, 1956 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE }, 1957 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE }, 1958 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE }, 1959 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE }, 1960 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE }, 1961 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE }, 1962 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE }, 1963 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE }, 1964 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE }, 1965 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE }, 1966 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE }, 1967 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE }, 1968 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE }, 1969 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE }, 1970 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE }, 1971 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE }, 1972 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE }, 1973 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE }, 1974 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE }, 1975 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE }, 1976 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 } 1977 }; 1978 1979 static const struct font_data charset_1[] = /* Uses VDMX */ 1980 { 1981 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE }, 1982 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE }, 1983 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE }, 1984 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE }, 1985 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE }, 1986 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE }, 1987 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE }, 1988 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE }, 1989 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE }, 1990 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE }, 1991 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE }, 1992 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE }, 1993 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE }, 1994 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE }, 1995 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE }, 1996 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE }, 1997 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE }, 1998 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE }, 1999 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE }, 2000 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE }, 2001 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE }, 2002 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE }, 2003 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE }, 2004 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE }, 2005 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE }, 2006 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE }, 2007 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE }, 2008 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE }, 2009 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE }, 2010 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE }, 2011 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE }, 2012 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE }, 2013 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE }, 2014 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE }, 2015 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE }, 2016 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE }, 2017 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE }, 2018 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE }, 2019 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE }, 2020 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE }, 2021 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE }, 2022 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE }, 2023 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE }, 2024 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE }, 2025 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE }, 2026 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE }, 2027 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE }, 2028 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE }, 2029 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE }, 2030 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE }, 2031 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE }, 2032 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE }, 2033 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 } 2034 }; 2035 2036 static const struct vdmx_data 2037 { 2038 WORD version; 2039 BYTE bCharSet; 2040 const struct font_data *fd; 2041 } data[] = 2042 { 2043 { 0, 0, charset_0 }, 2044 { 0, 1, charset_1 }, 2045 { 1, 0, charset_0 }, 2046 { 1, 1, charset_1 } 2047 }; 2048 int i; 2049 DWORD size, num; 2050 WORD *vdmx_header; 2051 BYTE *ratio_rec; 2052 char ttf_name[MAX_PATH]; 2053 void *res, *copy; 2054 BOOL ret; 2055 2056 if (!pAddFontResourceExA) 2057 { 2058 win_skip("AddFontResourceExA unavailable\n"); 2059 return; 2060 } 2061 2062 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++) 2063 { 2064 res = get_res_data( "wine_vdmx.ttf", &size ); 2065 2066 copy = HeapAlloc( GetProcessHeap(), 0, size ); 2067 memcpy( copy, res, size ); 2068 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') ); 2069 vdmx_header[0] = GET_BE_WORD( data[i].version ); 2070 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) ); 2071 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) ); 2072 ratio_rec = (BYTE *)&vdmx_header[3]; 2073 ratio_rec[0] = data[i].bCharSet; 2074 2075 write_tmp_file( copy, &size, ttf_name ); 2076 HeapFree( GetProcessHeap(), 0, copy ); 2077 2078 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" ); 2079 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 ); 2080 if (!num) win_skip("Unable to add ttf font resource\n"); 2081 else 2082 { 2083 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" ); 2084 test_height( hdc, data[i].fd ); 2085 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 ); 2086 } 2087 ret = DeleteFileA( ttf_name ); 2088 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED), 2089 "DeleteFile error %d\n", GetLastError()); 2090 } 2091 } 2092 2093 static void test_height_selection(void) 2094 { 2095 static const struct font_data tahoma[] = 2096 { 2097 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE }, 2098 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE }, 2099 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE }, 2100 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE }, 2101 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE }, 2102 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE }, 2103 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE }, 2104 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE }, 2105 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE }, 2106 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE }, 2107 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 } 2108 }; 2109 HDC hdc = CreateCompatibleDC(0); 2110 ok(hdc != NULL, "failed to create hdc\n"); 2111 2112 test_height( hdc, tahoma ); 2113 test_height_selection_vdmx( hdc ); 2114 2115 DeleteDC(hdc); 2116 } 2117 2118 static UINT get_font_fsselection(LOGFONTA *lf) 2119 { 2120 OUTLINETEXTMETRICA *otm; 2121 HFONT hfont, hfont_old; 2122 DWORD ret, otm_size; 2123 UINT fsSelection; 2124 HDC hdc; 2125 2126 hdc = GetDC(0); 2127 hfont = CreateFontIndirectA(lf); 2128 ok(hfont != NULL, "failed to create a font\n"); 2129 2130 hfont_old = SelectObject(hdc, hfont); 2131 2132 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL); 2133 otm = HeapAlloc(GetProcessHeap(), 0, otm_size); 2134 otm->otmSize = sizeof(*otm); 2135 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm); 2136 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError()); 2137 fsSelection = otm->otmfsSelection; 2138 HeapFree(GetProcessHeap(), 0, otm); 2139 SelectObject(hdc, hfont_old); 2140 DeleteObject(hfont); 2141 ReleaseDC(0, hdc); 2142 2143 return fsSelection; 2144 } 2145 2146 static void test_GetOutlineTextMetrics(void) 2147 { 2148 OUTLINETEXTMETRICA *otm; 2149 LOGFONTA lf; 2150 HFONT hfont, hfont_old; 2151 HDC hdc; 2152 DWORD ret, otm_size; 2153 LPSTR unset_ptr; 2154 UINT fsSelection; 2155 2156 /* check fsSelection field with bold simulation */ 2157 memset(&lf, 0, sizeof(lf)); 2158 strcpy(lf.lfFaceName, "Wingdings"); 2159 lf.lfCharSet = SYMBOL_CHARSET; 2160 2161 /* regular face */ 2162 fsSelection = get_font_fsselection(&lf); 2163 ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection); 2164 2165 /* face with bold simulation */ 2166 lf.lfWeight = FW_BOLD; 2167 fsSelection = get_font_fsselection(&lf); 2168 ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection); 2169 2170 /* check fsSelection field with oblique simulation */ 2171 memset(&lf, 0, sizeof(lf)); 2172 strcpy(lf.lfFaceName, "Tahoma"); 2173 lf.lfHeight = -13; 2174 lf.lfWeight = FW_NORMAL; 2175 lf.lfPitchAndFamily = DEFAULT_PITCH; 2176 lf.lfQuality = PROOF_QUALITY; 2177 2178 /* regular face */ 2179 fsSelection = get_font_fsselection(&lf); 2180 ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection); 2181 2182 lf.lfItalic = 1; 2183 /* face with oblique simulation */ 2184 fsSelection = get_font_fsselection(&lf); 2185 ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection); 2186 2187 if (!is_font_installed("Arial")) 2188 { 2189 skip("Arial is not installed\n"); 2190 return; 2191 } 2192 2193 hdc = GetDC(0); 2194 2195 memset(&lf, 0, sizeof(lf)); 2196 strcpy(lf.lfFaceName, "Arial"); 2197 lf.lfHeight = -13; 2198 lf.lfWeight = FW_NORMAL; 2199 lf.lfPitchAndFamily = DEFAULT_PITCH; 2200 lf.lfQuality = PROOF_QUALITY; 2201 hfont = CreateFontIndirectA(&lf); 2202 ok(hfont != NULL, "failed to create a font\n"); 2203 2204 hfont_old = SelectObject(hdc, hfont); 2205 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL); 2206 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size); 2207 2208 otm = HeapAlloc(GetProcessHeap(), 0, otm_size); 2209 2210 memset(otm, 0xAA, otm_size); 2211 SetLastError(0xdeadbeef); 2212 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */ 2213 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm); 2214 ok(ret == 1 /* Win9x */ || 2215 ret == otm->otmSize /* XP*/, 2216 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError()); 2217 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */ 2218 { 2219 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName); 2220 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName); 2221 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName); 2222 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName); 2223 } 2224 2225 memset(otm, 0xAA, otm_size); 2226 SetLastError(0xdeadbeef); 2227 otm->otmSize = otm_size; /* just in case for Win9x compatibility */ 2228 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm); 2229 ok(ret == 1 /* Win9x */ || 2230 ret == otm->otmSize /* XP*/, 2231 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError()); 2232 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */ 2233 { 2234 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName); 2235 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName); 2236 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName); 2237 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName); 2238 } 2239 2240 /* ask about truncated data */ 2241 memset(otm, 0xAA, otm_size); 2242 memset(&unset_ptr, 0xAA, sizeof(unset_ptr)); 2243 SetLastError(0xdeadbeef); 2244 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */ 2245 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm); 2246 ok(ret == 1 /* Win9x */ || 2247 ret == otm->otmSize /* XP*/, 2248 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError()); 2249 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */ 2250 { 2251 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName); 2252 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName); 2253 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName); 2254 } 2255 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName); 2256 2257 /* check handling of NULL pointer */ 2258 SetLastError(0xdeadbeef); 2259 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL); 2260 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError()); 2261 2262 HeapFree(GetProcessHeap(), 0, otm); 2263 2264 SelectObject(hdc, hfont_old); 2265 DeleteObject(hfont); 2266 2267 ReleaseDC(0, hdc); 2268 } 2269 2270 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea) 2271 { 2272 INT y, 2273 breakCount, 2274 areaWidth = clientArea->right - clientArea->left, 2275 nErrors = 0, e; 2276 const char *pFirstChar, *pLastChar; 2277 SIZE size; 2278 TEXTMETRICA tm; 2279 struct err 2280 { 2281 const char *start; 2282 int len; 2283 int GetTextExtentExPointWWidth; 2284 } error[20]; 2285 2286 GetTextMetricsA(hdc, &tm); 2287 y = clientArea->top; 2288 do { 2289 breakCount = 0; 2290 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */ 2291 pFirstChar = str; 2292 2293 do { 2294 pLastChar = str; 2295 2296 /* if not at the end of the string, ... */ 2297 if (*str == '\0') break; 2298 /* ... add the next word to the current extent */ 2299 while (*str != '\0' && *str++ != tm.tmBreakChar); 2300 breakCount++; 2301 SetTextJustification(hdc, 0, 0); 2302 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size); 2303 } while ((int) size.cx < areaWidth); 2304 2305 /* ignore trailing break chars */ 2306 breakCount--; 2307 while (*(pLastChar - 1) == tm.tmBreakChar) 2308 { 2309 pLastChar--; 2310 breakCount--; 2311 } 2312 2313 if (*str == '\0' || breakCount <= 0) pLastChar = str; 2314 2315 SetTextJustification(hdc, 0, 0); 2316 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size); 2317 2318 /* do not justify the last extent */ 2319 if (*str != '\0' && breakCount > 0) 2320 { 2321 SetTextJustification(hdc, areaWidth - size.cx, breakCount); 2322 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size); 2323 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1) 2324 { 2325 error[nErrors].start = pFirstChar; 2326 error[nErrors].len = pLastChar - pFirstChar; 2327 error[nErrors].GetTextExtentExPointWWidth = size.cx; 2328 nErrors++; 2329 } 2330 } 2331 2332 y += size.cy; 2333 str = pLastChar; 2334 } while (*str && y < clientArea->bottom); 2335 2336 for (e = 0; e < nErrors; e++) 2337 { 2338 /* The width returned by GetTextExtentPoint32() is exactly the same 2339 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */ 2340 ok(error[e].GetTextExtentExPointWWidth == areaWidth, 2341 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n", 2342 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth); 2343 } 2344 } 2345 2346 static void test_SetTextJustification(void) 2347 { 2348 HDC hdc; 2349 RECT clientArea; 2350 LOGFONTA lf; 2351 HFONT hfont; 2352 HWND hwnd; 2353 SIZE size, expect; 2354 int i; 2355 WORD indices[2]; 2356 static const char testText[] = 2357 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " 2358 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " 2359 "enim ad minim veniam, quis nostrud exercitation ullamco laboris " 2360 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in " 2361 "reprehenderit in voluptate velit esse cillum dolore eu fugiat " 2362 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, " 2363 "sunt in culpa qui officia deserunt mollit anim id est laborum."; 2364 2365 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL); 2366 GetClientRect( hwnd, &clientArea ); 2367 hdc = GetDC( hwnd ); 2368 2369 if (!is_font_installed("Times New Roman")) 2370 { 2371 skip("Times New Roman is not installed\n"); 2372 return; 2373 } 2374 2375 memset(&lf, 0, sizeof lf); 2376 lf.lfCharSet = ANSI_CHARSET; 2377 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 2378 lf.lfWeight = FW_DONTCARE; 2379 lf.lfHeight = 20; 2380 lf.lfQuality = DEFAULT_QUALITY; 2381 lstrcpyA(lf.lfFaceName, "Times New Roman"); 2382 hfont = create_font("Times New Roman", &lf); 2383 SelectObject(hdc, hfont); 2384 2385 testJustification(hdc, testText, &clientArea); 2386 2387 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done; 2388 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 ); 2389 2390 SetTextJustification(hdc, 0, 0); 2391 GetTextExtentPoint32A(hdc, " ", 1, &expect); 2392 GetTextExtentPoint32A(hdc, " ", 3, &size); 2393 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx ); 2394 SetTextJustification(hdc, 4, 1); 2395 GetTextExtentPoint32A(hdc, " ", 1, &size); 2396 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx ); 2397 SetTextJustification(hdc, 9, 2); 2398 GetTextExtentPoint32A(hdc, " ", 2, &size); 2399 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx ); 2400 SetTextJustification(hdc, 7, 3); 2401 GetTextExtentPoint32A(hdc, " ", 3, &size); 2402 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx ); 2403 SetTextJustification(hdc, 7, 3); 2404 SetTextCharacterExtra(hdc, 2 ); 2405 GetTextExtentPoint32A(hdc, " ", 3, &size); 2406 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx ); 2407 SetTextJustification(hdc, 0, 0); 2408 SetTextCharacterExtra(hdc, 0); 2409 size.cx = size.cy = 1234; 2410 GetTextExtentPoint32A(hdc, " ", 0, &size); 2411 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy ); 2412 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect); 2413 SetTextJustification(hdc, 5, 1); 2414 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size); 2415 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx ); 2416 SetTextJustification(hdc, 0, 0); 2417 2418 SetMapMode( hdc, MM_ANISOTROPIC ); 2419 SetWindowExtEx( hdc, 2, 2, NULL ); 2420 GetClientRect( hwnd, &clientArea ); 2421 DPtoLP( hdc, (POINT *)&clientArea, 2 ); 2422 testJustification(hdc, testText, &clientArea); 2423 2424 GetTextExtentPoint32A(hdc, "A", 1, &expect); 2425 for (i = 0; i < 10; i++) 2426 { 2427 SetTextCharacterExtra(hdc, i); 2428 GetTextExtentPoint32A(hdc, "A", 1, &size); 2429 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i ); 2430 } 2431 SetTextCharacterExtra(hdc, 0); 2432 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect); 2433 for (i = 0; i < 10; i++) 2434 { 2435 SetTextCharacterExtra(hdc, i); 2436 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size); 2437 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i ); 2438 } 2439 SetTextCharacterExtra(hdc, 0); 2440 2441 SetViewportExtEx( hdc, 3, 3, NULL ); 2442 GetClientRect( hwnd, &clientArea ); 2443 DPtoLP( hdc, (POINT *)&clientArea, 2 ); 2444 testJustification(hdc, testText, &clientArea); 2445 2446 GetTextExtentPoint32A(hdc, "A", 1, &expect); 2447 for (i = 0; i < 10; i++) 2448 { 2449 SetTextCharacterExtra(hdc, i); 2450 GetTextExtentPoint32A(hdc, "A", 1, &size); 2451 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i ); 2452 } 2453 2454 done: 2455 DeleteObject(hfont); 2456 ReleaseDC(hwnd, hdc); 2457 DestroyWindow(hwnd); 2458 } 2459 2460 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode) 2461 { 2462 HDC hdc; 2463 LOGFONTA lf; 2464 HFONT hfont, hfont_old; 2465 CHARSETINFO csi; 2466 FONTSIGNATURE fs; 2467 INT cs; 2468 DWORD i, ret; 2469 char name[64]; 2470 2471 assert(count <= 128); 2472 2473 memset(&lf, 0, sizeof(lf)); 2474 2475 lf.lfCharSet = charset; 2476 lf.lfHeight = 10; 2477 lstrcpyA(lf.lfFaceName, "Arial"); 2478 SetLastError(0xdeadbeef); 2479 hfont = CreateFontIndirectA(&lf); 2480 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); 2481 2482 hdc = GetDC(0); 2483 hfont_old = SelectObject(hdc, hfont); 2484 2485 cs = GetTextCharsetInfo(hdc, &fs, 0); 2486 ok(cs == charset, "expected %d, got %d\n", charset, cs); 2487 2488 SetLastError(0xdeadbeef); 2489 ret = GetTextFaceA(hdc, sizeof(name), name); 2490 ok(ret, "GetTextFaceA error %u\n", GetLastError()); 2491 2492 if (charset == SYMBOL_CHARSET) 2493 { 2494 ok(strcmp("Arial", name), "face name should NOT be Arial\n"); 2495 ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n"); 2496 } 2497 else 2498 { 2499 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name); 2500 ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n"); 2501 } 2502 2503 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET)) 2504 { 2505 trace("Can't find codepage for charset %d\n", cs); 2506 ReleaseDC(0, hdc); 2507 return FALSE; 2508 } 2509 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP); 2510 2511 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page) 2512 { 2513 skip("Font code page %d, looking for code page %d\n", 2514 pGdiGetCodePage(hdc), code_page); 2515 ReleaseDC(0, hdc); 2516 return FALSE; 2517 } 2518 2519 if (unicode) 2520 { 2521 char ansi_buf[128]; 2522 WCHAR unicode_buf[128]; 2523 2524 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128); 2525 2526 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count); 2527 2528 SetLastError(0xdeadbeef); 2529 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0); 2530 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n", 2531 count, ret, GetLastError()); 2532 } 2533 else 2534 { 2535 char ansi_buf[128]; 2536 2537 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128); 2538 2539 SetLastError(0xdeadbeef); 2540 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0); 2541 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n", 2542 count, ret, GetLastError()); 2543 } 2544 2545 SelectObject(hdc, hfont_old); 2546 DeleteObject(hfont); 2547 2548 ReleaseDC(0, hdc); 2549 2550 return TRUE; 2551 } 2552 2553 static void test_font_charset(void) 2554 { 2555 static struct charset_data 2556 { 2557 INT charset; 2558 UINT code_page; 2559 WORD font_idxA[128], font_idxW[128]; 2560 } cd[] = 2561 { 2562 { ANSI_CHARSET, 1252 }, 2563 { RUSSIAN_CHARSET, 1251 }, 2564 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */ 2565 }; 2566 int i; 2567 2568 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW) 2569 { 2570 win_skip("Skipping the font charset test on a Win9x platform\n"); 2571 return; 2572 } 2573 2574 if (!is_font_installed("Arial")) 2575 { 2576 skip("Arial is not installed\n"); 2577 return; 2578 } 2579 2580 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++) 2581 { 2582 if (cd[i].charset == SYMBOL_CHARSET) 2583 { 2584 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings")) 2585 { 2586 skip("Symbol or Wingdings is not installed\n"); 2587 break; 2588 } 2589 } 2590 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) && 2591 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE)) 2592 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i); 2593 } 2594 2595 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n"); 2596 if (i > 2) 2597 { 2598 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n"); 2599 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n"); 2600 } 2601 else 2602 skip("Symbol or Wingdings is not installed\n"); 2603 } 2604 2605 static void test_GdiGetCodePage(void) 2606 { 2607 static const struct _matching_data 2608 { 2609 UINT current_codepage; 2610 LPCSTR lfFaceName; 2611 UCHAR lfCharSet; 2612 UINT expected_codepage; 2613 } matching_data[] = { 2614 {1251, "Arial", ANSI_CHARSET, 1252}, 2615 {1251, "Tahoma", ANSI_CHARSET, 1252}, 2616 2617 {1252, "Arial", ANSI_CHARSET, 1252}, 2618 {1252, "Tahoma", ANSI_CHARSET, 1252}, 2619 2620 {1253, "Arial", ANSI_CHARSET, 1252}, 2621 {1253, "Tahoma", ANSI_CHARSET, 1252}, 2622 2623 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */ 2624 { 932, "Tahoma", ANSI_CHARSET, 1252}, 2625 { 932, "MS UI Gothic", ANSI_CHARSET, 1252}, 2626 2627 { 936, "Arial", ANSI_CHARSET, 936}, 2628 { 936, "Tahoma", ANSI_CHARSET, 936}, 2629 { 936, "Simsun", ANSI_CHARSET, 936}, 2630 2631 { 949, "Arial", ANSI_CHARSET, 949}, 2632 { 949, "Tahoma", ANSI_CHARSET, 949}, 2633 { 949, "Gulim", ANSI_CHARSET, 949}, 2634 2635 { 950, "Arial", ANSI_CHARSET, 950}, 2636 { 950, "Tahoma", ANSI_CHARSET, 950}, 2637 { 950, "PMingLiU", ANSI_CHARSET, 950}, 2638 }; 2639 HDC hdc; 2640 LOGFONTA lf; 2641 HFONT hfont; 2642 UINT charset, acp; 2643 DWORD codepage; 2644 int i; 2645 2646 if (!pGdiGetCodePage) 2647 { 2648 skip("GdiGetCodePage not available on this platform\n"); 2649 return; 2650 } 2651 2652 acp = GetACP(); 2653 2654 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++) 2655 { 2656 /* only test data matched current locale codepage */ 2657 if (matching_data[i].current_codepage != acp) 2658 continue; 2659 2660 if (!is_font_installed(matching_data[i].lfFaceName)) 2661 { 2662 skip("%s is not installed\n", matching_data[i].lfFaceName); 2663 continue; 2664 } 2665 2666 hdc = GetDC(0); 2667 2668 memset(&lf, 0, sizeof(lf)); 2669 lf.lfHeight = -16; 2670 lf.lfCharSet = matching_data[i].lfCharSet; 2671 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName); 2672 hfont = CreateFontIndirectA(&lf); 2673 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); 2674 2675 hfont = SelectObject(hdc, hfont); 2676 charset = GetTextCharset(hdc); 2677 codepage = pGdiGetCodePage(hdc); 2678 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n", 2679 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage); 2680 ok(codepage == matching_data[i].expected_codepage, 2681 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage); 2682 2683 hfont = SelectObject(hdc, hfont); 2684 DeleteObject(hfont); 2685 2686 /* CLIP_DFA_DISABLE turns off the font association */ 2687 lf.lfClipPrecision = CLIP_DFA_DISABLE; 2688 hfont = CreateFontIndirectA(&lf); 2689 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); 2690 2691 hfont = SelectObject(hdc, hfont); 2692 charset = GetTextCharset(hdc); 2693 codepage = pGdiGetCodePage(hdc); 2694 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n", 2695 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage); 2696 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage); 2697 2698 hfont = SelectObject(hdc, hfont); 2699 DeleteObject(hfont); 2700 2701 ReleaseDC(NULL, hdc); 2702 } 2703 } 2704 2705 static void test_GetFontUnicodeRanges(void) 2706 { 2707 LOGFONTA lf; 2708 HDC hdc; 2709 HFONT hfont, hfont_old; 2710 DWORD size; 2711 GLYPHSET *gs; 2712 DWORD i; 2713 2714 if (!pGetFontUnicodeRanges) 2715 { 2716 win_skip("GetFontUnicodeRanges not available before W2K\n"); 2717 return; 2718 } 2719 2720 memset(&lf, 0, sizeof(lf)); 2721 lstrcpyA(lf.lfFaceName, "Arial"); 2722 hfont = create_font("Arial", &lf); 2723 2724 hdc = GetDC(0); 2725 hfont_old = SelectObject(hdc, hfont); 2726 2727 size = pGetFontUnicodeRanges(NULL, NULL); 2728 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n"); 2729 2730 size = pGetFontUnicodeRanges(hdc, NULL); 2731 ok(size, "GetFontUnicodeRanges failed unexpectedly\n"); 2732 2733 gs = HeapAlloc(GetProcessHeap(), 0, size); 2734 2735 size = pGetFontUnicodeRanges(hdc, gs); 2736 ok(size, "GetFontUnicodeRanges failed\n"); 2737 2738 if (0) /* Disabled to limit console spam */ 2739 for (i = 0; i < gs->cRanges; i++) 2740 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs); 2741 trace("found %u ranges\n", gs->cRanges); 2742 2743 HeapFree(GetProcessHeap(), 0, gs); 2744 2745 SelectObject(hdc, hfont_old); 2746 DeleteObject(hfont); 2747 ReleaseDC(NULL, hdc); 2748 } 2749 2750 struct enum_font_data 2751 { 2752 int total, size; 2753 LOGFONTA *lf; 2754 }; 2755 2756 struct enum_fullname_data 2757 { 2758 int total, size; 2759 ENUMLOGFONTA *elf; 2760 }; 2761 2762 struct enum_font_dataW 2763 { 2764 int total, size; 2765 LOGFONTW *lf; 2766 }; 2767 2768 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam) 2769 { 2770 struct enum_font_data *efd = (struct enum_font_data *)lParam; 2771 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm; 2772 2773 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight); 2774 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight); 2775 2776 if (type != TRUETYPE_FONTTYPE) return 1; 2777 2778 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM); 2779 2780 if (0) /* Disabled to limit console spam */ 2781 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n", 2782 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic); 2783 if (efd->total >= efd->size) 2784 { 2785 efd->size = max( (efd->total + 1) * 2, 256 ); 2786 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) ); 2787 if (!efd->lf) return 0; 2788 } 2789 efd->lf[efd->total++] = *lf; 2790 2791 return 1; 2792 } 2793 2794 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam) 2795 { 2796 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam; 2797 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm; 2798 2799 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight); 2800 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight); 2801 2802 if (type != TRUETYPE_FONTTYPE) return 1; 2803 2804 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM); 2805 2806 if (0) /* Disabled to limit console spam */ 2807 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n", 2808 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic); 2809 if (efd->total >= efd->size) 2810 { 2811 efd->size = max( (efd->total + 1) * 2, 256 ); 2812 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) ); 2813 if (!efd->lf) return 0; 2814 } 2815 efd->lf[efd->total++] = *lf; 2816 2817 return 1; 2818 } 2819 2820 static void get_charset_stats(struct enum_font_data *efd, 2821 int *ansi_charset, int *symbol_charset, 2822 int *russian_charset) 2823 { 2824 int i; 2825 2826 *ansi_charset = 0; 2827 *symbol_charset = 0; 2828 *russian_charset = 0; 2829 2830 for (i = 0; i < efd->total; i++) 2831 { 2832 switch (efd->lf[i].lfCharSet) 2833 { 2834 case ANSI_CHARSET: 2835 (*ansi_charset)++; 2836 break; 2837 case SYMBOL_CHARSET: 2838 (*symbol_charset)++; 2839 break; 2840 case RUSSIAN_CHARSET: 2841 (*russian_charset)++; 2842 break; 2843 } 2844 } 2845 } 2846 2847 static void get_charset_statsW(struct enum_font_dataW *efd, 2848 int *ansi_charset, int *symbol_charset, 2849 int *russian_charset) 2850 { 2851 int i; 2852 2853 *ansi_charset = 0; 2854 *symbol_charset = 0; 2855 *russian_charset = 0; 2856 2857 for (i = 0; i < efd->total; i++) 2858 { 2859 switch (efd->lf[i].lfCharSet) 2860 { 2861 case ANSI_CHARSET: 2862 (*ansi_charset)++; 2863 break; 2864 case SYMBOL_CHARSET: 2865 (*symbol_charset)++; 2866 break; 2867 case RUSSIAN_CHARSET: 2868 (*russian_charset)++; 2869 break; 2870 } 2871 } 2872 } 2873 2874 static void test_EnumFontFamilies(const char *font_name, INT font_charset) 2875 { 2876 struct enum_font_data efd; 2877 struct enum_font_dataW efdw; 2878 LOGFONTA lf; 2879 HDC hdc; 2880 int i, ret, ansi_charset, symbol_charset, russian_charset; 2881 2882 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset); 2883 2884 if (*font_name && !is_truetype_font_installed(font_name)) 2885 { 2886 skip("%s is not installed\n", font_name); 2887 return; 2888 } 2889 memset( &efd, 0, sizeof(efd) ); 2890 memset( &efdw, 0, sizeof(efdw) ); 2891 2892 hdc = GetDC(0); 2893 2894 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr" 2895 * while EnumFontFamiliesEx doesn't. 2896 */ 2897 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */ 2898 { 2899 /* 2900 * Use EnumFontFamiliesW since win98 crashes when the 2901 * second parameter is NULL using EnumFontFamilies 2902 */ 2903 efdw.total = 0; 2904 SetLastError(0xdeadbeef); 2905 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw); 2906 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError()); 2907 if(ret) 2908 { 2909 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset); 2910 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n", 2911 ansi_charset, symbol_charset, russian_charset); 2912 ok(efdw.total > 0, "fonts enumerated: NULL\n"); 2913 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n"); 2914 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n"); 2915 ok(russian_charset > 0 || 2916 broken(russian_charset == 0), /* NT4 */ 2917 "NULL family should enumerate RUSSIAN_CHARSET\n"); 2918 } 2919 2920 efdw.total = 0; 2921 SetLastError(0xdeadbeef); 2922 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0); 2923 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError()); 2924 if(ret) 2925 { 2926 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset); 2927 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n", 2928 ansi_charset, symbol_charset, russian_charset); 2929 ok(efdw.total > 0, "fonts enumerated: NULL\n"); 2930 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n"); 2931 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n"); 2932 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n"); 2933 } 2934 } 2935 2936 efd.total = 0; 2937 SetLastError(0xdeadbeef); 2938 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd); 2939 ok(ret, "EnumFontFamilies error %u\n", GetLastError()); 2940 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset); 2941 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n", 2942 ansi_charset, symbol_charset, russian_charset, 2943 *font_name ? font_name : "<empty>"); 2944 if (*font_name) 2945 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name); 2946 else 2947 ok(!efd.total, "no fonts should be enumerated for empty font_name\n"); 2948 for (i = 0; i < efd.total; i++) 2949 { 2950 /* FIXME: remove completely once Wine is fixed */ 2951 todo_wine_if(efd.lf[i].lfCharSet != font_charset) 2952 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet); 2953 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n", 2954 font_name, efd.lf[i].lfFaceName); 2955 } 2956 2957 memset(&lf, 0, sizeof(lf)); 2958 lf.lfCharSet = ANSI_CHARSET; 2959 strcpy(lf.lfFaceName, font_name); 2960 efd.total = 0; 2961 SetLastError(0xdeadbeef); 2962 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0); 2963 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError()); 2964 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset); 2965 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n", 2966 ansi_charset, symbol_charset, russian_charset, 2967 *font_name ? font_name : "<empty>"); 2968 if (font_charset == SYMBOL_CHARSET) 2969 { 2970 if (*font_name) 2971 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name); 2972 else 2973 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name); 2974 } 2975 else 2976 { 2977 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name); 2978 for (i = 0; i < efd.total; i++) 2979 { 2980 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet); 2981 if (*font_name) 2982 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n", 2983 font_name, efd.lf[i].lfFaceName); 2984 } 2985 } 2986 2987 /* DEFAULT_CHARSET should enumerate all available charsets */ 2988 memset(&lf, 0, sizeof(lf)); 2989 lf.lfCharSet = DEFAULT_CHARSET; 2990 strcpy(lf.lfFaceName, font_name); 2991 efd.total = 0; 2992 SetLastError(0xdeadbeef); 2993 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0); 2994 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError()); 2995 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset); 2996 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n", 2997 ansi_charset, symbol_charset, russian_charset, 2998 *font_name ? font_name : "<empty>"); 2999 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name); 3000 for (i = 0; i < efd.total; i++) 3001 { 3002 if (*font_name) 3003 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n", 3004 font_name, efd.lf[i].lfFaceName); 3005 } 3006 if (*font_name) 3007 { 3008 switch (font_charset) 3009 { 3010 case ANSI_CHARSET: 3011 ok(ansi_charset > 0, 3012 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name); 3013 ok(!symbol_charset, 3014 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name); 3015 ok(russian_charset > 0, 3016 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name); 3017 break; 3018 case SYMBOL_CHARSET: 3019 ok(!ansi_charset, 3020 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name); 3021 ok(symbol_charset, 3022 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name); 3023 ok(!russian_charset, 3024 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name); 3025 break; 3026 case DEFAULT_CHARSET: 3027 ok(ansi_charset > 0, 3028 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name); 3029 ok(symbol_charset > 0, 3030 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name); 3031 ok(russian_charset > 0, 3032 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name); 3033 break; 3034 } 3035 } 3036 else 3037 { 3038 ok(ansi_charset > 0, 3039 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>"); 3040 ok(symbol_charset > 0, 3041 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>"); 3042 ok(russian_charset > 0, 3043 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>"); 3044 } 3045 3046 memset(&lf, 0, sizeof(lf)); 3047 lf.lfCharSet = SYMBOL_CHARSET; 3048 strcpy(lf.lfFaceName, font_name); 3049 efd.total = 0; 3050 SetLastError(0xdeadbeef); 3051 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0); 3052 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError()); 3053 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset); 3054 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n", 3055 ansi_charset, symbol_charset, russian_charset, 3056 *font_name ? font_name : "<empty>"); 3057 if (*font_name && font_charset == ANSI_CHARSET) 3058 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name); 3059 else 3060 { 3061 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name); 3062 for (i = 0; i < efd.total; i++) 3063 { 3064 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet); 3065 if (*font_name) 3066 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n", 3067 font_name, efd.lf[i].lfFaceName); 3068 } 3069 3070 ok(!ansi_charset, 3071 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>"); 3072 ok(symbol_charset > 0, 3073 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>"); 3074 ok(!russian_charset, 3075 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>"); 3076 } 3077 3078 ReleaseDC(0, hdc); 3079 3080 heap_free( efd.lf ); 3081 heap_free( efdw.lf ); 3082 } 3083 3084 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam) 3085 { 3086 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm; 3087 LOGFONTA *target = (LOGFONTA *)lParam; 3088 const DWORD valid_bits = 0x003f01ff; 3089 CHARSETINFO csi; 3090 DWORD fs; 3091 3092 if (type != TRUETYPE_FONTTYPE) return TRUE; 3093 3094 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) { 3095 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits; 3096 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) { 3097 *target = *lf; 3098 return FALSE; 3099 } 3100 } 3101 3102 return TRUE; 3103 } 3104 3105 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 3106 { 3107 struct enum_font_data *efd = (struct enum_font_data *)lParam; 3108 3109 if (type != TRUETYPE_FONTTYPE) return 1; 3110 3111 if (efd->total >= efd->size) 3112 { 3113 efd->size = max( (efd->total + 1) * 2, 256 ); 3114 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) ); 3115 if (!efd->lf) return 0; 3116 } 3117 efd->lf[efd->total++] = *lf; 3118 3119 return 1; 3120 } 3121 3122 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 3123 { 3124 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam; 3125 3126 if (type != TRUETYPE_FONTTYPE) return 1; 3127 3128 if (efnd->total >= efnd->size) 3129 { 3130 efnd->size = max( (efnd->total + 1) * 2, 256 ); 3131 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) ); 3132 if (!efnd->elf) return 0; 3133 } 3134 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf; 3135 3136 return 1; 3137 } 3138 3139 static void test_EnumFontFamiliesEx_default_charset(void) 3140 { 3141 struct enum_font_data efd; 3142 LOGFONTA target, enum_font; 3143 UINT acp; 3144 HDC hdc; 3145 CHARSETINFO csi; 3146 3147 acp = GetACP(); 3148 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) { 3149 skip("TranslateCharsetInfo failed for code page %u.\n", acp); 3150 return; 3151 } 3152 3153 hdc = GetDC(0); 3154 memset(&enum_font, 0, sizeof(enum_font)); 3155 enum_font.lfCharSet = csi.ciCharset; 3156 target.lfFaceName[0] = '\0'; 3157 target.lfCharSet = csi.ciCharset; 3158 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0); 3159 if (target.lfFaceName[0] == '\0') { 3160 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet); 3161 return; 3162 } 3163 if (acp == 874 || acp == 1255 || acp == 1256) { 3164 /* these codepage use complex script, expecting ANSI_CHARSET here. */ 3165 target.lfCharSet = ANSI_CHARSET; 3166 } 3167 3168 memset(&efd, 0, sizeof(efd)); 3169 memset(&enum_font, 0, sizeof(enum_font)); 3170 strcpy(enum_font.lfFaceName, target.lfFaceName); 3171 enum_font.lfCharSet = DEFAULT_CHARSET; 3172 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0); 3173 ReleaseDC(0, hdc); 3174 3175 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total); 3176 if (efd.total < 2) 3177 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total); 3178 else 3179 ok(efd.lf[0].lfCharSet == target.lfCharSet, 3180 "(%s) got charset %d expected %d\n", 3181 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet); 3182 3183 heap_free(efd.lf); 3184 return; 3185 } 3186 3187 static void test_negative_width(HDC hdc, const LOGFONTA *lf) 3188 { 3189 HFONT hfont, hfont_prev; 3190 DWORD ret; 3191 GLYPHMETRICS gm1, gm2; 3192 LOGFONTA lf2 = *lf; 3193 WORD idx; 3194 3195 if(!pGetGlyphIndicesA) 3196 return; 3197 3198 /* negative widths are handled just as positive ones */ 3199 lf2.lfWidth = -lf->lfWidth; 3200 3201 SetLastError(0xdeadbeef); 3202 hfont = CreateFontIndirectA(lf); 3203 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError()); 3204 check_font("original", lf, hfont); 3205 3206 hfont_prev = SelectObject(hdc, hfont); 3207 3208 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS); 3209 if (ret == GDI_ERROR || idx == 0xffff) 3210 { 3211 SelectObject(hdc, hfont_prev); 3212 DeleteObject(hfont); 3213 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName); 3214 return; 3215 } 3216 3217 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */ 3218 memset(&gm1, 0xab, sizeof(gm1)); 3219 SetLastError(0xdeadbeef); 3220 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat); 3221 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError()); 3222 3223 SelectObject(hdc, hfont_prev); 3224 DeleteObject(hfont); 3225 3226 SetLastError(0xdeadbeef); 3227 hfont = CreateFontIndirectA(&lf2); 3228 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError()); 3229 check_font("negative width", &lf2, hfont); 3230 3231 hfont_prev = SelectObject(hdc, hfont); 3232 3233 memset(&gm2, 0xbb, sizeof(gm2)); 3234 SetLastError(0xdeadbeef); 3235 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat); 3236 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError()); 3237 3238 SelectObject(hdc, hfont_prev); 3239 DeleteObject(hfont); 3240 3241 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX && 3242 gm1.gmBlackBoxY == gm2.gmBlackBoxY && 3243 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x && 3244 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y && 3245 gm1.gmCellIncX == gm2.gmCellIncX && 3246 gm1.gmCellIncY == gm2.gmCellIncY, 3247 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n", 3248 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x, 3249 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY, 3250 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x, 3251 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY); 3252 } 3253 3254 /* PANOSE is 10 bytes in size, need to pack the structure properly */ 3255 #include "pshpack2.h" 3256 typedef struct 3257 { 3258 USHORT version; 3259 SHORT xAvgCharWidth; 3260 USHORT usWeightClass; 3261 USHORT usWidthClass; 3262 SHORT fsType; 3263 SHORT ySubscriptXSize; 3264 SHORT ySubscriptYSize; 3265 SHORT ySubscriptXOffset; 3266 SHORT ySubscriptYOffset; 3267 SHORT ySuperscriptXSize; 3268 SHORT ySuperscriptYSize; 3269 SHORT ySuperscriptXOffset; 3270 SHORT ySuperscriptYOffset; 3271 SHORT yStrikeoutSize; 3272 SHORT yStrikeoutPosition; 3273 SHORT sFamilyClass; 3274 PANOSE panose; 3275 ULONG ulUnicodeRange1; 3276 ULONG ulUnicodeRange2; 3277 ULONG ulUnicodeRange3; 3278 ULONG ulUnicodeRange4; 3279 CHAR achVendID[4]; 3280 USHORT fsSelection; 3281 USHORT usFirstCharIndex; 3282 USHORT usLastCharIndex; 3283 /* According to the Apple spec, original version didn't have the below fields, 3284 * version numbers were taken from the OpenType spec. 3285 */ 3286 /* version 0 (TrueType 1.5) */ 3287 USHORT sTypoAscender; 3288 USHORT sTypoDescender; 3289 USHORT sTypoLineGap; 3290 USHORT usWinAscent; 3291 USHORT usWinDescent; 3292 /* version 1 (TrueType 1.66) */ 3293 ULONG ulCodePageRange1; 3294 ULONG ulCodePageRange2; 3295 /* version 2 (OpenType 1.2) */ 3296 SHORT sxHeight; 3297 SHORT sCapHeight; 3298 USHORT usDefaultChar; 3299 USHORT usBreakChar; 3300 USHORT usMaxContext; 3301 /* version 4 (OpenType 1.6) */ 3302 USHORT usLowerOpticalPointSize; 3303 USHORT usUpperOpticalPointSize; 3304 } TT_OS2_V4; 3305 #include "poppack.h" 3306 3307 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1)) 3308 3309 typedef struct 3310 { 3311 USHORT version; 3312 USHORT num_tables; 3313 } cmap_header; 3314 3315 typedef struct 3316 { 3317 USHORT plat_id; 3318 USHORT enc_id; 3319 ULONG offset; 3320 } cmap_encoding_record; 3321 3322 typedef struct 3323 { 3324 USHORT format; 3325 USHORT length; 3326 USHORT language; 3327 3328 BYTE glyph_ids[256]; 3329 } cmap_format_0; 3330 3331 typedef struct 3332 { 3333 USHORT format; 3334 USHORT length; 3335 USHORT language; 3336 3337 USHORT seg_countx2; 3338 USHORT search_range; 3339 USHORT entry_selector; 3340 USHORT range_shift; 3341 3342 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */ 3343 /* Then follows: 3344 USHORT pad; 3345 USHORT start_count[seg_countx2 / 2]; 3346 USHORT id_delta[seg_countx2 / 2]; 3347 USHORT id_range_offset[seg_countx2 / 2]; 3348 USHORT glyph_ids[]; 3349 */ 3350 } cmap_format_4; 3351 3352 typedef struct 3353 { 3354 USHORT end_count; 3355 USHORT start_count; 3356 USHORT id_delta; 3357 USHORT id_range_offset; 3358 } cmap_format_4_seg; 3359 3360 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V4 *os2, WORD family, const char *name) 3361 { 3362 ok((tmA->tmPitchAndFamily & 0xf0) == family || 3363 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH), 3364 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n", 3365 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle, 3366 os2->panose.bWeight, os2->panose.bProportion); 3367 } 3368 3369 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last) 3370 { 3371 int i; 3372 cmap_format_0 *cmap = (cmap_format_0*)ptr; 3373 3374 *first = 256; 3375 3376 for(i = 0; i < 256; i++) 3377 { 3378 if(cmap->glyph_ids[i] == 0) continue; 3379 *last = i; 3380 if(*first == 256) *first = i; 3381 } 3382 if(*first == 256) return FALSE; 3383 return TRUE; 3384 } 3385 3386 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg) 3387 { 3388 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2; 3389 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]); 3390 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]); 3391 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]); 3392 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]); 3393 } 3394 3395 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit) 3396 { 3397 int i; 3398 cmap_format_4 *cmap = (cmap_format_4*)ptr; 3399 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2; 3400 3401 *first = 0x10000; 3402 3403 for(i = 0; i < seg_count; i++) 3404 { 3405 cmap_format_4_seg seg; 3406 3407 get_seg4(cmap, i, &seg); 3408 3409 if(seg.start_count > 0xfffe) break; 3410 3411 if(*first == 0x10000) *first = seg.start_count; 3412 3413 *last = min(seg.end_count, 0xfffe); 3414 } 3415 3416 if(*first == 0x10000) return FALSE; 3417 return TRUE; 3418 } 3419 3420 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id) 3421 { 3422 USHORT i; 3423 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1); 3424 3425 for(i = 0; i < GET_BE_WORD(header->num_tables); i++) 3426 { 3427 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id) 3428 return (BYTE *)header + GET_BE_DWORD(record->offset); 3429 record++; 3430 } 3431 return NULL; 3432 } 3433 3434 typedef enum 3435 { 3436 cmap_none, 3437 cmap_ms_unicode, 3438 cmap_ms_symbol 3439 } cmap_type; 3440 3441 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type) 3442 { 3443 LONG size, ret; 3444 cmap_header *header; 3445 void *cmap; 3446 BOOL r = FALSE; 3447 WORD format; 3448 3449 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0); 3450 ok(size != GDI_ERROR, "no cmap table found\n"); 3451 if(size == GDI_ERROR) return FALSE; 3452 3453 header = HeapAlloc(GetProcessHeap(), 0, size); 3454 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size); 3455 ok(ret == size, "GetFontData should return %u not %u\n", size, ret); 3456 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version)); 3457 3458 cmap = get_cmap(header, 3, 1); 3459 if(cmap) 3460 *cmap_type = cmap_ms_unicode; 3461 else 3462 { 3463 cmap = get_cmap(header, 3, 0); 3464 if(cmap) *cmap_type = cmap_ms_symbol; 3465 } 3466 if(!cmap) 3467 { 3468 *cmap_type = cmap_none; 3469 goto end; 3470 } 3471 3472 format = GET_BE_WORD(*(WORD *)cmap); 3473 switch(format) 3474 { 3475 case 0: 3476 r = get_first_last_from_cmap0(cmap, first, last); 3477 break; 3478 case 4: 3479 r = get_first_last_from_cmap4(cmap, first, last, size); 3480 break; 3481 default: 3482 trace("unhandled cmap format %d\n", format); 3483 break; 3484 } 3485 3486 end: 3487 HeapFree(GetProcessHeap(), 0, header); 3488 return r; 3489 } 3490 3491 #define TT_PLATFORM_APPLE_UNICODE 0 3492 #define TT_PLATFORM_MACINTOSH 1 3493 #define TT_PLATFORM_MICROSOFT 3 3494 #define TT_APPLE_ID_DEFAULT 0 3495 #define TT_APPLE_ID_ISO_10646 2 3496 #define TT_APPLE_ID_UNICODE_2_0 3 3497 #define TT_MS_ID_SYMBOL_CS 0 3498 #define TT_MS_ID_UNICODE_CS 1 3499 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 3500 #define TT_NAME_ID_FONT_FAMILY 1 3501 #define TT_NAME_ID_FONT_SUBFAMILY 2 3502 #define TT_NAME_ID_UNIQUE_ID 3 3503 #define TT_NAME_ID_FULL_NAME 4 3504 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25 3505 3506 typedef struct sfnt_name 3507 { 3508 USHORT platform_id; 3509 USHORT encoding_id; 3510 USHORT language_id; 3511 USHORT name_id; 3512 USHORT length; 3513 USHORT offset; 3514 } sfnt_name; 3515 3516 static const LANGID mac_langid_table[] = 3517 { 3518 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */ 3519 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */ 3520 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */ 3521 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */ 3522 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */ 3523 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */ 3524 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */ 3525 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */ 3526 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */ 3527 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */ 3528 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */ 3529 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */ 3530 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */ 3531 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */ 3532 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */ 3533 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */ 3534 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */ 3535 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */ 3536 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */ 3537 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */ 3538 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */ 3539 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */ 3540 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */ 3541 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */ 3542 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */ 3543 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */ 3544 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */ 3545 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */ 3546 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */ 3547 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */ 3548 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */ 3549 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */ 3550 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */ 3551 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */ 3552 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */ 3553 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */ 3554 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */ 3555 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */ 3556 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */ 3557 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */ 3558 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */ 3559 0, /* TT_MAC_LANGID_YIDDISH */ 3560 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */ 3561 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */ 3562 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */ 3563 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */ 3564 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */ 3565 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */ 3566 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */ 3567 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */ 3568 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */ 3569 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */ 3570 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */ 3571 0, /* TT_MAC_LANGID_MOLDAVIAN */ 3572 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */ 3573 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */ 3574 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */ 3575 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */ 3576 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */ 3577 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */ 3578 0, /* TT_MAC_LANGID_KURDISH */ 3579 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */ 3580 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */ 3581 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */ 3582 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */ 3583 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */ 3584 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */ 3585 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */ 3586 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */ 3587 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */ 3588 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */ 3589 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */ 3590 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */ 3591 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */ 3592 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */ 3593 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */ 3594 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */ 3595 0, /* TT_MAC_LANGID_BURMESE */ 3596 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */ 3597 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */ 3598 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */ 3599 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */ 3600 0, /* TT_MAC_LANGID_TAGALOG */ 3601 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */ 3602 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */ 3603 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */ 3604 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */ 3605 0, /* TT_MAC_LANGID_GALLA */ 3606 0, /* TT_MAC_LANGID_SOMALI */ 3607 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */ 3608 0, /* TT_MAC_LANGID_RUANDA */ 3609 0, /* TT_MAC_LANGID_RUNDI */ 3610 0, /* TT_MAC_LANGID_CHEWA */ 3611 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */ 3612 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */ 3613 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */ 3614 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */ 3615 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */ 3616 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */ 3617 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */ 3618 0, /* TT_MAC_LANGID_LATIN */ 3619 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */ 3620 0, /* TT_MAC_LANGID_GUARANI */ 3621 0, /* TT_MAC_LANGID_AYMARA */ 3622 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */ 3623 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */ 3624 0, /* TT_MAC_LANGID_DZONGKHA */ 3625 0, /* TT_MAC_LANGID_JAVANESE */ 3626 0, /* TT_MAC_LANGID_SUNDANESE */ 3627 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */ 3628 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */ 3629 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */ 3630 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */ 3631 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */ 3632 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */ 3633 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */ 3634 0, /* TT_MAC_LANGID_TONGAN */ 3635 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */ 3636 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */ 3637 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */ 3638 }; 3639 3640 static inline WORD get_mac_code_page( const sfnt_name *name ) 3641 { 3642 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */ 3643 return 10000 + GET_BE_WORD(name->encoding_id); 3644 } 3645 3646 static int match_name_table_language( const sfnt_name *name, LANGID lang ) 3647 { 3648 LANGID name_lang; 3649 int res = 0; 3650 3651 switch (GET_BE_WORD(name->platform_id)) 3652 { 3653 case TT_PLATFORM_MICROSOFT: 3654 res += 5; /* prefer the Microsoft name */ 3655 switch (GET_BE_WORD(name->encoding_id)) 3656 { 3657 case TT_MS_ID_UNICODE_CS: 3658 case TT_MS_ID_SYMBOL_CS: 3659 name_lang = GET_BE_WORD(name->language_id); 3660 break; 3661 default: 3662 return 0; 3663 } 3664 break; 3665 case TT_PLATFORM_MACINTOSH: 3666 if (!IsValidCodePage( get_mac_code_page( name ))) return 0; 3667 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0; 3668 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)]; 3669 break; 3670 case TT_PLATFORM_APPLE_UNICODE: 3671 res += 2; /* prefer Unicode encodings */ 3672 switch (GET_BE_WORD(name->encoding_id)) 3673 { 3674 case TT_APPLE_ID_DEFAULT: 3675 case TT_APPLE_ID_ISO_10646: 3676 case TT_APPLE_ID_UNICODE_2_0: 3677 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0; 3678 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)]; 3679 break; 3680 default: 3681 return 0; 3682 } 3683 break; 3684 default: 3685 return 0; 3686 } 3687 if (name_lang == lang) res += 30; 3688 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20; 3689 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10; 3690 return res; 3691 } 3692 3693 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id) 3694 { 3695 struct sfnt_name_header 3696 { 3697 USHORT format; 3698 USHORT number_of_record; 3699 USHORT storage_offset; 3700 } *header; 3701 sfnt_name *entry; 3702 BOOL r = FALSE; 3703 LONG size, offset, length; 3704 LONG c, ret; 3705 WCHAR *name; 3706 BYTE *data; 3707 USHORT i; 3708 int res, best_lang = 0, best_index = -1; 3709 3710 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0); 3711 ok(size != GDI_ERROR, "no name table found\n"); 3712 if(size == GDI_ERROR) return FALSE; 3713 3714 data = HeapAlloc(GetProcessHeap(), 0, size); 3715 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size); 3716 ok(ret == size, "GetFontData should return %u not %u\n", size, ret); 3717 3718 header = (void *)data; 3719 header->format = GET_BE_WORD(header->format); 3720 header->number_of_record = GET_BE_WORD(header->number_of_record); 3721 header->storage_offset = GET_BE_WORD(header->storage_offset); 3722 if (header->format != 0) 3723 { 3724 trace("got format %u\n", header->format); 3725 goto out; 3726 } 3727 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size) 3728 { 3729 trace("number records out of range: %d\n", header->number_of_record); 3730 goto out; 3731 } 3732 if (header->storage_offset >= size) 3733 { 3734 trace("storage_offset %u > size %u\n", header->storage_offset, size); 3735 goto out; 3736 } 3737 3738 entry = (void *)&header[1]; 3739 for (i = 0; i < header->number_of_record; i++) 3740 { 3741 if (GET_BE_WORD(entry[i].name_id) != name_id) continue; 3742 res = match_name_table_language( &entry[i], language_id); 3743 if (res > best_lang) 3744 { 3745 best_lang = res; 3746 best_index = i; 3747 } 3748 } 3749 3750 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset); 3751 length = GET_BE_WORD(entry[best_index].length); 3752 if (offset + length > size) 3753 { 3754 trace("entry %d is out of range\n", best_index); 3755 goto out; 3756 } 3757 if (length >= out_size) 3758 { 3759 trace("buffer too small for entry %d\n", best_index); 3760 goto out; 3761 } 3762 3763 name = (WCHAR *)(data + offset); 3764 for (c = 0; c < length / 2; c++) 3765 out_buf[c] = GET_BE_WORD(name[c]); 3766 out_buf[c] = 0; 3767 3768 r = TRUE; 3769 3770 out: 3771 HeapFree(GetProcessHeap(), 0, data); 3772 return r; 3773 } 3774 3775 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm) 3776 { 3777 HDC hdc; 3778 HFONT hfont, hfont_old; 3779 TEXTMETRICA tmA; 3780 TT_OS2_V4 tt_os2; 3781 LONG size, ret; 3782 const char *font_name = lf->lfFaceName; 3783 DWORD cmap_first = 0, cmap_last = 0; 3784 UINT ascent, descent, cell_height; 3785 cmap_type cmap_type; 3786 BOOL sys_lang_non_english; 3787 3788 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH; 3789 hdc = GetDC(0); 3790 3791 SetLastError(0xdeadbeef); 3792 hfont = CreateFontIndirectA(lf); 3793 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError()); 3794 3795 hfont_old = SelectObject(hdc, hfont); 3796 3797 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0); 3798 if (size == GDI_ERROR) 3799 { 3800 trace("OS/2 chunk was not found\n"); 3801 goto end_of_test; 3802 } 3803 if (size > sizeof(tt_os2)) 3804 { 3805 trace("got too large OS/2 chunk of size %u\n", size); 3806 size = sizeof(tt_os2); 3807 } 3808 3809 memset(&tt_os2, 0, sizeof(tt_os2)); 3810 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size); 3811 ok(ret >= TT_OS2_V0_SIZE && ret <= size, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE, 3812 size, ret); 3813 3814 SetLastError(0xdeadbeef); 3815 ret = GetTextMetricsA(hdc, &tmA); 3816 ok(ret, "GetTextMetricsA error %u\n", GetLastError()); 3817 3818 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type)) 3819 { 3820 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name); 3821 } 3822 else 3823 { 3824 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A; 3825 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W; 3826 UINT os2_first_char, os2_last_char, default_char, break_char; 3827 USHORT version; 3828 TEXTMETRICW tmW; 3829 3830 ascent = GET_BE_WORD(tt_os2.usWinAscent); 3831 descent = abs((SHORT)GET_BE_WORD(tt_os2.usWinDescent)); 3832 cell_height = ascent + descent; 3833 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n", 3834 font_name, ntm->ntmCellHeight, cell_height, ascent, descent); 3835 3836 version = GET_BE_WORD(tt_os2.version); 3837 3838 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex); 3839 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex); 3840 default_char = GET_BE_WORD(tt_os2.usDefaultChar); 3841 break_char = GET_BE_WORD(tt_os2.usBreakChar); 3842 3843 if (winetest_debug > 1) 3844 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n", 3845 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last, 3846 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID); 3847 3848 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100)) 3849 { 3850 expect_first_W = 0; 3851 switch(GetACP()) 3852 { 3853 case 1255: /* Hebrew */ 3854 expect_last_W = 0xf896; 3855 break; 3856 case 1257: /* Baltic */ 3857 expect_last_W = 0xf8fd; 3858 break; 3859 default: 3860 expect_last_W = 0xf0ff; 3861 } 3862 expect_break_W = 0x20; 3863 expect_default_W = expect_break_W - 1; 3864 expect_first_A = 0x1e; 3865 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff); 3866 } 3867 else 3868 { 3869 expect_first_W = cmap_first; 3870 expect_last_W = cmap_last; 3871 if(os2_first_char <= 1) 3872 expect_break_W = os2_first_char + 2; 3873 else if(os2_first_char > 0xff) 3874 expect_break_W = 0x20; 3875 else 3876 expect_break_W = os2_first_char; 3877 expect_default_W = expect_break_W - 1; 3878 expect_first_A = expect_default_W - 1; 3879 expect_last_A = min(expect_last_W, 0xff); 3880 } 3881 expect_break_A = expect_break_W; 3882 expect_default_A = expect_default_W; 3883 3884 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */ 3885 todo_wine_if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e) 3886 ok(tmA.tmFirstChar == expect_first_A || 3887 tmA.tmFirstChar == expect_first_A + 1 /* win9x */, 3888 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A); 3889 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar)) 3890 ok(tmA.tmLastChar == expect_last_A || 3891 tmA.tmLastChar == 0xff /* win9x */, 3892 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A); 3893 else 3894 skip("tmLastChar is DBCS lead byte\n"); 3895 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n", 3896 font_name, tmA.tmBreakChar, expect_break_A); 3897 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english), 3898 "A: tmDefaultChar for %s got %02x expected %02x\n", 3899 font_name, tmA.tmDefaultChar, expect_default_A); 3900 3901 3902 SetLastError(0xdeadbeef); 3903 ret = GetTextMetricsW(hdc, &tmW); 3904 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, 3905 "GetTextMetricsW error %u\n", GetLastError()); 3906 if (ret) 3907 { 3908 /* Wine uses the os2 first char */ 3909 todo_wine_if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol) 3910 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n", 3911 font_name, tmW.tmFirstChar, expect_first_W); 3912 3913 /* Wine uses the os2 last char */ 3914 todo_wine_if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol) 3915 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n", 3916 font_name, tmW.tmLastChar, expect_last_W); 3917 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n", 3918 font_name, tmW.tmBreakChar, expect_break_W); 3919 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english), 3920 "W: tmDefaultChar for %s got %02x expected %02x\n", 3921 font_name, tmW.tmDefaultChar, expect_default_W); 3922 3923 /* Test the aspect ratio while we have tmW */ 3924 ret = GetDeviceCaps(hdc, LOGPIXELSX); 3925 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n", 3926 tmW.tmDigitizedAspectX, ret); 3927 ret = GetDeviceCaps(hdc, LOGPIXELSY); 3928 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n", 3929 tmW.tmDigitizedAspectX, ret); 3930 } 3931 } 3932 3933 /* test FF_ values */ 3934 switch(tt_os2.panose.bFamilyType) 3935 { 3936 case PAN_ANY: 3937 case PAN_NO_FIT: 3938 case PAN_FAMILY_TEXT_DISPLAY: 3939 case PAN_FAMILY_PICTORIAL: 3940 default: 3941 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */ 3942 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED) 3943 { 3944 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name); 3945 break; 3946 } 3947 switch(tt_os2.panose.bSerifStyle) 3948 { 3949 case PAN_ANY: 3950 case PAN_NO_FIT: 3951 default: 3952 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name); 3953 break; 3954 3955 case PAN_SERIF_COVE: 3956 case PAN_SERIF_OBTUSE_COVE: 3957 case PAN_SERIF_SQUARE_COVE: 3958 case PAN_SERIF_OBTUSE_SQUARE_COVE: 3959 case PAN_SERIF_SQUARE: 3960 case PAN_SERIF_THIN: 3961 case PAN_SERIF_BONE: 3962 case PAN_SERIF_EXAGGERATED: 3963 case PAN_SERIF_TRIANGLE: 3964 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name); 3965 break; 3966 3967 case PAN_SERIF_NORMAL_SANS: 3968 case PAN_SERIF_OBTUSE_SANS: 3969 case PAN_SERIF_PERP_SANS: 3970 case PAN_SERIF_FLARED: 3971 case PAN_SERIF_ROUNDED: 3972 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name); 3973 break; 3974 } 3975 break; 3976 3977 case PAN_FAMILY_SCRIPT: 3978 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name); 3979 break; 3980 3981 case PAN_FAMILY_DECORATIVE: 3982 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name); 3983 break; 3984 } 3985 3986 test_negative_width(hdc, lf); 3987 3988 end_of_test: 3989 SelectObject(hdc, hfont_old); 3990 DeleteObject(hfont); 3991 3992 ReleaseDC(0, hdc); 3993 } 3994 3995 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 3996 { 3997 INT *enumed = (INT *)lParam; 3998 3999 if (type == TRUETYPE_FONTTYPE) 4000 { 4001 (*enumed)++; 4002 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm); 4003 } 4004 return 1; 4005 } 4006 4007 static void test_GetTextMetrics(void) 4008 { 4009 LOGFONTA lf; 4010 HDC hdc; 4011 INT enumed; 4012 4013 /* Report only once */ 4014 if(!pGetGlyphIndicesA) 4015 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n"); 4016 4017 hdc = GetDC(0); 4018 4019 memset(&lf, 0, sizeof(lf)); 4020 lf.lfCharSet = DEFAULT_CHARSET; 4021 enumed = 0; 4022 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0); 4023 trace("Tested metrics of %d truetype fonts\n", enumed); 4024 4025 ReleaseDC(0, hdc); 4026 } 4027 4028 static void test_nonexistent_font(void) 4029 { 4030 static const struct 4031 { 4032 const char *name; 4033 int charset; 4034 } font_subst[] = 4035 { 4036 { "Times New Roman Baltic", 186 }, 4037 { "Times New Roman CE", 238 }, 4038 { "Times New Roman CYR", 204 }, 4039 { "Times New Roman Greek", 161 }, 4040 { "Times New Roman TUR", 162 } 4041 }; 4042 static const struct 4043 { 4044 const char *name; 4045 int charset; 4046 } shell_subst[] = 4047 { 4048 { "MS Shell Dlg", 186 }, 4049 { "MS Shell Dlg", 238 }, 4050 { "MS Shell Dlg", 204 }, 4051 { "MS Shell Dlg", 161 }, 4052 { "MS Shell Dlg", 162 } 4053 }; 4054 LOGFONTA lf; 4055 HDC hdc; 4056 HFONT hfont; 4057 CHARSETINFO csi; 4058 INT cs, expected_cs, i, ret; 4059 char buf[LF_FACESIZE]; 4060 4061 expected_cs = GetACP(); 4062 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE)) 4063 { 4064 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs); 4065 return; 4066 } 4067 expected_cs = csi.ciCharset; 4068 trace("ACP %d -> charset %d\n", GetACP(), expected_cs); 4069 4070 hdc = CreateCompatibleDC(0); 4071 4072 for (i = 0; i < sizeof(shell_subst)/sizeof(shell_subst[0]); i++) 4073 { 4074 ret = is_font_installed(shell_subst[i].name); 4075 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name); 4076 ret = is_truetype_font_installed(shell_subst[i].name); 4077 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name); 4078 4079 memset(&lf, 0, sizeof(lf)); 4080 lf.lfHeight = -13; 4081 lf.lfWeight = FW_REGULAR; 4082 strcpy(lf.lfFaceName, shell_subst[i].name); 4083 hfont = CreateFontIndirectA(&lf); 4084 hfont = SelectObject(hdc, hfont); 4085 GetTextFaceA(hdc, sizeof(buf), buf); 4086 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf); 4087 cs = GetTextCharset(hdc); 4088 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name); 4089 4090 DeleteObject(SelectObject(hdc, hfont)); 4091 4092 memset(&lf, 0, sizeof(lf)); 4093 lf.lfHeight = -13; 4094 lf.lfWeight = FW_DONTCARE; 4095 strcpy(lf.lfFaceName, shell_subst[i].name); 4096 hfont = CreateFontIndirectA(&lf); 4097 hfont = SelectObject(hdc, hfont); 4098 GetTextFaceA(hdc, sizeof(buf), buf); 4099 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf); 4100 cs = GetTextCharset(hdc); 4101 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name); 4102 DeleteObject(SelectObject(hdc, hfont)); 4103 } 4104 4105 if (!is_truetype_font_installed("Arial") || 4106 !is_truetype_font_installed("Times New Roman")) 4107 { 4108 DeleteDC(hdc); 4109 skip("Arial or Times New Roman not installed\n"); 4110 return; 4111 } 4112 4113 memset(&lf, 0, sizeof(lf)); 4114 lf.lfHeight = 100; 4115 lf.lfWeight = FW_REGULAR; 4116 lf.lfCharSet = ANSI_CHARSET; 4117 lf.lfPitchAndFamily = FF_SWISS; 4118 strcpy(lf.lfFaceName, "Nonexistent font"); 4119 hfont = CreateFontIndirectA(&lf); 4120 hfont = SelectObject(hdc, hfont); 4121 GetTextFaceA(hdc, sizeof(buf), buf); 4122 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf); 4123 cs = GetTextCharset(hdc); 4124 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs); 4125 DeleteObject(SelectObject(hdc, hfont)); 4126 4127 memset(&lf, 0, sizeof(lf)); 4128 lf.lfHeight = -13; 4129 lf.lfWeight = FW_DONTCARE; 4130 strcpy(lf.lfFaceName, "Nonexistent font"); 4131 hfont = CreateFontIndirectA(&lf); 4132 hfont = SelectObject(hdc, hfont); 4133 GetTextFaceA(hdc, sizeof(buf), buf); 4134 todo_wine /* Wine uses Arial for all substitutions */ 4135 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ || 4136 !lstrcmpiA(buf, "MS Serif") || /* Win9x */ 4137 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */ 4138 "Got %s\n", buf); 4139 cs = GetTextCharset(hdc); 4140 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs); 4141 DeleteObject(SelectObject(hdc, hfont)); 4142 4143 memset(&lf, 0, sizeof(lf)); 4144 lf.lfHeight = -13; 4145 lf.lfWeight = FW_REGULAR; 4146 strcpy(lf.lfFaceName, "Nonexistent font"); 4147 hfont = CreateFontIndirectA(&lf); 4148 hfont = SelectObject(hdc, hfont); 4149 GetTextFaceA(hdc, sizeof(buf), buf); 4150 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ || 4151 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf); 4152 cs = GetTextCharset(hdc); 4153 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs); 4154 DeleteObject(SelectObject(hdc, hfont)); 4155 4156 memset(&lf, 0, sizeof(lf)); 4157 lf.lfHeight = -13; 4158 lf.lfWeight = FW_DONTCARE; 4159 strcpy(lf.lfFaceName, "Times New Roman"); 4160 hfont = CreateFontIndirectA(&lf); 4161 hfont = SelectObject(hdc, hfont); 4162 GetTextFaceA(hdc, sizeof(buf), buf); 4163 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf); 4164 cs = GetTextCharset(hdc); 4165 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs); 4166 DeleteObject(SelectObject(hdc, hfont)); 4167 4168 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++) 4169 { 4170 ret = is_font_installed(font_subst[i].name); 4171 todo_wine 4172 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */, 4173 "%s should be enumerated\n", font_subst[i].name); 4174 ret = is_truetype_font_installed(font_subst[i].name); 4175 todo_wine 4176 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */, 4177 "%s should be enumerated\n", font_subst[i].name); 4178 4179 memset(&lf, 0, sizeof(lf)); 4180 lf.lfHeight = -13; 4181 lf.lfWeight = FW_REGULAR; 4182 strcpy(lf.lfFaceName, font_subst[i].name); 4183 hfont = CreateFontIndirectA(&lf); 4184 hfont = SelectObject(hdc, hfont); 4185 cs = GetTextCharset(hdc); 4186 if (font_subst[i].charset == expected_cs) 4187 { 4188 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name); 4189 GetTextFaceA(hdc, sizeof(buf), buf); 4190 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf); 4191 } 4192 else 4193 { 4194 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name); 4195 GetTextFaceA(hdc, sizeof(buf), buf); 4196 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ || 4197 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name); 4198 } 4199 DeleteObject(SelectObject(hdc, hfont)); 4200 4201 memset(&lf, 0, sizeof(lf)); 4202 lf.lfHeight = -13; 4203 lf.lfWeight = FW_DONTCARE; 4204 strcpy(lf.lfFaceName, font_subst[i].name); 4205 hfont = CreateFontIndirectA(&lf); 4206 hfont = SelectObject(hdc, hfont); 4207 GetTextFaceA(hdc, sizeof(buf), buf); 4208 ok(!lstrcmpiA(buf, "Arial") /* Wine */ || 4209 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ || 4210 !lstrcmpiA(buf, "MS Serif") /* Win9x */ || 4211 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */ 4212 "got %s for font %s\n", buf, font_subst[i].name); 4213 cs = GetTextCharset(hdc); 4214 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name); 4215 DeleteObject(SelectObject(hdc, hfont)); 4216 } 4217 4218 DeleteDC(hdc); 4219 } 4220 4221 static void test_RealizationInfo(void) 4222 { 4223 struct font_realization_info { 4224 DWORD size; 4225 DWORD flags; 4226 DWORD cache_num; 4227 DWORD instance_id; 4228 DWORD unk; 4229 WORD face_index; 4230 WORD simulations; 4231 }; 4232 4233 struct realization_info_t 4234 { 4235 DWORD flags; 4236 DWORD cache_num; 4237 DWORD instance_id; 4238 }; 4239 4240 HDC hdc; 4241 DWORD info[4], info2[10]; 4242 BOOL r, have_file = FALSE; 4243 HFONT hfont, hfont_old; 4244 LOGFONTA lf; 4245 DWORD needed, read; 4246 HANDLE h; 4247 BYTE file[16], data[14]; 4248 struct file_info 4249 { 4250 FILETIME time; 4251 LARGE_INTEGER size; 4252 WCHAR path[MAX_PATH]; 4253 } file_info; 4254 FILETIME time; 4255 LARGE_INTEGER size; 4256 4257 if(!pGdiRealizationInfo) 4258 { 4259 win_skip("GdiRealizationInfo not available\n"); 4260 return; 4261 } 4262 4263 hdc = GetDC(0); 4264 4265 memset(info, 0xcc, sizeof(info)); 4266 r = pGdiRealizationInfo(hdc, info); 4267 ok(r != 0, "ret 0\n"); 4268 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]); 4269 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n"); 4270 4271 if (!is_truetype_font_installed("Tahoma")) 4272 { 4273 skip("skipping GdiRealizationInfo with truetype font\n"); 4274 goto end; 4275 } 4276 4277 memset(&lf, 0, sizeof(lf)); 4278 strcpy(lf.lfFaceName, "Tahoma"); 4279 lf.lfHeight = 20; 4280 lf.lfWeight = FW_BOLD; 4281 lf.lfItalic = 1; 4282 hfont = CreateFontIndirectA(&lf); 4283 hfont_old = SelectObject(hdc, hfont); 4284 4285 memset(info, 0xcc, sizeof(info)); 4286 r = pGdiRealizationInfo(hdc, info); 4287 ok(r != 0, "ret 0\n"); 4288 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]); 4289 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n"); 4290 4291 if (pGetFontRealizationInfo) 4292 { 4293 struct font_realization_info *fri = (struct font_realization_info*)info2; 4294 struct realization_info_t *ri = (struct realization_info_t*)info; 4295 4296 /* The first DWORD represents a struct size. On a 4297 newly rebooted system setting this to < 16 results 4298 in GetFontRealizationInfo failing. However there 4299 appears to be some caching going on which results 4300 in calls after a successful call also succeeding even 4301 if the size < 16. This means we can't reliably test 4302 this behaviour. */ 4303 4304 memset(info2, 0xcc, sizeof(info2)); 4305 info2[0] = 16; 4306 r = pGetFontRealizationInfo(hdc, info2); 4307 ok(r != 0, "ret 0\n"); 4308 /* We may get the '24' version here if that has been previously 4309 requested. */ 4310 ok(fri->size == 16 || fri->size == 24, "got %d\n", info2[0]); 4311 ok(fri->flags == ri->flags, "flags mismatch\n"); 4312 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n"); 4313 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n"); 4314 ok(info2[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2[6]); 4315 4316 memset(info2, 0xcc, sizeof(info2)); 4317 info2[0] = 28; 4318 r = pGetFontRealizationInfo(hdc, info2); 4319 ok(r == FALSE, "got %d\n", r); 4320 4321 memset(info2, 0xcc, sizeof(info2)); 4322 info2[0] = 24; 4323 r = pGetFontRealizationInfo(hdc, info2); 4324 ok(r != 0, "ret 0\n"); 4325 ok(fri->size == 24, "got %d\n", fri->size); 4326 ok(fri->flags == ri->flags, "flags mismatch\n"); 4327 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n"); 4328 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n"); 4329 ok(fri->simulations == 0x2, "got simulations flags 0x%04x\n", fri->simulations); 4330 ok(fri->face_index == 0, "got wrong face index %u\n", fri->face_index); 4331 ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n"); 4332 4333 /* Test GetFontFileInfo() */ 4334 /* invalid font id */ 4335 SetLastError(0xdeadbeef); 4336 r = pGetFontFileInfo(0xabababab, 0, &file_info, sizeof(file_info), &needed); 4337 ok(r == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "ret %d gle %d\n", r, GetLastError()); 4338 4339 needed = 0; 4340 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed); 4341 ok(r != 0 || GetLastError() == ERROR_NOACCESS, "ret %d gle %d\n", r, GetLastError()); 4342 4343 if (r) 4344 { 4345 ok(needed > 0 && needed < sizeof(file_info), "got needed size %u\n", needed); 4346 4347 h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 4348 ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError()); 4349 4350 GetFileTime(h, NULL, NULL, &time); 4351 ok(!CompareFileTime(&file_info.time, &time), "time mismatch\n"); 4352 GetFileSizeEx(h, &size); 4353 ok(file_info.size.QuadPart == size.QuadPart, "size mismatch\n"); 4354 4355 /* Read first 16 bytes from the file */ 4356 ReadFile(h, file, sizeof(file), &read, NULL); 4357 CloseHandle(h); 4358 have_file = TRUE; 4359 4360 /* shorter buffer */ 4361 SetLastError(0xdeadbeef); 4362 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, needed - 1, &needed); 4363 ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %d\n", r, GetLastError()); 4364 } 4365 4366 if (pGetFontFileData) { 4367 /* Get bytes 2 - 16 using GetFontFileData */ 4368 r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data)); 4369 ok(r != 0, "ret 0 gle %d\n", GetLastError()); 4370 4371 if (have_file) 4372 ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n"); 4373 else 4374 win_skip("GetFontFileInfo() failed, skipping\n"); 4375 } 4376 } 4377 4378 DeleteObject(SelectObject(hdc, hfont_old)); 4379 4380 end: 4381 ReleaseDC(0, hdc); 4382 } 4383 4384 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include 4385 the nul in the count of characters copied when the face name buffer is not 4386 NULL, whereas it does if the buffer is NULL. Further, the Unicode version 4387 always includes it. */ 4388 static void test_GetTextFace(void) 4389 { 4390 static const char faceA[] = "Tahoma"; 4391 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0}; 4392 LOGFONTA fA = {0}; 4393 LOGFONTW fW = {0}; 4394 char bufA[LF_FACESIZE]; 4395 WCHAR bufW[LF_FACESIZE]; 4396 HFONT f, g; 4397 HDC dc; 4398 int n; 4399 4400 if(!is_font_installed("Tahoma")) 4401 { 4402 skip("Tahoma is not installed so skipping this test\n"); 4403 return; 4404 } 4405 4406 /* 'A' case. */ 4407 memcpy(fA.lfFaceName, faceA, sizeof faceA); 4408 f = CreateFontIndirectA(&fA); 4409 ok(f != NULL, "CreateFontIndirectA failed\n"); 4410 4411 dc = GetDC(NULL); 4412 g = SelectObject(dc, f); 4413 n = GetTextFaceA(dc, sizeof bufA, bufA); 4414 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n); 4415 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n"); 4416 4417 /* Play with the count arg. */ 4418 bufA[0] = 'x'; 4419 n = GetTextFaceA(dc, 0, bufA); 4420 ok(n == 0, "GetTextFaceA returned %d\n", n); 4421 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]); 4422 4423 bufA[0] = 'x'; 4424 n = GetTextFaceA(dc, 1, bufA); 4425 ok(n == 0, "GetTextFaceA returned %d\n", n); 4426 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]); 4427 4428 bufA[0] = 'x'; bufA[1] = 'y'; 4429 n = GetTextFaceA(dc, 2, bufA); 4430 ok(n == 1, "GetTextFaceA returned %d\n", n); 4431 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n"); 4432 4433 n = GetTextFaceA(dc, 0, NULL); 4434 ok(n == sizeof faceA || 4435 broken(n == 0), /* win98, winMe */ 4436 "GetTextFaceA returned %d\n", n); 4437 4438 DeleteObject(SelectObject(dc, g)); 4439 ReleaseDC(NULL, dc); 4440 4441 /* 'W' case. */ 4442 memcpy(fW.lfFaceName, faceW, sizeof faceW); 4443 SetLastError(0xdeadbeef); 4444 f = CreateFontIndirectW(&fW); 4445 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 4446 { 4447 win_skip("CreateFontIndirectW is not implemented\n"); 4448 return; 4449 } 4450 ok(f != NULL, "CreateFontIndirectW failed\n"); 4451 4452 dc = GetDC(NULL); 4453 g = SelectObject(dc, f); 4454 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW); 4455 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n); 4456 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n"); 4457 4458 /* Play with the count arg. */ 4459 bufW[0] = 'x'; 4460 n = GetTextFaceW(dc, 0, bufW); 4461 ok(n == 0, "GetTextFaceW returned %d\n", n); 4462 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]); 4463 4464 bufW[0] = 'x'; 4465 n = GetTextFaceW(dc, 1, bufW); 4466 ok(n == 1, "GetTextFaceW returned %d\n", n); 4467 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]); 4468 4469 bufW[0] = 'x'; bufW[1] = 'y'; 4470 n = GetTextFaceW(dc, 2, bufW); 4471 ok(n == 2, "GetTextFaceW returned %d\n", n); 4472 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n"); 4473 4474 n = GetTextFaceW(dc, 0, NULL); 4475 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n); 4476 4477 DeleteObject(SelectObject(dc, g)); 4478 ReleaseDC(NULL, dc); 4479 } 4480 4481 static void test_orientation(void) 4482 { 4483 static const char test_str[11] = "Test String"; 4484 HDC hdc; 4485 LOGFONTA lf; 4486 HFONT hfont, old_hfont; 4487 SIZE size; 4488 4489 if (!is_truetype_font_installed("Arial")) 4490 { 4491 skip("Arial is not installed\n"); 4492 return; 4493 } 4494 4495 hdc = CreateCompatibleDC(0); 4496 memset(&lf, 0, sizeof(lf)); 4497 lstrcpyA(lf.lfFaceName, "Arial"); 4498 lf.lfHeight = 72; 4499 lf.lfOrientation = lf.lfEscapement = 900; 4500 hfont = create_font("orientation", &lf); 4501 old_hfont = SelectObject(hdc, hfont); 4502 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n"); 4503 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx); 4504 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy); 4505 SelectObject(hdc, old_hfont); 4506 DeleteObject(hfont); 4507 DeleteDC(hdc); 4508 } 4509 4510 static void test_oemcharset(void) 4511 { 4512 HDC hdc; 4513 LOGFONTA lf, clf; 4514 HFONT hfont, old_hfont; 4515 int charset; 4516 4517 hdc = CreateCompatibleDC(0); 4518 ZeroMemory(&lf, sizeof(lf)); 4519 lf.lfHeight = 12; 4520 lf.lfCharSet = OEM_CHARSET; 4521 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN; 4522 lstrcpyA(lf.lfFaceName, "Terminal"); 4523 hfont = CreateFontIndirectA(&lf); 4524 old_hfont = SelectObject(hdc, hfont); 4525 charset = GetTextCharset(hdc); 4526 todo_wine 4527 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset); 4528 hfont = SelectObject(hdc, old_hfont); 4529 GetObjectA(hfont, sizeof(clf), &clf); 4530 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName); 4531 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily); 4532 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet); 4533 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight); 4534 DeleteObject(hfont); 4535 DeleteDC(hdc); 4536 } 4537 4538 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe, 4539 const TEXTMETRICA *lpntme, 4540 DWORD FontType, LPARAM lParam) 4541 { 4542 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme; 4543 CHARSETINFO csi; 4544 LOGFONTA lf = *lpelfe; 4545 HFONT hfont; 4546 DWORD found_subset; 4547 4548 /* skip bitmap, proportional or vertical font */ 4549 if ((FontType & TRUETYPE_FONTTYPE) == 0 || 4550 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH || 4551 lf.lfFaceName[0] == '@') 4552 return 1; 4553 4554 /* skip linked font */ 4555 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) || 4556 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0) 4557 return 1; 4558 4559 /* skip linked font, like SimSun-ExtB */ 4560 switch (lpelfe->lfCharSet) { 4561 case SHIFTJIS_CHARSET: 4562 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */ 4563 break; 4564 case GB2312_CHARSET: 4565 case CHINESEBIG5_CHARSET: 4566 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */ 4567 break; 4568 case HANGEUL_CHARSET: 4569 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */ 4570 break; 4571 default: 4572 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */ 4573 break; 4574 } 4575 if (!found_subset) 4576 return 1; 4577 4578 /* test with an odd height */ 4579 lf.lfHeight = -19; 4580 lf.lfWidth = 0; 4581 hfont = CreateFontIndirectA(&lf); 4582 if (hfont) 4583 { 4584 *(HFONT *)lParam = hfont; 4585 return 0; 4586 } 4587 return 1; 4588 } 4589 4590 static void test_GetGlyphOutline(void) 4591 { 4592 HDC hdc; 4593 GLYPHMETRICS gm, gm2; 4594 LOGFONTA lf; 4595 HFONT hfont, old_hfont; 4596 INT ret, ret2; 4597 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP, 4598 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP }; 4599 static const struct 4600 { 4601 UINT cs; 4602 UINT a; 4603 UINT w; 4604 } c[] = 4605 { 4606 {ANSI_CHARSET, 0x30, 0x30}, 4607 {SHIFTJIS_CHARSET, 0x82a0, 0x3042}, 4608 {HANGEUL_CHARSET, 0x8141, 0xac02}, 4609 {GB2312_CHARSET, 0x8141, 0x4e04}, 4610 {CHINESEBIG5_CHARSET, 0xa142, 0x3001} 4611 }; 4612 UINT i; 4613 4614 if (!is_truetype_font_installed("Tahoma")) 4615 { 4616 skip("Tahoma is not installed\n"); 4617 return; 4618 } 4619 4620 hdc = CreateCompatibleDC(0); 4621 memset(&lf, 0, sizeof(lf)); 4622 lf.lfHeight = 72; 4623 lstrcpyA(lf.lfFaceName, "Tahoma"); 4624 SetLastError(0xdeadbeef); 4625 hfont = CreateFontIndirectA(&lf); 4626 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); 4627 old_hfont = SelectObject(hdc, hfont); 4628 4629 memset(&gm, 0, sizeof(gm)); 4630 SetLastError(0xdeadbeef); 4631 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 4632 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); 4633 4634 memset(&gm, 0, sizeof(gm)); 4635 SetLastError(0xdeadbeef); 4636 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL); 4637 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n"); 4638 ok(GetLastError() == 0xdeadbeef || 4639 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */ 4640 "expected 0xdeadbeef, got %u\n", GetLastError()); 4641 4642 memset(&gm, 0, sizeof(gm)); 4643 SetLastError(0xdeadbeef); 4644 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 4645 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4646 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError()); 4647 4648 memset(&gm, 0, sizeof(gm)); 4649 SetLastError(0xdeadbeef); 4650 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL); 4651 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4652 { 4653 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n"); 4654 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError()); 4655 } 4656 4657 /* test for needed buffer size request on space char */ 4658 memset(&gm, 0, sizeof(gm)); 4659 SetLastError(0xdeadbeef); 4660 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat); 4661 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4662 { 4663 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n"); 4664 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX); 4665 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY); 4666 } 4667 4668 /* requesting buffer size for space char + error */ 4669 memset(&gm, 0, sizeof(gm)); 4670 SetLastError(0xdeadbeef); 4671 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL); 4672 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4673 { 4674 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n"); 4675 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError()); 4676 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX); 4677 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY); 4678 } 4679 4680 /* test GetGlyphOutline with a buffer too small */ 4681 SetLastError(0xdeadbeef); 4682 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat); 4683 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4684 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n"); 4685 4686 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i) 4687 { 4688 DWORD dummy; 4689 4690 memset(&gm, 0xab, sizeof(gm)); 4691 SetLastError(0xdeadbeef); 4692 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat); 4693 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4694 { 4695 if (fmt[i] == GGO_METRICS) 4696 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret); 4697 else 4698 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret); 4699 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX); 4700 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY); 4701 } 4702 4703 memset(&gm, 0xab, sizeof(gm)); 4704 SetLastError(0xdeadbeef); 4705 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat); 4706 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4707 { 4708 if (fmt[i] == GGO_METRICS) 4709 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret); 4710 else 4711 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret); 4712 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX); 4713 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY); 4714 } 4715 4716 memset(&gm, 0xab, sizeof(gm)); 4717 SetLastError(0xdeadbeef); 4718 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat); 4719 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4720 { 4721 if (fmt[i] == GGO_METRICS) 4722 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret); 4723 else 4724 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret); 4725 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX); 4726 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY); 4727 } 4728 4729 memset(&gm, 0xab, sizeof(gm)); 4730 SetLastError(0xdeadbeef); 4731 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat); 4732 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 4733 { 4734 if (fmt[i] == GGO_METRICS) { 4735 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret); 4736 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX); 4737 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY); 4738 } 4739 else 4740 { 4741 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret); 4742 memset(&gm2, 0xab, sizeof(gm2)); 4743 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0, 4744 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]); 4745 } 4746 } 4747 } 4748 4749 SelectObject(hdc, old_hfont); 4750 DeleteObject(hfont); 4751 4752 for (i = 0; i < sizeof c / sizeof c[0]; ++i) 4753 { 4754 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}}; 4755 TEXTMETRICA tm; 4756 4757 lf.lfFaceName[0] = '\0'; 4758 lf.lfCharSet = c[i].cs; 4759 lf.lfPitchAndFamily = 0; 4760 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0)) 4761 { 4762 skip("TrueType font for charset %u is not installed\n", c[i].cs); 4763 continue; 4764 } 4765 4766 old_hfont = SelectObject(hdc, hfont); 4767 4768 /* expected to ignore superfluous bytes (sigle-byte character) */ 4769 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat); 4770 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat); 4771 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2); 4772 4773 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat); 4774 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, 4775 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2); 4776 4777 /* expected to ignore superfluous bytes (double-byte character) */ 4778 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat); 4779 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat); 4780 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, 4781 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2); 4782 4783 /* expected to match wide-char version results */ 4784 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat); 4785 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2); 4786 4787 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0)) 4788 { 4789 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs); 4790 continue; 4791 } 4792 DeleteObject(SelectObject(hdc, hfont)); 4793 if (c[i].a <= 0xff) 4794 { 4795 DeleteObject(SelectObject(hdc, old_hfont)); 4796 continue; 4797 } 4798 4799 ret = GetObjectA(hfont, sizeof lf, &lf); 4800 ok(ret > 0, "GetObject error %u\n", GetLastError()); 4801 4802 ret = GetTextMetricsA(hdc, &tm); 4803 ok(ret, "GetTextMetrics error %u\n", GetLastError()); 4804 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat); 4805 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); 4806 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n", 4807 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); 4808 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight), 4809 "expected %d, got %d (%s:%d)\n", 4810 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); 4811 4812 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat); 4813 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); 4814 ok(gm2.gmCellIncY == -lf.lfHeight, 4815 "expected %d, got %d (%s:%d)\n", 4816 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet); 4817 4818 lf.lfItalic = TRUE; 4819 hfont = CreateFontIndirectA(&lf); 4820 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError()); 4821 DeleteObject(SelectObject(hdc, hfont)); 4822 ret = GetTextMetricsA(hdc, &tm); 4823 ok(ret, "GetTextMetrics error %u\n", GetLastError()); 4824 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat); 4825 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); 4826 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight), 4827 "expected %d, got %d (%s:%d)\n", 4828 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet); 4829 4830 lf.lfItalic = FALSE; 4831 lf.lfEscapement = lf.lfOrientation = 2700; 4832 hfont = CreateFontIndirectA(&lf); 4833 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError()); 4834 DeleteObject(SelectObject(hdc, hfont)); 4835 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat); 4836 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); 4837 ok(gm2.gmCellIncY == -lf.lfHeight, 4838 "expected %d, got %d (%s:%d)\n", 4839 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet); 4840 4841 hfont = SelectObject(hdc, old_hfont); 4842 DeleteObject(hfont); 4843 } 4844 4845 DeleteDC(hdc); 4846 } 4847 4848 /* bug #9995: there is a limit to the character width that can be specified */ 4849 static void test_GetTextMetrics2(const char *fontname, int font_height) 4850 { 4851 HFONT of, hf; 4852 HDC hdc; 4853 TEXTMETRICA tm; 4854 BOOL ret; 4855 int ave_width, height, width, ratio, scale; 4856 4857 if (!is_truetype_font_installed( fontname)) { 4858 skip("%s is not installed\n", fontname); 4859 return; 4860 } 4861 hdc = CreateCompatibleDC(0); 4862 ok( hdc != NULL, "CreateCompatibleDC failed\n"); 4863 /* select width = 0 */ 4864 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, 4865 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES, 4866 DEFAULT_QUALITY, VARIABLE_PITCH, 4867 fontname); 4868 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height); 4869 of = SelectObject( hdc, hf); 4870 ret = GetTextMetricsA( hdc, &tm); 4871 ok(ret, "GetTextMetricsA error %u\n", GetLastError()); 4872 height = tm.tmHeight; 4873 ave_width = tm.tmAveCharWidth; 4874 SelectObject( hdc, of); 4875 DeleteObject( hf); 4876 4877 trace("height %d, ave width %d\n", height, ave_width); 4878 4879 for (width = ave_width * 2; /* nothing*/; width += ave_width) 4880 { 4881 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, 4882 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES, 4883 DEFAULT_QUALITY, VARIABLE_PITCH, fontname); 4884 ok(hf != 0, "CreateFont failed\n"); 4885 of = SelectObject(hdc, hf); 4886 ret = GetTextMetricsA(hdc, &tm); 4887 ok(ret, "GetTextMetrics error %u\n", GetLastError()); 4888 SelectObject(hdc, of); 4889 DeleteObject(hf); 4890 4891 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200) 4892 break; 4893 } 4894 4895 DeleteDC(hdc); 4896 4897 ratio = width / height; 4898 scale = width / ave_width; 4899 4900 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n", 4901 width, height, ratio, width, ave_width, scale); 4902 4903 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio); 4904 } 4905 4906 static void test_GetCharacterPlacement(void) 4907 { 4908 GCP_RESULTSA result; 4909 DWORD size, size2; 4910 WCHAR glyphs[20]; 4911 HDC hdc; 4912 4913 hdc = CreateCompatibleDC(0); 4914 ok(!!hdc, "CreateCompatibleDC failed\n"); 4915 4916 memset(&result, 0, sizeof(result)); 4917 result.lStructSize = sizeof(result); 4918 result.lpGlyphs = glyphs; 4919 result.nGlyphs = 20; 4920 4921 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, &result, 0); 4922 ok(size, "GetCharacterPlacementA failed!\n"); 4923 4924 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, NULL, 0); 4925 ok(size2, "GetCharacterPlacementA failed!\n"); 4926 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size); 4927 4928 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, NULL, GCP_REORDER); 4929 ok(size2, "GetCharacterPlacementA failed!\n"); 4930 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size); 4931 4932 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, &result, GCP_REORDER); 4933 ok(size, "GetCharacterPlacementA failed!\n"); 4934 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size); 4935 } 4936 4937 static void test_CreateFontIndirect(void) 4938 { 4939 LOGFONTA lf, getobj_lf; 4940 int ret, i; 4941 HFONT hfont; 4942 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"}; 4943 4944 memset(&lf, 0, sizeof(lf)); 4945 lf.lfCharSet = ANSI_CHARSET; 4946 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 4947 lf.lfHeight = 16; 4948 lf.lfWidth = 16; 4949 lf.lfQuality = DEFAULT_QUALITY; 4950 lf.lfItalic = FALSE; 4951 lf.lfWeight = FW_DONTCARE; 4952 4953 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++) 4954 { 4955 lstrcpyA(lf.lfFaceName, TestName[i]); 4956 hfont = CreateFontIndirectA(&lf); 4957 ok(hfont != 0, "CreateFontIndirectA failed\n"); 4958 SetLastError(0xdeadbeef); 4959 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf); 4960 ok(ret, "GetObject failed: %d\n", GetLastError()); 4961 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic); 4962 ok(lf.lfWeight == getobj_lf.lfWeight || 4963 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */ 4964 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight); 4965 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) || 4966 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */ 4967 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName); 4968 DeleteObject(hfont); 4969 } 4970 } 4971 4972 static void test_CreateFontIndirectEx(void) 4973 { 4974 ENUMLOGFONTEXDVA lfex; 4975 HFONT hfont; 4976 4977 if (!pCreateFontIndirectExA) 4978 { 4979 win_skip("CreateFontIndirectExA is not available\n"); 4980 return; 4981 } 4982 4983 if (!is_truetype_font_installed("Arial")) 4984 { 4985 skip("Arial is not installed\n"); 4986 return; 4987 } 4988 4989 SetLastError(0xdeadbeef); 4990 hfont = pCreateFontIndirectExA(NULL); 4991 ok(hfont == NULL, "got %p\n", hfont); 4992 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError()); 4993 4994 memset(&lfex, 0, sizeof(lfex)); 4995 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial"); 4996 hfont = pCreateFontIndirectExA(&lfex); 4997 ok(hfont != 0, "CreateFontIndirectEx failed\n"); 4998 if (hfont) 4999 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont); 5000 DeleteObject(hfont); 5001 } 5002 5003 static void free_font(void *font) 5004 { 5005 UnmapViewOfFile(font); 5006 } 5007 5008 static void *load_font(const char *font_name, DWORD *font_size) 5009 { 5010 char file_name[MAX_PATH]; 5011 HANDLE file, mapping; 5012 void *font; 5013 5014 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL; 5015 strcat(file_name, "\\fonts\\"); 5016 strcat(file_name, font_name); 5017 5018 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); 5019 if (file == INVALID_HANDLE_VALUE) return NULL; 5020 5021 *font_size = GetFileSize(file, NULL); 5022 5023 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL); 5024 if (!mapping) 5025 { 5026 CloseHandle(file); 5027 return NULL; 5028 } 5029 5030 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); 5031 5032 CloseHandle(file); 5033 CloseHandle(mapping); 5034 return font; 5035 } 5036 5037 static void test_AddFontMemResource(void) 5038 { 5039 void *font; 5040 DWORD font_size, num_fonts; 5041 HANDLE ret; 5042 BOOL bRet; 5043 5044 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx) 5045 { 5046 win_skip("AddFontMemResourceEx is not available on this platform\n"); 5047 return; 5048 } 5049 5050 font = load_font("sserife.fon", &font_size); 5051 if (!font) 5052 { 5053 skip("Unable to locate and load font sserife.fon\n"); 5054 return; 5055 } 5056 5057 SetLastError(0xdeadbeef); 5058 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL); 5059 ok(!ret, "AddFontMemResourceEx should fail\n"); 5060 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5061 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5062 GetLastError()); 5063 5064 SetLastError(0xdeadbeef); 5065 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL); 5066 ok(!ret, "AddFontMemResourceEx should fail\n"); 5067 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5068 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5069 GetLastError()); 5070 5071 SetLastError(0xdeadbeef); 5072 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts); 5073 ok(!ret, "AddFontMemResourceEx should fail\n"); 5074 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5075 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5076 GetLastError()); 5077 5078 SetLastError(0xdeadbeef); 5079 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts); 5080 ok(!ret, "AddFontMemResourceEx should fail\n"); 5081 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5082 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5083 GetLastError()); 5084 5085 SetLastError(0xdeadbeef); 5086 ret = pAddFontMemResourceEx(font, 0, NULL, NULL); 5087 ok(!ret, "AddFontMemResourceEx should fail\n"); 5088 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5089 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5090 GetLastError()); 5091 5092 SetLastError(0xdeadbeef); 5093 ret = pAddFontMemResourceEx(font, 10, NULL, NULL); 5094 ok(!ret, "AddFontMemResourceEx should fail\n"); 5095 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5096 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5097 GetLastError()); 5098 5099 num_fonts = 0xdeadbeef; 5100 SetLastError(0xdeadbeef); 5101 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts); 5102 ok(!ret, "AddFontMemResourceEx should fail\n"); 5103 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5104 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5105 GetLastError()); 5106 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n"); 5107 5108 if (0) /* hangs under windows 2000 */ 5109 { 5110 num_fonts = 0xdeadbeef; 5111 SetLastError(0xdeadbeef); 5112 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts); 5113 ok(!ret, "AddFontMemResourceEx should fail\n"); 5114 ok(GetLastError() == 0xdeadbeef, 5115 "Expected GetLastError() to return 0xdeadbeef, got %u\n", 5116 GetLastError()); 5117 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n"); 5118 } 5119 5120 num_fonts = 0xdeadbeef; 5121 SetLastError(0xdeadbeef); 5122 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts); 5123 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError()); 5124 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n"); 5125 ok(num_fonts != 0, "number of loaded fonts should not be 0\n"); 5126 5127 free_font(font); 5128 5129 SetLastError(0xdeadbeef); 5130 bRet = pRemoveFontMemResourceEx(ret); 5131 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError()); 5132 5133 /* test invalid pointer to number of loaded fonts */ 5134 font = load_font("sserife.fon", &font_size); 5135 ok(font != NULL, "Unable to locate and load font sserife.fon\n"); 5136 5137 SetLastError(0xdeadbeef); 5138 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef); 5139 ok(!ret, "AddFontMemResourceEx should fail\n"); 5140 ok(GetLastError() == 0xdeadbeef, 5141 "Expected GetLastError() to return 0xdeadbeef, got %u\n", 5142 GetLastError()); 5143 5144 SetLastError(0xdeadbeef); 5145 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL); 5146 ok(!ret, "AddFontMemResourceEx should fail\n"); 5147 ok(GetLastError() == ERROR_INVALID_PARAMETER, 5148 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 5149 GetLastError()); 5150 5151 free_font(font); 5152 } 5153 5154 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam) 5155 { 5156 LOGFONTA *lf; 5157 5158 if (type != TRUETYPE_FONTTYPE) return 1; 5159 5160 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight); 5161 5162 lf = (LOGFONTA *)lparam; 5163 *lf = *elf; 5164 return 0; 5165 } 5166 5167 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam) 5168 { 5169 int ret; 5170 LOGFONTA *lf; 5171 5172 if (type != TRUETYPE_FONTTYPE) return 1; 5173 5174 lf = (LOGFONTA *)lparam; 5175 ret = strcmp(lf->lfFaceName, elf->lfFaceName); 5176 if(ret == 0) 5177 { 5178 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight); 5179 *lf = *elf; 5180 return 0; 5181 } 5182 return 1; 5183 } 5184 5185 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam) 5186 { 5187 return lparam; 5188 } 5189 5190 static void test_EnumFonts(void) 5191 { 5192 int ret; 5193 LOGFONTA lf; 5194 HDC hdc; 5195 5196 if (!is_truetype_font_installed("Arial")) 5197 { 5198 skip("Arial is not installed\n"); 5199 return; 5200 } 5201 5202 /* Windows uses localized font face names, so Arial Bold won't be found */ 5203 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH) 5204 { 5205 skip("User locale is not English, skipping the test\n"); 5206 return; 5207 } 5208 5209 hdc = CreateCompatibleDC(0); 5210 5211 /* check that the enumproc's retval is returned */ 5212 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe); 5213 ok(ret == 0xcafe, "got %08x\n", ret); 5214 5215 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf); 5216 ok(!ret, "font Arial is not enumerated\n"); 5217 ret = strcmp(lf.lfFaceName, "Arial"); 5218 ok(!ret, "expected Arial got %s\n", lf.lfFaceName); 5219 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight); 5220 5221 strcpy(lf.lfFaceName, "Arial"); 5222 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf); 5223 ok(!ret, "font Arial is not enumerated\n"); 5224 ret = strcmp(lf.lfFaceName, "Arial"); 5225 ok(!ret, "expected Arial got %s\n", lf.lfFaceName); 5226 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight); 5227 5228 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf); 5229 ok(!ret, "font Arial Bold is not enumerated\n"); 5230 ret = strcmp(lf.lfFaceName, "Arial"); 5231 ok(!ret, "expected Arial got %s\n", lf.lfFaceName); 5232 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight); 5233 5234 strcpy(lf.lfFaceName, "Arial Bold"); 5235 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf); 5236 ok(ret, "font Arial Bold should not be enumerated\n"); 5237 5238 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf); 5239 ok(!ret, "font Arial Bold Italic is not enumerated\n"); 5240 ret = strcmp(lf.lfFaceName, "Arial"); 5241 ok(!ret, "expected Arial got %s\n", lf.lfFaceName); 5242 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight); 5243 5244 strcpy(lf.lfFaceName, "Arial Bold Italic"); 5245 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf); 5246 ok(ret, "font Arial Bold Italic should not be enumerated\n"); 5247 5248 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf); 5249 ok(ret, "font Arial Italic Bold should not be enumerated\n"); 5250 5251 strcpy(lf.lfFaceName, "Arial Italic Bold"); 5252 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf); 5253 ok(ret, "font Arial Italic Bold should not be enumerated\n"); 5254 5255 DeleteDC(hdc); 5256 } 5257 5258 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 5259 { 5260 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam; 5261 5262 if (0) /* Disabled to limit console spam */ 5263 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n", 5264 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic); 5265 5266 if (type != TRUETYPE_FONTTYPE) return 1; 5267 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1; 5268 5269 if (efnd->total >= efnd->size) 5270 { 5271 efnd->size = max( (efnd->total + 1) * 2, 256 ); 5272 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) ); 5273 if (!efnd->elf) return 0; 5274 } 5275 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf; 5276 return 0; 5277 } 5278 5279 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 5280 { 5281 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam; 5282 5283 if (0) /* Disabled to limit console spam */ 5284 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n", 5285 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic); 5286 5287 if (type != TRUETYPE_FONTTYPE) return 1; 5288 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1; 5289 5290 if (efnd->total >= efnd->size) 5291 { 5292 efnd->size = max( (efnd->total + 1) * 2, 256 ); 5293 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) ); 5294 if (!efnd->elf) return 0; 5295 } 5296 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf; 5297 return 0; 5298 } 5299 5300 static void test_EnumFonts_subst(void) 5301 { 5302 int ret; 5303 LOGFONTA lf; 5304 HDC hdc; 5305 struct enum_fullname_data efnd; 5306 5307 ret = is_font_installed("MS Shell Dlg"); 5308 ok(ret, "MS Shell Dlg should be enumerated\n"); 5309 ret = is_truetype_font_installed("MS Shell Dlg"); 5310 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n"); 5311 5312 ret = is_font_installed("MS Shell Dlg 2"); 5313 ok(ret, "MS Shell Dlg 2 should be enumerated\n"); 5314 ret = is_truetype_font_installed("MS Shell Dlg 2"); 5315 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n"); 5316 5317 hdc = CreateCompatibleDC(0); 5318 5319 memset(&efnd, 0, sizeof(efnd)); 5320 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0); 5321 ok(ret, "MS Shell Dlg should not be enumerated\n"); 5322 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n"); 5323 5324 memset(&lf, 0, sizeof(lf)); 5325 lf.lfCharSet = DEFAULT_CHARSET; 5326 5327 efnd.total = 0; 5328 strcpy(lf.lfFaceName, "MS Shell Dlg"); 5329 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0); 5330 ok(!ret, "MS Shell Dlg should be enumerated\n"); 5331 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n"); 5332 if (efnd.total) 5333 { 5334 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg"); 5335 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName); 5336 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg"); 5337 ok(ret, "did not expect MS Shell Dlg\n"); 5338 } 5339 5340 efnd.total = 0; 5341 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0); 5342 ok(ret, "MS Shell Dlg 2 should not be enumerated\n"); 5343 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n"); 5344 5345 efnd.total = 0; 5346 strcpy(lf.lfFaceName, "MS Shell Dlg 2"); 5347 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0); 5348 ok(!ret, "MS Shell Dlg 2 should be enumerated\n"); 5349 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n"); 5350 if (efnd.total) 5351 { 5352 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2"); 5353 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName); 5354 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2"); 5355 ok(ret, "did not expect MS Shell Dlg 2\n"); 5356 } 5357 5358 heap_free(efnd.elf); 5359 DeleteDC(hdc); 5360 } 5361 5362 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) 5363 { 5364 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf; 5365 const char *fullname = (const char *)lParam; 5366 5367 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0; 5368 5369 return 1; 5370 } 5371 5372 static BOOL is_font_installed_fullname(const char *family, const char *fullname) 5373 { 5374 HDC hdc = GetDC(0); 5375 BOOL ret = FALSE; 5376 5377 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname)) 5378 ret = TRUE; 5379 5380 ReleaseDC(0, hdc); 5381 return ret; 5382 } 5383 5384 static void test_fullname(void) 5385 { 5386 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"}; 5387 WCHAR bufW[LF_FULLFACESIZE]; 5388 char bufA[LF_FULLFACESIZE]; 5389 HFONT hfont, of; 5390 LOGFONTA lf; 5391 HDC hdc; 5392 int i; 5393 DWORD ret; 5394 5395 hdc = CreateCompatibleDC(0); 5396 ok(hdc != NULL, "CreateCompatibleDC failed\n"); 5397 5398 memset(&lf, 0, sizeof(lf)); 5399 lf.lfCharSet = ANSI_CHARSET; 5400 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 5401 lf.lfHeight = 16; 5402 lf.lfWidth = 16; 5403 lf.lfQuality = DEFAULT_QUALITY; 5404 lf.lfItalic = FALSE; 5405 lf.lfWeight = FW_DONTCARE; 5406 5407 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++) 5408 { 5409 if (!is_font_installed_fullname("Lucida Sans", TestName[i])) 5410 { 5411 skip("%s is not installed\n", TestName[i]); 5412 continue; 5413 } 5414 5415 lstrcpyA(lf.lfFaceName, TestName[i]); 5416 hfont = CreateFontIndirectA(&lf); 5417 ok(hfont != 0, "CreateFontIndirectA failed\n"); 5418 5419 of = SelectObject(hdc, hfont); 5420 bufW[0] = 0; 5421 bufA[0] = 0; 5422 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES); 5423 ok(ret, "face full name could not be read\n"); 5424 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE); 5425 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA); 5426 SelectObject(hdc, of); 5427 DeleteObject(hfont); 5428 } 5429 DeleteDC(hdc); 5430 } 5431 5432 static WCHAR *prepend_at(WCHAR *family) 5433 { 5434 if (!family) 5435 return NULL; 5436 5437 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR)); 5438 family[0] = '@'; 5439 return family; 5440 } 5441 5442 static void test_fullname2_helper(const char *Family) 5443 { 5444 char *FamilyName, *FaceName, *StyleName, *otmStr; 5445 struct enum_fullname_data efnd; 5446 WCHAR *bufW; 5447 char *bufA; 5448 HFONT hfont, of; 5449 LOGFONTA lf; 5450 HDC hdc; 5451 int i; 5452 DWORD otm_size, ret, buf_size; 5453 OUTLINETEXTMETRICA *otm; 5454 BOOL want_vertical, get_vertical; 5455 want_vertical = ( Family[0] == '@' ); 5456 5457 hdc = CreateCompatibleDC(0); 5458 ok(hdc != NULL, "CreateCompatibleDC failed\n"); 5459 5460 memset(&lf, 0, sizeof(lf)); 5461 lf.lfCharSet = DEFAULT_CHARSET; 5462 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 5463 lf.lfHeight = 16; 5464 lf.lfWidth = 16; 5465 lf.lfQuality = DEFAULT_QUALITY; 5466 lf.lfItalic = FALSE; 5467 lf.lfWeight = FW_DONTCARE; 5468 strcpy(lf.lfFaceName, Family); 5469 memset(&efnd, 0, sizeof(efnd)); 5470 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0); 5471 if (efnd.total == 0) 5472 skip("%s is not installed\n", lf.lfFaceName); 5473 5474 for (i = 0; i < efnd.total; i++) 5475 { 5476 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName; 5477 FaceName = (char *)efnd.elf[i].elfFullName; 5478 StyleName = (char *)efnd.elf[i].elfStyle; 5479 5480 get_vertical = ( FamilyName[0] == '@' ); 5481 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName); 5482 5483 lstrcpyA(lf.lfFaceName, FaceName); 5484 hfont = CreateFontIndirectA(&lf); 5485 ok(hfont != 0, "CreateFontIndirectA failed\n"); 5486 5487 of = SelectObject(hdc, hfont); 5488 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0); 5489 ok(buf_size != GDI_ERROR, "no name table found\n"); 5490 if (buf_size == GDI_ERROR) continue; 5491 5492 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size); 5493 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size); 5494 5495 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL); 5496 otm = HeapAlloc(GetProcessHeap(), 0, otm_size); 5497 memset(otm, 0, otm_size); 5498 ret = GetOutlineTextMetricsA(hdc, otm_size, otm); 5499 ok(ret != 0, "GetOutlineTextMetrics fails!\n"); 5500 if (ret == 0) continue; 5501 5502 bufW[0] = 0; 5503 bufA[0] = 0; 5504 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID()); 5505 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES); 5506 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName); 5507 if (want_vertical) bufW = prepend_at(bufW); 5508 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE); 5509 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA); 5510 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName; 5511 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr); 5512 5513 bufW[0] = 0; 5514 bufA[0] = 0; 5515 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID()); 5516 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES); 5517 ok(ret, "FULL_NAME (face name) could not be read\n"); 5518 if (want_vertical) bufW = prepend_at(bufW); 5519 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE); 5520 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA); 5521 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName; 5522 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr); 5523 5524 bufW[0] = 0; 5525 bufA[0] = 0; 5526 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID()); 5527 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES); 5528 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName); 5529 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE); 5530 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA); 5531 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName; 5532 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr); 5533 5534 bufW[0] = 0; 5535 bufA[0] = 0; 5536 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID()); 5537 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES); 5538 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName); 5539 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE); 5540 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName; 5541 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA); 5542 5543 SelectObject(hdc, of); 5544 DeleteObject(hfont); 5545 5546 HeapFree(GetProcessHeap(), 0, otm); 5547 HeapFree(GetProcessHeap(), 0, bufW); 5548 HeapFree(GetProcessHeap(), 0, bufA); 5549 } 5550 heap_free(efnd.elf); 5551 DeleteDC(hdc); 5552 } 5553 5554 static void test_fullname2(void) 5555 { 5556 test_fullname2_helper("Arial"); 5557 test_fullname2_helper("DejaVu Sans"); 5558 test_fullname2_helper("Lucida Sans"); 5559 test_fullname2_helper("Tahoma"); 5560 test_fullname2_helper("Webdings"); 5561 test_fullname2_helper("Wingdings"); 5562 test_fullname2_helper("SimSun"); 5563 test_fullname2_helper("NSimSun"); 5564 test_fullname2_helper("MingLiu"); 5565 test_fullname2_helper("PMingLiu"); 5566 test_fullname2_helper("WenQuanYi Micro Hei"); 5567 test_fullname2_helper("MS UI Gothic"); 5568 test_fullname2_helper("Ume UI Gothic"); 5569 test_fullname2_helper("MS Gothic"); 5570 test_fullname2_helper("Ume Gothic"); 5571 test_fullname2_helper("MS PGothic"); 5572 test_fullname2_helper("Ume P Gothic"); 5573 test_fullname2_helper("Gulim"); 5574 test_fullname2_helper("Batang"); 5575 test_fullname2_helper("UnBatang"); 5576 test_fullname2_helper("UnDotum"); 5577 test_fullname2_helper("@SimSun"); 5578 test_fullname2_helper("@NSimSun"); 5579 test_fullname2_helper("@MingLiu"); 5580 test_fullname2_helper("@PMingLiu"); 5581 test_fullname2_helper("@WenQuanYi Micro Hei"); 5582 test_fullname2_helper("@MS UI Gothic"); 5583 test_fullname2_helper("@Ume UI Gothic"); 5584 test_fullname2_helper("@MS Gothic"); 5585 test_fullname2_helper("@Ume Gothic"); 5586 test_fullname2_helper("@MS PGothic"); 5587 test_fullname2_helper("@Ume P Gothic"); 5588 test_fullname2_helper("@Gulim"); 5589 test_fullname2_helper("@Batang"); 5590 test_fullname2_helper("@UnBatang"); 5591 test_fullname2_helper("@UnDotum"); 5592 5593 } 5594 5595 static void test_GetGlyphOutline_empty_contour(void) 5596 { 5597 HDC hdc; 5598 LOGFONTA lf; 5599 HFONT hfont, hfont_prev; 5600 TTPOLYGONHEADER *header; 5601 GLYPHMETRICS gm; 5602 char buf[1024]; 5603 DWORD ret; 5604 5605 memset(&lf, 0, sizeof(lf)); 5606 lf.lfHeight = 72; 5607 lstrcpyA(lf.lfFaceName, "wine_test"); 5608 5609 hfont = CreateFontIndirectA(&lf); 5610 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); 5611 5612 hdc = GetDC(NULL); 5613 5614 hfont_prev = SelectObject(hdc, hfont); 5615 ok(hfont_prev != NULL, "SelectObject failed\n"); 5616 5617 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat); 5618 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret); 5619 5620 header = (TTPOLYGONHEADER*)buf; 5621 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat); 5622 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret); 5623 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb); 5624 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType); 5625 header = (TTPOLYGONHEADER*)((char*)header+header->cb); 5626 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb); 5627 header = (TTPOLYGONHEADER*)((char*)header+header->cb); 5628 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb); 5629 5630 SelectObject(hdc, hfont_prev); 5631 DeleteObject(hfont); 5632 ReleaseDC(NULL, hdc); 5633 } 5634 5635 static void test_GetGlyphOutline_metric_clipping(void) 5636 { 5637 HDC hdc; 5638 LOGFONTA lf; 5639 HFONT hfont, hfont_prev; 5640 GLYPHMETRICS gm; 5641 TEXTMETRICA tm; 5642 TEXTMETRICW tmW; 5643 DWORD ret; 5644 5645 memset(&lf, 0, sizeof(lf)); 5646 lf.lfHeight = 72; 5647 lstrcpyA(lf.lfFaceName, "wine_test"); 5648 5649 SetLastError(0xdeadbeef); 5650 hfont = CreateFontIndirectA(&lf); 5651 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); 5652 5653 hdc = GetDC(NULL); 5654 5655 hfont_prev = SelectObject(hdc, hfont); 5656 ok(hfont_prev != NULL, "SelectObject failed\n"); 5657 5658 SetLastError(0xdeadbeef); 5659 ret = GetTextMetricsA(hdc, &tm); 5660 ok(ret, "GetTextMetrics error %u\n", GetLastError()); 5661 5662 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); 5663 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent, 5664 "Glyph top(%d) exceeds ascent(%d)\n", 5665 gm.gmptGlyphOrigin.y, tm.tmAscent); 5666 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat); 5667 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent, 5668 "Glyph bottom(%d) exceeds descent(%d)\n", 5669 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent); 5670 5671 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */ 5672 GetTextMetricsW(hdc, &tmW); 5673 todo_wine 5674 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar); 5675 5676 SelectObject(hdc, hfont_prev); 5677 DeleteObject(hfont); 5678 ReleaseDC(NULL, hdc); 5679 } 5680 5681 static void test_fstype_fixup(void) 5682 { 5683 HDC hdc; 5684 LOGFONTA lf; 5685 HFONT hfont, hfont_prev; 5686 DWORD ret; 5687 OUTLINETEXTMETRICA *otm; 5688 DWORD otm_size; 5689 5690 memset(&lf, 0, sizeof(lf)); 5691 lf.lfHeight = 72; 5692 lstrcpyA(lf.lfFaceName, "wine_test"); 5693 5694 SetLastError(0xdeadbeef); 5695 hfont = CreateFontIndirectA(&lf); 5696 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); 5697 5698 hdc = GetDC(NULL); 5699 5700 hfont_prev = SelectObject(hdc, hfont); 5701 ok(hfont_prev != NULL, "SelectObject failed\n"); 5702 5703 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL); 5704 otm = HeapAlloc(GetProcessHeap(), 0, otm_size); 5705 otm->otmSize = sizeof(*otm); 5706 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm); 5707 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError()); 5708 5709 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out, 5710 valid bits are 1, 2, 3, 8, 9. */ 5711 ok((otm->otmfsType & ~0x30e) == 0, "fsType %#x\n", otm->otmfsType); 5712 5713 HeapFree(GetProcessHeap(), 0, otm); 5714 5715 SelectObject(hdc, hfont_prev); 5716 DeleteObject(hfont); 5717 ReleaseDC(NULL, hdc); 5718 } 5719 5720 static void test_CreateScalableFontResource(void) 5721 { 5722 char ttf_name[MAX_PATH]; 5723 char tmp_path[MAX_PATH]; 5724 char fot_name[MAX_PATH]; 5725 char *file_part; 5726 DWORD ret; 5727 int i; 5728 5729 if (!pAddFontResourceExA || !pRemoveFontResourceExA) 5730 { 5731 win_skip("AddFontResourceExA is not available on this platform\n"); 5732 return; 5733 } 5734 5735 if (!write_ttf_file("wine_test.ttf", ttf_name)) 5736 { 5737 skip("Failed to create ttf file for testing\n"); 5738 return; 5739 } 5740 5741 trace("created %s\n", ttf_name); 5742 5743 ret = is_truetype_font_installed("wine_test"); 5744 ok(!ret, "font wine_test should not be enumerated\n"); 5745 5746 ret = GetTempPathA(MAX_PATH, tmp_path); 5747 ok(ret, "GetTempPath() error %d\n", GetLastError()); 5748 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name); 5749 ok(ret, "GetTempFileName() error %d\n", GetLastError()); 5750 5751 ret = GetFileAttributesA(fot_name); 5752 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name); 5753 5754 SetLastError(0xdeadbeef); 5755 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL); 5756 ok(!ret, "CreateScalableFontResource() should fail\n"); 5757 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError()); 5758 5759 SetLastError(0xdeadbeef); 5760 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, ""); 5761 ok(!ret, "CreateScalableFontResource() should fail\n"); 5762 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError()); 5763 5764 file_part = strrchr(ttf_name, '\\'); 5765 SetLastError(0xdeadbeef); 5766 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path); 5767 ok(!ret, "CreateScalableFontResource() should fail\n"); 5768 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError()); 5769 5770 SetLastError(0xdeadbeef); 5771 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path); 5772 ok(!ret, "CreateScalableFontResource() should fail\n"); 5773 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError()); 5774 5775 SetLastError(0xdeadbeef); 5776 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name); 5777 ok(!ret, "CreateScalableFontResource() should fail\n"); 5778 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError()); 5779 5780 ret = DeleteFileA(fot_name); 5781 ok(ret, "DeleteFile() error %d\n", GetLastError()); 5782 5783 ret = pRemoveFontResourceExA(fot_name, 0, 0); 5784 ok(!ret, "RemoveFontResourceEx() should fail\n"); 5785 5786 /* test public font resource */ 5787 SetLastError(0xdeadbeef); 5788 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL); 5789 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError()); 5790 5791 ret = is_truetype_font_installed("wine_test"); 5792 ok(!ret, "font wine_test should not be enumerated\n"); 5793 5794 SetLastError(0xdeadbeef); 5795 ret = pAddFontResourceExA(fot_name, 0, 0); 5796 ok(ret, "AddFontResourceEx() error %d\n", GetLastError()); 5797 5798 ret = is_truetype_font_installed("wine_test"); 5799 ok(ret, "font wine_test should be enumerated\n"); 5800 5801 test_GetGlyphOutline_empty_contour(); 5802 test_GetGlyphOutline_metric_clipping(); 5803 test_fstype_fixup(); 5804 5805 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0); 5806 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n"); 5807 5808 SetLastError(0xdeadbeef); 5809 ret = pRemoveFontResourceExA(fot_name, 0, 0); 5810 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError()); 5811 5812 ret = is_truetype_font_installed("wine_test"); 5813 ok(!ret, "font wine_test should not be enumerated\n"); 5814 5815 ret = pRemoveFontResourceExA(fot_name, 0, 0); 5816 ok(!ret, "RemoveFontResourceEx() should fail\n"); 5817 5818 /* test refcounting */ 5819 for (i = 0; i < 5; i++) 5820 { 5821 SetLastError(0xdeadbeef); 5822 ret = pAddFontResourceExA(fot_name, 0, 0); 5823 ok(ret, "AddFontResourceEx() error %d\n", GetLastError()); 5824 } 5825 for (i = 0; i < 5; i++) 5826 { 5827 SetLastError(0xdeadbeef); 5828 ret = pRemoveFontResourceExA(fot_name, 0, 0); 5829 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError()); 5830 } 5831 ret = pRemoveFontResourceExA(fot_name, 0, 0); 5832 ok(!ret, "RemoveFontResourceEx() should fail\n"); 5833 5834 DeleteFileA(fot_name); 5835 5836 /* test hidden font resource */ 5837 SetLastError(0xdeadbeef); 5838 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL); 5839 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError()); 5840 5841 ret = is_truetype_font_installed("wine_test"); 5842 ok(!ret, "font wine_test should not be enumerated\n"); 5843 5844 SetLastError(0xdeadbeef); 5845 ret = pAddFontResourceExA(fot_name, 0, 0); 5846 ok(ret, "AddFontResourceEx() error %d\n", GetLastError()); 5847 5848 ret = is_truetype_font_installed("wine_test"); 5849 todo_wine 5850 ok(!ret, "font wine_test should not be enumerated\n"); 5851 5852 /* XP allows removing a private font added with 0 flags */ 5853 SetLastError(0xdeadbeef); 5854 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0); 5855 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError()); 5856 5857 ret = is_truetype_font_installed("wine_test"); 5858 ok(!ret, "font wine_test should not be enumerated\n"); 5859 5860 ret = pRemoveFontResourceExA(fot_name, 0, 0); 5861 ok(!ret, "RemoveFontResourceEx() should fail\n"); 5862 5863 DeleteFileA(fot_name); 5864 DeleteFileA(ttf_name); 5865 } 5866 5867 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi) 5868 { 5869 LOGFONTA lf; 5870 HFONT hfont, hfont_prev; 5871 HDC hdc; 5872 char facename[100]; 5873 DWORD ret; 5874 static const WCHAR str[] = { 0x2025 }; 5875 5876 *installed = is_truetype_font_installed(name); 5877 5878 lf.lfHeight = -18; 5879 lf.lfWidth = 0; 5880 lf.lfEscapement = 0; 5881 lf.lfOrientation = 0; 5882 lf.lfWeight = FW_DONTCARE; 5883 lf.lfItalic = 0; 5884 lf.lfUnderline = 0; 5885 lf.lfStrikeOut = 0; 5886 lf.lfCharSet = DEFAULT_CHARSET; 5887 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS; 5888 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 5889 lf.lfQuality = DEFAULT_QUALITY; 5890 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; 5891 strcpy(lf.lfFaceName, name); 5892 5893 hfont = CreateFontIndirectA(&lf); 5894 ok(hfont != NULL, "CreateFontIndirectA failed\n"); 5895 5896 hdc = GetDC(NULL); 5897 5898 hfont_prev = SelectObject(hdc, hfont); 5899 ok(hfont_prev != NULL, "SelectObject failed\n"); 5900 5901 ret = GetTextFaceA(hdc, sizeof facename, facename); 5902 ok(ret, "GetTextFaceA failed\n"); 5903 *selected = !strcmp(facename, name); 5904 5905 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat); 5906 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n"); 5907 if (!*selected) 5908 memset(gm, 0, sizeof *gm); 5909 5910 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0); 5911 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n"); 5912 5913 SelectObject(hdc, hfont_prev); 5914 DeleteObject(hfont); 5915 ReleaseDC(NULL, hdc); 5916 } 5917 5918 static void check_vertical_metrics(const char *face) 5919 { 5920 LOGFONTA lf; 5921 HFONT hfont, hfont_prev; 5922 HDC hdc; 5923 DWORD ret; 5924 GLYPHMETRICS rgm, vgm; 5925 const UINT code = 0x5EAD, height = 1000; 5926 WORD idx; 5927 ABC abc; 5928 OUTLINETEXTMETRICA otm; 5929 USHORT numOfLongVerMetrics; 5930 5931 hdc = GetDC(NULL); 5932 5933 memset(&lf, 0, sizeof(lf)); 5934 strcpy(lf.lfFaceName, face); 5935 lf.lfHeight = -height; 5936 lf.lfCharSet = DEFAULT_CHARSET; 5937 lf.lfEscapement = lf.lfOrientation = 900; 5938 hfont = CreateFontIndirectA(&lf); 5939 hfont_prev = SelectObject(hdc, hfont); 5940 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat); 5941 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n"); 5942 ret = GetCharABCWidthsW(hdc, code, code, &abc); 5943 ok(ret, "GetCharABCWidthsW failed\n"); 5944 DeleteObject(SelectObject(hdc, hfont_prev)); 5945 5946 memset(&lf, 0, sizeof(lf)); 5947 strcpy(lf.lfFaceName, "@"); 5948 strcat(lf.lfFaceName, face); 5949 lf.lfHeight = -height; 5950 lf.lfCharSet = DEFAULT_CHARSET; 5951 hfont = CreateFontIndirectA(&lf); 5952 hfont_prev = SelectObject(hdc, hfont); 5953 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat); 5954 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n"); 5955 5956 memset(&otm, 0, sizeof(otm)); 5957 otm.otmSize = sizeof(otm); 5958 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm); 5959 ok(ret != 0, "GetOutlineTextMetricsA failed\n"); 5960 5961 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17, 5962 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) { 5963 int offset; 5964 SHORT topSideBearing; 5965 5966 if (!pGetGlyphIndicesW) { 5967 win_skip("GetGlyphIndices is not available on this platform\n"); 5968 } 5969 else { 5970 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0); 5971 ok(ret != 0, "GetGlyphIndicesW failed\n"); 5972 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics); 5973 if (numOfLongVerMetrics > idx) 5974 offset = idx * 2 + 1; 5975 else 5976 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics); 5977 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT), 5978 &topSideBearing, sizeof(SHORT)); 5979 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n"); 5980 topSideBearing = GET_BE_WORD(topSideBearing); 5981 ok(match_off_by_1(vgm.gmptGlyphOrigin.x, 5982 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE), 5983 "expected %d, got %d\n", 5984 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x); 5985 } 5986 } 5987 else 5988 { 5989 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent, 5990 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n", 5991 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent); 5992 } 5993 5994 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent || 5995 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */, 5996 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n", 5997 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent); 5998 5999 DeleteObject(SelectObject(hdc, hfont_prev)); 6000 ReleaseDC(NULL, hdc); 6001 } 6002 6003 static void test_vertical_font(void) 6004 { 6005 char ttf_name[MAX_PATH]; 6006 int num, i; 6007 BOOL ret, installed, selected; 6008 GLYPHMETRICS gm; 6009 WORD hgi, vgi; 6010 const char* face_list[] = { 6011 "@WineTestVertical", /* has vmtx table */ 6012 "@Ume Gothic", /* doesn't have vmtx table */ 6013 "@MS UI Gothic", /* has vmtx table, available on native */ 6014 }; 6015 6016 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW) 6017 { 6018 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n"); 6019 return; 6020 } 6021 6022 if (!write_ttf_file("vertical.ttf", ttf_name)) 6023 { 6024 skip("Failed to create ttf file for testing\n"); 6025 return; 6026 } 6027 6028 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0); 6029 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n"); 6030 6031 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi); 6032 ok(installed, "WineTestVertical is not installed\n"); 6033 ok(selected, "WineTestVertical is not selected\n"); 6034 ok(gm.gmBlackBoxX > gm.gmBlackBoxY, 6035 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n", 6036 gm.gmBlackBoxX, gm.gmBlackBoxY); 6037 6038 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi); 6039 ok(installed, "@WineTestVertical is not installed\n"); 6040 ok(selected, "@WineTestVertical is not selected\n"); 6041 ok(gm.gmBlackBoxX > gm.gmBlackBoxY, 6042 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n", 6043 gm.gmBlackBoxX, gm.gmBlackBoxY); 6044 6045 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi); 6046 6047 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) { 6048 const char* face = face_list[i]; 6049 if (!is_truetype_font_installed(face)) { 6050 skip("%s is not installed\n", face); 6051 continue; 6052 } 6053 trace("Testing %s...\n", face); 6054 check_vertical_metrics(&face[1]); 6055 } 6056 6057 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0); 6058 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError()); 6059 6060 DeleteFileA(ttf_name); 6061 } 6062 6063 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, 6064 DWORD type, LPARAM lParam) 6065 { 6066 if (lf->lfFaceName[0] == '@') { 6067 return 0; 6068 } 6069 return 1; 6070 } 6071 6072 static void test_east_asian_font_selection(void) 6073 { 6074 HDC hdc; 6075 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET, 6076 GB2312_CHARSET, CHINESEBIG5_CHARSET }; 6077 size_t i; 6078 6079 hdc = GetDC(NULL); 6080 6081 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++) 6082 { 6083 LOGFONTA lf; 6084 HFONT hfont; 6085 char face_name[LF_FACESIZE]; 6086 int ret; 6087 6088 memset(&lf, 0, sizeof lf); 6089 lf.lfFaceName[0] = '\0'; 6090 lf.lfCharSet = charset[i]; 6091 6092 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0)) 6093 { 6094 skip("Vertical font for charset %u is not installed\n", charset[i]); 6095 continue; 6096 } 6097 6098 hfont = CreateFontIndirectA(&lf); 6099 hfont = SelectObject(hdc, hfont); 6100 memset(face_name, 0, sizeof face_name); 6101 ret = GetTextFaceA(hdc, sizeof face_name, face_name); 6102 ok(ret && face_name[0] != '@', 6103 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name); 6104 DeleteObject(SelectObject(hdc, hfont)); 6105 6106 memset(&lf, 0, sizeof lf); 6107 strcpy(lf.lfFaceName, "@"); 6108 lf.lfCharSet = charset[i]; 6109 hfont = CreateFontIndirectA(&lf); 6110 hfont = SelectObject(hdc, hfont); 6111 memset(face_name, 0, sizeof face_name); 6112 ret = GetTextFaceA(hdc, sizeof face_name, face_name); 6113 ok(ret && face_name[0] == '@', 6114 "expected vertical face for charset %u, got %s\n", charset[i], face_name); 6115 DeleteObject(SelectObject(hdc, hfont)); 6116 } 6117 ReleaseDC(NULL, hdc); 6118 } 6119 6120 static int get_font_dpi(const LOGFONTA *lf, int *height) 6121 { 6122 HDC hdc = CreateCompatibleDC(0); 6123 HFONT hfont; 6124 TEXTMETRICA tm; 6125 int ret; 6126 6127 hfont = CreateFontIndirectA(lf); 6128 ok(hfont != 0, "CreateFontIndirect failed\n"); 6129 6130 SelectObject(hdc, hfont); 6131 ret = GetTextMetricsA(hdc, &tm); 6132 ok(ret, "GetTextMetrics failed\n"); 6133 ret = tm.tmDigitizedAspectX; 6134 if (height) *height = tm.tmHeight; 6135 6136 DeleteDC(hdc); 6137 DeleteObject(hfont); 6138 6139 return ret; 6140 } 6141 6142 static void test_stock_fonts(void) 6143 { 6144 static const int font[] = 6145 { 6146 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT 6147 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */ 6148 }; 6149 static const struct test_data 6150 { 6151 int charset, weight, height, height_pixels, dpi; 6152 const char face_name[LF_FACESIZE]; 6153 WORD lang_id; 6154 } td[][12] = 6155 { 6156 { /* ANSI_FIXED_FONT */ 6157 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC }, 6158 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_HEBREW}, 6159 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" }, 6160 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" }, 6161 { 0 } 6162 }, 6163 { /* ANSI_VAR_FONT */ 6164 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" }, 6165 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" }, 6166 { 0 } 6167 }, 6168 { /* SYSTEM_FONT */ 6169 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" }, 6170 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" }, 6171 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" }, 6172 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" }, 6173 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" }, 6174 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" }, 6175 { 0 } 6176 }, 6177 { /* DEVICE_DEFAULT_FONT */ 6178 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" }, 6179 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" }, 6180 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" }, 6181 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" }, 6182 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" }, 6183 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" }, 6184 { 0 } 6185 }, 6186 { /* DEFAULT_GUI_FONT */ 6187 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" }, 6188 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" }, 6189 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" }, 6190 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" }, 6191 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" }, 6192 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" }, 6193 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" }, 6194 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" }, 6195 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" }, 6196 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" }, 6197 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" }, 6198 { 0 } 6199 } 6200 }; 6201 int i, j; 6202 6203 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++) 6204 { 6205 HFONT hfont; 6206 LOGFONTA lf; 6207 int ret, height; 6208 6209 hfont = GetStockObject(font[i]); 6210 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]); 6211 6212 ret = GetObjectA(hfont, sizeof(lf), &lf); 6213 if (ret != sizeof(lf)) 6214 { 6215 /* NT4 */ 6216 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret); 6217 continue; 6218 } 6219 6220 for (j = 0; td[i][j].face_name[0] != 0; j++) 6221 { 6222 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) || 6223 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) || 6224 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name))) 6225 { 6226 continue; 6227 } 6228 6229 ret = get_font_dpi(&lf, &height); 6230 if (ret != td[i][j].dpi) 6231 { 6232 trace("%d(%d): font %s %d dpi doesn't match test data %d\n", 6233 i, j, lf.lfFaceName, ret, td[i][j].dpi); 6234 continue; 6235 } 6236 6237 /* FIXME: Remove once Wine is fixed */ 6238 todo_wine_if (td[i][j].dpi != 96 && 6239 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */ 6240 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) || 6241 /* System for 120 dpi and higher should include 20 pixel bitmap set */ 6242 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16))) 6243 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height); 6244 6245 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight); 6246 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight); 6247 if (td[i][j].face_name[0] == '?') 6248 { 6249 /* Wine doesn't have this font, skip this case for now. 6250 Actually, the face name is localized on Windows and varies 6251 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */ 6252 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName); 6253 } 6254 else 6255 { 6256 ok(!strcmp(td[i][j].face_name, lf.lfFaceName), "%d(%d): expected lfFaceName %s, got %s\n", i, j, td[i][j].face_name, lf.lfFaceName); 6257 } 6258 break; 6259 } 6260 } 6261 } 6262 6263 static void test_max_height(void) 6264 { 6265 HDC hdc; 6266 LOGFONTA lf; 6267 HFONT hfont, hfont_old; 6268 TEXTMETRICA tm1, tm; 6269 BOOL r; 6270 LONG invalid_height[] = { -65536, -123456, 123456 }; 6271 size_t i; 6272 6273 memset(&tm1, 0, sizeof(tm1)); 6274 memset(&lf, 0, sizeof(lf)); 6275 strcpy(lf.lfFaceName, "Tahoma"); 6276 lf.lfHeight = -1; 6277 6278 hdc = GetDC(NULL); 6279 6280 /* get 1 ppem value */ 6281 hfont = CreateFontIndirectA(&lf); 6282 hfont_old = SelectObject(hdc, hfont); 6283 r = GetTextMetricsA(hdc, &tm1); 6284 ok(r, "GetTextMetrics failed\n"); 6285 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight); 6286 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight); 6287 DeleteObject(SelectObject(hdc, hfont_old)); 6288 6289 /* test the largest value */ 6290 lf.lfHeight = -((1 << 16) - 1); 6291 hfont = CreateFontIndirectA(&lf); 6292 hfont_old = SelectObject(hdc, hfont); 6293 memset(&tm, 0, sizeof(tm)); 6294 r = GetTextMetricsA(hdc, &tm); 6295 ok(r, "GetTextMetrics failed\n"); 6296 ok(tm.tmHeight > tm1.tmHeight, 6297 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight); 6298 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth, 6299 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth); 6300 DeleteObject(SelectObject(hdc, hfont_old)); 6301 6302 /* test an invalid value */ 6303 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) { 6304 lf.lfHeight = invalid_height[i]; 6305 hfont = CreateFontIndirectA(&lf); 6306 hfont_old = SelectObject(hdc, hfont); 6307 memset(&tm, 0, sizeof(tm)); 6308 r = GetTextMetricsA(hdc, &tm); 6309 ok(r, "GetTextMetrics failed\n"); 6310 ok(tm.tmHeight == tm1.tmHeight, 6311 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight); 6312 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth, 6313 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth); 6314 DeleteObject(SelectObject(hdc, hfont_old)); 6315 } 6316 6317 ReleaseDC(NULL, hdc); 6318 return; 6319 } 6320 6321 static void test_vertical_order(void) 6322 { 6323 struct enum_font_data efd; 6324 LOGFONTA lf; 6325 HDC hdc; 6326 int i, j; 6327 6328 hdc = CreateCompatibleDC(0); 6329 ok(hdc != NULL, "CreateCompatibleDC failed\n"); 6330 6331 memset(&lf, 0, sizeof(lf)); 6332 lf.lfCharSet = DEFAULT_CHARSET; 6333 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 6334 lf.lfHeight = 16; 6335 lf.lfWidth = 16; 6336 lf.lfQuality = DEFAULT_QUALITY; 6337 lf.lfItalic = FALSE; 6338 lf.lfWeight = FW_DONTCARE; 6339 memset( &efd, 0, sizeof(efd) ); 6340 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0); 6341 for (i = 0; i < efd.total; i++) 6342 { 6343 if (efd.lf[i].lfFaceName[0] != '@') continue; 6344 for (j = 0; j < efd.total; j++) 6345 { 6346 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName)) 6347 { 6348 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName); 6349 break; 6350 } 6351 } 6352 } 6353 heap_free( efd.lf ); 6354 DeleteDC( hdc ); 6355 } 6356 6357 static void test_GetCharWidth32(void) 6358 { 6359 BOOL ret; 6360 HDC hdc; 6361 LOGFONTA lf; 6362 HFONT hfont; 6363 INT bufferA; 6364 INT bufferW; 6365 HWND hwnd; 6366 6367 if (!pGetCharWidth32A || !pGetCharWidth32W) 6368 { 6369 win_skip("GetCharWidth32A/W not available on this platform\n"); 6370 return; 6371 } 6372 6373 memset(&lf, 0, sizeof(lf)); 6374 strcpy(lf.lfFaceName, "System"); 6375 lf.lfHeight = 20; 6376 6377 hfont = CreateFontIndirectA(&lf); 6378 hdc = GetDC(0); 6379 hfont = SelectObject(hdc, hfont); 6380 6381 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6382 ok(ret, "GetCharWidth32W should have succeeded\n"); 6383 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA); 6384 ok(ret, "GetCharWidth32A should have succeeded\n"); 6385 ok (bufferA == bufferW, "Widths should be the same\n"); 6386 ok (bufferA > 0," Width should be greater than zero\n"); 6387 6388 hfont = SelectObject(hdc, hfont); 6389 DeleteObject(hfont); 6390 ReleaseDC(NULL, hdc); 6391 6392 memset(&lf, 0, sizeof(lf)); 6393 strcpy(lf.lfFaceName, "Tahoma"); 6394 lf.lfHeight = 20; 6395 6396 hfont = CreateFontIndirectA(&lf); 6397 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100, 6398 0, 0, 0, NULL); 6399 hdc = GetDC(hwnd); 6400 SetMapMode( hdc, MM_ANISOTROPIC ); 6401 SelectObject(hdc, hfont); 6402 6403 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6404 ok(ret, "GetCharWidth32W should have succeeded\n"); 6405 ok (bufferW > 0," Width should be greater than zero\n"); 6406 SetWindowExtEx(hdc, -1,-1,NULL); 6407 SetGraphicsMode(hdc, GM_COMPATIBLE); 6408 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6409 ok(ret, "GetCharWidth32W should have succeeded\n"); 6410 ok (bufferW > 0," Width should be greater than zero\n"); 6411 SetGraphicsMode(hdc, GM_ADVANCED); 6412 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6413 ok(ret, "GetCharWidth32W should have succeeded\n"); 6414 todo_wine ok (bufferW > 0," Width should be greater than zero\n"); 6415 SetWindowExtEx(hdc, 1,1,NULL); 6416 SetGraphicsMode(hdc, GM_COMPATIBLE); 6417 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6418 ok(ret, "GetCharWidth32W should have succeeded\n"); 6419 ok (bufferW > 0," Width should be greater than zero\n"); 6420 SetGraphicsMode(hdc, GM_ADVANCED); 6421 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6422 ok(ret, "GetCharWidth32W should have succeeded\n"); 6423 ok (bufferW > 0," Width should be greater than zero\n"); 6424 6425 ReleaseDC(hwnd, hdc); 6426 DestroyWindow(hwnd); 6427 6428 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100, 6429 0, 0, 0, NULL); 6430 hdc = GetDC(hwnd); 6431 SetMapMode( hdc, MM_ANISOTROPIC ); 6432 SelectObject(hdc, hfont); 6433 6434 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6435 ok(ret, "GetCharWidth32W should have succeeded\n"); 6436 ok (bufferW > 0," Width should be greater than zero\n"); 6437 SetWindowExtEx(hdc, -1,-1,NULL); 6438 SetGraphicsMode(hdc, GM_COMPATIBLE); 6439 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6440 ok(ret, "GetCharWidth32W should have succeeded\n"); 6441 ok (bufferW > 0," Width should be greater than zero\n"); 6442 SetGraphicsMode(hdc, GM_ADVANCED); 6443 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6444 ok(ret, "GetCharWidth32W should have succeeded\n"); 6445 ok (bufferW > 0," Width should be greater than zero\n"); 6446 SetWindowExtEx(hdc, 1,1,NULL); 6447 SetGraphicsMode(hdc, GM_COMPATIBLE); 6448 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6449 ok(ret, "GetCharWidth32W should have succeeded\n"); 6450 ok (bufferW > 0," Width should be greater than zero\n"); 6451 SetGraphicsMode(hdc, GM_ADVANCED); 6452 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW); 6453 ok(ret, "GetCharWidth32W should have succeeded\n"); 6454 todo_wine ok (bufferW > 0," Width should be greater than zero\n"); 6455 6456 ReleaseDC(hwnd, hdc); 6457 DestroyWindow(hwnd); 6458 DeleteObject(hfont); 6459 } 6460 6461 static void test_fake_bold_font(void) 6462 { 6463 static const MAT2 x2_mat = { {0,2}, {0,0}, {0,0}, {0,2} }; 6464 HDC hdc; 6465 LOGFONTA lf; 6466 BOOL ret; 6467 struct glyph_data { 6468 TEXTMETRICA tm; 6469 ABC abc; 6470 INT w; 6471 GLYPHMETRICS gm; 6472 } data[2]; 6473 int i; 6474 DWORD r; 6475 6476 if (!pGetCharWidth32A || !pGetCharABCWidthsA) { 6477 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n"); 6478 return; 6479 } 6480 6481 /* Test outline font */ 6482 memset(&lf, 0, sizeof(lf)); 6483 strcpy(lf.lfFaceName, "Wingdings"); 6484 lf.lfCharSet = SYMBOL_CHARSET; 6485 6486 hdc = GetDC(NULL); 6487 6488 for (i = 0; i <= 1; i++) 6489 { 6490 HFONT hfont, hfont_old; 6491 6492 lf.lfWeight = i ? FW_BOLD : FW_NORMAL; 6493 hfont = CreateFontIndirectA(&lf); 6494 hfont_old = SelectObject(hdc, hfont); 6495 6496 ret = GetTextMetricsA(hdc, &data[i].tm); 6497 ok(ret, "got %d\n", ret); 6498 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &data[i].abc); 6499 ok(ret, "got %d\n", ret); 6500 data[i].w = data[i].abc.abcA + data[i].abc.abcB + data[i].abc.abcC; 6501 r = GetGlyphOutlineA(hdc, 0x76, GGO_METRICS, &data[i].gm, 0, NULL, &x2_mat); 6502 ok(r != GDI_ERROR, "got %d\n", ret); 6503 6504 SelectObject(hdc, hfont_old); 6505 DeleteObject(hfont); 6506 } 6507 ReleaseDC(NULL, hdc); 6508 6509 /* compare results (outline) */ 6510 ok(data[0].tm.tmHeight == data[1].tm.tmHeight, 6511 "expected %d, got %d\n", data[0].tm.tmHeight, data[1].tm.tmHeight); 6512 ok(data[0].tm.tmAscent == data[1].tm.tmAscent, 6513 "expected %d, got %d\n", data[0].tm.tmAscent, data[1].tm.tmAscent); 6514 ok(data[0].tm.tmDescent == data[1].tm.tmDescent, 6515 "expected %d, got %d\n", data[0].tm.tmDescent, data[1].tm.tmDescent); 6516 ok(data[0].tm.tmAveCharWidth + 1 == data[1].tm.tmAveCharWidth, 6517 "expected %d, got %d\n", data[0].tm.tmAveCharWidth + 1, data[1].tm.tmAveCharWidth); 6518 ok(data[0].tm.tmMaxCharWidth + 1 == data[1].tm.tmMaxCharWidth, 6519 "expected %d, got %d\n", data[0].tm.tmMaxCharWidth + 1, data[1].tm.tmMaxCharWidth); 6520 ok(data[0].tm.tmOverhang == data[1].tm.tmOverhang, 6521 "expected %d, got %d\n", data[0].tm.tmOverhang, data[1].tm.tmOverhang); 6522 ok(data[0].w + 1 == data[1].w, 6523 "expected %d, got %d\n", data[0].w + 1, data[1].w); 6524 6525 ok(data[0].gm.gmCellIncX + 1 == data[1].gm.gmCellIncX, 6526 "expected %d, got %d\n", data[0].gm.gmCellIncX + 1, data[1].gm.gmCellIncX); 6527 ok(data[0].gm.gmCellIncY == data[1].gm.gmCellIncY, 6528 "expected %d, got %d\n", data[0].gm.gmCellIncY, data[1].gm.gmCellIncY); 6529 } 6530 6531 static void test_bitmap_font_glyph_index(void) 6532 { 6533 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0}; 6534 const struct { 6535 LPCSTR face; 6536 BYTE charset; 6537 } bitmap_font_list[] = { 6538 { "Courier", ANSI_CHARSET }, 6539 { "Small Fonts", ANSI_CHARSET }, 6540 { "Fixedsys", DEFAULT_CHARSET }, 6541 { "System", DEFAULT_CHARSET } 6542 }; 6543 HDC hdc; 6544 LOGFONTA lf; 6545 HFONT hFont; 6546 CHAR facename[LF_FACESIZE]; 6547 BITMAPINFO bmi; 6548 HBITMAP hBmp[2]; 6549 void *pixels[2]; 6550 int i, j; 6551 DWORD ret; 6552 BITMAP bmp; 6553 TEXTMETRICA tm; 6554 CHARSETINFO ci; 6555 BYTE chr = '\xA9'; 6556 6557 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) { 6558 win_skip("GetGlyphIndices is unavailable\n"); 6559 return; 6560 } 6561 6562 hdc = CreateCompatibleDC(0); 6563 ok(hdc != NULL, "CreateCompatibleDC failed\n"); 6564 6565 memset(&bmi, 0, sizeof(bmi)); 6566 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 6567 bmi.bmiHeader.biBitCount = 32; 6568 bmi.bmiHeader.biPlanes = 1; 6569 bmi.bmiHeader.biWidth = 128; 6570 bmi.bmiHeader.biHeight = 32; 6571 bmi.bmiHeader.biCompression = BI_RGB; 6572 6573 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) { 6574 memset(&lf, 0, sizeof(lf)); 6575 lf.lfCharSet = bitmap_font_list[i].charset; 6576 strcpy(lf.lfFaceName, bitmap_font_list[i].face); 6577 hFont = CreateFontIndirectA(&lf); 6578 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet); 6579 hFont = SelectObject(hdc, hFont); 6580 ret = GetTextMetricsA(hdc, &tm); 6581 ok(ret, "GetTextMetric failed\n"); 6582 ret = GetTextFaceA(hdc, sizeof(facename), facename); 6583 ok(ret, "GetTextFace failed\n"); 6584 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) { 6585 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face); 6586 continue; 6587 } 6588 if (lstrcmpiA(facename, lf.lfFaceName) != 0) { 6589 skip("expected %s, got %s\n", lf.lfFaceName, facename); 6590 continue; 6591 } 6592 6593 for (j = 0; j < 2; j++) { 6594 HBITMAP hBmpPrev; 6595 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0); 6596 ok(hBmp[j] != NULL, "Can't create DIB\n"); 6597 hBmpPrev = SelectObject(hdc, hBmp[j]); 6598 switch (j) { 6599 case 0: 6600 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL); 6601 break; 6602 case 1: 6603 { 6604 int len = lstrlenW(text); 6605 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD)); 6606 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0); 6607 ok(ret, "GetGlyphIndices failed\n"); 6608 ok(memcmp(indices, text, sizeof(WORD) * len) == 0, 6609 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet); 6610 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL); 6611 HeapFree(GetProcessHeap(), 0, indices); 6612 break; 6613 } 6614 } 6615 ok(ret, "ExtTextOutW failed\n"); 6616 SelectObject(hdc, hBmpPrev); 6617 } 6618 6619 GetObjectA(hBmp[0], sizeof(bmp), &bmp); 6620 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0, 6621 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet); 6622 6623 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET); 6624 if (!ret) { 6625 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet); 6626 goto next; 6627 } 6628 if (IsDBCSLeadByteEx(ci.ciACP, chr)) { 6629 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP); 6630 goto next; 6631 } 6632 6633 for (j = 0; j < 2; j++) { 6634 HBITMAP hBmpPrev; 6635 WORD code; 6636 hBmpPrev = SelectObject(hdc, hBmp[j]); 6637 switch (j) { 6638 case 0: 6639 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL); 6640 break; 6641 case 1: 6642 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0); 6643 ok(ret, "GetGlyphIndices failed\n"); 6644 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet); 6645 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL); 6646 break; 6647 } 6648 ok(ret, "ExtTextOutA failed\n"); 6649 SelectObject(hdc, hBmpPrev); 6650 } 6651 6652 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0, 6653 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet); 6654 next: 6655 for (j = 0; j < 2; j++) 6656 DeleteObject(hBmp[j]); 6657 hFont = SelectObject(hdc, hFont); 6658 DeleteObject(hFont); 6659 } 6660 6661 DeleteDC(hdc); 6662 } 6663 6664 static void test_GetCharWidthI(void) 6665 { 6666 static const char *teststr = "wine "; 6667 HFONT hfont, prev_hfont; 6668 WORD glyphs[5]; 6669 INT widths[5]; 6670 LOGFONTA lf; 6671 ABC abc[5]; 6672 int len, i; 6673 DWORD nb; 6674 BOOL ret; 6675 HDC hdc; 6676 6677 memset(&lf, 0, sizeof(lf)); 6678 strcpy(lf.lfFaceName, "Tahoma"); 6679 lf.lfHeight = -20; 6680 6681 hdc = GetDC(0); 6682 6683 hfont = CreateFontIndirectA(&lf); 6684 prev_hfont = SelectObject(hdc, hfont); 6685 6686 len = strlen(teststr); 6687 nb = GetGlyphIndicesA(hdc, teststr, len, glyphs, 0); 6688 ok(nb == len, "\n"); 6689 6690 memset(abc, 0xcc, sizeof(abc)); 6691 ret = GetCharABCWidthsI(hdc, 0, len, glyphs, abc); 6692 ok(ret, "GetCharABCWidthsI failed\n"); 6693 6694 memset(widths, 0xcc, sizeof(widths)); 6695 ret = GetCharWidthI(hdc, 0, len, glyphs, widths); 6696 ok(ret, "GetCharWidthI failed\n"); 6697 6698 for (i = 0; i < len; i++) 6699 ok(widths[i] == abc[i].abcA + abc[i].abcB + abc[i].abcC, "%u, glyph %u, got width %d\n", 6700 i, glyphs[i], widths[i]); 6701 6702 DeleteObject(SelectObject(hdc, prev_hfont)); 6703 ReleaseDC(0, hdc); 6704 } 6705 6706 START_TEST(font) 6707 { 6708 init(); 6709 6710 test_stock_fonts(); 6711 test_logfont(); 6712 test_bitmap_font(); 6713 test_outline_font(); 6714 test_bitmap_font_metrics(); 6715 test_GdiGetCharDimensions(); 6716 test_GetCharABCWidths(); 6717 test_text_extents(); 6718 test_GetGlyphIndices(); 6719 test_GetKerningPairs(); 6720 test_GetOutlineTextMetrics(); 6721 test_SetTextJustification(); 6722 test_font_charset(); 6723 test_GdiGetCodePage(); 6724 test_GetFontUnicodeRanges(); 6725 test_nonexistent_font(); 6726 test_orientation(); 6727 test_height_selection(); 6728 test_AddFontMemResource(); 6729 test_EnumFonts(); 6730 test_EnumFonts_subst(); 6731 6732 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr, 6733 * I'd like to avoid them in this test. 6734 */ 6735 test_EnumFontFamilies("Arial Black", ANSI_CHARSET); 6736 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET); 6737 if (is_truetype_font_installed("Arial Black") && 6738 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings"))) 6739 { 6740 test_EnumFontFamilies("", ANSI_CHARSET); 6741 test_EnumFontFamilies("", SYMBOL_CHARSET); 6742 test_EnumFontFamilies("", DEFAULT_CHARSET); 6743 } 6744 else 6745 skip("Arial Black or Symbol/Wingdings is not installed\n"); 6746 test_EnumFontFamiliesEx_default_charset(); 6747 test_GetTextMetrics(); 6748 test_RealizationInfo(); 6749 test_GetTextFace(); 6750 test_GetGlyphOutline(); 6751 test_GetTextMetrics2("Tahoma", -11); 6752 test_GetTextMetrics2("Tahoma", -55); 6753 test_GetTextMetrics2("Tahoma", -110); 6754 test_GetTextMetrics2("Arial", -11); 6755 test_GetTextMetrics2("Arial", -55); 6756 test_GetTextMetrics2("Arial", -110); 6757 test_GetCharacterPlacement(); 6758 test_CreateFontIndirect(); 6759 test_CreateFontIndirectEx(); 6760 test_oemcharset(); 6761 test_fullname(); 6762 test_fullname2(); 6763 test_east_asian_font_selection(); 6764 test_max_height(); 6765 test_vertical_order(); 6766 test_GetCharWidth32(); 6767 test_fake_bold_font(); 6768 test_bitmap_font_glyph_index(); 6769 test_GetCharWidthI(); 6770 6771 /* These tests should be last test until RemoveFontResource 6772 * is properly implemented. 6773 */ 6774 test_vertical_font(); 6775 test_CreateScalableFontResource(); 6776 } 6777