Fix yellow: add braces
[kugel-rb.git] / firmware / font.c
blob624e0de9a7bc27fe6d00229435cf25e13c805637
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"
38 #include "diacritic.h"
40 #ifndef BOOTLOADER
41 /* Font cache includes */
42 #include "font_cache.h"
43 #include "lru.h"
44 #endif
46 #ifndef O_BINARY
47 #define O_BINARY 0
48 #endif
50 /* compiled-in font */
51 extern struct font sysfont;
53 #ifndef BOOTLOADER
55 /* structure filled in by font_load */
56 static struct font font_ui;
58 /* system font table, in order of FONT_xxx definition */
59 static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
61 /* static buffer allocation structures */
62 static unsigned char mbuf[MAX_FONT_SIZE];
63 static unsigned char *freeptr = mbuf;
64 static unsigned char *fileptr;
65 static unsigned char *eofptr;
67 /* Font cache structures */
68 static struct font_cache font_cache_ui;
69 static int fnt_file = -1; /* >=0 if font is cached */
70 static uint32_t file_width_offset; /* offset to file width data */
71 static uint32_t file_offset_offset; /* offset to file offset data */
72 static void cache_create(int maxwidth, int height);
73 static int long_offset = 0;
74 static int glyph_file;
75 /* End Font cache structures */
77 static void glyph_cache_load(void);
79 void font_init(void)
81 memset(&font_ui, 0, sizeof(struct font));
84 /* Check if we have x bytes left in the file buffer */
85 #define HAVEBYTES(x) (fileptr + (x) <= eofptr)
87 /* Helper functions to read big-endian unaligned short or long from
88 the file buffer. Bounds-checking must be done in the calling
89 function.
92 static short readshort(void)
94 unsigned short s;
96 s = *fileptr++ & 0xff;
97 s |= (*fileptr++ << 8);
98 return s;
101 static int32_t readlong(void)
103 uint32_t l;
105 l = *fileptr++ & 0xff;
106 l |= *fileptr++ << 8;
107 l |= ((uint32_t)(*fileptr++)) << 16;
108 l |= ((uint32_t)(*fileptr++)) << 24;
109 return l;
112 /* read count bytes*/
113 static void readstr(char *buf, int count)
115 while (count--)
116 *buf++ = *fileptr++;
119 void font_reset(void)
121 memset(&font_ui, 0, sizeof(struct font));
124 static struct font* font_load_header(struct font *pf)
126 char version[4+1];
128 /* Check we have enough data */
129 if (!HAVEBYTES(28))
130 return NULL;
132 /* read magic and version #*/
133 memset(version, 0, sizeof(version));
134 readstr(version, 4);
136 if (strcmp(version, VERSION) != 0)
137 return NULL;
139 /* font info*/
140 pf->maxwidth = readshort();
141 pf->height = readshort();
142 pf->ascent = readshort();
143 fileptr += 2; /* Skip padding */
144 pf->firstchar = readlong();
145 pf->defaultchar = readlong();
146 pf->size = readlong();
148 /* get variable font data sizes*/
149 /* # words of bitmap_t*/
150 pf->bits_size = readlong();
152 return pf;
154 /* Load memory font */
155 static struct font* font_load_in_memory(struct font* pf)
157 int32_t i, noffset, nwidth;
159 if (!HAVEBYTES(4))
160 return NULL;
162 /* # longs of offset*/
163 noffset = readlong();
165 /* # bytes of width*/
166 nwidth = readlong();
168 /* variable font data*/
169 pf->bits = (unsigned char *)fileptr;
170 fileptr += pf->bits_size*sizeof(unsigned char);
172 if ( pf->bits_size < 0xFFDB )
174 /* pad to 16-bit boundary */
175 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
177 else
179 /* pad to 32-bit boundary*/
180 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
183 if (noffset)
185 if ( pf->bits_size < 0xFFDB )
187 long_offset = 0;
188 pf->offset = (unsigned short *)fileptr;
190 /* Check we have sufficient buffer */
191 if (!HAVEBYTES(noffset * sizeof(short)))
192 return NULL;
194 for (i=0; i<noffset; ++i)
196 ((unsigned short*)(pf->offset))[i] = (unsigned short)readshort();
199 else
201 long_offset = 1;
202 pf->offset = (unsigned short *)fileptr;
204 /* Check we have sufficient buffer */
205 if (!HAVEBYTES(noffset * sizeof(int32_t)))
206 return NULL;
208 for (i=0; i<noffset; ++i)
210 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong();
214 else
215 pf->offset = NULL;
217 if (nwidth) {
218 pf->width = (unsigned char *)fileptr;
219 fileptr += nwidth*sizeof(unsigned char);
221 else
222 pf->width = NULL;
224 if (fileptr > eofptr)
225 return NULL;
227 return pf; /* success!*/
230 /* Load cached font */
231 static struct font* font_load_cached(struct font* pf)
233 uint32_t noffset, nwidth;
234 unsigned char* oldfileptr = fileptr;
236 if (!HAVEBYTES(2 * sizeof(int32_t)))
237 return NULL;
239 /* # longs of offset*/
240 noffset = readlong();
242 /* # bytes of width*/
243 nwidth = readlong();
245 /* We are now at the bitmap data, this is fixed at 36.. */
246 pf->bits = NULL;
248 /* Calculate offset to offset data */
249 fileptr += pf->bits_size * sizeof(unsigned char);
251 if ( pf->bits_size < 0xFFDB )
253 long_offset = 0;
254 /* pad to 16-bit boundary */
255 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
257 else
259 long_offset = 1;
260 /* pad to 32-bit boundary*/
261 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
264 if (noffset)
265 file_offset_offset = (uint32_t)(fileptr - freeptr);
266 else
267 file_offset_offset = 0;
269 /* Calculate offset to widths data */
270 if ( pf->bits_size < 0xFFDB )
271 fileptr += noffset * sizeof(unsigned short);
272 else
273 fileptr += noffset * sizeof(uint32_t);
275 if (nwidth)
276 file_width_offset = (uint32_t)(fileptr - freeptr);
277 else
278 file_width_offset = 0;
280 fileptr = oldfileptr;
282 /* Create the cache */
283 cache_create(pf->maxwidth, pf->height);
285 return pf;
288 /* read and load font into incore font structure*/
289 struct font* font_load(const char *path)
291 int size;
292 struct font* pf = &font_ui;
294 /* save loaded glyphs */
295 glyph_cache_save();
297 /* Close font file handle */
298 if (fnt_file >= 0)
299 close(fnt_file);
301 /* open and read entire font file*/
302 fnt_file = open(path, O_RDONLY|O_BINARY);
304 if (fnt_file < 0) {
305 DEBUGF("Can't open font: %s\n", path);
306 return NULL;
309 /* Check file size */
310 size = filesize(fnt_file);
312 font_reset();
314 /* currently, font loading replaces earlier font allocation*/
315 freeptr = (unsigned char *)(((intptr_t)mbuf + 3) & ~3);
316 fileptr = freeptr;
319 if (size > MAX_FONT_SIZE)
321 read(fnt_file, fileptr, FONT_HEADER_SIZE);
322 eofptr = fileptr + FONT_HEADER_SIZE;
324 if (!font_load_header(pf))
326 DEBUGF("Failed font header load");
327 return NULL;
330 if (!font_load_cached(pf))
332 DEBUGF("Failed font cache load");
333 return NULL;
336 glyph_cache_load();
338 else
340 read(fnt_file, fileptr, MAX_FONT_SIZE);
341 eofptr = fileptr + size;
342 close(fnt_file);
343 fnt_file = -1;
345 if (!font_load_header(pf))
347 DEBUGF("Failed font header load");
348 return NULL;
351 if (!font_load_in_memory(pf))
353 DEBUGF("Failed mem load");
354 return NULL;
358 /* no need for multiple font loads currently*/
359 /*freeptr += filesize;*/
360 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
362 return pf; /* success!*/
366 * Return a pointer to an incore font structure.
367 * If the requested font isn't loaded/compiled-in,
368 * decrement the font number and try again.
370 struct font* font_get(int font)
372 struct font* pf;
374 if (font >= MAXFONTS)
375 font = 0;
377 while (1) {
378 pf = sysfonts[font];
379 if (pf && pf->height)
380 return pf;
381 if (--font < 0)
382 panicf("No font!");
387 * Reads an entry into cache entry
389 static void
390 load_cache_entry(struct font_cache_entry* p, void* callback_data)
392 struct font* pf = callback_data;
393 unsigned short char_code = p->_char_code;
394 unsigned char tmp[2];
396 if (file_width_offset)
398 int width_offset = file_width_offset + char_code;
399 lseek(fnt_file, width_offset, SEEK_SET);
400 read(fnt_file, &(p->width), 1);
402 else
404 p->width = pf->maxwidth;
407 int32_t bitmap_offset = 0;
409 if (file_offset_offset)
411 int32_t offset = file_offset_offset + char_code * (long_offset ? sizeof(int32_t) : sizeof(short));
412 lseek(fnt_file, offset, SEEK_SET);
413 read (fnt_file, tmp, 2);
414 bitmap_offset = tmp[0] | (tmp[1] << 8);
415 if (long_offset) {
416 read (fnt_file, tmp, 2);
417 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
420 else
422 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
425 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
426 lseek(fnt_file, file_offset, SEEK_SET);
428 int src_bytes = p->width * ((pf->height + 7) / 8);
429 read(fnt_file, p->bitmap, src_bytes);
433 * Converts cbuf into a font cache
435 static void cache_create(int maxwidth, int height)
437 /* maximum size of rotated bitmap */
438 int bitmap_size = maxwidth * ((height + 7) / 8);
440 /* Initialise cache */
441 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
445 * Returns width of character
447 int font_get_width(struct font* pf, unsigned short char_code)
449 /* check input range*/
450 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
451 char_code = pf->defaultchar;
452 char_code -= pf->firstchar;
454 return (fnt_file >= 0 && pf != &sysfont)?
455 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
456 pf->width? pf->width[char_code]: pf->maxwidth;
459 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
461 const unsigned char* bits;
463 /* check input range*/
464 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
465 char_code = pf->defaultchar;
466 char_code -= pf->firstchar;
468 if (fnt_file >= 0 && pf != &sysfont)
470 bits =
471 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
473 else
475 bits = pf->bits + (pf->offset?
476 pf->offset[char_code]:
477 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
480 return bits;
483 static void glyph_file_write(void* data)
485 struct font_cache_entry* p = data;
486 struct font* pf = &font_ui;
487 unsigned short ch;
488 unsigned char tmp[2];
490 ch = p->_char_code + pf->firstchar;
492 if (ch != 0xffff && glyph_file >= 0) {
493 tmp[0] = ch >> 8;
494 tmp[1] = ch & 0xff;
495 if (write(glyph_file, tmp, 2) != 2) {
496 close(glyph_file);
497 glyph_file = -1;
500 return;
503 /* save the char codes of the loaded glyphs to a file */
504 void glyph_cache_save(void)
507 if (fnt_file >= 0) {
508 #ifdef WPSEDITOR
509 glyph_file = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
510 #else
511 glyph_file = creat(GLYPH_CACHE_FILE);
512 #endif
513 if (glyph_file < 0) return;
515 lru_traverse(&font_cache_ui._lru, glyph_file_write);
517 if (glyph_file >= 0)
518 close(glyph_file);
520 return;
523 static void glyph_cache_load(void)
525 if (fnt_file >= 0) {
527 int fd;
528 unsigned char tmp[2];
529 unsigned short ch;
530 struct font* pf = &font_ui;
532 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
534 if (fd >= 0) {
536 while (read(fd, tmp, 2) == 2) {
537 ch = (tmp[0] << 8) | tmp[1];
538 font_get_bits(pf, ch);
541 close(fd);
542 } else {
543 /* load latin1 chars into cache */
544 ch = 256;
545 while (ch-- > 32)
546 font_get_bits(pf, ch);
549 return;
551 #else /* BOOTLOADER */
553 void font_init(void)
558 * Bootloader only supports the built-in sysfont.
560 struct font* font_get(int font)
562 (void)font;
563 return &sysfont;
567 * Returns width of character
569 int font_get_width(struct font* pf, unsigned short char_code)
571 /* check input range*/
572 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
573 char_code = pf->defaultchar;
574 char_code -= pf->firstchar;
576 return pf->width? pf->width[char_code]: pf->maxwidth;
579 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
581 const unsigned char* bits;
583 /* check input range*/
584 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
585 char_code = pf->defaultchar;
586 char_code -= pf->firstchar;
588 bits = pf->bits + (pf->offset?
589 pf->offset[char_code]:
590 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
592 return bits;
595 #endif /* BOOTLOADER */
598 * Returns the stringsize of a given string.
600 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
602 struct font* pf = font_get(fontnumber);
603 unsigned short ch;
604 int width = 0;
606 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
608 if (is_diacritic(ch, NULL))
609 continue;
611 /* get proportional width and glyph bits*/
612 width += font_get_width(pf,ch);
614 if ( w )
615 *w = width;
616 if ( h )
617 *h = pf->height;
618 return width;
621 /* -----------------------------------------------------------------
622 * vim: et sw=4 ts=8 sts=4 tw=78