FS#10984 - multifont! 2 major additions:

1) seperate UI font for the remote and main displays
2) allow individual skins to load additional fonts for use in the skin (Uo to 7 extra in this first version) see CustomWPS for info on how to load a font in the skins.

Code should always use FONT_UI+screen_number to get the correct user font


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24644 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jonathan Gordon 2010-02-14 06:26:16 +00:00
parent ed21ab1c8c
commit 1c2aa35371
20 changed files with 643 additions and 205 deletions

View file

@ -30,6 +30,7 @@
#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
#ifndef __PCTOOL__
#include "font_cache.h"
#include "sysfont.h"
#endif
@ -47,9 +48,14 @@
enum {
FONT_SYSFIXED, /* system fixed pitch font*/
FONT_UI, /* system porportional font*/
MAXFONTS
#ifdef HAVE_REMOTE_LCD
FONT_UI_REMOTE, /* UI font for remote LCD */
#endif
SYSTEMFONTCOUNT /* Number of fonts reserved for the system and ui */
};
#define MAXFONTS 10
/*
* .fnt loadable font file format definition
*
@ -89,17 +95,38 @@ struct font {
const unsigned char *width; /* character widths or NULL if fixed*/
int defaultchar; /* default char (not glyph index)*/
int32_t bits_size; /* # bytes of glyph bits*/
/* file, buffer and cache management */
int fd; /* fd for the font file. >= 0 if cached */
unsigned char *buffer_start; /* buffer to store the font in */
unsigned char *buffer_position; /* position in the buffer */
unsigned char *buffer_end; /* end of the buffer */
int buffer_size; /* size of the buffer in bytes */
#ifndef __PCTOOL__
struct font_cache cache;
uint32_t file_width_offset; /* offset to file width data */
uint32_t file_offset_offset; /* offset to file offset data */
int long_offset;
#endif
};
/* font routines*/
void font_init(void);
struct font* font_load(const char *path);
#ifdef HAVE_REMOTE_LCD
/* Load a font into the special remote ui font slot */
int font_load_remoteui(const char* path);
#endif
int font_load(struct font* pf, const char *path);
void font_unload(int font_id);
struct font* font_get(int font);
void font_reset(void);
void font_reset(struct font *pf);
int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber);
int font_get_width(struct font* ft, unsigned short ch);
const unsigned char * font_get_bits(struct font* ft, unsigned short ch);
void glyph_cache_save(void);
void glyph_cache_save(struct font* pf);
#else /* HAVE_LCD_BITMAP */

View file

@ -75,64 +75,77 @@ extern struct font sysfont;
/* structure filled in by font_load */
static struct font font_ui;
/* static buffer allocation structures */
static unsigned char main_buf[MAX_FONT_SIZE];
#ifdef HAVE_REMOTE_LCD
#define REMOTE_FONT_SIZE 10000
static struct font remote_font_ui;
static unsigned char remote_buf[REMOTE_FONT_SIZE];
#endif
/* system font table, in order of FONT_xxx definition */
static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL};
/* static buffer allocation structures */
static unsigned char mbuf[MAX_FONT_SIZE];
static unsigned char *freeptr = mbuf;
static unsigned char *fileptr;
static unsigned char *eofptr;
/* Font cache structures */
static struct font_cache font_cache_ui;
static int fnt_file = -1; /* >=0 if font is cached */
static uint32_t file_width_offset; /* offset to file width data */
static uint32_t file_offset_offset; /* offset to file offset data */
static void cache_create(int maxwidth, int height);
static int long_offset = 0;
static int glyph_file;
static void cache_create(struct font* pf, int maxwidth, int height);
static void glyph_cache_load(struct font* pf);
/* End Font cache structures */
static void glyph_cache_load(void);
void font_init(void)
{
memset(&font_ui, 0, sizeof(struct font));
int i = SYSTEMFONTCOUNT;
while (i<MAXFONTS)
sysfonts[i++] = NULL;
font_reset(NULL);
}
/* Check if we have x bytes left in the file buffer */
#define HAVEBYTES(x) (fileptr + (x) <= eofptr)
#define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
/* Helper functions to read big-endian unaligned short or long from
the file buffer. Bounds-checking must be done in the calling
function.
*/
static short readshort(void)
static short readshort(struct font *pf)
{
unsigned short s;
s = *fileptr++ & 0xff;
s |= (*fileptr++ << 8);
s = *pf->buffer_position++ & 0xff;
s |= (*pf->buffer_position++ << 8);
return s;
}
static int32_t readlong(void)
static int32_t readlong(struct font *pf)
{
uint32_t l;
l = *fileptr++ & 0xff;
l |= *fileptr++ << 8;
l |= ((uint32_t)(*fileptr++)) << 16;
l |= ((uint32_t)(*fileptr++)) << 24;
l = *pf->buffer_position++ & 0xff;
l |= *pf->buffer_position++ << 8;
l |= ((uint32_t)(*pf->buffer_position++)) << 16;
l |= ((uint32_t)(*pf->buffer_position++)) << 24;
return l;
}
void font_reset(void)
void font_reset(struct font *pf)
{
memset(&font_ui, 0, sizeof(struct font));
unsigned char* buffer = NULL;
size_t buf_size = 0;
if (pf == NULL)
pf = &font_ui;
else
{
buffer = pf->buffer_start;
buf_size = pf->buffer_size;
}
memset(pf, 0, sizeof(struct font));
pf->fd = -1;
if (buffer)
{
pf->buffer_start = buffer;
pf->buffer_size = buf_size;
}
}
static struct font* font_load_header(struct font *pf)
@ -142,23 +155,23 @@ static struct font* font_load_header(struct font *pf)
return NULL;
/* read magic and version #*/
if (memcmp(fileptr, VERSION, 4) != 0)
if (memcmp(pf->buffer_position, VERSION, 4) != 0)
return NULL;
fileptr += 4;
pf->buffer_position += 4;
/* font info*/
pf->maxwidth = readshort();
pf->height = readshort();
pf->ascent = readshort();
fileptr += 2; /* Skip padding */
pf->firstchar = readlong();
pf->defaultchar = readlong();
pf->size = readlong();
pf->maxwidth = readshort(pf);
pf->height = readshort(pf);
pf->ascent = readshort(pf);
pf->buffer_position += 2; /* Skip padding */
pf->firstchar = readlong(pf);
pf->defaultchar = readlong(pf);
pf->size = readlong(pf);
/* get variable font data sizes*/
/* # words of bitmap_t*/
pf->bits_size = readlong();
pf->bits_size = readlong(pf);
return pf;
}
@ -171,32 +184,32 @@ static struct font* font_load_in_memory(struct font* pf)
return NULL;
/* # longs of offset*/
noffset = readlong();
noffset = readlong(pf);
/* # bytes of width*/
nwidth = readlong();
nwidth = readlong(pf);
/* variable font data*/
pf->bits = (unsigned char *)fileptr;
fileptr += pf->bits_size*sizeof(unsigned char);
pf->bits = (unsigned char *)pf->buffer_position;
pf->buffer_position += pf->bits_size*sizeof(unsigned char);
if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
{
/* pad to 16-bit boundary */
fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
}
else
{
/* pad to 32-bit boundary*/
fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
}
if (noffset)
{
if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
{
long_offset = 0;
pf->offset = (uint16_t*)fileptr;
pf->long_offset = 0;
pf->offset = (uint16_t*)pf->buffer_position;
/* Check we have sufficient buffer */
if (!HAVEBYTES(noffset * sizeof(uint16_t)))
@ -204,13 +217,13 @@ static struct font* font_load_in_memory(struct font* pf)
for (i=0; i<noffset; ++i)
{
((uint16_t*)(pf->offset))[i] = (uint16_t)readshort();
((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
}
}
else
{
long_offset = 1;
pf->offset = (uint16_t*)fileptr;
pf->long_offset = 1;
pf->offset = (uint16_t*)pf->buffer_position;
/* Check we have sufficient buffer */
if (!HAVEBYTES(noffset * sizeof(int32_t)))
@ -218,7 +231,7 @@ static struct font* font_load_in_memory(struct font* pf)
for (i=0; i<noffset; ++i)
{
((uint32_t*)(pf->offset))[i] = (uint32_t)readlong();
((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
}
}
}
@ -226,13 +239,13 @@ static struct font* font_load_in_memory(struct font* pf)
pf->offset = NULL;
if (nwidth) {
pf->width = (unsigned char *)fileptr;
fileptr += nwidth*sizeof(unsigned char);
pf->width = (unsigned char *)pf->buffer_position;
pf->buffer_position += nwidth*sizeof(unsigned char);
}
else
pf->width = NULL;
if (fileptr > eofptr)
if (pf->buffer_position > pf->buffer_end)
return NULL;
return pf; /* success!*/
@ -242,135 +255,203 @@ static struct font* font_load_in_memory(struct font* pf)
static struct font* font_load_cached(struct font* pf)
{
uint32_t noffset, nwidth;
unsigned char* oldfileptr = fileptr;
unsigned char* oldfileptr = pf->buffer_position;
if (!HAVEBYTES(2 * sizeof(int32_t)))
return NULL;
/* # longs of offset*/
noffset = readlong();
noffset = readlong(pf);
/* # bytes of width*/
nwidth = readlong();
nwidth = readlong(pf);
/* We are now at the bitmap data, this is fixed at 36.. */
pf->bits = NULL;
/* Calculate offset to offset data */
fileptr += pf->bits_size * sizeof(unsigned char);
pf->buffer_position += pf->bits_size * sizeof(unsigned char);
if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
{
long_offset = 0;
pf->long_offset = 0;
/* pad to 16-bit boundary */
fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
}
else
{
long_offset = 1;
pf->long_offset = 1;
/* pad to 32-bit boundary*/
fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
}
if (noffset)
file_offset_offset = (uint32_t)(fileptr - freeptr);
pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
else
file_offset_offset = 0;
pf->file_offset_offset = 0;
/* Calculate offset to widths data */
if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
fileptr += noffset * sizeof(uint16_t);
pf->buffer_position += noffset * sizeof(uint16_t);
else
fileptr += noffset * sizeof(uint32_t);
pf->buffer_position += noffset * sizeof(uint32_t);
if (nwidth)
file_width_offset = (uint32_t)(fileptr - freeptr);
pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
else
file_width_offset = 0;
pf->file_width_offset = 0;
fileptr = oldfileptr;
pf->buffer_position = oldfileptr;
/* Create the cache */
cache_create(pf->maxwidth, pf->height);
cache_create(pf, pf->maxwidth, pf->height);
return pf;
}
/* read and load font into incore font structure*/
struct font* font_load(const char *path)
static bool internal_load_font(struct font* pf, const char *path,
char *buf, size_t buf_size)
{
int size;
struct font* pf = &font_ui;
/* save loaded glyphs */
glyph_cache_save();
glyph_cache_save(pf);
/* Close font file handle */
if (fnt_file >= 0)
close(fnt_file);
if (pf->fd >= 0)
close(pf->fd);
font_reset(pf);
/* open and read entire font file*/
fnt_file = open(path, O_RDONLY|O_BINARY);
pf->fd = open(path, O_RDONLY|O_BINARY);
if (fnt_file < 0) {
if (pf->fd < 0) {
DEBUGF("Can't open font: %s\n", path);
return NULL;
return false;
}
/* Check file size */
size = filesize(fnt_file);
font_reset();
/* currently, font loading replaces earlier font allocation*/
freeptr = (unsigned char *)(((intptr_t)mbuf + 3) & ~3);
fileptr = freeptr;
if (size > MAX_FONT_SIZE)
size = filesize(pf->fd);
pf->buffer_start = buf;
pf->buffer_size = buf_size;
pf->buffer_position = buf;
if (size > pf->buffer_size)
{
read(fnt_file, fileptr, FONT_HEADER_SIZE);
eofptr = fileptr + FONT_HEADER_SIZE;
read(pf->fd, pf->buffer_position, FONT_HEADER_SIZE);
pf->buffer_end = pf->buffer_position + FONT_HEADER_SIZE;
if (!font_load_header(pf))
{
DEBUGF("Failed font header load");
return NULL;
return false;
}
if (!font_load_cached(pf))
{
DEBUGF("Failed font cache load");
return NULL;
return false;
}
glyph_cache_load();
glyph_cache_load(pf);
}
else
{
read(fnt_file, fileptr, MAX_FONT_SIZE);
eofptr = fileptr + size;
close(fnt_file);
fnt_file = -1;
read(pf->fd, pf->buffer_position, pf->buffer_size);
pf->buffer_end = pf->buffer_position + size;
close(pf->fd);
pf->fd = -1;
if (!font_load_header(pf))
{
DEBUGF("Failed font header load");
return NULL;
return false;
}
if (!font_load_in_memory(pf))
{
DEBUGF("Failed mem load");
return NULL;
return false;
}
}
return true;
}
#ifdef HAVE_REMOTE_LCD
/* Load a font into the special remote ui font slot */
int font_load_remoteui(const char* path)
{
struct font* pf = &remote_font_ui;
if (!path)
{
if (sysfonts[FONT_UI_REMOTE] && sysfonts[FONT_UI_REMOTE] != sysfonts[FONT_UI])
font_unload(FONT_UI_REMOTE);
sysfonts[FONT_UI_REMOTE] = NULL;
return FONT_UI;
}
if (!internal_load_font(pf, path, remote_buf, REMOTE_FONT_SIZE))
{
sysfonts[FONT_UI_REMOTE] = NULL;
return -1;
}
sysfonts[FONT_UI_REMOTE] = pf;
return FONT_UI_REMOTE;
}
#endif
/* no need for multiple font loads currently*/
/*freeptr += filesize;*/
/*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
/* read and load font into incore font structure,
* returns the font number on success, -1 on failure */
int font_load(struct font* pf, const char *path)
{
int font_id = -1;
char *buffer;
size_t buffer_size;
if (pf == NULL)
{
pf = &font_ui;
font_id = FONT_UI;
}
else
{
for (font_id = SYSTEMFONTCOUNT; font_id < MAXFONTS; font_id++)
{
if (sysfonts[font_id] == NULL)
break;
}
if (font_id == MAXFONTS)
return -1; /* too many fonts */
}
if (font_id == FONT_UI)
{
/* currently, font loading replaces earlier font allocation*/
buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3);
buffer_size = MAX_FONT_SIZE;
}
else
{
buffer = pf->buffer_start;
buffer_size = pf->buffer_size;
}
if (!internal_load_font(pf, path, buffer, buffer_size))
return -1;
sysfonts[font_id] = pf;
return font_id; /* success!*/
}
return pf; /* success!*/
void font_unload(int font_id)
{
struct font* pf = sysfonts[font_id];
if (font_id >= SYSTEMFONTCOUNT && pf)
{
if (pf->fd >= 0)
close(pf->fd);
sysfonts[font_id] = NULL;
}
}
/*
@ -382,9 +463,6 @@ struct font* font_get(int font)
{
struct font* pf;
if (font >= MAXFONTS)
font = 0;
while (1) {
pf = sysfonts[font];
if (pf && pf->height)
@ -404,11 +482,11 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data)
unsigned short char_code = p->_char_code;
unsigned char tmp[2];
if (file_width_offset)
if (pf->file_width_offset)
{
int width_offset = file_width_offset + char_code;
lseek(fnt_file, width_offset, SEEK_SET);
read(fnt_file, &(p->width), 1);
int width_offset = pf->file_width_offset + char_code;
lseek(pf->fd, width_offset, SEEK_SET);
read(pf->fd, &(p->width), 1);
}
else
{
@ -417,14 +495,14 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data)
int32_t bitmap_offset = 0;
if (file_offset_offset)
if (pf->file_offset_offset)
{
int32_t offset = file_offset_offset + char_code * (long_offset ? sizeof(int32_t) : sizeof(int16_t));
lseek(fnt_file, offset, SEEK_SET);
read (fnt_file, tmp, 2);
int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
lseek(pf->fd, offset, SEEK_SET);
read (pf->fd, tmp, 2);
bitmap_offset = tmp[0] | (tmp[1] << 8);
if (long_offset) {
read (fnt_file, tmp, 2);
if (pf->long_offset) {
read (pf->fd, tmp, 2);
bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
}
}
@ -434,22 +512,22 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data)
}
int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
lseek(fnt_file, file_offset, SEEK_SET);
lseek(pf->fd, file_offset, SEEK_SET);
int src_bytes = p->width * ((pf->height + 7) / 8);
read(fnt_file, p->bitmap, src_bytes);
read(pf->fd, p->bitmap, src_bytes);
}
/*
* Converts cbuf into a font cache
*/
static void cache_create(int maxwidth, int height)
static void cache_create(struct font* pf, int maxwidth, int height)
{
/* maximum size of rotated bitmap */
int bitmap_size = maxwidth * ((height + 7) / 8);
/* Initialise cache */
font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
}
/*
@ -462,8 +540,8 @@ int font_get_width(struct font* pf, unsigned short char_code)
char_code = pf->defaultchar;
char_code -= pf->firstchar;
return (fnt_file >= 0 && pf != &sysfont)?
font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
return (pf->fd >= 0 && pf != &sysfont)?
font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
pf->width? pf->width[char_code]: pf->maxwidth;
}
@ -476,10 +554,10 @@ const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
char_code = pf->defaultchar;
char_code -= pf->firstchar;
if (fnt_file >= 0 && pf != &sysfont)
if (pf->fd >= 0 && pf != &sysfont)
{
bits =
(unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
(unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->bitmap;
}
else
{
@ -497,7 +575,7 @@ const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
return bits;
}
static int cache_fd;
static void glyph_file_write(void* data)
{
struct font_cache_entry* p = data;
@ -507,45 +585,48 @@ static void glyph_file_write(void* data)
ch = p->_char_code + pf->firstchar;
if (ch != 0xffff && glyph_file >= 0) {
if (ch != 0xffff && cache_fd >= 0) {
tmp[0] = ch >> 8;
tmp[1] = ch & 0xff;
if (write(glyph_file, tmp, 2) != 2) {
close(glyph_file);
glyph_file = -1;
if (write(cache_fd, tmp, 2) != 2) {
close(cache_fd);
cache_fd = -1;
}
}
return;
}
/* save the char codes of the loaded glyphs to a file */
void glyph_cache_save(void)
void glyph_cache_save(struct font* pf)
{
if (fnt_file >= 0) {
if (!pf)
pf = &font_ui;
if (pf->fd >= 0 && pf == &font_ui)
{
#ifdef WPSEDITOR
glyph_file = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
cache_fd = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
#else
glyph_file = creat(GLYPH_CACHE_FILE);
cache_fd = creat(GLYPH_CACHE_FILE);
#endif
if (glyph_file < 0) return;
if (cache_fd < 0) return;
lru_traverse(&font_cache_ui._lru, glyph_file_write);
if (glyph_file >= 0)
close(glyph_file);
lru_traverse(&pf->cache._lru, glyph_file_write);
if (cache_fd < 0)
{
close(cache_fd);
cache_fd = -1;
}
}
return;
}
static void glyph_cache_load(void)
static void glyph_cache_load(struct font* pf)
{
if (fnt_file >= 0) {
if (pf->fd >= 0) {
int fd;
unsigned char tmp[2];
unsigned short ch;
struct font* pf = &font_ui;
fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);

View file

@ -744,7 +744,7 @@ void shutdown_hw(void)
if (battery_level_safe()) { /* do not save on critical battery */
#ifdef HAVE_LCD_BITMAP
glyph_cache_save();
glyph_cache_save(NULL);
#endif
/* Commit pending writes if needed. Even though we don't do write caching,