Make the updated %rg tag match playback behaviour (fall back to track gain if album...
[kugel-rb.git] / firmware / font.c
blob40f99b330d8141776ea8eb269d1bea0f67642d50
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 "lcd.h"
32 #include "font.h"
33 #include "file.h"
34 #include "debug.h"
35 #include "panic.h"
36 #include "rbunicode.h"
37 /* Font cache includes */
38 #include "font_cache.h"
39 #include "lru.h"
41 #ifndef O_BINARY
42 #define O_BINARY 0
43 #endif
45 /* compiled-in font */
46 extern struct font sysfont;
48 /* structure filled in by font_load */
49 static struct font font_ui;
51 /* system font table, in order of FONT_xxx definition */
52 static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
54 /* static buffer allocation structures */
55 static unsigned char mbuf[MAX_FONT_SIZE];
56 static unsigned char *freeptr = mbuf;
57 static unsigned char *fileptr;
58 static unsigned char *eofptr;
60 /* Font cache structures */
61 static struct font_cache font_cache_ui;
62 static int fnt_file = -1; /* >=0 if font is cached */
63 unsigned long file_width_offset; /* offset to file width data */
64 unsigned long file_offset_offset; /* offset to file offset data */
65 static void cache_create(int maxwidth, int height);
66 static int long_offset = 0;
67 static int glyph_file;
68 /* End Font cache structures */
70 void font_init(void)
72 memset(&font_ui, 0, sizeof(struct font));
75 static int readshort(unsigned short *sp)
77 unsigned short s;
79 s = *fileptr++ & 0xff;
80 *sp = (*fileptr++ << 8) | s;
81 return (fileptr <= eofptr);
84 static long readlong(unsigned long *lp)
86 unsigned long l;
88 l = *fileptr++ & 0xff;
89 l |= *fileptr++ << 8;
90 l |= ((unsigned long)(*fileptr++)) << 16;
91 l |= ((unsigned long)(*fileptr++)) << 24;
92 *lp = l;
93 return (fileptr <= eofptr);
96 /* read count bytes*/
97 static int readstr(char *buf, int count)
99 int n = count;
101 while (--n >= 0)
102 *buf++ = *fileptr++;
103 return (fileptr <= eofptr)? count: 0;
106 void font_reset(void)
108 memset(&font_ui, 0, sizeof(struct font));
111 static struct font* font_load_header(struct font *pf)
113 char version[4+1];
114 unsigned short maxwidth, height, ascent, pad;
115 unsigned long firstchar, defaultchar, size;
116 unsigned long nbits;
118 /* read magic and version #*/
119 memset(version, 0, sizeof(version));
120 if (readstr(version, 4) != 4)
121 return NULL;
122 if (strcmp(version, VERSION) != 0)
123 return NULL;
125 /* font info*/
126 if (!readshort(&maxwidth))
127 return NULL;
128 pf->maxwidth = maxwidth;
129 if (!readshort(&height))
130 return NULL;
131 pf->height = height;
132 if (!readshort(&ascent))
133 return NULL;
134 pf->ascent = ascent;
135 if (!readshort(&pad))
136 return NULL;
137 if (!readlong(&firstchar))
138 return NULL;
139 pf->firstchar = firstchar;
140 if (!readlong(&defaultchar))
141 return NULL;
142 pf->defaultchar = defaultchar;
143 if (!readlong(&size))
144 return NULL;
145 pf->size = size;
147 /* get variable font data sizes*/
148 /* # words of bitmap_t*/
149 if (!readlong(&nbits))
150 return NULL;
151 pf->bits_size = nbits;
153 return pf;
155 /* Load memory font */
156 struct font* font_load_in_memory(struct font* pf)
158 long i, noffset, nwidth;
160 /* # longs of offset*/
161 if (!readlong(&noffset))
162 return NULL;
164 /* # bytes of width*/
165 if (!readlong(&nwidth))
166 return NULL;
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 *)(((long)fileptr + 1) & ~1);
177 else
179 /* pad to 32-bit boundary*/
180 fileptr = (unsigned char *)(((long)fileptr + 3) & ~3);
183 if (noffset)
185 if ( pf->bits_size < 0xFFDB )
187 long_offset = 0;
188 pf->offset = (unsigned short *)fileptr;
189 for (i=0; i<noffset; ++i)
191 unsigned short offset;
192 if (!readshort(&offset))
193 return NULL;
194 ((unsigned short*)(pf->offset))[i] = (unsigned short)offset;
197 else
199 long_offset = 1;
200 pf->offset = (unsigned short *)fileptr;
201 for (i=0; i<noffset; ++i)
203 unsigned long offset;
204 if (!readlong(&offset))
205 return NULL;
206 ((unsigned long*)(pf->offset))[i] = (unsigned long)offset;
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 struct font* font_load_cached(struct font* pf)
229 unsigned long noffset, nwidth;
230 unsigned char* oldfileptr = fileptr;
232 /* # longs of offset*/
233 if (!readlong(&noffset))
234 return NULL;
236 /* # bytes of width*/
237 if (!readlong(&nwidth))
238 return NULL;
240 /* We are now at the bitmap data, this is fixed at 36.. */
241 pf->bits = NULL;
243 /* Calculate offset to offset data */
244 fileptr += pf->bits_size * sizeof(unsigned char);
246 if ( pf->bits_size < 0xFFDB )
248 long_offset = 0;
249 /* pad to 16-bit boundary */
250 fileptr = (unsigned char *)(((long)fileptr + 1) & ~1);
252 else
254 long_offset = 1;
255 /* pad to 32-bit boundary*/
256 fileptr = (unsigned char *)(((long)fileptr + 3) & ~3);
259 if (noffset)
260 file_offset_offset = (unsigned long)(fileptr - freeptr);
261 else
262 file_offset_offset = 0;
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);
270 if (nwidth)
271 file_width_offset = (unsigned long)(fileptr - freeptr);
272 else
273 file_width_offset = 0;
275 fileptr = oldfileptr;
277 /* Create the cache */
278 cache_create(pf->maxwidth, pf->height);
280 return pf;
283 /* read and load font into incore font structure*/
284 struct font* font_load(const char *path)
286 int size;
287 struct font* pf = &font_ui;
289 /* save loaded glyphs */
290 glyph_cache_save();
292 /* Close font file handle */
293 if (fnt_file >= 0)
294 close(fnt_file);
296 /* open and read entire font file*/
297 fnt_file = open(path, O_RDONLY|O_BINARY);
299 if (fnt_file < 0) {
300 DEBUGF("Can't open font: %s\n", path);
301 return NULL;
304 /* Check file size */
305 size = filesize(fnt_file);
307 font_reset();
309 /* currently, font loading replaces earlier font allocation*/
310 freeptr = (unsigned char *)(((int)mbuf + 3) & ~3);
311 fileptr = freeptr;
314 if (size > MAX_FONT_SIZE)
316 read(fnt_file, fileptr, FONT_HEADER_SIZE);
317 eofptr = fileptr + FONT_HEADER_SIZE;
319 if (!font_load_header(pf))
321 DEBUGF("Failed font header load");
322 return NULL;
325 if (!font_load_cached(pf))
327 DEBUGF("Failed font cache load");
328 return NULL;
331 glyph_cache_load();
333 else
335 read(fnt_file, fileptr, MAX_FONT_SIZE);
336 eofptr = fileptr + size;
337 close(fnt_file);
338 fnt_file = -1;
340 if (!font_load_header(pf))
342 DEBUGF("Failed font header load");
343 return NULL;
346 if (!font_load_in_memory(pf))
348 DEBUGF("Failed mem load");
349 return NULL;
353 /* no need for multiple font loads currently*/
354 /*freeptr += filesize;*/
355 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
357 return pf; /* success!*/
361 * Return a pointer to an incore font structure.
362 * If the requested font isn't loaded/compiled-in,
363 * decrement the font number and try again.
365 struct font* font_get(int font)
367 struct font* pf;
369 if (font >= MAXFONTS)
370 font = 0;
372 while (1) {
373 pf = sysfonts[font];
374 if (pf && pf->height)
375 return pf;
376 if (--font < 0)
377 panicf("No font!");
381 * Returns the stringsize of a given string.
383 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
385 struct font* pf = font_get(fontnumber);
386 unsigned short ch;
387 int width = 0;
389 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
392 /* get proportional width and glyph bits*/
393 width += font_get_width(pf,ch);
395 if ( w )
396 *w = width;
397 if ( h )
398 *h = pf->height;
399 return width;
403 * Reads an entry into cache entry
405 static void
406 load_cache_entry(struct font_cache_entry* p, void* callback_data)
408 struct font* pf = callback_data;
409 unsigned short char_code = p->_char_code;
410 unsigned char tmp[2];
412 if (file_width_offset)
414 int width_offset = file_width_offset + char_code;
415 lseek(fnt_file, width_offset, SEEK_SET);
416 read(fnt_file, &(p->width), 1);
418 else
420 p->width = pf->maxwidth;
423 long bitmap_offset = 0;
425 if (file_offset_offset)
427 long offset = file_offset_offset + char_code * (long_offset ? sizeof(long) : sizeof(short));
428 lseek(fnt_file, offset, SEEK_SET);
429 read (fnt_file, tmp, 2);
430 bitmap_offset = tmp[0] | (tmp[1] << 8);
431 if (long_offset) {
432 read (fnt_file, tmp, 2);
433 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
436 else
438 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
441 long file_offset = FONT_HEADER_SIZE + bitmap_offset;
442 lseek(fnt_file, file_offset, SEEK_SET);
444 int src_bytes = p->width * ((pf->height + 7) / 8);
445 read(fnt_file, p->bitmap, src_bytes);
449 * Converts cbuf into a font cache
451 static void cache_create(int maxwidth, int height)
453 /* maximum size of rotated bitmap */
454 int bitmap_size = maxwidth * ((height + 7) / 8);
456 /* Initialise cache */
457 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
461 * Returns width of character
463 int font_get_width(struct font* pf, unsigned short char_code)
465 /* check input range*/
466 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
467 char_code = pf->defaultchar;
468 char_code -= pf->firstchar;
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;
475 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
477 const unsigned char* bits;
479 /* check input range*/
480 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
481 char_code = pf->defaultchar;
482 char_code -= pf->firstchar;
484 if (fnt_file >= 0 && pf != &sysfont)
486 bits =
487 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
489 else
491 bits = pf->bits + (pf->offset?
492 pf->offset[char_code]:
493 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
496 return bits;
499 void glyph_file_write(void* data)
501 struct font_cache_entry* p = data;
502 struct font* pf = &font_ui;
503 unsigned short ch;
504 unsigned char tmp[2];
506 ch = p->_char_code + pf->firstchar;
508 if (ch != 0xffff && glyph_file >= 0) {
509 tmp[0] = ch >> 8;
510 tmp[1] = ch & 0xff;
511 if (write(glyph_file, tmp, 2) != 2) {
512 close(glyph_file);
513 glyph_file = -1;
516 return;
519 /* save the char codes of the loaded glyphs to a file */
520 void glyph_cache_save(void)
523 if (fnt_file >= 0) {
525 glyph_file = creat(GLYPH_CACHE_FILE, O_WRONLY);
527 if (glyph_file < 0) return;
529 lru_traverse(&font_cache_ui._lru, glyph_file_write);
531 if (glyph_file >= 0)
532 close(glyph_file);
534 return;
537 void glyph_cache_load(void)
539 if (fnt_file >= 0) {
541 int fd;
542 unsigned char tmp[2];
543 unsigned short ch;
544 struct font* pf = &font_ui;
546 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
548 if (fd >= 0) {
550 while (read(fd, tmp, 2) == 2) {
551 ch = (tmp[0] << 8) | tmp[1];
552 font_get_bits(pf, ch);
555 close(fd);
556 } else {
557 /* load latin1 chars into cache */
558 ch = 256;
559 while (ch-- > 32)
560 font_get_bits(pf, ch);
563 return;
566 #endif /* HAVE_LCD_BITMAP */
568 /* -----------------------------------------------------------------
569 * vim: et sw=4 ts=8 sts=4 tw=78