From 0db3c7c0959ec3f1ad009fd0fd84a1d3bd390853 Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 13 Dec 2024 14:26:34 -0800 Subject: [PATCH] Font: experimental LIME_FREETYPE_SWF_METRICS define that more closely matches SWF behavior for font metrics like ascent/descent We're currently using freetype 2.9.1's algorithm for choosing font metrics, but it's not exactly the same as SWF (but it is closer than freetype 2.10's new algorithm). This algorithm should more closely match the font metrics used by AS3 compilers when embedding fonts with [Embed] metadata in AS3. --- project/src/text/Font.cpp | 109 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/project/src/text/Font.cpp b/project/src/text/Font.cpp index 3708902ff..9d002fc24 100644 --- a/project/src/text/Font.cpp +++ b/project/src/text/Font.cpp @@ -537,7 +537,40 @@ namespace lime { wchar_t* family_name = GetFamilyName (); - #ifdef LIME_FREETYPE_LEGACY_METRICS + #ifdef LIME_FREETYPE_SWF_METRICS + + // this should more closely match how [Embed] works in AS3 when + // embedding a font in a SWF + + int calculatedAscender = 0; + int calculatedDescender = 0; + int calculatedHeight = 0; + + TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_os2); + TT_HoriHeader* hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_hhea); + + if (os2 && os2->version != 0xFFFFU) { + + calculatedAscender = (FT_Short)os2->usWinAscent; + calculatedDescender = -(FT_Short)os2->usWinDescent; + calculatedHeight = calculatedAscender - calculatedDescender; + + } else if (hhea) { + + calculatedAscender = hhea->Ascender; + calculatedDescender = hhea->Descender; + calculatedHeight = calculatedAscender - calculatedDescender + hhea->Line_Gap; + + } else { + + // should never happen, but let's have a fallback to be safe + calculatedAscender = ((FT_Face)face)->ascender; + calculatedDescender = ((FT_Face)face)->descender; + calculatedHeight = ((FT_Face)face)->height; + + } + + #elif defined(LIME_FREETYPE_LEGACY_METRICS) // this is FreeType's font metrics algorithm from 2.9.1 // it behaves more like SWF than the new algorithm @@ -773,7 +806,28 @@ namespace lime { int Font::GetAscender () { - #ifdef LIME_FREETYPE_LEGACY_METRICS + #ifdef LIME_FREETYPE_SWF_METRICS + + // this should more closely match how [Embed] works in AS3 when + // embedding a font in a SWF + + TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_os2); + TT_HoriHeader* hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_hhea); + + if (os2 && os2->version != 0xFFFFU) { + + return (FT_Short)os2->usWinAscent; + + } else if (hhea) { + + return hhea->Ascender; + + } + + // should never happen, but let's have a fallback to be safe + return ((FT_Face)face)->ascender; + + #elif defined(LIME_FREETYPE_LEGACY_METRICS) // this is FreeType's font metrics algorithm from 2.9.1 // it behaves more like SWF than the new algorithm @@ -829,7 +883,29 @@ namespace lime { int Font::GetDescender () { - #ifdef LIME_FREETYPE_LEGACY_METRICS + #ifdef LIME_FREETYPE_SWF_METRICS + + // this should more closely match how [Embed] works in AS3 when + // embedding a font in a SWF + + TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_os2); + TT_HoriHeader* hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_hhea); + + if (os2 && os2->version != 0xFFFFU) { + + return -(FT_Short)os2->usWinDescent; + + } + else if (hhea) { + + return hhea->Descender; + + } + + // should never happen, but let's have a fallback to be safe + return ((FT_Face)face)->descender; + + #elif defined(LIME_FREETYPE_LEGACY_METRICS) // this is FreeType's font metrics algorithm from 2.9.1 // it behaves more like SWF than the new algorithm @@ -1061,7 +1137,32 @@ namespace lime { int Font::GetHeight () { - #ifdef LIME_FREETYPE_LEGACY_METRICS + #ifdef LIME_FREETYPE_SWF_METRICS + + // this should more closely match how [Embed] works in AS3 when + // embedding a font in a SWF + + TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_os2); + TT_HoriHeader* hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(((FT_Face)face), ft_sfnt_hhea); + + if (os2 && os2->version != 0xFFFFU) { + + int calculatedAscender = (FT_Short)os2->usWinAscent; + int calculatedDescender = -(FT_Short)os2->usWinDescent; + return calculatedAscender - calculatedDescender; + + } else if (hhea) { + + int calculatedAscender = hhea->Ascender; + int calculatedDescender = hhea->Descender; + return calculatedAscender - calculatedDescender + hhea->Line_Gap; + + } + + // should never happen, but let's have a fallback to be safe + return ((FT_Face)face)->height; + + #elif defined(LIME_FREETYPE_LEGACY_METRICS) // this is FreeType's font metrics algorithm from 2.9.1 // it behaves more like SWF than the new algorithm