1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

font: add kerning support

This commit is contained in:
Gabor Kiss-Vamosi 2019-05-01 16:43:32 +02:00
parent ed1632f464
commit 864c970ba3
9 changed files with 210 additions and 173 deletions

View File

@ -244,19 +244,18 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
return; return;
} }
const lv_font_glyph_dsc_t * g = lv_font_get_glyph_dsc(font_p, letter); lv_font_glyph_dsc_t g;
if(g == NULL) return; bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter);
lv_coord_t pos_x = pos_p->x + g->ofs_x; if(g_ret == false) return;
lv_coord_t pos_y = pos_p->y + g->ofs_y;
uint8_t bpp = lv_font_get_bpp(font_p, letter); /*Bit per pixel (1,2, 4 or 8)*/
lv_coord_t pos_x = pos_p->x + g.ofs_x;
lv_coord_t pos_y = pos_p->y + g.ofs_y;
const uint8_t * bpp_opa_table; const uint8_t * bpp_opa_table;
uint8_t bitmask_init; uint8_t bitmask_init;
uint8_t bitmask; uint8_t bitmask;
switch(bpp) { switch(g.bpp) {
case 1: case 1:
bpp_opa_table = bpp1_opa_table; bpp_opa_table = bpp1_opa_table;
bitmask_init = 0x80; bitmask_init = 0x80;
@ -281,7 +280,7 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
if(map_p == NULL) return; if(map_p == NULL) return;
/*If the letter is completely out of mask don't draw it */ /*If the letter is completely out of mask don't draw it */
if(pos_x + g->box_w < mask_p->x1 || pos_x > mask_p->x2 || pos_y + g->box_h < mask_p->y1 || if(pos_x + g.box_w < mask_p->x1 || pos_x > mask_p->x2 || pos_y + g.box_h < mask_p->y1 ||
pos_y > mask_p->y2) pos_y > mask_p->y2)
return; return;
@ -293,16 +292,16 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
lv_coord_t col, row; lv_coord_t col, row;
uint8_t col_bit; uint8_t col_bit;
uint8_t col_byte_cnt; uint8_t col_byte_cnt;
uint8_t width_byte_scr = g->box_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/ uint8_t width_byte_scr = g.box_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/
if(g->box_w & 0x7) width_byte_scr++; if(g.box_w & 0x7) width_byte_scr++;
uint8_t width_byte_bpp = (g->box_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/ uint8_t width_byte_bpp = (g.box_w * g.bpp) >> 3; /*Letter width in byte. Real width in the font*/
if((g->box_w * bpp) & 0x7) width_byte_bpp++; if((g.box_w * g.bpp) & 0x7) width_byte_bpp++;
/* Calculate the col/row start/end on the map*/ /* Calculate the col/row start/end on the map*/
lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x; lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x;
lv_coord_t col_end = pos_x + g->box_w <= mask_p->x2 ? g->box_w : mask_p->x2 - pos_x + 1; lv_coord_t col_end = pos_x + g.box_w <= mask_p->x2 ? g.box_w : mask_p->x2 - pos_x + 1;
lv_coord_t row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y; lv_coord_t row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y;
lv_coord_t row_end = pos_y + g->box_h <= mask_p->y2 ? g->box_h : mask_p->y2 - pos_y + 1; lv_coord_t row_end = pos_y + g.box_h <= mask_p->y2 ? g.box_h : mask_p->y2 - pos_y + 1;
/*Set a pointer on VDB to the first pixel of the letter*/ /*Set a pointer on VDB to the first pixel of the letter*/
vdb_buf_tmp += ((pos_y - vdb->area.y1) * vdb_width) + pos_x - vdb->area.x1; vdb_buf_tmp += ((pos_y - vdb->area.y1) * vdb_width) + pos_x - vdb->area.x1;
@ -311,21 +310,21 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
vdb_buf_tmp += (row_start * vdb_width) + col_start; vdb_buf_tmp += (row_start * vdb_width) + col_start;
/*Move on the map too*/ /*Move on the map too*/
map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3); map_p += (row_start * width_byte_bpp) + ((col_start * g.bpp) >> 3);
uint8_t letter_px; uint8_t letter_px;
lv_opa_t px_opa; lv_opa_t px_opa;
for(row = row_start; row < row_end; row++) { for(row = row_start; row < row_end; row++) {
col_byte_cnt = 0; col_byte_cnt = 0;
col_bit = (col_start * bpp) % 8; col_bit = (col_start * g.bpp) % 8;
bitmask = bitmask_init >> col_bit; bitmask = bitmask_init >> col_bit;
for(col = col_start; col < col_end; col++) { for(col = col_start; col < col_end; col++) {
letter_px = (*map_p & bitmask) >> (8 - col_bit - bpp); letter_px = (*map_p & bitmask) >> (8 - col_bit - g.bpp);
if(letter_px != 0) { if(letter_px != 0) {
if(opa == LV_OPA_COVER) { if(opa == LV_OPA_COVER) {
px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px]; px_opa = g.bpp == 8 ? letter_px : bpp_opa_table[letter_px];
} else { } else {
px_opa = bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8 px_opa = g.bpp == 8 ? (uint16_t)((uint16_t)letter_px * opa) >> 8
: (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8; : (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;
} }
@ -345,9 +344,9 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
vdb_buf_tmp++; vdb_buf_tmp++;
if(col_bit < 8 - bpp) { if(col_bit < 8 - g.bpp) {
col_bit += bpp; col_bit += g.bpp;
bitmask = bitmask >> bpp; bitmask = bitmask >> g.bpp;
} else { } else {
col_bit = 0; col_bit = 0;
col_byte_cnt++; col_byte_cnt++;

View File

@ -136,8 +136,10 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
cmd_state = CMD_STATE_WAIT; cmd_state = CMD_STATE_WAIT;
i = line_start; i = line_start;
uint32_t letter; uint32_t letter;
uint32_t letter_next;
while(i < line_end) { while(i < line_end) {
letter = lv_txt_encoded_next(txt, &i); letter = lv_txt_encoded_next(txt, &i);
letter_next = lv_txt_encoded_next(&txt[i], NULL);
/*Handle the re-color command*/ /*Handle the re-color command*/
if((flag & LV_TXT_FLAG_RECOLOR) != 0) { if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
@ -181,7 +183,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
if(cmd_state == CMD_STATE_IN) color = recolor; if(cmd_state == CMD_STATE_IN) color = recolor;
letter_w = lv_font_get_width_int(font, letter); letter_w = lv_font_get_glyph_width(font, letter, letter_next);
if(sel_start != 0xFFFF && sel_end != 0xFFFF) { if(sel_start != 0xFFFF && sel_end != 0xFFFF) {
int char_ind = lv_encoded_get_char_id(txt, i); int char_ind = lv_encoded_get_char_id(txt, i);

View File

@ -81,13 +81,19 @@ static const uint8_t lv_font_dejavu_20_glyph_bitmap[] = {
/*4 rows*/ /*4 rows*/
}; };
static const lv_font_kern_t kern_0031[] = {
{.next_unicode = 0x0033, .space = 3 << 4},
{.next_unicode = 0x0000} /*Trailing*/
};
/*Store the glyph descriptions*/ /*Store the glyph descriptions*/
static const lv_font_glyph_dsc_t lv_font_dejavu_20_glyph_dsc[] = { static const lv_font_glyph_dsc_built_in_t lv_font_dejavu_20_glyph_dsc[] = {
{.adv_w = LV_FONT_SET_ADV_W(6, 0), .box_w = 6, .box_h = 0, .ofs_x = 0, .ofs_y = 0, .bitmap_index = 0}, /*Unicode: U+0020 ( )*/ {.adv_w = LV_FONT_SET_WIDTH(6, 0), .box_w = 6, .box_h = 0, .ofs_x = 0, .ofs_y = 0, .bitmap_index = 0, }, /*Unicode: U+0020 ( )*/
{.adv_w = LV_FONT_SET_ADV_W(8, 0), .box_w = 8, .box_h = 13,.ofs_x = 0, .ofs_y = 3, .bitmap_index = 0}, /*Unicode: U+0031 (1)*/ {.adv_w = LV_FONT_SET_WIDTH(8, 0), .box_w = 8, .box_h = 13,.ofs_x = 0, .ofs_y = 3, .bitmap_index = 0, .kern_table = kern_0031}, /*Unicode: U+0031 (1)*/
{.adv_w = LV_FONT_SET_ADV_W(9, 0), .box_w = 9, .box_h = 13,.ofs_x = 0, .ofs_y = 3, .bitmap_index = 13}, /*Unicode: U+0033 (3)*/ {.adv_w = LV_FONT_SET_WIDTH(9, 0), .box_w = 9, .box_h = 13,.ofs_x = 0, .ofs_y = 3, .bitmap_index = 13}, /*Unicode: U+0033 (3)*/
{.adv_w = LV_FONT_SET_ADV_W(12, 0), .box_w = 12,.box_h = 13,.ofs_x = 0, .ofs_y = 3, .bitmap_index = 39}, /*Unicode: U+0041 (A)*/ {.adv_w = LV_FONT_SET_WIDTH(12, 0), .box_w = 12,.box_h = 13,.ofs_x = 0, .ofs_y = 3, .bitmap_index = 39}, /*Unicode: U+0041 (A)*/
{.adv_w = LV_FONT_SET_ADV_W(8, 0), .box_w = 8, .box_h = 10,.ofs_x = 0, .ofs_y = 6, .bitmap_index = 65}, /*Unicode: U+0061 (a)*/ {.adv_w = LV_FONT_SET_WIDTH(8, 0), .box_w = 8, .box_h = 10,.ofs_x = 0, .ofs_y = 6, .bitmap_index = 65}, /*Unicode: U+0061 (a)*/
}; };
static const uint16_t lv_font_dejavu_20_unicode_list[] = { static const uint16_t lv_font_dejavu_20_unicode_list[] = {
@ -99,10 +105,11 @@ static const uint16_t lv_font_dejavu_20_unicode_list[] = {
}; };
static lv_font_dsc_built_in_t lv_font_dejavu_20_dsc = { static lv_font_dsc_built_in_t lv_font_dejavu_20_dsc = {
.glyph_cnt = 5, /*Number of glyphs in the font*/ .glyph_cnt = 5, /*Number of glyphs in the font*/
.glyph_bitmap = lv_font_dejavu_20_glyph_bitmap, /*Bitmap of glyphs*/ .glyph_bitmap = lv_font_dejavu_20_glyph_bitmap, /*Bitmap of glyphs*/
.glyph_dsc = lv_font_dejavu_20_glyph_dsc, /*Description of glyphs*/ .glyph_dsc = lv_font_dejavu_20_glyph_dsc, /*Description of glyphs*/
.unicode_list = lv_font_dejavu_20_unicode_list, /*Every character in the font from 'unicode_first' to 'unicode_last'*/ .unicode_list = lv_font_dejavu_20_unicode_list, /*Every character in the font from 'unicode_first' to 'unicode_last'*/
.bpp = 1, /*Bit per pixel*/
}; };
lv_font_t lv_font_dejavu_20 = { lv_font_t lv_font_dejavu_20 = {
@ -111,7 +118,6 @@ lv_font_t lv_font_dejavu_20 = {
.dsc = &lv_font_dejavu_20_dsc, .dsc = &lv_font_dejavu_20_dsc,
.get_glyph_bitmap = lv_font_get_glyph_bitmap_plain, /*Function pointer to get glyph's bitmap*/ .get_glyph_bitmap = lv_font_get_glyph_bitmap_plain, /*Function pointer to get glyph's bitmap*/
.get_glyph_dsc = lv_font_get_glyph_dsc_plain, /*Function pointer to get glyph's width*/ .get_glyph_dsc = lv_font_get_glyph_dsc_plain, /*Function pointer to get glyph's width*/
.bpp = 1, /*Bit per pixel*/
.line_height = 20, /*Font height in pixels*/ .line_height = 20, /*Font height in pixels*/
.next_page = NULL, /*Pointer to a font extension*/ .next_page = NULL, /*Pointer to a font extension*/
}; };

View File

@ -102,62 +102,60 @@ const uint8_t * lv_font_get_glyph_bitmap(const lv_font_t * font_p, uint32_t lett
} }
/** /**
* Get the description of a glyph in a font. * Get the descriptor of a glyph
* @param font_p pointer to a font * @param font_p pointer to font
* @param letter an UNICODE character code * @param dsc_out store the result descriptor here
* @return pointer to a glyph descriptor * @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`
*/ */
const lv_font_glyph_dsc_t * lv_font_get_glyph_dsc(const lv_font_t * font_p, uint32_t letter) bool lv_font_get_glyph_dsc(const lv_font_t * font_p, lv_font_glyph_dsc_t * dsc_out, uint32_t letter)
{ {
const lv_font_t * font_i = font_p; const lv_font_t * font_i = font_p;
const lv_font_glyph_dsc_t * dsc; bool ret;
while(font_i != NULL) { while(font_i != NULL) {
dsc = font_i->get_glyph_dsc(font_i, letter); ret = font_i->get_glyph_dsc(font_i, dsc_out, letter);
if(dsc) { if(ret) return ret;
/*Glyph found*/
return dsc;
}
font_i = font_i->next_page; font_i = font_i->next_page;
} }
return NULL; return false;
}
uint8_t lv_font_get_width_int(const lv_font_t * font, uint32_t letter)
{
const lv_font_glyph_dsc_t * dsc = lv_font_get_glyph_dsc(font, letter);
return dsc ? LV_FONT_GET_ADV_W_INT(dsc->adv_w) : 0;
}
uint8_t lv_font_get_width_fract(const lv_font_t * font, uint32_t letter)
{
const lv_font_glyph_dsc_t * dsc = lv_font_get_glyph_dsc(font, letter);
return dsc ? LV_FONT_GET_ADV_W_FRACT(dsc->adv_w) : 0;
} }
/** /**
* Get the bit-per-pixel of font * Get the width of a glyph with kerning
* @param font pointer to font * @param font pointer to a font
* @param letter a letter from font (font extensions can have different bpp) * @param letter an UNICODE letter
* @return bpp of the font (or font extension) * @param letter_next the next letter after `letter`. Used for kerning
* @return the width of the glyph
*/ */
uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter) uint8_t lv_font_get_glyph_width(const lv_font_t * font, uint32_t letter, uint32_t letter_next)
{ {
const lv_font_t * font_i = font; lv_font_glyph_dsc_t dsc;
while(font_i != NULL) { bool ret = lv_font_get_glyph_dsc(font, &dsc, letter);
if(letter >= font_i->unicode_first && letter <= font_i->unicode_last) { if(ret == false) return 0;
return font_i->bpp;
int32_t w = dsc.adv_w;
/*Apply kerning is required*/
if(dsc.kern_table && letter_next != 0) {
uint32_t i;
for(i = 0; dsc.kern_table[i].next_unicode != 0; i++) {
if((uint32_t)dsc.kern_table[i].next_unicode == letter_next) {
w += dsc.kern_table[i].space;
break;
}
} }
font_i = font_i->next_page;
} }
return 0; if(w < 0) w = 0;
return w <= 0 ? 0 : LV_FONT_GET_WIDTH_INT(w);
} }
/** /**
* Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in * Used as `get_glyph_bitmap` callback in LittelvGL's native font format if the font is uncompressed.
* the range
* @param font pointer to font * @param font pointer to font
* @param unicode_letter an unicode letter which bitmap should be get * @param unicode_letter an unicode letter which bitmap should be get
* @return pointer to the bitmap or NULL if not found * @return pointer to the bitmap or NULL if not found
@ -190,23 +188,23 @@ const uint8_t * lv_font_get_glyph_bitmap_plain(const lv_font_t * font, uint32_t
} }
/** /**
* Generic glyph width get function used in 'font->get_width' when the font contains all characters * Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed.
* in the range * @param font_p pointer to font
* @param font pointer to font * @param dsc_out store the result descriptor here
* @param unicode_letter an unicode letter which width should be get * @param letter an UNICODE letter code
* @return width of the gylph or -1 if not found * @return true: descriptor is successfully loaded into `dsc_out`.
* false: the letter was not found, no data is loaded to `dsc_out`
*/ */
const lv_font_glyph_dsc_t * lv_font_get_glyph_dsc_plain(const lv_font_t * font, uint32_t unicode_letter) bool lv_font_get_glyph_dsc_plain(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter)
{ {
/*Check the range*/ /*Check the range*/
if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL; if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL;
lv_font_dsc_built_in_t * font_dsc = (lv_font_dsc_built_in_t *) font->dsc; lv_font_dsc_built_in_t * font_dsc = (lv_font_dsc_built_in_t *) font->dsc;
int32_t index = -1;
/*No Unicode list -> Continuous font*/ /*No Unicode list -> Continuous font*/
if(font_dsc->unicode_list == NULL) { if(font_dsc->unicode_list == NULL) {
uint32_t index = (unicode_letter - font->unicode_first); index = (unicode_letter - font->unicode_first);
return &font_dsc->glyph_dsc[index];
} }
/*Has Unicode list -> Sparse font */ /*Has Unicode list -> Sparse font */
else { else {
@ -215,13 +213,22 @@ const lv_font_glyph_dsc_t * lv_font_get_glyph_dsc_plain(const lv_font_t * font,
sizeof(font_dsc->unicode_list[0]), lv_font_codeCompare); sizeof(font_dsc->unicode_list[0]), lv_font_codeCompare);
if(pUnicode != NULL) { if(pUnicode != NULL) {
uint32_t idx = (uint16_t)(pUnicode - font_dsc->unicode_list); index = (uint16_t)(pUnicode - font_dsc->unicode_list);
return &font_dsc->glyph_dsc[idx];
} }
} }
/*If not returned earlier then the letter is not found in this font*/ if(index > 0) {
return NULL; dsc_out->adv_w = font_dsc->glyph_dsc[index].adv_w;
dsc_out->box_h = font_dsc->glyph_dsc[index].box_h;
dsc_out->box_w = font_dsc->glyph_dsc[index].box_w;
dsc_out->ofs_x = font_dsc->glyph_dsc[index].ofs_x;
dsc_out->ofs_y = font_dsc->glyph_dsc[index].ofs_y;
dsc_out->kern_table = font_dsc->glyph_dsc[index].kern_table;
dsc_out->bpp = font_dsc->bpp;
return true;
} else {
return false;
}
} }
/********************** /**********************

View File

@ -29,29 +29,27 @@ extern "C" {
* DEFINES * DEFINES
*********************/ *********************/
/*Number of fractional digits in the advanced width (`adv_w`) field of `lv_font_glyph_dsc_t`*/ /*Number of fractional digits in the advanced width (`adv_w`) field of `lv_font_glyph_dsc_t`*/
#define LV_FONT_ADV_W_FRACT_DIGIT 4 #define LV_FONT_WIDTH_FRACT_DIGIT 4
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
typedef struct {
int32_t next_unicode :23;
int32_t space :9; /*5 integer, 4 fractional*/
}lv_font_kern_t;
typedef struct typedef struct
{ {
uint32_t bitmap_index : 20; /* Start index of the bitmap. A font can be max 1 MB. */ uint16_t adv_w; /*The glyph needs this space. Draw the next glyph after this width. 8 bit integer, 4 bit fractional */
uint32_t adv_w :12; /*The glyph needs this space. Draw the next glyph after this width. 8 bit integer, 4 bit fractional */ uint8_t box_w; /*Width of the glyph's bounding box*/
uint8_t box_w; /*Width of the glyph's bounding box*/ uint8_t box_h; /*Height of the glyph's bounding box*/
uint8_t box_h; /*Height of the glyph's bounding box*/ int8_t ofs_x; /*x offset of the bounding box*/
uint8_t ofs_x; /*x offset of the bounding box*/ int8_t ofs_y; /*y offset of the bounding box*/
int8_t ofs_y; /*y offset of the bounding box*/ uint8_t bpp; /*Bit-per-pixel: 1, 2, 4, 8*/
} lv_font_glyph_dsc_t; const lv_font_kern_t * kern_table;
}lv_font_glyph_dsc_t;
typedef struct {
const uint8_t * glyph_bitmap;
const lv_font_glyph_dsc_t * glyph_dsc;
const uint16_t * unicode_list;
uint16_t glyph_cnt; /*Number of glyphs in the font. */
}lv_font_dsc_built_in_t;
typedef struct _lv_font_struct typedef struct _lv_font_struct
{ {
@ -59,21 +57,41 @@ typedef struct _lv_font_struct
uint32_t unicode_last; uint32_t unicode_last;
/*Get a glyph's descriptor from a font*/ /*Get a glyph's descriptor from a font*/
const lv_font_glyph_dsc_t * (*get_glyph_dsc)(const struct _lv_font_struct *, uint32_t letter); bool (*get_glyph_dsc)(const struct _lv_font_struct *, lv_font_glyph_dsc_t *, uint32_t letter);
/*Get a glyph's bitmap from a font*/ /*Get a glyph's bitmap from a font*/
const uint8_t * (*get_glyph_bitmap)(const struct _lv_font_struct *, uint32_t); const uint8_t * (*get_glyph_bitmap)(const struct _lv_font_struct *, uint32_t);
/*Pointer to the font in a font pack (must have the same line height)*/ /*Pointer to the font in a font pack (must have the same line height)*/
struct _lv_font_struct * next_page; struct _lv_font_struct * next_page;
uint8_t size; /*The original size*/ uint8_t size; /*The original size (height)*/
uint8_t line_height; /*The real line height where any text fits*/ uint8_t line_height; /*The real line height where any text fits*/
uint8_t base_line; /*Base line measured from the top of the line*/ uint8_t base_line; /*Base line measured from the top of the line_height*/
uint8_t bpp; /*Bit per pixel: 1, 2, 4 or 8*/
void * dsc; /*Store implementation specific data here*/ void * dsc; /*Store implementation specific data here*/
} lv_font_t; } lv_font_t;
typedef struct
{
uint32_t bitmap_index : 20; /* Start index of the bitmap. A font can be max 1 MB. */
uint32_t adv_w :12; /*The glyph needs this space. Draw the next glyph after this width. 8 bit integer, 4 bit fractional */
uint8_t box_w; /*Width of the glyph's bounding box*/
uint8_t box_h; /*Height of the glyph's bounding box*/
int8_t ofs_x; /*x offset of the bounding box*/
int8_t ofs_y; /*y offset of the bounding box*/
const lv_font_kern_t * kern_table;
}lv_font_glyph_dsc_built_in_t;
typedef struct {
const uint8_t * glyph_bitmap;
const lv_font_glyph_dsc_built_in_t * glyph_dsc;
const uint16_t * unicode_list;
uint16_t glyph_cnt; /*Number of glyphs in the font. */
uint8_t bpp; /*Bit per pixel: 1, 2, 4 or 8*/
}lv_font_dsc_built_in_t;
/********************** /**********************
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
@ -97,15 +115,6 @@ void lv_font_add(lv_font_t * child, lv_font_t * parent);
*/ */
void lv_font_remove(lv_font_t * child, lv_font_t * parent); void lv_font_remove(lv_font_t * child, lv_font_t * parent);
/**
* Tells if font which contains `letter` is monospace or not
* @param font_p point to font
* @param letter an UNICODE character code
* @return true: the letter is monospace; false not monospace
*/
bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter);
/** /**
* Return with the bitmap of a font. * Return with the bitmap of a font.
* @param font_p pointer to a font * @param font_p pointer to a font
@ -115,21 +124,23 @@ bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter);
const uint8_t * lv_font_get_glyph_bitmap(const lv_font_t * font_p, uint32_t letter); const uint8_t * lv_font_get_glyph_bitmap(const lv_font_t * font_p, uint32_t letter);
/** /**
* Get the description of a glyph in a font. * Get the descriptor of a glyph
* @param font_p pointer to a font * @param font_p pointer to font
* @param letter an UNICODE character code * @param dsc_out store the result descriptor here
* @return pointer to a glyph descriptor * @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`
*/ */
const lv_font_glyph_dsc_t * lv_font_get_glyph_dsc(const lv_font_t * font_p, uint32_t letter); bool lv_font_get_glyph_dsc(const lv_font_t * font_p, lv_font_glyph_dsc_t * dsc_out, uint32_t letter);
uint8_t lv_font_get_width_int(const lv_font_t * font, uint32_t letter);
/** /**
* Get the width of a letter in a font. If `monospace` is set then return with it. * Get the width of a glyph with kerning
* @param font_p pointer to a font * @param font pointer to a font
* @param letter an UNICODE character code * @param letter an UNICODE letter
* @return the width of a letter * @param letter_next the next letter after `letter`. Used for kerning
* @return the width of the glyph
*/ */
uint8_t lv_font_get_width_int(const lv_font_t * font_p, uint32_t letter); uint8_t lv_font_get_glyph_width(const lv_font_t * font, uint32_t letter, uint32_t letter_next);
/** /**
* Get the line height of a font. All characters fit into this height * Get the line height of a font. All characters fit into this height
@ -138,35 +149,26 @@ uint8_t lv_font_get_width_int(const lv_font_t * font_p, uint32_t letter);
*/ */
static inline uint8_t lv_font_get_line_height(const lv_font_t * font_p) static inline uint8_t lv_font_get_line_height(const lv_font_t * font_p)
{ {
return font_p->line_height;//(uint8_t)((int16_t)font_p->ascent - font_p->descent); return font_p->line_height;
} }
/** /**
* Get the bit-per-pixel of font * Used as `get_glyph_bitmap` callback in LittelvGL's native font format if the font is uncompressed.
* @param font pointer to font
* @param letter a letter from font (font extensions can have different bpp)
* @return bpp of the font (or font extension)
*/
uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter);
/**
* Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in
* the range
* @param font pointer to font * @param font pointer to font
* @param unicode_letter an unicode letter which bitmap should be get * @param unicode_letter an unicode letter which bitmap should be get
* @return pointer to the bitmap or NULL if not found * @return pointer to the bitmap or NULL if not found
*/ */
const uint8_t * lv_font_get_glyph_bitmap_plain(const lv_font_t * font, uint32_t unicode_letter); const uint8_t * lv_font_get_glyph_bitmap_plain(const lv_font_t * font, uint32_t letter);
/** /**
* Generic glyph width get function used in 'font->get_width' when the font contains all characters * Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed.
* in the range * @param font_p pointer to font
* @param font pointer to font * @param dsc_out store the result descriptor here
* @param unicode_letter an unicode letter which width should be get * @param letter an UNICODE letter code
* @return width of the gylph or -1 if not found * @return true: descriptor is successfully loaded into `dsc_out`.
* false: the letter was not found, no data is loaded to `dsc_out`
*/ */
const lv_font_glyph_dsc_t * lv_font_get_glyph_dsc_plain(const lv_font_t * font, uint32_t unicode_letter); bool lv_font_get_glyph_dsc_plain(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter);
/********************** /**********************
* MACROS * MACROS
@ -174,9 +176,9 @@ const lv_font_glyph_dsc_t * lv_font_get_glyph_dsc_plain(const lv_font_t * font,
#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name; #define LV_FONT_DECLARE(font_name) extern lv_font_t font_name;
#define LV_FONT_SET_ADV_W(_integer, _fract) ((_integer << LV_FONT_ADV_W_FRACT_DIGIT) + _fract) #define LV_FONT_SET_WIDTH(_integer, _fract) ((_integer << LV_FONT_WIDTH_FRACT_DIGIT) + _fract)
#define LV_FONT_GET_ADV_W_INT(_adv_w) (_adv_w >> LV_FONT_ADV_W_FRACT_DIGIT) #define LV_FONT_GET_WIDTH_INT(_w) (_w >> LV_FONT_WIDTH_FRACT_DIGIT)
#define LV_FONT_GET_ADV_W_FRACT(_adv_w) (_adv_w & ((1 << LV_FONT_ADV_W_FRACT_DIGIT) -1)) #define LV_FONT_GET_WIDTH_FRACT(_w) (_w & ((1 << LV_FONT_WIDTH_FRACT_DIGIT) -1))
/********************** /**********************

View File

@ -173,11 +173,13 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord
uint32_t n_char_since_last_break = 0; /* Used count word length of long words */ uint32_t n_char_since_last_break = 0; /* Used count word length of long words */
uint32_t last_break = NO_BREAK_FOUND; uint32_t last_break = NO_BREAK_FOUND;
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
uint32_t letter = 0; uint32_t letter;
uint32_t letter_next;
while(txt[i] != '\0') { while(txt[i] != '\0') {
lv_coord_t letter_width; lv_coord_t letter_width;
letter = lv_txt_encoded_next(txt, &i); letter = lv_txt_encoded_next(txt, &i);
letter_next = lv_txt_encoded_next(&txt[i], NULL);
/*Handle the recolor command*/ /*Handle the recolor command*/
if((flag & LV_TXT_FLAG_RECOLOR) != 0) { if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
@ -196,7 +198,7 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord
} else { /*Check the actual length*/ } else { /*Check the actual length*/
n_char_since_last_break++; n_char_since_last_break++;
letter_width = lv_font_get_width_int(font, letter); letter_width = lv_font_get_glyph_width(font, letter, letter_next);
cur_w += letter_width; cur_w += letter_width;
/* Get the length of the current work and determine best place /* Get the length of the current work and determine best place
@ -210,12 +212,12 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord
i = last_break; i = last_break;
} else { } else {
uint32_t i_tmp = i; uint32_t i_tmp = i;
cur_w -= /*ignore the first letter_space after the break char */
w_at_last_break + cur_w -= w_at_last_break + letter_space;
letter_space; /*ignore the first letter_space after the break char */
bool other = true; bool other = true;
while(txt[i_tmp] != '\0') { while(txt[i_tmp] != '\0') {
letter = lv_txt_encoded_next(txt, &i_tmp); letter = lv_txt_encoded_next(txt, &i_tmp);
letter_next = lv_txt_encoded_next(&txt[i_tmp], NULL);
/*Handle the recolor command*/ /*Handle the recolor command*/
if((flag & LV_TXT_FLAG_RECOLOR) != 0) { if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
@ -242,7 +244,7 @@ uint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord
break; break;
} }
n_char_since_last_break++; n_char_since_last_break++;
lv_coord_t letter_width2 = lv_font_get_width_int(font, letter); lv_coord_t letter_width2 = lv_font_get_glyph_width(font, letter, letter_next);
cur_w += letter_width2; cur_w += letter_width2;
if(cur_w > max_width) { if(cur_w > max_width) {
/* Current letter already exceeds, return previous */ /* Current letter already exceeds, return previous */
@ -323,17 +325,19 @@ lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, const lv_font_t *
lv_coord_t width = 0; lv_coord_t width = 0;
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
uint32_t letter; uint32_t letter;
uint32_t letter_next;
if(length != 0) { if(length != 0) {
while(i < length) { while(i < length) {
letter = lv_txt_encoded_next(txt, &i); letter = lv_txt_encoded_next(txt, &i);
letter_next = lv_txt_encoded_next(&txt[i], NULL);
if((flag & LV_TXT_FLAG_RECOLOR) != 0) { if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
if(lv_txt_is_cmd(&cmd_state, letter) != false) { if(lv_txt_is_cmd(&cmd_state, letter) != false) {
continue; continue;
} }
} }
lv_coord_t char_width = lv_font_get_width_int(font, letter); lv_coord_t char_width = lv_font_get_glyph_width(font, letter, letter_next);
if(char_width > 0) { if(char_width > 0) {
width += char_width; width += char_width;
width += letter_space; width += letter_space;

View File

@ -564,12 +564,20 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos)
} }
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
uint32_t i = line_start; uint32_t i = line_start;
uint32_t i_current = i; uint32_t i_current = i;
uint32_t letter; uint32_t letter;
uint32_t letter_next;
while(i <= new_line_start - 1) { while(i <= new_line_start - 1) {
letter = /* Get the current letter.
lv_txt_encoded_next(txt, &i); /*Be careful 'i' already points to the next character*/ * Be careful 'i' already points to the next character*/
letter = lv_txt_encoded_next(txt, &i);
/*Get the next letter too for kerning*/
letter_next = lv_txt_encoded_next(&txt[i], NULL);
/*Handle the recolor command*/ /*Handle the recolor command*/
if((flag & LV_TXT_FLAG_RECOLOR) != 0) { if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) { if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) {
@ -577,7 +585,7 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos)
} }
} }
x += lv_font_get_width_int(font, letter); x += lv_font_get_glyph_width(font, letter, letter_next);
if(pos->x < x) { if(pos->x < x) {
i = i_current; i = i_current;
break; break;
@ -670,12 +678,20 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos)
} }
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
uint32_t i = line_start; uint32_t i = line_start;
uint32_t i_current = i; uint32_t i_current = i;
uint32_t letter = 0; uint32_t letter;
uint32_t letter_next;
while(i <= new_line_start - 1) { while(i <= new_line_start - 1) {
letter = /* Get the current letter
lv_txt_encoded_next(txt, &i); /*Be careful 'i' already points to the next character*/ * Be careful 'i' already points to the next character */
letter = lv_txt_encoded_next(txt, &i);
/*Get the next letter for kerning*/
letter_next = lv_txt_encoded_next(&txt[i], NULL);
/*Handle the recolor command*/ /*Handle the recolor command*/
if((flag & LV_TXT_FLAG_RECOLOR) != 0) { if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) { if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) {
@ -683,7 +699,7 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos)
} }
} }
last_x = x; last_x = x;
x += lv_font_get_width_int(font, letter); x += lv_font_get_glyph_width(font, letter, letter_next);
if(pos->x < x) { if(pos->x < x) {
i = i_current; i = i_current;
break; break;
@ -692,7 +708,7 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos)
i_current = i; i_current = i;
} }
int max_diff = lv_font_get_width_int(font, letter) + style->text.letter_space + 1; int32_t max_diff = lv_font_get_glyph_width(font, letter, letter_next) + style->text.letter_space + 1;
return (pos->x >= (last_x - style->text.letter_space) && pos->x <= (last_x + max_diff)); return (pos->x >= (last_x - style->text.letter_space) && pos->x <= (last_x + max_diff));
} }
@ -833,10 +849,11 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_
style->text.line_space, LV_COORD_MAX, flag); style->text.line_space, LV_COORD_MAX, flag);
lv_point_t ofs; lv_point_t ofs;
/*Draw the text again next to the original to make an circular effect */ /*Draw the text again next to the original to make an circular effect */
if(size.x > lv_obj_get_width(label)) { if(size.x > lv_obj_get_width(label)) {
ofs.x = ext->offset.x + size.x + ofs.x = ext->offset.x + size.x +
lv_font_get_width_int(style->text.font, ' ') * LV_LABEL_WAIT_CHAR_COUNT; lv_font_get_glyph_width(style->text.font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT;
ofs.y = ext->offset.y; ofs.y = ext->offset.y;
lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs, lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs,
@ -950,8 +967,7 @@ static void lv_label_refr_text(lv_obj_t * label)
anim.start = 0; anim.start = 0;
anim.ready_cb = NULL; anim.ready_cb = NULL;
anim.path_cb = lv_anim_path_linear; anim.path_cb = lv_anim_path_linear;
anim.playback_pause = anim.playback_pause = (((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) /
(((lv_font_get_width_int(style->text.font, ' ') + style->text.letter_space) * 1000) /
ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT; ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT;
anim.repeat_pause = anim.playback_pause; anim.repeat_pause = anim.playback_pause;
anim.act_time = -anim.playback_pause; anim.act_time = -anim.playback_pause;
@ -990,8 +1006,7 @@ static void lv_label_refr_text(lv_obj_t * label)
anim.repeat = 1; anim.repeat = 1;
anim.playback = 0; anim.playback = 0;
anim.start = 0; anim.start = 0;
anim.act_time = anim.act_time = -(((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) /
-(((lv_font_get_width_int(style->text.font, ' ') + style->text.letter_space) * 1000) /
ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT; ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT;
anim.ready_cb = NULL; anim.ready_cb = NULL;
anim.path_cb = lv_anim_path_linear; anim.path_cb = lv_anim_path_linear;
@ -1000,7 +1015,7 @@ static void lv_label_refr_text(lv_obj_t * label)
bool hor_anim = false; bool hor_anim = false;
if(size.x > lv_obj_get_width(label)) { if(size.x > lv_obj_get_width(label)) {
anim.end = -size.x - lv_font_get_width_int(font, ' ') * LV_LABEL_WAIT_CHAR_COUNT; anim.end = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT;
anim.exec_cb = (lv_anim_exec_cb_t)lv_label_set_offset_x; anim.exec_cb = (lv_anim_exec_cb_t)lv_label_set_offset_x;
anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);
lv_anim_create(&anim); lv_anim_create(&anim);
@ -1031,7 +1046,7 @@ static void lv_label_refr_text(lv_obj_t * label)
} else { } else {
lv_point_t p; lv_point_t p;
p.x = lv_obj_get_width(label) - p.x = lv_obj_get_width(label) -
(lv_font_get_width_int(style->text.font, '.') + style->text.letter_space) * (lv_font_get_glyph_width(style->text.font, '.', '.') + style->text.letter_space) *
LV_LABEL_DOT_NUM; /*Shrink with dots*/ LV_LABEL_DOT_NUM; /*Shrink with dots*/
p.y = lv_obj_get_height(label); p.y = lv_obj_get_height(label);
p.y -= p.y % (lv_font_get_line_height(style->text.font) + p.y -= p.y % (lv_font_get_line_height(style->text.font) +

View File

@ -456,7 +456,7 @@ void lv_ta_set_text(lv_obj_t * ta, const char * txt)
/*Don't let 'width == 0' because the cursor will not be visible*/ /*Don't let 'width == 0' because the cursor will not be visible*/
if(lv_obj_get_width(ext->label) == 0) { if(lv_obj_get_width(ext->label) == 0) {
const lv_style_t * style = lv_obj_get_style(ext->label); const lv_style_t * style = lv_obj_get_style(ext->label);
lv_obj_set_width(ext->label, lv_font_get_width_int(style->text.font, ' ')); lv_obj_set_width(ext->label, lv_font_get_glyph_width(style->text.font, ' ', '\0'));
} }
if(ext->pwd_mode != 0) { if(ext->pwd_mode != 0) {
@ -1522,12 +1522,14 @@ static void refr_cursor_area(lv_obj_t * ta)
uint32_t letter = lv_txt_encoded_next(&txt[byte_pos], NULL); uint32_t letter = lv_txt_encoded_next(&txt[byte_pos], NULL);
lv_coord_t letter_h = lv_font_get_line_height(label_style->text.font); lv_coord_t letter_h = lv_font_get_line_height(label_style->text.font);
/*Set letter_w (set not 0 on non printable but valid chars)*/ /*Set letter_w (set not 0 on non printable but valid chars)*/
lv_coord_t letter_w; lv_coord_t letter_w;
if(letter == '\0' || letter == '\n' || letter == '\r') { if(letter == '\0' || letter == '\n' || letter == '\r') {
letter_w = lv_font_get_width_int(label_style->text.font, ' '); letter_w = lv_font_get_glyph_width(label_style->text.font, ' ', '\0');
} else { } else {
letter_w = lv_font_get_width_int(label_style->text.font, letter); /*`letter_next` parameter is '\0' to ignore kerning*/
letter_w = lv_font_get_glyph_width(label_style->text.font, letter, '\0');
} }
lv_point_t letter_pos; lv_point_t letter_pos;
@ -1545,9 +1547,9 @@ static void refr_cursor_area(lv_obj_t * ta)
} }
if(letter == '\0' || letter == '\n' || letter == '\r') { if(letter == '\0' || letter == '\n' || letter == '\r') {
letter_w = lv_font_get_width_int(label_style->text.font, ' '); letter_w = lv_font_get_glyph_width(label_style->text.font, ' ', '\0');
} else { } else {
letter_w = lv_font_get_width_int(label_style->text.font, letter); letter_w = lv_font_get_glyph_width(label_style->text.font, letter, '\0');
} }
} }

View File

@ -1031,7 +1031,7 @@ static void tabview_realign(lv_obj_t * tabview)
break; break;
case LV_TABVIEW_BTNS_POS_LEFT: case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT: case LV_TABVIEW_BTNS_POS_RIGHT:
btns_size = lv_font_get_width_int(style_btn_rel->text.font, 0x0041) + // 'A' btns_size = lv_font_get_glyph_width(style_btn_rel->text.font, 'A', '\0') +
style_btn_rel->body.padding.left + style_btn_rel->body.padding.left +
style_btn_rel->body.padding.right + style_btn_rel->body.padding.right +
style_btn_bg->body.padding.left + style_btn_bg->body.padding.right; style_btn_bg->body.padding.left + style_btn_bg->body.padding.right;