Skip to content

Commit

Permalink
Font: fall back to using freetype's 2.9.1 algorithm for calculating f…
Browse files Browse the repository at this point in the history
…ont metrics like ascent/descent

This allows us to upgrade freetype beyond 2.9.1 (actually, 2.8.1 due to a bug in freetype 2.9) without wildly different font metrics. The reason that we don't want to change font metrics algorithms is that freetype's new algorithm is very different than the algorithm used for SWF fonts. The older freetype algorithm is closer to SWF, so we want to stick with it.

Thankfully, freetype supports accessing various metrics stored in font files in a more raw form, so we can provide our own custom algorithm in a way that is fully supported by freetype. I just copied the existing algorithm straight from 2.9.1 to restore our preferred behavior.

I confirmed that, after this change, OpenFL renders metrics like Lime 8.1.3. But we have the same upgraded freetype as Lime 8.2.0 that we had to revert for 8.2.1.

I plan to experiment with a mode that matches SWF even more closely, now that I have a better understanding of how fonts and freetype work.
  • Loading branch information
joshtynjala committed Dec 13, 2024
1 parent 27d1d8b commit 62ab8eb
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 9 deletions.
6 changes: 6 additions & 0 deletions project/Build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@
<compilerflag value="-I${NATIVE_TOOLKIT_PATH}/freetype/include" />
<compilerflag value="-DLIME_FREETYPE" />

<!--
prefer FreeType's font metrics algorithm from 2.9.1
it behaves more like SWF than the new algorithm
-->
<compilerflag value="-DLIME_FREETYPE_LEGACY_METRICS" />

<file name="src/text/Font.cpp" />

<section if="LIME_HARFBUZZ">
Expand Down
216 changes: 207 additions & 9 deletions project/src/text/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include FT_BITMAP_H
#include FT_SFNT_NAMES_H
#include FT_TRUETYPE_IDS_H
#include FT_TRUETYPE_TABLES_H
#include FT_GLYPH_H
#include FT_OUTLINE_H
#endif
Expand Down Expand Up @@ -536,6 +537,57 @@ namespace lime {

wchar_t* family_name = GetFamilyName ();

#ifdef LIME_FREETYPE_LEGACY_METRICS

// this is FreeType's font metrics algorithm from 2.9.1
// it behaves more like SWF than the new algorithm

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);

int calculatedAscender = hhea->Ascender;
int calculatedDescender = hhea->Descender;
int calculatedHeight = calculatedAscender - calculatedDescender + hhea->Line_Gap;

if (!( calculatedAscender || calculatedDescender ))
{
if (os2->version != 0xFFFFU)
{
if (os2->sTypoAscender || os2->sTypoDescender)
{

calculatedAscender = os2->sTypoAscender;
calculatedDescender = os2->sTypoDescender;
calculatedHeight = calculatedAscender - calculatedDescender + os2->sTypoLineGap;

}
else
{

calculatedAscender = (FT_Short)os2->usWinAscent;
calculatedDescender = -(FT_Short)os2->usWinDescent;
calculatedHeight = calculatedAscender - calculatedDescender;

}
}
}

if (!calculatedAscender || !calculatedDescender) {

calculatedAscender = ((FT_Face)face)->ascender;
calculatedDescender = ((FT_Face)face)->descender;
calculatedHeight = ((FT_Face)face)->height;

}

#else

int calculatedAscender = ((FT_Face)face)->ascender;
int calculatedDescender = ((FT_Face)face)->descender;
int calculatedHeight = ((FT_Face)face)->height;

#endif

if (useCFFIValue) {

value ret = alloc_empty_object ();
Expand All @@ -548,9 +600,9 @@ namespace lime {
alloc_field (ret, val_id ("family_name"), family_name == NULL ? alloc_string (((FT_Face)face)->family_name) : alloc_wstring (family_name));
alloc_field (ret, val_id ("style_name"), alloc_string (((FT_Face)face)->style_name));
alloc_field (ret, val_id ("em_size"), alloc_int (((FT_Face)face)->units_per_EM));
alloc_field (ret, val_id ("ascend"), alloc_int (((FT_Face)face)->ascender));
alloc_field (ret, val_id ("descend"), alloc_int (((FT_Face)face)->descender));
alloc_field (ret, val_id ("height"), alloc_int (((FT_Face)face)->height));
alloc_field (ret, val_id ("ascend"), alloc_int (calculatedAscender));
alloc_field (ret, val_id ("descend"), alloc_int (calculatedDescender));
alloc_field (ret, val_id ("height"), alloc_int (calculatedHeight));

delete family_name;

Expand Down Expand Up @@ -647,9 +699,9 @@ namespace lime {
hl_dyn_setp (ret, hl_hash_utf8 ("family_name"), &hlt_bytes, _family_name);
hl_dyn_setp (ret, hl_hash_utf8 ("style_name"), &hlt_bytes, style_name);
hl_dyn_seti (ret, hl_hash_utf8 ("em_size"), &hlt_i32, ((FT_Face)face)->units_per_EM);
hl_dyn_seti (ret, hl_hash_utf8 ("ascend"), &hlt_i32, ((FT_Face)face)->ascender);
hl_dyn_seti (ret, hl_hash_utf8 ("descend"), &hlt_i32, ((FT_Face)face)->descender);
hl_dyn_seti (ret, hl_hash_utf8 ("height"), &hlt_i32, ((FT_Face)face)->height);
hl_dyn_seti (ret, hl_hash_utf8 ("ascend"), &hlt_i32, calculatedAscender);
hl_dyn_seti (ret, hl_hash_utf8 ("descend"), &hlt_i32, calculatedDescender);
hl_dyn_seti (ret, hl_hash_utf8 ("height"), &hlt_i32, calculatedHeight);

// 'glyphs' field
hl_varray* _glyphs = (hl_varray*)hl_alloc_array (&hlt_dynobj, num_glyphs);
Expand Down Expand Up @@ -721,15 +773,113 @@ namespace lime {

int Font::GetAscender () {

#ifdef LIME_FREETYPE_LEGACY_METRICS

// this is FreeType's font metrics algorithm from 2.9.1
// it behaves more like SWF than the new algorithm

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);

int calculatedAscender = hhea->Ascender;
int calculatedDescender = hhea->Descender;
int calculatedHeight = calculatedAscender - calculatedDescender + hhea->Line_Gap;

if (!( calculatedAscender || calculatedDescender ))
{
if (os2->version != 0xFFFFU)
{
if (os2->sTypoAscender || os2->sTypoDescender)
{

calculatedAscender = os2->sTypoAscender;
calculatedDescender = os2->sTypoDescender;
calculatedHeight = calculatedAscender - calculatedDescender + os2->sTypoLineGap;

}
else
{

calculatedAscender = (FT_Short)os2->usWinAscent;
calculatedDescender = -(FT_Short)os2->usWinDescent;
calculatedHeight = calculatedAscender - calculatedDescender;

}
}
}

if (!calculatedAscender || !calculatedDescender) {

calculatedAscender = ((FT_Face)face)->ascender;
calculatedDescender = ((FT_Face)face)->descender;
calculatedHeight = ((FT_Face)face)->height;

}

return calculatedAscender;

#else

return ((FT_Face)face)->ascender;

#endif

}


int Font::GetDescender () {

#ifdef LIME_FREETYPE_LEGACY_METRICS

// this is FreeType's font metrics algorithm from 2.9.1
// it behaves more like SWF than the new algorithm

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);

int calculatedAscender = hhea->Ascender;
int calculatedDescender = hhea->Descender;
int calculatedHeight = calculatedAscender - calculatedDescender + hhea->Line_Gap;

if (!( calculatedAscender || calculatedDescender ))
{
if (os2->version != 0xFFFFU)
{
if (os2->sTypoAscender || os2->sTypoDescender)
{

calculatedAscender = os2->sTypoAscender;
calculatedDescender = os2->sTypoDescender;
calculatedHeight = calculatedAscender - calculatedDescender + os2->sTypoLineGap;

}
else
{

calculatedAscender = (FT_Short)os2->usWinAscent;
calculatedDescender = -(FT_Short)os2->usWinDescent;
calculatedHeight = calculatedAscender - calculatedDescender;

}
}
}

if (!calculatedAscender || !calculatedDescender) {

calculatedAscender = ((FT_Face)face)->ascender;
calculatedDescender = ((FT_Face)face)->descender;
calculatedHeight = ((FT_Face)face)->height;

}

return calculatedDescender;

#else

return ((FT_Face)face)->descender;

#endif

}


Expand Down Expand Up @@ -911,8 +1061,56 @@ namespace lime {

int Font::GetHeight () {

#ifdef LIME_FREETYPE_LEGACY_METRICS

// this is FreeType's font metrics algorithm from 2.9.1
// it behaves more like SWF than the new algorithm

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);

int calculatedAscender = hhea->Ascender;
int calculatedDescender = hhea->Descender;
int calculatedHeight = calculatedAscender - calculatedDescender + hhea->Line_Gap;

if (!( calculatedAscender || calculatedDescender ))
{
if (os2->version != 0xFFFFU)
{
if (os2->sTypoAscender || os2->sTypoDescender)
{

calculatedAscender = os2->sTypoAscender;
calculatedDescender = os2->sTypoDescender;
calculatedHeight = calculatedAscender - calculatedDescender +
os2->sTypoLineGap;

}
else
{

calculatedAscender = (FT_Short)os2->usWinAscent;
calculatedDescender = -(FT_Short)os2->usWinDescent;
calculatedHeight = calculatedAscender - calculatedDescender;

}
}
}

if (!calculatedHeight) {

calculatedHeight = ((FT_Face)face)->height;

}

return calculatedHeight;

#else

return ((FT_Face)face)->height;

#endif

}


Expand Down Expand Up @@ -989,7 +1187,7 @@ namespace lime {
unsigned char g = bitmap.buffer[i * pitch + j * 3 + 1];
unsigned char b = bitmap.buffer[i * pitch + j * 3 + 2];
unsigned char a = (r + g + b) / 3;

//Red
position[(i * width + j) * 4 + 0] = r;
//Green
Expand Down Expand Up @@ -1039,10 +1237,10 @@ namespace lime {
return totalOffset;

}

void Font::SetSize(size_t size, size_t dpi)
{
//We changed the function signature to include a dpi argument which changes this from
//We changed the function signature to include a dpi argument which changes this from
//the default value of 72 for dpi. Any public api that uses this should probably be changed
//to allow setting the dpi in an appropriate future release.
size_t hdpi = dpi;
Expand Down

0 comments on commit 62ab8eb

Please sign in to comment.