xref: /reactos/dll/win32/gdiplus/font.c (revision 595b846d)
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  * Copyright (C) 2012 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "gdiplus_private.h"
21 
22 /* PANOSE is 10 bytes in size, need to pack the structure properly */
23 #include <pshpack2.h>
24 typedef struct
25 {
26     USHORT version;
27     SHORT xAvgCharWidth;
28     USHORT usWeightClass;
29     USHORT usWidthClass;
30     SHORT fsType;
31     SHORT ySubscriptXSize;
32     SHORT ySubscriptYSize;
33     SHORT ySubscriptXOffset;
34     SHORT ySubscriptYOffset;
35     SHORT ySuperscriptXSize;
36     SHORT ySuperscriptYSize;
37     SHORT ySuperscriptXOffset;
38     SHORT ySuperscriptYOffset;
39     SHORT yStrikeoutSize;
40     SHORT yStrikeoutPosition;
41     SHORT sFamilyClass;
42     PANOSE panose;
43     ULONG ulUnicodeRange1;
44     ULONG ulUnicodeRange2;
45     ULONG ulUnicodeRange3;
46     ULONG ulUnicodeRange4;
47     CHAR achVendID[4];
48     USHORT fsSelection;
49     USHORT usFirstCharIndex;
50     USHORT usLastCharIndex;
51     /* According to the Apple spec, original version didn't have the below fields,
52      * version numbers were taken from the OpenType spec.
53      */
54     /* version 0 (TrueType 1.5) */
55     USHORT sTypoAscender;
56     USHORT sTypoDescender;
57     USHORT sTypoLineGap;
58     USHORT usWinAscent;
59     USHORT usWinDescent;
60     /* version 1 (TrueType 1.66) */
61     ULONG ulCodePageRange1;
62     ULONG ulCodePageRange2;
63     /* version 2 (OpenType 1.2) */
64     SHORT sxHeight;
65     SHORT sCapHeight;
66     USHORT usDefaultChar;
67     USHORT usBreakChar;
68     USHORT usMaxContext;
69 } TT_OS2_V2;
70 
71 typedef struct
72 {
73     ULONG Version;
74     SHORT Ascender;
75     SHORT Descender;
76     SHORT LineGap;
77     USHORT advanceWidthMax;
78     SHORT minLeftSideBearing;
79     SHORT minRightSideBearing;
80     SHORT xMaxExtent;
81     SHORT caretSlopeRise;
82     SHORT caretSlopeRun;
83     SHORT caretOffset;
84     SHORT reserved[4];
85     SHORT metricDataFormat;
86     USHORT numberOfHMetrics;
87 } TT_HHEA;
88 #include <poppack.h>
89 
90 #ifdef WORDS_BIGENDIAN
91 #define GET_BE_WORD(x) (x)
92 #define GET_BE_DWORD(x) (x)
93 #else
94 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
95 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
96 #endif
97 
98 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
99                     ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
100                     ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
101 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
102 #define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a')
103 
104 static GpStatus clone_font_family(const GpFontFamily *, GpFontFamily **);
105 
106 static GpFontCollection installedFontCollection = {0};
107 
108 /*******************************************************************************
109  * GdipCreateFont [GDIPLUS.@]
110  *
111  * Create a new font based off of a FontFamily
112  *
113  * PARAMS
114  *  *fontFamily     [I] Family to base the font off of
115  *  emSize          [I] Size of the font
116  *  style           [I] Bitwise OR of FontStyle enumeration
117  *  unit            [I] Unit emSize is measured in
118  *  **font          [I] the resulting Font object
119  *
120  * RETURNS
121  *  SUCCESS: Ok
122  *  FAILURE: InvalidParameter if fontfamily or font is NULL.
123  *  FAILURE: FontFamilyNotFound if an invalid FontFamily is given
124  *
125  * NOTES
126  *  UnitDisplay is unsupported.
127  *  emSize is stored separately from lfHeight, to hold the fraction.
128  */
129 GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily,
130                         REAL emSize, INT style, Unit unit, GpFont **font)
131 {
132     HFONT hfont;
133     OUTLINETEXTMETRICW otm;
134     LOGFONTW lfw;
135     HDC hdc;
136     GpStatus stat;
137     int ret;
138 
139     if (!fontFamily || !font || emSize < 0.0)
140         return InvalidParameter;
141 
142     TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily,
143             debugstr_w(fontFamily->FamilyName), emSize, style, unit, font);
144 
145     memset(&lfw, 0, sizeof(lfw));
146 
147     stat = GdipGetFamilyName(fontFamily, lfw.lfFaceName, LANG_NEUTRAL);
148     if (stat != Ok) return stat;
149 
150     lfw.lfHeight = -units_to_pixels(emSize, unit, fontFamily->dpi);
151     lfw.lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR;
152     lfw.lfItalic = style & FontStyleItalic;
153     lfw.lfUnderline = style & FontStyleUnderline;
154     lfw.lfStrikeOut = style & FontStyleStrikeout;
155 
156     hfont = CreateFontIndirectW(&lfw);
157     hdc = CreateCompatibleDC(0);
158     SelectObject(hdc, hfont);
159     otm.otmSize = sizeof(otm);
160     ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
161     DeleteDC(hdc);
162     DeleteObject(hfont);
163 
164     if (!ret) return NotTrueTypeFont;
165 
166     *font = heap_alloc_zero(sizeof(GpFont));
167     if (!*font) return OutOfMemory;
168 
169     (*font)->unit = unit;
170     (*font)->emSize = emSize;
171     (*font)->otm = otm;
172 
173     stat = clone_font_family(fontFamily, &(*font)->family);
174     if (stat != Ok)
175     {
176         heap_free(*font);
177         return stat;
178     }
179 
180     TRACE("<-- %p\n", *font);
181 
182     return Ok;
183 }
184 
185 /*******************************************************************************
186  * GdipCreateFontFromLogfontW [GDIPLUS.@]
187  */
188 GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc,
189     GDIPCONST LOGFONTW *logfont, GpFont **font)
190 {
191     HFONT hfont, oldfont;
192     OUTLINETEXTMETRICW otm;
193     WCHAR facename[LF_FACESIZE];
194     GpStatus stat;
195     int ret;
196 
197     TRACE("(%p, %p, %p)\n", hdc, logfont, font);
198 
199     if (!hdc || !logfont || !font)
200         return InvalidParameter;
201 
202     hfont = CreateFontIndirectW(logfont);
203     oldfont = SelectObject(hdc, hfont);
204     otm.otmSize = sizeof(otm);
205     ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
206     GetTextFaceW(hdc, LF_FACESIZE, facename);
207     SelectObject(hdc, oldfont);
208     DeleteObject(hfont);
209 
210     if (!ret) return NotTrueTypeFont;
211 
212     *font = heap_alloc_zero(sizeof(GpFont));
213     if (!*font) return OutOfMemory;
214 
215     (*font)->unit = UnitWorld;
216     (*font)->emSize = otm.otmTextMetrics.tmAscent;
217     (*font)->otm = otm;
218 
219     stat = GdipCreateFontFamilyFromName(facename, NULL, &(*font)->family);
220     if (stat != Ok)
221     {
222         heap_free(*font);
223         return NotTrueTypeFont;
224     }
225 
226     TRACE("<-- %p\n", *font);
227 
228     return Ok;
229 }
230 
231 /*******************************************************************************
232  * GdipCreateFontFromLogfontA [GDIPLUS.@]
233  */
234 GpStatus WINGDIPAPI GdipCreateFontFromLogfontA(HDC hdc,
235     GDIPCONST LOGFONTA *lfa, GpFont **font)
236 {
237     LOGFONTW lfw;
238 
239     TRACE("(%p, %p, %p)\n", hdc, lfa, font);
240 
241     if(!lfa || !font)
242         return InvalidParameter;
243 
244     memcpy(&lfw, lfa, FIELD_OFFSET(LOGFONTA,lfFaceName) );
245 
246     if(!MultiByteToWideChar(CP_ACP, 0, lfa->lfFaceName, -1, lfw.lfFaceName, LF_FACESIZE))
247         return GenericError;
248 
249     return GdipCreateFontFromLogfontW(hdc, &lfw, font);
250 }
251 
252 /*******************************************************************************
253  * GdipDeleteFont [GDIPLUS.@]
254  */
255 GpStatus WINGDIPAPI GdipDeleteFont(GpFont* font)
256 {
257     TRACE("(%p)\n", font);
258 
259     if(!font)
260         return InvalidParameter;
261 
262     GdipDeleteFontFamily(font->family);
263     heap_free(font);
264 
265     return Ok;
266 }
267 
268 /*******************************************************************************
269  * GdipCreateFontFromDC [GDIPLUS.@]
270  */
271 GpStatus WINGDIPAPI GdipCreateFontFromDC(HDC hdc, GpFont **font)
272 {
273     HFONT hfont;
274     LOGFONTW lfw;
275 
276     TRACE("(%p, %p)\n", hdc, font);
277 
278     if(!font)
279         return InvalidParameter;
280 
281     hfont = GetCurrentObject(hdc, OBJ_FONT);
282     if(!hfont)
283         return GenericError;
284 
285     if(!GetObjectW(hfont, sizeof(LOGFONTW), &lfw))
286         return GenericError;
287 
288     return GdipCreateFontFromLogfontW(hdc, &lfw, font);
289 }
290 
291 /*******************************************************************************
292  * GdipGetFamily [GDIPLUS.@]
293  *
294  * Returns the FontFamily for the specified Font
295  *
296  * PARAMS
297  *  font    [I] Font to request from
298  *  family  [O] Resulting FontFamily object
299  *
300  * RETURNS
301  *  SUCCESS: Ok
302  *  FAILURE: An element of GpStatus
303  */
304 GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family)
305 {
306     TRACE("%p %p\n", font, family);
307 
308     if (!(font && family))
309         return InvalidParameter;
310 
311     return GdipCloneFontFamily(font->family, family);
312 }
313 
314 static REAL get_font_size(const GpFont *font)
315 {
316     return font->emSize;
317 }
318 
319 /******************************************************************************
320  * GdipGetFontSize [GDIPLUS.@]
321  *
322  * Returns the size of the font in Units
323  *
324  * PARAMS
325  *  *font       [I] The font to retrieve size from
326  *  *size       [O] Pointer to hold retrieved value
327  *
328  * RETURNS
329  *  SUCCESS: Ok
330  *  FAILURE: InvalidParameter (font or size was NULL)
331  *
332  * NOTES
333  *  Size returned is actually emSize -- not internal size used for drawing.
334  */
335 GpStatus WINGDIPAPI GdipGetFontSize(GpFont *font, REAL *size)
336 {
337     TRACE("(%p, %p)\n", font, size);
338 
339     if (!(font && size)) return InvalidParameter;
340 
341     *size = get_font_size(font);
342     TRACE("%s,%d => %f\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *size);
343 
344     return Ok;
345 }
346 
347 static INT get_font_style(const GpFont *font)
348 {
349     INT style;
350 
351     if (font->otm.otmTextMetrics.tmWeight > FW_REGULAR)
352         style = FontStyleBold;
353     else
354         style = FontStyleRegular;
355     if (font->otm.otmTextMetrics.tmItalic)
356         style |= FontStyleItalic;
357     if (font->otm.otmTextMetrics.tmUnderlined)
358         style |= FontStyleUnderline;
359     if (font->otm.otmTextMetrics.tmStruckOut)
360         style |= FontStyleStrikeout;
361 
362     return style;
363 }
364 
365 /*******************************************************************************
366  * GdipGetFontStyle [GDIPLUS.@]
367  *
368  * Gets the font's style, returned in bitwise OR of FontStyle enumeration
369  *
370  * PARAMS
371  *  font    [I] font to request from
372  *  style   [O] resulting pointer to a FontStyle enumeration
373  *
374  * RETURNS
375  *  SUCCESS: Ok
376  *  FAILURE: InvalidParameter
377  */
378 GpStatus WINGDIPAPI GdipGetFontStyle(GpFont *font, INT *style)
379 {
380     TRACE("%p %p\n", font, style);
381 
382     if (!(font && style))
383         return InvalidParameter;
384 
385     *style = get_font_style(font);
386     TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *style);
387 
388     return Ok;
389 }
390 
391 /*******************************************************************************
392  * GdipGetFontUnit  [GDIPLUS.@]
393  *
394  * PARAMS
395  *  font    [I] Font to retrieve from
396  *  unit    [O] Return value
397  *
398  * RETURNS
399  *  FAILURE: font or unit was NULL
400  *  OK: otherwise
401  */
402 GpStatus WINGDIPAPI GdipGetFontUnit(GpFont *font, Unit *unit)
403 {
404     TRACE("(%p, %p)\n", font, unit);
405 
406     if (!(font && unit)) return InvalidParameter;
407 
408     *unit = font->unit;
409     TRACE("%s,%d => %d\n", debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *unit);
410 
411     return Ok;
412 }
413 
414 /*******************************************************************************
415  * GdipGetLogFontA [GDIPLUS.@]
416  */
417 GpStatus WINGDIPAPI GdipGetLogFontA(GpFont *font, GpGraphics *graphics,
418     LOGFONTA *lfa)
419 {
420     GpStatus status;
421     LOGFONTW lfw;
422 
423     TRACE("(%p, %p, %p)\n", font, graphics, lfa);
424 
425     status = GdipGetLogFontW(font, graphics, &lfw);
426     if(status != Ok)
427         return status;
428 
429     memcpy(lfa, &lfw, FIELD_OFFSET(LOGFONTA,lfFaceName) );
430 
431     if(!WideCharToMultiByte(CP_ACP, 0, lfw.lfFaceName, -1, lfa->lfFaceName, LF_FACESIZE, NULL, NULL))
432         return GenericError;
433 
434     return Ok;
435 }
436 
437 /*******************************************************************************
438  * GdipGetLogFontW [GDIPLUS.@]
439  */
440 GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, LOGFONTW *lf)
441 {
442     REAL angle, rel_height, height;
443     GpMatrix matrix;
444     GpPointF pt[3];
445 
446     TRACE("(%p, %p, %p)\n", font, graphics, lf);
447 
448     if (!font || !graphics || !lf)
449         return InvalidParameter;
450 
451     matrix = graphics->worldtrans;
452 
453     if (font->unit == UnitPixel || font->unit == UnitWorld)
454     {
455         height = units_to_pixels(font->emSize, graphics->unit, graphics->yres);
456         if (graphics->unit != UnitDisplay)
457             GdipScaleMatrix(&matrix, graphics->scale, graphics->scale, MatrixOrderAppend);
458     }
459     else
460     {
461         if (graphics->unit == UnitDisplay || graphics->unit == UnitPixel)
462             height = units_to_pixels(font->emSize, font->unit, graphics->xres);
463         else
464             height = units_to_pixels(font->emSize, font->unit, graphics->yres);
465     }
466 
467     pt[0].X = 0.0;
468     pt[0].Y = 0.0;
469     pt[1].X = 1.0;
470     pt[1].Y = 0.0;
471     pt[2].X = 0.0;
472     pt[2].Y = 1.0;
473     GdipTransformMatrixPoints(&matrix, pt, 3);
474     angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
475     rel_height = sqrt((pt[2].Y - pt[0].Y) * (pt[2].Y - pt[0].Y)+
476                       (pt[2].X - pt[0].X) * (pt[2].X - pt[0].X));
477 
478     lf->lfHeight = -gdip_round(height * rel_height);
479     lf->lfWidth = 0;
480     lf->lfEscapement = lf->lfOrientation = gdip_round((angle / M_PI) * 1800.0);
481     if (lf->lfEscapement < 0)
482     {
483         lf->lfEscapement += 3600;
484         lf->lfOrientation += 3600;
485     }
486     lf->lfWeight = font->otm.otmTextMetrics.tmWeight;
487     lf->lfItalic = font->otm.otmTextMetrics.tmItalic ? 1 : 0;
488     lf->lfUnderline = font->otm.otmTextMetrics.tmUnderlined ? 1 : 0;
489     lf->lfStrikeOut = font->otm.otmTextMetrics.tmStruckOut ? 1 : 0;
490     lf->lfCharSet = font->otm.otmTextMetrics.tmCharSet;
491     lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
492     lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
493     lf->lfQuality = DEFAULT_QUALITY;
494     lf->lfPitchAndFamily = 0;
495     strcpyW(lf->lfFaceName, font->family->FamilyName);
496 
497     TRACE("=> %s,%d\n", debugstr_w(lf->lfFaceName), lf->lfHeight);
498 
499     return Ok;
500 }
501 
502 /*******************************************************************************
503  * GdipCloneFont [GDIPLUS.@]
504  */
505 GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont)
506 {
507     GpStatus stat;
508 
509     TRACE("(%p, %p)\n", font, cloneFont);
510 
511     if(!font || !cloneFont)
512         return InvalidParameter;
513 
514     *cloneFont = heap_alloc_zero(sizeof(GpFont));
515     if(!*cloneFont)    return OutOfMemory;
516 
517     **cloneFont = *font;
518     stat = GdipCloneFontFamily(font->family, &(*cloneFont)->family);
519     if (stat != Ok) heap_free(*cloneFont);
520 
521     return stat;
522 }
523 
524 /*******************************************************************************
525  * GdipGetFontHeight [GDIPLUS.@]
526  * PARAMS
527  *  font        [I] Font to retrieve height from
528  *  graphics    [I] The current graphics context
529  *  height      [O] Resulting height
530  * RETURNS
531  *  SUCCESS: Ok
532  *  FAILURE: Another element of GpStatus
533  *
534  * NOTES
535  *  Forwards to GdipGetFontHeightGivenDPI
536  */
537 GpStatus WINGDIPAPI GdipGetFontHeight(GDIPCONST GpFont *font,
538         GDIPCONST GpGraphics *graphics, REAL *height)
539 {
540     REAL dpi;
541     GpStatus stat;
542     REAL font_height;
543 
544     TRACE("%p %p %p\n", font, graphics, height);
545 
546     if (!font || !height) return InvalidParameter;
547 
548     stat = GdipGetFontHeightGivenDPI(font, font->family->dpi, &font_height);
549     if (stat != Ok) return stat;
550 
551     if (!graphics)
552     {
553         *height = font_height;
554         TRACE("%s,%d => %f\n",
555               debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *height);
556         return Ok;
557     }
558 
559     stat = GdipGetDpiY((GpGraphics *)graphics, &dpi);
560     if (stat != Ok) return stat;
561 
562     *height = pixels_to_units(font_height, graphics->unit, dpi);
563 
564     TRACE("%s,%d(unit %d) => %f\n",
565           debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, graphics->unit, *height);
566     return Ok;
567 }
568 
569 /*******************************************************************************
570  * GdipGetFontHeightGivenDPI [GDIPLUS.@]
571  * PARAMS
572  *  font        [I] Font to retrieve DPI from
573  *  dpi         [I] DPI to assume
574  *  height      [O] Return value
575  *
576  * RETURNS
577  *  SUCCESS: Ok
578  *  FAILURE: InvalidParameter if font or height is NULL
579  *
580  * NOTES
581  *  According to MSDN, the result is (lineSpacing)*(fontSize / emHeight)*dpi
582  *  (for anything other than unit Pixel)
583  */
584 GpStatus WINGDIPAPI GdipGetFontHeightGivenDPI(GDIPCONST GpFont *font, REAL dpi, REAL *height)
585 {
586     GpStatus stat;
587     INT style;
588     UINT16 line_spacing, em_height;
589     REAL font_size;
590 
591     if (!font || !height) return InvalidParameter;
592 
593     TRACE("%p (%s), %f, %p\n", font,
594             debugstr_w(font->family->FamilyName), dpi, height);
595 
596     font_size = units_to_pixels(get_font_size(font), font->unit, dpi);
597     style = get_font_style(font);
598     stat = GdipGetLineSpacing(font->family, style, &line_spacing);
599     if (stat != Ok) return stat;
600     stat = GdipGetEmHeight(font->family, style, &em_height);
601     if (stat != Ok) return stat;
602 
603     *height = (REAL)line_spacing * font_size / (REAL)em_height;
604 
605     TRACE("%s,%d => %f\n",
606           debugstr_w(font->family->FamilyName), font->otm.otmTextMetrics.tmHeight, *height);
607 
608     return Ok;
609 }
610 
611 /***********************************************************************
612  * Borrowed from GDI32:
613  *
614  * Elf is really an ENUMLOGFONTEXW, and ntm is a NEWTEXTMETRICEXW.
615  *     We have to use other types because of the FONTENUMPROCW definition.
616  */
617 static INT CALLBACK is_font_installed_proc(const LOGFONTW *elf,
618                             const TEXTMETRICW *ntm, DWORD type, LPARAM lParam)
619 {
620     const ENUMLOGFONTW *elfW = (const ENUMLOGFONTW *)elf;
621     LOGFONTW *lf = (LOGFONTW *)lParam;
622 
623     if (type & RASTER_FONTTYPE)
624         return 1;
625 
626     *lf = *elf;
627     /* replace substituted font name by a real one */
628     lstrcpynW(lf->lfFaceName, elfW->elfFullName, LF_FACESIZE);
629     return 0;
630 }
631 
632 struct font_metrics
633 {
634     WCHAR facename[LF_FACESIZE];
635     UINT16 em_height, ascent, descent, line_spacing; /* in font units */
636     int dpi;
637 };
638 
639 static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm)
640 {
641     OUTLINETEXTMETRICW otm;
642     TT_OS2_V2 tt_os2;
643     TT_HHEA tt_hori;
644     LONG size;
645     UINT16 line_gap;
646 
647     otm.otmSize = sizeof(otm);
648     if (!GetOutlineTextMetricsW(hdc, otm.otmSize, &otm)) return FALSE;
649 
650     fm->em_height = otm.otmEMSquare;
651     fm->dpi = GetDeviceCaps(hdc, LOGPIXELSY);
652 
653     memset(&tt_hori, 0, sizeof(tt_hori));
654     if (GetFontData(hdc, MS_HHEA_TAG, 0, &tt_hori, sizeof(tt_hori)) != GDI_ERROR)
655     {
656         fm->ascent = GET_BE_WORD(tt_hori.Ascender);
657         fm->descent = -GET_BE_WORD(tt_hori.Descender);
658         TRACE("hhea: ascent %d, descent %d\n", fm->ascent, fm->descent);
659         line_gap = GET_BE_WORD(tt_hori.LineGap);
660         fm->line_spacing = fm->ascent + fm->descent + line_gap;
661         TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing);
662         if (fm->ascent + fm->descent != 0) return TRUE;
663     }
664 
665     size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
666     if (size == GDI_ERROR) return FALSE;
667 
668     if (size > sizeof(tt_os2)) size = sizeof(tt_os2);
669 
670     memset(&tt_os2, 0, sizeof(tt_os2));
671     if (GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size) != size) return FALSE;
672 
673     fm->ascent = GET_BE_WORD(tt_os2.usWinAscent);
674     fm->descent = GET_BE_WORD(tt_os2.usWinDescent);
675     TRACE("usWinAscent %u, usWinDescent %u\n", fm->ascent, fm->descent);
676     if (fm->ascent + fm->descent == 0)
677     {
678         fm->ascent = GET_BE_WORD(tt_os2.sTypoAscender);
679         fm->descent = GET_BE_WORD(tt_os2.sTypoDescender);
680         TRACE("sTypoAscender %u, sTypoDescender %u\n", fm->ascent, fm->descent);
681     }
682     line_gap = GET_BE_WORD(tt_os2.sTypoLineGap);
683     fm->line_spacing = fm->ascent + fm->descent + line_gap;
684     TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing);
685     return TRUE;
686 }
687 
688 static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm)
689 {
690     LOGFONTW lf;
691     HDC hdc = CreateCompatibleDC(0);
692     GpStatus ret = FontFamilyNotFound;
693 
694     if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf))
695     {
696         HFONT hfont, old_font;
697 
698         strcpyW(fm->facename, lf.lfFaceName);
699 
700         hfont = CreateFontIndirectW(&lf);
701         old_font = SelectObject(hdc, hfont);
702         ret = get_font_metrics(hdc, fm) ? Ok : NotTrueTypeFont;
703         SelectObject(hdc, old_font);
704         DeleteObject(hfont);
705     }
706 
707     DeleteDC(hdc);
708     return ret;
709 }
710 
711 /*******************************************************************************
712  * GdipCreateFontFamilyFromName [GDIPLUS.@]
713  *
714  * Creates a font family object based on a supplied name
715  *
716  * PARAMS
717  *  name               [I] Name of the font
718  *  fontCollection     [I] What font collection (if any) the font belongs to (may be NULL)
719  *  FontFamily         [O] Pointer to the resulting FontFamily object
720  *
721  * RETURNS
722  *  SUCCESS: Ok
723  *  FAILURE: FamilyNotFound if the requested FontFamily does not exist on the system
724  *  FAILURE: Invalid parameter if FontFamily or name is NULL
725  *
726  * NOTES
727  *   If fontCollection is NULL then the object is not part of any collection
728  *
729  */
730 
731 GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name,
732                                         GpFontCollection *fontCollection,
733                                         GpFontFamily **FontFamily)
734 {
735     GpStatus stat;
736     GpFontFamily* ffamily;
737     struct font_metrics fm;
738 
739     TRACE("%s, %p %p\n", debugstr_w(name), fontCollection, FontFamily);
740 
741     if (!(name && FontFamily))
742         return InvalidParameter;
743     if (fontCollection)
744         FIXME("No support for FontCollections yet!\n");
745 
746     stat = find_installed_font(name, &fm);
747     if (stat != Ok) return stat;
748 
749     ffamily = heap_alloc_zero(sizeof (GpFontFamily));
750     if (!ffamily) return OutOfMemory;
751 
752     lstrcpyW(ffamily->FamilyName, fm.facename);
753     ffamily->em_height = fm.em_height;
754     ffamily->ascent = fm.ascent;
755     ffamily->descent = fm.descent;
756     ffamily->line_spacing = fm.line_spacing;
757     ffamily->dpi = fm.dpi;
758 
759     *FontFamily = ffamily;
760 
761     TRACE("<-- %p\n", ffamily);
762 
763     return Ok;
764 }
765 
766 static GpStatus clone_font_family(const GpFontFamily *family, GpFontFamily **clone)
767 {
768     *clone = heap_alloc_zero(sizeof(GpFontFamily));
769     if (!*clone) return OutOfMemory;
770 
771     **clone = *family;
772 
773     return Ok;
774 }
775 
776 /*******************************************************************************
777  * GdipCloneFontFamily [GDIPLUS.@]
778  *
779  * Creates a deep copy of a Font Family object
780  *
781  * PARAMS
782  *  FontFamily          [I] Font to clone
783  *  clonedFontFamily    [O] The resulting cloned font
784  *
785  * RETURNS
786  *  SUCCESS: Ok
787  */
788 GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily* FontFamily, GpFontFamily** clonedFontFamily)
789 {
790     GpStatus status;
791 
792     if (!(FontFamily && clonedFontFamily)) return InvalidParameter;
793 
794     TRACE("%p (%s), %p\n", FontFamily,
795             debugstr_w(FontFamily->FamilyName), clonedFontFamily);
796 
797     status = clone_font_family(FontFamily, clonedFontFamily);
798     if (status != Ok) return status;
799 
800     TRACE("<-- %p\n", *clonedFontFamily);
801 
802     return Ok;
803 }
804 
805 /*******************************************************************************
806  * GdipGetFamilyName [GDIPLUS.@]
807  *
808  * Returns the family name into name
809  *
810  * PARAMS
811  *  *family     [I] Family to retrieve from
812  *  *name       [O] WCHARS of the family name
813  *  LANGID      [I] charset
814  *
815  * RETURNS
816  *  SUCCESS: Ok
817  *  FAILURE: InvalidParameter if family is NULL
818  *
819  * NOTES
820  *   If name is a NULL ptr, then both XP and Vista will crash (so we do as well)
821  */
822 GpStatus WINGDIPAPI GdipGetFamilyName (GDIPCONST GpFontFamily *family,
823                                        WCHAR *name, LANGID language)
824 {
825     static int lang_fixme;
826 
827     if (family == NULL)
828          return InvalidParameter;
829 
830     TRACE("%p, %p, %d\n", family, name, language);
831 
832     if (language != LANG_NEUTRAL && !lang_fixme++)
833         FIXME("No support for handling of multiple languages!\n");
834 
835     lstrcpynW (name, family->FamilyName, LF_FACESIZE);
836 
837     return Ok;
838 }
839 
840 
841 /*****************************************************************************
842  * GdipDeleteFontFamily [GDIPLUS.@]
843  *
844  * Removes the specified FontFamily
845  *
846  * PARAMS
847  *  *FontFamily         [I] The family to delete
848  *
849  * RETURNS
850  *  SUCCESS: Ok
851  *  FAILURE: InvalidParameter if FontFamily is NULL.
852  *
853  */
854 GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily)
855 {
856     if (!FontFamily)
857         return InvalidParameter;
858     TRACE("Deleting %p (%s)\n", FontFamily, debugstr_w(FontFamily->FamilyName));
859 
860     heap_free (FontFamily);
861 
862     return Ok;
863 }
864 
865 GpStatus WINGDIPAPI GdipGetCellAscent(GDIPCONST GpFontFamily *family,
866         INT style, UINT16* CellAscent)
867 {
868     if (!(family && CellAscent)) return InvalidParameter;
869 
870     *CellAscent = family->ascent;
871     TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellAscent);
872 
873     return Ok;
874 }
875 
876 GpStatus WINGDIPAPI GdipGetCellDescent(GDIPCONST GpFontFamily *family,
877         INT style, UINT16* CellDescent)
878 {
879     TRACE("(%p, %d, %p)\n", family, style, CellDescent);
880 
881     if (!(family && CellDescent)) return InvalidParameter;
882 
883     *CellDescent = family->descent;
884     TRACE("%s => %u\n", debugstr_w(family->FamilyName), *CellDescent);
885 
886     return Ok;
887 }
888 
889 /*******************************************************************************
890  * GdipGetEmHeight [GDIPLUS.@]
891  *
892  * Gets the height of the specified family in EmHeights
893  *
894  * PARAMS
895  *  family      [I] Family to retrieve from
896  *  style       [I] (optional) style
897  *  EmHeight    [O] return value
898  *
899  * RETURNS
900  *  SUCCESS: Ok
901  *  FAILURE: InvalidParameter
902  */
903 GpStatus WINGDIPAPI GdipGetEmHeight(GDIPCONST GpFontFamily *family, INT style, UINT16* EmHeight)
904 {
905     if (!(family && EmHeight)) return InvalidParameter;
906 
907     TRACE("%p (%s), %d, %p\n", family, debugstr_w(family->FamilyName), style, EmHeight);
908 
909     *EmHeight = family->em_height;
910     TRACE("%s => %u\n", debugstr_w(family->FamilyName), *EmHeight);
911 
912     return Ok;
913 }
914 
915 
916 /*******************************************************************************
917  * GdipGetLineSpacing [GDIPLUS.@]
918  *
919  * Returns the line spacing in design units
920  *
921  * PARAMS
922  *  family      [I] Family to retrieve from
923  *  style       [I] (Optional) font style
924  *  LineSpacing [O] Return value
925  *
926  * RETURNS
927  *  SUCCESS: Ok
928  *  FAILURE: InvalidParameter (family or LineSpacing was NULL)
929  */
930 GpStatus WINGDIPAPI GdipGetLineSpacing(GDIPCONST GpFontFamily *family,
931         INT style, UINT16* LineSpacing)
932 {
933     TRACE("%p, %d, %p\n", family, style, LineSpacing);
934 
935     if (!(family && LineSpacing))
936         return InvalidParameter;
937 
938     if (style) FIXME("ignoring style\n");
939 
940     *LineSpacing = family->line_spacing;
941     TRACE("%s => %u\n", debugstr_w(family->FamilyName), *LineSpacing);
942 
943     return Ok;
944 }
945 
946 static INT CALLBACK font_has_style_proc(const LOGFONTW *elf,
947                             const TEXTMETRICW *ntm, DWORD type, LPARAM lParam)
948 {
949     INT fontstyle = FontStyleRegular;
950 
951     if (!ntm) return 1;
952 
953     if (ntm->tmWeight >= FW_BOLD) fontstyle |= FontStyleBold;
954     if (ntm->tmItalic) fontstyle |= FontStyleItalic;
955     if (ntm->tmUnderlined) fontstyle |= FontStyleUnderline;
956     if (ntm->tmStruckOut) fontstyle |= FontStyleStrikeout;
957 
958     return (INT)lParam != fontstyle;
959 }
960 
961 GpStatus WINGDIPAPI GdipIsStyleAvailable(GDIPCONST GpFontFamily* family,
962         INT style, BOOL* IsStyleAvailable)
963 {
964     HDC hdc;
965 
966     TRACE("%p %d %p\n", family, style, IsStyleAvailable);
967 
968     if (!(family && IsStyleAvailable))
969         return InvalidParameter;
970 
971     *IsStyleAvailable = FALSE;
972 
973     hdc = CreateCompatibleDC(0);
974 
975     if(!EnumFontFamiliesW(hdc, family->FamilyName, font_has_style_proc, (LPARAM)style))
976         *IsStyleAvailable = TRUE;
977 
978     DeleteDC(hdc);
979 
980     return Ok;
981 }
982 
983 /*****************************************************************************
984  * GdipGetGenericFontFamilyMonospace [GDIPLUS.@]
985  *
986  * Obtains a serif family (Courier New on Windows)
987  *
988  * PARAMS
989  *  **nativeFamily         [I] Where the font will be stored
990  *
991  * RETURNS
992  *  InvalidParameter if nativeFamily is NULL.
993  *  Ok otherwise.
994  */
995 GpStatus WINGDIPAPI GdipGetGenericFontFamilyMonospace(GpFontFamily **nativeFamily)
996 {
997     static const WCHAR CourierNew[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
998     static const WCHAR LiberationMono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o','\0'};
999     GpStatus stat;
1000 
1001     if (nativeFamily == NULL) return InvalidParameter;
1002 
1003     stat = GdipCreateFontFamilyFromName(CourierNew, NULL, nativeFamily);
1004 
1005     if (stat == FontFamilyNotFound)
1006         stat = GdipCreateFontFamilyFromName(LiberationMono, NULL, nativeFamily);
1007 
1008     if (stat == FontFamilyNotFound)
1009         ERR("Missing 'Courier New' font\n");
1010 
1011     return stat;
1012 }
1013 
1014 /*****************************************************************************
1015  * GdipGetGenericFontFamilySerif [GDIPLUS.@]
1016  *
1017  * Obtains a serif family (Times New Roman on Windows)
1018  *
1019  * PARAMS
1020  *  **nativeFamily         [I] Where the font will be stored
1021  *
1022  * RETURNS
1023  *  InvalidParameter if nativeFamily is NULL.
1024  *  Ok otherwise.
1025  */
1026 GpStatus WINGDIPAPI GdipGetGenericFontFamilySerif(GpFontFamily **nativeFamily)
1027 {
1028     static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
1029     static const WCHAR LiberationSerif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f','\0'};
1030     GpStatus stat;
1031 
1032     TRACE("(%p)\n", nativeFamily);
1033 
1034     if (nativeFamily == NULL) return InvalidParameter;
1035 
1036     stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, nativeFamily);
1037 
1038     if (stat == FontFamilyNotFound)
1039         stat = GdipCreateFontFamilyFromName(LiberationSerif, NULL, nativeFamily);
1040 
1041     if (stat == FontFamilyNotFound)
1042         ERR("Missing 'Times New Roman' font\n");
1043 
1044     return stat;
1045 }
1046 
1047 /*****************************************************************************
1048  * GdipGetGenericFontFamilySansSerif [GDIPLUS.@]
1049  *
1050  * Obtains a serif family (Microsoft Sans Serif on Windows)
1051  *
1052  * PARAMS
1053  *  **nativeFamily         [I] Where the font will be stored
1054  *
1055  * RETURNS
1056  *  InvalidParameter if nativeFamily is NULL.
1057  *  Ok otherwise.
1058  */
1059 GpStatus WINGDIPAPI GdipGetGenericFontFamilySansSerif(GpFontFamily **nativeFamily)
1060 {
1061     GpStatus stat;
1062     static const WCHAR MicrosoftSansSerif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
1063     static const WCHAR Tahoma[] = {'T','a','h','o','m','a','\0'};
1064 
1065     TRACE("(%p)\n", nativeFamily);
1066 
1067     if (nativeFamily == NULL) return InvalidParameter;
1068 
1069     stat = GdipCreateFontFamilyFromName(MicrosoftSansSerif, NULL, nativeFamily);
1070 
1071     if (stat == FontFamilyNotFound)
1072         /* FIXME: Microsoft Sans Serif is not installed on Wine. */
1073         stat = GdipCreateFontFamilyFromName(Tahoma, NULL, nativeFamily);
1074 
1075     return stat;
1076 }
1077 
1078 /*****************************************************************************
1079  * GdipGetGenericFontFamilySansSerif [GDIPLUS.@]
1080  */
1081 GpStatus WINGDIPAPI GdipNewPrivateFontCollection(GpFontCollection** fontCollection)
1082 {
1083     TRACE("%p\n", fontCollection);
1084 
1085     if (!fontCollection)
1086         return InvalidParameter;
1087 
1088     *fontCollection = heap_alloc_zero(sizeof(GpFontCollection));
1089     if (!*fontCollection) return OutOfMemory;
1090 
1091     (*fontCollection)->FontFamilies = NULL;
1092     (*fontCollection)->count = 0;
1093     (*fontCollection)->allocated = 0;
1094 
1095     TRACE("<-- %p\n", *fontCollection);
1096 
1097     return Ok;
1098 }
1099 
1100 /*****************************************************************************
1101  * GdipDeletePrivateFontCollection [GDIPLUS.@]
1102  */
1103 GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection **fontCollection)
1104 {
1105     INT i;
1106 
1107     TRACE("%p\n", fontCollection);
1108 
1109     if (!fontCollection)
1110         return InvalidParameter;
1111 
1112     for (i = 0; i < (*fontCollection)->count; i++) heap_free((*fontCollection)->FontFamilies[i]);
1113     heap_free(*fontCollection);
1114 
1115     return Ok;
1116 }
1117 
1118 /*****************************************************************************
1119  * GdipPrivateAddFontFile [GDIPLUS.@]
1120  */
1121 GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection *collection, GDIPCONST WCHAR *name)
1122 {
1123     HANDLE file, mapping;
1124     LARGE_INTEGER size;
1125     void *mem;
1126     GpStatus status;
1127 
1128     TRACE("%p, %s\n", collection, debugstr_w(name));
1129 
1130     if (!collection || !name) return InvalidParameter;
1131 
1132     file = CreateFileW(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1133     if (file == INVALID_HANDLE_VALUE) return InvalidParameter;
1134 
1135     if (!GetFileSizeEx(file, &size) || size.u.HighPart)
1136     {
1137         CloseHandle(file);
1138         return InvalidParameter;
1139     }
1140 
1141     mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
1142     CloseHandle(file);
1143     if (!mapping) return InvalidParameter;
1144 
1145     mem = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
1146     CloseHandle(mapping);
1147     if (!mem) return InvalidParameter;
1148 
1149     /* GdipPrivateAddMemoryFont creates a copy of the memory block */
1150     status = GdipPrivateAddMemoryFont(collection, mem, size.u.LowPart);
1151     UnmapViewOfFile(mem);
1152 
1153     return status;
1154 }
1155 
1156 #define TT_PLATFORM_APPLE_UNICODE   0
1157 #define TT_PLATFORM_MACINTOSH       1
1158 #define TT_PLATFORM_MICROSOFT       3
1159 
1160 #define TT_APPLE_ID_DEFAULT     0
1161 #define TT_APPLE_ID_ISO_10646   2
1162 #define TT_APPLE_ID_UNICODE_2_0 3
1163 
1164 #define TT_MS_ID_SYMBOL_CS  0
1165 #define TT_MS_ID_UNICODE_CS 1
1166 
1167 #define TT_MAC_ID_SIMPLIFIED_CHINESE    25
1168 
1169 #define NAME_ID_FULL_FONT_NAME  4
1170 
1171 typedef struct {
1172     USHORT major_version;
1173     USHORT minor_version;
1174     USHORT tables_no;
1175     USHORT search_range;
1176     USHORT entry_selector;
1177     USHORT range_shift;
1178 } tt_header;
1179 
1180 typedef struct {
1181     char tag[4];        /* table name */
1182     ULONG check_sum;    /* Check sum */
1183     ULONG offset;       /* Offset from beginning of file */
1184     ULONG length;       /* length of the table in bytes */
1185 } tt_table_directory;
1186 
1187 typedef struct {
1188     USHORT format;          /* format selector. Always 0 */
1189     USHORT count;           /* Name Records count */
1190     USHORT string_offset;   /* Offset for strings storage, * from start of the table */
1191 } tt_name_table;
1192 
1193 typedef struct {
1194     USHORT platform_id;
1195     USHORT encoding_id;
1196     USHORT language_id;
1197     USHORT name_id;
1198     USHORT length;
1199     USHORT offset;      /* from start of storage area */
1200 } tt_name_record;
1201 
1202 /* Copied from gdi32/freetype.c */
1203 
1204 static const LANGID mac_langid_table[] =
1205 {
1206     MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_ENGLISH */
1207     MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_FRENCH */
1208     MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_GERMAN */
1209     MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_ITALIAN */
1210     MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_DUTCH */
1211     MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_SWEDISH */
1212     MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_SPANISH */
1213     MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_DANISH */
1214     MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT),             /* TT_MAC_LANGID_PORTUGUESE */
1215     MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_NORWEGIAN */
1216     MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_HEBREW */
1217     MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_JAPANESE */
1218     MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_ARABIC */
1219     MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_FINNISH */
1220     MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_GREEK */
1221     MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_ICELANDIC */
1222     MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_MALTESE */
1223     MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_TURKISH */
1224     MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_CROATIAN */
1225     MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT),    /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1226     MAKELANGID(LANG_URDU,SUBLANG_DEFAULT),                   /* TT_MAC_LANGID_URDU */
1227     MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_HINDI */
1228     MAKELANGID(LANG_THAI,SUBLANG_DEFAULT),                   /* TT_MAC_LANGID_THAI */
1229     MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_KOREAN */
1230     MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT),             /* TT_MAC_LANGID_LITHUANIAN */
1231     MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_POLISH */
1232     MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_HUNGARIAN */
1233     MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_ESTONIAN */
1234     MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_LETTISH */
1235     MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT),                   /* TT_MAC_LANGID_SAAMISK */
1236     MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_FAEROESE */
1237     MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_FARSI */
1238     MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_RUSSIAN */
1239     MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT),     /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1240     MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN),            /* TT_MAC_LANGID_FLEMISH */
1241     MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_IRISH */
1242     MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_ALBANIAN */
1243     MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_ROMANIAN */
1244     MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_CZECH */
1245     MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_SLOVAK */
1246     MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_SLOVENIAN */
1247     0,                                                       /* TT_MAC_LANGID_YIDDISH */
1248     MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_SERBIAN */
1249     MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT),             /* TT_MAC_LANGID_MACEDONIAN */
1250     MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_BULGARIAN */
1251     MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_UKRAINIAN */
1252     MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT),             /* TT_MAC_LANGID_BYELORUSSIAN */
1253     MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_UZBEK */
1254     MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_KAZAKH */
1255     MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC),           /* TT_MAC_LANGID_AZERBAIJANI */
1256     0,                                                       /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1257     MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_ARMENIAN */
1258     MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_GEORGIAN */
1259     0,                                                       /* TT_MAC_LANGID_MOLDAVIAN */
1260     MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_KIRGHIZ */
1261     MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_TAJIKI */
1262     MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_TURKMEN */
1263     MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_MONGOLIAN */
1264     MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1265     MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_PASHTO */
1266     0,                                                       /* TT_MAC_LANGID_KURDISH */
1267     MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_KASHMIRI */
1268     MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_SINDHI */
1269     MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_TIBETAN */
1270     MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_NEPALI */
1271     MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_SANSKRIT */
1272     MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_MARATHI */
1273     MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_BENGALI */
1274     MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_ASSAMESE */
1275     MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_GUJARATI */
1276     MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_PUNJABI */
1277     MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_ORIYA */
1278     MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_MALAYALAM */
1279     MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_KANNADA */
1280     MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_TAMIL */
1281     MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_TELUGU */
1282     MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_SINHALESE */
1283     0,                                                       /* TT_MAC_LANGID_BURMESE */
1284     MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_KHMER */
1285     MAKELANGID(LANG_LAO,SUBLANG_DEFAULT),                    /* TT_MAC_LANGID_LAO */
1286     MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT),             /* TT_MAC_LANGID_VIETNAMESE */
1287     MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT),             /* TT_MAC_LANGID_INDONESIAN */
1288     0,                                                       /* TT_MAC_LANGID_TAGALOG */
1289     MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1290     0,                                                       /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1291     MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_AMHARIC */
1292     MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_TIGRINYA */
1293     0,                                                       /* TT_MAC_LANGID_GALLA */
1294     0,                                                       /* TT_MAC_LANGID_SOMALI */
1295     MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_SWAHILI */
1296     0,                                                       /* TT_MAC_LANGID_RUANDA */
1297     0,                                                       /* TT_MAC_LANGID_RUNDI */
1298     0,                                                       /* TT_MAC_LANGID_CHEWA */
1299     MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_MALAGASY */
1300     MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_ESPERANTO */
1301     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* 95-111 */
1302     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,          /* 112-127 */
1303     MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_WELSH */
1304     MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_BASQUE */
1305     MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_CATALAN */
1306     0,                                                       /* TT_MAC_LANGID_LATIN */
1307     MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT),                /* TT_MAC_LANGID_QUECHUA */
1308     0,                                                       /* TT_MAC_LANGID_GUARANI */
1309     0,                                                       /* TT_MAC_LANGID_AYMARA */
1310     MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT),                  /* TT_MAC_LANGID_TATAR */
1311     MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_UIGHUR */
1312     0,                                                       /* TT_MAC_LANGID_DZONGKHA */
1313     0,                                                       /* TT_MAC_LANGID_JAVANESE */
1314     0,                                                       /* TT_MAC_LANGID_SUNDANESE */
1315     MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT),               /* TT_MAC_LANGID_GALICIAN */
1316     MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_AFRIKAANS */
1317     MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT),                 /* TT_MAC_LANGID_BRETON */
1318     MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT),              /* TT_MAC_LANGID_INUKTITUT */
1319     MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT),        /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1320     MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT),            /* TT_MAC_LANGID_MANX_GAELIC */
1321     MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND),            /* TT_MAC_LANGID_IRISH_GAELIC */
1322     0,                                                       /* TT_MAC_LANGID_TONGAN */
1323     0,                                                       /* TT_MAC_LANGID_GREEK_POLYTONIC */
1324     MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT),            /* TT_MAC_LANGID_GREELANDIC */
1325     MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN),              /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1326 };
1327 
1328 static inline WORD get_mac_code_page( const tt_name_record *name )
1329 {
1330     WORD encoding_id = GET_BE_WORD(name->encoding_id);
1331     if (encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008;  /* special case */
1332     return 10000 + encoding_id;
1333 }
1334 
1335 static int match_name_table_language( const tt_name_record *name, LANGID lang )
1336 {
1337     LANGID name_lang;
1338 
1339     switch (GET_BE_WORD(name->platform_id))
1340     {
1341     case TT_PLATFORM_MICROSOFT:
1342         switch (GET_BE_WORD(name->encoding_id))
1343         {
1344         case TT_MS_ID_UNICODE_CS:
1345         case TT_MS_ID_SYMBOL_CS:
1346             name_lang = GET_BE_WORD(name->language_id);
1347             break;
1348         default:
1349             return 0;
1350         }
1351         break;
1352     case TT_PLATFORM_MACINTOSH:
1353         if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1354         name_lang = GET_BE_WORD(name->language_id);
1355         if (name_lang >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1356         name_lang = mac_langid_table[name_lang];
1357         break;
1358     case TT_PLATFORM_APPLE_UNICODE:
1359         switch (GET_BE_WORD(name->encoding_id))
1360         {
1361         case TT_APPLE_ID_DEFAULT:
1362         case TT_APPLE_ID_ISO_10646:
1363         case TT_APPLE_ID_UNICODE_2_0:
1364             name_lang = GET_BE_WORD(name->language_id);
1365             if (name_lang >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1366             name_lang = mac_langid_table[name_lang];
1367             break;
1368         default:
1369             return 0;
1370         }
1371         break;
1372     default:
1373         return 0;
1374     }
1375     if (name_lang == lang) return 3;
1376     if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) return 2;
1377     if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) return 1;
1378     return 0;
1379 }
1380 
1381 static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *data )
1382 {
1383     WORD name_len = GET_BE_WORD(name->length);
1384     WORD codepage;
1385     WCHAR *ret;
1386     int len;
1387 
1388     switch (GET_BE_WORD(name->platform_id))
1389     {
1390     case TT_PLATFORM_APPLE_UNICODE:
1391     case TT_PLATFORM_MICROSOFT:
1392         ret = heap_alloc((name_len / 2 + 1) * sizeof(WCHAR));
1393         for (len = 0; len < name_len / 2; len++)
1394             ret[len] = (data[len * 2] << 8) | data[len * 2 + 1];
1395         ret[len] = 0;
1396         return ret;
1397     case TT_PLATFORM_MACINTOSH:
1398         codepage = get_mac_code_page( name );
1399         len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, NULL, 0 ) + 1;
1400         if (!len)
1401             return NULL;
1402         ret = heap_alloc(len * sizeof(WCHAR));
1403         len = MultiByteToWideChar( codepage, 0, (char *)data, name_len, ret, len - 1 );
1404         ret[len] = 0;
1405         return ret;
1406     }
1407     return NULL;
1408 }
1409 
1410 static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id )
1411 {
1412     LANGID lang = GetSystemDefaultLangID();
1413     const tt_header *header;
1414     const tt_name_table *name_table;
1415     const tt_name_record *name_record;
1416     DWORD pos, ofs, count;
1417     int i, res, best_lang = 0, best_index = -1;
1418 
1419     if (sizeof(tt_header) > size)
1420         return NULL;
1421     header = (const tt_header*)mem;
1422     count = GET_BE_WORD(header->tables_no);
1423 
1424     if (GET_BE_WORD(header->major_version) != 1 || GET_BE_WORD(header->minor_version) != 0)
1425         return NULL;
1426 
1427     pos = sizeof(*header);
1428     for (i = 0; i < count; i++)
1429     {
1430         const tt_table_directory *table_directory = (const tt_table_directory*)&mem[pos];
1431         pos += sizeof(*table_directory);
1432         if (memcmp(table_directory->tag, "name", 4) == 0)
1433         {
1434             ofs = GET_BE_DWORD(table_directory->offset);
1435             break;
1436         }
1437     }
1438     if (i >= count)
1439         return NULL;
1440 
1441     if (ofs >= size)
1442         return NULL;
1443     pos = ofs + sizeof(*name_table);
1444     if (pos > size)
1445         return NULL;
1446     name_table = (const tt_name_table*)&mem[ofs];
1447     count =  GET_BE_WORD(name_table->count);
1448     if (GET_BE_WORD(name_table->string_offset) >= size - ofs) return NULL;
1449     ofs += GET_BE_WORD(name_table->string_offset);
1450     for (i=0; i<count; i++)
1451     {
1452         name_record = (const tt_name_record*)&mem[pos];
1453         pos += sizeof(*name_record);
1454         if (pos > size)
1455             return NULL;
1456 
1457         if (GET_BE_WORD(name_record->name_id) != id) continue;
1458         if (GET_BE_WORD(name_record->offset) >= size - ofs) return NULL;
1459         if (GET_BE_WORD(name_record->length) > size - ofs - GET_BE_WORD(name_record->offset)) return NULL;
1460 
1461         res = match_name_table_language( name_record, lang );
1462         if (res > best_lang)
1463         {
1464             best_lang = res;
1465             best_index = i;
1466         }
1467     }
1468 
1469     if (best_lang)
1470     {
1471         WCHAR *ret;
1472         name_record = (const tt_name_record*)(name_table + 1) + best_index;
1473         ret = copy_name_table_string( name_record, mem+ofs+GET_BE_WORD(name_record->offset) );
1474         TRACE( "name %u found platform %u lang %04x %s\n", GET_BE_WORD(name_record->name_id),
1475                 GET_BE_WORD(name_record->platform_id), GET_BE_WORD(name_record->language_id), debugstr_w( ret ));
1476         return ret;
1477     }
1478     return NULL;
1479 }
1480 
1481 static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam);
1482 
1483 /*****************************************************************************
1484  * GdipPrivateAddMemoryFont [GDIPLUS.@]
1485  */
1486 GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection,
1487         GDIPCONST void* memory, INT length)
1488 {
1489     WCHAR *name;
1490     DWORD count = 0;
1491     HANDLE font;
1492     GpStatus ret = Ok;
1493     TRACE("%p, %p, %d\n", fontCollection, memory, length);
1494 
1495     if (!fontCollection || !memory || !length)
1496         return InvalidParameter;
1497 
1498     name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME);
1499     if (!name)
1500         return OutOfMemory;
1501 
1502     font = AddFontMemResourceEx((void*)memory, length, NULL, &count);
1503     TRACE("%s: %p/%u\n", debugstr_w(name), font, count);
1504     if (!font || !count)
1505         ret = InvalidParameter;
1506     else
1507     {
1508         HDC hdc;
1509         LOGFONTW lfw;
1510 
1511         hdc = CreateCompatibleDC(0);
1512 
1513         /* Truncate name if necessary, GDI32 can't deal with long names */
1514         if(lstrlenW(name) > LF_FACESIZE - 1)
1515             name[LF_FACESIZE - 1] = 0;
1516 
1517         lfw.lfCharSet = DEFAULT_CHARSET;
1518         lstrcpyW(lfw.lfFaceName, name);
1519         lfw.lfPitchAndFamily = 0;
1520 
1521         if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)fontCollection, 0))
1522             ret = OutOfMemory;
1523 
1524         DeleteDC(hdc);
1525     }
1526     heap_free(name);
1527     return ret;
1528 }
1529 
1530 /*****************************************************************************
1531  * GdipGetFontCollectionFamilyCount [GDIPLUS.@]
1532  */
1533 GpStatus WINGDIPAPI GdipGetFontCollectionFamilyCount(
1534         GpFontCollection* fontCollection, INT* numFound)
1535 {
1536     TRACE("%p, %p\n", fontCollection, numFound);
1537 
1538     if (!(fontCollection && numFound))
1539         return InvalidParameter;
1540 
1541     *numFound = fontCollection->count;
1542     return Ok;
1543 }
1544 
1545 /*****************************************************************************
1546  * GdipGetFontCollectionFamilyList [GDIPLUS.@]
1547  */
1548 GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList(
1549         GpFontCollection* fontCollection, INT numSought,
1550         GpFontFamily* gpfamilies[], INT* numFound)
1551 {
1552     INT i;
1553     GpStatus stat=Ok;
1554 
1555     TRACE("%p, %d, %p, %p\n", fontCollection, numSought, gpfamilies, numFound);
1556 
1557     if (!(fontCollection && gpfamilies && numFound))
1558         return InvalidParameter;
1559 
1560     memset(gpfamilies, 0, sizeof(*gpfamilies) * numSought);
1561 
1562     for (i = 0; i < numSought && i < fontCollection->count && stat == Ok; i++)
1563     {
1564         stat = GdipCloneFontFamily(fontCollection->FontFamilies[i], &gpfamilies[i]);
1565     }
1566 
1567     if (stat == Ok)
1568         *numFound = i;
1569     else
1570     {
1571         int numToFree=i;
1572         for (i=0; i<numToFree; i++)
1573         {
1574             GdipDeleteFontFamily(gpfamilies[i]);
1575             gpfamilies[i] = NULL;
1576         }
1577     }
1578 
1579     return stat;
1580 }
1581 
1582 void free_installed_fonts(void)
1583 {
1584     while (installedFontCollection.count)
1585         GdipDeleteFontFamily(installedFontCollection.FontFamilies[--installedFontCollection.count]);
1586     heap_free(installedFontCollection.FontFamilies);
1587     installedFontCollection.FontFamilies = NULL;
1588     installedFontCollection.allocated = 0;
1589 }
1590 
1591 static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm,
1592         DWORD type, LPARAM lParam)
1593 {
1594     GpFontCollection* fonts = (GpFontCollection*)lParam;
1595     GpFontFamily* family;
1596     int i;
1597 
1598     if (type == RASTER_FONTTYPE)
1599         return 1;
1600 
1601     /* skip rotated fonts */
1602     if (lfw->lfFaceName[0] == '@')
1603         return 1;
1604 
1605     if (fonts->count && strcmpiW(lfw->lfFaceName, fonts->FontFamilies[fonts->count-1]->FamilyName) == 0)
1606         return 1;
1607 
1608     if (fonts->allocated == fonts->count)
1609     {
1610         INT new_alloc_count = fonts->allocated+50;
1611         GpFontFamily** new_family_list = heap_alloc(new_alloc_count*sizeof(void*));
1612 
1613         if (!new_family_list)
1614             return 0;
1615 
1616         memcpy(new_family_list, fonts->FontFamilies, fonts->count*sizeof(void*));
1617         heap_free(fonts->FontFamilies);
1618         fonts->FontFamilies = new_family_list;
1619         fonts->allocated = new_alloc_count;
1620     }
1621 
1622     if (GdipCreateFontFamilyFromName(lfw->lfFaceName, NULL, &family) != Ok)
1623         return 0;
1624 
1625     /* skip duplicates */
1626     for (i=0; i<fonts->count; i++)
1627     {
1628         if (strcmpiW(family->FamilyName, fonts->FontFamilies[i]->FamilyName) == 0)
1629         {
1630             GdipDeleteFontFamily(family);
1631             return 1;
1632         }
1633     }
1634 
1635     fonts->FontFamilies[fonts->count++] = family;
1636 
1637     return 1;
1638 }
1639 
1640 GpStatus WINGDIPAPI GdipNewInstalledFontCollection(
1641         GpFontCollection** fontCollection)
1642 {
1643     TRACE("(%p)\n",fontCollection);
1644 
1645     if (!fontCollection)
1646         return InvalidParameter;
1647 
1648     if (installedFontCollection.count == 0)
1649     {
1650         HDC hdc;
1651         LOGFONTW lfw;
1652 
1653         hdc = CreateCompatibleDC(0);
1654 
1655         lfw.lfCharSet = DEFAULT_CHARSET;
1656         lfw.lfFaceName[0] = 0;
1657         lfw.lfPitchAndFamily = 0;
1658 
1659         if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)&installedFontCollection, 0))
1660         {
1661             free_installed_fonts();
1662             DeleteDC(hdc);
1663             return OutOfMemory;
1664         }
1665 
1666         DeleteDC(hdc);
1667     }
1668 
1669     *fontCollection = &installedFontCollection;
1670 
1671     return Ok;
1672 }
1673