fix a bug where the backdrop from the sbs is displayed on scrolling lines in the...
[kugel-rb.git] / firmware / font.c
bloba8734e93a1ae0df2db81c3e62466a0614749ef37
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 #define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
42 /* max static loadable font buffer size */
43 #ifndef MAX_FONT_SIZE
44 #if LCD_HEIGHT > 64
45 #if MEM > 2
46 #define MAX_FONT_SIZE 60000
47 #else
48 #define MAX_FONT_SIZE 10000
49 #endif
50 #else
51 #define MAX_FONT_SIZE 4000
52 #endif
53 #endif
55 #ifndef FONT_HEADER_SIZE
56 #define FONT_HEADER_SIZE 36
57 #endif
59 #define GLYPH_CACHE_FILE ROCKBOX_DIR"/.glyphcache"
61 #ifndef BOOTLOADER
62 /* Font cache includes */
63 #include "font_cache.h"
64 #include "lru.h"
65 #endif
67 #ifndef O_BINARY
68 #define O_BINARY 0
69 #endif
71 /* compiled-in font */
72 extern struct font sysfont;
74 #ifndef BOOTLOADER
76 /* structure filled in by font_load */
77 static struct font font_ui;
79 /* system font table, in order of FONT_xxx definition */
80 static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
82 /* static buffer allocation structures */
83 static unsigned char mbuf[MAX_FONT_SIZE];
84 static unsigned char *freeptr = mbuf;
85 static unsigned char *fileptr;
86 static unsigned char *eofptr;
88 /* Font cache structures */
89 static struct font_cache font_cache_ui;
90 static int fnt_file = -1; /* >=0 if font is cached */
91 static uint32_t file_width_offset; /* offset to file width data */
92 static uint32_t file_offset_offset; /* offset to file offset data */
93 static void cache_create(int maxwidth, int height);
94 static int long_offset = 0;
95 static int glyph_file;
96 /* End Font cache structures */
98 static void glyph_cache_load(void);
100 void font_init(void)
102 memset(&font_ui, 0, sizeof(struct font));
105 /* Check if we have x bytes left in the file buffer */
106 #define HAVEBYTES(x) (fileptr + (x) <= eofptr)
108 /* Helper functions to read big-endian unaligned short or long from
109 the file buffer. Bounds-checking must be done in the calling
110 function.
113 static short readshort(void)
115 unsigned short s;
117 s = *fileptr++ & 0xff;
118 s |= (*fileptr++ << 8);
119 return s;
122 static int32_t readlong(void)
124 uint32_t l;
126 l = *fileptr++ & 0xff;
127 l |= *fileptr++ << 8;
128 l |= ((uint32_t)(*fileptr++)) << 16;
129 l |= ((uint32_t)(*fileptr++)) << 24;
130 return l;
133 void font_reset(void)
135 memset(&font_ui, 0, sizeof(struct font));
138 static struct font* font_load_header(struct font *pf)
140 /* Check we have enough data */
141 if (!HAVEBYTES(28))
142 return NULL;
144 /* read magic and version #*/
145 if (memcmp(fileptr, VERSION, 4) != 0)
146 return NULL;
148 fileptr += 4;
150 /* font info*/
151 pf->maxwidth = readshort();
152 pf->height = readshort();
153 pf->ascent = readshort();
154 fileptr += 2; /* Skip padding */
155 pf->firstchar = readlong();
156 pf->defaultchar = readlong();
157 pf->size = readlong();
159 /* get variable font data sizes*/
160 /* # words of bitmap_t*/
161 pf->bits_size = readlong();
163 return pf;
165 /* Load memory font */
166 static struct font* font_load_in_memory(struct font* pf)
168 int32_t i, noffset, nwidth;
170 if (!HAVEBYTES(4))
171 return NULL;
173 /* # longs of offset*/
174 noffset = readlong();
176 /* # bytes of width*/
177 nwidth = readlong();
179 /* variable font data*/
180 pf->bits = (unsigned char *)fileptr;
181 fileptr += pf->bits_size*sizeof(unsigned char);
183 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
185 /* pad to 16-bit boundary */
186 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
188 else
190 /* pad to 32-bit boundary*/
191 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
194 if (noffset)
196 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
198 long_offset = 0;
199 pf->offset = (uint16_t*)fileptr;
201 /* Check we have sufficient buffer */
202 if (!HAVEBYTES(noffset * sizeof(uint16_t)))
203 return NULL;
205 for (i=0; i<noffset; ++i)
207 ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort();
210 else
212 long_offset = 1;
213 pf->offset = (uint16_t*)fileptr;
215 /* Check we have sufficient buffer */
216 if (!HAVEBYTES(noffset * sizeof(int32_t)))
217 return NULL;
219 for (i=0; i<noffset; ++i)
221 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong();
225 else
226 pf->offset = NULL;
228 if (nwidth) {
229 pf->width = (unsigned char *)fileptr;
230 fileptr += nwidth*sizeof(unsigned char);
232 else
233 pf->width = NULL;
235 if (fileptr > eofptr)
236 return NULL;
238 return pf; /* success!*/
241 /* Load cached font */
242 static struct font* font_load_cached(struct font* pf)
244 uint32_t noffset, nwidth;
245 unsigned char* oldfileptr = fileptr;
247 if (!HAVEBYTES(2 * sizeof(int32_t)))
248 return NULL;
250 /* # longs of offset*/
251 noffset = readlong();
253 /* # bytes of width*/
254 nwidth = readlong();
256 /* We are now at the bitmap data, this is fixed at 36.. */
257 pf->bits = NULL;
259 /* Calculate offset to offset data */
260 fileptr += pf->bits_size * sizeof(unsigned char);
262 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
264 long_offset = 0;
265 /* pad to 16-bit boundary */
266 fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
268 else
270 long_offset = 1;
271 /* pad to 32-bit boundary*/
272 fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
275 if (noffset)
276 file_offset_offset = (uint32_t)(fileptr - freeptr);
277 else
278 file_offset_offset = 0;
280 /* Calculate offset to widths data */
281 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
282 fileptr += noffset * sizeof(uint16_t);
283 else
284 fileptr += noffset * sizeof(uint32_t);
286 if (nwidth)
287 file_width_offset = (uint32_t)(fileptr - freeptr);
288 else
289 file_width_offset = 0;
291 fileptr = oldfileptr;
293 /* Create the cache */
294 cache_create(pf->maxwidth, pf->height);
296 return pf;
299 /* read and load font into incore font structure*/
300 struct font* font_load(const char *path)
302 int size;
303 struct font* pf = &font_ui;
305 /* save loaded glyphs */
306 glyph_cache_save();
308 /* Close font file handle */
309 if (fnt_file >= 0)
310 close(fnt_file);
312 /* open and read entire font file*/
313 fnt_file = open(path, O_RDONLY|O_BINARY);
315 if (fnt_file < 0) {
316 DEBUGF("Can't open font: %s\n", path);
317 return NULL;
320 /* Check file size */
321 size = filesize(fnt_file);
323 font_reset();
325 /* currently, font loading replaces earlier font allocation*/
326 freeptr = (unsigned char *)(((intptr_t)mbuf + 3) & ~3);
327 fileptr = freeptr;
330 if (size > MAX_FONT_SIZE)
332 read(fnt_file, fileptr, FONT_HEADER_SIZE);
333 eofptr = fileptr + FONT_HEADER_SIZE;
335 if (!font_load_header(pf))
337 DEBUGF("Failed font header load");
338 return NULL;
341 if (!font_load_cached(pf))
343 DEBUGF("Failed font cache load");
344 return NULL;
347 glyph_cache_load();
349 else
351 read(fnt_file, fileptr, MAX_FONT_SIZE);
352 eofptr = fileptr + size;
353 close(fnt_file);
354 fnt_file = -1;
356 if (!font_load_header(pf))
358 DEBUGF("Failed font header load");
359 return NULL;
362 if (!font_load_in_memory(pf))
364 DEBUGF("Failed mem load");
365 return NULL;
369 /* no need for multiple font loads currently*/
370 /*freeptr += filesize;*/
371 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
373 return pf; /* success!*/
377 * Return a pointer to an incore font structure.
378 * If the requested font isn't loaded/compiled-in,
379 * decrement the font number and try again.
381 struct font* font_get(int font)
383 struct font* pf;
385 if (font >= MAXFONTS)
386 font = 0;
388 while (1) {
389 pf = sysfonts[font];
390 if (pf && pf->height)
391 return pf;
392 if (--font < 0)
393 panicf("No font!");
398 * Reads an entry into cache entry
400 static void
401 load_cache_entry(struct font_cache_entry* p, void* callback_data)
403 struct font* pf = callback_data;
404 unsigned short char_code = p->_char_code;
405 unsigned char tmp[2];
407 if (file_width_offset)
409 int width_offset = file_width_offset + char_code;
410 lseek(fnt_file, width_offset, SEEK_SET);
411 read(fnt_file, &(p->width), 1);
413 else
415 p->width = pf->maxwidth;
418 int32_t bitmap_offset = 0;
420 if (file_offset_offset)
422 int32_t offset = file_offset_offset + char_code * (long_offset ? sizeof(int32_t) : sizeof(int16_t));
423 lseek(fnt_file, offset, SEEK_SET);
424 read (fnt_file, tmp, 2);
425 bitmap_offset = tmp[0] | (tmp[1] << 8);
426 if (long_offset) {
427 read (fnt_file, tmp, 2);
428 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
431 else
433 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
436 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
437 lseek(fnt_file, file_offset, SEEK_SET);
439 int src_bytes = p->width * ((pf->height + 7) / 8);
440 read(fnt_file, p->bitmap, src_bytes);
444 * Converts cbuf into a font cache
446 static void cache_create(int maxwidth, int height)
448 /* maximum size of rotated bitmap */
449 int bitmap_size = maxwidth * ((height + 7) / 8);
451 /* Initialise cache */
452 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
456 * Returns width of character
458 int font_get_width(struct font* pf, unsigned short char_code)
460 /* check input range*/
461 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
462 char_code = pf->defaultchar;
463 char_code -= pf->firstchar;
465 return (fnt_file >= 0 && pf != &sysfont)?
466 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
467 pf->width? pf->width[char_code]: pf->maxwidth;
470 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
472 const unsigned char* bits;
474 /* check input range*/
475 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
476 char_code = pf->defaultchar;
477 char_code -= pf->firstchar;
479 if (fnt_file >= 0 && pf != &sysfont)
481 bits =
482 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
484 else
486 bits = pf->bits;
487 if (pf->offset)
489 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
490 bits += ((uint16_t*)(pf->offset))[char_code];
491 else
492 bits += ((uint32_t*)(pf->offset))[char_code];
494 else
495 bits += ((pf->height + 7) / 8) * pf->maxwidth * char_code;
498 return bits;
501 static void glyph_file_write(void* data)
503 struct font_cache_entry* p = data;
504 struct font* pf = &font_ui;
505 unsigned short ch;
506 unsigned char tmp[2];
508 ch = p->_char_code + pf->firstchar;
510 if (ch != 0xffff && glyph_file >= 0) {
511 tmp[0] = ch >> 8;
512 tmp[1] = ch & 0xff;
513 if (write(glyph_file, tmp, 2) != 2) {
514 close(glyph_file);
515 glyph_file = -1;
518 return;
521 /* save the char codes of the loaded glyphs to a file */
522 void glyph_cache_save(void)
525 if (fnt_file >= 0) {
526 #ifdef WPSEDITOR
527 glyph_file = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
528 #else
529 glyph_file = creat(GLYPH_CACHE_FILE);
530 #endif
531 if (glyph_file < 0) return;
533 lru_traverse(&font_cache_ui._lru, glyph_file_write);
535 if (glyph_file >= 0)
536 close(glyph_file);
538 return;
541 static void glyph_cache_load(void)
543 if (fnt_file >= 0) {
545 int fd;
546 unsigned char tmp[2];
547 unsigned short ch;
548 struct font* pf = &font_ui;
550 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
552 if (fd >= 0) {
554 while (read(fd, tmp, 2) == 2) {
555 ch = (tmp[0] << 8) | tmp[1];
556 font_get_bits(pf, ch);
559 close(fd);
560 } else {
561 /* load latin1 chars into cache */
562 ch = 256;
563 while (ch-- > 32)
564 font_get_bits(pf, ch);
567 return;
569 #else /* BOOTLOADER */
571 void font_init(void)
576 * Bootloader only supports the built-in sysfont.
578 struct font* font_get(int font)
580 (void)font;
581 return &sysfont;
585 * Returns width of character
587 int font_get_width(struct font* pf, unsigned short char_code)
589 /* check input range*/
590 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
591 char_code = pf->defaultchar;
592 char_code -= pf->firstchar;
594 return pf->width? pf->width[char_code]: pf->maxwidth;
597 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
599 const unsigned char* bits;
601 /* check input range*/
602 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
603 char_code = pf->defaultchar;
604 char_code -= pf->firstchar;
606 /* assume small font with uint16_t offsets*/
607 bits = pf->bits + (pf->offset?
608 ((uint16_t*)(pf->offset))[char_code]:
609 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
611 return bits;
614 #endif /* BOOTLOADER */
617 * Returns the stringsize of a given string.
619 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
621 struct font* pf = font_get(fontnumber);
622 unsigned short ch;
623 int width = 0;
625 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
627 if (is_diacritic(ch, NULL))
628 continue;
630 /* get proportional width and glyph bits*/
631 width += font_get_width(pf,ch);
633 if ( w )
634 *w = width;
635 if ( h )
636 *h = pf->height;
637 return width;
640 /* -----------------------------------------------------------------
641 * vim: et sw=4 ts=8 sts=4 tw=78