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