1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-21 06:53:01 +08:00
lvgl/src/lv_font/lv_font_fmt_txt.c

258 lines
9.1 KiB
C
Raw Normal View History

2019-05-20 06:40:00 +02:00
/**
* @file lv_font.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_font.h"
2019-05-29 06:40:19 +02:00
#include "lv_font_fmt_txt.h"
#include "../lv_misc/lv_types.h"
#include "../lv_misc/lv_log.h"
#include "../lv_misc/lv_utils.h"
2019-05-20 06:40:00 +02:00
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
2019-06-01 21:46:05 +02:00
static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter);
2019-06-02 11:56:57 +02:00
static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t gid_right);
2019-06-12 23:01:16 +02:00
static int32_t unicode_list_compare(const void * ref, const void * element);
static int32_t kern_pair_8_compare(const void * ref, const void * element);
static int32_t kern_pair_16_compare(const void * ref, const void * element);
2019-05-20 06:40:00 +02:00
/**********************
* STATIC VARIABLES
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Used as `get_glyph_bitmap` callback in LittelvGL's native font format if the font is uncompressed.
* @param font pointer to font
* @param unicode_letter an unicode letter which bitmap should be get
* @return pointer to the bitmap or NULL if not found
*/
2019-05-26 19:31:01 +02:00
const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unicode_letter)
2019-05-20 06:40:00 +02:00
{
2019-05-29 06:40:19 +02:00
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
2019-06-01 21:46:05 +02:00
uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
if(!gid) return false;
const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
2019-05-20 06:40:00 +02:00
2019-05-29 06:40:19 +02:00
if(gdsc) return &fdsc->glyph_bitmap[gdsc->bitmap_index];
2019-05-20 06:40:00 +02:00
/*If not returned earlier then the letter is not found in this font*/
return NULL;
}
/**
* Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed.
* @param font_p pointer to font
* @param dsc_out store the result descriptor here
* @param letter an UNICODE letter code
* @return true: descriptor is successfully loaded into `dsc_out`.
* false: the letter was not found, no data is loaded to `dsc_out`
*/
2019-05-29 06:40:19 +02:00
bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
2019-05-20 06:40:00 +02:00
{
2019-05-29 06:40:19 +02:00
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
2019-06-01 21:46:05 +02:00
uint32_t gid = get_glyph_dsc_id(font, unicode_letter);
if(!gid) return false;
2019-06-02 11:56:57 +02:00
int8_t kvalue = 0;
2019-06-01 21:46:05 +02:00
if(fdsc->kern_dsc) {
uint32_t gid_next = get_glyph_dsc_id(font, unicode_letter_next);
if(gid_next) {
kvalue = get_kern_value(font, gid, gid_next);
2019-05-20 06:40:00 +02:00
}
2019-06-01 21:46:05 +02:00
}
2019-05-20 06:40:00 +02:00
2019-06-01 21:46:05 +02:00
/*Put together a glyph dsc*/
const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];
2019-05-29 06:40:19 +02:00
2019-06-05 15:16:43 +02:00
uint32_t adv_w = gdsc->adv_w + ((int32_t)((int32_t)kvalue * fdsc->kern_scale) >> 4);
adv_w = (adv_w + (1 << 3)) >> 4;
2019-05-29 06:40:19 +02:00
2019-06-05 15:16:43 +02:00
dsc_out->adv_w = adv_w;
2019-06-01 21:46:05 +02:00
dsc_out->box_h = gdsc->box_h;
dsc_out->box_w = gdsc->box_w;
dsc_out->ofs_x = gdsc->ofs_x;
dsc_out->ofs_y = gdsc->ofs_y;
dsc_out->bpp = fdsc->bpp;
2019-05-29 06:40:19 +02:00
2019-06-01 21:46:05 +02:00
return true;
2019-05-20 06:40:00 +02:00
}
/**********************
* STATIC FUNCTIONS
**********************/
2019-06-01 21:46:05 +02:00
static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter)
2019-05-29 06:40:19 +02:00
{
2019-06-01 21:46:05 +02:00
if(letter == '\0') return 0;
2019-05-29 06:40:19 +02:00
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
2019-07-29 16:19:30 +02:00
/*Check the cache first*/
2019-06-14 06:24:02 +02:00
if(letter == fdsc->last_letter) return fdsc->last_glyph_id;
2019-05-29 06:40:19 +02:00
uint16_t i;
for(i = 0; i < fdsc->cmap_num; i++) {
/*Relative code point*/
uint32_t rcp = letter - fdsc->cmaps[i].range_start;
2019-06-01 21:46:05 +02:00
if(rcp > fdsc->cmaps[i].range_length) continue;
2019-05-29 06:40:19 +02:00
uint32_t glyph_id = 0;
if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY) {
glyph_id = fdsc->cmaps[i].glyph_id_start + rcp;
}
2019-06-01 21:46:05 +02:00
else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL) {
2019-06-02 11:56:57 +02:00
const uint8_t * gid_ofs_8 = fdsc->cmaps[i].glyph_id_ofs_list;
glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_8[rcp];
2019-06-01 21:46:05 +02:00
}
2019-06-02 11:56:57 +02:00
else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_TINY) {
2019-06-12 23:01:16 +02:00
uint8_t * p = lv_utils_bsearch(&rcp, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
if(p) {
uint32_t ofs = (lv_uintptr_t)p - (lv_uintptr_t) fdsc->cmaps[i].unicode_list;
2019-06-12 23:01:16 +02:00
ofs = ofs >> 1; /*The list stores `uint16_t` so the get the index divide by 2*/
glyph_id = fdsc->cmaps[i].glyph_id_start + ofs;
2019-06-02 11:56:57 +02:00
}
}
2019-06-12 23:01:16 +02:00
else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_FULL) {
uint8_t * p = lv_utils_bsearch(&rcp, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare);
if(p) {
uint32_t ofs = (lv_uintptr_t)p - (lv_uintptr_t) fdsc->cmaps[i].unicode_list;
2019-06-12 23:01:16 +02:00
ofs = ofs >> 1; /*The list stores `uint16_t` so the get the index divide by 2*/
const uint8_t * gid_ofs_16 = fdsc->cmaps[i].glyph_id_ofs_list;
glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_16[ofs];
2019-06-02 11:56:57 +02:00
}
2019-06-01 21:46:05 +02:00
}
2019-05-29 06:40:19 +02:00
/*Update the cache*/
fdsc->last_letter = letter;
fdsc->last_glyph_id = glyph_id;
2019-06-01 21:46:05 +02:00
return glyph_id;
2019-05-29 06:40:19 +02:00
}
fdsc->last_letter = letter;
fdsc->last_glyph_id = 0;
2019-06-01 21:46:05 +02:00
return 0;
}
2019-06-02 11:56:57 +02:00
static int8_t get_kern_value(const lv_font_t * font, uint32_t gid_left, uint32_t gid_right)
2019-06-01 21:46:05 +02:00
{
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
2019-05-29 06:40:19 +02:00
2019-06-02 11:56:57 +02:00
int8_t value = 0;
2019-06-12 23:01:16 +02:00
2019-06-02 11:56:57 +02:00
if(fdsc->kern_classes == 0) {
/*Kern pairs*/
const lv_font_fmt_txt_kern_pair_t * kdsc = fdsc->kern_dsc;
2019-06-05 12:28:31 +02:00
if(kdsc->glyph_ids_size == 0) {
2019-06-12 23:01:16 +02:00
/* Use binary search to find the kern value.
* The pairs are ordered left_id first, then right_id secondly. */
2019-06-02 11:56:57 +02:00
const uint8_t * g_ids = kdsc->glyph_ids;
2019-06-12 23:01:16 +02:00
uint16_t g_id_both = (gid_right << 8) + gid_left; /*Create one number from the ids*/
uint8_t * kid_p = lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 2, kern_pair_8_compare);
/*If the `g_id_both` were found get its index from the pointer*/
if(kid_p) {
uint32_t ofs = (lv_uintptr_t)kid_p - (lv_uintptr_t)g_ids;
2019-06-12 23:01:16 +02:00
ofs = ofs >> 1; /*ofs is for pair, divide by 2 to refer as a single value*/
value = kdsc->values[ofs];
2019-06-02 11:56:57 +02:00
}
2019-06-05 12:28:31 +02:00
} else if(kdsc->glyph_ids_size == 1) {
2019-06-12 23:01:16 +02:00
/* Use binary search to find the kern value.
* The pairs are ordered left_id first, then right_id secondly. */
2019-06-02 11:56:57 +02:00
const uint16_t * g_ids = kdsc->glyph_ids;
2019-06-12 23:01:16 +02:00
uint32_t g_id_both = (uint32_t)((uint32_t)gid_right << 8) + gid_left; /*Create one number from the ids*/
uint8_t * kid_p = lv_utils_bsearch(&g_id_both, g_ids, kdsc->pair_cnt, 4, kern_pair_16_compare);
/*If the `g_id_both` were found get its index from the pointer*/
if(kid_p) {
uint32_t ofs = (lv_uintptr_t)kid_p - (lv_uintptr_t)g_ids;
2019-06-12 23:01:16 +02:00
ofs = ofs >> 4; /*ofs is 4 byte pairs, divide by 4 to refer as a single value*/
value = kdsc->values[ofs];
2019-06-02 11:56:57 +02:00
}
2019-06-12 23:01:16 +02:00
2019-06-05 12:28:31 +02:00
} else {
/*Invalid value*/
2019-06-02 11:56:57 +02:00
}
} else {
/*Kern classes*/
const lv_font_fmt_txt_kern_classes_t * kdsc = fdsc->kern_dsc;
uint8_t left_class = kdsc->left_class_mapping[gid_left];
uint8_t right_class = kdsc->left_class_mapping[gid_right];
/* If class = 0, kerning not exist for that glyph
* else got the value form `class_pair_values` 2D array*/
if(left_class > 0 && right_class > 0) {
value = kdsc->class_pair_values[(left_class-1)* kdsc->right_class_cnt + (right_class-1)];
}
}
return value;
2019-05-29 06:40:19 +02:00
}
2019-06-12 23:01:16 +02:00
static int32_t kern_pair_8_compare(const void * ref, const void * element)
{
const uint8_t * ref8_p = ref;
const uint8_t * element8_p = element;
/*If the MSB is different it will matter. If not return the diff. of the LSB*/
if(ref8_p[0] != element8_p[0]) return (int32_t)ref8_p[0] - element8_p[0];
else return (int32_t) ref8_p[1] - element8_p[1];
}
static int32_t kern_pair_16_compare(const void * ref, const void * element)
{
const uint16_t * ref16_p = ref;
const uint16_t * element16_p = element;
/*If the MSB is different it will matter. If not return the diff. of the LSB*/
if(ref16_p[0] != element16_p[0]) return (int32_t)ref16_p[0] - element16_p[0];
else return (int32_t) ref16_p[1] - element16_p[1];
}
2019-05-29 06:40:19 +02:00
2019-05-20 06:40:00 +02:00
/** Code Comparator.
*
* Compares the value of both input arguments.
*
* @param[in] pRef Pointer to the reference.
* @param[in] pElement Pointer to the element to compare.
*
* @return Result of comparison.
* @retval < 0 Reference is greater than element.
* @retval = 0 Reference is equal to element.
* @retval > 0 Reference is less than element.
*
*/
2019-06-12 23:01:16 +02:00
static int32_t unicode_list_compare(const void * ref, const void * element)
{
return (*(uint16_t *)ref) - (*(uint16_t *)element);
}