summaryrefslogtreecommitdiff
path: root/firmware/font.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/font.c')
-rw-r--r--firmware/font.c392
1 files changed, 347 insertions, 45 deletions
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 @@
33#include "file.h" 33#include "file.h"
34#include "debug.h" 34#include "debug.h"
35#include "panic.h" 35#include "panic.h"
36#include "rbunicode.h"
37/* Font cache includes */
38#include "font_cache.h"
39#include "lru.h"
36 40
37#ifndef O_BINARY 41#ifndef O_BINARY
38#define O_BINARY 0 42#define O_BINARY 0
@@ -53,6 +57,16 @@ static unsigned char *freeptr = mbuf;
53static unsigned char *fileptr; 57static unsigned char *fileptr;
54static unsigned char *eofptr; 58static unsigned char *eofptr;
55 59
60/* Font cache structures */
61static struct font_cache font_cache_ui;
62static int fnt_file = -1; /* >=0 if font is cached */
63unsigned long file_width_offset; /* offset to file width data */
64unsigned long file_offset_offset; /* offset to file offset data */
65static void cache_create(int maxwidth, int height);
66static int long_offset = 0;
67static int glyph_file;
68/* End Font cache structures */
69
56void font_init(void) 70void font_init(void)
57{ 71{
58 memset(&font_ui, 0, sizeof(struct font)); 72 memset(&font_ui, 0, sizeof(struct font));
@@ -94,41 +108,12 @@ void font_reset(void)
94 memset(&font_ui, 0, sizeof(struct font)); 108 memset(&font_ui, 0, sizeof(struct font));
95} 109}
96 110
97/* read and load font into incore font structure*/ 111static struct font* font_load_header(struct font *pf)
98struct font* font_load(const char *path)
99{ 112{
100 int fd, filesize; 113 char version[4+1];
101 unsigned short maxwidth, height, ascent, pad; 114 unsigned short maxwidth, height, ascent, pad;
102 unsigned long firstchar, defaultchar, size; 115 unsigned long firstchar, defaultchar, size;
103 unsigned long i, nbits, noffset, nwidth; 116 unsigned long nbits;
104 char version[4+1];
105 struct font* pf = &font_ui;
106
107 /* open and read entire font file*/
108 fd = open(path, O_RDONLY|O_BINARY);
109 if (fd < 0) {
110 DEBUGF("Can't open font: %s\n", path);
111 return NULL;
112 }
113
114 font_reset();
115
116 /* currently, font loading replaces earlier font allocation*/
117 freeptr = (unsigned char *)(((int)mbuf + 3) & ~3);
118
119 fileptr = freeptr;
120 filesize = read(fd, fileptr, MAX_FONT_SIZE);
121 eofptr = fileptr + filesize;
122
123 /* no need for multiple font loads currently*/
124 /*freeptr += filesize;*/
125 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
126
127 close(fd);
128 if (filesize == MAX_FONT_SIZE) {
129 DEBUGF("Font %s too large: %d\n", path, filesize);
130 return NULL;
131 }
132 117
133 /* read magic and version #*/ 118 /* read magic and version #*/
134 memset(version, 0, sizeof(version)); 119 memset(version, 0, sizeof(version));
@@ -163,6 +148,14 @@ struct font* font_load(const char *path)
163 /* # words of bitmap_t*/ 148 /* # words of bitmap_t*/
164 if (!readlong(&nbits)) 149 if (!readlong(&nbits))
165 return NULL; 150 return NULL;
151 pf->bits_size = nbits;
152
153 return pf;
154}
155/* Load memory font */
156struct font* font_load_in_memory(struct font* pf)
157{
158 long i, noffset, nwidth;
166 159
167 /* # longs of offset*/ 160 /* # longs of offset*/
168 if (!readlong(&noffset)) 161 if (!readlong(&noffset))
@@ -174,19 +167,44 @@ struct font* font_load(const char *path)
174 167
175 /* variable font data*/ 168 /* variable font data*/
176 pf->bits = (unsigned char *)fileptr; 169 pf->bits = (unsigned char *)fileptr;
177 fileptr += nbits*sizeof(unsigned char); 170 fileptr += pf->bits_size*sizeof(unsigned char);
178 171
179 /* pad to 16 bit boundary*/ 172 if ( pf->bits_size < 0xFFDB )
180 fileptr = (unsigned char *)(((long)fileptr + 1) & ~1); 173 {
174 /* pad to 16-bit boundary */
175 fileptr = (unsigned char *)(((int)fileptr + 1) & ~1);
176 }
177 else
178 {
179 /* pad to 32-bit boundary*/
180 fileptr = (unsigned char *)(((int)fileptr + 3) & ~3);
181 }
181 182
182 if (noffset) { 183 if (noffset)
183 pf->offset = (unsigned short *)fileptr; 184 {
184 for (i=0; i<noffset; ++i) 185 if ( pf->bits_size < 0xFFDB )
186 {
187 long_offset = 0;
188 pf->offset = (unsigned short *)fileptr;
189 for (i=0; i<noffset; ++i)
190 {
191 unsigned short offset;
192 if (!readshort(&offset))
193 return NULL;
194 ((unsigned short*)(pf->offset))[i] = (unsigned short)offset;
195 }
196 }
197 else
185 { 198 {
186 unsigned short offset; 199 long_offset = 1;
187 if (!readshort(&offset)) 200 pf->offset = (unsigned short *)fileptr;
188 return NULL; 201 for (i=0; i<noffset; ++i)
189 ((unsigned short*)(pf->offset))[i] = (unsigned short)offset; 202 {
203 unsigned long offset;
204 if (!readlong(&offset))
205 return NULL;
206 ((unsigned long*)(pf->offset))[i] = (unsigned long)offset;
207 }
190 } 208 }
191 } 209 }
192 else 210 else
@@ -205,6 +223,141 @@ struct font* font_load(const char *path)
205 return pf; /* success!*/ 223 return pf; /* success!*/
206} 224}
207 225
226/* Load cached font */
227struct font* font_load_cached(struct font* pf)
228{
229 unsigned long noffset, nwidth;
230 unsigned char* oldfileptr = fileptr;
231
232 /* # longs of offset*/
233 if (!readlong(&noffset))
234 return NULL;
235
236 /* # bytes of width*/
237 if (!readlong(&nwidth))
238 return NULL;
239
240 /* We are now at the bitmap data, this is fixed at 36.. */
241 pf->bits = NULL;
242
243 /* Calculate offset to offset data */
244 fileptr += pf->bits_size * sizeof(unsigned char);
245
246 if ( pf->bits_size < 0xFFDB )
247 {
248 long_offset = 0;
249 /* pad to 16-bit boundary */
250 fileptr = (unsigned char *)(((int)fileptr + 1) & ~1);
251 }
252 else
253 {
254 long_offset = 1;
255 /* pad to 32-bit boundary*/
256 fileptr = (unsigned char *)(((int)fileptr + 3) & ~3);
257 }
258
259 if (noffset)
260 file_offset_offset = (unsigned long)(fileptr - freeptr);
261 else
262 file_offset_offset = 0;
263
264 /* Calculate offset to widths data */
265 if ( pf->bits_size < 0xFFDB )
266 fileptr += noffset * sizeof(unsigned short);
267 else
268 fileptr += noffset * sizeof(unsigned long);
269
270 if (nwidth)
271 file_width_offset = (unsigned long)(fileptr - freeptr);
272 else
273 file_width_offset = 0;
274
275 fileptr = oldfileptr;
276
277 /* Create the cache */
278 cache_create(pf->maxwidth, pf->height);
279
280 return pf;
281}
282
283/* read and load font into incore font structure*/
284struct font* font_load(const char *path)
285{
286 int filesize;
287 struct font* pf = &font_ui;
288
289 /* save loaded glyphs */
290 glyph_cache_save();
291
292 /* Close font file handle */
293 if (fnt_file >= 0)
294 close(fnt_file);
295
296 /* open and read entire font file*/
297 fnt_file = open(path, O_RDONLY|O_BINARY);
298
299 if (fnt_file < 0) {
300 DEBUGF("Can't open font: %s\n", path);
301 return NULL;
302 }
303
304 /* Check file size */
305 filesize = lseek(fnt_file, 0, SEEK_END);
306 lseek(fnt_file, 0, SEEK_SET);
307
308 font_reset();
309
310 /* currently, font loading replaces earlier font allocation*/
311 freeptr = (unsigned char *)(((int)mbuf + 3) & ~3);
312 fileptr = freeptr;
313
314
315 if (filesize > MAX_FONT_SIZE)
316 {
317 read(fnt_file, fileptr, FONT_HEADER_SIZE);
318 eofptr = fileptr + FONT_HEADER_SIZE;
319
320 if (!font_load_header(pf))
321 {
322 DEBUGF("Failed font header load");
323 return NULL;
324 }
325
326 if (!font_load_cached(pf))
327 {
328 DEBUGF("Failed font cache load");
329 return NULL;
330 }
331
332 glyph_cache_load();
333 }
334 else
335 {
336 read(fnt_file, fileptr, MAX_FONT_SIZE);
337 eofptr = fileptr + filesize;
338 close(fnt_file);
339 fnt_file = -1;
340
341 if (!font_load_header(pf))
342 {
343 DEBUGF("Failed font header load");
344 return NULL;
345 }
346
347 if (!font_load_in_memory(pf))
348 {
349 DEBUGF("Failed mem load");
350 return NULL;
351 }
352 }
353
354 /* no need for multiple font loads currently*/
355 /*freeptr += filesize;*/
356 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
357
358 return pf; /* success!*/
359}
360
208/* 361/*
209 * Return a pointer to an incore font structure. 362 * Return a pointer to an incore font structure.
210 * If the requested font isn't loaded/compiled-in, 363 * If the requested font isn't loaded/compiled-in,
@@ -231,17 +384,18 @@ struct font* font_get(int font)
231int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber) 384int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
232{ 385{
233 struct font* pf = font_get(fontnumber); 386 struct font* pf = font_get(fontnumber);
234 int ch; 387 unsigned short ch;
235 int width = 0; 388 int width = 0;
236 389
237 while((ch = *str++)) { 390 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
391 {
238 /* check input range*/ 392 /* check input range*/
239 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) 393 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
240 ch = pf->defaultchar; 394 ch = pf->defaultchar;
241 ch -= pf->firstchar; 395 ch -= pf->firstchar;
242 396
243 /* get proportional width and glyph bits*/ 397 /* get proportional width and glyph bits*/
244 width += pf->width? pf->width[ch]: pf->maxwidth; 398 width += font_get_width(pf,ch);
245 } 399 }
246 if ( w ) 400 if ( w )
247 *w = width; 401 *w = width;
@@ -250,6 +404,154 @@ int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
250 return width; 404 return width;
251} 405}
252 406
407/*
408 * Reads an entry into cache entry
409 */
410static void
411load_cache_entry(struct font_cache_entry* p, void* callback_data)
412{
413 struct font* pf = callback_data;
414 unsigned short char_code = p->_char_code;
415 unsigned char tmp[2];
416
417 if (file_width_offset)
418 {
419 int width_offset = file_width_offset + char_code;
420 lseek(fnt_file, width_offset, SEEK_SET);
421 read(fnt_file, &(p->width), 1);
422 }
423 else
424 {
425 p->width = pf->maxwidth;
426 }
427
428 long bitmap_offset = 0;
429
430 if (file_offset_offset)
431 {
432 long offset = file_offset_offset + char_code * (long_offset ? sizeof(long) : sizeof(short));
433 lseek(fnt_file, offset, SEEK_SET);
434 read (fnt_file, tmp, 2);
435 bitmap_offset = tmp[0] | (tmp[1] << 8);
436 if (long_offset) {
437 read (fnt_file, tmp, 2);
438 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
439 }
440 }
441 else
442 {
443 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
444 }
445
446 long file_offset = FONT_HEADER_SIZE + bitmap_offset;
447 lseek(fnt_file, file_offset, SEEK_SET);
448
449 int src_bytes = p->width * ((pf->height + 7) / 8);
450 read(fnt_file, p->bitmap, src_bytes);
451}
452
453/*
454 * Converts cbuf into a font cache
455 */
456static void cache_create(int maxwidth, int height)
457{
458 /* maximum size of rotated bitmap */
459 int bitmap_size = maxwidth * ((height + 7) / 8);
460
461 /* Initialise cache */
462 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
463}
464
465/*
466 * Returns width of character
467 */
468int font_get_width(struct font* pf, unsigned short char_code)
469{
470 return (fnt_file >= 0 && pf != &sysfont)?
471 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
472 pf->width? pf->width[char_code]: pf->maxwidth;
473}
474
475const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
476{
477 const unsigned char* bits;
478 if (fnt_file >= 0 && pf != &sysfont)
479 {
480 bits =
481 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
482 }
483 else
484 {
485 bits = pf->bits + (pf->offset?
486 pf->offset[char_code]:
487 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
488 }
489
490 return bits;
491}
492
493void glyph_file_write(void* data)
494{
495 struct font_cache_entry* p = data;
496 unsigned char tmp[2];
497
498 if (p->_char_code != 0xffff && glyph_file >= 0) {
499 tmp[0] = p->_char_code >> 8;
500 tmp[1] = p->_char_code & 0xff;
501 if (write(glyph_file, tmp, 2) != 2) {
502 close(glyph_file);
503 glyph_file = -1;
504 }
505 }
506 return;
507}
508
509/* save the char codes of the loaded glyphs to a file */
510void glyph_cache_save(void)
511{
512
513 if (fnt_file >= 0) {
514
515 glyph_file = creat(GLYPH_CACHE_FILE, 0);
516
517 if (glyph_file < 0) return;
518
519 lru_traverse(&font_cache_ui._lru, glyph_file_write);
520
521 if (glyph_file >= 0)
522 close(glyph_file);
523 }
524 return;
525}
526
527void glyph_cache_load(void)
528{
529 if (fnt_file >= 0) {
530
531 int fd;
532 unsigned char tmp[2];
533 unsigned short ch;
534 struct font* pf = &font_ui;
535
536 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
537
538 if (fd >= 0) {
539
540 while (read(fd, tmp, 2) == 2) {
541 ch = (tmp[0] << 8) | tmp[1];
542 font_get_bits(pf, ch);
543 }
544
545 close(fd);
546 } else {
547 /* load latin1 chars into cache */
548 ch = 255 - pf->firstchar;
549 while (ch--)
550 font_get_bits(pf, ch);
551 }
552 }
553 return;
554}
253 555
254#endif /* HAVE_LCD_BITMAP */ 556#endif /* HAVE_LCD_BITMAP */
255 557