Add "elfzip" target to make which creates a zip of all elf files, as mapzip does...
[maemo-rb.git] / firmware / font.c
blob8538ef9490815cb29b02ee563a149b604e075f9c
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 "font.h"
35 #include "file.h"
36 #include "debug.h"
37 #include "panic.h"
38 #include "rbunicode.h"
39 #include "diacritic.h"
40 #include "rbpaths.h"
42 #define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
44 /* max static loadable font buffer size */
45 #ifndef MAX_FONT_SIZE
46 #if LCD_HEIGHT > 64
47 #if MEMORYSIZE > 2
48 #define MAX_FONT_SIZE 60000
49 #else
50 #define MAX_FONT_SIZE 10000
51 #endif
52 #else
53 #define MAX_FONT_SIZE 4000
54 #endif
55 #endif
57 #ifndef FONT_HEADER_SIZE
58 #define FONT_HEADER_SIZE 36
59 #endif
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;
78 /* static buffer allocation structures */
79 static unsigned char main_buf[MAX_FONT_SIZE];
80 #ifdef HAVE_REMOTE_LCD
81 #define REMOTE_FONT_SIZE 10000
82 static struct font remote_font_ui;
83 static unsigned char remote_buf[REMOTE_FONT_SIZE];
84 #endif
86 /* system font table, in order of FONT_xxx definition */
87 static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL};
90 /* Font cache structures */
91 static void cache_create(struct font* pf, int maxwidth, int height);
92 static void glyph_cache_load(struct font* pf);
93 /* End Font cache structures */
95 void font_init(void)
97 int i = SYSTEMFONTCOUNT;
98 while (i<MAXFONTS)
99 sysfonts[i++] = NULL;
100 font_reset(NULL);
101 #ifdef HAVE_REMOTE_LCD
102 font_reset(&remote_font_ui);
103 #endif
106 /* Check if we have x bytes left in the file buffer */
107 #define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
109 /* Helper functions to read big-endian unaligned short or long from
110 the file buffer. Bounds-checking must be done in the calling
111 function.
114 static short readshort(struct font *pf)
116 unsigned short s;
118 s = *pf->buffer_position++ & 0xff;
119 s |= (*pf->buffer_position++ << 8);
120 return s;
123 static int32_t readlong(struct font *pf)
125 uint32_t l;
127 l = *pf->buffer_position++ & 0xff;
128 l |= *pf->buffer_position++ << 8;
129 l |= ((uint32_t)(*pf->buffer_position++)) << 16;
130 l |= ((uint32_t)(*pf->buffer_position++)) << 24;
131 return l;
134 void font_reset(struct font *pf)
136 unsigned char* buffer = NULL;
137 size_t buf_size = 0;
138 if (pf == NULL)
139 pf = &font_ui;
140 else
142 buffer = pf->buffer_start;
143 buf_size = pf->buffer_size;
145 memset(pf, 0, sizeof(struct font));
146 pf->fd = -1;
147 if (buffer)
149 pf->buffer_start = buffer;
150 pf->buffer_size = buf_size;
154 static struct font* font_load_header(struct font *pf)
156 /* Check we have enough data */
157 if (!HAVEBYTES(28))
158 return NULL;
160 /* read magic and version #*/
161 if (memcmp(pf->buffer_position, VERSION, 4) != 0)
162 return NULL;
164 pf->buffer_position += 4;
166 /* font info*/
167 pf->maxwidth = readshort(pf);
168 pf->height = readshort(pf);
169 pf->ascent = readshort(pf);
170 pf->buffer_position += 2; /* Skip padding */
171 pf->firstchar = readlong(pf);
172 pf->defaultchar = readlong(pf);
173 pf->size = readlong(pf);
175 /* get variable font data sizes*/
176 /* # words of bitmap_t*/
177 pf->bits_size = readlong(pf);
179 return pf;
181 /* Load memory font */
182 static struct font* font_load_in_memory(struct font* pf)
184 int32_t i, noffset, nwidth;
186 if (!HAVEBYTES(4))
187 return NULL;
189 /* # longs of offset*/
190 noffset = readlong(pf);
192 /* # bytes of width*/
193 nwidth = readlong(pf);
195 /* variable font data*/
196 pf->bits = (unsigned char *)pf->buffer_position;
197 pf->buffer_position += pf->bits_size*sizeof(unsigned char);
199 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
201 /* pad to 16-bit boundary */
202 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
204 else
206 /* pad to 32-bit boundary*/
207 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
210 if (noffset)
212 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
214 pf->long_offset = 0;
215 pf->offset = (uint16_t*)pf->buffer_position;
217 /* Check we have sufficient buffer */
218 if (!HAVEBYTES(noffset * sizeof(uint16_t)))
219 return NULL;
221 for (i=0; i<noffset; ++i)
223 ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
226 else
228 pf->long_offset = 1;
229 pf->offset = (uint16_t*)pf->buffer_position;
231 /* Check we have sufficient buffer */
232 if (!HAVEBYTES(noffset * sizeof(int32_t)))
233 return NULL;
235 for (i=0; i<noffset; ++i)
237 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
241 else
242 pf->offset = NULL;
244 if (nwidth) {
245 pf->width = (unsigned char *)pf->buffer_position;
246 pf->buffer_position += nwidth*sizeof(unsigned char);
248 else
249 pf->width = NULL;
251 if (pf->buffer_position > pf->buffer_end)
252 return NULL;
254 return pf; /* success!*/
257 /* Load cached font */
258 static struct font* font_load_cached(struct font* pf)
260 uint32_t noffset, nwidth;
261 unsigned char* oldfileptr = pf->buffer_position;
263 if (!HAVEBYTES(2 * sizeof(int32_t)))
264 return NULL;
266 /* # longs of offset*/
267 noffset = readlong(pf);
269 /* # bytes of width*/
270 nwidth = readlong(pf);
272 /* We are now at the bitmap data, this is fixed at 36.. */
273 pf->bits = NULL;
275 /* Calculate offset to offset data */
276 pf->buffer_position += pf->bits_size * sizeof(unsigned char);
278 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
280 pf->long_offset = 0;
281 /* pad to 16-bit boundary */
282 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
284 else
286 pf->long_offset = 1;
287 /* pad to 32-bit boundary*/
288 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
291 if (noffset)
292 pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
293 else
294 pf->file_offset_offset = 0;
296 /* Calculate offset to widths data */
297 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
298 pf->buffer_position += noffset * sizeof(uint16_t);
299 else
300 pf->buffer_position += noffset * sizeof(uint32_t);
302 if (nwidth)
303 pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
304 else
305 pf->file_width_offset = 0;
307 pf->buffer_position = oldfileptr;
309 /* Create the cache */
310 cache_create(pf, pf->maxwidth, pf->height);
312 return pf;
315 static bool internal_load_font(struct font* pf, const char *path,
316 char *buf, size_t buf_size)
318 int size;
320 /* save loaded glyphs */
321 glyph_cache_save(pf);
322 /* Close font file handle */
323 if (pf->fd >= 0)
324 close(pf->fd);
326 font_reset(pf);
328 /* open and read entire font file*/
329 pf->fd = open(path, O_RDONLY|O_BINARY);
331 if (pf->fd < 0) {
332 DEBUGF("Can't open font: %s\n", path);
333 return false;
336 /* Check file size */
337 size = filesize(pf->fd);
338 pf->buffer_start = buf;
339 pf->buffer_size = buf_size;
341 pf->buffer_position = buf;
343 if (size > pf->buffer_size)
345 read(pf->fd, pf->buffer_position, FONT_HEADER_SIZE);
346 pf->buffer_end = pf->buffer_position + FONT_HEADER_SIZE;
348 if (!font_load_header(pf))
350 DEBUGF("Failed font header load");
351 close(pf->fd);
352 pf->fd = -1;
353 return false;
356 if (!font_load_cached(pf))
358 DEBUGF("Failed font cache load");
359 close(pf->fd);
360 pf->fd = -1;
361 return false;
364 glyph_cache_load(pf);
366 else
368 read(pf->fd, pf->buffer_position, pf->buffer_size);
369 pf->buffer_end = pf->buffer_position + size;
370 close(pf->fd);
371 pf->fd = -1;
373 if (!font_load_header(pf))
375 DEBUGF("Failed font header load");
376 return false;
379 if (!font_load_in_memory(pf))
381 DEBUGF("Failed mem load");
382 return false;
385 return true;
388 #ifdef HAVE_REMOTE_LCD
389 /* Load a font into the special remote ui font slot */
390 int font_load_remoteui(const char* path)
392 struct font* pf = &remote_font_ui;
393 if (!path)
395 if (sysfonts[FONT_UI_REMOTE] && sysfonts[FONT_UI_REMOTE] != sysfonts[FONT_UI])
396 font_unload(FONT_UI_REMOTE);
397 sysfonts[FONT_UI_REMOTE] = NULL;
398 return FONT_UI;
400 if (!internal_load_font(pf, path, remote_buf, REMOTE_FONT_SIZE))
402 sysfonts[FONT_UI_REMOTE] = NULL;
403 return -1;
406 sysfonts[FONT_UI_REMOTE] = pf;
407 return FONT_UI_REMOTE;
409 #endif
411 /* read and load font into incore font structure,
412 * returns the font number on success, -1 on failure */
413 int font_load(struct font* pf, const char *path)
415 int font_id = -1;
416 char *buffer;
417 size_t buffer_size;
418 if (pf == NULL)
420 pf = &font_ui;
421 font_id = FONT_UI;
423 else
425 for (font_id = SYSTEMFONTCOUNT; font_id < MAXFONTS; font_id++)
427 if (sysfonts[font_id] == NULL)
428 break;
430 if (font_id == MAXFONTS)
431 return -1; /* too many fonts */
434 if (font_id == FONT_UI)
436 /* currently, font loading replaces earlier font allocation*/
437 buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3);
438 buffer_size = MAX_FONT_SIZE;
440 else
442 buffer = pf->buffer_start;
443 buffer_size = pf->buffer_size;
446 if (!internal_load_font(pf, path, buffer, buffer_size))
447 return -1;
449 sysfonts[font_id] = pf;
450 return font_id; /* success!*/
453 void font_unload(int font_id)
455 struct font* pf = sysfonts[font_id];
456 if (font_id >= SYSTEMFONTCOUNT && pf)
458 if (pf->fd >= 0)
459 close(pf->fd);
460 sysfonts[font_id] = NULL;
465 * Return a pointer to an incore font structure.
466 * If the requested font isn't loaded/compiled-in,
467 * decrement the font number and try again.
469 struct font* font_get(int font)
471 struct font* pf;
473 while (1) {
474 pf = sysfonts[font];
475 if (pf && pf->height)
476 return pf;
477 if (--font < 0)
478 panicf("No font!");
483 * Reads an entry into cache entry
485 static void
486 load_cache_entry(struct font_cache_entry* p, void* callback_data)
488 struct font* pf = callback_data;
489 unsigned short char_code = p->_char_code;
490 unsigned char tmp[2];
492 if (pf->file_width_offset)
494 int width_offset = pf->file_width_offset + char_code;
495 lseek(pf->fd, width_offset, SEEK_SET);
496 read(pf->fd, &(p->width), 1);
498 else
500 p->width = pf->maxwidth;
503 int32_t bitmap_offset = 0;
505 if (pf->file_offset_offset)
507 int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
508 lseek(pf->fd, offset, SEEK_SET);
509 read (pf->fd, tmp, 2);
510 bitmap_offset = tmp[0] | (tmp[1] << 8);
511 if (pf->long_offset) {
512 read (pf->fd, tmp, 2);
513 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
516 else
518 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
521 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
522 lseek(pf->fd, file_offset, SEEK_SET);
524 int src_bytes = p->width * ((pf->height + 7) / 8);
525 read(pf->fd, p->bitmap, src_bytes);
529 * Converts cbuf into a font cache
531 static void cache_create(struct font* pf, int maxwidth, int height)
533 /* maximum size of rotated bitmap */
534 int bitmap_size = maxwidth * ((height + 7) / 8);
536 /* Initialise cache */
537 font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
541 * Returns width of character
543 int font_get_width(struct font* pf, unsigned short char_code)
545 /* check input range*/
546 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
547 char_code = pf->defaultchar;
548 char_code -= pf->firstchar;
550 return (pf->fd >= 0 && pf != &sysfont)?
551 font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
552 pf->width? pf->width[char_code]: pf->maxwidth;
555 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
557 const unsigned char* bits;
559 /* check input range*/
560 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
561 char_code = pf->defaultchar;
562 char_code -= pf->firstchar;
564 if (pf->fd >= 0 && pf != &sysfont)
566 bits =
567 (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->bitmap;
569 else
571 bits = pf->bits;
572 if (pf->offset)
574 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
575 bits += ((uint16_t*)(pf->offset))[char_code];
576 else
577 bits += ((uint32_t*)(pf->offset))[char_code];
579 else
580 bits += ((pf->height + 7) / 8) * pf->maxwidth * char_code;
583 return bits;
585 static int cache_fd;
586 static void glyph_file_write(void* data)
588 struct font_cache_entry* p = data;
589 struct font* pf = &font_ui;
590 unsigned short ch;
591 unsigned char tmp[2];
593 if ( p->_char_code == 0xffff )
594 return;
596 ch = p->_char_code + pf->firstchar;
598 if ( cache_fd >= 0) {
599 tmp[0] = ch >> 8;
600 tmp[1] = ch & 0xff;
601 if (write(cache_fd, tmp, 2) != 2) {
602 close(cache_fd);
603 cache_fd = -1;
606 return;
609 /* save the char codes of the loaded glyphs to a file */
610 void glyph_cache_save(struct font* pf)
612 if (!pf)
613 pf = &font_ui;
614 if (pf->fd >= 0 && pf == &font_ui)
616 cache_fd = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666);
617 if (cache_fd < 0)
618 return;
620 lru_traverse(&pf->cache._lru, glyph_file_write);
622 if (cache_fd >= 0)
624 close(cache_fd);
625 cache_fd = -1;
628 return;
631 int font_glyphs_to_bufsize(const char *path, int glyphs)
633 struct font f;
634 int bufsize;
635 char buf[FONT_HEADER_SIZE];
637 f.buffer_start = buf;
638 f.buffer_size = sizeof(buf);
639 f.buffer_position = buf;
641 f.fd = open(path, O_RDONLY|O_BINARY);
642 if(f.fd < 0)
643 return 0;
645 read(f.fd, f.buffer_position, FONT_HEADER_SIZE);
646 f.buffer_end = f.buffer_position + FONT_HEADER_SIZE;
648 if( !font_load_header(&f) )
650 close(f.fd);
651 return 0;
653 close(f.fd);
655 bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) +
656 sizeof( unsigned short);
657 bufsize += f.maxwidth * ((f.height + 7) / 8);
658 bufsize *= glyphs;
659 if ( bufsize < FONT_HEADER_SIZE )
660 bufsize = FONT_HEADER_SIZE;
661 return bufsize;
664 static int ushortcmp(const void *a, const void *b)
666 return ((int)(*(unsigned short*)a - *(unsigned short*)b));
668 static void glyph_cache_load(struct font* pf)
671 #define MAX_SORT 256
672 if (pf->fd >= 0) {
673 int fd;
674 int i, size;
675 unsigned char tmp[2];
676 unsigned short ch;
677 unsigned short glyphs[MAX_SORT];
678 unsigned short glyphs_lru_order[MAX_SORT];
679 int glyph_file_skip=0, glyph_file_size=0;
681 int sort_size = pf->cache._capacity;
682 if ( sort_size > MAX_SORT )
683 sort_size = MAX_SORT;
685 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
686 if (fd >= 0) {
688 /* only read what fits */
689 glyph_file_size = filesize( fd );
690 if ( glyph_file_size > 2*pf->cache._capacity ) {
691 glyph_file_skip = glyph_file_size - 2*pf->cache._capacity;
692 lseek( fd, glyph_file_skip, SEEK_SET );
695 while(1) {
697 for ( size = 0;
698 read( fd, tmp, 2 ) == 2 && size < sort_size;
699 size++ )
701 glyphs[size] = (tmp[0] << 8) | tmp[1];
702 glyphs_lru_order[size] = glyphs[size];
705 /* sort glyphs array to make sector cache happy */
706 qsort((void *)glyphs, size, sizeof(unsigned short),
707 ushortcmp );
709 /* load font bitmaps */
710 i = 0;
711 font_get_bits(pf, glyphs[i]);
712 for ( i = 1; i < size ; i++) {
713 if ( glyphs[i] != glyphs[i-1] )
714 font_get_bits(pf, glyphs[i]);
717 /* redo to fix lru order */
718 for ( i = 0; i < size ; i++)
719 font_get_bits(pf, glyphs_lru_order[i]);
721 if ( size < sort_size )
722 break;
725 close(fd);
726 } else {
727 /* load latin1 chars into cache */
728 for ( ch = 32 ; ch < 256 && ch < pf->cache._capacity + 32; ch++ )
729 font_get_bits(pf, ch);
732 return;
734 #else /* BOOTLOADER */
736 void font_init(void)
741 * Bootloader only supports the built-in sysfont.
743 struct font* font_get(int font)
745 (void)font;
746 return &sysfont;
750 * Returns width of character
752 int font_get_width(struct font* pf, unsigned short char_code)
754 /* check input range*/
755 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
756 char_code = pf->defaultchar;
757 char_code -= pf->firstchar;
759 return pf->width? pf->width[char_code]: pf->maxwidth;
762 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
764 const unsigned char* bits;
766 /* check input range*/
767 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
768 char_code = pf->defaultchar;
769 char_code -= pf->firstchar;
771 /* assume small font with uint16_t offsets*/
772 bits = pf->bits + (pf->offset?
773 ((uint16_t*)(pf->offset))[char_code]:
774 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
776 return bits;
779 #endif /* BOOTLOADER */
782 * Returns the stringsize of a given string.
784 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
786 struct font* pf = font_get(fontnumber);
787 unsigned short ch;
788 int width = 0;
790 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
792 if (is_diacritic(ch, NULL))
793 continue;
795 /* get proportional width and glyph bits*/
796 width += font_get_width(pf,ch);
798 if ( w )
799 *w = width;
800 if ( h )
801 *h = pf->height;
802 return width;
805 /* -----------------------------------------------------------------
806 * vim: et sw=4 ts=8 sts=4 tw=78