2 * Copyright (C) 2007 Google (Evan Stade)
3 * Copyright (C) 2012 Dmitry Timoshkov
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.
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.
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
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL (gdiplus
);
35 #include "gdiplus_private.h"
37 static const REAL mm_per_inch
= 25.4;
38 static const REAL inch_per_point
= 1.0/72.0;
40 static GpFontCollection installedFontCollection
= {0};
42 static inline REAL
get_dpi (void)
47 GdipCreateFromHDC (hdc
, &graphics
);
48 GdipGetDpiX(graphics
, &dpi
);
49 GdipDeleteGraphics(graphics
);
55 static inline REAL
point_to_pixel (REAL point
)
57 return point
* get_dpi() * inch_per_point
;
60 static inline REAL
inch_to_pixel (REAL inch
)
62 return inch
* get_dpi();
65 static inline REAL
document_to_pixel (REAL doc
)
67 return doc
* (get_dpi() / 300.0); /* Per MSDN */
70 static inline REAL
mm_to_pixel (REAL mm
)
72 return mm
* (get_dpi() / mm_per_inch
);
75 /*******************************************************************************
76 * GdipCreateFont [GDIPLUS.@]
78 * Create a new font based off of a FontFamily
81 * *fontFamily [I] Family to base the font off of
82 * emSize [I] Size of the font
83 * style [I] Bitwise OR of FontStyle enumeration
84 * unit [I] Unit emSize is measured in
85 * **font [I] the resulting Font object
89 * FAILURE: InvalidParameter if fontfamily or font is NULL.
90 * FAILURE: FontFamilyNotFound if an invalid FontFamily is given
93 * UnitDisplay is unsupported.
94 * emSize is stored separately from lfHeight, to hold the fraction.
96 GpStatus WINGDIPAPI
GdipCreateFont(GDIPCONST GpFontFamily
*fontFamily
,
97 REAL emSize
, INT style
, Unit unit
, GpFont
**font
)
99 WCHAR facename
[LF_FACESIZE
];
101 const OUTLINETEXTMETRICW
*otm
;
104 if (!fontFamily
|| !font
)
105 return InvalidParameter
;
107 TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily
,
108 debugstr_w(fontFamily
->FamilyName
), emSize
, style
, unit
, font
);
110 stat
= GdipGetFamilyName (fontFamily
, facename
, 0);
111 if (stat
!= Ok
) return stat
;
112 *font
= GdipAlloc(sizeof(GpFont
));
114 otm
= &fontFamily
->otm
;
115 lfw
= &((*font
)->lfw
);
116 ZeroMemory(&(*lfw
), sizeof(*lfw
));
118 lfw
->lfWeight
= otm
->otmTextMetrics
.tmWeight
;
119 lfw
->lfItalic
= otm
->otmTextMetrics
.tmItalic
;
120 lfw
->lfUnderline
= otm
->otmTextMetrics
.tmUnderlined
;
121 lfw
->lfStrikeOut
= otm
->otmTextMetrics
.tmStruckOut
;
122 lfw
->lfCharSet
= otm
->otmTextMetrics
.tmCharSet
;
123 lfw
->lfPitchAndFamily
= otm
->otmTextMetrics
.tmPitchAndFamily
;
124 lstrcpynW(lfw
->lfFaceName
, facename
, LF_FACESIZE
);
129 /* FIXME: Figure out when World != Pixel */
130 (*font
)->pixel_size
= emSize
; break;
132 FIXME("Unknown behavior for UnitDisplay! Please report!\n");
133 /* FIXME: Figure out how this works...
134 * MSDN says that if "DISPLAY" is a monitor, then pixel should be
135 * used. That's not what I got. Tests on Windows revealed no output,
136 * and the tests in tests/font crash windows */
137 (*font
)->pixel_size
= 0; break;
139 (*font
)->pixel_size
= emSize
; break;
141 (*font
)->pixel_size
= point_to_pixel(emSize
); break;
143 (*font
)->pixel_size
= inch_to_pixel(emSize
); break;
145 (*font
)->pixel_size
= document_to_pixel(emSize
); break;
147 (*font
)->pixel_size
= mm_to_pixel(emSize
); break;
150 lfw
->lfHeight
= (*font
)->pixel_size
* -1;
152 lfw
->lfWeight
= style
& FontStyleBold
? FW_BOLD
: FW_REGULAR
;
153 lfw
->lfItalic
= style
& FontStyleItalic
;
154 lfw
->lfUnderline
= style
& FontStyleUnderline
;
155 lfw
->lfStrikeOut
= style
& FontStyleStrikeout
;
157 (*font
)->unit
= unit
;
158 (*font
)->emSize
= emSize
;
159 (*font
)->height
= otm
->otmEMSquare
;
160 (*font
)->line_spacing
= otm
->otmTextMetrics
.tmAscent
+ otm
->otmTextMetrics
.tmDescent
+ otm
->otmTextMetrics
.tmExternalLeading
;
162 stat
= GdipCloneFontFamily((GpFontFamily
*)fontFamily
, &(*font
)->family
);
169 TRACE("<-- %p\n", *font
);
174 /*******************************************************************************
175 * GdipCreateFontFromLogfontW [GDIPLUS.@]
177 GpStatus WINGDIPAPI
GdipCreateFontFromLogfontW(HDC hdc
,
178 GDIPCONST LOGFONTW
*logfont
, GpFont
**font
)
180 HFONT hfont
, oldfont
;
184 TRACE("(%p, %p, %p)\n", hdc
, logfont
, font
);
186 if(!logfont
|| !font
)
187 return InvalidParameter
;
189 if (logfont
->lfFaceName
[0] == 0)
190 return NotTrueTypeFont
;
192 *font
= GdipAlloc(sizeof(GpFont
));
193 if(!*font
) return OutOfMemory
;
195 memcpy((*font
)->lfw
.lfFaceName
, logfont
->lfFaceName
, LF_FACESIZE
*
197 (*font
)->lfw
.lfHeight
= logfont
->lfHeight
;
198 (*font
)->lfw
.lfItalic
= logfont
->lfItalic
;
199 (*font
)->lfw
.lfUnderline
= logfont
->lfUnderline
;
200 (*font
)->lfw
.lfStrikeOut
= logfont
->lfStrikeOut
;
202 hfont
= CreateFontIndirectW(&(*font
)->lfw
);
203 oldfont
= SelectObject(hdc
, hfont
);
204 GetTextMetricsW(hdc
, &textmet
);
206 (*font
)->lfw
.lfHeight
= -(textmet
.tmHeight
-textmet
.tmInternalLeading
);
207 (*font
)->lfw
.lfWeight
= textmet
.tmWeight
;
208 (*font
)->lfw
.lfCharSet
= textmet
.tmCharSet
;
210 (*font
)->pixel_size
= (*font
)->emSize
= textmet
.tmHeight
;
211 (*font
)->unit
= UnitPixel
;
212 (*font
)->height
= 1; /* FIXME: need NEWTEXTMETRIC.ntmSizeEM here */
213 (*font
)->line_spacing
= textmet
.tmAscent
+ textmet
.tmDescent
+ textmet
.tmExternalLeading
;
215 SelectObject(hdc
, oldfont
);
218 stat
= GdipCreateFontFamilyFromName(logfont
->lfFaceName
, NULL
, &(*font
)->family
);
222 return NotTrueTypeFont
;
225 TRACE("<-- %p\n", *font
);
230 /*******************************************************************************
231 * GdipCreateFontFromLogfontA [GDIPLUS.@]
233 GpStatus WINGDIPAPI
GdipCreateFontFromLogfontA(HDC hdc
,
234 GDIPCONST LOGFONTA
*lfa
, GpFont
**font
)
238 TRACE("(%p, %p, %p)\n", hdc
, lfa
, font
);
241 return InvalidParameter
;
243 memcpy(&lfw
, lfa
, FIELD_OFFSET(LOGFONTA
,lfFaceName
) );
245 if(!MultiByteToWideChar(CP_ACP
, 0, lfa
->lfFaceName
, -1, lfw
.lfFaceName
, LF_FACESIZE
))
248 return GdipCreateFontFromLogfontW(hdc
, &lfw
, font
);
251 /*******************************************************************************
252 * GdipDeleteFont [GDIPLUS.@]
254 GpStatus WINGDIPAPI
GdipDeleteFont(GpFont
* font
)
256 TRACE("(%p)\n", font
);
259 return InvalidParameter
;
261 GdipDeleteFontFamily(font
->family
);
267 /*******************************************************************************
268 * GdipCreateFontFromDC [GDIPLUS.@]
270 GpStatus WINGDIPAPI
GdipCreateFontFromDC(HDC hdc
, GpFont
**font
)
275 TRACE("(%p, %p)\n", hdc
, font
);
278 return InvalidParameter
;
280 hfont
= GetCurrentObject(hdc
, OBJ_FONT
);
284 if(!GetObjectW(hfont
, sizeof(LOGFONTW
), &lfw
))
287 return GdipCreateFontFromLogfontW(hdc
, &lfw
, font
);
290 /*******************************************************************************
291 * GdipGetFamily [GDIPLUS.@]
293 * Returns the FontFamily for the specified Font
296 * font [I] Font to request from
297 * family [O] Resulting FontFamily object
301 * FAILURE: An element of GpStatus
303 GpStatus WINGDIPAPI
GdipGetFamily(GpFont
*font
, GpFontFamily
**family
)
305 TRACE("%p %p\n", font
, family
);
307 if (!(font
&& family
))
308 return InvalidParameter
;
310 return GdipCloneFontFamily(font
->family
, family
);
313 /******************************************************************************
314 * GdipGetFontSize [GDIPLUS.@]
316 * Returns the size of the font in Units
319 * *font [I] The font to retrieve size from
320 * *size [O] Pointer to hold retrieved value
324 * FAILURE: InvalidParameter (font or size was NULL)
327 * Size returned is actually emSize -- not internal size used for drawing.
329 GpStatus WINGDIPAPI
GdipGetFontSize(GpFont
*font
, REAL
*size
)
331 TRACE("(%p, %p)\n", font
, size
);
333 if (!(font
&& size
)) return InvalidParameter
;
335 *size
= font
->emSize
;
336 TRACE("%s,%d => %f\n", debugstr_w(font
->lfw
.lfFaceName
), font
->lfw
.lfHeight
, *size
);
341 /*******************************************************************************
342 * GdipGetFontStyle [GDIPLUS.@]
344 * Gets the font's style, returned in bitwise OR of FontStyle enumeration
347 * font [I] font to request from
348 * style [O] resulting pointer to a FontStyle enumeration
352 * FAILURE: InvalidParameter
354 GpStatus WINGDIPAPI
GdipGetFontStyle(GpFont
*font
, INT
*style
)
356 TRACE("%p %p\n", font
, style
);
358 if (!(font
&& style
))
359 return InvalidParameter
;
361 if (font
->lfw
.lfWeight
> FW_REGULAR
)
362 *style
= FontStyleBold
;
364 *style
= FontStyleRegular
;
365 if (font
->lfw
.lfItalic
)
366 *style
|= FontStyleItalic
;
367 if (font
->lfw
.lfUnderline
)
368 *style
|= FontStyleUnderline
;
369 if (font
->lfw
.lfStrikeOut
)
370 *style
|= FontStyleStrikeout
;
375 /*******************************************************************************
376 * GdipGetFontUnit [GDIPLUS.@]
379 * font [I] Font to retrieve from
380 * unit [O] Return value
383 * FAILURE: font or unit was NULL
386 GpStatus WINGDIPAPI
GdipGetFontUnit(GpFont
*font
, Unit
*unit
)
388 TRACE("(%p, %p)\n", font
, unit
);
390 if (!(font
&& unit
)) return InvalidParameter
;
393 TRACE("%s,%d => %d\n", debugstr_w(font
->lfw
.lfFaceName
), font
->lfw
.lfHeight
, *unit
);
398 /*******************************************************************************
399 * GdipGetLogFontA [GDIPLUS.@]
401 GpStatus WINGDIPAPI
GdipGetLogFontA(GpFont
*font
, GpGraphics
*graphics
,
407 TRACE("(%p, %p, %p)\n", font
, graphics
, lfa
);
409 status
= GdipGetLogFontW(font
, graphics
, &lfw
);
413 memcpy(lfa
, &lfw
, FIELD_OFFSET(LOGFONTA
,lfFaceName
) );
415 if(!WideCharToMultiByte(CP_ACP
, 0, lfw
.lfFaceName
, -1, lfa
->lfFaceName
, LF_FACESIZE
, NULL
, NULL
))
421 /*******************************************************************************
422 * GdipGetLogFontW [GDIPLUS.@]
424 GpStatus WINGDIPAPI
GdipGetLogFontW(GpFont
*font
, GpGraphics
*graphics
,
427 TRACE("(%p, %p, %p)\n", font
, graphics
, lfw
);
429 /* FIXME: use graphics */
430 if(!font
|| !graphics
|| !lfw
)
431 return InvalidParameter
;
434 TRACE("=> %s,%d\n", debugstr_w(font
->lfw
.lfFaceName
), font
->lfw
.lfHeight
);
439 /*******************************************************************************
440 * GdipCloneFont [GDIPLUS.@]
442 GpStatus WINGDIPAPI
GdipCloneFont(GpFont
*font
, GpFont
**cloneFont
)
446 TRACE("(%p, %p)\n", font
, cloneFont
);
448 if(!font
|| !cloneFont
)
449 return InvalidParameter
;
451 *cloneFont
= GdipAlloc(sizeof(GpFont
));
452 if(!*cloneFont
) return OutOfMemory
;
455 stat
= GdipCloneFontFamily(font
->family
, &(*cloneFont
)->family
);
456 if (stat
!= Ok
) GdipFree(*cloneFont
);
461 /*******************************************************************************
462 * GdipGetFontHeight [GDIPLUS.@]
464 * font [I] Font to retrieve height from
465 * graphics [I] The current graphics context
466 * height [O] Resulting height
469 * FAILURE: Another element of GpStatus
472 * Forwards to GdipGetFontHeightGivenDPI
474 GpStatus WINGDIPAPI
GdipGetFontHeight(GDIPCONST GpFont
*font
,
475 GDIPCONST GpGraphics
*graphics
, REAL
*height
)
480 TRACE("%p %p %p\n", font
, graphics
, height
);
482 stat
= GdipGetDpiY((GpGraphics
*)graphics
, &dpi
);
485 stat
= GdipGetFontHeightGivenDPI(font
, dpi
, height
);
490 /*******************************************************************************
491 * GdipGetFontHeightGivenDPI [GDIPLUS.@]
493 * font [I] Font to retrieve DPI from
494 * dpi [I] DPI to assume
495 * height [O] Return value
499 * FAILURE: InvalidParameter if font or height is NULL
502 * According to MSDN, the result is (lineSpacing)*(fontSize / emHeight)*dpi
503 * (for anything other than unit Pixel)
505 GpStatus WINGDIPAPI
GdipGetFontHeightGivenDPI(GDIPCONST GpFont
*font
, REAL dpi
, REAL
*height
)
509 UINT16 line_spacing
, em_height
;
510 REAL font_height
, font_size
;
512 if (!font
|| !height
) return InvalidParameter
;
514 TRACE("%p (%s), %f, %p\n", font
,
515 debugstr_w(font
->family
->FamilyName
), dpi
, height
);
517 stat
= GdipGetFontSize((GpFont
*)font
, &font_size
);
518 if (stat
!= Ok
) return stat
;
519 stat
= GdipGetFontStyle((GpFont
*)font
, &style
);
520 if (stat
!= Ok
) return stat
;
521 stat
= GdipGetLineSpacing(font
->family
, style
, &line_spacing
);
522 if (stat
!= Ok
) return stat
;
523 stat
= GdipGetEmHeight(font
->family
, style
, &em_height
);
524 if (stat
!= Ok
) return stat
;
526 font_height
= (REAL
)line_spacing
* font_size
/ (REAL
)em_height
;
532 *height
= font_height
;
535 *height
= font_height
* dpi
* inch_per_point
;
538 *height
= font_height
* dpi
;
541 *height
= font_height
* (dpi
/ 300.0);
544 *height
= font_height
* (dpi
/ mm_per_inch
);
547 FIXME("Unhandled unit type: %d\n", font
->unit
);
548 return NotImplemented
;
551 TRACE("%s,%d(unit %d) => %f\n",
552 debugstr_w(font
->lfw
.lfFaceName
), font
->lfw
.lfHeight
, font
->unit
, *height
);
557 /***********************************************************************
558 * Borrowed from GDI32:
560 * Elf is really an ENUMLOGFONTEXW, and ntm is a NEWTEXTMETRICEXW.
561 * We have to use other types because of the FONTENUMPROCW definition.
563 static INT CALLBACK
is_font_installed_proc(const LOGFONTW
*elf
,
564 const TEXTMETRICW
*ntm
, DWORD type
, LPARAM lParam
)
566 if (!ntm
|| type
== RASTER_FONTTYPE
)
571 *(LOGFONTW
*)lParam
= *elf
;
576 static BOOL
find_installed_font(const WCHAR
*name
, OUTLINETEXTMETRICW
*otm
)
579 HDC hdc
= CreateCompatibleDC(0);
582 if(!EnumFontFamiliesW(hdc
, name
, is_font_installed_proc
, (LPARAM
)&lf
))
587 hfont
= CreateFontIndirectW(&lf
);
588 hfont
= SelectObject(hdc
, hfont
);
590 otm
->otmSize
= sizeof(*otm
);
591 if (GetOutlineTextMetricsW(hdc
, otm
->otmSize
, otm
))
594 DeleteObject(SelectObject(hdc
, hfont
));
601 /*******************************************************************************
602 * GdipCreateFontFamilyFromName [GDIPLUS.@]
604 * Creates a font family object based on a supplied name
607 * name [I] Name of the font
608 * fontCollection [I] What font collection (if any) the font belongs to (may be NULL)
609 * FontFamily [O] Pointer to the resulting FontFamily object
613 * FAILURE: FamilyNotFound if the requested FontFamily does not exist on the system
614 * FAILURE: Invalid parameter if FontFamily or name is NULL
617 * If fontCollection is NULL then the object is not part of any collection
621 GpStatus WINGDIPAPI
GdipCreateFontFamilyFromName(GDIPCONST WCHAR
*name
,
622 GpFontCollection
*fontCollection
,
623 GpFontFamily
**FontFamily
)
625 GpFontFamily
* ffamily
;
626 OUTLINETEXTMETRICW otm
;
628 TRACE("%s, %p %p\n", debugstr_w(name
), fontCollection
, FontFamily
);
630 if (!(name
&& FontFamily
))
631 return InvalidParameter
;
633 FIXME("No support for FontCollections yet!\n");
635 if (!find_installed_font(name
, &otm
))
636 return FontFamilyNotFound
;
638 ffamily
= GdipAlloc(sizeof (GpFontFamily
));
639 if (!ffamily
) return OutOfMemory
;
642 lstrcpynW(ffamily
->FamilyName
, name
, LF_FACESIZE
);
644 *FontFamily
= ffamily
;
646 TRACE("<-- %p\n", ffamily
);
651 /*******************************************************************************
652 * GdipCloneFontFamily [GDIPLUS.@]
654 * Creates a deep copy of a Font Family object
657 * FontFamily [I] Font to clone
658 * clonedFontFamily [O] The resulting cloned font
663 GpStatus WINGDIPAPI
GdipCloneFontFamily(GpFontFamily
* FontFamily
, GpFontFamily
** clonedFontFamily
)
665 if (!(FontFamily
&& clonedFontFamily
)) return InvalidParameter
;
667 TRACE("stub: %p (%s), %p\n", FontFamily
,
668 debugstr_w(FontFamily
->FamilyName
), clonedFontFamily
);
670 *clonedFontFamily
= GdipAlloc(sizeof(GpFontFamily
));
671 if (!*clonedFontFamily
) return OutOfMemory
;
673 (*clonedFontFamily
)->otm
= FontFamily
->otm
;
674 lstrcpyW((*clonedFontFamily
)->FamilyName
, FontFamily
->FamilyName
);
676 TRACE("<-- %p\n", *clonedFontFamily
);
681 /*******************************************************************************
682 * GdipGetFamilyName [GDIPLUS.@]
684 * Returns the family name into name
687 * *family [I] Family to retrieve from
688 * *name [O] WCHARS of the family name
693 * FAILURE: InvalidParameter if family is NULL
696 * If name is a NULL ptr, then both XP and Vista will crash (so we do as well)
698 GpStatus WINGDIPAPI
GdipGetFamilyName (GDIPCONST GpFontFamily
*family
,
699 WCHAR
*name
, LANGID language
)
701 static int lang_fixme
;
704 return InvalidParameter
;
706 TRACE("%p, %p, %d\n", family
, name
, language
);
708 if (language
!= LANG_NEUTRAL
&& !lang_fixme
++)
709 FIXME("No support for handling of multiple languages!\n");
711 lstrcpynW (name
, family
->FamilyName
, LF_FACESIZE
);
717 /*****************************************************************************
718 * GdipDeleteFontFamily [GDIPLUS.@]
720 * Removes the specified FontFamily
723 * *FontFamily [I] The family to delete
727 * FAILURE: InvalidParameter if FontFamily is NULL.
730 GpStatus WINGDIPAPI
GdipDeleteFontFamily(GpFontFamily
*FontFamily
)
733 return InvalidParameter
;
734 TRACE("Deleting %p (%s)\n", FontFamily
, debugstr_w(FontFamily
->FamilyName
));
736 GdipFree (FontFamily
);
741 GpStatus WINGDIPAPI
GdipGetCellAscent(GDIPCONST GpFontFamily
*family
,
742 INT style
, UINT16
* CellAscent
)
744 if (!(family
&& CellAscent
)) return InvalidParameter
;
746 *CellAscent
= family
->otm
.otmTextMetrics
.tmAscent
;
747 TRACE("%d => %u\n", family
->otm
.otmTextMetrics
.tmHeight
, *CellAscent
);
752 GpStatus WINGDIPAPI
GdipGetCellDescent(GDIPCONST GpFontFamily
*family
,
753 INT style
, UINT16
* CellDescent
)
755 TRACE("(%p, %d, %p)\n", family
, style
, CellDescent
);
757 if (!(family
&& CellDescent
)) return InvalidParameter
;
759 *CellDescent
= family
->otm
.otmTextMetrics
.tmDescent
;
760 TRACE("%d => %u\n", family
->otm
.otmTextMetrics
.tmHeight
, *CellDescent
);
765 /*******************************************************************************
766 * GdipGetEmHeight [GDIPLUS.@]
768 * Gets the height of the specified family in EmHeights
771 * family [I] Family to retrieve from
772 * style [I] (optional) style
773 * EmHeight [O] return value
777 * FAILURE: InvalidParameter
779 GpStatus WINGDIPAPI
GdipGetEmHeight(GDIPCONST GpFontFamily
*family
, INT style
, UINT16
* EmHeight
)
781 if (!(family
&& EmHeight
)) return InvalidParameter
;
783 TRACE("%p (%s), %d, %p\n", family
, debugstr_w(family
->FamilyName
), style
, EmHeight
);
785 *EmHeight
= family
->otm
.otmEMSquare
;
786 TRACE("%d => %u\n", family
->otm
.otmTextMetrics
.tmHeight
, *EmHeight
);
792 /*******************************************************************************
793 * GdipGetLineSpacing [GDIPLUS.@]
795 * Returns the line spacing in design units
798 * family [I] Family to retrieve from
799 * style [I] (Optional) font style
800 * LineSpacing [O] Return value
804 * FAILURE: InvalidParameter (family or LineSpacing was NULL)
806 GpStatus WINGDIPAPI
GdipGetLineSpacing(GDIPCONST GpFontFamily
*family
,
807 INT style
, UINT16
* LineSpacing
)
809 TRACE("%p, %d, %p\n", family
, style
, LineSpacing
);
811 if (!(family
&& LineSpacing
))
812 return InvalidParameter
;
814 if (style
) FIXME("ignoring style\n");
816 *LineSpacing
= family
->otm
.otmTextMetrics
.tmAscent
+ family
->otm
.otmTextMetrics
.tmDescent
+ family
->otm
.otmTextMetrics
.tmExternalLeading
;
817 TRACE("%d => %u\n", family
->otm
.otmTextMetrics
.tmHeight
, *LineSpacing
);
822 static INT CALLBACK
font_has_style_proc(const LOGFONTW
*elf
,
823 const TEXTMETRICW
*ntm
, DWORD type
, LPARAM lParam
)
825 INT fontstyle
= FontStyleRegular
;
829 if (ntm
->tmWeight
>= FW_BOLD
) fontstyle
|= FontStyleBold
;
830 if (ntm
->tmItalic
) fontstyle
|= FontStyleItalic
;
831 if (ntm
->tmUnderlined
) fontstyle
|= FontStyleUnderline
;
832 if (ntm
->tmStruckOut
) fontstyle
|= FontStyleStrikeout
;
834 return (INT
)lParam
!= fontstyle
;
837 GpStatus WINGDIPAPI
GdipIsStyleAvailable(GDIPCONST GpFontFamily
* family
,
838 INT style
, BOOL
* IsStyleAvailable
)
842 TRACE("%p %d %p\n", family
, style
, IsStyleAvailable
);
844 if (!(family
&& IsStyleAvailable
))
845 return InvalidParameter
;
847 *IsStyleAvailable
= FALSE
;
851 if(!EnumFontFamiliesW(hdc
, family
->FamilyName
, font_has_style_proc
, (LPARAM
)style
))
852 *IsStyleAvailable
= TRUE
;
859 /*****************************************************************************
860 * GdipGetGenericFontFamilyMonospace [GDIPLUS.@]
862 * Obtains a serif family (Courier New on Windows)
865 * **nativeFamily [I] Where the font will be stored
868 * InvalidParameter if nativeFamily is NULL.
871 GpStatus WINGDIPAPI
GdipGetGenericFontFamilyMonospace(GpFontFamily
**nativeFamily
)
873 static const WCHAR CourierNew
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
874 static const WCHAR LiberationMono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o','\0'};
877 if (nativeFamily
== NULL
) return InvalidParameter
;
879 stat
= GdipCreateFontFamilyFromName(CourierNew
, NULL
, nativeFamily
);
881 if (stat
== FontFamilyNotFound
)
882 stat
= GdipCreateFontFamilyFromName(LiberationMono
, NULL
, nativeFamily
);
884 if (stat
== FontFamilyNotFound
)
885 ERR("Missing 'Courier New' font\n");
890 /*****************************************************************************
891 * GdipGetGenericFontFamilySerif [GDIPLUS.@]
893 * Obtains a serif family (Times New Roman on Windows)
896 * **nativeFamily [I] Where the font will be stored
899 * InvalidParameter if nativeFamily is NULL.
902 GpStatus WINGDIPAPI
GdipGetGenericFontFamilySerif(GpFontFamily
**nativeFamily
)
904 static const WCHAR TimesNewRoman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
905 static const WCHAR LiberationSerif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f','\0'};
908 TRACE("(%p)\n", nativeFamily
);
910 if (nativeFamily
== NULL
) return InvalidParameter
;
912 stat
= GdipCreateFontFamilyFromName(TimesNewRoman
, NULL
, nativeFamily
);
914 if (stat
== FontFamilyNotFound
)
915 stat
= GdipCreateFontFamilyFromName(LiberationSerif
, NULL
, nativeFamily
);
917 if (stat
== FontFamilyNotFound
)
918 ERR("Missing 'Times New Roman' font\n");
923 /*****************************************************************************
924 * GdipGetGenericFontFamilySansSerif [GDIPLUS.@]
926 * Obtains a serif family (Microsoft Sans Serif on Windows)
929 * **nativeFamily [I] Where the font will be stored
932 * InvalidParameter if nativeFamily is NULL.
935 GpStatus WINGDIPAPI
GdipGetGenericFontFamilySansSerif(GpFontFamily
**nativeFamily
)
938 static const WCHAR MicrosoftSansSerif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
939 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a','\0'};
941 TRACE("(%p)\n", nativeFamily
);
943 if (nativeFamily
== NULL
) return InvalidParameter
;
945 stat
= GdipCreateFontFamilyFromName(MicrosoftSansSerif
, NULL
, nativeFamily
);
947 if (stat
== FontFamilyNotFound
)
948 /* FIXME: Microsoft Sans Serif is not installed on Wine. */
949 stat
= GdipCreateFontFamilyFromName(Tahoma
, NULL
, nativeFamily
);
954 /*****************************************************************************
955 * GdipGetGenericFontFamilySansSerif [GDIPLUS.@]
957 GpStatus WINGDIPAPI
GdipNewPrivateFontCollection(GpFontCollection
** fontCollection
)
959 TRACE("%p\n", fontCollection
);
962 return InvalidParameter
;
964 *fontCollection
= GdipAlloc(sizeof(GpFontCollection
));
965 if (!*fontCollection
) return OutOfMemory
;
967 (*fontCollection
)->FontFamilies
= NULL
;
968 (*fontCollection
)->count
= 0;
969 (*fontCollection
)->allocated
= 0;
971 TRACE("<-- %p\n", *fontCollection
);
976 /*****************************************************************************
977 * GdipDeletePrivateFontCollection [GDIPLUS.@]
979 GpStatus WINGDIPAPI
GdipDeletePrivateFontCollection(GpFontCollection
**fontCollection
)
983 TRACE("%p\n", fontCollection
);
986 return InvalidParameter
;
988 for (i
= 0; i
< (*fontCollection
)->count
; i
++) GdipFree((*fontCollection
)->FontFamilies
[i
]);
989 GdipFree(*fontCollection
);
994 /*****************************************************************************
995 * GdipPrivateAddFontFile [GDIPLUS.@]
997 GpStatus WINGDIPAPI
GdipPrivateAddFontFile(GpFontCollection
* fontCollection
,
998 GDIPCONST WCHAR
* filename
)
1000 FIXME("stub: %p, %s\n", fontCollection
, debugstr_w(filename
));
1002 if (!(fontCollection
&& filename
))
1003 return InvalidParameter
;
1005 return NotImplemented
;
1008 /* Copied from msi/font.c */
1010 typedef struct _tagTT_OFFSET_TABLE
{
1011 USHORT uMajorVersion
;
1012 USHORT uMinorVersion
;
1013 USHORT uNumOfTables
;
1014 USHORT uSearchRange
;
1015 USHORT uEntrySelector
;
1019 typedef struct _tagTT_TABLE_DIRECTORY
{
1020 char szTag
[4]; /* table name */
1021 ULONG uCheckSum
; /* Check sum */
1022 ULONG uOffset
; /* Offset from beginning of file */
1023 ULONG uLength
; /* length of the table in bytes */
1024 } TT_TABLE_DIRECTORY
;
1026 typedef struct _tagTT_NAME_TABLE_HEADER
{
1027 USHORT uFSelector
; /* format selector. Always 0 */
1028 USHORT uNRCount
; /* Name Records count */
1029 USHORT uStorageOffset
; /* Offset for strings storage,
1030 * from start of the table */
1031 } TT_NAME_TABLE_HEADER
;
1033 #define NAME_ID_FULL_FONT_NAME 4
1034 #define NAME_ID_VERSION 5
1036 typedef struct _tagTT_NAME_RECORD
{
1041 USHORT uStringLength
;
1042 USHORT uStringOffset
; /* from start of storage area */
1045 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1046 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
1049 * Code based off of code located here
1050 * http://www.codeproject.com/gdi/fontnamefromfile.asp
1052 static WCHAR
*load_ttf_name_id( const char *mem
, DWORD_PTR size
, DWORD id
, WCHAR
*ret
, DWORD len
)
1054 const TT_TABLE_DIRECTORY
*tblDir
;
1055 TT_OFFSET_TABLE ttOffsetTable
;
1056 TT_NAME_TABLE_HEADER ttNTHeader
;
1057 TT_NAME_RECORD ttRecord
;
1061 if (sizeof(TT_OFFSET_TABLE
) > size
)
1063 ttOffsetTable
= *(TT_OFFSET_TABLE
*)mem
;
1064 ttOffsetTable
.uNumOfTables
= SWAPWORD(ttOffsetTable
.uNumOfTables
);
1065 ttOffsetTable
.uMajorVersion
= SWAPWORD(ttOffsetTable
.uMajorVersion
);
1066 ttOffsetTable
.uMinorVersion
= SWAPWORD(ttOffsetTable
.uMinorVersion
);
1068 if (ttOffsetTable
.uMajorVersion
!= 1 || ttOffsetTable
.uMinorVersion
!= 0)
1071 pos
= sizeof(ttOffsetTable
);
1072 for (i
= 0; i
< ttOffsetTable
.uNumOfTables
; i
++)
1074 tblDir
= (const TT_TABLE_DIRECTORY
*)&mem
[pos
];
1075 pos
+= sizeof(*tblDir
);
1076 if (memcmp(tblDir
->szTag
,"name",4)==0)
1078 ofs
= SWAPLONG(tblDir
->uOffset
);
1082 if (i
>= ttOffsetTable
.uNumOfTables
)
1085 pos
= ofs
+ sizeof(ttNTHeader
);
1088 ttNTHeader
= *(TT_NAME_TABLE_HEADER
*)&mem
[ofs
];
1089 ttNTHeader
.uNRCount
= SWAPWORD(ttNTHeader
.uNRCount
);
1090 ttNTHeader
.uStorageOffset
= SWAPWORD(ttNTHeader
.uStorageOffset
);
1091 for(i
=0; i
<ttNTHeader
.uNRCount
; i
++)
1093 ttRecord
= *(TT_NAME_RECORD
*)&mem
[pos
];
1094 pos
+= sizeof(ttRecord
);
1098 ttRecord
.uNameID
= SWAPWORD(ttRecord
.uNameID
);
1099 if (ttRecord
.uNameID
== id
)
1103 ttRecord
.uStringLength
= SWAPWORD(ttRecord
.uStringLength
);
1104 ttRecord
.uStringOffset
= SWAPWORD(ttRecord
.uStringOffset
);
1105 if (ofs
+ ttRecord
.uStringOffset
+ ttNTHeader
.uStorageOffset
+ ttRecord
.uStringLength
> size
)
1107 buf
= mem
+ ofs
+ ttRecord
.uStringOffset
+ ttNTHeader
.uStorageOffset
;
1108 len
= MultiByteToWideChar(CP_ACP
, 0, buf
, ttRecord
.uStringLength
, ret
, len
-1);
1116 static INT CALLBACK
add_font_proc(const LOGFONTW
*lfw
, const TEXTMETRICW
*ntm
, DWORD type
, LPARAM lParam
);
1118 /*****************************************************************************
1119 * GdipPrivateAddMemoryFont [GDIPLUS.@]
1121 GpStatus WINGDIPAPI
GdipPrivateAddMemoryFont(GpFontCollection
* fontCollection
,
1122 GDIPCONST
void* memory
, INT length
)
1124 WCHAR buf
[32], *name
;
1127 TRACE("%p, %p, %d\n", fontCollection
, memory
, length
);
1129 if (!fontCollection
|| !memory
|| !length
)
1130 return InvalidParameter
;
1132 name
= load_ttf_name_id(memory
, length
, NAME_ID_FULL_FONT_NAME
, buf
, sizeof(buf
)/sizeof(*buf
));
1136 font
= AddFontMemResourceEx((void*)memory
, length
, NULL
, &count
);
1137 TRACE("%s: %p/%u\n", debugstr_w(name
), font
, count
);
1138 if (!font
|| !count
)
1139 return InvalidParameter
;
1148 lfw
.lfCharSet
= DEFAULT_CHARSET
;
1149 lstrcpyW(lfw
.lfFaceName
, name
);
1150 lfw
.lfPitchAndFamily
= 0;
1152 if (!EnumFontFamiliesExW(hdc
, &lfw
, add_font_proc
, (LPARAM
)fontCollection
, 0))
1163 /*****************************************************************************
1164 * GdipGetFontCollectionFamilyCount [GDIPLUS.@]
1166 GpStatus WINGDIPAPI
GdipGetFontCollectionFamilyCount(
1167 GpFontCollection
* fontCollection
, INT
* numFound
)
1169 TRACE("%p, %p\n", fontCollection
, numFound
);
1171 if (!(fontCollection
&& numFound
))
1172 return InvalidParameter
;
1174 *numFound
= fontCollection
->count
;
1178 /*****************************************************************************
1179 * GdipGetFontCollectionFamilyList [GDIPLUS.@]
1181 GpStatus WINGDIPAPI
GdipGetFontCollectionFamilyList(
1182 GpFontCollection
* fontCollection
, INT numSought
,
1183 GpFontFamily
* gpfamilies
[], INT
* numFound
)
1188 TRACE("%p, %d, %p, %p\n", fontCollection
, numSought
, gpfamilies
, numFound
);
1190 if (!(fontCollection
&& gpfamilies
&& numFound
))
1191 return InvalidParameter
;
1193 memset(gpfamilies
, 0, sizeof(*gpfamilies
) * numSought
);
1195 for (i
= 0; i
< numSought
&& i
< fontCollection
->count
&& stat
== Ok
; i
++)
1197 stat
= GdipCloneFontFamily(fontCollection
->FontFamilies
[i
], &gpfamilies
[i
]);
1205 for (i
=0; i
<numToFree
; i
++)
1207 GdipDeleteFontFamily(gpfamilies
[i
]);
1208 gpfamilies
[i
] = NULL
;
1215 void free_installed_fonts(void)
1217 while (installedFontCollection
.count
)
1218 GdipDeleteFontFamily(installedFontCollection
.FontFamilies
[--installedFontCollection
.count
]);
1219 HeapFree(GetProcessHeap(), 0, installedFontCollection
.FontFamilies
);
1220 installedFontCollection
.FontFamilies
= NULL
;
1221 installedFontCollection
.allocated
= 0;
1224 static INT CALLBACK
add_font_proc(const LOGFONTW
*lfw
, const TEXTMETRICW
*ntm
,
1225 DWORD type
, LPARAM lParam
)
1227 GpFontCollection
* fonts
= (GpFontCollection
*)lParam
;
1230 if (type
== RASTER_FONTTYPE
)
1233 /* skip duplicates */
1234 for (i
=0; i
<fonts
->count
; i
++)
1235 if (strcmpiW(lfw
->lfFaceName
, fonts
->FontFamilies
[i
]->FamilyName
) == 0)
1238 if (fonts
->allocated
== fonts
->count
)
1240 INT new_alloc_count
= fonts
->allocated
+50;
1241 GpFontFamily
** new_family_list
= HeapAlloc(GetProcessHeap(), 0, new_alloc_count
*sizeof(void*));
1243 if (!new_family_list
)
1246 memcpy(new_family_list
, fonts
->FontFamilies
, fonts
->count
*sizeof(void*));
1247 HeapFree(GetProcessHeap(), 0, fonts
->FontFamilies
);
1248 fonts
->FontFamilies
= new_family_list
;
1249 fonts
->allocated
= new_alloc_count
;
1252 if (GdipCreateFontFamilyFromName(lfw
->lfFaceName
, NULL
, &fonts
->FontFamilies
[fonts
->count
]) == Ok
)
1260 GpStatus WINGDIPAPI
GdipNewInstalledFontCollection(
1261 GpFontCollection
** fontCollection
)
1263 TRACE("(%p)\n",fontCollection
);
1265 if (!fontCollection
)
1266 return InvalidParameter
;
1268 if (installedFontCollection
.count
== 0)
1275 lfw
.lfCharSet
= DEFAULT_CHARSET
;
1276 lfw
.lfFaceName
[0] = 0;
1277 lfw
.lfPitchAndFamily
= 0;
1279 if (!EnumFontFamiliesExW(hdc
, &lfw
, add_font_proc
, (LPARAM
)&installedFontCollection
, 0))
1281 free_installed_fonts();
1289 *fontCollection
= &installedFontCollection
;