The value of descent I get from System.Drawing.FontFamily.GetCellDescent
for some fonts is different from values of I get when the font is read by other APIs/sources (e.g. SixLabors.Fonts library or FontForge program).
As a concrete example, Calibri font:
var fontName = "Calibri";
var systemDrawingFontFamily = System.Drawing.FontFamily.Families.SingleOrDefault(ff => ff.Name == fontName);
Console.WriteLine($"System.Drawing EmHeight {systemDrawingFontFamily.GetEmHeight(System.Drawing.FontStyle.Regular)}");
Console.WriteLine($"System.Drawing CellAscent {systemDrawingFontFamily.GetCellAscent(System.Drawing.FontStyle.Regular)}");
Console.WriteLine($"System.Drawing CellDescent {systemDrawingFontFamily.GetCellDescent(System.Drawing.FontStyle.Regular)}");
Console.WriteLine($"System.Drawing LineSpacing {systemDrawingFontFamily.GetLineSpacing(System.Drawing.FontStyle.Regular)}");
var sixLaborsFont = SixLabors.Fonts.SystemFonts.Families.SingleOrDefault(x => x.Name == fontName);
var sixLaborsFontMetrics = sixLaborsFont.CreateFont(0, SixLabors.Fonts.FontStyle.Regular).FontMetrics;
Console.WriteLine($"6L EmHeight {sixLaborsFontMetrics.UnitsPerEm}");
Console.WriteLine($"6L Ascender {sixLaborsFontMetrics.Ascender}");
Console.WriteLine($"6L Descender {-sixLaborsFontMetrics.Descender}");
Console.WriteLine($"6L LineGap {sixLaborsFontMetrics.LineGap}");
Console.WriteLine($"6L LineHeight {sixLaborsFontMetrics.LineHeight}");
System.Drawing EmHeight 2048
System.Drawing CellAscent 1950
System.Drawing CellDescent 550
System.Drawing LineSpacing 2500
6L EmHeight 2048
6L Ascender 1536
6L Descender 512
6L LineGap 452
6L LineHeight 2500
Typography has kind of confused vocabulary, the ascender for MS includes internal leading, but descender should be same.
Why is the descender value obtained from System.Drawing different from other sources? How is it calculated?
I went through all system fonts and in about 20% of cases, the descent has different value.
FontFamily.GetCellDescent actually calls Win32 API GDI+ function GetCellDescent. I assume that GDI+ uses same logic as GDI.
GDI has a documentation page with details about font sizes (emphasis mine):
Font Ascenders and Descenders
Some applications determine the line spacing between text lines of different sizes by using a font's maximum ascender and descender. An application can retrieve these values by calling the GetTextMetrics function and then checking the tmAscent and tmDescent members of the TEXTMETRIC.
The maximum ascent and descent are different from the typographic ascent and descent. In TrueType and OpenType fonts, the typographic ascent and descent are typically the top of the f glyph and bottom of the g glyph. An application can retrieve the typographic ascender and descender for a TrueType or OpenType font by calling the GetOutlineTextMetrics function and checking the values in the otmMacAscent and otmMacDescent members of the OUTLINETEXTMETRIC structure.
So basically the FontFamily.GetCellDescent finds a character with maximum bottom size and returns that value (in logical units).
When I called GDI API functions the
GetCellAscent
, GetCellDescent
and GetLineSpacing
.Better answer: GetCellDescent
returns a win descent metric from OS/2, as seen on the different page of FontForge. I modified it and loaded the modified font and got this number.