clean up some debugging output.
[Rockbox.git] / firmware / font.c
blob03e18919daa36f2602f27aa96843bcc80db1c275
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (c) 2002 by Greg Haerr <greg@censoft.com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 * Rockbox startup font initialization
23 * This file specifies which fonts get compiled-in and
24 * loaded at startup, as well as their mapping into
25 * the FONT_SYSFIXED, FONT_UI and FONT_MP3 ids.
27 #include "config.h"
29 #if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
31 #include <stdio.h>
32 #include <string.h>
33 #include "inttypes.h"
34 #include "lcd.h"
35 #include "font.h"
36 #include "file.h"
37 #include "debug.h"
38 #include "panic.h"
39 #include "rbunicode.h"
40 /* Font cache includes */
41 #include "font_cache.h"
42 #include "lru.h"
44 #ifndef O_BINARY
45 #define O_BINARY 0
46 #endif
48 /* compiled-in font */
49 extern struct font sysfont;
51 /* structure filled in by font_load */
52 static struct font font_ui;
54 /* system font table, in order of FONT_xxx definition */
55 static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
57 /* static buffer allocation structures */
58 static unsigned char mbuf[MAX_FONT_SIZE];
59 static unsigned char *freeptr = mbuf;
60 static unsigned char *fileptr;
61 static unsigned char *eofptr;
63 /* Font cache structures */
64 static struct font_cache font_cache_ui;
65 static int fnt_file = -1; /* >=0 if font is cached */
66 static uint32_t file_width_offset; /* offset to file width data */
67 static uint32_t file_offset_offset; /* offset to file offset data */
68 static void cache_create(int maxwidth, int height);
69 static int long_offset = 0;
70 static int glyph_file;
71 /* End Font cache structures */
73 static void glyph_cache_load(void);
75 void font_init(void)
77 memset(&font_ui, 0, sizeof(struct font));
80 /* Check if we have x bytes left in the file buffer */
81 #define HAVEBYTES(x) (fileptr + (x) <= eofptr)
83 /* Helper functions to read big-endian unaligned short or long from
84 the file buffer. Bounds-checking must be done in the calling
85 function.
88 static short readshort(void)
90 unsigned short s;
92 s = *fileptr++ & 0xff;
93 s |= (*fileptr++ << 8);
94 return s;
97 static int32_t readlong(void)
99 uint32_t l;
101 l = *fileptr++ & 0xff;
102 l |= *fileptr++ << 8;
103 l |= ((uint32_t)(*fileptr++)) << 16;
104 l |= ((uint32_t)(*fileptr++)) << 24;
105 return l;
108 /* read count bytes*/
109 static void readstr(char *buf, int count)
111 while (count--)
112 *buf++ = *fileptr++;
115 void font_reset(void)
117 memset(&font_ui, 0, sizeof(struct font));
120 static struct font* font_load_header(struct font *pf)
122 char version[4+1];
124 /* Check we have enough data */
125 if (!HAVEBYTES(28))
126 return NULL;
128 /* read magic and version #*/
129 memset(version, 0, sizeof(version));
130 readstr(version, 4);
132 if (strcmp(version, VERSION) != 0)
133 return NULL;
135 /* font info*/
136 pf->maxwidth = readshort();
137 pf->height = readshort();
138 pf->ascent = readshort();
139 fileptr += 2; /* Skip padding */
140 pf->firstchar = readlong();
141 pf->defaultchar = readlong();
142 pf->size = readlong();
144 /* get variable font data sizes*/
145 /* # words of bitmap_t*/
146 pf->bits_size = readlong();
148 return pf;
150 /* Load memory font */
151 static struct font* font_load_in_memory(struct font* pf)
153 int32_t i, noffset, nwidth;
155 if (!HAVEBYTES(4))
156 return NULL;
158 /* # longs of offset*/
159 noffset = readlong();
161 /* # bytes of width*/
162 nwidth = readlong();
164 /* variable font data*/
165 pf->bits = (unsigned char *)fileptr;
166 fileptr += pf->bits_size*sizeof(unsigned char);
168 if ( pf->bits_size < 0xFFDB )
170 /* pad to 16-bit boundary */
171 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
173 else
175 /* pad to 32-bit boundary*/
176 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
179 if (noffset)
181 if ( pf->bits_size < 0xFFDB )
183 long_offset = 0;
184 pf->offset = (unsigned short *)fileptr;
186 /* Check we have sufficient buffer */
187 if (!HAVEBYTES(noffset * sizeof(short)))
188 return NULL;
190 for (i=0; i<noffset; ++i)
192 ((unsigned short*)(pf->offset))[i] = (unsigned short)readshort();
195 else
197 long_offset = 1;
198 pf->offset = (unsigned short *)fileptr;
200 /* Check we have sufficient buffer */
201 if (!HAVEBYTES(noffset * sizeof(int32_t)))
202 return NULL;
204 for (i=0; i<noffset; ++i)
206 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong();
210 else
211 pf->offset = NULL;
213 if (nwidth) {
214 pf->width = (unsigned char *)fileptr;
215 fileptr += nwidth*sizeof(unsigned char);
217 else
218 pf->width = NULL;
220 if (fileptr > eofptr)
221 return NULL;
223 return pf; /* success!*/
226 /* Load cached font */
227 static struct font* font_load_cached(struct font* pf)
229 uint32_t noffset, nwidth;
230 unsigned char* oldfileptr = fileptr;
232 if (!HAVEBYTES(2 * sizeof(int32_t)))
233 return NULL;
235 /* # longs of offset*/
236 noffset = readlong();
238 /* # bytes of width*/
239 nwidth = readlong();
241 /* We are now at the bitmap data, this is fixed at 36.. */
242 pf->bits = NULL;
244 /* Calculate offset to offset data */
245 fileptr += pf->bits_size * sizeof(unsigned char);
247 if ( pf->bits_size < 0xFFDB )
249 long_offset = 0;
250 /* pad to 16-bit boundary */
251 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
253 else
255 long_offset = 1;
256 /* pad to 32-bit boundary*/
257 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
260 if (noffset)
261 file_offset_offset = (uint32_t)(fileptr - freeptr);
262 else
263 file_offset_offset = 0;
265 /* Calculate offset to widths data */
266 if ( pf->bits_size < 0xFFDB )
267 fileptr += noffset * sizeof(unsigned short);
268 else
269 fileptr += noffset * sizeof(uint32_t);
271 if (nwidth)
272 file_width_offset = (uint32_t)(fileptr - freeptr);
273 else
274 file_width_offset = 0;
276 fileptr = oldfileptr;
278 /* Create the cache */
279 cache_create(pf->maxwidth, pf->height);
281 return pf;
284 /* read and load font into incore font structure*/
285 struct font* font_load(const char *path)
287 int size;
288 struct font* pf = &font_ui;
290 /* save loaded glyphs */
291 glyph_cache_save();
293 /* Close font file handle */
294 if (fnt_file >= 0)
295 close(fnt_file);
297 /* open and read entire font file*/
298 fnt_file = open(path, O_RDONLY|O_BINARY);
300 if (fnt_file < 0) {
301 DEBUGF("Can't open font: %s\n", path);
302 return NULL;
305 /* Check file size */
306 size = filesize(fnt_file);
308 font_reset();
310 /* currently, font loading replaces earlier font allocation*/
311 freeptr = (unsigned char *)(((intptr_t)mbuf + 3) & ~3);
312 fileptr = freeptr;
315 if (size > MAX_FONT_SIZE)
317 read(fnt_file, fileptr, FONT_HEADER_SIZE);
318 eofptr = fileptr + FONT_HEADER_SIZE;
320 if (!font_load_header(pf))
322 DEBUGF("Failed font header load");
323 return NULL;
326 if (!font_load_cached(pf))
328 DEBUGF("Failed font cache load");
329 return NULL;
332 glyph_cache_load();
334 else
336 read(fnt_file, fileptr, MAX_FONT_SIZE);
337 eofptr = fileptr + size;
338 close(fnt_file);
339 fnt_file = -1;
341 if (!font_load_header(pf))
343 DEBUGF("Failed font header load");
344 return NULL;
347 if (!font_load_in_memory(pf))
349 DEBUGF("Failed mem load");
350 return NULL;
354 /* no need for multiple font loads currently*/
355 /*freeptr += filesize;*/
356 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
358 return pf; /* success!*/
362 * Return a pointer to an incore font structure.
363 * If the requested font isn't loaded/compiled-in,
364 * decrement the font number and try again.
366 struct font* font_get(int font)
368 struct font* pf;
370 if (font >= MAXFONTS)
371 font = 0;
373 while (1) {
374 pf = sysfonts[font];
375 if (pf && pf->height)
376 return pf;
377 if (--font < 0)
378 panicf("No font!");
382 * Returns the stringsize of a given string.
384 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
386 struct font* pf = font_get(fontnumber);
387 unsigned short ch;
388 int width = 0;
390 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
393 /* get proportional width and glyph bits*/
394 width += font_get_width(pf,ch);
396 if ( w )
397 *w = width;
398 if ( h )
399 *h = pf->height;
400 return width;
404 * Reads an entry into cache entry
406 static void
407 load_cache_entry(struct font_cache_entry* p, void* callback_data)
409 struct font* pf = callback_data;
410 unsigned short char_code = p->_char_code;
411 unsigned char tmp[2];
413 if (file_width_offset)
415 int width_offset = file_width_offset + char_code;
416 lseek(fnt_file, width_offset, SEEK_SET);
417 read(fnt_file, &(p->width), 1);
419 else
421 p->width = pf->maxwidth;
424 int32_t bitmap_offset = 0;
426 if (file_offset_offset)
428 int32_t offset = file_offset_offset + char_code * (long_offset ? sizeof(int32_t) : sizeof(short));
429 lseek(fnt_file, offset, SEEK_SET);
430 read (fnt_file, tmp, 2);
431 bitmap_offset = tmp[0] | (tmp[1] << 8);
432 if (long_offset) {
433 read (fnt_file, tmp, 2);
434 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
437 else
439 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
442 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
443 lseek(fnt_file, file_offset, SEEK_SET);
445 int src_bytes = p->width * ((pf->height + 7) / 8);
446 read(fnt_file, p->bitmap, src_bytes);
450 * Converts cbuf into a font cache
452 static void cache_create(int maxwidth, int height)
454 /* maximum size of rotated bitmap */
455 int bitmap_size = maxwidth * ((height + 7) / 8);
457 /* Initialise cache */
458 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
462 * Returns width of character
464 int font_get_width(struct font* pf, unsigned short char_code)
466 /* check input range*/
467 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
468 char_code = pf->defaultchar;
469 char_code -= pf->firstchar;
471 return (fnt_file >= 0 && pf != &sysfont)?
472 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
473 pf->width? pf->width[char_code]: pf->maxwidth;
476 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
478 const unsigned char* bits;
480 /* check input range*/
481 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
482 char_code = pf->defaultchar;
483 char_code -= pf->firstchar;
485 if (fnt_file >= 0 && pf != &sysfont)
487 bits =
488 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
490 else
492 bits = pf->bits + (pf->offset?
493 pf->offset[char_code]:
494 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
497 return bits;
500 static void glyph_file_write(void* data)
502 struct font_cache_entry* p = data;
503 struct font* pf = &font_ui;
504 unsigned short ch;
505 unsigned char tmp[2];
507 ch = p->_char_code + pf->firstchar;
509 if (ch != 0xffff && glyph_file >= 0) {
510 tmp[0] = ch >> 8;
511 tmp[1] = ch & 0xff;
512 if (write(glyph_file, tmp, 2) != 2) {
513 close(glyph_file);
514 glyph_file = -1;
517 return;
520 /* save the char codes of the loaded glyphs to a file */
521 void glyph_cache_save(void)
524 if (fnt_file >= 0) {
526 glyph_file = creat(GLYPH_CACHE_FILE);
528 if (glyph_file < 0) return;
530 lru_traverse(&font_cache_ui._lru, glyph_file_write);
532 if (glyph_file >= 0)
533 close(glyph_file);
535 return;
538 static void glyph_cache_load(void)
540 if (fnt_file >= 0) {
542 int fd;
543 unsigned char tmp[2];
544 unsigned short ch;
545 struct font* pf = &font_ui;
547 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
549 if (fd >= 0) {
551 while (read(fd, tmp, 2) == 2) {
552 ch = (tmp[0] << 8) | tmp[1];
553 font_get_bits(pf, ch);
556 close(fd);
557 } else {
558 /* load latin1 chars into cache */
559 ch = 256;
560 while (ch-- > 32)
561 font_get_bits(pf, ch);
564 return;
567 #endif /* HAVE_LCD_BITMAP */
569 /* -----------------------------------------------------------------
570 * vim: et sw=4 ts=8 sts=4 tw=78