From b0fee17d6e1a463dcd84568e5997663b69488998 Mon Sep 17 00:00:00 2001 From: Marcoen Hirschberg Date: Tue, 6 Dec 2005 13:27:15 +0000 Subject: waiting is over: initial unicode commit git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8169 a1c6a512-1295-4272-9138-f99709370657 --- firmware/font.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 347 insertions(+), 45 deletions(-) (limited to 'firmware/font.c') diff --git a/firmware/font.c b/firmware/font.c index 303887701d..e8d5db46b9 100644 --- a/firmware/font.c +++ b/firmware/font.c @@ -33,6 +33,10 @@ #include "file.h" #include "debug.h" #include "panic.h" +#include "rbunicode.h" +/* Font cache includes */ +#include "font_cache.h" +#include "lru.h" #ifndef O_BINARY #define O_BINARY 0 @@ -53,6 +57,16 @@ 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 */ +unsigned long file_width_offset; /* offset to file width data */ +unsigned long 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; +/* End Font cache structures */ + void font_init(void) { memset(&font_ui, 0, sizeof(struct font)); @@ -94,41 +108,12 @@ void font_reset(void) memset(&font_ui, 0, sizeof(struct font)); } -/* read and load font into incore font structure*/ -struct font* font_load(const char *path) +static struct font* font_load_header(struct font *pf) { - int fd, filesize; + char version[4+1]; unsigned short maxwidth, height, ascent, pad; unsigned long firstchar, defaultchar, size; - unsigned long i, nbits, noffset, nwidth; - char version[4+1]; - struct font* pf = &font_ui; - - /* open and read entire font file*/ - fd = open(path, O_RDONLY|O_BINARY); - if (fd < 0) { - DEBUGF("Can't open font: %s\n", path); - return NULL; - } - - font_reset(); - - /* currently, font loading replaces earlier font allocation*/ - freeptr = (unsigned char *)(((int)mbuf + 3) & ~3); - - fileptr = freeptr; - filesize = read(fd, fileptr, MAX_FONT_SIZE); - eofptr = fileptr + filesize; - - /* no need for multiple font loads currently*/ - /*freeptr += filesize;*/ - /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/ - - close(fd); - if (filesize == MAX_FONT_SIZE) { - DEBUGF("Font %s too large: %d\n", path, filesize); - return NULL; - } + unsigned long nbits; /* read magic and version #*/ memset(version, 0, sizeof(version)); @@ -163,6 +148,14 @@ struct font* font_load(const char *path) /* # words of bitmap_t*/ if (!readlong(&nbits)) return NULL; + pf->bits_size = nbits; + + return pf; +} +/* Load memory font */ +struct font* font_load_in_memory(struct font* pf) +{ + long i, noffset, nwidth; /* # longs of offset*/ if (!readlong(&noffset)) @@ -174,19 +167,44 @@ struct font* font_load(const char *path) /* variable font data*/ pf->bits = (unsigned char *)fileptr; - fileptr += nbits*sizeof(unsigned char); + fileptr += pf->bits_size*sizeof(unsigned char); - /* pad to 16 bit boundary*/ - fileptr = (unsigned char *)(((long)fileptr + 1) & ~1); + if ( pf->bits_size < 0xFFDB ) + { + /* pad to 16-bit boundary */ + fileptr = (unsigned char *)(((int)fileptr + 1) & ~1); + } + else + { + /* pad to 32-bit boundary*/ + fileptr = (unsigned char *)(((int)fileptr + 3) & ~3); + } - if (noffset) { - pf->offset = (unsigned short *)fileptr; - for (i=0; ibits_size < 0xFFDB ) + { + long_offset = 0; + pf->offset = (unsigned short *)fileptr; + for (i=0; ioffset))[i] = (unsigned short)offset; + } + } + else { - unsigned short offset; - if (!readshort(&offset)) - return NULL; - ((unsigned short*)(pf->offset))[i] = (unsigned short)offset; + long_offset = 1; + pf->offset = (unsigned short *)fileptr; + for (i=0; ioffset))[i] = (unsigned long)offset; + } } } else @@ -205,6 +223,141 @@ struct font* font_load(const char *path) return pf; /* success!*/ } +/* Load cached font */ +struct font* font_load_cached(struct font* pf) +{ + unsigned long noffset, nwidth; + unsigned char* oldfileptr = fileptr; + + /* # longs of offset*/ + if (!readlong(&noffset)) + return NULL; + + /* # bytes of width*/ + if (!readlong(&nwidth)) + return NULL; + + /* 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); + + if ( pf->bits_size < 0xFFDB ) + { + long_offset = 0; + /* pad to 16-bit boundary */ + fileptr = (unsigned char *)(((int)fileptr + 1) & ~1); + } + else + { + long_offset = 1; + /* pad to 32-bit boundary*/ + fileptr = (unsigned char *)(((int)fileptr + 3) & ~3); + } + + if (noffset) + file_offset_offset = (unsigned long)(fileptr - freeptr); + else + file_offset_offset = 0; + + /* Calculate offset to widths data */ + if ( pf->bits_size < 0xFFDB ) + fileptr += noffset * sizeof(unsigned short); + else + fileptr += noffset * sizeof(unsigned long); + + if (nwidth) + file_width_offset = (unsigned long)(fileptr - freeptr); + else + file_width_offset = 0; + + fileptr = oldfileptr; + + /* Create the cache */ + cache_create(pf->maxwidth, pf->height); + + return pf; +} + +/* read and load font into incore font structure*/ +struct font* font_load(const char *path) +{ + int filesize; + struct font* pf = &font_ui; + + /* save loaded glyphs */ + glyph_cache_save(); + + /* Close font file handle */ + if (fnt_file >= 0) + close(fnt_file); + + /* open and read entire font file*/ + fnt_file = open(path, O_RDONLY|O_BINARY); + + if (fnt_file < 0) { + DEBUGF("Can't open font: %s\n", path); + return NULL; + } + + /* Check file size */ + filesize = lseek(fnt_file, 0, SEEK_END); + lseek(fnt_file, 0, SEEK_SET); + + font_reset(); + + /* currently, font loading replaces earlier font allocation*/ + freeptr = (unsigned char *)(((int)mbuf + 3) & ~3); + fileptr = freeptr; + + + if (filesize > MAX_FONT_SIZE) + { + read(fnt_file, fileptr, FONT_HEADER_SIZE); + eofptr = fileptr + FONT_HEADER_SIZE; + + if (!font_load_header(pf)) + { + DEBUGF("Failed font header load"); + return NULL; + } + + if (!font_load_cached(pf)) + { + DEBUGF("Failed font cache load"); + return NULL; + } + + glyph_cache_load(); + } + else + { + read(fnt_file, fileptr, MAX_FONT_SIZE); + eofptr = fileptr + filesize; + close(fnt_file); + fnt_file = -1; + + if (!font_load_header(pf)) + { + DEBUGF("Failed font header load"); + return NULL; + } + + if (!font_load_in_memory(pf)) + { + DEBUGF("Failed mem load"); + return NULL; + } + } + + /* no need for multiple font loads currently*/ + /*freeptr += filesize;*/ + /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/ + + return pf; /* success!*/ +} + /* * Return a pointer to an incore font structure. * If the requested font isn't loaded/compiled-in, @@ -231,17 +384,18 @@ struct font* font_get(int font) int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber) { struct font* pf = font_get(fontnumber); - int ch; + unsigned short ch; int width = 0; - while((ch = *str++)) { + for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch)) + { /* check input range*/ if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) ch = pf->defaultchar; ch -= pf->firstchar; /* get proportional width and glyph bits*/ - width += pf->width? pf->width[ch]: pf->maxwidth; + width += font_get_width(pf,ch); } if ( w ) *w = width; @@ -250,6 +404,154 @@ int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber) return width; } +/* + * Reads an entry into cache entry + */ +static void +load_cache_entry(struct font_cache_entry* p, void* callback_data) +{ + struct font* pf = callback_data; + unsigned short char_code = p->_char_code; + unsigned char tmp[2]; + + if (file_width_offset) + { + int width_offset = file_width_offset + char_code; + lseek(fnt_file, width_offset, SEEK_SET); + read(fnt_file, &(p->width), 1); + } + else + { + p->width = pf->maxwidth; + } + + long bitmap_offset = 0; + + if (file_offset_offset) + { + long offset = file_offset_offset + char_code * (long_offset ? sizeof(long) : sizeof(short)); + lseek(fnt_file, offset, SEEK_SET); + read (fnt_file, tmp, 2); + bitmap_offset = tmp[0] | (tmp[1] << 8); + if (long_offset) { + read (fnt_file, tmp, 2); + bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24); + } + } + else + { + bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code; + } + + long file_offset = FONT_HEADER_SIZE + bitmap_offset; + lseek(fnt_file, file_offset, SEEK_SET); + + int src_bytes = p->width * ((pf->height + 7) / 8); + read(fnt_file, p->bitmap, src_bytes); +} + +/* + * Converts cbuf into a font cache + */ +static void cache_create(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); +} + +/* + * Returns width of character + */ +int font_get_width(struct font* pf, unsigned short char_code) +{ + return (fnt_file >= 0 && pf != &sysfont)? + font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width: + pf->width? pf->width[char_code]: pf->maxwidth; +} + +const unsigned char* font_get_bits(struct font* pf, unsigned short char_code) +{ + const unsigned char* bits; + if (fnt_file >= 0 && pf != &sysfont) + { + bits = + (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap; + } + else + { + bits = pf->bits + (pf->offset? + pf->offset[char_code]: + (((pf->height + 7) / 8) * pf->maxwidth * char_code)); + } + + return bits; +} + +void glyph_file_write(void* data) +{ + struct font_cache_entry* p = data; + unsigned char tmp[2]; + + if (p->_char_code != 0xffff && glyph_file >= 0) { + tmp[0] = p->_char_code >> 8; + tmp[1] = p->_char_code & 0xff; + if (write(glyph_file, tmp, 2) != 2) { + close(glyph_file); + glyph_file = -1; + } + } + return; +} + +/* save the char codes of the loaded glyphs to a file */ +void glyph_cache_save(void) +{ + + if (fnt_file >= 0) { + + glyph_file = creat(GLYPH_CACHE_FILE, 0); + + if (glyph_file < 0) return; + + lru_traverse(&font_cache_ui._lru, glyph_file_write); + + if (glyph_file >= 0) + close(glyph_file); + } + return; +} + +void glyph_cache_load(void) +{ + if (fnt_file >= 0) { + + int fd; + unsigned char tmp[2]; + unsigned short ch; + struct font* pf = &font_ui; + + fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY); + + if (fd >= 0) { + + while (read(fd, tmp, 2) == 2) { + ch = (tmp[0] << 8) | tmp[1]; + font_get_bits(pf, ch); + } + + close(fd); + } else { + /* load latin1 chars into cache */ + ch = 255 - pf->firstchar; + while (ch--) + font_get_bits(pf, ch); + } + } + return; +} #endif /* HAVE_LCD_BITMAP */ -- cgit v1.2.3