diff options
Diffstat (limited to 'source/blender/blenfont/intern/blf_font.c')
-rw-r--r-- | source/blender/blenfont/intern/blf_font.c | 196 |
1 files changed, 170 insertions, 26 deletions
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 226752bffd8..f820ec14507 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. */ @@ -55,6 +56,8 @@ BatchBLF g_batch; /* freetype2 handle ONLY for this file! */ static FT_Library ft_lib = NULL; +static FTC_Manager ftc_manager = NULL; +static FTC_CMapCache ftc_charmap_cache = NULL; /* Lock for FreeType library, used around face creation and deletion. */ static ThreadMutex ft_lib_mutex; @@ -67,19 +70,75 @@ static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font); /* -------------------------------------------------------------------- */ -/* Return glyph id from charcode. */ -uint blf_get_char_index(struct FontBLF *font, uint charcode) +/** \name FreeType Caching + * \{ */ + +/* Called when a face is removed by the cache. FreeType will call FT_Done_Face. */ +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. Now 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_mutex_lock(&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_mutex_unlock(&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; +} + +/* Called when the FreeType cache is removing a font size. */ +static void blf_size_finalizer(void *object) { - return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0; + FT_Size size = object; + FontBLF *font = (FontBLF *)size->generic.data; + font->ft_size = NULL; } /* -------------------------------------------------------------------- */ /** \name FreeType Utilities (Internal) * \{ */ +/* Return glyph id from charcode. */ +uint blf_get_char_index(struct FontBLF *font, uint charcode) +{ + if (font->flags & BLF_CACHED) { + /* Use charmap cache for much faster lookup. */ + return FTC_CMapCache_Lookup(ftc_charmap_cache, font, -1, charcode); + } + else { + /* Fonts that are not cached need to use the regular lookup function. */ + return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0; + } +} + /* Convert a FreeType 26.6 value representing an unscaled design size to fractional pixels. */ static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value) { + /* Make sure we have a valid font->ft_size. */ + blf_ensure_size(font); + /* Scale value by font size using integer-optimized multiplication. */ FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale); @@ -1115,6 +1174,7 @@ int blf_font_count_missing_chars(FontBLF *font, static ft_pix blf_font_height_max_ft_pix(FontBLF *font) { + blf_ensure_size(font); /* 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)); } @@ -1126,6 +1186,7 @@ int blf_font_height_max(FontBLF *font) static ft_pix blf_font_width_max_ft_pix(FontBLF *font) { + blf_ensure_size(font); /* 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)); } @@ -1137,11 +1198,13 @@ int blf_font_width_max(FontBLF *font) int blf_font_descender(FontBLF *font) { + blf_ensure_size(font); return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender); } int blf_font_ascender(FontBLF *font) { + blf_ensure_size(font); return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender); } @@ -1164,12 +1227,29 @@ int blf_font_init(void) memset(&g_batch, 0, sizeof(g_batch)); BLI_mutex_init(&ft_lib_mutex); int err = FT_Init_FreeType(&ft_lib); + if (err == FT_Err_Ok) { + /* Create a FreeType cache manager. */ + 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) { + /* Create a charmap cache to speed up glyph index lookups. */ + err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache); + } + } return err; } void blf_font_exit(void) { BLI_mutex_end(&ft_lib_mutex); + if (ftc_manager) { + FTC_Manager_Done(ftc_manager); + } if (ft_lib) { FT_Done_FreeType(ft_lib); } @@ -1229,8 +1309,6 @@ static void blf_font_fill(FontBLF *font) font->buf_info.col_init[1] = 0; font->buf_info.col_init[2] = 0; font->buf_info.col_init[3] = 0; - - font->ft_lib = ft_lib; } /** @@ -1248,14 +1326,20 @@ bool blf_ensure_face(FontBLF *font) FT_Error err; - BLI_mutex_lock(&ft_lib_mutex); - if (font->filepath) { - err = FT_New_Face(ft_lib, font->filepath, 0, &font->face); + if (font->flags & BLF_CACHED) { + err = FTC_Manager_LookupFace(ftc_manager, font, &font->face); } - if (font->mem) { - err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face); + else { + BLI_mutex_lock(&ft_lib_mutex); + if (font->filepath) { + err = FT_New_Face(font->ft_lib, font->filepath, 0, &font->face); + } + if (font->mem) { + err = FT_New_Memory_Face(font->ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face); + } + font->face->generic.data = font; + BLI_mutex_unlock(&ft_lib_mutex); } - BLI_mutex_unlock(&ft_lib_mutex); if (err) { if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) { @@ -1295,7 +1379,11 @@ bool blf_ensure_face(FontBLF *font) } } - font->ft_size = font->face->size; + if (!(font->flags & BLF_CACHED)) { + /* Not cached so point at the face's size for convenience. */ + font->ft_size = font->face->size; + } + font->face_flags = font->face->face_flags; if (FT_HAS_MULTIPLE_MASTERS(font)) { @@ -1366,11 +1454,16 @@ static const eFaceDetails static_face_details[] = { {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0}, }; -/* Create a new font from filename OR from passed memory pointer. */ -static FontBLF *blf_font_new_ex(const char *name, - const char *filepath, - const unsigned char *mem, - const size_t mem_size) +/** + * Create a new font from filename OR memory pointer. + * For normal operation pass NULL as FT_Library object. Pass a custom FT_Library if you + * want to use the font without its lifetime being managed by the FreeType cache subsystem. + */ +FontBLF *blf_font_new_ex(const char *name, + const char *filepath, + const unsigned char *mem, + const size_t mem_size, + void *ft_library) { FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); @@ -1382,6 +1475,16 @@ static FontBLF *blf_font_new_ex(const char *name, } blf_font_fill(font); + if (ft_library && ((FT_Library)ft_library != ft_lib)) { + font->ft_lib = (FT_Library)ft_library; + } + else { + font->ft_lib = ft_lib; + font->flags |= BLF_CACHED; + } + + font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib; + BLI_mutex_init(&font->glyph_cache_mutex); /* If we have static details about this font file, we don't have to load the Face yet. */ @@ -1422,12 +1525,12 @@ static FontBLF *blf_font_new_ex(const char *name, FontBLF *blf_font_new(const char *name, const char *filename) { - return blf_font_new_ex(name, filename, NULL, 0); + return blf_font_new_ex(name, filename, NULL, 0, NULL); } FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, const size_t mem_size) { - return blf_font_new_ex(name, NULL, mem, mem_size); + return blf_font_new_ex(name, NULL, mem, mem_size, NULL); } void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, const size_t mem_size) @@ -1451,12 +1554,17 @@ void blf_font_free(FontBLF *font) } if (font->variations) { - FT_Done_MM_Var(ft_lib, font->variations); + FT_Done_MM_Var(font->ft_lib, font->variations); } if (font->face) { BLI_mutex_lock(&ft_lib_mutex); - FT_Done_Face(font->face); + if (font->flags & BLF_CACHED) { + FTC_Manager_RemoveFaceID(ftc_manager, font); + } + else { + FT_Done_Face(font->face); + } BLI_mutex_unlock(&ft_lib_mutex); font->face = NULL; } @@ -1478,6 +1586,28 @@ void blf_font_free(FontBLF *font) /** \name Font Configure * \{ */ +void blf_ensure_size(FontBLF *font) +{ + if (font->ft_size || !(font->flags & BLF_CACHED)) { + return; + } + + FTC_ScalerRec scaler = {0}; + scaler.face_id = font; + scaler.width = 0; + scaler.height = round_fl_to_uint(font->size * 64.0f); + scaler.pixel = 0; + scaler.x_res = font->dpi; + scaler.y_res = font->dpi; + if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) == FT_Err_Ok) { + font->ft_size->generic.data = (void *)font; + font->ft_size->generic.finalizer = blf_size_finalizer; + return; + } + + BLI_assert_unreachable(); +} + bool blf_font_size(FontBLF *font, float size, unsigned int dpi) { if (!blf_ensure_face(font)) { @@ -1490,16 +1620,30 @@ bool blf_font_size(FontBLF *font, float size, unsigned int dpi) 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; + if (font->flags & BLF_CACHED) { + 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) { + return false; + } + font->ft_size->generic.data = (void *)font; + font->ft_size->generic.finalizer = blf_size_finalizer; } else { - printf("The current font does not support the size, %f and DPI, %u\n", size, dpi); - return false; + if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) != FT_Err_Ok) { + return false; + } + font->ft_size = font->face->size; } } + font->size = size; + font->dpi = dpi; return true; } |