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