[GDIPLUS_WINETEST] Sync with Wine 3.0. CORE-14225
[reactos.git] / modules / rostests / winetests / gdiplus / font.c
1 /*
2 * Unit test suite for fonts
3 *
4 * Copyright (C) 2007 Google (Evan Stade)
5 * Copyright (C) 2012 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 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
25 #define expect_(expected, got, precision) ok(abs((expected) - (got)) <= (precision), "Expected %d, got %d\n", (expected), (got))
26 #define expectf_(expected, got, precision) ok(fabs((expected) - (got)) <= (precision), "Expected %f, got %f\n", (expected), (got))
27 #define expectf(expected, got) expectf_((expected), (got), 0.001)
28
29 static const WCHAR nonexistent[] = {'T','h','i','s','F','o','n','t','s','h','o','u','l','d','N','o','t','E','x','i','s','t','\0'};
30 static const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
31 static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
32 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
33
34 static void set_rect_empty(RectF *rc)
35 {
36 rc->X = 0.0;
37 rc->Y = 0.0;
38 rc->Width = 0.0;
39 rc->Height = 0.0;
40 }
41
42 static void create_testfontfile(const WCHAR *filename, int resource, WCHAR pathW[MAX_PATH])
43 {
44 DWORD written;
45 HANDLE file;
46 HRSRC res;
47 void *ptr;
48
49 GetTempPathW(MAX_PATH, pathW);
50 lstrcatW(pathW, filename);
51
52 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
53 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW), GetLastError());
54
55 res = FindResourceA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(resource), (LPCSTR)RT_RCDATA);
56 ok(res != 0, "couldn't find resource\n");
57 ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res));
58 WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), &written, NULL);
59 ok(written == SizeofResource(GetModuleHandleA(NULL), res), "couldn't write resource\n");
60 CloseHandle(file);
61 }
62
63 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
64 static void _delete_testfontfile(const WCHAR *filename, int line)
65 {
66 BOOL ret = DeleteFileW(filename);
67 ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError());
68 }
69
70 static void test_long_name(void)
71 {
72 WCHAR path[MAX_PATH];
73 static const WCHAR path_longname[] = {'w','i','n','e','_','l','o','n','g','n','a','m','e','.','t','t','f',0};
74 GpStatus stat;
75 GpFontCollection *fonts;
76 INT num_families;
77 GpFontFamily *family;
78 WCHAR family_name[LF_FACESIZE];
79 GpFont *font;
80
81 stat = GdipNewPrivateFontCollection(&fonts);
82 ok(stat == Ok, "GdipNewPrivateFontCollection failed: %d\n", stat);
83
84 create_testfontfile(path_longname, 1, path);
85
86 stat = GdipPrivateAddFontFile(fonts, path);
87 ok(stat == Ok, "GdipPrivateAddFontFile failed: %d\n", stat);
88
89 stat = GdipGetFontCollectionFamilyCount(fonts, &num_families);
90 ok(stat == Ok, "GdipGetFontCollectionFamilyCount failed: %d\n", stat);
91
92 ok(num_families == 1, "expected num_families to be 1, got %d\n", num_families);
93
94 stat = GdipGetFontCollectionFamilyList(fonts, num_families, &family, &num_families);
95 ok(stat == Ok, "GdipGetFontCollectionFamilyList failed: %d\n", stat);
96
97 stat = GdipGetFamilyName(family, family_name, LANG_NEUTRAL);
98 ok(stat == Ok, "GdipGetFamilyName failed: %d\n", stat);
99
100 stat = GdipCreateFont(family, 256.0, FontStyleRegular, UnitPixel, &font);
101 ok(stat == Ok, "GdipCreateFont failed: %d\n", stat);
102
103 /* Cleanup */
104
105 stat = GdipDeleteFont(font);
106 ok(stat == Ok, "GdipDeleteFont failed: %d\n", stat);
107
108 stat = GdipDeletePrivateFontCollection(&fonts);
109 ok(stat == Ok, "GdipDeletePrivateFontCollection failed: %d\n", stat);
110
111 DELETE_FONTFILE(path);
112 }
113
114 static void test_createfont(void)
115 {
116 GpFontFamily* fontfamily = NULL, *fontfamily2;
117 GpFont* font = NULL;
118 GpStatus stat;
119 Unit unit;
120 UINT i;
121 REAL size;
122 WCHAR familyname[LF_FACESIZE];
123
124 stat = GdipCreateFontFamilyFromName(nonexistent, NULL, &fontfamily);
125 expect (FontFamilyNotFound, stat);
126 stat = GdipDeleteFont(font);
127 expect (InvalidParameter, stat);
128 stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &fontfamily);
129 expect (Ok, stat);
130 stat = GdipCreateFont(fontfamily, 12, FontStyleRegular, UnitPoint, &font);
131 expect (Ok, stat);
132 stat = GdipGetFontUnit (font, &unit);
133 expect (Ok, stat);
134 expect (UnitPoint, unit);
135
136 stat = GdipGetFamily(font, &fontfamily2);
137 expect(Ok, stat);
138 stat = GdipGetFamilyName(fontfamily2, familyname, 0);
139 expect(Ok, stat);
140 ok (lstrcmpiW(Tahoma, familyname) == 0, "Expected Tahoma, got %s\n",
141 wine_dbgstr_w(familyname));
142 stat = GdipDeleteFontFamily(fontfamily2);
143 expect(Ok, stat);
144
145 /* Test to see if returned size is based on unit (it's not) */
146 GdipGetFontSize(font, &size);
147 ok (size == 12, "Expected 12, got %f\n", size);
148 GdipDeleteFont(font);
149
150 /* Make sure everything is converted correctly for all Units */
151 for (i = UnitWorld; i <=UnitMillimeter; i++)
152 {
153 if (i == UnitDisplay) continue; /* Crashes WindowsXP, wtf? */
154 stat = GdipCreateFont(fontfamily, 24, FontStyleRegular, i, &font);
155 expect(Ok, stat);
156 GdipGetFontSize (font, &size);
157 ok (size == 24, "Expected 24, got %f (with unit: %d)\n", size, i);
158 GdipGetFontUnit (font, &unit);
159 expect (i, unit);
160 GdipDeleteFont(font);
161 }
162
163 GdipDeleteFontFamily(fontfamily);
164 }
165
166 static void test_logfont(void)
167 {
168 LOGFONTA lfa, lfa2;
169 GpFont *font;
170 GpFontFamily *family;
171 GpStatus stat;
172 GpGraphics *graphics;
173 HDC hdc = GetDC(0);
174 INT style;
175 REAL rval;
176 UINT16 em_height, line_spacing;
177 Unit unit;
178
179 stat = GdipCreateFromHDC(hdc, &graphics);
180 expect(Ok, stat);
181
182 memset(&lfa, 0, sizeof(LOGFONTA));
183 memset(&lfa2, 0xff, sizeof(LOGFONTA));
184 lstrcpyA(lfa.lfFaceName, "Tahoma");
185
186 stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font);
187 expect(Ok, stat);
188 stat = GdipGetLogFontA(font, graphics, &lfa2);
189 expect(Ok, stat);
190
191 ok(lfa2.lfHeight < 0, "Expected negative height\n");
192 expect(0, lfa2.lfWidth);
193 expect(0, lfa2.lfEscapement);
194 expect(0, lfa2.lfOrientation);
195 ok((lfa2.lfWeight >= 100) && (lfa2.lfWeight <= 900), "Expected weight to be set\n");
196 expect(0, lfa2.lfItalic);
197 expect(0, lfa2.lfUnderline);
198 expect(0, lfa2.lfStrikeOut);
199 ok(lfa2.lfCharSet == GetTextCharset(hdc) || lfa2.lfCharSet == ANSI_CHARSET,
200 "Expected %x or %x, got %x\n", GetTextCharset(hdc), ANSI_CHARSET, lfa2.lfCharSet);
201 expect(0, lfa2.lfOutPrecision);
202 expect(0, lfa2.lfClipPrecision);
203 expect(0, lfa2.lfQuality);
204 expect(0, lfa2.lfPitchAndFamily);
205
206 GdipDeleteFont(font);
207
208 memset(&lfa, 0, sizeof(LOGFONTA));
209 lfa.lfHeight = 25;
210 lfa.lfWidth = 25;
211 lfa.lfEscapement = lfa.lfOrientation = 50;
212 lfa.lfItalic = lfa.lfUnderline = lfa.lfStrikeOut = TRUE;
213
214 memset(&lfa2, 0xff, sizeof(LOGFONTA));
215 lstrcpyA(lfa.lfFaceName, "Tahoma");
216
217 stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font);
218 expect(Ok, stat);
219 stat = GdipGetLogFontA(font, graphics, &lfa2);
220 expect(Ok, stat);
221
222 ok(lfa2.lfHeight < 0, "Expected negative height\n");
223 expect(0, lfa2.lfWidth);
224 expect(0, lfa2.lfEscapement);
225 expect(0, lfa2.lfOrientation);
226 ok((lfa2.lfWeight >= 100) && (lfa2.lfWeight <= 900), "Expected weight to be set\n");
227 expect(TRUE, lfa2.lfItalic);
228 expect(TRUE, lfa2.lfUnderline);
229 expect(TRUE, lfa2.lfStrikeOut);
230 ok(lfa2.lfCharSet == GetTextCharset(hdc) || lfa2.lfCharSet == ANSI_CHARSET,
231 "Expected %x or %x, got %x\n", GetTextCharset(hdc), ANSI_CHARSET, lfa2.lfCharSet);
232 expect(0, lfa2.lfOutPrecision);
233 expect(0, lfa2.lfClipPrecision);
234 expect(0, lfa2.lfQuality);
235 expect(0, lfa2.lfPitchAndFamily);
236
237 stat = GdipGetFontStyle(font, &style);
238 expect(Ok, stat);
239 ok (style == (FontStyleItalic | FontStyleUnderline | FontStyleStrikeout),
240 "Expected , got %d\n", style);
241
242 stat = GdipGetFontUnit(font, &unit);
243 expect(Ok, stat);
244 expect(UnitWorld, unit);
245
246 stat = GdipGetFontHeight(font, graphics, &rval);
247 expect(Ok, stat);
248 expectf(25.347656, rval);
249 stat = GdipGetFontSize(font, &rval);
250 expect(Ok, stat);
251 expectf(21.0, rval);
252
253 stat = GdipGetFamily(font, &family);
254 expect(Ok, stat);
255 stat = GdipGetEmHeight(family, FontStyleRegular, &em_height);
256 expect(Ok, stat);
257 expect(2048, em_height);
258 stat = GdipGetLineSpacing(family, FontStyleRegular, &line_spacing);
259 expect(Ok, stat);
260 expect(2472, line_spacing);
261 GdipDeleteFontFamily(family);
262
263 GdipDeleteFont(font);
264
265 memset(&lfa, 0, sizeof(lfa));
266 lfa.lfHeight = -25;
267 lstrcpyA(lfa.lfFaceName, "Tahoma");
268 stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font);
269 expect(Ok, stat);
270 memset(&lfa2, 0xff, sizeof(lfa2));
271 stat = GdipGetLogFontA(font, graphics, &lfa2);
272 expect(Ok, stat);
273 expect(lfa.lfHeight, lfa2.lfHeight);
274
275 stat = GdipGetFontUnit(font, &unit);
276 expect(Ok, stat);
277 expect(UnitWorld, unit);
278
279 stat = GdipGetFontHeight(font, graphics, &rval);
280 expect(Ok, stat);
281 expectf(30.175781, rval);
282 stat = GdipGetFontSize(font, &rval);
283 expect(Ok, stat);
284 expectf(25.0, rval);
285
286 stat = GdipGetFamily(font, &family);
287 expect(Ok, stat);
288 stat = GdipGetEmHeight(family, FontStyleRegular, &em_height);
289 expect(Ok, stat);
290 expect(2048, em_height);
291 stat = GdipGetLineSpacing(family, FontStyleRegular, &line_spacing);
292 expect(Ok, stat);
293 expect(2472, line_spacing);
294 GdipDeleteFontFamily(family);
295
296 GdipDeleteFont(font);
297
298 GdipDeleteGraphics(graphics);
299 ReleaseDC(0, hdc);
300 }
301
302 static void test_fontfamily (void)
303 {
304 GpFontFamily *family, *clonedFontFamily;
305 WCHAR itsName[LF_FACESIZE];
306 GpStatus stat;
307
308 /* FontFamily cannot be NULL */
309 stat = GdipCreateFontFamilyFromName (Tahoma , NULL, NULL);
310 expect (InvalidParameter, stat);
311
312 /* FontFamily must be able to actually find the family.
313 * If it can't, any subsequent calls should fail.
314 */
315 stat = GdipCreateFontFamilyFromName (nonexistent, NULL, &family);
316 expect (FontFamilyNotFound, stat);
317
318 /* Bitmap fonts are not found */
319 stat = GdipCreateFontFamilyFromName (MSSansSerif, NULL, &family);
320 expect (FontFamilyNotFound, stat);
321 if(stat == Ok) GdipDeleteFontFamily(family);
322
323 stat = GdipCreateFontFamilyFromName (Tahoma, NULL, &family);
324 expect (Ok, stat);
325
326 stat = GdipGetFamilyName (family, itsName, LANG_NEUTRAL);
327 expect (Ok, stat);
328 expect (0, lstrcmpiW(itsName, Tahoma));
329
330 if (0)
331 {
332 /* Crashes on Windows XP SP2, Vista, and so Wine as well */
333 stat = GdipGetFamilyName (family, NULL, LANG_NEUTRAL);
334 expect (Ok, stat);
335 }
336
337 /* Make sure we don't read old data */
338 ZeroMemory (itsName, sizeof(itsName));
339 stat = GdipCloneFontFamily(family, &clonedFontFamily);
340 expect (Ok, stat);
341 GdipDeleteFontFamily(family);
342 stat = GdipGetFamilyName(clonedFontFamily, itsName, LANG_NEUTRAL);
343 expect(Ok, stat);
344 expect(0, lstrcmpiW(itsName, Tahoma));
345
346 GdipDeleteFontFamily(clonedFontFamily);
347 }
348
349 static void test_fontfamily_properties (void)
350 {
351 GpFontFamily* FontFamily = NULL;
352 GpStatus stat;
353 UINT16 result = 0;
354
355 stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &FontFamily);
356 expect(Ok, stat);
357
358 stat = GdipGetLineSpacing(FontFamily, FontStyleRegular, &result);
359 expect(Ok, stat);
360 ok (result == 2472, "Expected 2472, got %d\n", result);
361 result = 0;
362 stat = GdipGetEmHeight(FontFamily, FontStyleRegular, &result);
363 expect(Ok, stat);
364 ok(result == 2048, "Expected 2048, got %d\n", result);
365 result = 0;
366 stat = GdipGetCellAscent(FontFamily, FontStyleRegular, &result);
367 expect(Ok, stat);
368 ok(result == 2049, "Expected 2049, got %d\n", result);
369 result = 0;
370 stat = GdipGetCellDescent(FontFamily, FontStyleRegular, &result);
371 expect(Ok, stat);
372 ok(result == 423, "Expected 423, got %d\n", result);
373 GdipDeleteFontFamily(FontFamily);
374
375 stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, &FontFamily);
376 if(stat == FontFamilyNotFound)
377 skip("Times New Roman not installed\n");
378 else
379 {
380 result = 0;
381 stat = GdipGetLineSpacing(FontFamily, FontStyleRegular, &result);
382 expect(Ok, stat);
383 ok(result == 2355, "Expected 2355, got %d\n", result);
384 result = 0;
385 stat = GdipGetEmHeight(FontFamily, FontStyleRegular, &result);
386 expect(Ok, stat);
387 ok(result == 2048, "Expected 2048, got %d\n", result);
388 result = 0;
389 stat = GdipGetCellAscent(FontFamily, FontStyleRegular, &result);
390 expect(Ok, stat);
391 ok(result == 1825, "Expected 1825, got %d\n", result);
392 result = 0;
393 stat = GdipGetCellDescent(FontFamily, FontStyleRegular, &result);
394 expect(Ok, stat);
395 ok(result == 443, "Expected 443 got %d\n", result);
396 GdipDeleteFontFamily(FontFamily);
397 }
398 }
399
400 static void check_family(const char* context, GpFontFamily *family, WCHAR *name)
401 {
402 GpStatus stat;
403 GpFont* font;
404
405 *name = 0;
406 stat = GdipGetFamilyName(family, name, LANG_NEUTRAL);
407 ok(stat == Ok, "could not get the %s family name: %.8x\n", context, stat);
408
409 stat = GdipCreateFont(family, 12, FontStyleRegular, UnitPixel, &font);
410 ok(stat == Ok, "could not create a font for the %s family: %.8x\n", context, stat);
411 if (stat == Ok)
412 {
413 stat = GdipDeleteFont(font);
414 ok(stat == Ok, "could not delete the %s family font: %.8x\n", context, stat);
415 }
416
417 stat = GdipDeleteFontFamily(family);
418 ok(stat == Ok, "could not delete the %s family: %.8x\n", context, stat);
419 }
420
421 static void test_getgenerics (void)
422 {
423 GpStatus stat;
424 GpFontFamily *family;
425 WCHAR sansname[LF_FACESIZE], serifname[LF_FACESIZE], mononame[LF_FACESIZE];
426 int missingfonts = 0;
427
428 stat = GdipGetGenericFontFamilySansSerif(&family);
429 expect (Ok, stat);
430 if (stat == FontFamilyNotFound)
431 missingfonts = 1;
432 else
433 check_family("Sans Serif", family, sansname);
434
435 stat = GdipGetGenericFontFamilySerif(&family);
436 expect (Ok, stat);
437 if (stat == FontFamilyNotFound)
438 missingfonts = 1;
439 else
440 check_family("Serif", family, serifname);
441
442 stat = GdipGetGenericFontFamilyMonospace(&family);
443 expect (Ok, stat);
444 if (stat == FontFamilyNotFound)
445 missingfonts = 1;
446 else
447 check_family("Monospace", family, mononame);
448
449 if (missingfonts && strcmp(winetest_platform, "wine") == 0)
450 trace("You may need to install either the Microsoft Web Fonts or the Liberation Fonts\n");
451
452 /* Check that the family names are all different */
453 ok(lstrcmpiW(sansname, serifname) != 0, "Sans Serif and Serif families should be different: %s\n", wine_dbgstr_w(sansname));
454 ok(lstrcmpiW(sansname, mononame) != 0, "Sans Serif and Monospace families should be different: %s\n", wine_dbgstr_w(sansname));
455 ok(lstrcmpiW(serifname, mononame) != 0, "Serif and Monospace families should be different: %s\n", wine_dbgstr_w(serifname));
456 }
457
458 static void test_installedfonts (void)
459 {
460 GpStatus stat;
461 GpFontCollection* collection=NULL;
462
463 stat = GdipNewInstalledFontCollection(NULL);
464 expect (InvalidParameter, stat);
465
466 stat = GdipNewInstalledFontCollection(&collection);
467 expect (Ok, stat);
468 ok (collection != NULL, "got NULL font collection\n");
469 }
470
471 static void test_heightgivendpi(void)
472 {
473 GpStatus stat;
474 GpFont* font = NULL;
475 GpFontFamily* fontfamily = NULL;
476 REAL height;
477 Unit unit;
478
479 stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &fontfamily);
480 expect(Ok, stat);
481
482 stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitPixel, &font);
483 expect(Ok, stat);
484
485 stat = GdipGetFontHeightGivenDPI(NULL, 96, &height);
486 expect(InvalidParameter, stat);
487
488 stat = GdipGetFontHeightGivenDPI(font, 96, NULL);
489 expect(InvalidParameter, stat);
490
491 stat = GdipGetFontHeightGivenDPI(font, 96, &height);
492 expect(Ok, stat);
493 expectf(36.210938, height);
494 GdipDeleteFont(font);
495
496 height = 12345;
497 stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitWorld, &font);
498 expect(Ok, stat);
499
500 stat = GdipGetFontUnit(font, &unit);
501 expect(Ok, stat);
502 expect(UnitWorld, unit);
503
504 stat = GdipGetFontHeightGivenDPI(font, 96, &height);
505 expect(Ok, stat);
506 expectf(36.210938, height);
507 GdipDeleteFont(font);
508
509 height = 12345;
510 stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitPoint, &font);
511 expect(Ok, stat);
512 stat = GdipGetFontHeightGivenDPI(font, 96, &height);
513 expect(Ok, stat);
514 expectf(48.281250, height);
515 GdipDeleteFont(font);
516
517 height = 12345;
518 stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitInch, &font);
519 expect(Ok, stat);
520
521 stat = GdipGetFontUnit(font, &unit);
522 expect(Ok, stat);
523 expect(UnitInch, unit);
524
525 stat = GdipGetFontHeightGivenDPI(font, 96, &height);
526 expect(Ok, stat);
527 expectf(3476.250000, height);
528 GdipDeleteFont(font);
529
530 height = 12345;
531 stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitDocument, &font);
532 expect(Ok, stat);
533
534 stat = GdipGetFontUnit(font, &unit);
535 expect(Ok, stat);
536 expect(UnitDocument, unit);
537
538 stat = GdipGetFontHeightGivenDPI(font, 96, &height);
539 expect(Ok, stat);
540 expectf(11.587500, height);
541 GdipDeleteFont(font);
542
543 height = 12345;
544 stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitMillimeter, &font);
545 expect(Ok, stat);
546
547 stat = GdipGetFontUnit(font, &unit);
548 expect(Ok, stat);
549 expect(UnitMillimeter, unit);
550
551 stat = GdipGetFontHeightGivenDPI(font, 96, &height);
552 expect(Ok, stat);
553 expectf(136.860245, height);
554 GdipDeleteFont(font);
555
556 GdipDeleteFontFamily(fontfamily);
557 }
558
559 static int CALLBACK font_enum_proc(const LOGFONTW *lfe, const TEXTMETRICW *ntme,
560 DWORD type, LPARAM lparam)
561 {
562 NEWTEXTMETRICW *ntm = (NEWTEXTMETRICW *)lparam;
563
564 if (type != TRUETYPE_FONTTYPE) return 1;
565
566 *ntm = *(NEWTEXTMETRICW *)ntme;
567 return 0;
568 }
569
570 struct font_metrics
571 {
572 UINT16 em_height, line_spacing, ascent, descent;
573 REAL font_height, font_size;
574 INT lfHeight;
575 };
576
577 static void gdi_get_font_metrics(LOGFONTW *lf, struct font_metrics *fm)
578 {
579 HDC hdc;
580 HFONT hfont;
581 NEWTEXTMETRICW ntm;
582 OUTLINETEXTMETRICW otm;
583 int ret;
584
585 hdc = CreateCompatibleDC(0);
586
587 /* it's the only way to get extended NEWTEXTMETRIC fields */
588 ret = EnumFontFamiliesExW(hdc, lf, font_enum_proc, (LPARAM)&ntm, 0);
589 ok(!ret, "EnumFontFamiliesExW failed to find %s\n", wine_dbgstr_w(lf->lfFaceName));
590
591 hfont = CreateFontIndirectW(lf);
592 SelectObject(hdc, hfont);
593
594 otm.otmSize = sizeof(otm);
595 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
596 ok(ret, "GetOutlineTextMetrics failed\n");
597
598 DeleteDC(hdc);
599 DeleteObject(hfont);
600
601 fm->lfHeight = -otm.otmTextMetrics.tmAscent;
602 fm->line_spacing = ntm.ntmCellHeight;
603 fm->font_size = (REAL)otm.otmTextMetrics.tmAscent;
604 fm->font_height = (REAL)fm->line_spacing * fm->font_size / (REAL)ntm.ntmSizeEM;
605 fm->em_height = ntm.ntmSizeEM;
606 fm->ascent = ntm.ntmSizeEM;
607 fm->descent = ntm.ntmCellHeight - ntm.ntmSizeEM;
608 }
609
610 static void gdip_get_font_metrics(GpFont *font, struct font_metrics *fm)
611 {
612 INT style;
613 GpFontFamily *family;
614 GpStatus stat;
615
616 stat = GdipGetFontStyle(font, &style);
617 expect(Ok, stat);
618
619 stat = GdipGetFontHeight(NULL, NULL, &fm->font_height);
620 expect(InvalidParameter, stat);
621
622 stat = GdipGetFontHeight(font, NULL, NULL);
623 expect(InvalidParameter, stat);
624
625 stat = GdipGetFontHeight(font, NULL, &fm->font_height);
626 expect(Ok, stat);
627 stat = GdipGetFontSize(font, &fm->font_size);
628 expect(Ok, stat);
629
630 fm->lfHeight = (INT)(fm->font_size * -1.0);
631
632 stat = GdipGetFamily(font, &family);
633 expect(Ok, stat);
634
635 stat = GdipGetEmHeight(family, style, &fm->em_height);
636 expect(Ok, stat);
637 stat = GdipGetLineSpacing(family, style, &fm->line_spacing);
638 expect(Ok, stat);
639 stat = GdipGetCellAscent(family, style, &fm->ascent);
640 expect(Ok, stat);
641 stat = GdipGetCellDescent(family, style, &fm->descent);
642 expect(Ok, stat);
643
644 GdipDeleteFontFamily(family);
645 }
646
647 static void cmp_font_metrics(struct font_metrics *fm1, struct font_metrics *fm2, int line)
648 {
649 ok_(__FILE__, line)(fm1->lfHeight == fm2->lfHeight, "lfHeight %d != %d\n", fm1->lfHeight, fm2->lfHeight);
650 ok_(__FILE__, line)(fm1->em_height == fm2->em_height, "em_height %u != %u\n", fm1->em_height, fm2->em_height);
651 ok_(__FILE__, line)(fm1->line_spacing == fm2->line_spacing, "line_spacing %u != %u\n", fm1->line_spacing, fm2->line_spacing);
652 ok_(__FILE__, line)(abs(fm1->ascent - fm2->ascent) <= 1, "ascent %u != %u\n", fm1->ascent, fm2->ascent);
653 ok_(__FILE__, line)(abs(fm1->descent - fm2->descent) <= 1, "descent %u != %u\n", fm1->descent, fm2->descent);
654 ok(fm1->font_height > 0.0, "fm1->font_height should be positive, got %f\n", fm1->font_height);
655 ok(fm2->font_height > 0.0, "fm2->font_height should be positive, got %f\n", fm2->font_height);
656 ok_(__FILE__, line)(fm1->font_height == fm2->font_height, "font_height %f != %f\n", fm1->font_height, fm2->font_height);
657 ok(fm1->font_size > 0.0, "fm1->font_size should be positive, got %f\n", fm1->font_size);
658 ok(fm2->font_size > 0.0, "fm2->font_size should be positive, got %f\n", fm2->font_size);
659 ok_(__FILE__, line)(fm1->font_size == fm2->font_size, "font_size %f != %f\n", fm1->font_size, fm2->font_size);
660 }
661
662 static void test_font_metrics(void)
663 {
664 LOGFONTW lf;
665 GpFont *font;
666 GpFontFamily *family;
667 GpGraphics *graphics;
668 GpStatus stat;
669 Unit unit;
670 struct font_metrics fm_gdi, fm_gdip;
671 HDC hdc;
672
673 hdc = CreateCompatibleDC(0);
674 stat = GdipCreateFromHDC(hdc, &graphics);
675 expect(Ok, stat);
676
677 memset(&lf, 0, sizeof(lf));
678
679 /* Tahoma,-13 */
680 lstrcpyW(lf.lfFaceName, Tahoma);
681 lf.lfHeight = -13;
682 stat = GdipCreateFontFromLogfontW(hdc, &lf, &font);
683 expect(Ok, stat);
684
685 stat = GdipGetFontUnit(font, &unit);
686 expect(Ok, stat);
687 expect(UnitWorld, unit);
688
689 gdip_get_font_metrics(font, &fm_gdip);
690 trace("gdiplus:\n");
691 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
692 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
693 fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent,
694 fm_gdip.font_height, fm_gdip.font_size);
695
696 gdi_get_font_metrics(&lf, &fm_gdi);
697 trace("gdi:\n");
698 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
699 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
700 fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent,
701 fm_gdi.font_height, fm_gdi.font_size);
702
703 cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__);
704
705 stat = GdipGetLogFontW(font, graphics, &lf);
706 expect(Ok, stat);
707 ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight);
708 gdi_get_font_metrics(&lf, &fm_gdi);
709 trace("gdi:\n");
710 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
711 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
712 fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent,
713 fm_gdi.font_height, fm_gdi.font_size);
714 ok((REAL)lf.lfHeight * -1.0 == fm_gdi.font_size, "expected %f, got %f\n", (REAL)lf.lfHeight * -1.0, fm_gdi.font_size);
715
716 cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__);
717
718 GdipDeleteFont(font);
719
720 /* Tahoma,13 */
721 lstrcpyW(lf.lfFaceName, Tahoma);
722 lf.lfHeight = 13;
723 stat = GdipCreateFontFromLogfontW(hdc, &lf, &font);
724 expect(Ok, stat);
725
726 stat = GdipGetFontUnit(font, &unit);
727 expect(Ok, stat);
728 expect(UnitWorld, unit);
729
730 gdip_get_font_metrics(font, &fm_gdip);
731 trace("gdiplus:\n");
732 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
733 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
734 fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent,
735 fm_gdip.font_height, fm_gdip.font_size);
736
737 gdi_get_font_metrics(&lf, &fm_gdi);
738 trace("gdi:\n");
739 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
740 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
741 fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent,
742 fm_gdi.font_height, fm_gdi.font_size);
743
744 cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__);
745
746 stat = GdipGetLogFontW(font, graphics, &lf);
747 expect(Ok, stat);
748 ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight);
749 gdi_get_font_metrics(&lf, &fm_gdi);
750 trace("gdi:\n");
751 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
752 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
753 fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent,
754 fm_gdi.font_height, fm_gdi.font_size);
755 ok((REAL)lf.lfHeight * -1.0 == fm_gdi.font_size, "expected %f, got %f\n", (REAL)lf.lfHeight * -1.0, fm_gdi.font_size);
756
757 cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__);
758
759 GdipDeleteFont(font);
760
761 stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &family);
762 expect(Ok, stat);
763
764 /* Tahoma,13 */
765 stat = GdipCreateFont(family, 13.0, FontStyleRegular, UnitPixel, &font);
766 expect(Ok, stat);
767
768 gdip_get_font_metrics(font, &fm_gdip);
769 trace("gdiplus:\n");
770 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
771 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
772 fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent,
773 fm_gdip.font_height, fm_gdip.font_size);
774
775 stat = GdipGetLogFontW(font, graphics, &lf);
776 expect(Ok, stat);
777 ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight);
778 gdi_get_font_metrics(&lf, &fm_gdi);
779 trace("gdi:\n");
780 trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n",
781 wine_dbgstr_w(lf.lfFaceName), lf.lfHeight,
782 fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent,
783 fm_gdi.font_height, fm_gdi.font_size);
784 ok((REAL)lf.lfHeight * -1.0 == fm_gdi.font_size, "expected %f, got %f\n", (REAL)lf.lfHeight * -1.0, fm_gdi.font_size);
785
786 cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__);
787
788 stat = GdipGetLogFontW(font, NULL, &lf);
789 expect(InvalidParameter, stat);
790
791 GdipDeleteFont(font);
792
793 stat = GdipCreateFont(family, -13.0, FontStyleRegular, UnitPixel, &font);
794 expect(InvalidParameter, stat);
795
796 GdipDeleteFontFamily(family);
797
798 GdipDeleteGraphics(graphics);
799 DeleteDC(hdc);
800 }
801
802 static void test_font_substitution(void)
803 {
804 WCHAR ms_shell_dlg[LF_FACESIZE];
805 char fallback_font[LF_FACESIZE];
806 HDC hdc;
807 HFONT hfont;
808 LOGFONTA lf;
809 GpStatus status;
810 GpGraphics *graphics;
811 GpFont *font;
812 GpFontFamily *family;
813 int ret;
814
815 hdc = CreateCompatibleDC(0);
816 status = GdipCreateFromHDC(hdc, &graphics);
817 expect(Ok, status);
818
819 hfont = GetStockObject(DEFAULT_GUI_FONT);
820 ok(hfont != 0, "GetStockObject(DEFAULT_GUI_FONT) failed\n");
821
822 memset(&lf, 0xfe, sizeof(lf));
823 ret = GetObjectA(hfont, sizeof(lf), &lf);
824 ok(ret == sizeof(lf), "GetObject failed\n");
825 ok(!lstrcmpA(lf.lfFaceName, "MS Shell Dlg"), "wrong face name %s\n", lf.lfFaceName);
826 MultiByteToWideChar(CP_ACP, 0, lf.lfFaceName, -1, ms_shell_dlg, LF_FACESIZE);
827
828 status = GdipCreateFontFromLogfontA(hdc, &lf, &font);
829 expect(Ok, status);
830 memset(&lf, 0xfe, sizeof(lf));
831 status = GdipGetLogFontA(font, graphics, &lf);
832 expect(Ok, status);
833 ok(!lstrcmpA(lf.lfFaceName, "Microsoft Sans Serif") ||
834 !lstrcmpA(lf.lfFaceName, "Tahoma"), "wrong face name %s\n", lf.lfFaceName);
835 GdipDeleteFont(font);
836
837 status = GdipCreateFontFamilyFromName(ms_shell_dlg, NULL, &family);
838 expect(Ok, status);
839 status = GdipCreateFont(family, 12, FontStyleRegular, UnitPoint, &font);
840 expect(Ok, status);
841 memset(&lf, 0xfe, sizeof(lf));
842 status = GdipGetLogFontA(font, graphics, &lf);
843 expect(Ok, status);
844 ok(!lstrcmpA(lf.lfFaceName, "Microsoft Sans Serif") ||
845 !lstrcmpA(lf.lfFaceName, "Tahoma"), "wrong face name %s\n", lf.lfFaceName);
846 GdipDeleteFont(font);
847 GdipDeleteFontFamily(family);
848
849 status = GdipCreateFontFamilyFromName(nonexistent, NULL, &family);
850 ok(status == FontFamilyNotFound, "expected FontFamilyNotFound, got %d\n", status);
851
852 /* nonexistent fonts fallback to Arial, or something else if it's missing */
853 strcpy(lf.lfFaceName,"Arial");
854 status = GdipCreateFontFromLogfontA(hdc, &lf, &font);
855 expect(Ok, status);
856 status = GdipGetLogFontA(font, graphics, &lf);
857 expect(Ok, status);
858 strcpy(fallback_font,lf.lfFaceName);
859 trace("fallback font %s\n", fallback_font);
860 GdipDeleteFont(font);
861
862 lstrcpyA(lf.lfFaceName, "ThisFontShouldNotExist");
863 status = GdipCreateFontFromLogfontA(hdc, &lf, &font);
864 expect(Ok, status);
865 memset(&lf, 0xfe, sizeof(lf));
866 status = GdipGetLogFontA(font, graphics, &lf);
867 expect(Ok, status);
868 ok(!lstrcmpA(lf.lfFaceName, fallback_font), "wrong face name %s / %s\n", lf.lfFaceName, fallback_font);
869 GdipDeleteFont(font);
870
871 /* empty FaceName */
872 lf.lfFaceName[0] = 0;
873 status = GdipCreateFontFromLogfontA(hdc, &lf, &font);
874 expect(Ok, status);
875 memset(&lf, 0xfe, sizeof(lf));
876 status = GdipGetLogFontA(font, graphics, &lf);
877 expect(Ok, status);
878 ok(!lstrcmpA(lf.lfFaceName, fallback_font), "wrong face name %s / %s\n", lf.lfFaceName, fallback_font);
879 GdipDeleteFont(font);
880
881 /* zeroing out lfWeight and lfCharSet leads to font creation failure */
882 lf.lfWeight = 0;
883 lf.lfCharSet = 0;
884 lstrcpyA(lf.lfFaceName, "ThisFontShouldNotExist");
885 font = NULL;
886 status = GdipCreateFontFromLogfontA(hdc, &lf, &font);
887 todo_wine
888 ok(status == NotTrueTypeFont || broken(status == FileNotFound), /* before XP */
889 "expected NotTrueTypeFont, got %d\n", status);
890 /* FIXME: remove when wine is fixed */
891 if (font) GdipDeleteFont(font);
892
893 /* empty FaceName */
894 lf.lfFaceName[0] = 0;
895 font = NULL;
896 status = GdipCreateFontFromLogfontA(hdc, &lf, &font);
897 todo_wine
898 ok(status == NotTrueTypeFont || broken(status == FileNotFound), /* before XP */
899 "expected NotTrueTypeFont, got %d\n", status);
900 /* FIXME: remove when wine is fixed */
901 if (font) GdipDeleteFont(font);
902
903 GdipDeleteGraphics(graphics);
904 DeleteDC(hdc);
905 }
906
907 static void test_font_transform(void)
908 {
909 static const WCHAR string[] = { 'A',0 };
910 GpStatus status;
911 HDC hdc;
912 LOGFONTA lf;
913 GpFont *font;
914 GpGraphics *graphics;
915 GpMatrix *matrix;
916 GpStringFormat *format, *typographic;
917 PointF pos[1] = { { 0,0 } };
918 REAL height, margin_y;
919 RectF bounds, rect;
920
921 hdc = CreateCompatibleDC(0);
922 status = GdipCreateFromHDC(hdc, &graphics);
923 expect(Ok, status);
924
925 status = GdipSetPageUnit(graphics, UnitPixel);
926 expect(Ok, status);
927
928 status = GdipCreateStringFormat(0, LANG_NEUTRAL, &format);
929 expect(Ok, status);
930 status = GdipStringFormatGetGenericTypographic(&typographic);
931 expect(Ok, status);
932
933 memset(&lf, 0, sizeof(lf));
934 lstrcpyA(lf.lfFaceName, "Tahoma");
935 lf.lfHeight = -100;
936 lf.lfWidth = 100;
937 status = GdipCreateFontFromLogfontA(hdc, &lf, &font);
938 expect(Ok, status);
939
940 margin_y = 100.0 / 8.0;
941
942 /* identity matrix */
943 status = GdipCreateMatrix(&matrix);
944 expect(Ok, status);
945 status = GdipSetWorldTransform(graphics, matrix);
946 expect(Ok, status);
947 status = GdipGetLogFontA(font, graphics, &lf);
948 expect(Ok, status);
949 expect(-100, lf.lfHeight);
950 expect(0, lf.lfWidth);
951 expect(0, lf.lfEscapement);
952 expect(0, lf.lfOrientation);
953 status = GdipGetFontHeight(font, graphics, &height);
954 expect(Ok, status);
955 expectf(120.703125, height);
956 set_rect_empty(&rect);
957 set_rect_empty(&bounds);
958 status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, NULL, NULL);
959 expect(Ok, status);
960 expectf(0.0, bounds.X);
961 expectf(0.0, bounds.Y);
962 todo_wine
963 expectf(height + margin_y, bounds.Height);
964 set_rect_empty(&rect);
965 set_rect_empty(&bounds);
966 status = GdipMeasureString(graphics, string, -1, font, &rect, typographic, &bounds, NULL, NULL);
967 expect(Ok, status);
968 expectf(0.0, bounds.X);
969 expectf(0.0, bounds.Y);
970 expectf_(height, bounds.Height, 1.0);
971 set_rect_empty(&bounds);
972 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
973 DriverStringOptionsCmapLookup, NULL, &bounds);
974 expect(Ok, status);
975 expectf(0.0, bounds.X);
976 expectf_(-100.0, bounds.Y, 0.05);
977 expectf_(height, bounds.Height, 0.5);
978 set_rect_empty(&bounds);
979 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
980 DriverStringOptionsCmapLookup, matrix, &bounds);
981 expect(Ok, status);
982 expectf(0.0, bounds.X);
983 expectf_(-100.0, bounds.Y, 0.05);
984 expectf_(height, bounds.Height, 0.5);
985
986 /* scale matrix */
987 status = GdipScaleMatrix(matrix, 2.0, 3.0, MatrixOrderAppend);
988 expect(Ok, status);
989 status = GdipSetWorldTransform(graphics, matrix);
990 expect(Ok, status);
991 status = GdipGetLogFontA(font, graphics, &lf);
992 expect(Ok, status);
993 expect(-300, lf.lfHeight);
994 expect(0, lf.lfWidth);
995 expect(0, lf.lfEscapement);
996 expect(0, lf.lfOrientation);
997 status = GdipGetFontHeight(font, graphics, &height);
998 expect(Ok, status);
999 expectf(120.703125, height);
1000 set_rect_empty(&rect);
1001 set_rect_empty(&bounds);
1002 status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, NULL, NULL);
1003 expect(Ok, status);
1004 expectf(0.0, bounds.X);
1005 expectf(0.0, bounds.Y);
1006 todo_wine
1007 expectf(height + margin_y, bounds.Height);
1008 set_rect_empty(&rect);
1009 set_rect_empty(&bounds);
1010 status = GdipMeasureString(graphics, string, -1, font, &rect, typographic, &bounds, NULL, NULL);
1011 expect(Ok, status);
1012 expectf(0.0, bounds.X);
1013 expectf(0.0, bounds.Y);
1014 expectf_(height, bounds.Height, 0.05);
1015 set_rect_empty(&bounds);
1016 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1017 DriverStringOptionsCmapLookup, NULL, &bounds);
1018 expect(Ok, status);
1019 expectf(0.0, bounds.X);
1020 expectf_(-100.0, bounds.Y, 0.05);
1021 expectf_(height, bounds.Height, 0.2);
1022 set_rect_empty(&bounds);
1023 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1024 DriverStringOptionsCmapLookup, matrix, &bounds);
1025 expect(Ok, status);
1026 expectf(0.0, bounds.X);
1027 todo_wine
1028 expectf_(-300.0, bounds.Y, 0.15);
1029 todo_wine
1030 expectf(height * 3.0, bounds.Height);
1031
1032 /* scale + ratate matrix */
1033 status = GdipRotateMatrix(matrix, 45.0, MatrixOrderAppend);
1034 expect(Ok, status);
1035 status = GdipSetWorldTransform(graphics, matrix);
1036 expect(Ok, status);
1037 status = GdipGetLogFontA(font, graphics, &lf);
1038 expect(Ok, status);
1039 expect(-300, lf.lfHeight);
1040 expect(0, lf.lfWidth);
1041 expect_(3151, lf.lfEscapement, 1);
1042 expect_(3151, lf.lfOrientation, 1);
1043 status = GdipGetFontHeight(font, graphics, &height);
1044 expect(Ok, status);
1045 expectf(120.703125, height);
1046 set_rect_empty(&rect);
1047 set_rect_empty(&bounds);
1048 status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, NULL, NULL);
1049 expect(Ok, status);
1050 expectf(0.0, bounds.X);
1051 expectf(0.0, bounds.Y);
1052 todo_wine
1053 expectf(height + margin_y, bounds.Height);
1054 set_rect_empty(&rect);
1055 set_rect_empty(&bounds);
1056 status = GdipMeasureString(graphics, string, -1, font, &rect, typographic, &bounds, NULL, NULL);
1057 expect(Ok, status);
1058 expectf(0.0, bounds.X);
1059 expectf(0.0, bounds.Y);
1060 expectf_(height, bounds.Height, 0.05);
1061 set_rect_empty(&bounds);
1062 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1063 DriverStringOptionsCmapLookup, NULL, &bounds);
1064 expect(Ok, status);
1065 expectf(0.0, bounds.X);
1066 expectf_(-100.0, bounds.Y, 0.05);
1067 expectf_(height, bounds.Height, 0.2);
1068 set_rect_empty(&bounds);
1069 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1070 DriverStringOptionsCmapLookup, matrix, &bounds);
1071 expect(Ok, status);
1072 todo_wine
1073 expectf_(-43.814377, bounds.X, 0.05);
1074 todo_wine
1075 expectf_(-212.235611, bounds.Y, 0.05);
1076 todo_wine
1077 expectf_(340.847534, bounds.Height, 0.05);
1078
1079 /* scale + ratate + shear matrix */
1080 status = GdipShearMatrix(matrix, 4.0, 5.0, MatrixOrderAppend);
1081 expect(Ok, status);
1082 status = GdipSetWorldTransform(graphics, matrix);
1083 expect(Ok, status);
1084 status = GdipGetLogFontA(font, graphics, &lf);
1085 expect(Ok, status);
1086 todo_wine
1087 expect(1032, lf.lfHeight);
1088 expect(0, lf.lfWidth);
1089 expect_(3099, lf.lfEscapement, 1);
1090 expect_(3099, lf.lfOrientation, 1);
1091 status = GdipGetFontHeight(font, graphics, &height);
1092 expect(Ok, status);
1093 expectf(120.703125, height);
1094 set_rect_empty(&rect);
1095 set_rect_empty(&bounds);
1096 status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, NULL, NULL);
1097 expect(Ok, status);
1098 expectf(0.0, bounds.X);
1099 expectf(0.0, bounds.Y);
1100 todo_wine
1101 expectf(height + margin_y, bounds.Height);
1102 set_rect_empty(&rect);
1103 set_rect_empty(&bounds);
1104 status = GdipMeasureString(graphics, string, -1, font, &rect, typographic, &bounds, NULL, NULL);
1105 expect(Ok, status);
1106 expectf(0.0, bounds.X);
1107 expectf(0.0, bounds.Y);
1108 expectf_(height, bounds.Height, 0.2);
1109 set_rect_empty(&bounds);
1110 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1111 DriverStringOptionsCmapLookup, NULL, &bounds);
1112 expect(Ok, status);
1113 expectf(0.0, bounds.X);
1114 expectf_(-100.0, bounds.Y, 0.2);
1115 expectf_(height, bounds.Height, 0.2);
1116 set_rect_empty(&bounds);
1117 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1118 DriverStringOptionsCmapLookup, matrix, &bounds);
1119 expect(Ok, status);
1120 todo_wine
1121 expectf_(-636.706848, bounds.X, 0.05);
1122 todo_wine
1123 expectf_(-175.257523, bounds.Y, 0.05);
1124 todo_wine
1125 expectf_(1532.984985, bounds.Height, 0.05);
1126
1127 /* scale + ratate + shear + translate matrix */
1128 status = GdipTranslateMatrix(matrix, 10.0, 20.0, MatrixOrderAppend);
1129 expect(Ok, status);
1130 status = GdipSetWorldTransform(graphics, matrix);
1131 expect(Ok, status);
1132 status = GdipGetLogFontA(font, graphics, &lf);
1133 expect(Ok, status);
1134 todo_wine
1135 expect(1032, lf.lfHeight);
1136 expect(0, lf.lfWidth);
1137 expect_(3099, lf.lfEscapement, 1);
1138 expect_(3099, lf.lfOrientation, 1);
1139 status = GdipGetFontHeight(font, graphics, &height);
1140 expect(Ok, status);
1141 expectf(120.703125, height);
1142 set_rect_empty(&rect);
1143 set_rect_empty(&bounds);
1144 status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, NULL, NULL);
1145 expect(Ok, status);
1146 expectf(0.0, bounds.X);
1147 expectf(0.0, bounds.Y);
1148 todo_wine
1149 expectf(height + margin_y, bounds.Height);
1150 set_rect_empty(&rect);
1151 set_rect_empty(&bounds);
1152 status = GdipMeasureString(graphics, string, -1, font, &rect, typographic, &bounds, NULL, NULL);
1153 expect(Ok, status);
1154 expectf(0.0, bounds.X);
1155 expectf(0.0, bounds.Y);
1156 expectf_(height, bounds.Height, 0.1);
1157 set_rect_empty(&bounds);
1158 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1159 DriverStringOptionsCmapLookup, NULL, &bounds);
1160 expect(Ok, status);
1161 expectf(0.0, bounds.X);
1162 expectf_(-100.0, bounds.Y, 0.2);
1163 expectf_(height, bounds.Height, 0.2);
1164 set_rect_empty(&bounds);
1165 status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos,
1166 DriverStringOptionsCmapLookup, matrix, &bounds);
1167 expect(Ok, status);
1168 todo_wine
1169 expectf_(-626.706848, bounds.X, 0.05);
1170 todo_wine
1171 expectf_(-155.257523, bounds.Y, 0.05);
1172 todo_wine
1173 expectf_(1532.984985, bounds.Height, 0.05);
1174
1175 GdipDeleteMatrix(matrix);
1176 GdipDeleteFont(font);
1177 GdipDeleteGraphics(graphics);
1178 GdipDeleteStringFormat(typographic);
1179 GdipDeleteStringFormat(format);
1180 DeleteDC(hdc);
1181 }
1182
1183 static void test_GdipGetFontCollectionFamilyList(void)
1184 {
1185 GpFontFamily *family, *family2;
1186 GpFontCollection *collection;
1187 INT found, count;
1188 GpStatus status;
1189
1190 status = GdipNewInstalledFontCollection(&collection);
1191 ok(status == Ok, "Failed to get system collection, status %d.\n", status);
1192
1193 count = 0;
1194 status = GdipGetFontCollectionFamilyCount(collection, &count);
1195 ok(status == Ok, "Failed to get family count, status %d.\n", status);
1196 ok(count > 0, "Unexpected empty collection.\n");
1197
1198 status = GdipGetFontCollectionFamilyList(NULL, 0, NULL, NULL);
1199 ok(status == InvalidParameter, "Unexpected status %d.\n", status);
1200
1201 found = 123;
1202 status = GdipGetFontCollectionFamilyList(NULL, 0, NULL, &found);
1203 ok(status == InvalidParameter, "Unexpected status %d.\n", status);
1204 ok(found == 123, "Unexpected list count %d.\n", found);
1205
1206 status = GdipGetFontCollectionFamilyList(collection, 0, NULL, NULL);
1207 ok(status == InvalidParameter, "Unexpected status %d.\n", status);
1208
1209 found = 123;
1210 status = GdipGetFontCollectionFamilyList(collection, 0, NULL, &found);
1211 ok(status == InvalidParameter, "Unexpected status %d.\n", status);
1212 ok(found == 123, "Unexpected list count %d.\n", found);
1213
1214 found = 123;
1215 status = GdipGetFontCollectionFamilyList(collection, 1, NULL, &found);
1216 ok(status == InvalidParameter, "Unexpected status %d.\n", status);
1217 ok(found == 123, "Unexpected list count %d.\n", found);
1218
1219 family = NULL;
1220 found = 0;
1221 status = GdipGetFontCollectionFamilyList(collection, 1, &family, &found);
1222 ok(status == Ok, "Failed to get family list, status %d.\n", status);
1223 ok(found == 1, "Unexpected list count %d.\n", found);
1224 ok(family != NULL, "Expected family instance.\n");
1225
1226 family = NULL;
1227 found = 0;
1228 status = GdipGetFontCollectionFamilyList(collection, 1, &family2, &found);
1229 ok(status == Ok, "Failed to get family list, status %d.\n", status);
1230 ok(found == 1, "Unexpected list count %d.\n", found);
1231 ok(family2 != family, "Unexpected family instance.\n");
1232
1233 GdipDeleteFontFamily(family);
1234 GdipDeleteFontFamily(family2);
1235 }
1236
1237 START_TEST(font)
1238 {
1239 struct GdiplusStartupInput gdiplusStartupInput;
1240 ULONG_PTR gdiplusToken;
1241 HMODULE hmsvcrt;
1242 int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask);
1243
1244 /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */
1245 hmsvcrt = LoadLibraryA("msvcrt");
1246 _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s");
1247 if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e);
1248
1249 gdiplusStartupInput.GdiplusVersion = 1;
1250 gdiplusStartupInput.DebugEventCallback = NULL;
1251 gdiplusStartupInput.SuppressBackgroundThread = 0;
1252 gdiplusStartupInput.SuppressExternalCodecs = 0;
1253
1254 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
1255
1256 test_long_name();
1257 test_font_transform();
1258 if (!winetest_interactive)
1259 skip("ROSTESTS-154: Skipping test_font_substitution because of improper error handling\n");
1260 else
1261 test_font_substitution();
1262 test_font_metrics();
1263 test_createfont();
1264 test_logfont();
1265 test_fontfamily();
1266 test_fontfamily_properties();
1267 test_getgenerics();
1268 test_installedfonts();
1269 test_heightgivendpi();
1270 test_GdipGetFontCollectionFamilyList();
1271
1272 GdiplusShutdown(gdiplusToken);
1273 }