FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / firmware / font.c
blob46502328e4410364b645ada93d6f803d1d9166ab
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 #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"
39 #ifndef BOOTLOADER
40 /* Font cache includes */
41 #include "font_cache.h"
42 #include "lru.h"
43 #endif
45 #ifndef O_BINARY
46 #define O_BINARY 0
47 #endif
49 /* compiled-in font */
50 extern struct font sysfont;
52 #ifndef BOOTLOADER
54 /* structure filled in by font_load */
55 static struct font font_ui;
57 /* system font table, in order of FONT_xxx definition */
58 static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
60 /* static buffer allocation structures */
61 static unsigned char mbuf[MAX_FONT_SIZE];
62 static unsigned char *freeptr = mbuf;
63 static unsigned char *fileptr;
64 static unsigned char *eofptr;
66 /* Font cache structures */
67 static struct font_cache font_cache_ui;
68 static int fnt_file = -1; /* >=0 if font is cached */
69 static uint32_t file_width_offset; /* offset to file width data */
70 static uint32_t file_offset_offset; /* offset to file offset data */
71 static void cache_create(int maxwidth, int height, int depth);
72 static int long_offset = 0;
73 static int glyph_file;
74 /* End Font cache structures */
76 static void glyph_cache_load(void);
78 void font_init(void)
80 memset(&font_ui, 0, sizeof(struct font));
83 /* Check if we have x bytes left in the file buffer */
84 #define HAVEBYTES(x) (fileptr + (x) <= eofptr)
86 /* Helper functions to read big-endian unaligned short or long from
87 the file buffer. Bounds-checking must be done in the calling
88 function.
91 static short readshort(void)
93 unsigned short s;
95 s = *fileptr++ & 0xff;
96 s |= (*fileptr++ << 8);
97 return s;
100 static int32_t readlong(void)
102 uint32_t l;
104 l = *fileptr++ & 0xff;
105 l |= *fileptr++ << 8;
106 l |= ((uint32_t)(*fileptr++)) << 16;
107 l |= ((uint32_t)(*fileptr++)) << 24;
108 return l;
111 /* read count bytes*/
112 static void readstr(char *buf, int count)
114 while (count--)
115 *buf++ = *fileptr++;
118 void font_reset(void)
120 memset(&font_ui, 0, sizeof(struct font));
123 static struct font* font_load_header(struct font *pf)
125 char version[4+1];
127 /* Check we have enough data */
128 if (!HAVEBYTES(28))
129 return NULL;
131 /* read magic and version #*/
132 memset(version, 0, sizeof(version));
133 readstr(version, 4);
135 if (strcmp(version, VERSION) != 0)
136 return NULL;
138 /* font info*/
139 pf->maxwidth = readshort();
140 pf->height = readshort();
141 pf->ascent = readshort();
142 pf->depth = readshort();
143 pf->firstchar = readlong();
144 pf->defaultchar = readlong();
145 pf->size = readlong();
147 /* get variable font data sizes*/
148 /* # words of bitmap_t*/
149 pf->bits_size = readlong();
151 return pf;
153 /* Load memory font */
154 static struct font* font_load_in_memory(struct font* pf)
156 int32_t i, noffset, nwidth;
158 if (!HAVEBYTES(4))
159 return NULL;
161 /* # longs of offset*/
162 noffset = readlong();
164 /* # bytes of width*/
165 nwidth = readlong();
167 /* variable font data*/
168 pf->bits = (unsigned char *)fileptr;
169 fileptr += pf->bits_size*sizeof(unsigned char);
171 if ( pf->bits_size < 0xFFDB )
173 /* pad to 16-bit boundary */
174 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
176 else
178 /* pad to 32-bit boundary*/
179 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
182 if (noffset)
184 if ( pf->bits_size < 0xFFDB )
186 long_offset = 0;
187 pf->offset = (unsigned short *)fileptr;
189 /* Check we have sufficient buffer */
190 if (!HAVEBYTES(noffset * sizeof(short)))
191 return NULL;
193 for (i=0; i<noffset; ++i)
195 ((unsigned short*)(pf->offset))[i] = (unsigned short)readshort();
198 else
200 long_offset = 1;
201 pf->offset = (unsigned short *)fileptr;
203 /* Check we have sufficient buffer */
204 if (!HAVEBYTES(noffset * sizeof(int32_t)))
205 return NULL;
207 for (i=0; i<noffset; ++i)
209 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong();
213 else
214 pf->offset = NULL;
216 if (nwidth) {
217 pf->width = (unsigned char *)fileptr;
218 fileptr += nwidth*sizeof(unsigned char);
220 else
221 pf->width = NULL;
223 if (fileptr > eofptr)
224 return NULL;
226 return pf; /* success!*/
229 /* Load cached font */
230 static struct font* font_load_cached(struct font* pf)
232 uint32_t noffset, nwidth;
233 unsigned char* oldfileptr = fileptr;
235 if (!HAVEBYTES(2 * sizeof(int32_t)))
236 return NULL;
238 /* # longs of offset*/
239 noffset = readlong();
241 /* # bytes of width*/
242 nwidth = readlong();
244 /* We are now at the bitmap data, this is fixed at 36.. */
245 pf->bits = NULL;
247 /* Calculate offset to offset data */
248 fileptr += pf->bits_size * sizeof(unsigned char);
250 if ( pf->bits_size < 0xFFDB )
252 long_offset = 0;
253 /* pad to 16-bit boundary */
254 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
256 else
258 long_offset = 1;
259 /* pad to 32-bit boundary*/
260 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
263 if (noffset)
264 file_offset_offset = (uint32_t)(fileptr - freeptr);
265 else
266 file_offset_offset = 0;
268 /* Calculate offset to widths data */
269 if ( pf->bits_size < 0xFFDB )
270 fileptr += noffset * sizeof(unsigned short);
271 else
272 fileptr += noffset * sizeof(uint32_t);
274 if (nwidth)
275 file_width_offset = (uint32_t)(fileptr - freeptr);
276 else
277 file_width_offset = 0;
279 fileptr = oldfileptr;
281 /* Create the cache */
282 cache_create(pf->maxwidth, pf->height, pf->depth);
284 return pf;
287 /* read and load font into incore font structure*/
288 struct font* font_load(const char *path)
290 int size;
291 struct font* pf = &font_ui;
293 /* save loaded glyphs */
294 glyph_cache_save();
296 /* Close font file handle */
297 if (fnt_file >= 0)
298 close(fnt_file);
300 /* open and read entire font file*/
301 fnt_file = open(path, O_RDONLY|O_BINARY);
303 if (fnt_file < 0) {
304 DEBUGF("Can't open font: %s\n", path);
305 return NULL;
308 /* Check file size */
309 size = filesize(fnt_file);
311 font_reset();
313 /* currently, font loading replaces earlier font allocation*/
314 freeptr = (unsigned char *)(((intptr_t)mbuf + 3) & ~3);
315 fileptr = freeptr;
318 if (size > MAX_FONT_SIZE)
320 read(fnt_file, fileptr, FONT_HEADER_SIZE);
321 eofptr = fileptr + FONT_HEADER_SIZE;
323 if (!font_load_header(pf))
325 DEBUGF("Failed font header load");
326 return NULL;
329 if (!font_load_cached(pf))
331 DEBUGF("Failed font cache load");
332 return NULL;
335 glyph_cache_load();
337 else
339 read(fnt_file, fileptr, MAX_FONT_SIZE);
340 eofptr = fileptr + size;
341 close(fnt_file);
342 fnt_file = -1;
344 if (!font_load_header(pf))
346 DEBUGF("Failed font header load");
347 return NULL;
350 if (!font_load_in_memory(pf))
352 DEBUGF("Failed mem load");
353 return NULL;
357 /* no need for multiple font loads currently*/
358 /*freeptr += filesize;*/
359 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
361 return pf; /* success!*/
365 * Return a pointer to an incore font structure.
366 * If the requested font isn't loaded/compiled-in,
367 * decrement the font number and try again.
369 struct font* font_get(int font)
371 struct font* pf;
373 if (font >= MAXFONTS)
374 font = 0;
376 while (1) {
377 pf = sysfonts[font];
378 if (pf && pf->height)
379 return pf;
380 if (--font < 0)
381 panicf("No font!");
386 * Reads an entry into cache entry
388 static void
389 load_cache_entry(struct font_cache_entry* p, void* callback_data)
391 struct font* pf = callback_data;
392 unsigned short char_code = p->_char_code;
393 unsigned char tmp[2];
395 if (file_width_offset)
397 int width_offset = file_width_offset + char_code;
398 lseek(fnt_file, width_offset, SEEK_SET);
399 read(fnt_file, &(p->width), 1);
401 else
403 p->width = pf->maxwidth;
406 int32_t bitmap_offset = 0;
408 if (file_offset_offset)
410 int32_t offset = file_offset_offset + char_code * (long_offset ? sizeof(int32_t) : sizeof(short));
411 lseek(fnt_file, offset, SEEK_SET);
412 read (fnt_file, tmp, 2);
413 bitmap_offset = tmp[0] | (tmp[1] << 8);
414 if (long_offset) {
415 read (fnt_file, tmp, 2);
416 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
419 else
421 bitmap_offset = pf->depth
422 ? (pf->height * p->width + 1) / 2 * char_code
423 : ((pf->height + 7) / 8) * p->width * char_code;
426 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
427 lseek(fnt_file, file_offset, SEEK_SET);
429 int src_bytes = pf->depth
430 ? (pf->height * p->width + 1) / 2
431 : p->width * ((pf->height + 7) / 8);
432 read(fnt_file, p->bitmap, src_bytes);
436 * Converts cbuf into a font cache
438 static void cache_create(int maxwidth, int height, int depth)
440 /* maximum size of rotated bitmap */
441 int bitmap_size = depth
442 ? (maxwidth * height + 1) / 2
443 : maxwidth * ((height + 7) / 8);
445 /* Initialise cache */
446 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
450 * Returns width of character
452 int font_get_width(struct font* pf, unsigned short char_code)
454 /* check input range*/
455 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
456 char_code = pf->defaultchar;
457 char_code -= pf->firstchar;
459 return (fnt_file >= 0 && pf != &sysfont)?
460 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
461 pf->width? pf->width[char_code]: pf->maxwidth;
464 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
466 const unsigned char* bits;
468 /* check input range*/
469 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
470 char_code = pf->defaultchar;
471 char_code -= pf->firstchar;
473 if (fnt_file >= 0 && pf != &sysfont)
475 bits =
476 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
478 else
480 bits = pf->bits + (pf->offset?
481 pf->offset[char_code]:
482 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
485 return bits;
488 static void glyph_file_write(void* data)
490 struct font_cache_entry* p = data;
491 struct font* pf = &font_ui;
492 unsigned short ch;
493 unsigned char tmp[2];
495 ch = p->_char_code + pf->firstchar;
497 if (ch != 0xffff && glyph_file >= 0) {
498 tmp[0] = ch >> 8;
499 tmp[1] = ch & 0xff;
500 if (write(glyph_file, tmp, 2) != 2) {
501 close(glyph_file);
502 glyph_file = -1;
505 return;
508 /* save the char codes of the loaded glyphs to a file */
509 void glyph_cache_save(void)
512 if (fnt_file >= 0) {
513 #ifdef WPSEDITOR
514 glyph_file = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
515 #else
516 glyph_file = creat(GLYPH_CACHE_FILE);
517 #endif
518 if (glyph_file < 0) return;
520 lru_traverse(&font_cache_ui._lru, glyph_file_write);
522 if (glyph_file >= 0)
523 close(glyph_file);
525 return;
528 static void glyph_cache_load(void)
530 if (fnt_file >= 0) {
532 int fd;
533 unsigned char tmp[2];
534 unsigned short ch;
535 struct font* pf = &font_ui;
537 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
539 if (fd >= 0) {
541 while (read(fd, tmp, 2) == 2) {
542 ch = (tmp[0] << 8) | tmp[1];
543 font_get_bits(pf, ch);
546 close(fd);
547 } else {
548 /* load latin1 chars into cache */
549 ch = 256;
550 while (ch-- > 32)
551 font_get_bits(pf, ch);
554 return;
556 #else /* BOOTLOADER */
558 void font_init(void)
563 * Bootloader only supports the built-in sysfont.
565 struct font* font_get(int font)
567 (void)font;
568 return &sysfont;
572 * Returns width of character
574 int font_get_width(struct font* pf, unsigned short char_code)
576 /* check input range*/
577 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
578 char_code = pf->defaultchar;
579 char_code -= pf->firstchar;
581 return pf->width? pf->width[char_code]: pf->maxwidth;
584 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
586 const unsigned char* bits;
588 /* check input range*/
589 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
590 char_code = pf->defaultchar;
591 char_code -= pf->firstchar;
593 bits = pf->bits + (pf->offset?
594 pf->offset[char_code]:
595 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
597 return bits;
600 #endif /* BOOTLOADER */
603 * Returns the stringsize of a given string.
605 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
607 struct font* pf = font_get(fontnumber);
608 unsigned short ch;
609 int width = 0;
611 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
614 /* get proportional width and glyph bits*/
615 width += font_get_width(pf,ch);
617 if ( w )
618 *w = width;
619 if ( h )
620 *h = pf->height;
621 return width;
624 /* -----------------------------------------------------------------
625 * vim: et sw=4 ts=8 sts=4 tw=78