Fix an implicit declaration warning.
[kugel-rb.git] / firmware / font.c
blob0f9f453ae23c8cd01731696bd08bdd40259eb62e
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 <stdlib.h>
32 #include "inttypes.h"
33 #include "lcd.h"
34 #include "system.h"
35 #include "font.h"
36 #include "file.h"
37 #include "debug.h"
38 #include "panic.h"
39 #include "rbunicode.h"
40 #include "diacritic.h"
41 #include "rbpaths.h"
43 #define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
45 /* max static loadable font buffer size */
46 #ifndef MAX_FONT_SIZE
47 #if LCD_HEIGHT > 64
48 #if MEMORYSIZE > 2
49 #define MAX_FONT_SIZE 60000
50 #else
51 #define MAX_FONT_SIZE 10000
52 #endif
53 #else
54 #define MAX_FONT_SIZE 4000
55 #endif
56 #endif
58 #ifndef FONT_HEADER_SIZE
59 #define FONT_HEADER_SIZE 36
60 #endif
62 #ifndef BOOTLOADER
63 /* Font cache includes */
64 #include "font_cache.h"
65 #include "lru.h"
66 #endif
68 #ifndef O_BINARY
69 #define O_BINARY 0
70 #endif
72 /* compiled-in font */
73 extern struct font sysfont;
75 #ifndef BOOTLOADER
77 /* structure filled in by font_load */
78 static struct font font_ui;
79 /* static buffer allocation structures */
80 static unsigned char main_buf[MAX_FONT_SIZE] CACHEALIGN_ATTR;
81 #ifdef HAVE_REMOTE_LCD
82 #define REMOTE_FONT_SIZE 10000
83 static struct font remote_font_ui;
84 static unsigned char remote_buf[REMOTE_FONT_SIZE] CACHEALIGN_ATTR;
85 #endif
87 /* system font table, in order of FONT_xxx definition */
88 static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL};
91 /* Font cache structures */
92 static void cache_create(struct font* pf);
93 static void glyph_cache_load(struct font* pf);
94 /* End Font cache structures */
96 void font_init(void)
98 int i = SYSTEMFONTCOUNT;
99 while (i<MAXFONTS)
100 sysfonts[i++] = NULL;
101 font_reset(NULL);
102 #ifdef HAVE_REMOTE_LCD
103 font_reset(&remote_font_ui);
104 #endif
107 /* Check if we have x bytes left in the file buffer */
108 #define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
110 /* Helper functions to read big-endian unaligned short or long from
111 the file buffer. Bounds-checking must be done in the calling
112 function.
115 static short readshort(struct font *pf)
117 unsigned short s;
119 s = *pf->buffer_position++ & 0xff;
120 s |= (*pf->buffer_position++ << 8);
121 return s;
124 static int32_t readlong(struct font *pf)
126 uint32_t l;
128 l = *pf->buffer_position++ & 0xff;
129 l |= *pf->buffer_position++ << 8;
130 l |= ((uint32_t)(*pf->buffer_position++)) << 16;
131 l |= ((uint32_t)(*pf->buffer_position++)) << 24;
132 return l;
135 static int glyph_bytes( struct font *pf, int width )
137 return pf->depth ?
138 (pf->height * width + 1) / 2:
139 width * ((pf->height + 7) / 8);
142 void font_reset(struct font *pf)
144 unsigned char* buffer = NULL;
145 size_t buf_size = 0;
146 if (pf == NULL)
147 pf = &font_ui;
148 else
150 buffer = pf->buffer_start;
151 buf_size = pf->buffer_size;
153 memset(pf, 0, sizeof(struct font));
154 pf->fd = -1;
155 if (buffer)
157 pf->buffer_start = buffer;
158 pf->buffer_size = buf_size;
162 static struct font* font_load_header(struct font *pf)
164 /* Check we have enough data */
165 if (!HAVEBYTES(28))
166 return NULL;
168 /* read magic and version #*/
169 if (memcmp(pf->buffer_position, VERSION, 4) != 0)
170 return NULL;
172 pf->buffer_position += 4;
174 /* font info*/
175 pf->maxwidth = readshort(pf);
176 pf->height = readshort(pf);
177 pf->ascent = readshort(pf);
178 pf->depth = readshort(pf);
179 pf->firstchar = readlong(pf);
180 pf->defaultchar = readlong(pf);
181 pf->size = readlong(pf);
183 /* get variable font data sizes*/
184 /* # words of bitmap_t*/
185 pf->bits_size = readlong(pf);
187 return pf;
189 /* Load memory font */
190 static struct font* font_load_in_memory(struct font* pf)
192 int32_t i, noffset, nwidth;
194 if (!HAVEBYTES(4))
195 return NULL;
197 /* # longs of offset*/
198 noffset = readlong(pf);
200 /* # bytes of width*/
201 nwidth = readlong(pf);
203 /* variable font data*/
204 pf->bits = (unsigned char *)pf->buffer_position;
205 pf->buffer_position += pf->bits_size*sizeof(unsigned char);
207 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
209 /* pad to 16-bit boundary */
210 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
212 else
214 /* pad to 32-bit boundary*/
215 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
218 if (noffset)
220 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
222 pf->long_offset = 0;
223 pf->offset = (uint16_t*)pf->buffer_position;
225 /* Check we have sufficient buffer */
226 if (!HAVEBYTES(noffset * sizeof(uint16_t)))
227 return NULL;
229 for (i=0; i<noffset; ++i)
231 ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
234 else
236 pf->long_offset = 1;
237 pf->offset = (uint16_t*)pf->buffer_position;
239 /* Check we have sufficient buffer */
240 if (!HAVEBYTES(noffset * sizeof(int32_t)))
241 return NULL;
243 for (i=0; i<noffset; ++i)
245 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
249 else
250 pf->offset = NULL;
252 if (nwidth) {
253 pf->width = (unsigned char *)pf->buffer_position;
254 pf->buffer_position += nwidth*sizeof(unsigned char);
256 else
257 pf->width = NULL;
259 if (pf->buffer_position > pf->buffer_end)
260 return NULL;
262 return pf; /* success!*/
265 /* Load cached font */
266 static struct font* font_load_cached(struct font* pf)
268 uint32_t noffset, nwidth;
269 unsigned char* oldfileptr = pf->buffer_position;
271 if (!HAVEBYTES(2 * sizeof(int32_t)))
272 return NULL;
274 /* # longs of offset*/
275 noffset = readlong(pf);
277 /* # bytes of width*/
278 nwidth = readlong(pf);
280 /* We are now at the bitmap data, this is fixed at 36.. */
281 pf->bits = NULL;
283 /* Calculate offset to offset data */
284 pf->buffer_position += pf->bits_size * sizeof(unsigned char);
286 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
288 pf->long_offset = 0;
289 /* pad to 16-bit boundary */
290 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
292 else
294 pf->long_offset = 1;
295 /* pad to 32-bit boundary*/
296 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
299 if (noffset)
300 pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
301 else
302 pf->file_offset_offset = 0;
304 /* Calculate offset to widths data */
305 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
306 pf->buffer_position += noffset * sizeof(uint16_t);
307 else
308 pf->buffer_position += noffset * sizeof(uint32_t);
310 if (nwidth)
311 pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
312 else
313 pf->file_width_offset = 0;
315 pf->buffer_position = oldfileptr;
317 /* Create the cache */
318 cache_create(pf);
320 return pf;
323 static bool internal_load_font(struct font* pf, const char *path,
324 char *buf, size_t buf_size)
326 int size;
328 /* save loaded glyphs */
329 glyph_cache_save(pf);
330 /* Close font file handle */
331 if (pf->fd >= 0)
332 close(pf->fd);
334 font_reset(pf);
336 /* open and read entire font file*/
337 pf->fd = open(path, O_RDONLY|O_BINARY);
339 if (pf->fd < 0) {
340 DEBUGF("Can't open font: %s\n", path);
341 return false;
344 /* Check file size */
345 size = filesize(pf->fd);
346 pf->buffer_start = buf;
347 pf->buffer_size = buf_size;
349 pf->buffer_position = buf;
351 if (size > pf->buffer_size)
353 read(pf->fd, pf->buffer_position, FONT_HEADER_SIZE);
354 pf->buffer_end = pf->buffer_position + FONT_HEADER_SIZE;
356 if (!font_load_header(pf))
358 DEBUGF("Failed font header load");
359 close(pf->fd);
360 pf->fd = -1;
361 return false;
364 if (!font_load_cached(pf))
366 DEBUGF("Failed font cache load");
367 close(pf->fd);
368 pf->fd = -1;
369 return false;
372 glyph_cache_load(pf);
374 else
376 read(pf->fd, pf->buffer_position, pf->buffer_size);
377 pf->buffer_end = pf->buffer_position + size;
378 close(pf->fd);
379 pf->fd = -1;
381 if (!font_load_header(pf))
383 DEBUGF("Failed font header load");
384 return false;
387 if (!font_load_in_memory(pf))
389 DEBUGF("Failed mem load");
390 return false;
393 return true;
396 #ifdef HAVE_REMOTE_LCD
397 /* Load a font into the special remote ui font slot */
398 int font_load_remoteui(const char* path)
400 struct font* pf = &remote_font_ui;
401 if (!path)
403 if (sysfonts[FONT_UI_REMOTE] && sysfonts[FONT_UI_REMOTE] != sysfonts[FONT_UI])
404 font_unload(FONT_UI_REMOTE);
405 sysfonts[FONT_UI_REMOTE] = NULL;
406 return FONT_UI;
408 if (!internal_load_font(pf, path, remote_buf, REMOTE_FONT_SIZE))
410 sysfonts[FONT_UI_REMOTE] = NULL;
411 return -1;
414 sysfonts[FONT_UI_REMOTE] = pf;
415 return FONT_UI_REMOTE;
417 #endif
419 /* read and load font into incore font structure,
420 * returns the font number on success, -1 on failure */
421 int font_load(struct font* pf, const char *path)
423 int font_id = -1;
424 char *buffer;
425 size_t buffer_size;
426 if (pf == NULL)
428 pf = &font_ui;
429 font_id = FONT_UI;
431 else
433 for (font_id = SYSTEMFONTCOUNT; font_id < MAXFONTS; font_id++)
435 if (sysfonts[font_id] == NULL)
436 break;
438 if (font_id == MAXFONTS)
439 return -1; /* too many fonts */
442 if (font_id == FONT_UI)
444 /* currently, font loading replaces earlier font allocation*/
445 buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3);
446 /* make sure above doesn't exceed */
447 buffer_size = MAX_FONT_SIZE-3;
449 else
451 buffer = pf->buffer_start;
452 buffer_size = pf->buffer_size;
455 if (!internal_load_font(pf, path, buffer, buffer_size))
456 return -1;
458 sysfonts[font_id] = pf;
459 return font_id; /* success!*/
462 void font_unload(int font_id)
464 struct font* pf = sysfonts[font_id];
465 if (font_id >= SYSTEMFONTCOUNT && pf)
467 if (pf->fd >= 0)
468 close(pf->fd);
469 sysfonts[font_id] = NULL;
474 * Return a pointer to an incore font structure.
475 * If the requested font isn't loaded/compiled-in,
476 * decrement the font number and try again.
478 struct font* font_get(int font)
480 struct font* pf;
482 while (1) {
483 pf = sysfonts[font];
484 if (pf && pf->height)
485 return pf;
486 if (--font < 0)
487 panicf("No font!");
492 * Reads an entry into cache entry
494 static void
495 load_cache_entry(struct font_cache_entry* p, void* callback_data)
497 struct font* pf = callback_data;
498 unsigned short char_code = p->_char_code;
499 unsigned char tmp[2];
501 if (pf->file_width_offset)
503 int width_offset = pf->file_width_offset + char_code;
504 lseek(pf->fd, width_offset, SEEK_SET);
505 read(pf->fd, &(p->width), 1);
507 else
509 p->width = pf->maxwidth;
512 int32_t bitmap_offset = 0;
514 if (pf->file_offset_offset)
516 int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
517 lseek(pf->fd, offset, SEEK_SET);
518 read (pf->fd, tmp, 2);
519 bitmap_offset = tmp[0] | (tmp[1] << 8);
520 if (pf->long_offset) {
521 read (pf->fd, tmp, 2);
522 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
525 else
527 bitmap_offset = char_code * glyph_bytes(pf, p->width);
530 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
531 lseek(pf->fd, file_offset, SEEK_SET);
532 int src_bytes = glyph_bytes(pf, p->width);
533 read(pf->fd, p->bitmap, src_bytes);
537 * Converts cbuf into a font cache
539 static void cache_create(struct font* pf)
541 /* maximum size of rotated bitmap */
542 int bitmap_size = glyph_bytes( pf, pf->maxwidth);
544 /* Initialise cache */
545 font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
549 * Returns width of character
551 int font_get_width(struct font* pf, unsigned short char_code)
553 /* check input range*/
554 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
555 char_code = pf->defaultchar;
556 char_code -= pf->firstchar;
558 return (pf->fd >= 0 && pf != &sysfont)?
559 font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
560 pf->width? pf->width[char_code]: pf->maxwidth;
563 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
565 const unsigned char* bits;
567 /* check input range*/
568 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
569 char_code = pf->defaultchar;
570 char_code -= pf->firstchar;
572 if (pf->fd >= 0 && pf != &sysfont)
574 bits =
575 (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->bitmap;
577 else
579 bits = pf->bits;
580 if (pf->offset)
582 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
583 bits += ((uint16_t*)(pf->offset))[char_code];
584 else
585 bits += ((uint32_t*)(pf->offset))[char_code];
587 else
588 bits += char_code * glyph_bytes(pf, pf->maxwidth);
591 return bits;
593 static int cache_fd;
594 static void glyph_file_write(void* data)
596 struct font_cache_entry* p = data;
597 struct font* pf = &font_ui;
598 unsigned short ch;
599 unsigned char tmp[2];
601 if ( p->_char_code == 0xffff )
602 return;
604 ch = p->_char_code + pf->firstchar;
606 if ( cache_fd >= 0) {
607 tmp[0] = ch >> 8;
608 tmp[1] = ch & 0xff;
609 if (write(cache_fd, tmp, 2) != 2) {
610 close(cache_fd);
611 cache_fd = -1;
614 return;
617 /* save the char codes of the loaded glyphs to a file */
618 void glyph_cache_save(struct font* pf)
620 if (!pf)
621 pf = &font_ui;
622 if (pf->fd >= 0 && pf == &font_ui)
624 cache_fd = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666);
625 if (cache_fd < 0)
626 return;
628 lru_traverse(&pf->cache._lru, glyph_file_write);
630 if (cache_fd >= 0)
632 close(cache_fd);
633 cache_fd = -1;
636 return;
639 int font_glyphs_to_bufsize(const char *path, int glyphs)
641 struct font f;
642 int bufsize;
643 char buf[FONT_HEADER_SIZE];
645 f.buffer_start = buf;
646 f.buffer_size = sizeof(buf);
647 f.buffer_position = buf;
649 f.fd = open(path, O_RDONLY|O_BINARY);
650 if(f.fd < 0)
651 return 0;
653 read(f.fd, f.buffer_position, FONT_HEADER_SIZE);
654 f.buffer_end = f.buffer_position + FONT_HEADER_SIZE;
656 if( !font_load_header(&f) )
658 close(f.fd);
659 return 0;
661 close(f.fd);
663 bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) +
664 sizeof( unsigned short);
665 bufsize += glyph_bytes(&f, f.maxwidth);
666 bufsize *= glyphs;
667 if ( bufsize < FONT_HEADER_SIZE )
668 bufsize = FONT_HEADER_SIZE;
669 return bufsize;
672 static int ushortcmp(const void *a, const void *b)
674 return ((int)(*(unsigned short*)a - *(unsigned short*)b));
676 static void glyph_cache_load(struct font* pf)
679 #define MAX_SORT 256
680 if (pf->fd >= 0) {
681 int fd;
682 int i, size;
683 unsigned char tmp[2];
684 unsigned short ch;
685 unsigned short glyphs[MAX_SORT];
686 unsigned short glyphs_lru_order[MAX_SORT];
687 int glyph_file_skip=0, glyph_file_size=0;
689 int sort_size = pf->cache._capacity;
690 if ( sort_size > MAX_SORT )
691 sort_size = MAX_SORT;
693 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
694 if (fd >= 0) {
696 /* only read what fits */
697 glyph_file_size = filesize( fd );
698 if ( glyph_file_size > 2*pf->cache._capacity ) {
699 glyph_file_skip = glyph_file_size - 2*pf->cache._capacity;
700 lseek( fd, glyph_file_skip, SEEK_SET );
703 while(1) {
705 for ( size = 0;
706 read( fd, tmp, 2 ) == 2 && size < sort_size;
707 size++ )
709 glyphs[size] = (tmp[0] << 8) | tmp[1];
710 glyphs_lru_order[size] = glyphs[size];
713 /* sort glyphs array to make sector cache happy */
714 qsort((void *)glyphs, size, sizeof(unsigned short),
715 ushortcmp );
717 /* load font bitmaps */
718 i = 0;
719 font_get_bits(pf, glyphs[i]);
720 for ( i = 1; i < size ; i++) {
721 if ( glyphs[i] != glyphs[i-1] )
722 font_get_bits(pf, glyphs[i]);
725 /* redo to fix lru order */
726 for ( i = 0; i < size ; i++)
727 font_get_bits(pf, glyphs_lru_order[i]);
729 if ( size < sort_size )
730 break;
733 close(fd);
734 } else {
735 /* load latin1 chars into cache */
736 for ( ch = 32 ; ch < 256 && ch < pf->cache._capacity + 32; ch++ )
737 font_get_bits(pf, ch);
740 return;
742 #else /* BOOTLOADER */
744 void font_init(void)
749 * Bootloader only supports the built-in sysfont.
751 struct font* font_get(int font)
753 (void)font;
754 return &sysfont;
758 * Returns width of character
760 int font_get_width(struct font* pf, unsigned short char_code)
762 /* check input range*/
763 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
764 char_code = pf->defaultchar;
765 char_code -= pf->firstchar;
767 return pf->width? pf->width[char_code]: pf->maxwidth;
770 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
772 const unsigned char* bits;
774 /* check input range*/
775 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
776 char_code = pf->defaultchar;
777 char_code -= pf->firstchar;
779 /* assume small font with uint16_t offsets*/
780 bits = pf->bits + (pf->offset?
781 ((uint16_t*)(pf->offset))[char_code]:
782 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
784 return bits;
787 #endif /* BOOTLOADER */
790 * Returns the stringsize of a given string.
792 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
794 struct font* pf = font_get(fontnumber);
795 unsigned short ch;
796 int width = 0;
798 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
800 if (is_diacritic(ch, NULL))
801 continue;
803 /* get proportional width and glyph bits*/
804 width += font_get_width(pf,ch);
806 if ( w )
807 *w = width;
808 if ( h )
809 *h = pf->height;
810 return width;
813 /* -----------------------------------------------------------------
814 * vim: et sw=4 ts=8 sts=4 tw=78