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
This commit is contained in:
parent
fca7cb0101
commit
9d77b5a0ed
Notes:
blender-bot
2023-02-14 00:44:02 +01:00
Referenced by commitd3c653c6d9
, BLF: Revert FreeType Cache Referenced by commit8b46731396
, Fix Build Warnings in blf_font.c
|
@ -122,7 +122,7 @@ bool BLF_has_glyph(int fontid, unsigned int unicode)
|
|||
{
|
||||
FontBLF *font = blf_get(fontid);
|
||||
if (font) {
|
||||
return FT_Get_Char_Index(font->face, unicode) != FT_Err_Ok;
|
||||
return blf_get_char_index(font, unicode) != FT_Err_Ok;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -64,6 +68,53 @@ static void (*blf_draw_cache_flush)(void) = NULL;
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,16 +94,16 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
|
|||
memset(gc->bucket, 0, sizeof(gc->bucket));
|
||||
|
||||
/* Determine ideal fixed-width size for monospaced output. */
|
||||
FT_UInt gindex = FT_Get_Char_Index(font->face, U'0');
|
||||
if (gindex) {
|
||||
FT_UInt gindex = blf_get_char_index(font, U'0');
|
||||
if (gindex && font->face) {
|
||||
FT_Fixed advance = 0;
|
||||
FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance);
|
||||
/* Use CSS 'ch unit' width, advance of zero character. */
|
||||
gc->fixed_width = (int)(advance >> 16);
|
||||
}
|
||||
else {
|
||||
/* Font does not contain "0" so use CSS fallback of 1/2 of em. */
|
||||
gc->fixed_width = (int)((font->face->size->metrics.height / 2) >> 6);
|
||||
/* Font does not have a face or does not contain "0" so use CSS fallback of 1/2 of em. */
|
||||
gc->fixed_width = (int)((font->ft_size->metrics.height / 2) >> 6);
|
||||
}
|
||||
if (gc->fixed_width < 1) {
|
||||
gc->fixed_width = 1;
|
||||
|
@ -565,7 +565,7 @@ static bool blf_font_has_coverage_bit(FontBLF *font, int coverage_bit)
|
|||
*/
|
||||
static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode)
|
||||
{
|
||||
FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode);
|
||||
FT_UInt glyph_index = blf_get_char_index(*font, charcode);
|
||||
if (glyph_index) {
|
||||
return glyph_index;
|
||||
}
|
||||
|
@ -584,12 +584,10 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode
|
|||
continue;
|
||||
}
|
||||
if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) {
|
||||
if (blf_ensure_face(f)) {
|
||||
glyph_index = FT_Get_Char_Index(f->face, charcode);
|
||||
if (glyph_index) {
|
||||
*font = f;
|
||||
return glyph_index;
|
||||
}
|
||||
glyph_index = blf_get_char_index(f, charcode);
|
||||
if (glyph_index) {
|
||||
*font = f;
|
||||
return glyph_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -599,8 +597,8 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode
|
|||
#endif
|
||||
|
||||
/* Not found in the stack, return from Last Resort if there is one. */
|
||||
if (last_resort && blf_ensure_face(last_resort)) {
|
||||
glyph_index = FT_Get_Char_Index(last_resort->face, charcode);
|
||||
if (last_resort) {
|
||||
glyph_index = blf_get_char_index(last_resort, charcode);
|
||||
if (glyph_index) {
|
||||
*font = last_resort;
|
||||
return glyph_index;
|
||||
|
@ -789,8 +787,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) {
|
||||
|
@ -849,7 +847,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;
|
||||
}
|
||||
|
@ -898,13 +897,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
|
|||
int fixed_width)
|
||||
{
|
||||
if (glyph_font != settings_font) {
|
||||
FT_Set_Char_Size(glyph_font->face,
|
||||
0,
|
||||
((FT_F26Dot6)(settings_font->size)) * 64,
|
||||
settings_font->dpi,
|
||||
settings_font->dpi);
|
||||
glyph_font->size = settings_font->size;
|
||||
glyph_font->dpi = settings_font->dpi;
|
||||
blf_font_size(glyph_font, settings_font->size, settings_font->dpi);
|
||||
}
|
||||
|
||||
/* We need to keep track if changes are still needed. */
|
||||
|
@ -961,7 +954,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
|
|||
/* Fallback glyph transforms, but only if required and not yet done. */
|
||||
|
||||
if (weight != 0.0f && !weight_done) {
|
||||
blf_glyph_transform_weight(glyph, weight, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
|
||||
blf_glyph_transform_weight(glyph, weight, FT_IS_FIXED_WIDTH(glyph_font));
|
||||
}
|
||||
if (slant != 0.0f && !slant_done) {
|
||||
blf_glyph_transform_slant(glyph, slant);
|
||||
|
@ -990,11 +983,9 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
|
|||
FontBLF *font_with_glyph = font;
|
||||
FT_UInt glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode);
|
||||
|
||||
/* Glyphs are dynamically created as needed by font rendering. this means that
|
||||
* to make font rendering thread safe we have to do locking here. note that this
|
||||
* must be a lock for the whole library and not just per font, because the font
|
||||
* renderer uses a shared buffer internally. */
|
||||
BLI_spin_lock(font_with_glyph->ft_lib_mutex);
|
||||
if (!blf_ensure_face(font_with_glyph)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FT_GlyphSlot glyph = blf_glyph_render(
|
||||
font, font_with_glyph, glyph_index, charcode, gc->fixed_width);
|
||||
|
@ -1004,7 +995,6 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
|
|||
g = blf_glyph_cache_add_glyph(font, gc, glyph, charcode, glyph_index);
|
||||
}
|
||||
|
||||
BLI_spin_unlock(font_with_glyph->ft_lib_mutex);
|
||||
return g;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,16 @@ struct ResultBLF;
|
|||
struct rctf;
|
||||
struct rcti;
|
||||
|
||||
/* Max number of fonts in memory. Take care that every font has a glyph cache per size/dpi,
|
||||
/* 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 0
|
||||
/* Maximum number of opened FT_Size objects managed by cache. 0 is default of 4 */
|
||||
#define BLF_CACHE_MAX_SIZES 0
|
||||
/* Maximum number of bytes to use for cached data nodes. 0 is default of 200,000. */
|
||||
#define BLF_CACHE_BYTES 0
|
||||
|
||||
extern struct FontBLF *global_font[BLF_MAX_FONT];
|
||||
|
||||
|
@ -39,6 +46,8 @@ void blf_font_exit(void);
|
|||
|
||||
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_draw_buffer__start(struct FontBLF *font);
|
||||
|
|
|
@ -329,6 +329,12 @@ typedef struct FontBLF {
|
|||
/* freetype2 face. */
|
||||
FT_Face face;
|
||||
|
||||
/* FreeType size is separated from face when using their caching subsystem. */
|
||||
FT_Size ft_size;
|
||||
|
||||
/* Copy of the font->face->face_flags, in case we don't have a face loaded. */
|
||||
FT_Long face_flags;
|
||||
|
||||
/* data for buffer usage (drawing into a texture buffer) */
|
||||
FontBufInfoBLF buf_info;
|
||||
|
||||
|
|
Loading…
Reference in New Issue