ReactOS  r76032
font.c
Go to the documentation of this file.
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/test.h"
32 
33 static inline BOOL match_off_by_n(int a, int b, unsigned int n)
34 {
35  return abs(a - b) <= n;
36 }
37 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
38 #define near_match(a, b) match_off_by_n((a), (b), 6)
39 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
40 
41 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
42 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
43 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
45 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
46 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
47 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
48 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
49 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
50 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
51 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
52 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
54 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
55 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
56 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
57 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
58 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
59 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
60 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
61 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *);
62 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
63 
64 static HMODULE hgdi32 = 0;
65 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
67 
68 #ifdef WORDS_BIGENDIAN
69 #define GET_BE_WORD(x) (x)
70 #define GET_BE_DWORD(x) (x)
71 #else
72 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
73 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
74 #endif
75 
76 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
77  ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
78  ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
79 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
80 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
81 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
82 
83 static void init(void)
84 {
85  hgdi32 = GetModuleHandleA("gdi32.dll");
86 
87  pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
88  pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
89  pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
90  pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
91  pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
92  pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
93  pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
94  pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
95  pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
96  pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
97  pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
98  pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
99  pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
100  pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
101  pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
102  pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
103  pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
104  pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
105  pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
106  pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
107  pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
108 
110 }
111 
112 static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size)
113 {
114  return HeapAlloc(GetProcessHeap(), 0, size);
115 }
116 
117 static inline void* __WINE_ALLOC_SIZE(2) heap_realloc(void *mem, size_t size)
118 {
119  if (!mem) return heap_alloc(size);
120  return HeapReAlloc(GetProcessHeap(), 0, mem, size);
121 }
122 
123 static inline BOOL heap_free(void *mem)
124 {
125  return HeapFree(GetProcessHeap(), 0, mem);
126 }
127 
129 {
130  if (type != TRUETYPE_FONTTYPE) return 1;
131 
132  return 0;
133 }
134 
136 {
137  HDC hdc = GetDC(0);
138  BOOL ret = FALSE;
139 
141  ret = TRUE;
142 
143  ReleaseDC(0, hdc);
144  return ret;
145 }
146 
148 {
149  return 0;
150 }
151 
152 static BOOL is_font_installed(const char *name)
153 {
154  HDC hdc = GetDC(0);
155  BOOL ret = FALSE;
156 
157  if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
158  ret = TRUE;
159 
160  ReleaseDC(0, hdc);
161  return ret;
162 }
163 
164 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
165 {
166  HRSRC rsrc;
167  void *rsrc_data;
168 
169  rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
170  if (!rsrc) return NULL;
171 
172  rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
173  if (!rsrc_data) return NULL;
174 
175  *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
176  if (!*rsrc_size) return NULL;
177 
178  return rsrc_data;
179 }
180 
181 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
182 {
183  char tmp_path[MAX_PATH];
184  HANDLE hfile;
185  BOOL ret;
186 
187  GetTempPathA(MAX_PATH, tmp_path);
188  GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
189 
191  if (hfile == INVALID_HANDLE_VALUE) return FALSE;
192 
193  ret = WriteFile(hfile, data, *size, size, NULL);
194 
195  CloseHandle(hfile);
196  return ret;
197 }
198 
199 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
200 {
201  void *rsrc_data;
202  DWORD rsrc_size;
203 
204  rsrc_data = get_res_data( fontname, &rsrc_size );
205  if (!rsrc_data) return FALSE;
206 
207  return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
208 }
209 
210 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
211 {
212  LOGFONTA getobj_lf;
213  int ret, minlen = 0;
214 
215  if (!hfont)
216  return;
217 
218  ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
219  /* NT4 tries to be clever and only returns the minimum length */
220  while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
221  minlen++;
222  minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
223  ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
224  ok(lf->lfHeight == getobj_lf.lfHeight ||
225  broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
226  "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
227  ok(lf->lfWidth == getobj_lf.lfWidth ||
228  broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
229  "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
230  ok(lf->lfEscapement == getobj_lf.lfEscapement ||
231  broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
232  "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
233  ok(lf->lfOrientation == getobj_lf.lfOrientation ||
234  broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
235  "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
236  ok(lf->lfWeight == getobj_lf.lfWeight ||
237  broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
238  "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
239  ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
240  ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
241  ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
242  ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
243  ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
244  ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
245  ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
246  ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
247  ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
248  broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
249  "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
250 }
251 
252 static HFONT create_font(const char* test, const LOGFONTA* lf)
253 {
255  ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
256  if (hfont)
257  check_font(test, lf, hfont);
258  return hfont;
259 }
260 
261 static void test_logfont(void)
262 {
263  LOGFONTA lf;
264  HFONT hfont;
265 
266  memset(&lf, 0, sizeof lf);
267 
268  lf.lfCharSet = ANSI_CHARSET;
270  lf.lfWeight = FW_DONTCARE;
271  lf.lfHeight = 16;
272  lf.lfWidth = 16;
274 
275  lstrcpyA(lf.lfFaceName, "Arial");
276  hfont = create_font("Arial", &lf);
277  DeleteObject(hfont);
278 
279  memset(&lf, 'A', sizeof(lf));
280  hfont = CreateFontIndirectA(&lf);
281  ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
282 
283  lf.lfFaceName[LF_FACESIZE - 1] = 0;
284  check_font("AAA...", &lf, hfont);
285  DeleteObject(hfont);
286 }
287 
289 {
290  if (type & RASTER_FONTTYPE)
291  {
292  LOGFONTA *lf = (LOGFONTA *)lParam;
293  *lf = *elf;
294  return 0; /* stop enumeration */
295  }
296 
297  return 1; /* continue enumeration */
298 }
299 
300 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
301 {
302  ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
303  ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
304  ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
305  ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
306  ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
307  ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
308  ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
309  ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
310  ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
311  ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
312  ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
313  ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
314  ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
315  ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
316  ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
317  ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
318  ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
319  ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
320  ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
321  ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
322 }
323 
324 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
325  LONG lfWidth, const char *test_str,
326  INT test_str_len, const TEXTMETRICA *tm_orig,
327  const SIZE *size_orig, INT width_of_A_orig,
328  INT scale_x, INT scale_y)
329 {
330  LOGFONTA lf;
331  OUTLINETEXTMETRICA otm;
332  TEXTMETRICA tm;
333  SIZE size;
334  INT width_of_A, cx, cy;
335  UINT ret;
336 
337  if (!hfont)
338  return;
339 
340  ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
341 
342  GetObjectA(hfont, sizeof(lf), &lf);
343 
344  if (GetOutlineTextMetricsA(hdc, 0, NULL))
345  {
346  otm.otmSize = sizeof(otm) / 2;
347  ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
348  ok(ret == sizeof(otm)/2 /* XP */ ||
349  ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
350 
351  memset(&otm, 0x1, sizeof(otm));
352  otm.otmSize = sizeof(otm);
353  ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
354  ok(ret == sizeof(otm) /* XP */ ||
355  ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
356 
357  memset(&tm, 0x2, sizeof(tm));
358  ret = GetTextMetricsA(hdc, &tm);
359  ok(ret, "GetTextMetricsA failed\n");
360  /* the structure size is aligned */
361  if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
362  {
363  ok(0, "tm != otm\n");
364  compare_tm(&tm, &otm.otmTextMetrics);
365  }
366 
367  tm = otm.otmTextMetrics;
368 if (0) /* these metrics are scaled too, but with rounding errors */
369 {
370  ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
371  ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
372 }
373  ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
374  ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
375  ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
376  ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
377  ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
378  ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
379  }
380  else
381  {
382  ret = GetTextMetricsA(hdc, &tm);
383  ok(ret, "GetTextMetricsA failed\n");
384  }
385 
386  cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
387  cy = tm.tmHeight / tm_orig->tmHeight;
388  ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
389  lfHeight, scale_x, scale_y, cx, cy);
390  ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
391  ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
392  ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
393  ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
394  ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
395 
396  ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
397  if (lf.lfHeight)
398  {
399  if (lf.lfWidth)
400  ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
401  }
402  else
403  ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
404 
405  GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
406 
407  ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
408  ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
409 
410  GetCharWidthA(hdc, 'A', 'A', &width_of_A);
411 
412  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);
413 }
414 
415 /* Test how GDI scales bitmap font metrics */
416 static void test_bitmap_font(void)
417 {
418  static const char test_str[11] = "Test String";
419  HDC hdc;
420  LOGFONTA bitmap_lf;
421  HFONT hfont, old_hfont;
422  TEXTMETRICA tm_orig;
423  SIZE size_orig;
424  INT ret, i, width_orig, height_orig, scale, lfWidth;
425 
426  hdc = CreateCompatibleDC(0);
427 
428  /* "System" has only 1 pixel size defined, otherwise the test breaks */
429  ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
430  if (ret)
431  {
432  ReleaseDC(0, hdc);
433  trace("no bitmap fonts were found, skipping the test\n");
434  return;
435  }
436 
437  trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
438 
439  height_orig = bitmap_lf.lfHeight;
440  lfWidth = bitmap_lf.lfWidth;
441 
442  hfont = create_font("bitmap", &bitmap_lf);
443  old_hfont = SelectObject(hdc, hfont);
444  ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
445  ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
446  ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
447  SelectObject(hdc, old_hfont);
448  DeleteObject(hfont);
449 
450  bitmap_lf.lfHeight = 0;
451  bitmap_lf.lfWidth = 4;
452  hfont = create_font("bitmap", &bitmap_lf);
453  old_hfont = SelectObject(hdc, hfont);
454  test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
455  SelectObject(hdc, old_hfont);
456  DeleteObject(hfont);
457 
458  bitmap_lf.lfHeight = height_orig;
459  bitmap_lf.lfWidth = lfWidth;
460 
461  /* test fractional scaling */
462  for (i = 1; i <= height_orig * 6; i++)
463  {
464  INT nearest_height;
465 
466  bitmap_lf.lfHeight = i;
467  hfont = create_font("fractional", &bitmap_lf);
468  scale = (i + height_orig - 1) / height_orig;
469  nearest_height = scale * height_orig;
470  /* Only jump to the next height if the difference <= 25% original height */
471  if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
472  /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
473  so we'll not test this particular height. */
474  else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
475  else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
476  old_hfont = SelectObject(hdc, hfont);
477  test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
478  SelectObject(hdc, old_hfont);
479  DeleteObject(hfont);
480  }
481 
482  /* test integer scaling 3x2 */
483  bitmap_lf.lfHeight = height_orig * 2;
484  bitmap_lf.lfWidth *= 3;
485  hfont = create_font("3x2", &bitmap_lf);
486  old_hfont = SelectObject(hdc, hfont);
487  test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
488  SelectObject(hdc, old_hfont);
489  DeleteObject(hfont);
490 
491  /* test integer scaling 3x3 */
492  bitmap_lf.lfHeight = height_orig * 3;
493  bitmap_lf.lfWidth = 0;
494  hfont = create_font("3x3", &bitmap_lf);
495  old_hfont = SelectObject(hdc, hfont);
496  test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
497  SelectObject(hdc, old_hfont);
498  DeleteObject(hfont);
499 
500  DeleteDC(hdc);
501 }
502 
503 /* Test how GDI scales outline font metrics */
504 static void test_outline_font(void)
505 {
506  static const char test_str[11] = "Test String";
507  HDC hdc, hdc_2;
508  LOGFONTA lf;
509  HFONT hfont, old_hfont, old_hfont_2;
510  OUTLINETEXTMETRICA otm;
511  SIZE size_orig;
512  INT width_orig, height_orig, lfWidth;
513  XFORM xform;
514  GLYPHMETRICS gm;
515  MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
516  POINT pt;
517  INT ret;
518 
519  if (!is_truetype_font_installed("Arial"))
520  {
521  skip("Arial is not installed\n");
522  return;
523  }
524 
525  hdc = CreateCompatibleDC(0);
526 
527  memset(&lf, 0, sizeof(lf));
528  strcpy(lf.lfFaceName, "Arial");
529  lf.lfHeight = 72;
530  hfont = create_font("outline", &lf);
531  old_hfont = SelectObject(hdc, hfont);
532  otm.otmSize = sizeof(otm);
533  ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
534  ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
535  ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
536 
537  test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
538  SelectObject(hdc, old_hfont);
539  DeleteObject(hfont);
540 
541  /* font of otmEMSquare height helps to avoid a lot of rounding errors */
542  lf.lfHeight = otm.otmEMSquare;
543  lf.lfHeight = -lf.lfHeight;
544  hfont = create_font("outline", &lf);
545  old_hfont = SelectObject(hdc, hfont);
546  otm.otmSize = sizeof(otm);
547  ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
548  ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
549  ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
550  SelectObject(hdc, old_hfont);
551  DeleteObject(hfont);
552 
553  height_orig = otm.otmTextMetrics.tmHeight;
554  lfWidth = otm.otmTextMetrics.tmAveCharWidth;
555 
556  /* test integer scaling 3x2 */
557  lf.lfHeight = height_orig * 2;
558  lf.lfWidth = lfWidth * 3;
559  hfont = create_font("3x2", &lf);
560  old_hfont = SelectObject(hdc, hfont);
561  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
562  SelectObject(hdc, old_hfont);
563  DeleteObject(hfont);
564 
565  /* test integer scaling 3x3 */
566  lf.lfHeight = height_orig * 3;
567  lf.lfWidth = lfWidth * 3;
568  hfont = create_font("3x3", &lf);
569  old_hfont = SelectObject(hdc, hfont);
570  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
571  SelectObject(hdc, old_hfont);
572  DeleteObject(hfont);
573 
574  /* test integer scaling 1x1 */
575  lf.lfHeight = height_orig * 1;
576  lf.lfWidth = lfWidth * 1;
577  hfont = create_font("1x1", &lf);
578  old_hfont = SelectObject(hdc, hfont);
579  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
580  SelectObject(hdc, old_hfont);
581  DeleteObject(hfont);
582 
583  /* test integer scaling 1x1 */
584  lf.lfHeight = height_orig;
585  lf.lfWidth = 0;
586  hfont = create_font("1x1", &lf);
587  old_hfont = SelectObject(hdc, hfont);
588  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
589 
590  /* with an identity matrix */
591  memset(&gm, 0, sizeof(gm));
592  SetLastError(0xdeadbeef);
593  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
594  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
595  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
596  ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
597  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598  /* with a custom matrix */
599  memset(&gm, 0, sizeof(gm));
600  SetLastError(0xdeadbeef);
601  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
602  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
603  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
604  ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
605  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
606 
607  /* Test that changing the DC transformation affects only the font
608  * selected on this DC and doesn't affect the same font selected on
609  * another DC.
610  */
611  hdc_2 = CreateCompatibleDC(0);
612  old_hfont_2 = SelectObject(hdc_2, hfont);
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 
616 
617  /* font metrics on another DC should be unchanged */
618  test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
619 
620  /* test restrictions of compatibility mode GM_COMPATIBLE */
621  /* part 1: rescaling only X should not change font scaling on screen.
622  So compressing the X axis by 2 is not done, and this
623  appears as X scaling of 2 that no one requested. */
624  SetWindowExtEx(hdc, 100, 100, NULL);
625  SetViewportExtEx(hdc, 50, 100, NULL);
626  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
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  /* part 2: rescaling only Y should change font scaling.
631  As also X is scaled by a factor of 2, but this is not
632  requested by the DC transformation, we get a scaling factor
633  of 2 in the X coordinate. */
634  SetViewportExtEx(hdc, 100, 200, NULL);
635  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
636  /* font metrics on another DC should be unchanged */
637  test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
638 
639  /* restore scaling */
640  SetMapMode(hdc, MM_TEXT);
641 
642  /* font metrics on another DC should be unchanged */
643  test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
644 
645  SelectObject(hdc_2, old_hfont_2);
646  DeleteDC(hdc_2);
647 
648  if (!SetGraphicsMode(hdc, GM_ADVANCED))
649  {
650  SelectObject(hdc, old_hfont);
651  DeleteObject(hfont);
652  DeleteDC(hdc);
653  skip("GM_ADVANCED is not supported on this platform\n");
654  return;
655  }
656 
657  xform.eM11 = 20.0f;
658  xform.eM12 = 0.0f;
659  xform.eM21 = 0.0f;
660  xform.eM22 = 20.0f;
661  xform.eDx = 0.0f;
662  xform.eDy = 0.0f;
663 
664  SetLastError(0xdeadbeef);
665  ret = SetWorldTransform(hdc, &xform);
666  ok(ret, "SetWorldTransform error %u\n", GetLastError());
667 
668  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
669 
670  /* with an identity matrix */
671  memset(&gm, 0, sizeof(gm));
672  SetLastError(0xdeadbeef);
673  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
674  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
675  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
676  pt.x = width_orig; pt.y = 0;
677  LPtoDP(hdc, &pt, 1);
678  ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
679  ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
680  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
681  /* with a custom matrix */
682  memset(&gm, 0, sizeof(gm));
683  SetLastError(0xdeadbeef);
684  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
685  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
686  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
687  pt.x = width_orig; pt.y = 0;
688  LPtoDP(hdc, &pt, 1);
689  ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
690  ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
691  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
692 
693  SetLastError(0xdeadbeef);
694  ret = SetMapMode(hdc, MM_LOMETRIC);
695  ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
696 
697  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
698 
699  /* with an identity matrix */
700  memset(&gm, 0, sizeof(gm));
701  SetLastError(0xdeadbeef);
702  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
703  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
704  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
705  pt.x = width_orig; pt.y = 0;
706  LPtoDP(hdc, &pt, 1);
707  ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
708  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
709  /* with a custom matrix */
710  memset(&gm, 0, sizeof(gm));
711  SetLastError(0xdeadbeef);
712  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
713  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
714  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
715  pt.x = width_orig; pt.y = 0;
716  LPtoDP(hdc, &pt, 1);
717  ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
718  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
719 
720  SetLastError(0xdeadbeef);
721  ret = SetMapMode(hdc, MM_TEXT);
722  ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
723 
724  test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
725 
726  /* with an identity matrix */
727  memset(&gm, 0, sizeof(gm));
728  SetLastError(0xdeadbeef);
729  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
730  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
731  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
732  pt.x = width_orig; pt.y = 0;
733  LPtoDP(hdc, &pt, 1);
734  ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
735  ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
736  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
737  /* with a custom matrix */
738  memset(&gm, 0, sizeof(gm));
739  SetLastError(0xdeadbeef);
740  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
741  ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
742  trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
743  pt.x = width_orig; pt.y = 0;
744  LPtoDP(hdc, &pt, 1);
745  ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
746  ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
747  ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
748 
749  SelectObject(hdc, old_hfont);
750  DeleteObject(hfont);
751  DeleteDC(hdc);
752 }
753 
755 {
756  LOGFONTA *lf = (LOGFONTA *)lParam;
757 
758  if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
759  {
760  *lf = *elf;
761  return 0; /* stop enumeration */
762  }
763  return 1; /* continue enumeration */
764 }
765 
766 static BOOL is_CJK(void)
767 {
769 }
770 
771 #define FH_SCALE 0x80000000
772 static void test_bitmap_font_metrics(void)
773 {
774  static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
775  static const struct font_data
776  {
777  const char face_name[LF_FACESIZE];
779  int ave_char_width, max_char_width, dpi;
780  BYTE first_char, last_char, def_char, break_char;
781  DWORD ansi_bitfield;
782  const WORD *skip_lang_id;
783  int scaled_height;
784  } fd[] =
785  {
786  { "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 },
787  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
788  { "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 },
789  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
790  { "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 },
791  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
792  { "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 },
793  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
794  { "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 },
795  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
796 
797  { "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 },
798  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
799  { "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 },
800  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
801  { "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 },
802  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
803  { "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 },
804  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
805  { "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 },
806  { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
807 
808  { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
809  { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810  { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811  { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
812  { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
813  { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
814  { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
815  { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
816  { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
817  { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
818  { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
819  { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
820  { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
821  { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
822  { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
823  { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
824 
825  { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
826  { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
827  { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
828  { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
829  { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
830  { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
831  { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
832  { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
833  { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
834  { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
835  { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
836  { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
837 
838  { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
839  { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
840  { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
841  { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
842  { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
843  { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
844  { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
845  { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
846  { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
847  { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
848  { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
849  { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
850  { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
851  { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
852  { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
853  { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
854  { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
855 
856  { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
857  { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
858  { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
859  { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
860  { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
861  { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
862  { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
863  { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
864  { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
865  { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
866  { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
867 
868  { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
869  { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
870  { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
871 
872  { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
873  { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
874  { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
875 
876  { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
877  { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
878  { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
879 
880  { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
881  { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
882 
883  { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
884  { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
885  { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
886  { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
887  { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
888  { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
889  { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
890  { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
891  { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
892  { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
893  { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
894  { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
895  { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
896  { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
897  { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
898  { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
899  { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
900  { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
901  { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
902  { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
903  { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
904 
905  { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
906  { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
907  { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
908  { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
909  { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
910  { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
911  { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
912  { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
913  { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
914  { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
915  { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
916  { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
917 
918  { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
919  { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
920  { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
921 
922  { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
923 
924  /* FIXME: add "Terminal" */
925  };
926  static const int font_log_pixels[] = { 96, 120 };
927  HDC hdc;
928  LOGFONTA lf;
929  HFONT hfont, old_hfont;
930  TEXTMETRICA tm;
931  INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
932  char face_name[LF_FACESIZE];
933  CHARSETINFO csi;
934 
935  trace("system language id %04x\n", system_lang_id);
936 
937  expected_cs = GetACP();
938  if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
939  {
940  skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
941  return;
942  }
943  expected_cs = csi.ciCharset;
944  trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
945 
946  hdc = CreateCompatibleDC(0);
947  ok(hdc != NULL, "failed to create hdc\n");
948 
949  trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
950  GetDeviceCaps(hdc, LOGPIXELSY));
951 
952  screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
953  diff = 32768;
954  font_res = 0;
955  for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
956  {
957  int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
958  if (new_diff < diff)
959  {
960  diff = new_diff;
961  font_res = font_log_pixels[i];
962  }
963  }
964  trace("best font resolution is %d\n", font_res);
965 
966  for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
967  {
968  int bit, height;
969 
970  memset(&lf, 0, sizeof(lf));
971 
972  height = fd[i].height & ~FH_SCALE;
973  lf.lfHeight = height;
974  strcpy(lf.lfFaceName, fd[i].face_name);
975 
976  for(bit = 0; bit < 32; bit++)
977  {
978  GLYPHMETRICS gm;
979  DWORD fs[2];
980  BOOL bRet;
981 
982  fs[0] = 1L << bit;
983  fs[1] = 0;
984  if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
985  if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
986 
987  lf.lfCharSet = csi.ciCharset;
988  ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
989  if (fd[i].height & FH_SCALE)
990  ok(ret, "scaled font height %d should not be enumerated\n", height);
991  else
992  {
993  if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
994  {
995  todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */
996  ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
997  }
998  }
999  if (ret && !(fd[i].height & FH_SCALE))
1000  continue;
1001 
1002  hfont = create_font(lf.lfFaceName, &lf);
1003  old_hfont = SelectObject(hdc, hfont);
1004 
1005  SetLastError(0xdeadbeef);
1006  ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
1007  ok(ret, "GetTextFace error %u\n", GetLastError());
1008 
1009  if (strcmp(face_name, fd[i].face_name) != 0)
1010  {
1011  ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
1012  ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
1013  SelectObject(hdc, old_hfont);
1014  DeleteObject(hfont);
1015  continue;
1016  }
1017 
1018  memset(&gm, 0, sizeof(gm));
1019  SetLastError(0xdeadbeef);
1020  ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1021  todo_wine {
1022  ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1023  ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1024  }
1025 
1026  bRet = GetTextMetricsA(hdc, &tm);
1027  ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1028 
1029  SetLastError(0xdeadbeef);
1030  ret = GetTextCharset(hdc);
1031  if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1032  ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1033  else
1034  ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1035 
1036  trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1037  trace("expected %s, height %d scaled_height %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1038 
1039  if(fd[i].dpi == tm.tmDigitizedAspectX)
1040  {
1041  int skipme = 0;
1042  trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1043  if (fd[i].skip_lang_id)
1044  {
1045  int si = 0;
1046  skipme = 0;
1047  while(!skipme && fd[i].skip_lang_id[si])
1048  if (fd[i].skip_lang_id[si++] == system_lang_id)
1049  skipme = 1;
1050  }
1051  if (!skipme)
1052  {
1053  ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1054  if (fd[i].height & FH_SCALE)
1055  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);
1056  else
1057  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);
1058  ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1059  ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1060  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);
1061  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);
1062  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);
1063  ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1064  ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1065  /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1066  make default char test fail */
1067  if (tm.tmCharSet == lf.lfCharSet)
1068  ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1069  ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1070  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);
1071 
1072  /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1073  that make the max width bigger */
1074  if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1075  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);
1076  }
1077  else
1078  skip("Skipping font metrics test for system langid 0x%x\n",
1079  system_lang_id);
1080  }
1081  SelectObject(hdc, old_hfont);
1082  DeleteObject(hfont);
1083  }
1084  }
1085 
1086  DeleteDC(hdc);
1087 }
1088 
1089 static void test_GdiGetCharDimensions(void)
1090 {
1091  HDC hdc;
1092  TEXTMETRICW tm;
1093  LONG ret;
1094  SIZE size;
1095  LONG avgwidth, height;
1096  static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1097 
1098  if (!pGdiGetCharDimensions)
1099  {
1100  win_skip("GdiGetCharDimensions not available on this platform\n");
1101  return;
1102  }
1103 
1104  hdc = CreateCompatibleDC(NULL);
1105 
1106  GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1107  avgwidth = ((size.cx / 26) + 1) / 2;
1108 
1109  ret = pGdiGetCharDimensions(hdc, &tm, &height);
1110  ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1111  ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1112 
1113  ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1114  ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1115 
1116  ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1117  ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1118 
1119  height = 0;
1120  ret = pGdiGetCharDimensions(hdc, NULL, &height);
1121  ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1122  ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1123 
1124  DeleteDC(hdc);
1125 }
1126 
1127 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1128  const TEXTMETRICA *lpntme,
1129  DWORD FontType, LPARAM lParam)
1130 {
1131  if (FontType & TRUETYPE_FONTTYPE)
1132  {
1133  HFONT hfont;
1134 
1135  hfont = CreateFontIndirectA(lpelfe);
1136  if (hfont)
1137  {
1138  *(HFONT *)lParam = hfont;
1139  return 0;
1140  }
1141  }
1142 
1143  return 1;
1144 }
1145 
1146 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1147 {
1148  ABC abc[1];
1149  ABCFLOAT abcf[1];
1150  BOOL ret = FALSE;
1151 
1152  ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1153  ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1154  ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1155  todo_wine_if (todo)
1156  ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1157  todo_wine_if (todo)
1158  ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1159 
1160  ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1161  ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1162  ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1163  todo_wine_if (todo)
1164  ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1165  todo_wine_if (todo)
1166  ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1167 
1168  ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1169  ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1170  ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1171  todo_wine_if (todo)
1172  ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1173  todo_wine_if (todo)
1174  ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1175 }
1176 
1177 static void test_GetCharABCWidths(void)
1178 {
1179  static const WCHAR str[] = {'i',0};
1180  BOOL ret;
1181  HDC hdc;
1182  LOGFONTA lf;
1183  HFONT hfont;
1184  ABC abc[1];
1185  ABC abcw[1];
1186  ABCFLOAT abcf[1];
1187  WORD glyphs[1];
1188  DWORD nb;
1189  HWND hwnd;
1190  static const struct
1191  {
1192  UINT first;
1193  UINT last;
1194  } range[] =
1195  {
1196  {0xff, 0xff},
1197  {0x100, 0x100},
1198  {0xff, 0x100},
1199  {0x1ff, 0xff00},
1200  {0xffff, 0xffff},
1201  {0x10000, 0x10000},
1202  {0xffff, 0x10000},
1203  {0xffffff, 0xffffff},
1204  {0x1000000, 0x1000000},
1205  {0xffffff, 0x1000000},
1206  {0xffffffff, 0xffffffff},
1207  {0x00, 0xff}
1208  };
1209  static const struct
1210  {
1211  UINT cs;
1212  UINT a;
1213  UINT w;
1214  BOOL r[sizeof range / sizeof range[0]];
1215  } c[] =
1216  {
1217  {ANSI_CHARSET, 0x30, 0x30,
1219  {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1220  {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1221  {HANGEUL_CHARSET, 0x8141, 0xac02,
1222  {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1223  {GB2312_CHARSET, 0x8141, 0x4e04,
1224  {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1225  {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1226  {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1227  };
1228  UINT i;
1229 
1230  if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1231  {
1232  win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1233  return;
1234  }
1235 
1236  memset(&lf, 0, sizeof(lf));
1237  strcpy(lf.lfFaceName, "System");
1238  lf.lfHeight = 20;
1239 
1240  hfont = CreateFontIndirectA(&lf);
1241  hdc = GetDC(0);
1242  hfont = SelectObject(hdc, hfont);
1243 
1244  nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1245  ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1246 
1247  ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1248  ok(!ret, "GetCharABCWidthsI should have failed\n");
1249 
1250  ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1251  ok(!ret, "GetCharABCWidthsI should have failed\n");
1252 
1253  ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1254  ok(ret, "GetCharABCWidthsI should have succeeded\n");
1255 
1256  ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1257  ok(!ret, "GetCharABCWidthsW should have failed\n");
1258 
1259  ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1260  ok(!ret, "GetCharABCWidthsW should have failed\n");
1261 
1262  ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1263  ok(!ret, "GetCharABCWidthsW should have failed\n");
1264 
1265  ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1266  ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1267 
1268  ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1269  ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1270 
1271  ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1272  ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1273 
1274  hfont = SelectObject(hdc, hfont);
1275  DeleteObject(hfont);
1276 
1277  for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1278  {
1279  ABC a[2], w[2];
1280  ABC full[256];
1281  UINT code = 0x41, j;
1282 
1283  lf.lfFaceName[0] = '\0';
1284  lf.lfCharSet = c[i].cs;
1285  lf.lfPitchAndFamily = 0;
1286  if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1287  {
1288  skip("TrueType font for charset %u is not installed\n", c[i].cs);
1289  continue;
1290  }
1291 
1292  memset(a, 0, sizeof a);
1293  memset(w, 0, sizeof w);
1294  hfont = SelectObject(hdc, hfont);
1295  ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1296  pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1297  memcmp(a, w, sizeof a) == 0,
1298  "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1299 
1300  memset(a, 0xbb, sizeof a);
1301  ret = pGetCharABCWidthsA(hdc, code, code, a);
1302  ok(ret, "GetCharABCWidthsA should have succeeded\n");
1303  memset(full, 0xcc, sizeof full);
1304  ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1305  ok(ret, "GetCharABCWidthsA should have succeeded\n");
1306  ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1307  "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1308 
1309  for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1310  {
1311  memset(full, 0xdd, sizeof full);
1312  ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1313  ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1314  range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1315  if (ret)
1316  {
1317  UINT last = range[j].last - range[j].first;
1318  ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1319  ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1320  "GetCharABCWidthsA %x should match. codepage = %u\n",
1321  range[j].last, c[i].cs);
1322  }
1323  }
1324 
1325  hfont = SelectObject(hdc, hfont);
1326  DeleteObject(hfont);
1327  }
1328 
1329  memset(&lf, 0, sizeof(lf));
1330  strcpy(lf.lfFaceName, "Tahoma");
1331  lf.lfHeight = 200;
1332  hfont = CreateFontIndirectA(&lf);
1333 
1334  /* test empty glyph's metrics */
1335  hfont = SelectObject(hdc, hfont);
1336  ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1337  ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1338  ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1339  ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1340  ok(ret, "GetCharABCWidthsW should have succeeded\n");
1341  ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1342 
1343  /* 1) prepare unrotated font metrics */
1344  ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1345  ok(ret, "GetCharABCWidthsW should have succeeded\n");
1346  DeleteObject(SelectObject(hdc, hfont));
1347 
1348  /* 2) get rotated font metrics */
1349  lf.lfEscapement = lf.lfOrientation = 900;
1350  hfont = CreateFontIndirectA(&lf);
1351  hfont = SelectObject(hdc, hfont);
1352  ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1353  ok(ret, "GetCharABCWidthsW should have succeeded\n");
1354 
1355  /* 3) compare ABC results */
1356  ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1357  "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1358  ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1359  "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1360  ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1361  "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1362 
1363  DeleteObject(SelectObject(hdc, hfont));
1364  ReleaseDC(NULL, hdc);
1365 
1366  trace("ABC sign test for a variety of transforms:\n");
1367  memset(&lf, 0, sizeof(lf));
1368  strcpy(lf.lfFaceName, "Tahoma");
1369  lf.lfHeight = 20;
1370  hfont = CreateFontIndirectA(&lf);
1371  hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1372  0, 0, 0, NULL);
1373  hdc = GetDC(hwnd);
1374  SetMapMode(hdc, MM_ANISOTROPIC);
1375  SelectObject(hdc, hfont);
1376 
1377  nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1378  ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1379 
1380  ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1381  ok(ret, "GetCharABCWidthsI should have succeeded\n");
1382  ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1383  ok(ret, "GetCharABCWidthsW should have succeeded\n");
1384  ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1385  ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1386 
1387  ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1388  SetWindowExtEx(hdc, -1, -1, NULL);
1390  ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1392  ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1393  SetWindowExtEx(hdc, 1, 1, NULL);
1395  ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1397  ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1398 
1399  ReleaseDC(hwnd, hdc);
1400  DestroyWindow(hwnd);
1401 
1402  trace("RTL layout\n");
1403  hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1404  0, 0, 0, NULL);
1405  hdc = GetDC(hwnd);
1406  SetMapMode(hdc, MM_ANISOTROPIC);
1407  SelectObject(hdc, hfont);
1408 
1409  ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1410  SetWindowExtEx(hdc, -1, -1, NULL);
1412  ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1414  ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1415  SetWindowExtEx(hdc, 1, 1, NULL);
1417  ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1419  ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1420 
1421  ReleaseDC(hwnd, hdc);
1422  DestroyWindow(hwnd);
1423  DeleteObject(hfont);
1424 }
1425 
1426 static void test_text_extents(void)
1427 {
1428  static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1429  static const WCHAR emptyW[] = {0};
1430  LPINT extents;
1431  INT i, len, fit1, fit2, extents2[3];
1432  LOGFONTA lf;
1433  TEXTMETRICA tm;
1434  HDC hdc;
1435  HFONT hfont;
1436  SIZE sz;
1437  SIZE sz1, sz2;
1438  BOOL ret;
1439 
1440  memset(&lf, 0, sizeof(lf));
1441  strcpy(lf.lfFaceName, "Arial");
1442  lf.lfHeight = 20;
1443 
1444  hfont = CreateFontIndirectA(&lf);
1445  hdc = GetDC(0);
1446  hfont = SelectObject(hdc, hfont);
1447  GetTextMetricsA(hdc, &tm);
1448  ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1449  ok(ret, "got %d\n", ret);
1450  ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1451 
1452  memset(&sz, 0xcc, sizeof(sz));
1453  ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1454  ok(ret, "got %d\n", ret);
1455  ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1456 
1457  memset(&sz, 0xcc, sizeof(sz));
1458  ret = GetTextExtentPointA(hdc, "", 0, &sz);
1459  ok(ret, "got %d\n", ret);
1460  ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1461 
1462  SetLastError(0xdeadbeef);
1463  GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1465  {
1466  win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1467  hfont = SelectObject(hdc, hfont);
1468  DeleteObject(hfont);
1469  ReleaseDC(0, hdc);
1470  return;
1471  }
1472 
1473  memset(&sz, 0xcc, sizeof(sz));
1474  ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1475  ok(ret, "got %d\n", ret);
1476  ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1477 
1478  memset(&sz, 0xcc, sizeof(sz));
1479  ret = GetTextExtentPointW(hdc, emptyW, 0, &sz);
1480  ok(ret, "got %d\n", ret);
1481  ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1482 
1483  len = lstrlenW(wt);
1484  extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1485  extents[0] = 1; /* So that the increasing sequence test will fail
1486  if the extents array is untouched. */
1487  GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1488  GetTextExtentPointW(hdc, wt, len, &sz2);
1489  ok(sz1.cy == sz2.cy,
1490  "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1491  /* Because of the '\n' in the string GetTextExtentExPoint and
1492  GetTextExtentPoint return different widths under Win2k, but
1493  under WinXP they return the same width. So we don't test that
1494  here. */
1495 
1496  for (i = 1; i < len; ++i)
1497  ok(extents[i-1] <= extents[i],
1498  "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1499  i);
1500  ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1501  ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1502  ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1503  GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1504  ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1505  ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1506  GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1507  ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1508  GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1509  ok(extents[0] == extents[2] && extents[1] == extents[3],
1510  "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1511  GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1512  ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1513  "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1514 
1515  /* extents functions fail with -ve counts (the interesting case being -1) */
1516  ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1517  ok(ret == FALSE, "got %d\n", ret);
1518  ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1519  ok(ret == FALSE, "got %d\n", ret);
1520  ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1521  ok(ret == FALSE, "got %d\n", ret);
1522 
1523  /* max_extent = 0 succeeds and returns zero */
1524  fit1 = fit2 = -215;
1525  ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1526  ok(ret == TRUE ||
1527  broken(ret == FALSE), /* NT4, 2k */
1528  "got %d\n", ret);
1529  ok(fit1 == 0 ||
1530  broken(fit1 == -215), /* NT4, 2k */
1531  "fit = %d\n", fit1);
1532  ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1533  ok(ret == TRUE, "got %d\n", ret);
1534  ok(fit2 == 0, "fit = %d\n", fit2);
1535 
1536  /* max_extent = -1 is interpreted as a very large width that will
1537  * definitely fit our three characters */
1538  fit1 = fit2 = -215;
1539  ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1540  ok(ret == TRUE, "got %d\n", ret);
1541  ok(fit1 == 3, "fit = %d\n", fit1);
1542  ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1543  ok(ret == TRUE, "got %d\n", ret);
1544  ok(fit2 == 3, "fit = %d\n", fit2);
1545 
1546  /* max_extent = -2 is interpreted similarly, but the Ansi version
1547  * rejects it while the Unicode one accepts it */
1548  fit1 = fit2 = -215;
1549  ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1550  ok(ret == FALSE, "got %d\n", ret);
1551  ok(fit1 == -215, "fit = %d\n", fit1);
1552  ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1553  ok(ret == TRUE, "got %d\n", ret);
1554  ok(fit2 == 3, "fit = %d\n", fit2);
1555 
1556  hfont = SelectObject(hdc, hfont);
1557  DeleteObject(hfont);
1558 
1559  /* non-MM_TEXT mapping mode */
1560  lf.lfHeight = 2000;
1561  hfont = CreateFontIndirectA(&lf);
1562  hfont = SelectObject(hdc, hfont);
1563 
1564  SetMapMode( hdc, MM_HIMETRIC );
1565  ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1566  ok(ret, "got %d\n", ret);
1567  ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1568 
1569  ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1570  ok(ret, "got %d\n", ret);
1571  ok(fit1 == 2, "got %d\n", fit1);
1572  ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1573  for(i = 0; i < 2; i++)
1574  ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1575 
1576  hfont = SelectObject(hdc, hfont);
1577  DeleteObject(hfont);
1578  HeapFree(GetProcessHeap(), 0, extents);
1579  ReleaseDC(NULL, hdc);
1580 }
1581 
1582 static void test_GetGlyphIndices(void)
1583 {
1584  HDC hdc;
1585  HFONT hfont;
1586  DWORD charcount;
1587  LOGFONTA lf;
1588  DWORD flags = 0;
1589  WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1590  WORD glyphs[(sizeof(testtext)/2)-1];
1591  TEXTMETRICA textm;
1592  HFONT hOldFont;
1593 
1594  if (!pGetGlyphIndicesW) {
1595  win_skip("GetGlyphIndicesW not available on platform\n");
1596  return;
1597  }
1598 
1599  hdc = GetDC(0);
1600 
1601  memset(&lf, 0, sizeof(lf));
1602  strcpy(lf.lfFaceName, "System");
1603  lf.lfHeight = 16;
1604  lf.lfCharSet = ANSI_CHARSET;
1605 
1606  hfont = CreateFontIndirectA(&lf);
1607  ok(hfont != 0, "CreateFontIndirectEx failed\n");
1608  ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1609  if (textm.tmCharSet == ANSI_CHARSET)
1610  {
1611  flags |= GGI_MARK_NONEXISTING_GLYPHS;
1612  charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1613  ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1614  ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1615  flags = 0;
1616  charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1617  ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1618  ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1619  textm.tmDefaultChar, glyphs[4]);
1620  }
1621  else
1622  /* FIXME: Write tests for non-ANSI charsets. */
1623  skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1624 
1625  if(!is_font_installed("Tahoma"))
1626  {
1627  skip("Tahoma is not installed so skipping this test\n");
1628  return;
1629  }
1630  memset(&lf, 0, sizeof(lf));
1631  strcpy(lf.lfFaceName, "Tahoma");
1632  lf.lfHeight = 20;
1633 
1634  hfont = CreateFontIndirectA(&lf);
1635  hOldFont = SelectObject(hdc, hfont);
1636  ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1637  flags |= GGI_MARK_NONEXISTING_GLYPHS;
1638  charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1639  ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1640  ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1641  flags = 0;
1642  testtext[0] = textm.tmDefaultChar;
1643  charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1644  ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1645  ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1646  ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1647  DeleteObject(SelectObject(hdc, hOldFont));
1648 }
1649 
1650 static void test_GetKerningPairs(void)
1651 {
1652  static const struct kerning_data
1653  {
1654  const char face_name[LF_FACESIZE];
1655  LONG height;
1656  /* some interesting fields from OUTLINETEXTMETRIC */
1657  LONG tmHeight, tmAscent, tmDescent;
1658  UINT otmEMSquare;
1659  INT otmAscent;
1660  INT otmDescent;
1661  UINT otmLineGap;
1662  UINT otmsCapEmHeight;
1663  UINT otmsXHeight;
1664  INT otmMacAscent;
1665  INT otmMacDescent;
1666  UINT otmMacLineGap;
1667  UINT otmusMinimumPPEM;
1668  /* small subset of kerning pairs to test */
1669  DWORD total_kern_pairs;
1670  const KERNINGPAIR kern_pair[26];
1671  } kd[] =
1672  {
1673  {"Arial", 12, 12, 9, 3,
1674  2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1675  26,
1676  {
1677  {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1678  {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1679  {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1680  {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1681  {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1682  {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1683  {933,970,+1},{933,972,-1}
1684  }
1685  },
1686  {"Arial", -34, 39, 32, 7,
1687  2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1688  26,
1689  {
1690  {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1691  {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1692  {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1693  {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1694  {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1695  {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1696  {933,970,+2},{933,972,-3}
1697  }
1698  },
1699  { "Arial", 120, 120, 97, 23,
1700  2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1701  26,
1702  {
1703  {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1704  {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1705  {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1706  {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1707  {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1708  {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1709  {933,970,+6},{933,972,-10}
1710  }
1711  },
1712 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1713  { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1714  2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1715  26,
1716  {
1717  {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1718  {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1719  {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1720  {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1721  {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1722  {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1723  {933,970,+54},{933,972,-83}
1724  }
1725  }
1726 #endif
1727  };
1728  LOGFONTA lf;
1729  HFONT hfont, hfont_old;
1730  KERNINGPAIR *kern_pair;
1731  HDC hdc;
1732  DWORD total_kern_pairs, ret, i, n, matches;
1733 
1734  hdc = GetDC(0);
1735 
1736  /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1737  * which may render this test unusable, so we're trying to avoid that.
1738  */
1739  SetLastError(0xdeadbeef);
1740  GetKerningPairsW(hdc, 0, NULL);
1742  {
1743  win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1744  ReleaseDC(0, hdc);
1745  return;
1746  }
1747 
1748  for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1749  {
1750  OUTLINETEXTMETRICW otm;
1751  UINT uiRet;
1752 
1753  if (!is_font_installed(kd[i].face_name))
1754  {
1755  trace("%s is not installed so skipping this test\n", kd[i].face_name);
1756  continue;
1757  }
1758 
1759  trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1760 
1761  memset(&lf, 0, sizeof(lf));
1762  strcpy(lf.lfFaceName, kd[i].face_name);
1763  lf.lfHeight = kd[i].height;
1764  hfont = CreateFontIndirectA(&lf);
1765  ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name);
1766 
1767  hfont_old = SelectObject(hdc, hfont);
1768 
1769  SetLastError(0xdeadbeef);
1770  otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1771  uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1772  ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1773 
1774  ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1775  kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1776  ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1777  kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1778  ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1779  kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1780 
1781  ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1782  kd[i].otmEMSquare, otm.otmEMSquare);
1783  ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1784  kd[i].otmAscent, otm.otmAscent);
1785  ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1786  kd[i].otmDescent, otm.otmDescent);
1787  ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1788  kd[i].otmLineGap, otm.otmLineGap);
1789  ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1790  kd[i].otmMacDescent, otm.otmMacDescent);
1791  ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1792  kd[i].otmMacAscent, otm.otmMacAscent);
1793 todo_wine {
1794  ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1795  kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1796  ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1797  kd[i].otmsXHeight, otm.otmsXHeight);
1798  /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1799  if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1800  kd[i].otmMacLineGap, otm.otmMacLineGap);
1801  ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1802  kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1803 }
1804 
1805  total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1806  trace("total_kern_pairs %u\n", total_kern_pairs);
1807  kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1808 
1809  /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1810  * passes on XP.
1811  */
1812  SetLastError(0xdeadbeef);
1813  ret = GetKerningPairsW(hdc, 0, kern_pair);
1815  "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1816  ok(ret == 0, "got %u, expected 0\n", ret);
1817 
1818  ret = GetKerningPairsW(hdc, 100, NULL);
1819  ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1820 
1821  ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1822  ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1823 
1824  ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1825  ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1826 
1827  matches = 0;
1828 
1829  for (n = 0; n < ret; n++)
1830  {
1831  DWORD j;
1832  /* Disabled to limit console spam */
1833  if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1834  trace("{'%c','%c',%d},\n",
1835  kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1836  for (j = 0; j < kd[i].total_kern_pairs; j++)
1837  {
1838  if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1839  kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1840  {
1841  ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1842  "pair %d:%d got %d, expected %d\n",
1843  kern_pair[n].wFirst, kern_pair[n].wSecond,
1844  kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1845  matches++;
1846  }
1847  }
1848  }
1849 
1850  ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1851  matches, kd[i].total_kern_pairs);
1852 
1853  HeapFree(GetProcessHeap(), 0, kern_pair);
1854 
1855  SelectObject(hdc, hfont_old);
1856  DeleteObject(hfont);
1857  }
1858 
1859  ReleaseDC(0, hdc);
1860 }
1861 
1863 {
1864  const char face_name[LF_FACESIZE];
1868 };
1869 
1870 static void test_height( HDC hdc, const struct font_data *fd )
1871 {
1872  LOGFONTA lf;
1873  HFONT hfont, old_hfont;
1874  TEXTMETRICA tm;
1875  INT ret, i;
1876 
1877  for (i = 0; fd[i].face_name[0]; i++)
1878  {
1879  if (!is_truetype_font_installed(fd[i].face_name))
1880  {
1881  skip("%s is not installed\n", fd[i].face_name);
1882  continue;
1883  }
1884 
1885  memset(&lf, 0, sizeof(lf));
1886  lf.lfHeight = fd[i].requested_height;
1887  lf.lfWeight = fd[i].weight;
1888  strcpy(lf.lfFaceName, fd[i].face_name);
1889 
1890  hfont = CreateFontIndirectA(&lf);
1891  ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
1892 
1893  old_hfont = SelectObject(hdc, hfont);
1894  ret = GetTextMetricsA(hdc, &tm);
1895  ok(ret, "GetTextMetrics error %d\n", GetLastError());
1896  if(fd[i].dpi == tm.tmDigitizedAspectX)
1897  {
1898  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);
1899  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);
1900  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);
1901  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);
1902  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);
1903  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);
1904  }
1905 
1906  SelectObject(hdc, old_hfont);
1907  /* force GDI to use new font, otherwise Windows leaks the font reference */
1908  GetTextMetricsA(hdc, &tm);
1909  DeleteObject(hfont);
1910  }
1911 }
1912 
1913 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1914 {
1915  WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1916  DWORD *table = (DWORD *)ttf + 3;
1917 
1918  for (i = 0; i < num_tables; i++)
1919  {
1920  if (table[0] == tag)
1921  return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1922  table += 4;
1923  }
1924  return NULL;
1925 }
1926 
1928 {
1929  static const struct font_data charset_0[] = /* doesn't use VDMX */
1930  {
1931  { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1932  { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1933  { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1934  { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1935  { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1936  { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1937  { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1938  { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1939  { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1940  { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1941  { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1942  { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1943  { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1944  { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1945  { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1946  { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1947  { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1948  { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1949  { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1950  { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1951  { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1952  { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1953  { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1954  { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1955  { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1956  { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1957  { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1958  { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1959  { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1960  { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1961  { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1962  { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1963  { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1964  { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1965  { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1966  { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1967  { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1968  { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1969  { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1970  { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1971  { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1972  { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1973  { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1974  { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1975  { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1976  { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1977  { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1978  { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1979  { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1980  { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1981  { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1982  { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1983  { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1984  };
1985 
1986  static const struct font_data charset_1[] = /* Uses VDMX */
1987  {
1988  { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1989  { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1990  { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1991  { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1992  { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1993  { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1994  { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1995  { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1996  { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1997  { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1998  { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1999  { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2000  { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2001  { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2002  { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2003  { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2004  { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2005  { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2006  { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2007  { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2008  { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2009  { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2010  { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2011  { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
2012  { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
2013  { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
2014  { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2015  { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2016  { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2017  { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2018  { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2019  { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2020  { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2021  { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2022  { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2023  { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2024  { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2025  { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2026  { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2027  { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2028  { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2029  { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2030  { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2031  { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2032  { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2033  { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2034  { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2035  { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2036  { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2037  { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2038  { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2039  { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2040  { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2041  };
2042 
2043  static const struct vdmx_data
2044  {
2045  WORD version;
2046  BYTE bCharSet;
2047  const struct font_data *fd;
2048  } data[] =
2049  {
2050  { 0, 0, charset_0 },
2051  { 0, 1, charset_1 },
2052  { 1, 0, charset_0 },
2053  { 1, 1, charset_1 }
2054  };
2055  int i;
2056  DWORD size, num;
2057  WORD *vdmx_header;
2058  BYTE *ratio_rec;
2059  char ttf_name[MAX_PATH];
2060  void *res, *copy;
2061  BOOL ret;
2062 
2063  if (!pAddFontResourceExA)
2064  {
2065  win_skip("AddFontResourceExA unavailable\n");
2066  return;
2067  }
2068 
2069  for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2070  {
2071  res = get_res_data( "wine_vdmx.ttf", &size );
2072 
2073  copy = HeapAlloc( GetProcessHeap(), 0, size );
2074  memcpy( copy, res, size );
2075  vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2076  vdmx_header[0] = GET_BE_WORD( data[i].version );
2077  ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2078  ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2079  ratio_rec = (BYTE *)&vdmx_header[3];
2080  ratio_rec[0] = data[i].bCharSet;
2081 
2082  write_tmp_file( copy, &size, ttf_name );
2083  HeapFree( GetProcessHeap(), 0, copy );
2084 
2085  ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2086  num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2087  if (!num) win_skip("Unable to add ttf font resource\n");
2088  else
2089  {
2090  ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2091  test_height( hdc, data[i].fd );
2092  pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2093  }
2094  ret = DeleteFileA( ttf_name );
2095  ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2096  "DeleteFile error %d\n", GetLastError());
2097  }
2098 }
2099 
2100 static void test_height_selection(void)
2101 {
2102  static const struct font_data tahoma[] =
2103  {
2104  {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2105  {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2106  {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2107  {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2108  {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2109  {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2110  {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2111  {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2112  {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2113  {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2114  {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2115  };
2116  HDC hdc = CreateCompatibleDC(0);
2117  ok(hdc != NULL, "failed to create hdc\n");
2118 
2119  test_height( hdc, tahoma );
2121 
2122  DeleteDC(hdc);
2123 }
2124 
2126 {
2127  OUTLINETEXTMETRICA *otm;
2128  HFONT hfont, hfont_old;
2129  DWORD ret, otm_size;
2130  UINT fsSelection;
2131  HDC hdc;
2132 
2133  hdc = GetDC(0);
2134  hfont = CreateFontIndirectA(lf);
2135  ok(hfont != NULL, "failed to create a font\n");
2136 
2137  hfont_old = SelectObject(hdc, hfont);
2138 
2139  otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2140  otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2141  otm->otmSize = sizeof(*otm);
2142  ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2143  ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2144  fsSelection = otm->otmfsSelection;
2145  HeapFree(GetProcessHeap(), 0, otm);
2146  SelectObject(hdc, hfont_old);
2147  DeleteObject(hfont);
2148  ReleaseDC(0, hdc);
2149 
2150  return fsSelection;
2151 }
2152 
2154 {
2155  OUTLINETEXTMETRICA *otm;
2156  LOGFONTA lf;
2157  HFONT hfont, hfont_old;
2158  HDC hdc;
2159  DWORD ret, otm_size;
2160  LPSTR unset_ptr;
2161  UINT fsSelection;
2162 
2163  /* check fsSelection field with bold simulation */
2164  memset(&lf, 0, sizeof(lf));
2165  strcpy(lf.lfFaceName, "Wingdings");
2167 
2168  /* regular face */
2169  fsSelection = get_font_fsselection(&lf);
2170  ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection);
2171 
2172  /* face with bold simulation */
2173  lf.lfWeight = FW_BOLD;
2174  fsSelection = get_font_fsselection(&lf);
2175  ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection);
2176 
2177  /* check fsSelection field with oblique simulation */
2178  memset(&lf, 0, sizeof(lf));
2179  strcpy(lf.lfFaceName, "Tahoma");
2180  lf.lfHeight = -13;
2181  lf.lfWeight = FW_NORMAL;
2183  lf.lfQuality = PROOF_QUALITY;
2184 
2185  /* regular face */
2186  fsSelection = get_font_fsselection(&lf);
2187  ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection);
2188 
2189  lf.lfItalic = 1;
2190  /* face with oblique simulation */
2191  fsSelection = get_font_fsselection(&lf);
2192  ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection);
2193 
2194  if (!is_font_installed("Arial"))
2195  {
2196  skip("Arial is not installed\n");
2197  return;
2198  }
2199 
2200  hdc = GetDC(0);
2201 
2202  memset(&lf, 0, sizeof(lf));
2203  strcpy(lf.lfFaceName, "Arial");
2204  lf.lfHeight = -13;
2205  lf.lfWeight = FW_NORMAL;
2207  lf.lfQuality = PROOF_QUALITY;
2208  hfont = CreateFontIndirectA(&lf);
2209  ok(hfont != NULL, "failed to create a font\n");
2210 
2211  hfont_old = SelectObject(hdc, hfont);
2212  otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2213  trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2214 
2215  otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2216 
2217  memset(otm, 0xAA, otm_size);
2218  SetLastError(0xdeadbeef);
2219  otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2220  ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2221  ok(ret == 1 /* Win9x */ ||
2222  ret == otm->otmSize /* XP*/,
2223  "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2224  if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2225  {
2226  ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2227  ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2228  ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2229  ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2230  }
2231 
2232  memset(otm, 0xAA, otm_size);
2233  SetLastError(0xdeadbeef);
2234  otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2235  ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2236  ok(ret == 1 /* Win9x */ ||
2237  ret == otm->otmSize /* XP*/,
2238  "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2239  if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2240  {
2241  ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2242  ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2243  ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2244  ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2245  }
2246 
2247  /* ask about truncated data */
2248  memset(otm, 0xAA, otm_size);
2249  memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2250  SetLastError(0xdeadbeef);
2251  otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2252  ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2253  ok(ret == 1 /* Win9x */ ||
2254  ret == otm->otmSize /* XP*/,
2255  "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2256  if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2257  {
2258  ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2259  ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2260  ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2261  }
2262  ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2263 
2264  /* check handling of NULL pointer */
2265  SetLastError(0xdeadbeef);
2266  ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2267  ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2268 
2269  HeapFree(GetProcessHeap(), 0, otm);
2270 
2271  SelectObject(hdc, hfont_old);
2272  DeleteObject(hfont);
2273 
2274  ReleaseDC(0, hdc);
2275 }
2276 
2277 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2278 {
2279  INT y,
2280  breakCount,
2281  areaWidth = clientArea->right - clientArea->left,
2282  nErrors = 0, e;
2283  const char *pFirstChar, *pLastChar;
2284  SIZE size;
2285  TEXTMETRICA tm;
2286  struct err
2287  {
2288  const char *start;
2289  int len;
2290  int GetTextExtentExPointWWidth;
2291  } error[20];
2292 
2293  GetTextMetricsA(hdc, &tm);
2294  y = clientArea->top;
2295  do {
2296  breakCount = 0;
2297  while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2298  pFirstChar = str;
2299 
2300  do {
2301  pLastChar = str;
2302 
2303  /* if not at the end of the string, ... */
2304  if (*str == '\0') break;
2305  /* ... add the next word to the current extent */
2306  while (*str != '\0' && *str++ != tm.tmBreakChar);
2307  breakCount++;
2308  SetTextJustification(hdc, 0, 0);
2309  GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2310  } while ((int) size.cx < areaWidth);
2311 
2312  /* ignore trailing break chars */
2313  breakCount--;
2314  while (*(pLastChar - 1) == tm.tmBreakChar)
2315  {
2316  pLastChar--;
2317  breakCount--;
2318  }
2319 
2320  if (*str == '\0' || breakCount <= 0) pLastChar = str;
2321 
2322  SetTextJustification(hdc, 0, 0);
2323  GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2324 
2325  /* do not justify the last extent */
2326  if (*str != '\0' && breakCount > 0)
2327  {
2328  SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2329  GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2330  if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2331  {
2332  error[nErrors].start = pFirstChar;
2333  error[nErrors].len = pLastChar - pFirstChar;
2334  error[nErrors].GetTextExtentExPointWWidth = size.cx;
2335  nErrors++;
2336  }
2337  }
2338 
2339  y += size.cy;
2340  str = pLastChar;
2341  } while (*str && y < clientArea->bottom);
2342 
2343  for (e = 0; e < nErrors; e++)
2344  {
2345  /* The width returned by GetTextExtentPoint32() is exactly the same
2346  returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2347  ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2348  "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2349  error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2350  }
2351 }
2352 
2353 static void test_SetTextJustification(void)
2354 {
2355  HDC hdc;
2356  RECT clientArea;
2357  LOGFONTA lf;
2358  HFONT hfont;
2359  HWND hwnd;
2360  SIZE size, expect;
2361  int i;
2362  WORD indices[2];
2363  static const char testText[] =
2364  "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2365  "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2366  "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2367  "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2368  "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2369  "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2370  "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2371 
2372  hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2373  GetClientRect( hwnd, &clientArea );
2374  hdc = GetDC( hwnd );
2375 
2376  if (!is_font_installed("Times New Roman"))
2377  {
2378  skip("Times New Roman is not installed\n");
2379  return;
2380  }
2381 
2382  memset(&lf, 0, sizeof lf);
2383  lf.lfCharSet = ANSI_CHARSET;
2385  lf.lfWeight = FW_DONTCARE;
2386  lf.lfHeight = 20;
2388  lstrcpyA(lf.lfFaceName, "Times New Roman");
2389  hfont = create_font("Times New Roman", &lf);
2390  SelectObject(hdc, hfont);
2391 
2392  testJustification(hdc, testText, &clientArea);
2393 
2394  if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2395  pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2396 
2397  SetTextJustification(hdc, 0, 0);
2398  GetTextExtentPoint32A(hdc, " ", 1, &expect);
2399  GetTextExtentPoint32A(hdc, " ", 3, &size);
2400  ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2401  SetTextJustification(hdc, 4, 1);
2402  GetTextExtentPoint32A(hdc, " ", 1, &size);
2403  ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2404  SetTextJustification(hdc, 9, 2);
2405  GetTextExtentPoint32A(hdc, " ", 2, &size);
2406  ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2407  SetTextJustification(hdc, 7, 3);
2408  GetTextExtentPoint32A(hdc, " ", 3, &size);
2409  ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2410  SetTextJustification(hdc, 7, 3);
2411  SetTextCharacterExtra(hdc, 2 );
2412  GetTextExtentPoint32A(hdc, " ", 3, &size);
2413  ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2414  SetTextJustification(hdc, 0, 0);
2415  SetTextCharacterExtra(hdc, 0);
2416  size.cx = size.cy = 1234;
2417  GetTextExtentPoint32A(hdc, " ", 0, &size);
2418  ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2419  pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2420  SetTextJustification(hdc, 5, 1);
2421  pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2422  ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2423  SetTextJustification(hdc, 0, 0);
2424 
2425  SetMapMode( hdc, MM_ANISOTROPIC );
2426  SetWindowExtEx( hdc, 2, 2, NULL );
2427  GetClientRect( hwnd, &clientArea );
2428  DPtoLP( hdc, (POINT *)&clientArea, 2 );
2429  testJustification(hdc, testText, &clientArea);
2430 
2431  GetTextExtentPoint32A(hdc, "A", 1, &expect);
2432  for (i = 0; i < 10; i++)
2433  {
2434  SetTextCharacterExtra(hdc, i);
2435  GetTextExtentPoint32A(hdc, "A", 1, &size);
2436  ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2437  }
2438  SetTextCharacterExtra(hdc, 0);
2439  pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2440  for (i = 0; i < 10; i++)
2441  {
2442  SetTextCharacterExtra(hdc, i);
2443  pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2444  ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2445  }
2446  SetTextCharacterExtra(hdc, 0);
2447 
2448  SetViewportExtEx( hdc, 3, 3, NULL );
2449  GetClientRect( hwnd, &clientArea );
2450  DPtoLP( hdc, (POINT *)&clientArea, 2 );
2451  testJustification(hdc, testText, &clientArea);
2452 
2453  GetTextExtentPoint32A(hdc, "A", 1, &expect);
2454  for (i = 0; i < 10; i++)
2455  {
2456  SetTextCharacterExtra(hdc, i);
2457  GetTextExtentPoint32A(hdc, "A", 1, &size);
2458  ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2459  }
2460 
2461 done:
2462  DeleteObject(hfont);
2463  ReleaseDC(hwnd, hdc);
2464  DestroyWindow(hwnd);
2465 }
2466 
2467 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2468 {
2469  HDC hdc;
2470  LOGFONTA lf;
2471  HFONT hfont, hfont_old;
2472  CHARSETINFO csi;
2473  FONTSIGNATURE fs;
2474  INT cs;
2475  DWORD i, ret;
2476  char name[64];
2477 
2478  assert(count <= 128);
2479 
2480  memset(&lf, 0, sizeof(lf));
2481 
2482  lf.lfCharSet = charset;
2483  lf.lfHeight = 10;
2484  lstrcpyA(lf.lfFaceName, "Arial");
2485  SetLastError(0xdeadbeef);
2486  hfont = CreateFontIndirectA(&lf);
2487  ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2488 
2489  hdc = GetDC(0);
2490  hfont_old = SelectObject(hdc, hfont);
2491 
2492  cs = GetTextCharsetInfo(hdc, &fs, 0);
2493  ok(cs == charset, "expected %d, got %d\n", charset, cs);
2494 
2495  SetLastError(0xdeadbeef);
2496  ret = GetTextFaceA(hdc, sizeof(name), name);
2497  ok(ret, "GetTextFaceA error %u\n", GetLastError());
2498 
2499  if (charset == SYMBOL_CHARSET)
2500  {
2501  ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2502  ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n");
2503  }
2504  else
2505  {
2506  ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2507  ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2508  }
2509 
2510  if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2511  {
2512  trace("Can't find codepage for charset %d\n", cs);
2513  ReleaseDC(0, hdc);
2514  return FALSE;
2515  }
2516  ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2517 
2518  if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2519  {
2520  skip("Font code page %d, looking for code page %d\n",
2521  pGdiGetCodePage(hdc), code_page);
2522  ReleaseDC(0, hdc);
2523  return FALSE;
2524  }
2525 
2526  if (unicode)
2527  {
2528  char ansi_buf[128];
2529  WCHAR unicode_buf[128];
2530 
2531  for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2532 
2533  MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2534 
2535  SetLastError(0xdeadbeef);
2536  ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2537  ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2538  count, ret, GetLastError());
2539  }
2540  else
2541  {
2542  char ansi_buf[128];
2543 
2544  for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2545 
2546  SetLastError(0xdeadbeef);
2547  ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2548  ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2549  count, ret, GetLastError());
2550  }
2551 
2552  SelectObject(hdc, hfont_old);
2553  DeleteObject(hfont);
2554 
2555  ReleaseDC(0, hdc);
2556 
2557  return TRUE;
2558 }
2559 
2560 static void test_font_charset(void)
2561 {
2562  static struct charset_data
2563  {
2564  INT charset;
2565  UINT code_page;
2566  WORD font_idxA[128], font_idxW[128];
2567  } cd[] =
2568  {
2569  { ANSI_CHARSET, 1252 },
2570  { RUSSIAN_CHARSET, 1251 },
2571  { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2572  };
2573  int i;
2574 
2575  if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2576  {
2577  win_skip("Skipping the font charset test on a Win9x platform\n");
2578  return;
2579  }
2580 
2581  if (!is_font_installed("Arial"))
2582  {
2583  skip("Arial is not installed\n");
2584  return;
2585  }
2586 
2587  for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2588  {
2589  if (cd[i].charset == SYMBOL_CHARSET)
2590  {
2591  if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2592  {
2593  skip("Symbol or Wingdings is not installed\n");
2594  break;
2595  }
2596  }
2597  if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2598  get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2599  ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2600  }
2601 
2602  ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2603  if (i > 2)
2604  {
2605  ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2606  ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2607  }
2608  else
2609  skip("Symbol or Wingdings is not installed\n");
2610 }
2611 
2612 static void test_GdiGetCodePage(void)
2613 {
2614  static const struct _matching_data
2615  {
2616  UINT current_codepage;
2617  LPCSTR lfFaceName;
2618  UCHAR lfCharSet;
2619  UINT expected_codepage;
2620  } matching_data[] = {
2621  {1251, "Arial", ANSI_CHARSET, 1252},
2622  {1251, "Tahoma", ANSI_CHARSET, 1252},
2623 
2624  {1252, "Arial", ANSI_CHARSET, 1252},
2625  {1252, "Tahoma", ANSI_CHARSET, 1252},
2626 
2627  {1253, "Arial", ANSI_CHARSET, 1252},
2628  {1253, "Tahoma", ANSI_CHARSET, 1252},
2629 
2630  { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2631  { 932, "Tahoma", ANSI_CHARSET, 1252},
2632  { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2633 
2634  { 936, "Arial", ANSI_CHARSET, 936},
2635  { 936, "Tahoma", ANSI_CHARSET, 936},
2636  { 936, "Simsun", ANSI_CHARSET, 936},
2637 
2638  { 949, "Arial", ANSI_CHARSET, 949},
2639  { 949, "Tahoma", ANSI_CHARSET, 949},
2640  { 949, "Gulim", ANSI_CHARSET, 949},
2641 
2642  { 950, "Arial", ANSI_CHARSET, 950},
2643  { 950, "Tahoma", ANSI_CHARSET, 950},
2644  { 950, "PMingLiU", ANSI_CHARSET, 950},
2645  };
2646  HDC hdc;
2647  LOGFONTA lf;
2648  HFONT hfont;
2649  UINT charset, acp;
2650  DWORD codepage;
2651  int i;
2652 
2653  if (!pGdiGetCodePage)
2654  {
2655  skip("GdiGetCodePage not available on this platform\n");
2656  return;
2657  }
2658 
2659  acp = GetACP();
2660 
2661  for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2662  {
2663  /* only test data matched current locale codepage */
2664  if (matching_data[i].current_codepage != acp)
2665  continue;
2666 
2667  if (!is_font_installed(matching_data[i].lfFaceName))
2668  {
2669  skip("%s is not installed\n", matching_data[i].lfFaceName);
2670  continue;
2671  }
2672 
2673  hdc = GetDC(0);
2674 
2675  memset(&lf, 0, sizeof(lf));
2676  lf.lfHeight = -16;
2677  lf.lfCharSet = matching_data[i].lfCharSet;
2678  lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2679  hfont = CreateFontIndirectA(&lf);
2680  ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2681 
2682  hfont = SelectObject(hdc, hfont);
2683  charset = GetTextCharset(hdc);
2684  codepage = pGdiGetCodePage(hdc);
2685  trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2686  acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2687  ok(codepage == matching_data[i].expected_codepage,
2688  "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2689 
2690  hfont = SelectObject(hdc, hfont);
2691  DeleteObject(hfont);
2692 
2693  /* CLIP_DFA_DISABLE turns off the font association */
2695  hfont = CreateFontIndirectA(&lf);
2696  ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2697 
2698  hfont = SelectObject(hdc, hfont);
2699  charset = GetTextCharset(hdc);
2700  codepage = pGdiGetCodePage(hdc);
2701  trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2702  acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2703  ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2704 
2705  hfont = SelectObject(hdc, hfont);
2706  DeleteObject(hfont);
2707 
2708  ReleaseDC(NULL, hdc);
2709  }
2710 }
2711 
2712 static void test_GetFontUnicodeRanges(void)
2713 {
2714  LOGFONTA lf;
2715  HDC hdc;
2716  HFONT hfont, hfont_old;
2717  DWORD size;
2718  GLYPHSET *gs;
2719  DWORD i;
2720 
2721  if (!pGetFontUnicodeRanges)
2722  {
2723  win_skip("GetFontUnicodeRanges not available before W2K\n");
2724  return;
2725  }
2726 
2727  memset(&lf, 0, sizeof(lf));
2728  lstrcpyA(lf.lfFaceName, "Arial");
2729  hfont = create_font("Arial", &lf);
2730 
2731  hdc = GetDC(0);
2732  hfont_old = SelectObject(hdc, hfont);
2733 
2734  size = pGetFontUnicodeRanges(NULL, NULL);
2735  ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2736 
2737  size = pGetFontUnicodeRanges(hdc, NULL);
2738  ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2739 
2740  gs = HeapAlloc(GetProcessHeap(), 0, size);
2741 
2742  size = pGetFontUnicodeRanges(hdc, gs);
2743  ok(size, "GetFontUnicodeRanges failed\n");
2744 
2745  if (0) /* Disabled to limit console spam */
2746  for (i = 0; i < gs->cRanges; i++)
2747  trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2748  trace("found %u ranges\n", gs->cRanges);
2749 
2750  HeapFree(GetProcessHeap(), 0, gs);
2751 
2752  SelectObject(hdc, hfont_old);
2753  DeleteObject(hfont);
2754  ReleaseDC(NULL, hdc);
2755 }
2756 
2758 {
2759  int total, size;
2761 };
2762 
2764 {
2765  int total, size;
2767 };
2768 
2770 {
2771  int total, size;
2773 };
2774 
2776 {
2777  struct enum_font_data *efd = (struct enum_font_data *)lParam;
2778  const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2779 
2780  ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2781  ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2782 
2783  if (type != TRUETYPE_FONTTYPE) return 1;
2784 
2785  ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2786 
2787  if (0) /* Disabled to limit console spam */
2788  trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2789  lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2790  if (efd->total >= efd->size)
2791  {
2792  efd->size = max( (efd->total + 1) * 2, 256 );
2793  efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2794  if (!efd->lf) return 0;
2795  }
2796  efd->lf[efd->total++] = *lf;
2797 
2798  return 1;
2799 }
2800 
2802 {
2803  struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2804  const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2805 
2806  ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2807  ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2808 
2809  if (type != TRUETYPE_FONTTYPE) return 1;
2810 
2811  ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2812 
2813  if (0) /* Disabled to limit console spam */
2814  trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2815  wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2816  if (efd->total >= efd->size)
2817  {
2818  efd->size = max( (efd->total + 1) * 2, 256 );
2819  efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2820  if (!efd->lf) return 0;
2821  }
2822  efd->lf[efd->total++] = *lf;
2823 
2824  return 1;
2825 }
2826 
2827 static void get_charset_stats(struct enum_font_data *efd,
2828  int *ansi_charset, int *symbol_charset,
2829  int *russian_charset)
2830 {
2831  int i;
2832 
2833  *ansi_charset = 0;
2834  *symbol_charset = 0;
2835  *russian_charset = 0;
2836 
2837  for (i = 0; i < efd->total; i++)
2838  {
2839  switch (efd->lf[i].lfCharSet)
2840  {
2841  case ANSI_CHARSET:
2842  (*ansi_charset)++;
2843  break;
2844  case SYMBOL_CHARSET:
2845  (*symbol_charset)++;
2846  break;
2847  case RUSSIAN_CHARSET:
2848  (*russian_charset)++;
2849  break;
2850  }
2851  }
2852 }
2853 
2854 static void get_charset_statsW(struct enum_font_dataW *efd,
2855  int *ansi_charset, int *symbol_charset,
2856  int *russian_charset)
2857 {
2858  int i;
2859 
2860  *ansi_charset = 0;
2861  *symbol_charset = 0;
2862  *russian_charset = 0;
2863 
2864  for (i = 0; i < efd->total; i++)
2865  {
2866  switch (efd->lf[i].lfCharSet)
2867  {
2868  case ANSI_CHARSET:
2869  (*ansi_charset)++;
2870  break;
2871  case SYMBOL_CHARSET:
2872  (*symbol_charset)++;
2873  break;
2874  case RUSSIAN_CHARSET:
2875  (*russian_charset)++;
2876  break;
2877  }
2878  }
2879 }
2880 
2881 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2882 {
2883  struct enum_font_data efd;
2884  struct enum_font_dataW efdw;
2885  LOGFONTA lf;
2886  HDC hdc;
2887  int i, ret, ansi_charset, symbol_charset, russian_charset;
2888 
2889  trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2890 
2891  if (*font_name && !is_truetype_font_installed(font_name))
2892  {
2893  skip("%s is not installed\n", font_name);
2894  return;
2895  }
2896  memset( &efd, 0, sizeof(efd) );
2897  memset( &efdw, 0, sizeof(efdw) );
2898 
2899  hdc = GetDC(0);
2900 
2901  /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2902  * while EnumFontFamiliesEx doesn't.
2903  */
2904  if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2905  {
2906  /*
2907  * Use EnumFontFamiliesW since win98 crashes when the
2908  * second parameter is NULL using EnumFontFamilies
2909  */
2910  efdw.total = 0;
2911  SetLastError(0xdeadbeef);
2912  ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2913  ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2914  if(ret)
2915  {
2916  get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2917  trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2918  ansi_charset, symbol_charset, russian_charset);
2919  ok(efdw.total > 0, "fonts enumerated: NULL\n");
2920  ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2921  ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2922  ok(russian_charset > 0 ||
2923  broken(russian_charset == 0), /* NT4 */
2924  "NULL family should enumerate RUSSIAN_CHARSET\n");
2925  }
2926 
2927  efdw.total = 0;
2928  SetLastError(0xdeadbeef);
2929  ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2930  ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2931  if(ret)
2932  {
2933  get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2934  trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2935  ansi_charset, symbol_charset, russian_charset);
2936  ok(efdw.total > 0, "fonts enumerated: NULL\n");
2937  ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2938  ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2939  ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2940  }
2941  }
2942 
2943  efd.total = 0;
2944  SetLastError(0xdeadbeef);
2945  ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2946  ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2947  get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2948  trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2949  ansi_charset, symbol_charset, russian_charset,
2950  *font_name ? font_name : "<empty>");
2951  if (*font_name)
2952  ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2953  else
2954  ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2955  for (i = 0; i < efd.total; i++)
2956  {
2957  /* FIXME: remove completely once Wine is fixed */
2958  todo_wine_if(efd.lf[i].lfCharSet != font_charset)
2959  ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2960  ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2961  font_name, efd.lf[i].lfFaceName);
2962  }
2963 
2964  memset(&lf, 0, sizeof(lf));
2965  lf.lfCharSet = ANSI_CHARSET;
2966  strcpy(lf.lfFaceName, font_name);
2967  efd.total = 0;
2968  SetLastError(0xdeadbeef);
2969  ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2970  ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2971  get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2972  trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2973  ansi_charset, symbol_charset, russian_charset,
2974  *font_name ? font_name : "<empty>");
2975  if (font_charset == SYMBOL_CHARSET)
2976  {
2977  if (*font_name)
2978  ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2979  else
2980  ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2981  }
2982  else
2983  {
2984  ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2985  for (i = 0; i < efd.total; i++)
2986  {
2987  ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2988  if (*font_name)
2989  ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2990  font_name, efd.lf[i].lfFaceName);
2991  }
2992  }
2993 
2994  /* DEFAULT_CHARSET should enumerate all available charsets */
2995  memset(&lf, 0, sizeof(lf));
2996  lf.lfCharSet = DEFAULT_CHARSET;
2997  strcpy(lf.lfFaceName, font_name);
2998  efd.total = 0;
2999  SetLastError(0xdeadbeef);
3000  EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3001  ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3002  get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3003  trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
3004  ansi_charset, symbol_charset, russian_charset,
3005  *font_name ? font_name : "<empty>");
3006  ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
3007  for (i = 0; i < efd.total; i++)
3008  {
3009  if (*font_name)
3010  ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3011  font_name, efd.lf[i].lfFaceName);
3012  }
3013  if (*font_name)
3014  {
3015  switch (font_charset)
3016  {
3017  case ANSI_CHARSET:
3018  ok(ansi_charset > 0,
3019  "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3020  ok(!symbol_charset,
3021  "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
3022  ok(russian_charset > 0,
3023  "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3024  break;
3025  case SYMBOL_CHARSET:
3026  ok(!ansi_charset,
3027  "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
3028  ok(symbol_charset,
3029  "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3030  ok(!russian_charset,
3031  "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
3032  break;
3033  case DEFAULT_CHARSET:
3034  ok(ansi_charset > 0,
3035  "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3036  ok(symbol_charset > 0,
3037  "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3038  ok(russian_charset > 0,
3039  "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3040  break;
3041  }
3042  }
3043  else
3044  {
3045  ok(ansi_charset > 0,
3046  "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3047  ok(symbol_charset > 0,
3048  "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3049  ok(russian_charset > 0,
3050  "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3051  }
3052 
3053  memset(&lf, 0, sizeof(lf));
3054  lf.lfCharSet = SYMBOL_CHARSET;
3055  strcpy(lf.lfFaceName, font_name);
3056  efd.total = 0;
3057  SetLastError(0xdeadbeef);
3058  EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3059  ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3060  get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3061  trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
3062  ansi_charset, symbol_charset, russian_charset,
3063  *font_name ? font_name : "<empty>");
3064  if (*font_name && font_charset == ANSI_CHARSET)
3065  ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
3066  else
3067  {
3068  ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
3069  for (i = 0; i < efd.total; i++)
3070  {
3071  ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3072  if (*font_name)
3073  ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3074  font_name, efd.lf[i].lfFaceName);
3075  }
3076 
3077  ok(!ansi_charset,
3078  "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3079  ok(symbol_charset > 0,
3080  "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3081  ok(!russian_charset,
3082  "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3083  }
3084 
3085  ReleaseDC(0, hdc);
3086 
3087  heap_free( efd.lf );
3088  heap_free( efdw.lf );
3089 }
3090 
3092 {
3093  const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
3094  LOGFONTA *target = (LOGFONTA *)lParam;
3095  const DWORD valid_bits = 0x003f01ff;
3096  CHARSETINFO csi;
3097  DWORD fs;
3098 
3099  if (type != TRUETYPE_FONTTYPE) return TRUE;
3100 
3102  fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
3103  if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
3104  *target = *lf;
3105  return FALSE;
3106  }
3107  }
3108 
3109  return TRUE;
3110 }
3111 
3113 {
3114  struct enum_font_data *efd = (struct enum_font_data *)lParam;
3115 
3116  if (type != TRUETYPE_FONTTYPE) return 1;
3117 
3118  if (efd->total >= efd->size)
3119  {
3120  efd->size = max( (efd->total + 1) * 2, 256 );
3121  efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
3122  if (!efd->lf) return 0;
3123  }
3124  efd->lf[efd->total++] = *lf;
3125 
3126  return 1;
3127 }
3128 
3130 {
3131  struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3132 
3133  if (type != TRUETYPE_FONTTYPE) return 1;
3134 
3135  if (efnd->total >= efnd->size)
3136  {
3137  efnd->size = max( (efnd->total + 1) * 2, 256 );
3138  efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
3139  if (!efnd->elf) return 0;
3140  }
3141  efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3142 
3143  return 1;
3144 }
3145 
3147 {
3148  struct enum_font_data efd;
3149  LOGFONTA target, enum_font;
3150  UINT acp;
3151  HDC hdc;
3152  CHARSETINFO csi;
3153 
3154  acp = GetACP();
3155  if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3156  skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3157  return;
3158  }
3159 
3160  hdc = GetDC(0);
3161  memset(&enum_font, 0, sizeof(enum_font));
3162  enum_font.lfCharSet = csi.ciCharset;
3163  target.lfFaceName[0] = '\0';
3164  target.lfCharSet = csi.ciCharset;
3165  EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3166  if (target.lfFaceName[0] == '\0') {
3167  skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3168  return;
3169  }
3170  if (acp == 874 || acp == 1255 || acp == 1256) {
3171  /* these codepage use complex script, expecting ANSI_CHARSET here. */
3172  target.lfCharSet = ANSI_CHARSET;
3173  }
3174 
3175  memset(&efd, 0, sizeof(efd));
3176  memset(&enum_font, 0, sizeof(enum_font));
3177  strcpy(enum_font.lfFaceName, target.lfFaceName);
3178  enum_font.lfCharSet = DEFAULT_CHARSET;
3179  EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3180  ReleaseDC(0, hdc);
3181 
3182  trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3183  if (efd.total < 2)
3184  ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3185  else
3186  ok(efd.lf[0].lfCharSet == target.lfCharSet,
3187  "(%s) got charset %d expected %d\n",
3188  efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3189 
3190  heap_free(efd.lf);
3191  return;
3192 }
3193 
3194 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3195 {
3196  HFONT hfont, hfont_prev;
3197  DWORD ret;
3198  GLYPHMETRICS gm1, gm2;
3199  LOGFONTA lf2 = *lf;
3200  WORD idx;
3201 
3202  if(!pGetGlyphIndicesA)
3203  return;
3204 
3205  /* negative widths are handled just as positive ones */
3206  lf2.lfWidth = -lf->lfWidth;
3207 
3208  SetLastError(0xdeadbeef);
3209  hfont = CreateFontIndirectA(lf);
3210  ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3211  check_font("original", lf, hfont);
3212 
3213  hfont_prev = SelectObject(hdc, hfont);
3214 
3215  ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3216  if (ret == GDI_ERROR || idx == 0xffff)
3217  {
3218  SelectObject(hdc, hfont_prev);
3219  DeleteObject(hfont);
3220  skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3221  return;
3222  }
3223 
3224  /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3225  memset(&gm1, 0xab, sizeof(gm1));
3226  SetLastError(0xdeadbeef);
3227  ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3228  ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3229 
3230  SelectObject(hdc, hfont_prev);
3231  DeleteObject(hfont);
3232 
3233  SetLastError(0xdeadbeef);
3234  hfont = CreateFontIndirectA(&lf2);
3235  ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3236  check_font("negative width", &lf2, hfont);
3237 
3238  hfont_prev = SelectObject(hdc, hfont);
3239 
3240  memset(&gm2, 0xbb, sizeof(gm2));
3241  SetLastError(0xdeadbeef);
3242  ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3243  ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3244 
3245  SelectObject(hdc, hfont_prev);
3246  DeleteObject(hfont);
3247 
3248  ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3249  gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3250  gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3251  gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3252  gm1.gmCellIncX == gm2.gmCellIncX &&
3253  gm1.gmCellIncY == gm2.gmCellIncY,
3254  "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3255  gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3256  gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3257  gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3258  gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3259 }
3260 
3261 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3262 #include "pshpack2.h"
3263 typedef struct
3264 {
3286  CHAR achVendID[4];
3290  /* According to the Apple spec, original version didn't have the below fields,
3291  * version numbers were taken from the OpenType spec.
3292  */
3293  /* version 0 (TrueType 1.5) */
3299  /* version 1 (TrueType 1.66) */
3302  /* version 2 (OpenType 1.2) */
3308  /* version 4 (OpenType 1.6) */
3311 } TT_OS2_V4;
3312 #include "poppack.h"
3313 
3314 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3315 
3316 typedef struct
3317 {
3320 } cmap_header;
3321 
3322 typedef struct
3323 {
3328 
3329 typedef struct
3330 {
3334 
3335  BYTE glyph_ids[256];
3336 } cmap_format_0;
3337 
3338 typedef struct
3339 {
3343 
3348 
3349  USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3350 /* Then follows:
3351  USHORT pad;
3352  USHORT start_count[seg_countx2 / 2];
3353  USHORT id_delta[seg_countx2 / 2];
3354  USHORT id_range_offset[seg_countx2 / 2];
3355  USHORT glyph_ids[];
3356 */
3357 } cmap_format_4;
3358 
3359 typedef struct
3360 {
3366 
3367 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V4 *os2, WORD family, const char *name)
3368 {
3369  ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3371  "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3372  name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3373  os2->panose.bWeight, os2->panose.bProportion);
3374 }
3375 
3377 {
3378  int i;
3379  cmap_format_0 *cmap = (cmap_format_0*)ptr;
3380 
3381  *first = 256;
3382 
3383  for(i = 0; i < 256; i++)
3384  {
3385  if(cmap->glyph_ids[i] == 0) continue;
3386  *last = i;
3387  if(*first == 256) *first = i;
3388  }
3389  if(*first == 256) return FALSE;
3390  return TRUE;
3391 }
3392 
3393 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3394 {
3395  USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3396  seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3397  seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3398  seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3399  seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3400 }
3401 
3403 {
3404  int i;
3405  cmap_format_4 *cmap = (cmap_format_4*)ptr;
3406  USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3407 
3408  *first = 0x10000;
3409 
3410  for(i = 0; i < seg_count; i++)
3411  {
3413 
3414  get_seg4(cmap, i, &seg);
3415 
3416  if(seg.start_count > 0xfffe) break;
3417 
3418  if(*first == 0x10000) *first = seg.start_count;
3419 
3420  *last = min(seg.end_count, 0xfffe);
3421  }
3422 
3423  if(*first == 0x10000) return FALSE;
3424  return TRUE;
3425 }
3426 
3427 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3428 {
3429  USHORT i;
3431 
3432  for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3433  {
3434  if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3435  return (BYTE *)header + GET_BE_DWORD(record->offset);
3436  record++;
3437  }
3438  return NULL;
3439 }
3440 
3441 typedef enum
3442 {
3446 } cmap_type;
3447 
3449 {
3450  LONG size, ret;
3452  void *cmap;
3453  BOOL r = FALSE;
3454  WORD format;
3455 
3456  size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3457  ok(size != GDI_ERROR, "no cmap table found\n");
3458  if(size == GDI_ERROR) return FALSE;
3459 
3460  header = HeapAlloc(GetProcessHeap(), 0, size);
3461  ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3462  ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3463  ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3464 
3465  cmap = get_cmap(header, 3, 1);
3466  if(cmap)
3467  *cmap_type = cmap_ms_unicode;
3468  else
3469  {
3470  cmap = get_cmap(header, 3, 0);
3471  if(cmap) *cmap_type = cmap_ms_symbol;
3472  }
3473  if(!cmap)
3474  {
3475  *cmap_type = cmap_none;
3476  goto end;
3477  }
3478 
3479  format = GET_BE_WORD(*(WORD *)cmap);
3480  switch(format)
3481  {
3482  case 0:
3483  r = get_first_last_from_cmap0(cmap, first, last);
3484  break;
3485  case 4:
3486  r = get_first_last_from_cmap4(cmap, first, last, size);
3487  break;
3488  default:
3489  trace("unhandled cmap format %d\n", format);
3490  break;
3491  }
3492 
3493 end:
3494  HeapFree(GetProcessHeap(), 0, header);
3495  return r;
3496 }
3497 
3498 #define TT_PLATFORM_APPLE_UNICODE 0
3499 #define TT_PLATFORM_MACINTOSH 1
3500 #define TT_PLATFORM_MICROSOFT 3
3501 #define TT_APPLE_ID_DEFAULT 0
3502 #define TT_APPLE_ID_ISO_10646 2
3503 #define TT_APPLE_ID_UNICODE_2_0 3
3504 #define TT_MS_ID_SYMBOL_CS 0
3505 #define TT_MS_ID_UNICODE_CS 1
3506 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3507 #define TT_NAME_ID_FONT_FAMILY 1
3508 #define TT_NAME_ID_FONT_SUBFAMILY 2
3509 #define TT_NAME_ID_UNIQUE_ID 3
3510 #define TT_NAME_ID_FULL_NAME 4
3511 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3512 
3513 typedef struct sfnt_name
3514 {
3521 } sfnt_name;
3522 
3523 static const LANGID mac_langid_table[] =
3524 {
3525  MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3526  MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3527  MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3528  MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3529  MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3530  MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3531  MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3532  MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3533  MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3534  MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3535  MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3536  MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3537  MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3538  MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3539  MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3540  MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3541  MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3542  MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3543  MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3544  MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3545  MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3546  MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3547  MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3548  MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3549  MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3550  MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3551  MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3552  MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3553  MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3554  MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3555  MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3556  MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3557  MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3558  MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3559  MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3560  MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3561  MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3562  MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3563  MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3564  MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3565  MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3566  0, /* TT_MAC_LANGID_YIDDISH */
3567  MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3568  MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3569  MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3570  MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3571  MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3572  MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3573  MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3574  MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3575  0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3576  MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3577  MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3578  0, /* TT_MAC_LANGID_MOLDAVIAN */
3579  MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3580  MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3581  MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3582  MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3583  MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3584  MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3585  0, /* TT_MAC_LANGID_KURDISH */
3586  MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3587  MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3588  MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3589  MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3590  MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3591  MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3592  MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3593  MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3594  MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3595  MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3596  MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3597  MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3598  MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3599  MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3600  MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3601  MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3602  0, /* TT_MAC_LANGID_BURMESE */
3603  MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3604  MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3605  MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3606  MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3607  0, /* TT_MAC_LANGID_TAGALOG */
3608  MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3609  0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3610  MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3611  MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3612  0, /* TT_MAC_LANGID_GALLA */
3613  0, /* TT_MAC_LANGID_SOMALI */
3614  MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3615  0, /* TT_MAC_LANGID_RUANDA */
3616  0, /* TT_MAC_LANGID_RUNDI */
3617  0, /* TT_MAC_LANGID_CHEWA */
3618  MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3619  MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3620  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3621  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3622  MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3623  MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3624  MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3625  0, /* TT_MAC_LANGID_LATIN */
3626  MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3627  0, /* TT_MAC_LANGID_GUARANI */
3628  0, /* TT_MAC_LANGID_AYMARA */
3629  MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3630  MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3631  0, /* TT_MAC_LANGID_DZONGKHA */
3632  0, /* TT_MAC_LANGID_JAVANESE */
3633  0, /* TT_MAC_LANGID_SUNDANESE */
3634  MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3635  MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3636  MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3637  MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3638  MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3639  MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3640  MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3641  0, /* TT_MAC_LANGID_TONGAN */
3642  0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3643  MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3644  MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3645 };
3646 
3647 static inline WORD get_mac_code_page( const sfnt_name *name )
3648 {
3649  if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3650  return 10000 + GET_BE_WORD(name->encoding_id);
3651 }
3652 
3654 {
3655  LANGID name_lang;
3656  int res = 0;
3657 
3658  switch (GET_BE_WORD(name->platform_id))
3659  {
3660  case TT_PLATFORM_MICROSOFT:
3661  res += 5; /* prefer the Microsoft name */
3662  switch (GET_BE_WORD(name->encoding_id))
3663  {
3664  case TT_MS_ID_UNICODE_CS:
3665  case TT_MS_ID_SYMBOL_CS:
3666  name_lang = GET_BE_WORD(name->language_id);
3667  break;
3668  default:
3669  return 0;
3670  }
3671  break;
3672  case TT_PLATFORM_MACINTOSH:
3673  if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3674  if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3675  name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3676  break;
3678  res += 2; /* prefer Unicode encodings */
3679  switch (GET_BE_WORD(name->encoding_id))
3680  {
3681  case TT_APPLE_ID_DEFAULT:
3682  case TT_APPLE_ID_ISO_10646:
3684  if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3685  name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3686  break;
3687  default:
3688  return 0;
3689  }
3690  break;
3691  default:
3692  return 0;
3693  }
3694  if (name_lang == lang) res += 30;
3695  else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3696  else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3697  return res;
3698 }
3699 
3700 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3701 {
3702  struct sfnt_name_header
3703  {
3704  USHORT format;
3705  USHORT number_of_record;
3706  USHORT storage_offset;
3707  } *header;
3708