Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarley Acheson <harley.acheson@gmail.com>2022-08-04 23:05:19 +0300
committerHarley Acheson <harley.acheson@gmail.com>2022-08-04 23:05:19 +0300
commit9d77b5a0ed7bed48dcb7483e79945067666eac0b (patch)
tree21acf2c4dd9665568c4d41761485f3bf3952b929 /source/blender/blenfont/intern/blf_font.c
parentfca7cb01011a3e34d21fcff6800d0b26b2be6e8e (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.c168
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;
}