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