61ee6f3ed88bcc5f9515d0d57ec2d99cace9e580
[reactos.git] / modules / rostests / winetests / gdi32 / font.c
1 /*
2 * Unit test suite for fonts
3 *
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "precomp.h"
23
24 #include <winnls.h>
25
26 static inline BOOL match_off_by_n(int a, int b, unsigned int n)
27 {
28 return abs(a - b) <= n;
29 }
30 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
31 #define near_match(a, b) match_off_by_n((a), (b), 6)
32 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
33
34 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
35 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
36 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
37 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
38 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
39 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
40 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
41 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
42 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
43 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
44 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
45 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
46 LPINT nfit, LPINT dxs, LPSIZE size );
47 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
48 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
49 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
50 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
51 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
52 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
53 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
54 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *);
55 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
56
57 static HMODULE hgdi32 = 0;
58 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
59 static WORD system_lang_id;
60
61 #ifdef WORDS_BIGENDIAN
62 #define GET_BE_WORD(x) (x)
63 #define GET_BE_DWORD(x) (x)
64 #else
65 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
66 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
67 #endif
68
69 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
70 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
71 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
72 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
73 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
74 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
75
76 static void init(void)
77 {
78 hgdi32 = GetModuleHandleA("gdi32.dll");
79
80 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
81 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
82 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
83 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
84 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
85 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
86 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
87 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
88 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
89 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
90 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
91 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
92 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
93 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
94 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
95 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
96 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
97 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
98 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
99 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
100 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
101
102 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
103 }
104
105 static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size)
106 {
107 return HeapAlloc(GetProcessHeap(), 0, size);
108 }
109
110 static inline void* __WINE_ALLOC_SIZE(2) heap_realloc(void *mem, size_t size)
111 {
112 if (!mem) return heap_alloc(size);
113 return HeapReAlloc(GetProcessHeap(), 0, mem, size);
114 }
115
116 static inline BOOL heap_free(void *mem)
117 {
118 return HeapFree(GetProcessHeap(), 0, mem);
119 }
120
121 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
122 {
123 if (type != TRUETYPE_FONTTYPE) return 1;
124
125 return 0;
126 }
127
128 static BOOL is_truetype_font_installed(const char *name)
129 {
130 HDC hdc = GetDC(0);
131 BOOL ret = FALSE;
132
133 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
134 ret = TRUE;
135
136 ReleaseDC(0, hdc);
137 return ret;
138 }
139
140 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
141 {
142 return 0;
143 }
144
145 static BOOL is_font_installed(const char *name)
146 {
147 HDC hdc = GetDC(0);
148 BOOL ret = FALSE;
149
150 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
151 ret = TRUE;
152
153 ReleaseDC(0, hdc);
154 return ret;
155 }
156
157 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
158 {
159 HRSRC rsrc;
160 void *rsrc_data;
161
162 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
163 if (!rsrc) return NULL;
164
165 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
166 if (!rsrc_data) return NULL;
167
168 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
169 if (!*rsrc_size) return NULL;
170
171 return rsrc_data;
172 }
173
174 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
175 {
176 char tmp_path[MAX_PATH];
177 HANDLE hfile;
178 BOOL ret;
179
180 GetTempPathA(MAX_PATH, tmp_path);
181 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
182
183 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
184 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
185
186 ret = WriteFile(hfile, data, *size, size, NULL);
187
188 CloseHandle(hfile);
189 return ret;
190 }
191
192 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
193 {
194 void *rsrc_data;
195 DWORD rsrc_size;
196
197 rsrc_data = get_res_data( fontname, &rsrc_size );
198 if (!rsrc_data) return FALSE;
199
200 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
201 }
202
203 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
204 {
205 LOGFONTA getobj_lf;
206 int ret, minlen = 0;
207
208 if (!hfont)
209 return;
210
211 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
212 /* NT4 tries to be clever and only returns the minimum length */
213 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
214 minlen++;
215 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
216 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
217 ok(lf->lfHeight == getobj_lf.lfHeight ||
218 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
219 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
220 ok(lf->lfWidth == getobj_lf.lfWidth ||
221 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
222 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
223 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
224 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
225 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
226 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
227 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
228 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
229 ok(lf->lfWeight == getobj_lf.lfWeight ||
230 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
231 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
232 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
233 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
234 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
235 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
236 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
237 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
238 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
239 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
240 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
241 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
242 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
243 }
244
245 static HFONT create_font(const char* test, const LOGFONTA* lf)
246 {
247 HFONT hfont = CreateFontIndirectA(lf);
248 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
249 if (hfont)
250 check_font(test, lf, hfont);
251 return hfont;
252 }
253
254 static void test_logfont(void)
255 {
256 LOGFONTA lf;
257 HFONT hfont;
258
259 memset(&lf, 0, sizeof lf);
260
261 lf.lfCharSet = ANSI_CHARSET;
262 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
263 lf.lfWeight = FW_DONTCARE;
264 lf.lfHeight = 16;
265 lf.lfWidth = 16;
266 lf.lfQuality = DEFAULT_QUALITY;
267
268 lstrcpyA(lf.lfFaceName, "Arial");
269 hfont = create_font("Arial", &lf);
270 DeleteObject(hfont);
271
272 memset(&lf, 'A', sizeof(lf));
273 hfont = CreateFontIndirectA(&lf);
274 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
275
276 lf.lfFaceName[LF_FACESIZE - 1] = 0;
277 check_font("AAA...", &lf, hfont);
278 DeleteObject(hfont);
279 }
280
281 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
282 {
283 if (type & RASTER_FONTTYPE)
284 {
285 LOGFONTA *lf = (LOGFONTA *)lParam;
286 *lf = *elf;
287 return 0; /* stop enumeration */
288 }
289
290 return 1; /* continue enumeration */
291 }
292
293 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
294 {
295 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
296 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
297 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
298 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
299 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
300 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
301 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
302 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
303 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
304 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
305 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
306 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
307 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
308 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
309 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
310 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
311 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
312 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
313 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
314 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
315 }
316
317 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
318 LONG lfWidth, const char *test_str,
319 INT test_str_len, const TEXTMETRICA *tm_orig,
320 const SIZE *size_orig, INT width_of_A_orig,
321 INT scale_x, INT scale_y)
322 {
323 LOGFONTA lf;
324 OUTLINETEXTMETRICA otm;
325 TEXTMETRICA tm;
326 SIZE size;
327 INT width_of_A, cx, cy;
328 UINT ret;
329
330 if (!hfont)
331 return;
332
333 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
334
335 GetObjectA(hfont, sizeof(lf), &lf);
336
337 if (GetOutlineTextMetricsA(hdc, 0, NULL))
338 {
339 otm.otmSize = sizeof(otm) / 2;
340 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
341 ok(ret == sizeof(otm)/2 /* XP */ ||
342 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
343
344 memset(&otm, 0x1, sizeof(otm));
345 otm.otmSize = sizeof(otm);
346 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
347 ok(ret == sizeof(otm) /* XP */ ||
348 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
349
350 memset(&tm, 0x2, sizeof(tm));
351 ret = GetTextMetricsA(hdc, &tm);
352 ok(ret, "GetTextMetricsA failed\n");
353 /* the structure size is aligned */
354 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
355 {
356 ok(0, "tm != otm\n");
357 compare_tm(&tm, &otm.otmTextMetrics);
358 }
359
360 tm = otm.otmTextMetrics;
361 if (0) /* these metrics are scaled too, but with rounding errors */
362 {
363 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
364 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
365 }
366 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
367 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
368 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
369 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
370 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
371 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
372 }
373 else
374 {
375 ret = GetTextMetricsA(hdc, &tm);
376 ok(ret, "GetTextMetricsA failed\n");
377 }
378
379 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
380 cy = tm.tmHeight / tm_orig->tmHeight;
381 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
382 lfHeight, scale_x, scale_y, cx, cy);
383 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
384 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
385 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
386 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
387 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
388
389 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
390 if (lf.lfHeight)
391 {
392 if (lf.lfWidth)
393 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
394 }
395 else
396 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
397
398 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
399
400 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
401 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
402
403 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
404
405 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
406 }
407
408 /* Test how GDI scales bitmap font metrics */
409 static void test_bitmap_font(void)
410 {
411 static const char test_str[11] = "Test String";
412 HDC hdc;
413 LOGFONTA bitmap_lf;
414 HFONT hfont, old_hfont;
415 TEXTMETRICA tm_orig;
416 SIZE size_orig;
417 INT ret, i, width_orig, height_orig, scale, lfWidth;
418
419 hdc = CreateCompatibleDC(0);
420
421 /* "System" has only 1 pixel size defined, otherwise the test breaks */
422 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
423 if (ret)
424 {
425 ReleaseDC(0, hdc);
426 trace("no bitmap fonts were found, skipping the test\n");
427 return;
428 }
429
430 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
431
432 height_orig = bitmap_lf.lfHeight;
433 lfWidth = bitmap_lf.lfWidth;
434
435 hfont = create_font("bitmap", &bitmap_lf);
436 old_hfont = SelectObject(hdc, hfont);
437 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
438 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
439 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
440 SelectObject(hdc, old_hfont);
441 DeleteObject(hfont);
442
443 bitmap_lf.lfHeight = 0;
444 bitmap_lf.lfWidth = 4;
445 hfont = create_font("bitmap", &bitmap_lf);
446 old_hfont = SelectObject(hdc, hfont);
447 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
448 SelectObject(hdc, old_hfont);
449 DeleteObject(hfont);
450
451 bitmap_lf.lfHeight = height_orig;
452 bitmap_lf.lfWidth = lfWidth;
453
454 /* test fractional scaling */
455 for (i = 1; i <= height_orig * 6; i++)
456 {
457 INT nearest_height;
458
459 bitmap_lf.lfHeight = i;
460 hfont = create_font("fractional", &bitmap_lf);
461 scale = (i + height_orig - 1) / height_orig;
462 nearest_height = scale * height_orig;
463 /* Only jump to the next height if the difference <= 25% original height */
464 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
465 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
466 so we'll not test this particular height. */
467 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
468 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
469 old_hfont = SelectObject(hdc, hfont);
470 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
471 SelectObject(hdc, old_hfont);
472 DeleteObject(hfont);
473 }
474
475 /* test integer scaling 3x2 */
476 bitmap_lf.lfHeight = height_orig * 2;
477 bitmap_lf.lfWidth *= 3;
478 hfont = create_font("3x2", &bitmap_lf);
479 old_hfont = SelectObject(hdc, hfont);
480 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
481 SelectObject(hdc, old_hfont);
482 DeleteObject(hfont);
483
484 /* test integer scaling 3x3 */
485 bitmap_lf.lfHeight = height_orig * 3;
486 bitmap_lf.lfWidth = 0;
487 hfont = create_font("3x3", &bitmap_lf);
488 old_hfont = SelectObject(hdc, hfont);
489 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
490 SelectObject(hdc, old_hfont);
491 DeleteObject(hfont);
492
493 DeleteDC(hdc);
494 }
495
496 /* Test how GDI scales outline font metrics */
497 static void test_outline_font(void)
498 {
499 static const char test_str[11] = "Test String";
500 HDC hdc, hdc_2;
501 LOGFONTA lf;
502 HFONT hfont, old_hfont, old_hfont_2;
503 OUTLINETEXTMETRICA otm;
504 SIZE size_orig;
505 INT width_orig, height_orig, lfWidth;
506 XFORM xform;
507 GLYPHMETRICS gm;
508 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
509 POINT pt;
510 INT ret;
511
512 if (!is_truetype_font_installed("Arial"))
513 {
514 skip("Arial is not installed\n");
515 return;
516 }
517
518 hdc = CreateCompatibleDC(0);
519
520 memset(&lf, 0, sizeof(lf));
521 strcpy(lf.lfFaceName, "Arial");
522 lf.lfHeight = 72;
523 hfont = create_font("outline", &lf);
524 old_hfont = SelectObject(hdc, hfont);
525 otm.otmSize = sizeof(otm);
526 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
527 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
528 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
529
530 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
531 SelectObject(hdc, old_hfont);
532 DeleteObject(hfont);
533
534 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
535 lf.lfHeight = otm.otmEMSquare;
536 lf.lfHeight = -lf.lfHeight;
537 hfont = create_font("outline", &lf);
538 old_hfont = SelectObject(hdc, hfont);
539 otm.otmSize = sizeof(otm);
540 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
541 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
542 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
543 SelectObject(hdc, old_hfont);
544 DeleteObject(hfont);
545
546 height_orig = otm.otmTextMetrics.tmHeight;
547 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
548
549 /* test integer scaling 3x2 */
550 lf.lfHeight = height_orig * 2;
551 lf.lfWidth = lfWidth * 3;
552 hfont = create_font("3x2", &lf);
553 old_hfont = SelectObject(hdc, hfont);
554 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
555 SelectObject(hdc, old_hfont);
556 DeleteObject(hfont);
557
558 /* test integer scaling 3x3 */
559 lf.lfHeight = height_orig * 3;
560 lf.lfWidth = lfWidth * 3;
561 hfont = create_font("3x3", &lf);
562 old_hfont = SelectObject(hdc, hfont);
563 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
564 SelectObject(hdc, old_hfont);
565 DeleteObject(hfont);
566
567 /* test integer scaling 1x1 */
568 lf.lfHeight = height_orig * 1;
569 lf.lfWidth = lfWidth * 1;
570 hfont = create_font("1x1", &lf);
571 old_hfont = SelectObject(hdc, hfont);
572 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
573 SelectObject(hdc, old_hfont);
574 DeleteObject(hfont);
575
576 /* test integer scaling 1x1 */
577 lf.lfHeight = height_orig;
578 lf.lfWidth = 0;
579 hfont = create_font("1x1", &lf);
580 old_hfont = SelectObject(hdc, hfont);
581 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
582
583 /* with an identity matrix */
584 memset(&gm, 0, sizeof(gm));
585 SetLastError(0xdeadbeef);
586 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
587 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
588 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
589 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
591 /* with a custom matrix */
592 memset(&gm, 0, sizeof(gm));
593 SetLastError(0xdeadbeef);
594 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
595 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
596 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
597 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
598 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
599
600 /* Test that changing the DC transformation affects only the font
601 * selected on this DC and doesn't affect the same font selected on
602 * another DC.
603 */
604 hdc_2 = CreateCompatibleDC(0);
605 old_hfont_2 = SelectObject(hdc_2, hfont);
606 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
607
608 SetMapMode(hdc, MM_ANISOTROPIC);
609
610 /* font metrics on another DC should be unchanged */
611 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
612
613 /* test restrictions of compatibility mode GM_COMPATIBLE */
614 /* part 1: rescaling only X should not change font scaling on screen.
615 So compressing the X axis by 2 is not done, and this
616 appears as X scaling of 2 that no one requested. */
617 SetWindowExtEx(hdc, 100, 100, NULL);
618 SetViewportExtEx(hdc, 50, 100, NULL);
619 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
620 /* font metrics on another DC should be unchanged */
621 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
622
623 /* part 2: rescaling only Y should change font scaling.
624 As also X is scaled by a factor of 2, but this is not
625 requested by the DC transformation, we get a scaling factor
626 of 2 in the X coordinate. */
627 SetViewportExtEx(hdc, 100, 200, NULL);
628 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
629 /* font metrics on another DC should be unchanged */
630 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
631
632 /* restore scaling */
633 SetMapMode(hdc, MM_TEXT);
634
635 /* font metrics on another DC should be unchanged */
636 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
637
638 SelectObject(hdc_2, old_hfont_2);
639 DeleteDC(hdc_2);
640
641 if (!SetGraphicsMode(hdc, GM_ADVANCED))
642 {
643 SelectObject(hdc, old_hfont);
644 DeleteObject(hfont);
645 DeleteDC(hdc);
646 skip("GM_ADVANCED is not supported on this platform\n");
647 return;
648 }
649
650 xform.eM11 = 20.0f;
651 xform.eM12 = 0.0f;
652 xform.eM21 = 0.0f;
653 xform.eM22 = 20.0f;
654 xform.eDx = 0.0f;
655 xform.eDy = 0.0f;
656
657 SetLastError(0xdeadbeef);
658 ret = SetWorldTransform(hdc, &xform);
659 ok(ret, "SetWorldTransform error %u\n", GetLastError());
660
661 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
662
663 /* with an identity matrix */
664 memset(&gm, 0, sizeof(gm));
665 SetLastError(0xdeadbeef);
666 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
667 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
668 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
669 pt.x = width_orig; pt.y = 0;
670 LPtoDP(hdc, &pt, 1);
671 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
672 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
673 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
674 /* with a custom matrix */
675 memset(&gm, 0, sizeof(gm));
676 SetLastError(0xdeadbeef);
677 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
678 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
679 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
680 pt.x = width_orig; pt.y = 0;
681 LPtoDP(hdc, &pt, 1);
682 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
683 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
684 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
685
686 SetLastError(0xdeadbeef);
687 ret = SetMapMode(hdc, MM_LOMETRIC);
688 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
689
690 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
691
692 /* with an identity matrix */
693 memset(&gm, 0, sizeof(gm));
694 SetLastError(0xdeadbeef);
695 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
696 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
697 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
698 pt.x = width_orig; pt.y = 0;
699 LPtoDP(hdc, &pt, 1);
700 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
701 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
702 /* with a custom matrix */
703 memset(&gm, 0, sizeof(gm));
704 SetLastError(0xdeadbeef);
705 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
706 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
708 pt.x = width_orig; pt.y = 0;
709 LPtoDP(hdc, &pt, 1);
710 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
711 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
712
713 SetLastError(0xdeadbeef);
714 ret = SetMapMode(hdc, MM_TEXT);
715 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
716
717 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
718
719 /* with an identity matrix */
720 memset(&gm, 0, sizeof(gm));
721 SetLastError(0xdeadbeef);
722 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
723 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
724 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
725 pt.x = width_orig; pt.y = 0;
726 LPtoDP(hdc, &pt, 1);
727 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
728 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
729 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
730 /* with a custom matrix */
731 memset(&gm, 0, sizeof(gm));
732 SetLastError(0xdeadbeef);
733 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
734 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
735 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
736 pt.x = width_orig; pt.y = 0;
737 LPtoDP(hdc, &pt, 1);
738 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
739 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
740 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
741
742 SelectObject(hdc, old_hfont);
743 DeleteObject(hfont);
744 DeleteDC(hdc);
745 }
746
747 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
748 {
749 LOGFONTA *lf = (LOGFONTA *)lParam;
750
751 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
752 {
753 *lf = *elf;
754 return 0; /* stop enumeration */
755 }
756 return 1; /* continue enumeration */
757 }
758
759 static BOOL is_CJK(void)
760 {
761 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
762 }
763
764 #define FH_SCALE 0x80000000
765 static void test_bitmap_font_metrics(void)
766 {
767 static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
768 static const struct font_data
769 {
770 const char face_name[LF_FACESIZE];
771 int weight, height, ascent, descent, int_leading, ext_leading;
772 int ave_char_width, max_char_width, dpi;
773 BYTE first_char, last_char, def_char, break_char;
774 DWORD ansi_bitfield;
775 const WORD *skip_lang_id;
776 int scaled_height;
777 } fd[] =
778 {
779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
781 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
782 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
783 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
784 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
785 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
786 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
787 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 16 },
788 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
789
790 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
791 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
792 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
793 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
794 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
795 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
796 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
797 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
798 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
799 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
800
801 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
802 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
803 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
804 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
805 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
806 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
807 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
808 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
809 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
810 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
811 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
812 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
813 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
814 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
815 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
816 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
817
818 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
819 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
820 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
822 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
823 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
824 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
825 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
826 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
827 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
828 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
830
831 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
832 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
833 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
834 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
835 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
836 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
837 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
838 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
839 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
840 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
841 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
842 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
843 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
844 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
845 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
846 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
847 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
848
849 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
850 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
851 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
852 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
853 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
854 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
855 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
856 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
857 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
858 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
859 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
860
861 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
862 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
863 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
864
865 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
866 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
867 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
868
869 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
870 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
871 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
872
873 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
874 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
875
876 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
877 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
878 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
879 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
880 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
881 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
882 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
883 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
884 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
885 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
886 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
887 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
888 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
889 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
890 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
891 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
892 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
893 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
894 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
895 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
896 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
897
898 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
899 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
900 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
901 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
902 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
903 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
904 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
905 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
906 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
907 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
908 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
909 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
910
911 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
912 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
913 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
914
915 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
916
917 /* FIXME: add "Terminal" */
918 };
919 static const int font_log_pixels[] = { 96, 120 };
920 HDC hdc;
921 LOGFONTA lf;
922 HFONT hfont, old_hfont;
923 TEXTMETRICA tm;
924 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
925 char face_name[LF_FACESIZE];
926 CHARSETINFO csi;
927
928 trace("system language id %04x\n", system_lang_id);
929
930 expected_cs = GetACP();
931 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
932 {
933 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
934 return;
935 }
936 expected_cs = csi.ciCharset;
937 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
938
939 hdc = CreateCompatibleDC(0);
940 ok(hdc != NULL, "failed to create hdc\n");
941
942 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
943 GetDeviceCaps(hdc, LOGPIXELSY));
944
945 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
946 diff = 32768;
947 font_res = 0;
948 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
949 {
950 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
951 if (new_diff < diff)
952 {
953 diff = new_diff;
954 font_res = font_log_pixels[i];
955 }
956 }
957 trace("best font resolution is %d\n", font_res);
958
959 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
960 {
961 int bit, height;
962
963 memset(&lf, 0, sizeof(lf));
964
965 height = fd[i].height & ~FH_SCALE;
966 lf.lfHeight = height;
967 strcpy(lf.lfFaceName, fd[i].face_name);
968
969 for(bit = 0; bit < 32; bit++)
970 {
971 GLYPHMETRICS gm;
972 DWORD fs[2];
973 BOOL bRet;
974
975 fs[0] = 1L << bit;
976 fs[1] = 0;
977 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
978 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
979
980 lf.lfCharSet = csi.ciCharset;
981 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
982 if (fd[i].height & FH_SCALE)
983 ok(ret, "scaled font height %d should not be enumerated\n", height);
984 else
985 {
986 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
987 {
988 todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */
989 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
990 }
991 }
992 if (ret && !(fd[i].height & FH_SCALE))
993 continue;
994
995 hfont = create_font(lf.lfFaceName, &lf);
996 old_hfont = SelectObject(hdc, hfont);
997
998 SetLastError(0xdeadbeef);
999 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
1000 ok(ret, "GetTextFace error %u\n", GetLastError());
1001
1002 if (strcmp(face_name, fd[i].face_name) != 0)
1003 {
1004 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
1005 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
1006 SelectObject(hdc, old_hfont);
1007 DeleteObject(hfont);
1008 continue;
1009 }
1010
1011 memset(&gm, 0, sizeof(gm));
1012 SetLastError(0xdeadbeef);
1013 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1014 todo_wine {
1015 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1016 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1017 }
1018
1019 bRet = GetTextMetricsA(hdc, &tm);
1020 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1021
1022 SetLastError(0xdeadbeef);
1023 ret = GetTextCharset(hdc);
1024 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1025 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1026 else
1027 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1028
1029 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1030 trace("expected %s, height %d scaled_height %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1031
1032 if(fd[i].dpi == tm.tmDigitizedAspectX)
1033 {
1034 int skipme = 0;
1035 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1036 if (fd[i].skip_lang_id)
1037 {
1038 int si = 0;
1039 skipme = 0;
1040 while(!skipme && fd[i].skip_lang_id[si])
1041 if (fd[i].skip_lang_id[si++] == system_lang_id)
1042 skipme = 1;
1043 }
1044 if (!skipme)
1045 {
1046 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1047 if (fd[i].height & FH_SCALE)
1048 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
1049 else
1050 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
1051 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1052 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1053 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
1054 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
1055 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
1056 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1057 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1058 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1059 make default char test fail */
1060 if (tm.tmCharSet == lf.lfCharSet)
1061 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1062 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1063 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
1064
1065 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1066 that make the max width bigger */
1067 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1068 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
1069 }
1070 else
1071 skip("Skipping font metrics test for system langid 0x%x\n",
1072 system_lang_id);
1073 }
1074 SelectObject(hdc, old_hfont);
1075 DeleteObject(hfont);
1076 }
1077 }
1078
1079 DeleteDC(hdc);
1080 }
1081
1082 static void test_GdiGetCharDimensions(void)
1083 {
1084 HDC hdc;
1085 TEXTMETRICW tm;
1086 LONG ret;
1087 SIZE size;
1088 LONG avgwidth, height;
1089 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1090
1091 if (!pGdiGetCharDimensions)
1092 {
1093 win_skip("GdiGetCharDimensions not available on this platform\n");
1094 return;
1095 }
1096
1097 hdc = CreateCompatibleDC(NULL);
1098
1099 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1100 avgwidth = ((size.cx / 26) + 1) / 2;
1101
1102 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1103 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1104 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1105
1106 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1107 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1108
1109 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1110 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1111
1112 height = 0;
1113 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1114 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1115 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1116
1117 DeleteDC(hdc);
1118 }
1119
1120 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1121 const TEXTMETRICA *lpntme,
1122 DWORD FontType, LPARAM lParam)
1123 {
1124 if (FontType & TRUETYPE_FONTTYPE)
1125 {
1126 HFONT hfont;
1127
1128 hfont = CreateFontIndirectA(lpelfe);
1129 if (hfont)
1130 {
1131 *(HFONT *)lParam = hfont;
1132 return 0;
1133 }
1134 }
1135
1136 return 1;
1137 }
1138
1139 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1140 {
1141 ABC abc[1];
1142 ABCFLOAT abcf[1];
1143 BOOL ret = FALSE;
1144
1145 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1146 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1147 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1148 todo_wine_if (todo)
1149 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1150 todo_wine_if (todo)
1151 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1152
1153 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1154 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1155 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1156 todo_wine_if (todo)
1157 ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1158 todo_wine_if (todo)
1159 ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1160
1161 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1162 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1163 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1164 todo_wine_if (todo)
1165 ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1166 todo_wine_if (todo)
1167 ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1168 }
1169
1170 static void test_GetCharABCWidths(void)
1171 {
1172 static const WCHAR str[] = {'i',0};
1173 BOOL ret;
1174 HDC hdc;
1175 LOGFONTA lf;
1176 HFONT hfont;
1177 ABC abc[1];
1178 ABC abcw[1];
1179 ABCFLOAT abcf[1];
1180 WORD glyphs[1];
1181 DWORD nb;
1182 HWND hwnd;
1183 static const struct
1184 {
1185 UINT first;
1186 UINT last;
1187 } range[] =
1188 {
1189 {0xff, 0xff},
1190 {0x100, 0x100},
1191 {0xff, 0x100},
1192 {0x1ff, 0xff00},
1193 {0xffff, 0xffff},
1194 {0x10000, 0x10000},
1195 {0xffff, 0x10000},
1196 {0xffffff, 0xffffff},
1197 {0x1000000, 0x1000000},
1198 {0xffffff, 0x1000000},
1199 {0xffffffff, 0xffffffff},
1200 {0x00, 0xff}
1201 };
1202 static const struct
1203 {
1204 UINT cs;
1205 UINT a;
1206 UINT w;
1207 BOOL r[sizeof range / sizeof range[0]];
1208 } c[] =
1209 {
1210 {ANSI_CHARSET, 0x30, 0x30,
1211 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1212 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1213 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1214 {HANGEUL_CHARSET, 0x8141, 0xac02,
1215 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1216 {GB2312_CHARSET, 0x8141, 0x4e04,
1217 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1218 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1219 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1220 };
1221 UINT i;
1222
1223 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1224 {
1225 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1226 return;
1227 }
1228
1229 memset(&lf, 0, sizeof(lf));
1230 strcpy(lf.lfFaceName, "System");
1231 lf.lfHeight = 20;
1232
1233 hfont = CreateFontIndirectA(&lf);
1234 hdc = GetDC(0);
1235 hfont = SelectObject(hdc, hfont);
1236
1237 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1238 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1239
1240 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1241 ok(!ret, "GetCharABCWidthsI should have failed\n");
1242
1243 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1244 ok(!ret, "GetCharABCWidthsI should have failed\n");
1245
1246 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1247 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1248
1249 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1250 ok(!ret, "GetCharABCWidthsW should have failed\n");
1251
1252 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1253 ok(!ret, "GetCharABCWidthsW should have failed\n");
1254
1255 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1256 ok(!ret, "GetCharABCWidthsW should have failed\n");
1257
1258 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1259 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1260
1261 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1262 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1263
1264 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1265 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1266
1267 hfont = SelectObject(hdc, hfont);
1268 DeleteObject(hfont);
1269
1270 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1271 {
1272 ABC a[2], w[2];
1273 ABC full[256];
1274 UINT code = 0x41, j;
1275
1276 lf.lfFaceName[0] = '\0';
1277 lf.lfCharSet = c[i].cs;
1278 lf.lfPitchAndFamily = 0;
1279 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1280 {
1281 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1282 continue;
1283 }
1284
1285 memset(a, 0, sizeof a);
1286 memset(w, 0, sizeof w);
1287 hfont = SelectObject(hdc, hfont);
1288 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1289 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1290 memcmp(a, w, sizeof a) == 0,
1291 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1292
1293 memset(a, 0xbb, sizeof a);
1294 ret = pGetCharABCWidthsA(hdc, code, code, a);
1295 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1296 memset(full, 0xcc, sizeof full);
1297 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1298 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1299 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1300 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1301
1302 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1303 {
1304 memset(full, 0xdd, sizeof full);
1305 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1306 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1307 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1308 if (ret)
1309 {
1310 UINT last = range[j].last - range[j].first;
1311 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1312 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1313 "GetCharABCWidthsA %x should match. codepage = %u\n",
1314 range[j].last, c[i].cs);
1315 }
1316 }
1317
1318 hfont = SelectObject(hdc, hfont);
1319 DeleteObject(hfont);
1320 }
1321
1322 memset(&lf, 0, sizeof(lf));
1323 strcpy(lf.lfFaceName, "Tahoma");
1324 lf.lfHeight = 200;
1325 hfont = CreateFontIndirectA(&lf);
1326
1327 /* test empty glyph's metrics */
1328 hfont = SelectObject(hdc, hfont);
1329 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1330 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1331 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1332 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1333 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1334 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1335
1336 /* 1) prepare unrotated font metrics */
1337 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1338 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1339 DeleteObject(SelectObject(hdc, hfont));
1340
1341 /* 2) get rotated font metrics */
1342 lf.lfEscapement = lf.lfOrientation = 900;
1343 hfont = CreateFontIndirectA(&lf);
1344 hfont = SelectObject(hdc, hfont);
1345 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1346 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1347
1348 /* 3) compare ABC results */
1349 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1350 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1351 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1352 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1353 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1354 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1355
1356 DeleteObject(SelectObject(hdc, hfont));
1357 ReleaseDC(NULL, hdc);
1358
1359 trace("ABC sign test for a variety of transforms:\n");
1360 memset(&lf, 0, sizeof(lf));
1361 strcpy(lf.lfFaceName, "Tahoma");
1362 lf.lfHeight = 20;
1363 hfont = CreateFontIndirectA(&lf);
1364 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1365 0, 0, 0, NULL);
1366 hdc = GetDC(hwnd);
1367 SetMapMode(hdc, MM_ANISOTROPIC);
1368 SelectObject(hdc, hfont);
1369
1370 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1371 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1372
1373 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1374 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1375 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1376 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1377 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1378 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1379
1380 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1381 SetWindowExtEx(hdc, -1, -1, NULL);
1382 SetGraphicsMode(hdc, GM_COMPATIBLE);
1383 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1384 SetGraphicsMode(hdc, GM_ADVANCED);
1385 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1386 SetWindowExtEx(hdc, 1, 1, NULL);
1387 SetGraphicsMode(hdc, GM_COMPATIBLE);
1388 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1389 SetGraphicsMode(hdc, GM_ADVANCED);
1390 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1391
1392 ReleaseDC(hwnd, hdc);
1393 DestroyWindow(hwnd);
1394
1395 trace("RTL layout\n");
1396 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1397 0, 0, 0, NULL);
1398 hdc = GetDC(hwnd);
1399 SetMapMode(hdc, MM_ANISOTROPIC);
1400 SelectObject(hdc, hfont);
1401
1402 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1403 SetWindowExtEx(hdc, -1, -1, NULL);
1404 SetGraphicsMode(hdc, GM_COMPATIBLE);
1405 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1406 SetGraphicsMode(hdc, GM_ADVANCED);
1407 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1408 SetWindowExtEx(hdc, 1, 1, NULL);
1409 SetGraphicsMode(hdc, GM_COMPATIBLE);
1410 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1411 SetGraphicsMode(hdc, GM_ADVANCED);
1412 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1413
1414 ReleaseDC(hwnd, hdc);
1415 DestroyWindow(hwnd);
1416 DeleteObject(hfont);
1417 }
1418
1419 static void test_text_extents(void)
1420 {
1421 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1422 static const WCHAR emptyW[] = {0};
1423 LPINT extents;
1424 INT i, len, fit1, fit2, extents2[3];
1425 LOGFONTA lf;
1426 TEXTMETRICA tm;
1427 HDC hdc;
1428 HFONT hfont;
1429 SIZE sz;
1430 SIZE sz1, sz2;
1431 BOOL ret;
1432
1433 memset(&lf, 0, sizeof(lf));
1434 strcpy(lf.lfFaceName, "Arial");
1435 lf.lfHeight = 20;
1436
1437 hfont = CreateFontIndirectA(&lf);
1438 hdc = GetDC(0);
1439 hfont = SelectObject(hdc, hfont);
1440 GetTextMetricsA(hdc, &tm);
1441 ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1442 ok(ret, "got %d\n", ret);
1443 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1444
1445 memset(&sz, 0xcc, sizeof(sz));
1446 ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1447 ok(ret, "got %d\n", ret);
1448 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1449
1450 memset(&sz, 0xcc, sizeof(sz));
1451 ret = GetTextExtentPointA(hdc, "", 0, &sz);
1452 ok(ret, "got %d\n", ret);
1453 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1454
1455 SetLastError(0xdeadbeef);
1456 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1457 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1458 {
1459 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1460 hfont = SelectObject(hdc, hfont);
1461 DeleteObject(hfont);
1462 ReleaseDC(0, hdc);
1463 return;
1464 }
1465
1466 memset(&sz, 0xcc, sizeof(sz));
1467 ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1468 ok(ret, "got %d\n", ret);
1469 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1470
1471 memset(&sz, 0xcc, sizeof(sz));
1472 ret = GetTextExtentPointW(hdc, emptyW, 0, &sz);
1473 ok(ret, "got %d\n", ret);
1474 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1475
1476 len = lstrlenW(wt);
1477 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1478 extents[0] = 1; /* So that the increasing sequence test will fail
1479 if the extents array is untouched. */
1480 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1481 GetTextExtentPointW(hdc, wt, len, &sz2);
1482 ok(sz1.cy == sz2.cy,
1483 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1484 /* Because of the '\n' in the string GetTextExtentExPoint and
1485 GetTextExtentPoint return different widths under Win2k, but
1486 under WinXP they return the same width. So we don't test that
1487 here. */
1488
1489 for (i = 1; i < len; ++i)
1490 ok(extents[i-1] <= extents[i],
1491 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1492 i);
1493 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1494 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1495 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1496 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1497 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1498 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1499 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1500 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1501 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1502 ok(extents[0] == extents[2] && extents[1] == extents[3],
1503 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1504 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1505 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1506 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1507
1508 /* extents functions fail with -ve counts (the interesting case being -1) */
1509 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1510 ok(ret == FALSE, "got %d\n", ret);
1511 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1512 ok(ret == FALSE, "got %d\n", ret);
1513 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1514 ok(ret == FALSE, "got %d\n", ret);
1515
1516 /* max_extent = 0 succeeds and returns zero */
1517 fit1 = fit2 = -215;
1518 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1519 ok(ret == TRUE ||
1520 broken(ret == FALSE), /* NT4, 2k */
1521 "got %d\n", ret);
1522 ok(fit1 == 0 ||
1523 broken(fit1 == -215), /* NT4, 2k */
1524 "fit = %d\n", fit1);
1525 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1526 ok(ret == TRUE, "got %d\n", ret);
1527 ok(fit2 == 0, "fit = %d\n", fit2);
1528
1529 /* max_extent = -1 is interpreted as a very large width that will
1530 * definitely fit our three characters */
1531 fit1 = fit2 = -215;
1532 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1533 ok(ret == TRUE, "got %d\n", ret);
1534 ok(fit1 == 3, "fit = %d\n", fit1);
1535 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1536 ok(ret == TRUE, "got %d\n", ret);
1537 ok(fit2 == 3, "fit = %d\n", fit2);
1538
1539 /* max_extent = -2 is interpreted similarly, but the Ansi version
1540 * rejects it while the Unicode one accepts it */
1541 fit1 = fit2 = -215;
1542 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1543 ok(ret == FALSE, "got %d\n", ret);
1544 ok(fit1 == -215, "fit = %d\n", fit1);
1545 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1546 ok(ret == TRUE, "got %d\n", ret);
1547 ok(fit2 == 3, "fit = %d\n", fit2);
1548
1549 hfont = SelectObject(hdc, hfont);
1550 DeleteObject(hfont);
1551
1552 /* non-MM_TEXT mapping mode */
1553 lf.lfHeight = 2000;
1554 hfont = CreateFontIndirectA(&lf);
1555 hfont = SelectObject(hdc, hfont);
1556
1557 SetMapMode( hdc, MM_HIMETRIC );
1558 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1559 ok(ret, "got %d\n", ret);
1560 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1561
1562 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1563 ok(ret, "got %d\n", ret);
1564 ok(fit1 == 2, "got %d\n", fit1);
1565 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1566 for(i = 0; i < 2; i++)
1567 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1568
1569 hfont = SelectObject(hdc, hfont);
1570 DeleteObject(hfont);
1571 HeapFree(GetProcessHeap(), 0, extents);
1572 ReleaseDC(NULL, hdc);
1573 }
1574
1575 static void test_GetGlyphIndices(void)
1576 {
1577 HDC hdc;
1578 HFONT hfont;
1579 DWORD charcount;
1580 LOGFONTA lf;
1581 DWORD flags = 0;
1582 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1583 WORD glyphs[(sizeof(testtext)/2)-1];
1584 TEXTMETRICA textm;
1585 HFONT hOldFont;
1586
1587 if (!pGetGlyphIndicesW) {
1588 win_skip("GetGlyphIndicesW not available on platform\n");
1589 return;
1590 }
1591
1592 hdc = GetDC(0);
1593
1594 memset(&lf, 0, sizeof(lf));
1595 strcpy(lf.lfFaceName, "System");
1596 lf.lfHeight = 16;
1597 lf.lfCharSet = ANSI_CHARSET;
1598
1599 hfont = CreateFontIndirectA(&lf);
1600 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1601 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1602 if (textm.tmCharSet == ANSI_CHARSET)
1603 {
1604 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1605 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1606 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1607 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1608 flags = 0;
1609 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1610 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1611 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1612 textm.tmDefaultChar, glyphs[4]);
1613 }
1614 else
1615 /* FIXME: Write tests for non-ANSI charsets. */
1616 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1617
1618 if(!is_font_installed("Tahoma"))
1619 {
1620 skip("Tahoma is not installed so skipping this test\n");
1621 return;
1622 }
1623 memset(&lf, 0, sizeof(lf));
1624 strcpy(lf.lfFaceName, "Tahoma");
1625 lf.lfHeight = 20;
1626
1627 hfont = CreateFontIndirectA(&lf);
1628 hOldFont = SelectObject(hdc, hfont);
1629 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1630 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1631 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1632 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1633 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1634 flags = 0;
1635 testtext[0] = textm.tmDefaultChar;
1636 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1637 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1638 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1639 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1640 DeleteObject(SelectObject(hdc, hOldFont));
1641 }
1642
1643 static void test_GetKerningPairs(void)
1644 {
1645 static const struct kerning_data
1646 {
1647 const char face_name[LF_FACESIZE];
1648 LONG height;
1649 /* some interesting fields from OUTLINETEXTMETRIC */
1650 LONG tmHeight, tmAscent, tmDescent;
1651 UINT otmEMSquare;
1652 INT otmAscent;
1653 INT otmDescent;
1654 UINT otmLineGap;
1655 UINT otmsCapEmHeight;
1656 UINT otmsXHeight;
1657 INT otmMacAscent;
1658 INT otmMacDescent;
1659 UINT otmMacLineGap;
1660 UINT otmusMinimumPPEM;
1661 /* small subset of kerning pairs to test */
1662 DWORD total_kern_pairs;
1663 const KERNINGPAIR kern_pair[26];
1664 } kd[] =
1665 {
1666 {"Arial", 12, 12, 9, 3,
1667 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1668 26,
1669 {
1670 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1671 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1672 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1673 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1674 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1675 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1676 {933,970,+1},{933,972,-1}
1677 }
1678 },
1679 {"Arial", -34, 39, 32, 7,
1680 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1681 26,
1682 {
1683 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1684 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1685 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1686 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1687 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1688 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1689 {933,970,+2},{933,972,-3}
1690 }
1691 },
1692 { "Arial", 120, 120, 97, 23,
1693 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1694 26,
1695 {
1696 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1697 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1698 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1699 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1700 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1701 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1702 {933,970,+6},{933,972,-10}
1703 }
1704 },
1705 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1706 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1707 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1708 26,
1709 {
1710 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1711 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1712 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1713 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1714 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1715 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1716 {933,970,+54},{933,972,-83}
1717 }
1718 }
1719 #endif
1720 };
1721 LOGFONTA lf;
1722 HFONT hfont, hfont_old;
1723 KERNINGPAIR *kern_pair;
1724 HDC hdc;
1725 DWORD total_kern_pairs, ret, i, n, matches;
1726
1727 hdc = GetDC(0);
1728
1729 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1730 * which may render this test unusable, so we're trying to avoid that.
1731 */
1732 SetLastError(0xdeadbeef);
1733 GetKerningPairsW(hdc, 0, NULL);
1734 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1735 {
1736 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1737 ReleaseDC(0, hdc);
1738 return;
1739 }
1740
1741 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1742 {
1743 OUTLINETEXTMETRICW otm;
1744 UINT uiRet;
1745
1746 if (!is_font_installed(kd[i].face_name))
1747 {
1748 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1749 continue;
1750 }
1751
1752 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1753
1754 memset(&lf, 0, sizeof(lf));
1755 strcpy(lf.lfFaceName, kd[i].face_name);
1756 lf.lfHeight = kd[i].height;
1757 hfont = CreateFontIndirectA(&lf);
1758 ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name);
1759
1760 hfont_old = SelectObject(hdc, hfont);
1761
1762 SetLastError(0xdeadbeef);
1763 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1764 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1765 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1766
1767 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1768 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1769 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1770 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1771 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1772 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1773
1774 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1775 kd[i].otmEMSquare, otm.otmEMSquare);
1776 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1777 kd[i].otmAscent, otm.otmAscent);
1778 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1779 kd[i].otmDescent, otm.otmDescent);
1780 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1781 kd[i].otmLineGap, otm.otmLineGap);
1782 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1783 kd[i].otmMacDescent, otm.otmMacDescent);
1784 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1785 kd[i].otmMacAscent, otm.otmMacAscent);
1786 todo_wine {
1787 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1788 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1789 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1790 kd[i].otmsXHeight, otm.otmsXHeight);
1791 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1792 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1793 kd[i].otmMacLineGap, otm.otmMacLineGap);
1794 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1795 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1796 }
1797
1798 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1799 trace("total_kern_pairs %u\n", total_kern_pairs);
1800 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1801
1802 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1803 * passes on XP.
1804 */
1805 SetLastError(0xdeadbeef);
1806 ret = GetKerningPairsW(hdc, 0, kern_pair);
1807 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1808 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1809 ok(ret == 0, "got %u, expected 0\n", ret);
1810
1811 ret = GetKerningPairsW(hdc, 100, NULL);
1812 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1813
1814 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1815 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1816
1817 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1818 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1819
1820 matches = 0;
1821
1822 for (n = 0; n < ret; n++)
1823 {
1824 DWORD j;
1825 /* Disabled to limit console spam */
1826 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1827 trace("{'%c','%c',%d},\n",
1828 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1829 for (j = 0; j < kd[i].total_kern_pairs; j++)
1830 {
1831 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1832 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1833 {
1834 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1835 "pair %d:%d got %d, expected %d\n",
1836 kern_pair[n].wFirst, kern_pair[n].wSecond,
1837 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1838 matches++;
1839 }
1840 }
1841 }
1842
1843 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1844 matches, kd[i].total_kern_pairs);
1845
1846 HeapFree(GetProcessHeap(), 0, kern_pair);
1847
1848 SelectObject(hdc, hfont_old);
1849 DeleteObject(hfont);
1850 }
1851
1852 ReleaseDC(0, hdc);
1853 }
1854
1855 struct font_data
1856 {
1857 const char face_name[LF_FACESIZE];
1858 int requested_height;
1859 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1860 BOOL exact;
1861 };
1862
1863 static void test_height( HDC hdc, const struct font_data *fd )
1864 {
1865 LOGFONTA lf;
1866 HFONT hfont, old_hfont;
1867 TEXTMETRICA tm;
1868 INT ret, i;
1869
1870 for (i = 0; fd[i].face_name[0]; i++)
1871 {
1872 if (!is_truetype_font_installed(fd[i].face_name))
1873 {
1874 skip("%s is not installed\n", fd[i].face_name);
1875 continue;
1876 }
1877
1878 memset(&lf, 0, sizeof(lf));
1879 lf.lfHeight = fd[i].requested_height;
1880 lf.lfWeight = fd[i].weight;
1881 strcpy(lf.lfFaceName, fd[i].face_name);
1882
1883 hfont = CreateFontIndirectA(&lf);
1884 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
1885
1886 old_hfont = SelectObject(hdc, hfont);
1887 ret = GetTextMetricsA(hdc, &tm);
1888 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1889 if(fd[i].dpi == tm.tmDigitizedAspectX)
1890 {
1891 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1892 ok(match_off_by_1(tm.tmHeight, fd[i].height, fd[i].exact), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1893 ok(match_off_by_1(tm.tmAscent, fd[i].ascent, fd[i].exact), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1894 ok(match_off_by_1(tm.tmDescent, fd[i].descent, fd[i].exact), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1895 ok(match_off_by_1(tm.tmInternalLeading, fd[i].int_leading, fd[i].exact), "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1896 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1897 }
1898
1899 SelectObject(hdc, old_hfont);
1900 /* force GDI to use new font, otherwise Windows leaks the font reference */
1901 GetTextMetricsA(hdc, &tm);
1902 DeleteObject(hfont);
1903 }
1904 }
1905
1906 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1907 {
1908 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1909 DWORD *table = (DWORD *)ttf + 3;
1910
1911 for (i = 0; i < num_tables; i++)
1912 {
1913 if (table[0] == tag)
1914 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1915 table += 4;
1916 }
1917 return NULL;
1918 }
1919
1920 static void test_height_selection_vdmx( HDC hdc )
1921 {
1922 static const struct font_data charset_0[] = /* doesn't use VDMX */
1923 {
1924 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1925 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1926 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1927 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1928 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1929 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1930 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1931 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1932 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1933 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1934 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1935 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1936 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1937 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1938 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1939 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1940 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1941 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1942 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1943 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1944 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1945 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1946 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1947 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1948 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1949 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1950 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1951 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1952 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1953 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1954 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1955 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1956 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1957 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1958 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1959 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1960 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1961 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1962 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1963 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1964 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1965 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1966 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1967 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1968 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1969 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1970 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1971 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1972 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1973 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1974 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1975 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1976 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1977 };
1978
1979 static const struct font_data charset_1[] = /* Uses VDMX */
1980 {
1981 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1982 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1983 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1984 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1985 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1986 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1987 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1988 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1989 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1990 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1991 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1992 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1993 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1994 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1995 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1996 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1997 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1998 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1999 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2000 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2001 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2002 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2003 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2004 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
2005 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
2006 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
2007 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2008 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2009 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2010 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2011 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2012 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2013 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2014 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2015 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2016 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2017 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2018 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2019 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2020 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2021 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2022 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2023 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2024 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2025 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2026 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2027 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2028 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2029 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2030 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2031 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2032 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2033 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2034 };
2035
2036 static const struct vdmx_data
2037 {
2038 WORD version;
2039 BYTE bCharSet;
2040 const struct font_data *fd;
2041 } data[] =
2042 {
2043 { 0, 0, charset_0 },
2044 { 0, 1, charset_1 },
2045 { 1, 0, charset_0 },
2046 { 1, 1, charset_1 }
2047 };
2048 int i;
2049 DWORD size, num;
2050 WORD *vdmx_header;
2051 BYTE *ratio_rec;
2052 char ttf_name[MAX_PATH];
2053 void *res, *copy;
2054 BOOL ret;
2055
2056 if (!pAddFontResourceExA)
2057 {
2058 win_skip("AddFontResourceExA unavailable\n");
2059 return;
2060 }
2061
2062 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2063 {
2064 res = get_res_data( "wine_vdmx.ttf", &size );
2065
2066 copy = HeapAlloc( GetProcessHeap(), 0, size );
2067 memcpy( copy, res, size );
2068 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2069 vdmx_header[0] = GET_BE_WORD( data[i].version );
2070 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2071 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2072 ratio_rec = (BYTE *)&vdmx_header[3];
2073 ratio_rec[0] = data[i].bCharSet;
2074
2075 write_tmp_file( copy, &size, ttf_name );
2076 HeapFree( GetProcessHeap(), 0, copy );
2077
2078 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2079 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2080 if (!num) win_skip("Unable to add ttf font resource\n");
2081 else
2082 {
2083 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2084 test_height( hdc, data[i].fd );
2085 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2086 }
2087 ret = DeleteFileA( ttf_name );
2088 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2089 "DeleteFile error %d\n", GetLastError());
2090 }
2091 }
2092
2093 static void test_height_selection(void)
2094 {
2095 static const struct font_data tahoma[] =
2096 {
2097 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2098 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2099 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2100 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2101 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2102 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2103 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2104 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2105 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2106 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2107 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2108 };
2109 HDC hdc = CreateCompatibleDC(0);
2110 ok(hdc != NULL, "failed to create hdc\n");
2111
2112 test_height( hdc, tahoma );
2113 test_height_selection_vdmx( hdc );
2114
2115 DeleteDC(hdc);
2116 }
2117
2118 static UINT get_font_fsselection(LOGFONTA *lf)
2119 {
2120 OUTLINETEXTMETRICA *otm;
2121 HFONT hfont, hfont_old;
2122 DWORD ret, otm_size;
2123 UINT fsSelection;
2124 HDC hdc;
2125
2126 hdc = GetDC(0);
2127 hfont = CreateFontIndirectA(lf);
2128 ok(hfont != NULL, "failed to create a font\n");
2129
2130 hfont_old = SelectObject(hdc, hfont);
2131
2132 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2133 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2134 otm->otmSize = sizeof(*otm);
2135 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2136 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2137 fsSelection = otm->otmfsSelection;
2138 HeapFree(GetProcessHeap(), 0, otm);
2139 SelectObject(hdc, hfont_old);
2140 DeleteObject(hfont);
2141 ReleaseDC(0, hdc);
2142
2143 return fsSelection;
2144 }
2145
2146 static void test_GetOutlineTextMetrics(void)
2147 {
2148 OUTLINETEXTMETRICA *otm;
2149 LOGFONTA lf;
2150 HFONT hfont, hfont_old;
2151 HDC hdc;
2152 DWORD ret, otm_size;
2153 LPSTR unset_ptr;
2154 UINT fsSelection;
2155
2156 /* check fsSelection field with bold simulation */
2157 memset(&lf, 0, sizeof(lf));
2158 strcpy(lf.lfFaceName, "Wingdings");
2159 lf.lfCharSet = SYMBOL_CHARSET;
2160
2161 /* regular face */
2162 fsSelection = get_font_fsselection(&lf);
2163 ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection);
2164
2165 /* face with bold simulation */
2166 lf.lfWeight = FW_BOLD;
2167 fsSelection = get_font_fsselection(&lf);
2168 ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection);
2169
2170 /* check fsSelection field with oblique simulation */
2171 memset(&lf, 0, sizeof(lf));
2172 strcpy(lf.lfFaceName, "Tahoma");
2173 lf.lfHeight = -13;
2174 lf.lfWeight = FW_NORMAL;
2175 lf.lfPitchAndFamily = DEFAULT_PITCH;
2176 lf.lfQuality = PROOF_QUALITY;
2177
2178 /* regular face */
2179 fsSelection = get_font_fsselection(&lf);
2180 ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection);
2181
2182 lf.lfItalic = 1;
2183 /* face with oblique simulation */
2184 fsSelection = get_font_fsselection(&lf);
2185 ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection);
2186
2187 if (!is_font_installed("Arial"))
2188 {
2189 skip("Arial is not installed\n");
2190 return;
2191 }
2192
2193 hdc = GetDC(0);
2194
2195 memset(&lf, 0, sizeof(lf));
2196 strcpy(lf.lfFaceName, "Arial");
2197 lf.lfHeight = -13;
2198 lf.lfWeight = FW_NORMAL;
2199 lf.lfPitchAndFamily = DEFAULT_PITCH;
2200 lf.lfQuality = PROOF_QUALITY;
2201 hfont = CreateFontIndirectA(&lf);
2202 ok(hfont != NULL, "failed to create a font\n");
2203
2204 hfont_old = SelectObject(hdc, hfont);
2205 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2206 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2207
2208 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2209
2210 memset(otm, 0xAA, otm_size);
2211 SetLastError(0xdeadbeef);
2212 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2213 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2214 ok(ret == 1 /* Win9x */ ||
2215 ret == otm->otmSize /* XP*/,
2216 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2217 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2218 {
2219 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2220 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2221 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2222 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2223 }
2224
2225 memset(otm, 0xAA, otm_size);
2226 SetLastError(0xdeadbeef);
2227 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2228 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2229 ok(ret == 1 /* Win9x */ ||
2230 ret == otm->otmSize /* XP*/,
2231 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2232 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2233 {
2234 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2235 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2236 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2237 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2238 }
2239
2240 /* ask about truncated data */
2241 memset(otm, 0xAA, otm_size);
2242 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2243 SetLastError(0xdeadbeef);
2244 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2245 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2246 ok(ret == 1 /* Win9x */ ||
2247 ret == otm->otmSize /* XP*/,
2248 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2249 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2250 {
2251 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2252 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2253 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2254 }
2255 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2256
2257 /* check handling of NULL pointer */
2258 SetLastError(0xdeadbeef);
2259 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2260 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2261
2262 HeapFree(GetProcessHeap(), 0, otm);
2263
2264 SelectObject(hdc, hfont_old);
2265 DeleteObject(hfont);
2266
2267 ReleaseDC(0, hdc);
2268 }
2269
2270 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2271 {
2272 INT y,
2273 breakCount,
2274 areaWidth = clientArea->right - clientArea->left,
2275 nErrors = 0, e;
2276 const char *pFirstChar, *pLastChar;
2277 SIZE size;
2278 TEXTMETRICA tm;
2279 struct err
2280 {
2281 const char *start;
2282 int len;
2283 int GetTextExtentExPointWWidth;
2284 } error[20];
2285
2286 GetTextMetricsA(hdc, &tm);
2287 y = clientArea->top;
2288 do {
2289 breakCount = 0;
2290 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2291 pFirstChar = str;
2292
2293 do {
2294 pLastChar = str;
2295
2296 /* if not at the end of the string, ... */
2297 if (*str == '\0') break;
2298 /* ... add the next word to the current extent */
2299 while (*str != '\0' && *str++ != tm.tmBreakChar);
2300 breakCount++;
2301 SetTextJustification(hdc, 0, 0);
2302 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2303 } while ((int) size.cx < areaWidth);
2304
2305 /* ignore trailing break chars */
2306 breakCount--;
2307 while (*(pLastChar - 1) == tm.tmBreakChar)
2308 {
2309 pLastChar--;
2310 breakCount--;
2311 }
2312
2313 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2314
2315 SetTextJustification(hdc, 0, 0);
2316 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2317
2318 /* do not justify the last extent */
2319 if (*str != '\0' && breakCount > 0)
2320 {
2321 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2322 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2323 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2324 {
2325 error[nErrors].start = pFirstChar;
2326 error[nErrors].len = pLastChar - pFirstChar;
2327 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2328 nErrors++;
2329 }
2330 }
2331
2332 y += size.cy;
2333 str = pLastChar;
2334 } while (*str && y < clientArea->bottom);
2335
2336 for (e = 0; e < nErrors; e++)
2337 {
2338 /* The width returned by GetTextExtentPoint32() is exactly the same
2339 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2340 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2341 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2342 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2343 }
2344 }
2345
2346 static void test_SetTextJustification(void)
2347 {
2348 HDC hdc;
2349 RECT clientArea;
2350 LOGFONTA lf;
2351 HFONT hfont;
2352 HWND hwnd;
2353 SIZE size, expect;
2354 int i;
2355 WORD indices[2];
2356 static const char testText[] =
2357 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2358 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2359 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2360 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2361 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2362 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2363 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2364
2365 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2366 GetClientRect( hwnd, &clientArea );
2367 hdc = GetDC( hwnd );
2368
2369 if (!is_font_installed("Times New Roman"))
2370 {
2371 skip("Times New Roman is not installed\n");
2372 return;
2373 }
2374
2375 memset(&lf, 0, sizeof lf);
2376 lf.lfCharSet = ANSI_CHARSET;
2377 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2378 lf.lfWeight = FW_DONTCARE;
2379 lf.lfHeight = 20;
2380 lf.lfQuality = DEFAULT_QUALITY;
2381 lstrcpyA(lf.lfFaceName, "Times New Roman");
2382 hfont = create_font("Times New Roman", &lf);
2383 SelectObject(hdc, hfont);
2384
2385 testJustification(hdc, testText, &clientArea);
2386
2387 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2388 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2389
2390 SetTextJustification(hdc, 0, 0);
2391 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2392 GetTextExtentPoint32A(hdc, " ", 3, &size);
2393 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2394 SetTextJustification(hdc, 4, 1);
2395 GetTextExtentPoint32A(hdc, " ", 1, &size);
2396 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2397 SetTextJustification(hdc, 9, 2);
2398 GetTextExtentPoint32A(hdc, " ", 2, &size);
2399 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2400 SetTextJustification(hdc, 7, 3);
2401 GetTextExtentPoint32A(hdc, " ", 3, &size);
2402 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2403 SetTextJustification(hdc, 7, 3);
2404 SetTextCharacterExtra(hdc, 2 );
2405 GetTextExtentPoint32A(hdc, " ", 3, &size);
2406 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
<