diff options
author | Harley Acheson <harley.acheson@gmail.com> | 2022-08-04 23:05:19 +0300 |
---|---|---|
committer | Harley Acheson <harley.acheson@gmail.com> | 2022-08-04 23:05:19 +0300 |
commit | 9d77b5a0ed7bed48dcb7483e79945067666eac0b (patch) | |
tree | 21acf2c4dd9665568c4d41761485f3bf3952b929 /source/blender/blenfont/intern/blf_font.c | |
parent | fca7cb01011a3e34d21fcff6800d0b26b2be6e8e (diff) |
BLF: Implement FreeType Caching
Implementation of the FreeType 2 cache subsystem, which limits the
number of concurrently-opened FT_Face and FT_Size objects, as well as
caching information like character maps to speed up glyph id lookups.
See D13137 for much more detail.
Differential Revision: https://developer.blender.org/D13137
Reviewed by Brecht Van Lommel
Diffstat (limited to 'source/blender/blenfont/intern/blf_font.c')
-rw-r--r-- | source/blender/blenfont/intern/blf_font.c | 168 |
1 files changed, 111 insertions, 57 deletions
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 339df9eb269..372dc19d64a 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -17,6 +17,7 @@ #include <ft2build.h> #include FT_FREETYPE_H +#include FT_CACHE_H /* FreeType Cache. */ #include FT_GLYPH_H #include FT_MULTIPLE_MASTERS_H /* Variable font support. */ #include FT_TRUETYPE_IDS_H /* Codepoint coverage constants. */ @@ -54,7 +55,10 @@ BatchBLF g_batch; /* freetype2 handle ONLY for this file! */ -static FT_Library ft_lib; +static FT_Library ft_lib = NULL; +static FTC_Manager ftc_manager = NULL; +static FTC_CMapCache ftc_charmap_cache = NULL; + static SpinLock ft_lib_mutex; static SpinLock blf_glyph_cache_mutex; @@ -65,6 +69,53 @@ static ft_pix blf_font_height_max_ft_pix(struct FontBLF *font); static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font); /* -------------------------------------------------------------------- */ +/** \name FreeType Caching + * \{ */ + +/* Called when a face is removed. FreeType will call FT_Done_Face itself. */ +static void blf_face_finalizer(void *object) +{ + FT_Face face = object; + FontBLF *font = (FontBLF *)face->generic.data; + font->face = NULL; +} + +/* Called in response to FTC_Manager_LookupFace. Add a face to our font. */ +FT_Error blf_cache_face_requester(FTC_FaceID faceID, + FT_Library lib, + FT_Pointer reqData, + FT_Face *face) +{ + FontBLF *font = (FontBLF *)faceID; + int err = FT_Err_Cannot_Open_Resource; + + BLI_spin_lock(font->ft_lib_mutex); + + if (font->filepath) { + err = FT_New_Face(lib, font->filepath, 0, face); + } + else if (font->mem) { + err = FT_New_Memory_Face(lib, font->mem, (FT_Long)font->mem_size, 0, face); + } + + BLI_spin_unlock(font->ft_lib_mutex); + + if (err == FT_Err_Ok) { + font->face = *face; + font->face->generic.data = font; + font->face->generic.finalizer = blf_face_finalizer; + } + + return err; +} + +/* Use cache, not blf_get_char_index, to return glyph id from charcode. */ +uint blf_get_char_index(struct FontBLF *font, uint charcode) +{ + return FTC_CMapCache_Lookup(ftc_charmap_cache, font, -1, charcode); +} + +/* -------------------------------------------------------------------- */ /** \name FreeType Utilities (Internal) * \{ */ @@ -72,12 +123,12 @@ static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font); static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value) { /* Scale value by font size using integer-optimized multiplication. */ - FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale); + FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale); /* Copied from FreeType's FT_Get_Kerning (with FT_KERNING_DEFAULT), scaling down */ /* kerning distances at small ppem values so that they don't become too big. */ - if (font->face->size->metrics.x_ppem < 25) { - scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25); + if (font->ft_size->metrics.x_ppem < 25) { + scaled = FT_MulDiv(scaled, font->ft_size->metrics.x_ppem, 25); } return (ft_pix)scaled; @@ -296,7 +347,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph /* Small adjust if there is hinting. */ adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0); - if (FT_HAS_KERNING(font->face) && g_prev) { + if (FT_HAS_KERNING(font) && g_prev) { FT_Vector delta = {KERNING_ENTRY_UNSET}; /* Get unscaled kerning value from our cache if ASCII. */ @@ -305,7 +356,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph } /* If not ASCII or not found in cache, ask FreeType for kerning. */ - if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) { + if (UNLIKELY(font->face && delta.x == KERNING_ENTRY_UNSET)) { /* Note that this function sets delta values to zero on any error. */ FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta); } @@ -925,8 +976,7 @@ static void blf_font_wrap_apply(FontBLF *font, int lines = 0; ft_pix pen_x_next = 0; - /* Space between lines needs to be aligned to the pixel grid (T97310). */ - ft_pix line_height = FT_PIX_FLOOR(blf_font_height_max_ft_pix(font)); + ft_pix line_height = blf_font_height_max_ft_pix(font); GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); @@ -1090,7 +1140,7 @@ int blf_font_count_missing_chars(FontBLF *font, } else { c = BLI_str_utf8_as_unicode_step(str, str_len, &i); - if (FT_Get_Char_Index((font)->face, c) == 0) { + if (blf_get_char_index(font, c) == 0) { missing++; } } @@ -1107,18 +1157,8 @@ int blf_font_count_missing_chars(FontBLF *font, static ft_pix blf_font_height_max_ft_pix(FontBLF *font) { - ft_pix height_max; - FT_Face face = font->face; - if (FT_IS_SCALABLE(face)) { - height_max = ft_pix_from_int((int)(face->ascender - face->descender) * - (int)face->size->metrics.y_ppem) / - (ft_pix)face->units_per_EM; - } - else { - height_max = (ft_pix)face->size->metrics.height; - } - /* can happen with size 1 fonts */ - return MAX2(height_max, ft_pix_from_int(1)); + /* Metrics.height is rounded to pixel. Force minimum of one pixel. */ + return MAX2((ft_pix)font->ft_size->metrics.height, ft_pix_from_int(1)); } int blf_font_height_max(FontBLF *font) @@ -1128,18 +1168,8 @@ int blf_font_height_max(FontBLF *font) static ft_pix blf_font_width_max_ft_pix(FontBLF *font) { - ft_pix width_max; - const FT_Face face = font->face; - if (FT_IS_SCALABLE(face)) { - width_max = ft_pix_from_int((int)(face->bbox.xMax - face->bbox.xMin) * - (int)face->size->metrics.x_ppem) / - (ft_pix)face->units_per_EM; - } - else { - width_max = (ft_pix)face->size->metrics.max_advance; - } - /* can happen with size 1 fonts */ - return MAX2(width_max, ft_pix_from_int(1)); + /* Metrics.max_advance is rounded to pixel. Force minimum of one pixel. */ + return MAX2((ft_pix)font->ft_size->metrics.max_advance, ft_pix_from_int(1)); } int blf_font_width_max(FontBLF *font) @@ -1149,12 +1179,12 @@ int blf_font_width_max(FontBLF *font) int blf_font_descender(FontBLF *font) { - return ft_pix_to_int((ft_pix)font->face->size->metrics.descender); + return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender); } int blf_font_ascender(FontBLF *font) { - return ft_pix_to_int((ft_pix)font->face->size->metrics.ascender); + return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender); } char *blf_display_name(FontBLF *font) @@ -1176,13 +1206,31 @@ int blf_font_init(void) memset(&g_batch, 0, sizeof(g_batch)); BLI_spin_init(&ft_lib_mutex); BLI_spin_init(&blf_glyph_cache_mutex); - return FT_Init_FreeType(&ft_lib); + int err = FT_Init_FreeType(&ft_lib); + if (err == FT_Err_Ok) { + err = FTC_Manager_New(ft_lib, + BLF_CACHE_MAX_FACES, + BLF_CACHE_MAX_SIZES, + BLF_CACHE_BYTES, + blf_cache_face_requester, + NULL, + &ftc_manager); + if (err == FT_Err_Ok) { + err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache); + } + } + return err; } void blf_font_exit(void) { - FT_Done_FreeType(ft_lib); BLI_spin_end(&ft_lib_mutex); + if (ftc_manager) { + FTC_Manager_Done(ftc_manager); + } + if (ft_lib) { + FT_Done_FreeType(ft_lib); + } BLI_spin_end(&blf_glyph_cache_mutex); blf_batch_draw_exit(); } @@ -1261,12 +1309,7 @@ bool blf_ensure_face(FontBLF *font) FT_Error err; - if (font->filepath) { - err = FT_New_Face(ft_lib, font->filepath, 0, &font->face); - } - if (font->mem) { - err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face); - } + err = FTC_Manager_LookupFace(ftc_manager, font, &font->face); if (err) { if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) { @@ -1306,7 +1349,9 @@ bool blf_ensure_face(FontBLF *font) } } - if (FT_HAS_MULTIPLE_MASTERS(font->face)) { + font->face_flags = font->face->face_flags; + + if (FT_HAS_MULTIPLE_MASTERS(font)) { FT_Get_MM_Var(font->face, &(font->variations)); } @@ -1319,11 +1364,11 @@ bool blf_ensure_face(FontBLF *font) font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4; } - if (FT_IS_FIXED_WIDTH(font->face)) { + if (FT_IS_FIXED_WIDTH(font)) { font->flags |= BLF_MONOSPACED; } - if (FT_HAS_KERNING(font->face) && !font->kerning_cache) { + if (FT_HAS_KERNING(font) && !font->kerning_cache) { /* Create kerning cache table and fill with value indicating "unset". */ font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__); for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) { @@ -1438,7 +1483,9 @@ void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, const siz open.flags = FT_OPEN_MEMORY; open.memory_base = (const FT_Byte *)mem; open.memory_size = (FT_Long)mem_size; - FT_Attach_Stream(font->face, &open); + if (blf_ensure_face(font)) { + FT_Attach_Stream(font->face, &open); + } } void blf_font_free(FontBLF *font) @@ -1454,7 +1501,8 @@ void blf_font_free(FontBLF *font) } if (font->face) { - FT_Done_Face(font->face); + FTC_Manager_RemoveFaceID(ftc_manager, font); + font->face = NULL; } if (font->filepath) { MEM_freeN(font->filepath); @@ -1482,17 +1530,23 @@ bool blf_font_size(FontBLF *font, float size, unsigned int dpi) /* Adjust our new size to be on even 64ths. */ size = (float)ft_size / 64.0f; - if (font->size != size || font->dpi != dpi) { - if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) == FT_Err_Ok) { - font->size = size; - font->dpi = dpi; - } - else { - printf("The current font does not support the size, %f and DPI, %u\n", size, dpi); - return false; - } + FTC_ScalerRec scaler = {0}; + scaler.face_id = font; + scaler.width = 0; + scaler.height = ft_size; + scaler.pixel = 0; + scaler.x_res = dpi; + scaler.y_res = dpi; + + if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) != FT_Err_Ok) { + printf("The current font don't support the size, %f and dpi, %u\n", size, dpi); + return false; } + font->size = size; + font->dpi = dpi; + font->ft_size->generic.data = (void *)font; + return true; } |