Make bufadvance rely on bufseek instead of duplicating code
[Rockbox.git] / firmware / font.c
blobc58087daa3d0eb9f1d12be74c1a6c6f5cec2cf8b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (c) 2002 by Greg Haerr <greg@censoft.com>
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 * Rockbox startup font initialization
21 * This file specifies which fonts get compiled-in and
22 * loaded at startup, as well as their mapping into
23 * the FONT_SYSFIXED, FONT_UI and FONT_MP3 ids.
25 #include "config.h"
27 #if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
29 #include <stdio.h>
30 #include <string.h>
31 #include "inttypes.h"
32 #include "lcd.h"
33 #include "font.h"
34 #include "file.h"
35 #include "debug.h"
36 #include "panic.h"
37 #include "rbunicode.h"
38 /* Font cache includes */
39 #include "font_cache.h"
40 #include "lru.h"
42 #ifndef O_BINARY
43 #define O_BINARY 0
44 #endif
46 /* compiled-in font */
47 extern struct font sysfont;
49 /* structure filled in by font_load */
50 static struct font font_ui;
52 /* system font table, in order of FONT_xxx definition */
53 static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
55 /* static buffer allocation structures */
56 static unsigned char mbuf[MAX_FONT_SIZE];
57 static unsigned char *freeptr = mbuf;
58 static unsigned char *fileptr;
59 static unsigned char *eofptr;
61 /* Font cache structures */
62 static struct font_cache font_cache_ui;
63 static int fnt_file = -1; /* >=0 if font is cached */
64 uint32_t file_width_offset; /* offset to file width data */
65 uint32_t file_offset_offset; /* offset to file offset data */
66 static void cache_create(int maxwidth, int height);
67 static int long_offset = 0;
68 static int glyph_file;
69 /* End Font cache structures */
71 static void glyph_cache_load(void);
73 void font_init(void)
75 memset(&font_ui, 0, sizeof(struct font));
78 /* Check if we have x bytes left in the file buffer */
79 #define HAVEBYTES(x) (fileptr + (x) <= eofptr)
81 /* Helper functions to read big-endian unaligned short or long from
82 the file buffer. Bounds-checking must be done in the calling
83 function.
86 static short readshort(void)
88 unsigned short s;
90 s = *fileptr++ & 0xff;
91 s |= (*fileptr++ << 8);
92 return s;
95 static int32_t readlong(void)
97 uint32_t l;
99 l = *fileptr++ & 0xff;
100 l |= *fileptr++ << 8;
101 l |= ((uint32_t)(*fileptr++)) << 16;
102 l |= ((uint32_t)(*fileptr++)) << 24;
103 return l;
106 /* read count bytes*/
107 static void readstr(char *buf, int count)
109 while (count--)
110 *buf++ = *fileptr++;
113 void font_reset(void)
115 memset(&font_ui, 0, sizeof(struct font));
118 static struct font* font_load_header(struct font *pf)
120 char version[4+1];
122 /* Check we have enough data */
123 if (!HAVEBYTES(28))
124 return NULL;
126 /* read magic and version #*/
127 memset(version, 0, sizeof(version));
128 readstr(version, 4);
130 if (strcmp(version, VERSION) != 0)
131 return NULL;
133 /* font info*/
134 pf->maxwidth = readshort();
135 pf->height = readshort();
136 pf->ascent = readshort();
137 fileptr += 2; /* Skip padding */
138 pf->firstchar = readlong();
139 pf->defaultchar = readlong();
140 pf->size = readlong();
142 /* get variable font data sizes*/
143 /* # words of bitmap_t*/
144 pf->bits_size = readlong();
146 return pf;
148 /* Load memory font */
149 static struct font* font_load_in_memory(struct font* pf)
151 int32_t i, noffset, nwidth;
153 if (!HAVEBYTES(4))
154 return NULL;
156 /* # longs of offset*/
157 noffset = readlong();
159 /* # bytes of width*/
160 nwidth = readlong();
162 /* variable font data*/
163 pf->bits = (unsigned char *)fileptr;
164 fileptr += pf->bits_size*sizeof(unsigned char);
166 if ( pf->bits_size < 0xFFDB )
168 /* pad to 16-bit boundary */
169 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
171 else
173 /* pad to 32-bit boundary*/
174 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
177 if (noffset)
179 if ( pf->bits_size < 0xFFDB )
181 long_offset = 0;
182 pf->offset = (unsigned short *)fileptr;
184 /* Check we have sufficient buffer */
185 if (!HAVEBYTES(noffset * sizeof(short)))
186 return NULL;
188 for (i=0; i<noffset; ++i)
190 ((unsigned short*)(pf->offset))[i] = (unsigned short)readshort();
193 else
195 long_offset = 1;
196 pf->offset = (unsigned short *)fileptr;
198 /* Check we have sufficient buffer */
199 if (!HAVEBYTES(noffset * sizeof(int32_t)))
200 return NULL;
202 for (i=0; i<noffset; ++i)
204 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong();
208 else
209 pf->offset = NULL;
211 if (nwidth) {
212 pf->width = (unsigned char *)fileptr;
213 fileptr += nwidth*sizeof(unsigned char);
215 else
216 pf->width = NULL;
218 if (fileptr > eofptr)
219 return NULL;
221 return pf; /* success!*/
224 /* Load cached font */
225 static struct font* font_load_cached(struct font* pf)
227 uint32_t noffset, nwidth;
228 unsigned char* oldfileptr = fileptr;
230 if (!HAVEBYTES(2 * sizeof(int32_t)))
231 return NULL;
233 /* # longs of offset*/
234 noffset = readlong();
236 /* # bytes of width*/
237 nwidth = readlong();
239 /* We are now at the bitmap data, this is fixed at 36.. */
240 pf->bits = NULL;
242 /* Calculate offset to offset data */
243 fileptr += pf->bits_size * sizeof(unsigned char);
245 if ( pf->bits_size < 0xFFDB )
247 long_offset = 0;
248 /* pad to 16-bit boundary */
249 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
251 else
253 long_offset = 1;
254 /* pad to 32-bit boundary*/
255 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
258 if (noffset)
259 file_offset_offset = (uint32_t)(fileptr - freeptr);
260 else
261 file_offset_offset = 0;
263 /* Calculate offset to widths data */
264 if ( pf->bits_size < 0xFFDB )
265 fileptr += noffset * sizeof(unsigned short);
266 else
267 fileptr += noffset * sizeof(uint32_t);
269 if (nwidth)
270 file_width_offset = (uint32_t)(fileptr - freeptr);
271 else
272 file_width_offset = 0;
274 fileptr = oldfileptr;
276 /* Create the cache */
277 cache_create(pf->maxwidth, pf->height);
279 return pf;
282 /* read and load font into incore font structure*/
283 struct font* font_load(const char *path)
285 int size;
286 struct font* pf = &font_ui;
288 /* save loaded glyphs */
289 glyph_cache_save();
291 /* Close font file handle */
292 if (fnt_file >= 0)
293 close(fnt_file);
295 /* open and read entire font file*/
296 fnt_file = open(path, O_RDONLY|O_BINARY);
298 if (fnt_file < 0) {
299 DEBUGF("Can't open font: %s\n", path);
300 return NULL;
303 /* Check file size */
304 size = filesize(fnt_file);
306 font_reset();
308 /* currently, font loading replaces earlier font allocation*/
309 freeptr = (unsigned char *)(((intptr_t)mbuf + 3) & ~3);
310 fileptr = freeptr;
313 if (size > MAX_FONT_SIZE)
315 read(fnt_file, fileptr, FONT_HEADER_SIZE);
316 eofptr = fileptr + FONT_HEADER_SIZE;
318 if (!font_load_header(pf))
320 DEBUGF("Failed font header load");
321 return NULL;
324 if (!font_load_cached(pf))
326 DEBUGF("Failed font cache load");
327 return NULL;
330 glyph_cache_load();
332 else
334 read(fnt_file, fileptr, MAX_FONT_SIZE);
335 eofptr = fileptr + size;
336 close(fnt_file);
337 fnt_file = -1;
339 if (!font_load_header(pf))
341 DEBUGF("Failed font header load");
342 return NULL;
345 if (!font_load_in_memory(pf))
347 DEBUGF("Failed mem load");
348 return NULL;
352 /* no need for multiple font loads currently*/
353 /*freeptr += filesize;*/
354 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
356 return pf; /* success!*/
360 * Return a pointer to an incore font structure.
361 * If the requested font isn't loaded/compiled-in,
362 * decrement the font number and try again.
364 struct font* font_get(int font)
366 struct font* pf;
368 if (font >= MAXFONTS)
369 font = 0;
371 while (1) {
372 pf = sysfonts[font];
373 if (pf && pf->height)
374 return pf;
375 if (--font < 0)
376 panicf("No font!");
380 * Returns the stringsize of a given string.
382 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
384 struct font* pf = font_get(fontnumber);
385 unsigned short ch;
386 int width = 0;
388 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
391 /* get proportional width and glyph bits*/
392 width += font_get_width(pf,ch);
394 if ( w )
395 *w = width;
396 if ( h )
397 *h = pf->height;
398 return width;
402 * Reads an entry into cache entry
404 static void
405 load_cache_entry(struct font_cache_entry* p, void* callback_data)
407 struct font* pf = callback_data;
408 unsigned short char_code = p->_char_code;
409 unsigned char tmp[2];
411 if (file_width_offset)
413 int width_offset = file_width_offset + char_code;
414 lseek(fnt_file, width_offset, SEEK_SET);
415 read(fnt_file, &(p->width), 1);
417 else
419 p->width = pf->maxwidth;
422 int32_t bitmap_offset = 0;
424 if (file_offset_offset)
426 int32_t offset = file_offset_offset + char_code * (long_offset ? sizeof(int32_t) : sizeof(short));
427 lseek(fnt_file, offset, SEEK_SET);
428 read (fnt_file, tmp, 2);
429 bitmap_offset = tmp[0] | (tmp[1] << 8);
430 if (long_offset) {
431 read (fnt_file, tmp, 2);
432 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
435 else
437 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
440 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
441 lseek(fnt_file, file_offset, SEEK_SET);
443 int src_bytes = p->width * ((pf->height + 7) / 8);
444 read(fnt_file, p->bitmap, src_bytes);
448 * Converts cbuf into a font cache
450 static void cache_create(int maxwidth, int height)
452 /* maximum size of rotated bitmap */
453 int bitmap_size = maxwidth * ((height + 7) / 8);
455 /* Initialise cache */
456 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
460 * Returns width of character
462 int font_get_width(struct font* pf, unsigned short char_code)
464 /* check input range*/
465 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
466 char_code = pf->defaultchar;
467 char_code -= pf->firstchar;
469 return (fnt_file >= 0 && pf != &sysfont)?
470 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
471 pf->width? pf->width[char_code]: pf->maxwidth;
474 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
476 const unsigned char* bits;
478 /* check input range*/
479 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
480 char_code = pf->defaultchar;
481 char_code -= pf->firstchar;
483 if (fnt_file >= 0 && pf != &sysfont)
485 bits =
486 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
488 else
490 bits = pf->bits + (pf->offset?
491 pf->offset[char_code]:
492 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
495 return bits;
498 static void glyph_file_write(void* data)
500 struct font_cache_entry* p = data;
501 struct font* pf = &font_ui;
502 unsigned short ch;
503 unsigned char tmp[2];
505 ch = p->_char_code + pf->firstchar;
507 if (ch != 0xffff && glyph_file >= 0) {
508 tmp[0] = ch >> 8;
509 tmp[1] = ch & 0xff;
510 if (write(glyph_file, tmp, 2) != 2) {
511 close(glyph_file);
512 glyph_file = -1;
515 return;
518 /* save the char codes of the loaded glyphs to a file */
519 void glyph_cache_save(void)
522 if (fnt_file >= 0) {
524 glyph_file = creat(GLYPH_CACHE_FILE);
526 if (glyph_file < 0) return;
528 lru_traverse(&font_cache_ui._lru, glyph_file_write);
530 if (glyph_file >= 0)
531 close(glyph_file);
533 return;
536 static void glyph_cache_load(void)
538 if (fnt_file >= 0) {
540 int fd;
541 unsigned char tmp[2];
542 unsigned short ch;
543 struct font* pf = &font_ui;
545 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
547 if (fd >= 0) {
549 while (read(fd, tmp, 2) == 2) {
550 ch = (tmp[0] << 8) | tmp[1];
551 font_get_bits(pf, ch);
554 close(fd);
555 } else {
556 /* load latin1 chars into cache */
557 ch = 256;
558 while (ch-- > 32)
559 font_get_bits(pf, ch);
562 return;
565 #endif /* HAVE_LCD_BITMAP */
567 /* -----------------------------------------------------------------
568 * vim: et sw=4 ts=8 sts=4 tw=78