fonts: Do not unload completely on USB.
The font engine can now perform cache lookups even if the font file is closed, if the font was disabled with the new font_disable_all() function. It is highly probable that the lookup succeeds but in the cache-miss case a blank, full-width glyph will be returned. Change-Id: I3c97e747d2a0ba30c7b495c6118c9f029d265b56
This commit is contained in:
parent
84c7d6133b
commit
c23ce62829
4 changed files with 123 additions and 13 deletions
|
@ -125,6 +125,13 @@ void font_unload(int font_id);
|
||||||
void font_unload_all(void);
|
void font_unload_all(void);
|
||||||
void font_lock(int font_id, bool lock);
|
void font_lock(int font_id, bool lock);
|
||||||
|
|
||||||
|
/* Closes the file descriptor if the font file (if cached) but keeps
|
||||||
|
* the cache intact, so font_get_{bits,width} still work. */
|
||||||
|
void font_disable_all(void);
|
||||||
|
/* Re-opens the file descriptor of the font file. Should be called as
|
||||||
|
* counter-part of font_disable_all(); */
|
||||||
|
void font_enable_all(void);
|
||||||
|
|
||||||
struct font* font_get(int font);
|
struct font* font_get(int font);
|
||||||
|
|
||||||
int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber);
|
int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber);
|
||||||
|
|
116
firmware/font.c
116
firmware/font.c
|
@ -88,9 +88,10 @@ extern struct font sysfont;
|
||||||
#ifndef BOOTLOADER
|
#ifndef BOOTLOADER
|
||||||
|
|
||||||
struct buflib_alloc_data {
|
struct buflib_alloc_data {
|
||||||
struct font font;
|
struct font font; /* must be the first member! */
|
||||||
int handle_locks; /* is the buflib handle currently locked? */
|
int handle_locks; /* is the buflib handle currently locked? */
|
||||||
int refcount; /* how many times has this font been loaded? */
|
int refcount; /* how many times has this font been loaded? */
|
||||||
|
int disabled; /* font disabled (use fallback glyphs, from sysfont) */
|
||||||
unsigned char buffer[];
|
unsigned char buffer[];
|
||||||
};
|
};
|
||||||
static int buflib_allocations[MAXFONTS];
|
static int buflib_allocations[MAXFONTS];
|
||||||
|
@ -285,6 +286,7 @@ static struct font* font_load_cached(struct font* pf,
|
||||||
int32_t noffset)
|
int32_t noffset)
|
||||||
{
|
{
|
||||||
/* We are now at the bitmap data, this is fixed at 36.. */
|
/* We are now at the bitmap data, this is fixed at 36.. */
|
||||||
|
pf->width = NULL;
|
||||||
pf->bits = NULL;
|
pf->bits = NULL;
|
||||||
|
|
||||||
/* Calculate offset to offset data */
|
/* Calculate offset to offset data */
|
||||||
|
@ -412,11 +414,10 @@ int font_load_ex( const char *path, size_t buf_size, int glyphs )
|
||||||
/* load font struct f with file header */
|
/* load font struct f with file header */
|
||||||
int file_size = filesize( fd );
|
int file_size = filesize( fd );
|
||||||
struct font header;
|
struct font header;
|
||||||
struct font *pheader = &header;
|
|
||||||
struct font f;
|
struct font f;
|
||||||
|
|
||||||
uint32_t nwidth, noffset;
|
uint32_t nwidth, noffset;
|
||||||
if ( !font_load_header( fd, pheader, &f, &nwidth, &noffset )
|
if ( !font_load_header( fd, &header, &f, &nwidth, &noffset )
|
||||||
#if LCD_DEPTH < 16
|
#if LCD_DEPTH < 16
|
||||||
|| f.depth
|
|| f.depth
|
||||||
#endif
|
#endif
|
||||||
|
@ -470,6 +471,7 @@ int font_load_ex( const char *path, size_t buf_size, int glyphs )
|
||||||
old_id = font_id;
|
old_id = font_id;
|
||||||
old_refcount = pd->refcount;
|
old_refcount = pd->refcount;
|
||||||
pd->refcount = 1;
|
pd->refcount = 1;
|
||||||
|
pd->disabled = false;
|
||||||
font_unload(font_id);
|
font_unload(font_id);
|
||||||
font_id = font_load_ex(path, bufsize, glyphs);
|
font_id = font_load_ex(path, bufsize, glyphs);
|
||||||
if (font_id < 0)
|
if (font_id < 0)
|
||||||
|
@ -623,6 +625,58 @@ void font_unload_all(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void font_disable(int font_id)
|
||||||
|
{
|
||||||
|
if ( font_id < 0 || font_id >= MAXFONTS )
|
||||||
|
return;
|
||||||
|
int handle = buflib_allocations[font_id];
|
||||||
|
if ( handle < 0 )
|
||||||
|
return;
|
||||||
|
struct buflib_alloc_data *pdata = core_get_data(handle);
|
||||||
|
struct font *pf = &pdata->font;
|
||||||
|
|
||||||
|
if (pf->fd >= 0)
|
||||||
|
{
|
||||||
|
/* save the cache, but it keep it in-RAM so that cache lookups
|
||||||
|
* can still succeed on the same font */
|
||||||
|
glyph_cache_save(font_id);
|
||||||
|
close(pf->fd);
|
||||||
|
pf->fd = -1;
|
||||||
|
pdata->disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void font_disable_all(void)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < MAXFONTS; i++)
|
||||||
|
font_disable(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void font_enable(int font_id)
|
||||||
|
{
|
||||||
|
if ( font_id < 0 || font_id >= MAXFONTS )
|
||||||
|
return;
|
||||||
|
int handle = buflib_allocations[font_id];
|
||||||
|
if ( handle < 0 )
|
||||||
|
return;
|
||||||
|
struct buflib_alloc_data *pdata = core_get_data(handle);
|
||||||
|
struct font *pf = &pdata->font;
|
||||||
|
|
||||||
|
if (pdata->disabled && pf->fd < 0)
|
||||||
|
{
|
||||||
|
const char *filename = font_filename(font_id);
|
||||||
|
pf->fd = open(filename, O_RDONLY);
|
||||||
|
pdata->disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void font_enable_all(void)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < MAXFONTS; i++)
|
||||||
|
font_enable(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a pointer to an incore font structure.
|
* Return a pointer to an incore font structure.
|
||||||
* If the requested font isn't loaded/compiled-in,
|
* If the requested font isn't loaded/compiled-in,
|
||||||
|
@ -715,10 +769,15 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data)
|
||||||
static void cache_create(struct font* pf)
|
static void cache_create(struct font* pf)
|
||||||
{
|
{
|
||||||
/* maximum size of rotated bitmap */
|
/* maximum size of rotated bitmap */
|
||||||
int bitmap_size = glyph_bytes( pf, pf->maxwidth);
|
int bitmap_size = glyph_bytes(pf, pf->maxwidth);
|
||||||
|
/* reserve one blank glyph that is guaranteed to be available, even
|
||||||
|
* when the font file is closed during USB */
|
||||||
|
unsigned char *cache_buf = pf->buffer_start + bitmap_size;
|
||||||
|
size_t cache_size = pf->buffer_size - (cache_buf - pf->buffer_start);
|
||||||
|
ALIGN_BUFFER(cache_buf, cache_size, 2);
|
||||||
|
memset(pf->buffer_start, 0, bitmap_size);
|
||||||
/* Initialise cache */
|
/* Initialise cache */
|
||||||
font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
|
font_cache_create(&pf->cache, cache_buf, cache_size, bitmap_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -726,32 +785,65 @@ static void cache_create(struct font* pf)
|
||||||
*/
|
*/
|
||||||
int font_get_width(struct font* pf, unsigned short char_code)
|
int font_get_width(struct font* pf, unsigned short char_code)
|
||||||
{
|
{
|
||||||
|
int width;
|
||||||
|
struct font_cache_entry *e;
|
||||||
|
struct buflib_alloc_data *data = (struct buflib_alloc_data *) pf;
|
||||||
|
bool cache_only = data->disabled;
|
||||||
|
|
||||||
/* check input range*/
|
/* check input range*/
|
||||||
if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
|
if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
|
||||||
char_code = pf->defaultchar;
|
char_code = pf->defaultchar;
|
||||||
char_code -= pf->firstchar;
|
char_code -= pf->firstchar;
|
||||||
|
|
||||||
return (pf->fd >= 0 && pf != &sysfont)?
|
if ((pf->fd >= 0 || cache_only) && pf != &sysfont
|
||||||
font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
|
&& (e = font_cache_get(&pf->cache,char_code,cache_only,load_cache_entry,pf)))
|
||||||
pf->width? pf->width[char_code]: pf->maxwidth;
|
width = e->width;
|
||||||
|
else if (pf->width)
|
||||||
|
width = pf->width[char_code];
|
||||||
|
else
|
||||||
|
width = pf->maxwidth;
|
||||||
|
|
||||||
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
|
const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
|
||||||
{
|
{
|
||||||
const unsigned char* bits;
|
const unsigned char* bits;
|
||||||
|
struct buflib_alloc_data *data;
|
||||||
|
|
||||||
/* check input range*/
|
/* check input range*/
|
||||||
if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
|
if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
|
||||||
char_code = pf->defaultchar;
|
char_code = pf->defaultchar;
|
||||||
char_code -= pf->firstchar;
|
char_code -= pf->firstchar;
|
||||||
|
|
||||||
|
data = (struct buflib_alloc_data *) pf;
|
||||||
|
|
||||||
if (pf->fd >= 0 && pf != &sysfont)
|
if (pf->fd >= 0 && pf != &sysfont)
|
||||||
{
|
{
|
||||||
bits =
|
bits =
|
||||||
(unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry, pf)->bitmap;
|
(unsigned char*)font_cache_get(&pf->cache, char_code,
|
||||||
|
false, load_cache_entry, data)->bitmap;
|
||||||
|
}
|
||||||
|
else if (data->disabled)
|
||||||
|
{
|
||||||
|
/* the font handle is closed, but the cache is intact. Attempt
|
||||||
|
* a lookup, which is very likely to succeed. Return a placeholder
|
||||||
|
* glyph on miss (again, this is very unlikely */
|
||||||
|
struct font_cache_entry *e = font_cache_get(&pf->cache, char_code,
|
||||||
|
true, NULL, NULL);
|
||||||
|
if (LIKELY(e))
|
||||||
|
bits = (unsigned char *) e->bitmap;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Could attempt to find a suitable fallback glyph from the same
|
||||||
|
* font. For now just return blank space which is
|
||||||
|
* reserved by cache_create() at buffer_start */
|
||||||
|
bits = pf->buffer_start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* This font is entirely in RAM */
|
||||||
bits = pf->bits;
|
bits = pf->bits;
|
||||||
if (pf->offset)
|
if (pf->offset)
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,6 +125,7 @@ static int search(struct font_cache* fcache,
|
||||||
struct font_cache_entry* font_cache_get(
|
struct font_cache_entry* font_cache_get(
|
||||||
struct font_cache* fcache,
|
struct font_cache* fcache,
|
||||||
unsigned short char_code,
|
unsigned short char_code,
|
||||||
|
bool cache_only,
|
||||||
void (*callback) (struct font_cache_entry* p, void *callback_data),
|
void (*callback) (struct font_cache_entry* p, void *callback_data),
|
||||||
void *callback_data)
|
void *callback_data)
|
||||||
{
|
{
|
||||||
|
@ -166,6 +167,8 @@ struct font_cache_entry* font_cache_get(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not found */
|
/* not found */
|
||||||
|
if (cache_only)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* find index to replace */
|
/* find index to replace */
|
||||||
short lru_handle_to_replace = fcache->_lru._head;
|
short lru_handle_to_replace = fcache->_lru._head;
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef _FONT_CACHE_H_
|
#ifndef _FONT_CACHE_H_
|
||||||
#define _FONT_CACHE_H_
|
#define _FONT_CACHE_H_
|
||||||
|
#include <stdbool.h>
|
||||||
#include "lru.h"
|
#include "lru.h"
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -45,10 +47,16 @@ struct font_cache_entry
|
||||||
/* Create an auto sized font cache from buf */
|
/* Create an auto sized font cache from buf */
|
||||||
void font_cache_create(
|
void font_cache_create(
|
||||||
struct font_cache* fcache, void* buf, int buf_size, int bitmap_bytes_size);
|
struct font_cache* fcache, void* buf, int buf_size, int bitmap_bytes_size);
|
||||||
/* Get font cache entry */
|
|
||||||
|
/* Get font cache entry for the given char_code
|
||||||
|
*
|
||||||
|
* cache_only: true if only a cache lookup should be performed and loading on miss should be avoided
|
||||||
|
*
|
||||||
|
* Note: With cache_only this can return NULL, which otherwise never happens */
|
||||||
struct font_cache_entry* font_cache_get(
|
struct font_cache_entry* font_cache_get(
|
||||||
struct font_cache* fcache,
|
struct font_cache* fcache,
|
||||||
unsigned short char_code,
|
unsigned short char_code,
|
||||||
|
bool cache_only,
|
||||||
void (*callback) (struct font_cache_entry* p, void *callback_data),
|
void (*callback) (struct font_cache_entry* p, void *callback_data),
|
||||||
void *callback_data);
|
void *callback_data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue