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:
Diffstat (limited to 'source/blender/blenfont')
-rw-r--r--source/blender/blenfont/BLF_api.h2
-rw-r--r--source/blender/blenfont/intern/blf.c20
-rw-r--r--source/blender/blenfont/intern/blf_font.c196
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c15
-rw-r--r--source/blender/blenfont/intern/blf_internal.h16
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c15
6 files changed, 226 insertions, 38 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 75824ae056f..d3226a8f609 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -353,6 +353,8 @@ enum {
BLF_LAST_RESORT = 1 << 15,
/** Failure to load this font. Don't try again. */
BLF_BAD_FONT = 1 << 16,
+ /** This font is managed by the FreeType cache subsystem. */
+ BLF_CACHED = 1 << 17,
};
#define BLF_DRAW_STR_DUMMY_MAX 1024
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 36475321d4c..6fcb74e9cb0 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -22,6 +22,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_string.h"
#include "BLI_threads.h"
#include "BLF_api.h"
@@ -885,12 +886,21 @@ void BLF_draw_buffer(int fontid, const char *str, const size_t str_len)
char *BLF_display_name_from_file(const char *filepath)
{
- FontBLF *font = blf_font_new("font_name", filepath);
- if (!font) {
- return NULL;
+ /* While listing font directories this function can be called simultaneously from a greater
+ * number of threads than we want the FreeType cache to keep open at a time. Therefore open
+ * with own FT_Library object and use FreeType calls directly to avoid any contention. */
+ char *name = NULL;
+ FT_Library ft_library;
+ if (FT_Init_FreeType(&ft_library) == FT_Err_Ok) {
+ FT_Face face;
+ if (FT_New_Face(ft_library, filepath, 0, &face) == FT_Err_Ok) {
+ if (face->family_name) {
+ name = BLI_sprintfN("%s %s", face->family_name, face->style_name);
+ }
+ FT_Done_Face(face);
+ }
+ FT_Done_FreeType(ft_library);
}
- char *name = blf_display_name(font);
- blf_font_free(font);
return name;
}
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;
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index f938174f92e..fdf9883ee8f 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -103,6 +103,7 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
}
else {
/* Font does not have a face or does not contain "0" so use CSS fallback of 1/2 of em. */
+ blf_ensure_size(font);
gc->fixed_width = (int)((font->ft_size->metrics.height / 2) >> 6);
}
if (gc->fixed_width < 1) {
@@ -570,6 +571,11 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode
return glyph_index;
}
+ /* Only fonts managed by the cache can fallback. */
+ if (!((*font)->flags & BLF_CACHED)) {
+ return 0;
+ }
+
/* Not found in main font, so look in the others. */
FontBLF *last_resort = NULL;
int coverage_bit = blf_charcode_to_coverage_bit(charcode);
@@ -787,8 +793,8 @@ static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool mo
{
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
/* Fake bold if the font does not have this variable axis. */
- const FT_Pos average_width = FT_MulFix(glyph->face->units_per_EM,
- glyph->face->size->metrics.x_scale);
+ const FontBLF *font = (FontBLF *)glyph->face->generic.data;
+ const FT_Pos average_width = font->ft_size->metrics.height;
FT_Pos change = (FT_Pos)((float)average_width * factor * 0.1f);
FT_Outline_EmboldenXY(&glyph->outline, change, change / 2);
if (monospaced) {
@@ -847,7 +853,8 @@ static bool blf_glyph_transform_width(FT_GlyphSlot glyph, float factor)
static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor)
{
if (glyph->advance.x > 0) {
- const long int size = glyph->face->size->metrics.height;
+ const FontBLF *font = (FontBLF *)glyph->face->generic.data;
+ const long int size = font->ft_size->metrics.height;
glyph->advance.x += (FT_Pos)(factor * (float)size / 6.0f);
return true;
}
@@ -899,6 +906,8 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
blf_font_size(glyph_font, settings_font->size, settings_font->dpi);
}
+ blf_ensure_size(glyph_font);
+
/* We need to keep track if changes are still needed. */
bool weight_done = false;
bool slant_done = false;
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 221e656f096..5c1099d6386 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -16,7 +16,14 @@ struct rcti;
/* Max number of FontBLFs in memory. Take care that every font has a glyph cache per size/dpi,
* so we don't need load the same font with different size, just load one and call BLF_size. */
-#define BLF_MAX_FONT 32
+#define BLF_MAX_FONT 64
+
+/* Maximum number of opened FT_Face objects managed by cache. 0 is default of 2. */
+#define BLF_CACHE_MAX_FACES 4
+/* Maximum number of opened FT_Size objects managed by cache. 0 is default of 4 */
+#define BLF_CACHE_MAX_SIZES 8
+/* Maximum number of bytes to use for cached data nodes. 0 is default of 200,000. */
+#define BLF_CACHE_BYTES 400000
extern struct FontBLF *global_font[BLF_MAX_FONT];
@@ -42,10 +49,17 @@ bool blf_font_id_is_valid(int fontid);
uint blf_get_char_index(struct FontBLF *font, uint charcode);
bool blf_ensure_face(struct FontBLF *font);
+void blf_ensure_size(struct FontBLF *font);
void blf_draw_buffer__start(struct FontBLF *font);
void blf_draw_buffer__end(void);
+struct FontBLF *blf_font_new_ex(const char *name,
+ const char *filepath,
+ const unsigned char *mem,
+ size_t mem_size,
+ void *ft_library);
+
struct FontBLF *blf_font_new(const char *name, const char *filepath);
struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, size_t mem_size);
void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, size_t mem_size);
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index 9460e9413d1..676d5ab2362 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -46,12 +46,20 @@ void BLF_thumb_preview(const char *filepath,
/* shrink 1/th each line */
int font_shrink = 4;
- FontBLF *font;
+ /* While viewing thumbnails in font directories this function can be called simultaneously from a
+ * greater number of threads than we want the FreeType cache to keep open at a time. Therefore
+ * pass own FT_Library to font creation so that it is not managed by the FreeType cache system.
+ */
- /* Create a new blender font obj and fill it with default values */
- font = blf_font_new("thumb_font", filepath);
+ FT_Library ft_library = NULL;
+ if (FT_Init_FreeType(&ft_library) != FT_Err_Ok) {
+ return;
+ }
+
+ FontBLF *font = blf_font_new_ex("thumb_font", filepath, NULL, 0, ft_library);
if (!font) {
printf("Info: Can't load font '%s', no preview possible\n", filepath);
+ FT_Done_FreeType(ft_library);
return;
}
@@ -102,4 +110,5 @@ void BLF_thumb_preview(const char *filepath,
blf_draw_buffer__end();
blf_font_free(font);
+ FT_Done_FreeType(ft_library);
}