1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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.
38 #include "rbunicode.h"
39 #include "diacritic.h"
42 #define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
44 /* max static loadable font buffer size */
48 #define MAX_FONT_SIZE 60000
50 #define MAX_FONT_SIZE 10000
53 #define MAX_FONT_SIZE 4000
57 #ifndef FONT_HEADER_SIZE
58 #define FONT_HEADER_SIZE 36
62 /* Font cache includes */
63 #include "font_cache.h"
71 /* compiled-in font */
72 extern struct font sysfont
;
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
];
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 */
97 int i
= SYSTEMFONTCOUNT
;
101 #ifdef HAVE_REMOTE_LCD
102 font_reset(&remote_font_ui
);
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
114 static short readshort(struct font
*pf
)
118 s
= *pf
->buffer_position
++ & 0xff;
119 s
|= (*pf
->buffer_position
++ << 8);
123 static int32_t readlong(struct font
*pf
)
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;
134 void font_reset(struct font
*pf
)
136 unsigned char* buffer
= NULL
;
142 buffer
= pf
->buffer_start
;
143 buf_size
= pf
->buffer_size
;
145 memset(pf
, 0, sizeof(struct font
));
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 */
160 /* read magic and version #*/
161 if (memcmp(pf
->buffer_position
, VERSION
, 4) != 0)
164 pf
->buffer_position
+= 4;
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
);
181 /* Load memory font */
182 static struct font
* font_load_in_memory(struct font
* pf
)
184 int32_t i
, noffset
, nwidth
;
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);
206 /* pad to 32-bit boundary*/
207 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
212 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
215 pf
->offset
= (uint16_t*)pf
->buffer_position
;
217 /* Check we have sufficient buffer */
218 if (!HAVEBYTES(noffset
* sizeof(uint16_t)))
221 for (i
=0; i
<noffset
; ++i
)
223 ((uint16_t*)(pf
->offset
))[i
] = (uint16_t)readshort(pf
);
229 pf
->offset
= (uint16_t*)pf
->buffer_position
;
231 /* Check we have sufficient buffer */
232 if (!HAVEBYTES(noffset
* sizeof(int32_t)))
235 for (i
=0; i
<noffset
; ++i
)
237 ((uint32_t*)(pf
->offset
))[i
] = (uint32_t)readlong(pf
);
245 pf
->width
= (unsigned char *)pf
->buffer_position
;
246 pf
->buffer_position
+= nwidth
*sizeof(unsigned char);
251 if (pf
->buffer_position
> pf
->buffer_end
)
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)))
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.. */
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
)
281 /* pad to 16-bit boundary */
282 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 1) & ~1);
287 /* pad to 32-bit boundary*/
288 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
292 pf
->file_offset_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
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);
300 pf
->buffer_position
+= noffset
* sizeof(uint32_t);
303 pf
->file_width_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
305 pf
->file_width_offset
= 0;
307 pf
->buffer_position
= oldfileptr
;
309 /* Create the cache */
310 cache_create(pf
, pf
->maxwidth
, pf
->height
);
315 static bool internal_load_font(struct font
* pf
, const char *path
,
316 char *buf
, size_t buf_size
)
320 /* save loaded glyphs */
321 glyph_cache_save(pf
);
322 /* Close font file handle */
328 /* open and read entire font file*/
329 pf
->fd
= open(path
, O_RDONLY
|O_BINARY
);
332 DEBUGF("Can't open font: %s\n", path
);
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");
356 if (!font_load_cached(pf
))
358 DEBUGF("Failed font cache load");
364 glyph_cache_load(pf
);
368 read(pf
->fd
, pf
->buffer_position
, pf
->buffer_size
);
369 pf
->buffer_end
= pf
->buffer_position
+ size
;
373 if (!font_load_header(pf
))
375 DEBUGF("Failed font header load");
379 if (!font_load_in_memory(pf
))
381 DEBUGF("Failed mem load");
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
;
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
;
400 if (!internal_load_font(pf
, path
, remote_buf
, REMOTE_FONT_SIZE
))
402 sysfonts
[FONT_UI_REMOTE
] = NULL
;
406 sysfonts
[FONT_UI_REMOTE
] = pf
;
407 return FONT_UI_REMOTE
;
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
)
425 for (font_id
= SYSTEMFONTCOUNT
; font_id
< MAXFONTS
; font_id
++)
427 if (sysfonts
[font_id
] == NULL
)
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
;
442 buffer
= pf
->buffer_start
;
443 buffer_size
= pf
->buffer_size
;
446 if (!internal_load_font(pf
, path
, buffer
, buffer_size
))
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
)
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
)
475 if (pf
&& pf
->height
)
483 * Reads an entry into cache entry
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);
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);
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
)
567 (unsigned char*)font_cache_get(&pf
->cache
,char_code
,load_cache_entry
,pf
)->bitmap
;
574 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
575 bits
+= ((uint16_t*)(pf
->offset
))[char_code
];
577 bits
+= ((uint32_t*)(pf
->offset
))[char_code
];
580 bits
+= ((pf
->height
+ 7) / 8) * pf
->maxwidth
* char_code
;
586 static void glyph_file_write(void* data
)
588 struct font_cache_entry
* p
= data
;
589 struct font
* pf
= &font_ui
;
591 unsigned char tmp
[2];
593 if ( p
->_char_code
== 0xffff )
596 ch
= p
->_char_code
+ pf
->firstchar
;
598 if ( cache_fd
>= 0) {
601 if (write(cache_fd
, tmp
, 2) != 2) {
609 /* save the char codes of the loaded glyphs to a file */
610 void glyph_cache_save(struct font
* pf
)
614 if (pf
->fd
>= 0 && pf
== &font_ui
)
617 const char *file
= get_user_file_path(GLYPH_CACHE_FILE
, IS_FILE
|NEED_WRITE
,
620 cache_fd
= open(file
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
624 lru_traverse(&pf
->cache
._lru
, glyph_file_write
);
635 int font_glyphs_to_bufsize(const char *path
, int glyphs
)
639 char buf
[FONT_HEADER_SIZE
];
641 f
.buffer_start
= buf
;
642 f
.buffer_size
= sizeof(buf
);
643 f
.buffer_position
= buf
;
645 f
.fd
= open(path
, O_RDONLY
|O_BINARY
);
649 read(f
.fd
, f
.buffer_position
, FONT_HEADER_SIZE
);
650 f
.buffer_end
= f
.buffer_position
+ FONT_HEADER_SIZE
;
652 if( !font_load_header(&f
) )
659 bufsize
= LRU_SLOT_OVERHEAD
+ sizeof(struct font_cache_entry
) +
660 sizeof( unsigned short);
661 bufsize
+= f
.maxwidth
* ((f
.height
+ 7) / 8);
663 if ( bufsize
< FONT_HEADER_SIZE
)
664 bufsize
= FONT_HEADER_SIZE
;
668 static int ushortcmp(const void *a
, const void *b
)
670 return ((int)(*(unsigned short*)a
- *(unsigned short*)b
));
672 static void glyph_cache_load(struct font
* pf
)
679 unsigned char tmp
[2];
682 unsigned short glyphs
[MAX_SORT
];
683 unsigned short glyphs_lru_order
[MAX_SORT
];
684 int glyph_file_skip
=0, glyph_file_size
=0;
686 int sort_size
= pf
->cache
._capacity
;
687 if ( sort_size
> MAX_SORT
)
688 sort_size
= MAX_SORT
;
690 fd
= open(get_user_file_path(GLYPH_CACHE_FILE
, IS_FILE
|NEED_WRITE
,
691 path
, sizeof(path
)), O_RDONLY
|O_BINARY
);
694 /* only read what fits */
695 glyph_file_size
= filesize( fd
);
696 if ( glyph_file_size
> 2*pf
->cache
._capacity
) {
697 glyph_file_skip
= glyph_file_size
- 2*pf
->cache
._capacity
;
698 lseek( fd
, glyph_file_skip
, SEEK_SET
);
704 read( fd
, tmp
, 2 ) == 2 && size
< sort_size
;
707 glyphs
[size
] = (tmp
[0] << 8) | tmp
[1];
708 glyphs_lru_order
[size
] = glyphs
[size
];
711 /* sort glyphs array to make sector cache happy */
712 qsort((void *)glyphs
, size
, sizeof(unsigned short),
715 /* load font bitmaps */
717 font_get_bits(pf
, glyphs
[i
]);
718 for ( i
= 1; i
< size
; i
++) {
719 if ( glyphs
[i
] != glyphs
[i
-1] )
720 font_get_bits(pf
, glyphs
[i
]);
723 /* redo to fix lru order */
724 for ( i
= 0; i
< size
; i
++)
725 font_get_bits(pf
, glyphs_lru_order
[i
]);
727 if ( size
< sort_size
)
733 /* load latin1 chars into cache */
734 for ( ch
= 32 ; ch
< 256 && ch
< pf
->cache
._capacity
+ 32; ch
++ )
735 font_get_bits(pf
, ch
);
740 #else /* BOOTLOADER */
747 * Bootloader only supports the built-in sysfont.
749 struct font
* font_get(int font
)
756 * Returns width of character
758 int font_get_width(struct font
* pf
, unsigned short char_code
)
760 /* check input range*/
761 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
762 char_code
= pf
->defaultchar
;
763 char_code
-= pf
->firstchar
;
765 return pf
->width
? pf
->width
[char_code
]: pf
->maxwidth
;
768 const unsigned char* font_get_bits(struct font
* pf
, unsigned short char_code
)
770 const unsigned char* bits
;
772 /* check input range*/
773 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
774 char_code
= pf
->defaultchar
;
775 char_code
-= pf
->firstchar
;
777 /* assume small font with uint16_t offsets*/
778 bits
= pf
->bits
+ (pf
->offset
?
779 ((uint16_t*)(pf
->offset
))[char_code
]:
780 (((pf
->height
+ 7) / 8) * pf
->maxwidth
* char_code
));
785 #endif /* BOOTLOADER */
788 * Returns the stringsize of a given string.
790 int font_getstringsize(const unsigned char *str
, int *w
, int *h
, int fontnumber
)
792 struct font
* pf
= font_get(fontnumber
);
796 for (str
= utf8decode(str
, &ch
); ch
!= 0 ; str
= utf8decode(str
, &ch
))
798 if (is_diacritic(ch
, NULL
))
801 /* get proportional width and glyph bits*/
802 width
+= font_get_width(pf
,ch
);
811 /* -----------------------------------------------------------------
812 * vim: et sw=4 ts=8 sts=4 tw=78