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