mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-24 08:16:29 +08:00
feat(freetype): refactoring freetype to make glyph dsc independent (#5131)
This commit is contained in:
+2
-1
@@ -50,7 +50,8 @@ typedef struct {
|
||||
uint8_t bpp: 4; /**< Bit-per-pixel: 1, 2, 4, 8*/
|
||||
uint8_t is_placeholder: 1; /** Glyph is missing. But placeholder will still be displayed */
|
||||
|
||||
lv_cache_entry_t * entry;
|
||||
uint32_t glyph_index; /**< The index of the glyph in the font file. Used by the font cache*/
|
||||
lv_cache_entry_t * entry; /**< The cache entry of the glyph draw data. Used by the font cache*/
|
||||
} lv_font_glyph_dsc_t;
|
||||
|
||||
/** The bitmaps might be upscaled by 3 to achieve subpixel rendering.*/
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @file lv_freetype_glyph.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_freetype_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#if LV_USE_FREETYPE
|
||||
|
||||
#define LV_FREETYPE_GLYPH_DSC_CACHE_SIZE (LV_FREETYPE_CACHE_FT_OUTLINES * 2)
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct _lv_freetype_glyph_cache_data_t {
|
||||
uint32_t unicode;
|
||||
uint32_t size;
|
||||
|
||||
lv_font_glyph_dsc_t glyph_dsc;
|
||||
} lv_freetype_glyph_cache_data_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool freetype_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc, uint32_t unicode_letter,
|
||||
uint32_t unicode_letter_next);
|
||||
|
||||
static bool freetype_glyph_create_cb(lv_freetype_glyph_cache_data_t * data, void * user_data);
|
||||
static void freetype_glyph_free_cb(lv_freetype_glyph_cache_data_t * data, void * user_data);
|
||||
static lv_cache_compare_res_t freetype_glyph_compare_cb(const lv_freetype_glyph_cache_data_t * lhs,
|
||||
const lv_freetype_glyph_cache_data_t * rhs);
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
lv_cache_t * lv_freetype_glyph_cache_create(lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
|
||||
lv_cache_ops_t ops = {
|
||||
.create_cb = (lv_cache_create_cb_t)freetype_glyph_create_cb,
|
||||
.free_cb = (lv_cache_free_cb_t)freetype_glyph_free_cb,
|
||||
.compare_cb = (lv_cache_compare_cb_t)freetype_glyph_compare_cb,
|
||||
};
|
||||
|
||||
lv_cache_t * cache = lv_cache_create(&lv_cache_class_lru_rb_count
|
||||
, sizeof(lv_freetype_glyph_cache_data_t),
|
||||
LV_FREETYPE_GLYPH_DSC_CACHE_SIZE,
|
||||
ops
|
||||
);
|
||||
if(cache == NULL) {
|
||||
LV_LOG_ERROR("lv_cache_create failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dsc->font.get_glyph_dsc = freetype_get_glyph_dsc_cb;
|
||||
return cache;
|
||||
}
|
||||
|
||||
void lv_freetype_glyph_cache_delete(lv_cache_t * cache)
|
||||
{
|
||||
lv_cache_destroy(cache, NULL);
|
||||
}
|
||||
|
||||
static bool freetype_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc, uint32_t unicode_letter,
|
||||
uint32_t unicode_letter_next)
|
||||
{
|
||||
LV_ASSERT_NULL(font);
|
||||
LV_ASSERT_NULL(g_dsc);
|
||||
|
||||
if(unicode_letter < 0x20) {
|
||||
g_dsc->adv_w = 0;
|
||||
g_dsc->box_h = 0;
|
||||
g_dsc->box_w = 0;
|
||||
g_dsc->ofs_x = 0;
|
||||
g_dsc->ofs_y = 0;
|
||||
g_dsc->bpp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)font->dsc;
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
|
||||
lv_freetype_glyph_cache_data_t search_key = {
|
||||
.unicode = unicode_letter,
|
||||
.size = dsc->size,
|
||||
};
|
||||
|
||||
lv_cache_t * glyph_cache = lv_freetype_get_glyph_cache(dsc);
|
||||
|
||||
lv_cache_entry_t * entry = lv_cache_acquire_or_create(glyph_cache, &search_key, dsc);
|
||||
if(entry == NULL) {
|
||||
LV_LOG_ERROR("glyph lookup failed for unicode = %u", unicode_letter);
|
||||
return false;
|
||||
}
|
||||
lv_freetype_glyph_cache_data_t * data = lv_cache_entry_get_data(entry);
|
||||
*g_dsc = data->glyph_dsc;
|
||||
|
||||
if((dsc->style & LV_FREETYPE_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) {
|
||||
g_dsc->adv_w = g_dsc->box_w + g_dsc->ofs_x;
|
||||
}
|
||||
|
||||
g_dsc->entry = NULL;
|
||||
|
||||
lv_cache_release(glyph_cache, entry, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/*-----------------
|
||||
* Cache Callbacks
|
||||
*----------------*/
|
||||
|
||||
static bool freetype_glyph_create_cb(lv_freetype_glyph_cache_data_t * data, void * user_data)
|
||||
{
|
||||
lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)user_data;
|
||||
|
||||
FT_Error error;
|
||||
|
||||
FT_Size ft_size = lv_freetype_lookup_size(dsc);
|
||||
if(!ft_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lv_font_glyph_dsc_t * dsc_out = &data->glyph_dsc;
|
||||
|
||||
FT_Face face = ft_size->face;
|
||||
FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap);
|
||||
FT_UInt glyph_index = FTC_CMapCache_Lookup(dsc->context->cmap_cache, dsc->face_id, charmap_index, data->unicode);
|
||||
|
||||
FT_Set_Pixel_Sizes(face, 0, dsc->size);
|
||||
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_COMPUTE_METRICS | FT_LOAD_NO_BITMAP);
|
||||
if(error) {
|
||||
FT_ERROR_MSG("FT_Load_Glyph", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
FT_GlyphSlot glyph = ft_size->face->glyph;
|
||||
|
||||
#if LV_FREETYPE_CACHE_TYPE == LV_FREETYPE_CACHE_TYPE_OUTLINE
|
||||
dsc_out->adv_w = FT_F26DOT6_TO_INT(glyph->metrics.horiAdvance);
|
||||
dsc_out->box_h = FT_F26DOT6_TO_INT(glyph->metrics.height); /*Height of the bitmap in [px]*/
|
||||
dsc_out->box_w = FT_F26DOT6_TO_INT(glyph->metrics.width); /*Width of the bitmap in [px]*/
|
||||
dsc_out->ofs_x = FT_F26DOT6_TO_INT(glyph->metrics.horiBearingX); /*X offset of the bitmap in [pf]*/
|
||||
dsc_out->ofs_y = FT_F26DOT6_TO_INT(glyph->metrics.horiBearingY -
|
||||
glyph->metrics.height); /*Y offset of the bitmap measured from the as line*/
|
||||
#elif LV_FREETYPE_CACHE_TYPE == LV_FREETYPE_CACHE_TYPE_BITMAP
|
||||
FT_Bitmap * glyph_bitmap = &ft_size->face->glyph->bitmap;
|
||||
|
||||
dsc_out->adv_w = FT_F26DOT6_TO_INT(glyph->advance.x); /*Width of the glyph in [pf]*/
|
||||
dsc_out->box_h = glyph_bitmap->rows; /*Height of the bitmap in [px]*/
|
||||
dsc_out->box_w = glyph_bitmap->width; /*Width of the bitmap in [px]*/
|
||||
dsc_out->ofs_x = glyph->bitmap_left; /*X offset of the bitmap in [pf]*/
|
||||
dsc_out->ofs_y = glyph->bitmap_top -
|
||||
dsc_out->box_h; /*Y offset of the bitmap measured from the as line*/
|
||||
#endif
|
||||
|
||||
dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
|
||||
dsc_out->is_placeholder = glyph_index == 0;
|
||||
dsc_out->glyph_index = glyph_index;
|
||||
|
||||
return true;
|
||||
}
|
||||
static void freetype_glyph_free_cb(lv_freetype_glyph_cache_data_t * data, void * user_data)
|
||||
{
|
||||
LV_UNUSED(data);
|
||||
LV_UNUSED(user_data);
|
||||
}
|
||||
static lv_cache_compare_res_t freetype_glyph_compare_cb(const lv_freetype_glyph_cache_data_t * lhs,
|
||||
const lv_freetype_glyph_cache_data_t * rhs)
|
||||
{
|
||||
if(lhs->unicode != rhs->unicode) {
|
||||
return lhs->unicode > rhs->unicode ? 1 : -1;
|
||||
}
|
||||
if(lhs->size != rhs->size) {
|
||||
return lhs->size > rhs->size ? 1 : -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -20,36 +20,32 @@
|
||||
**********************/
|
||||
|
||||
struct _lv_freetype_cache_context_t {
|
||||
lv_cache_t * cache;
|
||||
|
||||
FT_Face face;
|
||||
};
|
||||
|
||||
struct _lv_freetype_cache_node_t {
|
||||
FT_Face face;
|
||||
lv_cache_t * image_cache;
|
||||
lv_cache_t * glyph_cache;
|
||||
};
|
||||
|
||||
typedef struct _lv_freetype_image_cache_data_t {
|
||||
FT_UInt glyph_index;
|
||||
uint32_t size;
|
||||
|
||||
lv_font_glyph_dsc_t glyph_dsc;
|
||||
lv_draw_buf_t * draw_buf;
|
||||
};
|
||||
} lv_freetype_image_cache_data_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static bool freetype_get_glyph_dsc_cb(const lv_font_t * font,
|
||||
lv_font_glyph_dsc_t * dsc_out,
|
||||
uint32_t unicode_letter,
|
||||
uint32_t unicode_letter_next);
|
||||
|
||||
static const uint8_t * freetype_get_glyph_bitmap_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc,
|
||||
uint32_t unicode_letter,
|
||||
uint8_t * bitmap_out);
|
||||
|
||||
static bool freetype_image_create_cb(lv_freetype_cache_node_t * data, void * user_data);
|
||||
static void freetype_image_free_cb(lv_freetype_cache_node_t * node, void * user_data);
|
||||
static lv_cache_compare_res_t freetype_image_compare_cb(const lv_freetype_cache_node_t * lhs,
|
||||
const lv_freetype_cache_node_t * rhs);
|
||||
static bool freetype_image_create_cb(lv_freetype_image_cache_data_t * data, void * user_data);
|
||||
static void freetype_image_free_cb(lv_freetype_image_cache_data_t * node, void * user_data);
|
||||
static lv_cache_compare_res_t freetype_image_compare_cb(const lv_freetype_image_cache_data_t * lhs,
|
||||
const lv_freetype_image_cache_data_t * rhs);
|
||||
|
||||
static void freetype_image_release_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc);
|
||||
/**********************
|
||||
@@ -72,34 +68,18 @@ lv_freetype_cache_context_t * lv_freetype_cache_context_create(lv_freetype_conte
|
||||
LV_ASSERT_MALLOC(cache_ctx);
|
||||
lv_memzero(cache_ctx, sizeof(lv_freetype_cache_context_t));
|
||||
|
||||
lv_cache_ops_t ops = {
|
||||
.compare_cb = (lv_cache_compare_cb_t)freetype_image_compare_cb,
|
||||
.create_cb = (lv_cache_create_cb_t)freetype_image_create_cb,
|
||||
.free_cb = (lv_cache_free_cb_t)freetype_image_free_cb,
|
||||
};
|
||||
|
||||
cache_ctx->cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(lv_freetype_cache_node_t),
|
||||
LV_FREETYPE_CACHE_FT_OUTLINES, ops);
|
||||
if(cache_ctx->cache == NULL) {
|
||||
LV_LOG_ERROR("lv_cache_create failed");
|
||||
lv_free(cache_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cache_ctx;
|
||||
}
|
||||
|
||||
void lv_freetype_cache_context_delete(lv_freetype_cache_context_t * cache_ctx)
|
||||
{
|
||||
LV_ASSERT_NULL(cache_ctx);
|
||||
lv_cache_destroy(cache_ctx->cache, NULL);
|
||||
lv_free(cache_ctx);
|
||||
}
|
||||
|
||||
bool lv_freetype_on_font_create(lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
dsc->font.get_glyph_dsc = freetype_get_glyph_dsc_cb;
|
||||
dsc->font.get_glyph_bitmap = freetype_get_glyph_bitmap_cb;
|
||||
dsc->font.release_glyph = freetype_image_release_cb;
|
||||
|
||||
@@ -113,70 +93,50 @@ bool lv_freetype_on_font_create(lv_freetype_font_dsc_t * dsc)
|
||||
if(dsc->style & LV_FREETYPE_FONT_STYLE_ITALIC) {
|
||||
lv_freetype_italic_transform(face);
|
||||
}
|
||||
|
||||
lv_freetype_cache_node_t * cache_node = lv_malloc_zeroed(sizeof(lv_freetype_cache_node_t));
|
||||
if(cache_node == NULL) {
|
||||
LV_LOG_ERROR("cache_node alloc failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
lv_cache_ops_t ops = {
|
||||
.compare_cb = (lv_cache_compare_cb_t)freetype_image_compare_cb,
|
||||
.create_cb = (lv_cache_create_cb_t)freetype_image_create_cb,
|
||||
.free_cb = (lv_cache_free_cb_t)freetype_image_free_cb,
|
||||
};
|
||||
|
||||
cache_node->image_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(lv_freetype_image_cache_data_t),
|
||||
LV_FREETYPE_CACHE_FT_OUTLINES, ops);
|
||||
cache_node->glyph_cache = lv_freetype_glyph_cache_create(dsc);
|
||||
if(cache_node->image_cache == NULL || cache_node->glyph_cache == NULL) {
|
||||
LV_LOG_ERROR("lv_cache_create failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dsc->cache_node = cache_node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void lv_freetype_on_font_delete(lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
lv_cache_destroy(dsc->cache_node->image_cache, NULL);
|
||||
lv_freetype_glyph_cache_delete(dsc->cache_node->glyph_cache);
|
||||
lv_free(dsc->cache_node);
|
||||
}
|
||||
|
||||
lv_cache_t * lv_freetype_get_glyph_cache(const lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
return dsc->cache_node->glyph_cache;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static bool freetype_get_glyph_dsc_cb(const lv_font_t * font,
|
||||
lv_font_glyph_dsc_t * dsc_out,
|
||||
uint32_t unicode_letter,
|
||||
uint32_t unicode_letter_next)
|
||||
{
|
||||
if(unicode_letter < 0x20) {
|
||||
dsc_out->adv_w = 0;
|
||||
dsc_out->box_h = 0;
|
||||
dsc_out->box_w = 0;
|
||||
dsc_out->ofs_x = 0;
|
||||
dsc_out->ofs_y = 0;
|
||||
dsc_out->bpp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)font->dsc;
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
|
||||
FT_Size ft_size = lv_freetype_lookup_size(dsc);
|
||||
if(!ft_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FT_Face face = ft_size->face;
|
||||
FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap);
|
||||
FT_UInt glyph_index = FTC_CMapCache_Lookup(dsc->context->cmap_cache, dsc->face_id, charmap_index, unicode_letter);
|
||||
dsc_out->is_placeholder = glyph_index == 0;
|
||||
dsc->context->cache_context->face = face;
|
||||
|
||||
lv_freetype_cache_node_t search_key = {
|
||||
.glyph_index = glyph_index,
|
||||
.size = dsc->size,
|
||||
};
|
||||
|
||||
lv_cache_entry_t * entry = lv_cache_acquire_or_create(dsc->context->cache_context->cache, &search_key, dsc);
|
||||
if(entry == NULL) {
|
||||
LV_LOG_ERROR("glyph lookup failed for glyph_index = %u", glyph_index);
|
||||
return false;
|
||||
}
|
||||
lv_freetype_cache_node_t * data = lv_cache_entry_get_data(entry);
|
||||
*dsc_out = data->glyph_dsc;
|
||||
|
||||
if((dsc->style & LV_FREETYPE_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) {
|
||||
dsc_out->adv_w = dsc_out->box_w + dsc_out->ofs_x;
|
||||
}
|
||||
|
||||
dsc_out->entry = NULL;
|
||||
|
||||
lv_cache_release(dsc->context->cache_context->cache, entry, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const uint8_t * freetype_get_glyph_bitmap_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc,
|
||||
uint32_t unicode_letter,
|
||||
uint8_t * bitmap_out)
|
||||
@@ -195,19 +155,19 @@ static const uint8_t * freetype_get_glyph_bitmap_cb(const lv_font_t * font, lv_f
|
||||
FT_Face face = ft_size->face;
|
||||
FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap);
|
||||
FT_UInt glyph_index = FTC_CMapCache_Lookup(dsc->context->cmap_cache, dsc->face_id, charmap_index, unicode_letter);
|
||||
dsc->context->cache_context->face = face;
|
||||
dsc->cache_node->face = face;
|
||||
|
||||
lv_cache_t * cache = dsc->context->cache_context->cache;
|
||||
lv_cache_t * cache = dsc->cache_node->image_cache;
|
||||
|
||||
lv_freetype_cache_node_t search_key = {
|
||||
lv_freetype_image_cache_data_t search_key = {
|
||||
.glyph_index = glyph_index,
|
||||
.size = dsc->size
|
||||
.size = dsc->size,
|
||||
};
|
||||
|
||||
lv_cache_entry_t * entry = lv_cache_acquire_or_create(cache, &search_key, dsc);
|
||||
|
||||
g_dsc->entry = entry;
|
||||
lv_freetype_cache_node_t * cache_node = lv_cache_entry_get_data(entry);
|
||||
lv_freetype_image_cache_data_t * cache_node = lv_cache_entry_get_data(entry);
|
||||
|
||||
return cache_node->draw_buf->data;
|
||||
}
|
||||
@@ -216,7 +176,7 @@ static void freetype_image_release_cb(const lv_font_t * font, lv_font_glyph_dsc_
|
||||
{
|
||||
LV_ASSERT_NULL(font);
|
||||
lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)font->dsc;
|
||||
lv_cache_release(dsc->context->cache_context->cache, g_dsc->entry, NULL);
|
||||
lv_cache_release(dsc->cache_node->image_cache, g_dsc->entry, NULL);
|
||||
g_dsc->entry = NULL;
|
||||
}
|
||||
|
||||
@@ -224,13 +184,13 @@ static void freetype_image_release_cb(const lv_font_t * font, lv_font_glyph_dsc_
|
||||
* Cache Callbacks
|
||||
*----------------*/
|
||||
|
||||
static bool freetype_image_create_cb(lv_freetype_cache_node_t * data, void * user_data)
|
||||
static bool freetype_image_create_cb(lv_freetype_image_cache_data_t * data, void * user_data)
|
||||
{
|
||||
lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)user_data;
|
||||
|
||||
FT_Error error;
|
||||
|
||||
FT_Face face = dsc->context->cache_context->face;
|
||||
FT_Face face = dsc->cache_node->face;
|
||||
FT_Set_Pixel_Sizes(face, 0, dsc->size);
|
||||
error = FT_Load_Glyph(face, data->glyph_index, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL);
|
||||
if(error) {
|
||||
@@ -252,33 +212,26 @@ static bool freetype_image_create_cb(lv_freetype_cache_node_t * data, void * use
|
||||
|
||||
FT_BitmapGlyph glyph_bitmap = (FT_BitmapGlyph)glyph;
|
||||
|
||||
lv_font_glyph_dsc_t * dsc_out = &data->glyph_dsc;
|
||||
uint16_t box_h = glyph_bitmap->bitmap.rows; /*Height of the bitmap in [px]*/
|
||||
uint16_t box_w = glyph_bitmap->bitmap.width; /*Width of the bitmap in [px]*/
|
||||
|
||||
dsc_out->adv_w = FT_F16DOT16_TO_INT(glyph_bitmap->root.advance.x);
|
||||
dsc_out->box_h = glyph_bitmap->bitmap.rows; /*Height of the bitmap in [px]*/
|
||||
dsc_out->box_w = glyph_bitmap->bitmap.width; /*Width of the bitmap in [px]*/
|
||||
dsc_out->ofs_x = glyph_bitmap->left; /*X offset of the bitmap in [pf]*/
|
||||
dsc_out->ofs_y = glyph_bitmap->top -
|
||||
glyph_bitmap->bitmap.rows; /*Y offset of the bitmap measured from the as line*/
|
||||
dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
|
||||
uint32_t stride = lv_draw_buf_width_to_stride(box_w, LV_COLOR_FORMAT_A8);
|
||||
data->draw_buf = lv_draw_buf_create(box_w, box_h, LV_COLOR_FORMAT_A8, stride);
|
||||
|
||||
uint32_t stride = lv_draw_buf_width_to_stride(dsc_out->box_w, LV_COLOR_FORMAT_A8);
|
||||
data->draw_buf = lv_draw_buf_create(dsc_out->box_w, dsc_out->box_h, LV_COLOR_FORMAT_A8, stride);
|
||||
|
||||
for(int y = 0; y < dsc_out->box_h; ++y) {
|
||||
lv_memcpy((uint8_t *)(data->draw_buf->data) + y * stride, glyph_bitmap->bitmap.buffer + y * dsc_out->box_w,
|
||||
dsc_out->box_w);
|
||||
for(int y = 0; y < box_h; ++y) {
|
||||
lv_memcpy((uint8_t *)(data->draw_buf->data) + y * stride, glyph_bitmap->bitmap.buffer + y * box_w,
|
||||
box_w);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static void freetype_image_free_cb(lv_freetype_cache_node_t * data, void * user_data)
|
||||
static void freetype_image_free_cb(lv_freetype_image_cache_data_t * data, void * user_data)
|
||||
{
|
||||
LV_UNUSED(user_data);
|
||||
lv_draw_buf_destroy(data->draw_buf);
|
||||
}
|
||||
static lv_cache_compare_res_t freetype_image_compare_cb(const lv_freetype_cache_node_t * lhs,
|
||||
const lv_freetype_cache_node_t * rhs)
|
||||
static lv_cache_compare_res_t freetype_image_compare_cb(const lv_freetype_image_cache_data_t * lhs,
|
||||
const lv_freetype_image_cache_data_t * rhs)
|
||||
{
|
||||
if(lhs->glyph_index != rhs->glyph_index) {
|
||||
return lhs->glyph_index > rhs->glyph_index ? 1 : -1;
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
#define LV_FREETYPE_OUTLINE_REF_SIZE_DEF 128
|
||||
|
||||
#define LV_FREETYPE_GLYPH_DSC_CACHE_SIZE (LV_FREETYPE_CACHE_FT_OUTLINES * 2)
|
||||
|
||||
#if LV_FREETYPE_CACHE_FT_OUTLINES <= 0
|
||||
#error "LV_FREETYPE_CACHE_FT_OUTLINES must be greater than 0"
|
||||
#endif
|
||||
@@ -34,12 +32,6 @@ struct _lv_freetype_cache_context_t {
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
typedef struct _lv_freetype_glyph_dsc_node_t {
|
||||
FT_UInt glyph_index;
|
||||
uint32_t size;
|
||||
lv_font_glyph_dsc_t glyph_dsc;
|
||||
} lv_freetype_glyph_dsc_node_t;
|
||||
|
||||
struct _lv_freetype_cache_node_t {
|
||||
lv_freetype_cache_context_t * cache_context;
|
||||
|
||||
@@ -48,13 +40,12 @@ struct _lv_freetype_cache_node_t {
|
||||
lv_freetype_font_style_t style;
|
||||
FT_Face face;
|
||||
|
||||
/*glyph cache*/
|
||||
lv_cache_t * glyph_cache;
|
||||
|
||||
/*glyph outline cache*/
|
||||
lv_cache_t * glyph_outline_cache;
|
||||
int outline_cnt;
|
||||
|
||||
/*glyph size cache*/
|
||||
lv_cache_t * glyph_dsc_cache;
|
||||
int dsc_cnt;
|
||||
};
|
||||
|
||||
typedef struct _lv_freetype_outline_node_t {
|
||||
@@ -69,15 +60,12 @@ typedef struct _lv_freetype_outline_node_t {
|
||||
static lv_freetype_outline_t outline_create(lv_freetype_context_t * ctx, FT_Face face, FT_UInt glyph_index,
|
||||
uint32_t size, uint32_t strength);
|
||||
static lv_result_t outline_delete(lv_freetype_cache_context_t * cache_context, lv_freetype_outline_t outline);
|
||||
static bool freetype_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter,
|
||||
uint32_t unicode_letter_next);
|
||||
static const uint8_t * freetype_get_glyph_bitmap_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc,
|
||||
uint32_t unicode_letter,
|
||||
uint8_t * bitmap_out);
|
||||
static void freetype_release_glyph_cb(const lv_font_t * font, lv_font_glyph_dsc_t * g_dsc);
|
||||
|
||||
static lv_freetype_cache_node_t * lv_freetype_cache_node_lookup(lv_freetype_context_t * ctx, const char * pathname,
|
||||
lv_freetype_font_style_t style);
|
||||
static lv_freetype_cache_node_t * lv_freetype_cache_node_lookup(lv_freetype_font_dsc_t * dsc, const char * pathname);
|
||||
static void lv_freetype_cache_node_drop(lv_freetype_font_dsc_t * dsc);
|
||||
static lv_cache_entry_t * lv_freetype_outline_lookup(lv_freetype_font_dsc_t * dsc, uint32_t unicode_letter);
|
||||
|
||||
@@ -87,12 +75,6 @@ static void freetype_glyph_outline_free_cb(lv_freetype_outline_node_t * node, lv
|
||||
static lv_cache_compare_res_t freetype_glyph_outline_cmp_cb(const lv_freetype_outline_node_t * node_a,
|
||||
const lv_freetype_outline_node_t * node_b);
|
||||
|
||||
/*glyph dsc cache lru callbacks*/
|
||||
static bool freetype_glyph_dsc_create_cb(lv_freetype_glyph_dsc_node_t * glyph_dsc_node, lv_freetype_font_dsc_t * dsc);
|
||||
static void freetype_glyph_dsc_free_cb(lv_freetype_glyph_dsc_node_t * glyph_dsc_node, lv_freetype_font_dsc_t * dsc);
|
||||
static lv_cache_compare_res_t freetype_glyph_dsc_cmp_cb(const lv_freetype_glyph_dsc_node_t * node_a,
|
||||
const lv_freetype_glyph_dsc_node_t * node_b);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
@@ -142,8 +124,7 @@ void lv_freetype_cache_context_delete(lv_freetype_cache_context_t * cache_contex
|
||||
bool lv_freetype_on_font_create(lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
dsc->cache_node = lv_freetype_cache_node_lookup(dsc->context, lv_freetype_get_pathname(dsc->face_id), dsc->style);
|
||||
dsc->font.get_glyph_dsc = freetype_get_glyph_dsc_cb;
|
||||
dsc->cache_node = lv_freetype_cache_node_lookup(dsc, lv_freetype_get_pathname(dsc->face_id));
|
||||
dsc->font.get_glyph_bitmap = freetype_get_glyph_bitmap_cb;
|
||||
dsc->font.release_glyph = freetype_release_glyph_cb;
|
||||
return true;
|
||||
@@ -206,6 +187,12 @@ bool lv_freetype_is_outline_font(const lv_font_t * font)
|
||||
return true;
|
||||
}
|
||||
|
||||
lv_cache_t * lv_freetype_get_glyph_cache(const lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
return dsc->cache_node->glyph_cache;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -214,12 +201,13 @@ bool lv_freetype_is_outline_font(const lv_font_t * font)
|
||||
* FACE CACHE
|
||||
*------------------*/
|
||||
|
||||
static lv_freetype_cache_node_t * lv_freetype_cache_node_lookup(lv_freetype_context_t * ctx,
|
||||
const char * pathname, lv_freetype_font_style_t style)
|
||||
static lv_freetype_cache_node_t * lv_freetype_cache_node_lookup(lv_freetype_font_dsc_t * dsc, const char * pathname)
|
||||
{
|
||||
LV_ASSERT_NULL(ctx);
|
||||
LV_ASSERT_NULL(pathname);
|
||||
|
||||
lv_freetype_context_t * ctx = dsc->context;
|
||||
lv_freetype_font_style_t style = dsc->style;
|
||||
|
||||
lv_freetype_cache_context_t * cache_context = ctx->cache_context;
|
||||
|
||||
lv_freetype_cache_node_t * cache;
|
||||
@@ -269,20 +257,13 @@ static lv_freetype_cache_node_t * lv_freetype_cache_node_lookup(lv_freetype_cont
|
||||
cache->ref_cnt = 1;
|
||||
cache->cache_context = cache_context;
|
||||
|
||||
lv_cache_ops_t glyph_dsc_cache_ops = {
|
||||
.create_cb = (lv_cache_create_cb_t)freetype_glyph_dsc_create_cb,
|
||||
.free_cb = (lv_cache_free_cb_t)freetype_glyph_dsc_free_cb,
|
||||
.compare_cb = (lv_cache_compare_cb_t)freetype_glyph_dsc_cmp_cb,
|
||||
};
|
||||
lv_cache_ops_t glyph_outline_cache_ops = {
|
||||
.create_cb = (lv_cache_create_cb_t)freetype_glyph_outline_create_cb,
|
||||
.free_cb = (lv_cache_free_cb_t)freetype_glyph_outline_free_cb,
|
||||
.compare_cb = (lv_cache_compare_cb_t)freetype_glyph_outline_cmp_cb,
|
||||
};
|
||||
|
||||
cache->glyph_dsc_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(lv_freetype_glyph_dsc_node_t),
|
||||
LV_FREETYPE_GLYPH_DSC_CACHE_SIZE,
|
||||
glyph_dsc_cache_ops);
|
||||
cache->glyph_cache = lv_freetype_glyph_cache_create(dsc);
|
||||
cache->glyph_outline_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(lv_freetype_outline_node_t),
|
||||
LV_FREETYPE_CACHE_FT_OUTLINES,
|
||||
glyph_outline_cache_ops);
|
||||
@@ -315,112 +296,11 @@ static void lv_freetype_cache_node_drop(lv_freetype_font_dsc_t * dsc)
|
||||
lv_ll_t * cache_ll = &cache_node->cache_context->cache_ll;
|
||||
_lv_ll_remove(cache_ll, cache_node);
|
||||
|
||||
lv_cache_destroy(cache_node->glyph_dsc_cache, dsc);
|
||||
lv_cache_destroy(cache_node->glyph_outline_cache, dsc);
|
||||
lv_freetype_glyph_cache_delete(cache_node->glyph_cache);
|
||||
lv_free(cache_node);
|
||||
}
|
||||
|
||||
/*-------------------
|
||||
* GLYPH DSC CACHE
|
||||
*------------------*/
|
||||
|
||||
static bool freetype_glyph_dsc_create_cb(lv_freetype_glyph_dsc_node_t * glyph_dsc_node, lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
lv_font_glyph_dsc_t * dsc_out = &glyph_dsc_node->glyph_dsc;
|
||||
|
||||
FT_UInt glyph_index = glyph_dsc_node->glyph_index;
|
||||
/* cache miss, load dsc */
|
||||
FT_Size ft_size = lv_freetype_lookup_size(dsc);
|
||||
if(!ft_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FT_Error error = FT_Load_Glyph(ft_size->face, glyph_index, FT_LOAD_COMPUTE_METRICS | FT_LOAD_NO_BITMAP);
|
||||
if(error) {
|
||||
FT_ERROR_MSG("FT_Load_Glyph", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
LV_LOG_INFO("glyph_index = %u, cnt = %d", glyph_index, ++dsc->cache_node->dsc_cnt);
|
||||
|
||||
FT_GlyphSlot glyph = ft_size->face->glyph;
|
||||
|
||||
dsc_out->adv_w = FT_F26DOT6_TO_INT(glyph->metrics.horiAdvance);
|
||||
dsc_out->box_h = FT_F26DOT6_TO_INT(glyph->metrics.height); /*Height of the bitmap in [px]*/
|
||||
dsc_out->box_w = FT_F26DOT6_TO_INT(glyph->metrics.width); /*Width of the bitmap in [px]*/
|
||||
dsc_out->ofs_x = FT_F26DOT6_TO_INT(glyph->metrics.horiBearingX); /*X offset of the bitmap in [pf]*/
|
||||
dsc_out->ofs_y = FT_F26DOT6_TO_INT(glyph->metrics.horiBearingY -
|
||||
glyph->metrics.height); /*Y offset of the bitmap measured from the as line*/
|
||||
dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
|
||||
dsc_out->is_placeholder = glyph_index == 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void freetype_glyph_dsc_free_cb(lv_freetype_glyph_dsc_node_t * glyph_dsc_node, lv_freetype_font_dsc_t * dsc)
|
||||
{
|
||||
LV_UNUSED(glyph_dsc_node);
|
||||
LV_UNUSED(dsc);
|
||||
LV_LOG_INFO("cnt = %d", --dsc->cache_node->dsc_cnt);
|
||||
}
|
||||
|
||||
static lv_cache_compare_res_t freetype_glyph_dsc_cmp_cb(const lv_freetype_glyph_dsc_node_t * node_a,
|
||||
const lv_freetype_glyph_dsc_node_t * node_b)
|
||||
{
|
||||
if(node_a->glyph_index != node_b->glyph_index)
|
||||
return (node_a->glyph_index > node_b->glyph_index) ? 1 : -1;
|
||||
|
||||
if(node_a->size != node_b->size)
|
||||
return (node_a->size > node_b->size) ? 1 : -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool freetype_get_glyph_dsc_cb(const lv_font_t * font,
|
||||
lv_font_glyph_dsc_t * dsc_out,
|
||||
uint32_t unicode_letter,
|
||||
uint32_t unicode_letter_next)
|
||||
{
|
||||
LV_ASSERT_NULL(font);
|
||||
LV_ASSERT_NULL(dsc_out);
|
||||
|
||||
if(unicode_letter < 0x20) {
|
||||
dsc_out->adv_w = 0;
|
||||
dsc_out->box_h = 0;
|
||||
dsc_out->box_w = 0;
|
||||
dsc_out->ofs_x = 0;
|
||||
dsc_out->ofs_y = 0;
|
||||
dsc_out->bpp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
lv_freetype_font_dsc_t * dsc = (lv_freetype_font_dsc_t *)font->dsc;
|
||||
LV_ASSERT_FREETYPE_FONT_DSC(dsc);
|
||||
|
||||
lv_freetype_cache_node_t * cache_node = dsc->cache_node;
|
||||
|
||||
FT_UInt charmap_index = FT_Get_Charmap_Index(cache_node->face->charmap);
|
||||
FT_UInt glyph_index = FTC_CMapCache_Lookup(dsc->context->cmap_cache, dsc->face_id, charmap_index, unicode_letter);
|
||||
|
||||
lv_freetype_glyph_dsc_node_t tmp_node;
|
||||
tmp_node.glyph_index = glyph_index;
|
||||
tmp_node.size = dsc->size;
|
||||
|
||||
lv_cache_entry_t * entry = lv_cache_acquire_or_create(cache_node->glyph_dsc_cache, &tmp_node, dsc);
|
||||
if(entry == NULL) {
|
||||
return false;
|
||||
}
|
||||
lv_freetype_glyph_dsc_node_t * new_node = lv_cache_entry_get_data(entry);
|
||||
*dsc_out = new_node->glyph_dsc;
|
||||
|
||||
if((dsc->style & LV_FREETYPE_FONT_STYLE_ITALIC) && (unicode_letter_next == '\0')) {
|
||||
dsc_out->adv_w = dsc_out->box_w + dsc_out->ofs_x;
|
||||
}
|
||||
lv_cache_release(cache_node->glyph_dsc_cache, entry, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-------------------
|
||||
* OUTLINE CACHE
|
||||
*------------------*/
|
||||
|
||||
@@ -105,6 +105,10 @@ lv_freetype_cache_context_t * lv_freetype_cache_context_create(lv_freetype_conte
|
||||
|
||||
void lv_freetype_cache_context_delete(lv_freetype_cache_context_t * cache_ctx);
|
||||
|
||||
lv_cache_t * lv_freetype_glyph_cache_create(lv_freetype_font_dsc_t * dsc);
|
||||
|
||||
void lv_freetype_glyph_cache_delete(lv_cache_t * cache);
|
||||
|
||||
bool lv_freetype_on_font_create(lv_freetype_font_dsc_t * dsc);
|
||||
|
||||
void lv_freetype_on_font_delete(lv_freetype_font_dsc_t * dsc);
|
||||
@@ -113,6 +117,8 @@ void lv_freetype_italic_transform(FT_Face face);
|
||||
|
||||
const char * lv_freetype_get_pathname(FTC_FaceID face_id);
|
||||
|
||||
lv_cache_t * lv_freetype_get_glyph_cache(const lv_freetype_font_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
Reference in New Issue
Block a user