BLF: Improved Cached Fallback Font Setup

Changes to FontBLF initialization so that the cached fallback fonts,
which remain faceless until needed, get all required setup.
Otherwise they are not kerned and we also don't get metrics from them.

Pull Request: https://projects.blender.org/blender/blender/pulls/114018
This commit is contained in:
Harley Acheson 2023-10-22 03:54:57 +02:00 committed by Harley Acheson
parent fd63c01c4f
commit b53111e935
2 changed files with 60 additions and 48 deletions

View File

@ -75,6 +75,8 @@ static ft_pix blf_font_width_max_ft_pix(FontBLF *font);
/** \name FreeType Caching
* \{ */
static bool blf_setup_face(FontBLF *font);
/**
* Called when a face is removed by the cache. FreeType will call #FT_Done_Face.
*/
@ -112,6 +114,11 @@ static FT_Error blf_cache_face_requester(FTC_FaceID faceID,
font->face = *face;
font->face->generic.data = font;
font->face->generic.finalizer = blf_face_finalizer;
/* More FontBLF setup now that we have a face. */
if (!blf_setup_face(font)) {
err = FT_Err_Cannot_Open_Resource;
}
}
else {
/* Clear this on error to avoid exception in FTC_Manager_LookupFace. */
@ -1454,10 +1461,6 @@ static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
metrics->underline_position = short(face->underline_position);
metrics->underline_thickness = short(face->underline_thickness);
metrics->num_glyphs = int(face->num_glyphs);
metrics->bounding_box.xmin = int(face->bbox.xMin);
metrics->bounding_box.xmax = int(face->bbox.xMax);
metrics->bounding_box.ymin = int(face->bbox.yMin);
metrics->bounding_box.ymax = int(face->bbox.yMax);
if (metrics->cap_height == 0) {
/* Calculate or guess cap height if it is not set in the font. */
@ -1537,6 +1540,46 @@ static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
if (metrics->superscript_yoffset == 0) {
metrics->superscript_yoffset = short(float(metrics->units_per_EM) * 0.35f);
}
metrics->valid = true;
}
/**
* Extra FontBLF setup needed after it gets a Face. Called from
* both blf_ensure_face and from the blf_cache_face_requester callback.
*/
static bool blf_setup_face(FontBLF *font)
{
font->face_flags = font->face->face_flags;
if (FT_HAS_MULTIPLE_MASTERS(font) && !font->variations) {
FT_Get_MM_Var(font->face, &(font->variations));
}
if (!font->metrics.valid) {
blf_font_metrics(font->face, &font->metrics);
font->char_weight = font->metrics.weight;
font->char_slant = font->metrics.slant;
font->char_width = font->metrics.width;
font->char_spacing = font->metrics.spacing;
}
if (FT_IS_FIXED_WIDTH(font)) {
font->flags |= BLF_MONOSPACED;
}
if (FT_HAS_KERNING(font) && !font->kerning_cache) {
/* Create kerning cache table and fill with value indicating "unset". */
font->kerning_cache = static_cast<KerningCacheBLF *>(
MEM_mallocN(sizeof(KerningCacheBLF), __func__));
for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) {
font->kerning_cache->ascii_table[i][j] = KERNING_ENTRY_UNSET;
}
}
}
return true;
}
bool blf_ensure_face(FontBLF *font)
@ -1620,45 +1663,8 @@ bool blf_ensure_face(FontBLF *font)
font->ft_size = font->face->size;
}
font->face_flags = font->face->face_flags;
if (FT_HAS_MULTIPLE_MASTERS(font)) {
FT_Get_MM_Var(font->face, &(font->variations));
}
blf_ensure_size(font);
blf_font_metrics(font->face, &font->metrics);
font->char_weight = font->metrics.weight;
font->char_slant = font->metrics.slant;
font->char_width = font->metrics.width;
font->char_spacing = font->metrics.spacing;
/* Save TrueType table with bits to quickly test most unicode block coverage. */
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
if (os2_table) {
font->unicode_ranges[0] = uint(os2_table->ulUnicodeRange1);
font->unicode_ranges[1] = uint(os2_table->ulUnicodeRange2);
font->unicode_ranges[2] = uint(os2_table->ulUnicodeRange3);
font->unicode_ranges[3] = uint(os2_table->ulUnicodeRange4);
}
if (FT_IS_FIXED_WIDTH(font)) {
font->flags |= BLF_MONOSPACED;
}
if (FT_HAS_KERNING(font) && !font->kerning_cache) {
/* Create kerning cache table and fill with value indicating "unset". */
font->kerning_cache = static_cast<KerningCacheBLF *>(
MEM_mallocN(sizeof(KerningCacheBLF), __func__));
for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) {
font->kerning_cache->ascii_table[i][j] = KERNING_ENTRY_UNSET;
}
}
}
return true;
/* Setup Font details that require having a Face. */
return blf_setup_face(font);
}
struct FaceDetails {
@ -1755,6 +1761,15 @@ static FontBLF *blf_font_new_impl(const char *filepath,
blf_font_free(font);
return nullptr;
}
/* Save TrueType table with bits to quickly test most unicode block coverage. */
TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
if (os2_table) {
font->unicode_ranges[0] = uint(os2_table->ulUnicodeRange1);
font->unicode_ranges[1] = uint(os2_table->ulUnicodeRange2);
font->unicode_ranges[2] = uint(os2_table->ulUnicodeRange3);
font->unicode_ranges[3] = uint(os2_table->ulUnicodeRange4);
}
}
/* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */

View File

@ -210,6 +210,8 @@ typedef struct FontBufInfoBLF {
} FontBufInfoBLF;
typedef struct FontMetrics {
/** Indicate that these values have been properly loaded. */
bool valid;
/** This font's default weight, 100-900, 400 is normal. */
short weight;
/** This font's default width, 1 is normal, 2 is twice as wide. */
@ -232,11 +234,6 @@ typedef struct FontMetrics {
/** Maximum Unicode index, or 0xFFFF if greater than. */
short last_charindex;
/**
* Bounds that can contain every glyph in the font when in default positions. Can be used for
* maximum ascender, minimum descender. Can be out by a pixel when hinting. Does not change with
* variation axis changes. */
rcti bounding_box;
/**
* Positive number of font units from baseline to top of typical capitals. Can be slightly more
* than cap height when head serifs, terminals, or apexes extend above cap line. */