Open handerss-spotfire opened 1 year ago
Hi @handerss-spotfire, your PR looks very interresting as after reading your explanation, I noticed that the vertical positioning of my text is not the same on Windows and WebAssembly version of my app. Just one question: you recommand to use "Typo" metrics for cross-plarform, can I get that from Skia? or do I have to parse the font manually to extract those values? Thank you!
You can get the relevant data tables using SKTypeface.TryGetTableData
but then you have to parse them yourself. This is roughly we do it to get "Windows" style rendering on all platforms:
private static uint GetIntTag(string v)
{
return
(uint)v[0] << 24 |
(uint)v[1] << 16 |
(uint)v[2] << 08 |
(uint)v[3] << 00;
}
public static bool TryReadFontMetrics(SKTypeface typeface, out (int Ascent, int Descent, int LineGap) fontMetrics)
{
fontMetrics = (0, 0, 0);
(int Ascent, int Descent, int? LineGap) os2Metrics = (0, 0, null);
if (typeface.TryGetTableData(GetIntTag("OS/2"), out var os2Table))
{
os2Metrics = ReadOS2Table(os2Table);
}
if (os2Metrics.LineGap == null && typeface.TryGetTableData(GetIntTag("hhea"), out var hheaTable))
{
var hhea = ReadHheaTable(hheaTable);
// See: https://learn.microsoft.com/en-us/typography/opentype/spec/recom#baseline-to-baseline-distances
var lineGap = Math.Max(
0,
(hhea.Ascent - hhea.Descent + hhea.LineGap) - (os2Metrics.Ascent + os2Metrics.Descent));
fontMetrics = (os2Metrics.Ascent, os2Metrics.Descent, lineGap);
}
return fontMetrics.Ascent > 0 && fontMetrics.Descent > 0;
}
Where ReadOS2Table
and ReadHheaTable
parse using a BinaryReader
according the specs OS/2 hhea.
Note that when parsing the OS/2 table it's important to read metrics as specified by the font selection flags: https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection.
Thanks a lot for the details, I found tables and the properties, just need to find how to convert them to float correctly but I will look at the spec links.
This PR adds the ability to provide custom vertical font metrics when layouting text.
The background here is that Skia report different font metrics depending on platform. Windows uses
usWinAscent
,usWinDescent
, and this lovely formula for calculating leading:MAX(0, (hhea.ascender - hhea.descender + hhea.lineGap) - (usWinAscent + usWinDescent))
. If I remember correctly Linux uses thesTypo*
metrics.For cross-platform .NET applications that want to have similar rendering on both Windows and Linux (in particular vertical positioning) there needs to be a way to override the metrics reported by Skia.
I realize this may be out-of-scope for this library, feel free to close the PR in that case.