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 }
1274