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