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.
37 #include "core_alloc.h"
40 #include "rbunicode.h"
41 #include "diacritic.h"
44 #define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
46 /* max static loadable font buffer size */
50 #define MAX_FONT_SIZE 60000
52 #define MAX_FONT_SIZE 10000
55 #define MAX_FONT_SIZE 4000
59 #ifndef FONT_HEADER_SIZE
60 #define FONT_HEADER_SIZE 36
64 /* Font cache includes */
65 #include "font_cache.h"
73 /* compiled-in font */
74 extern struct font sysfont
;
78 struct buflib_alloc_data
{
80 bool handle_locked
; /* is the buflib handle currently locked? */
81 int refcount
; /* how many times has this font been loaded? */
82 unsigned char buffer
[];
84 static int buflib_allocations
[MAXFONTS
];
85 static int handle_for_glyphcache
;
87 static int buflibmove_callback(int handle
, void* current
, void* new)
90 struct buflib_alloc_data
*alloc
= (struct buflib_alloc_data
*)current
;
91 size_t diff
= new - current
;
93 if (alloc
->handle_locked
)
94 return BUFLIB_CB_CANNOT_MOVE
;
97 alloc
->font
.bits
+= diff
;
98 if (alloc
->font
.offset
)
99 alloc
->font
.offset
+= diff
;
100 if (alloc
->font
.width
)
101 alloc
->font
.width
+= diff
;
103 alloc
->font
.buffer_start
+= diff
;
104 alloc
->font
.buffer_end
+= diff
;
105 alloc
->font
.buffer_position
+= diff
;
107 if (alloc
->font
.cache
._index
)
108 alloc
->font
.cache
._index
+= diff
;
109 if (alloc
->font
.cache
._lru
._base
)
110 alloc
->font
.cache
._lru
._base
+= diff
;
114 static void lock_font_handle(int handle
, bool lock
)
116 struct buflib_alloc_data
*alloc
= core_get_data(handle
);
117 alloc
->handle_locked
= lock
;
120 static struct buflib_callbacks buflibops
= {buflibmove_callback
, NULL
};
122 static inline struct font
*pf_from_handle(int handle
)
124 struct buflib_alloc_data
*alloc
= core_get_data(handle
);
125 struct font
*pf
= &alloc
->font
;
129 static inline unsigned char *buffer_from_handle(int handle
)
131 struct buflib_alloc_data
*alloc
= core_get_data(handle
);
132 unsigned char* buffer
= alloc
->buffer
;
136 /* Font cache structures */
137 static void cache_create(struct font
* pf
);
138 static void glyph_cache_load(struct font
* pf
);
139 /* End Font cache structures */
145 buflib_allocations
[i
++] = -1;
146 handle_for_glyphcache
= -1;
149 /* Check if we have x bytes left in the file buffer */
150 #define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
152 /* Helper functions to read big-endian unaligned short or long from
153 the file buffer. Bounds-checking must be done in the calling
157 static short readshort(struct font
*pf
)
161 s
= *pf
->buffer_position
++ & 0xff;
162 s
|= (*pf
->buffer_position
++ << 8);
166 static int32_t readlong(struct font
*pf
)
170 l
= *pf
->buffer_position
++ & 0xff;
171 l
|= *pf
->buffer_position
++ << 8;
172 l
|= ((uint32_t)(*pf
->buffer_position
++)) << 16;
173 l
|= ((uint32_t)(*pf
->buffer_position
++)) << 24;
177 static int glyph_bytes( struct font
*pf
, int width
)
181 ret
= ( pf
->height
* width
+ 1 ) / 2;
183 ret
= width
* ((pf
->height
+ 7) / 8);
184 return (ret
+ 1) & ~1;
187 static struct font
* font_load_header(struct font
*pf
)
189 /* Check we have enough data */
193 /* read magic and version #*/
194 if (memcmp(pf
->buffer_position
, VERSION
, 4) != 0)
197 pf
->buffer_position
+= 4;
200 pf
->maxwidth
= readshort(pf
);
201 pf
->height
= readshort(pf
);
202 pf
->ascent
= readshort(pf
);
203 pf
->depth
= readshort(pf
);
204 pf
->firstchar
= readlong(pf
);
205 pf
->defaultchar
= readlong(pf
);
206 pf
->size
= readlong(pf
);
208 /* get variable font data sizes*/
209 /* # words of bitmap_t*/
210 pf
->bits_size
= readlong(pf
);
214 /* Load memory font */
215 static struct font
* font_load_in_memory(struct font
* pf
)
217 int32_t i
, noffset
, nwidth
;
222 /* # longs of offset*/
223 noffset
= readlong(pf
);
225 /* # bytes of width*/
226 nwidth
= readlong(pf
);
228 /* variable font data*/
229 pf
->bits
= (unsigned char *)pf
->buffer_position
;
230 pf
->buffer_position
+= pf
->bits_size
*sizeof(unsigned char);
232 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
234 /* pad to 16-bit boundary */
235 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 1) & ~1);
239 /* pad to 32-bit boundary*/
240 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
245 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
248 pf
->offset
= (uint16_t*)pf
->buffer_position
;
250 /* Check we have sufficient buffer */
251 if (!HAVEBYTES(noffset
* sizeof(uint16_t)))
254 for (i
=0; i
<noffset
; ++i
)
256 ((uint16_t*)(pf
->offset
))[i
] = (uint16_t)readshort(pf
);
262 pf
->offset
= (uint16_t*)pf
->buffer_position
;
264 /* Check we have sufficient buffer */
265 if (!HAVEBYTES(noffset
* sizeof(int32_t)))
268 for (i
=0; i
<noffset
; ++i
)
270 ((uint32_t*)(pf
->offset
))[i
] = (uint32_t)readlong(pf
);
278 pf
->width
= (unsigned char *)pf
->buffer_position
;
279 pf
->buffer_position
+= nwidth
*sizeof(unsigned char);
284 if (pf
->buffer_position
> pf
->buffer_end
)
287 return pf
; /* success!*/
290 /* Load cached font */
291 static struct font
* font_load_cached(struct font
* pf
)
293 uint32_t noffset
, nwidth
;
294 unsigned char* oldfileptr
= pf
->buffer_position
;
296 if (!HAVEBYTES(2 * sizeof(int32_t)))
299 /* # longs of offset*/
300 noffset
= readlong(pf
);
302 /* # bytes of width*/
303 nwidth
= readlong(pf
);
305 /* We are now at the bitmap data, this is fixed at 36.. */
308 /* Calculate offset to offset data */
309 pf
->buffer_position
+= pf
->bits_size
* sizeof(unsigned char);
311 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
314 /* pad to 16-bit boundary */
315 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 1) & ~1);
320 /* pad to 32-bit boundary*/
321 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
325 pf
->file_offset_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
327 pf
->file_offset_offset
= 0;
329 /* Calculate offset to widths data */
330 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
331 pf
->buffer_position
+= noffset
* sizeof(uint16_t);
333 pf
->buffer_position
+= noffset
* sizeof(uint32_t);
336 pf
->file_width_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
338 pf
->file_width_offset
= 0;
340 pf
->buffer_position
= oldfileptr
;
342 /* Create the cache */
348 static void font_reset(int font_id
)
350 struct font
*pf
= pf_from_handle(buflib_allocations
[font_id
]);
352 memset(pf
, 0, sizeof(struct font
));
357 static bool internal_load_font(int font_id
, const char *path
,
358 char *buf
, size_t buf_size
)
361 struct font
* pf
= pf_from_handle(buflib_allocations
[font_id
]);
362 /* save loaded glyphs */
363 glyph_cache_save(pf
);
364 /* Close font file handle */
370 /* open and read entire font file*/
371 pf
->fd
= open(path
, O_RDONLY
|O_BINARY
);
374 DEBUGF("Can't open font: %s\n", path
);
378 /* Check file size */
379 size
= filesize(pf
->fd
);
380 pf
->buffer_start
= buf
;
381 pf
->buffer_size
= buf_size
;
383 pf
->buffer_position
= buf
;
385 if (size
> pf
->buffer_size
)
387 read(pf
->fd
, pf
->buffer_position
, FONT_HEADER_SIZE
);
388 pf
->buffer_end
= pf
->buffer_position
+ FONT_HEADER_SIZE
;
390 if (!font_load_header(pf
))
392 DEBUGF("Failed font header load");
398 if (!font_load_cached(pf
))
400 DEBUGF("Failed font cache load");
406 glyph_cache_load(pf
);
410 read(pf
->fd
, pf
->buffer_position
, pf
->buffer_size
);
411 pf
->buffer_end
= pf
->buffer_position
+ size
;
415 if (!font_load_header(pf
))
417 DEBUGF("Failed font header load");
421 if (!font_load_in_memory(pf
))
423 DEBUGF("Failed mem load");
430 static int find_font_index(const char* path
)
432 int index
= 0, handle
;
434 while (index
< MAXFONTS
)
436 handle
= buflib_allocations
[index
];
437 if (handle
> 0 && !strcmp(core_get_name(handle
), path
))
441 return FONT_SYSFIXED
;
444 static int alloc_and_init(int font_idx
, const char* name
, size_t size
)
446 int *phandle
= &buflib_allocations
[font_idx
];
447 int handle
= *phandle
;
448 struct buflib_alloc_data
*pdata
;
450 size_t alloc_size
= size
+ sizeof(struct buflib_alloc_data
);
453 *phandle
= core_alloc_ex(name
, alloc_size
, &buflibops
);
457 pdata
= core_get_data(handle
);
459 font_reset(font_idx
);
460 pdata
->handle_locked
= false;
462 pf
->buffer_position
= pf
->buffer_start
= buffer_from_handle(handle
);
463 pf
->buffer_size
= size
;
467 const char* font_filename(int font_id
)
469 int handle
= buflib_allocations
[font_id
];
471 return core_get_name(handle
);
475 /* read and load font into incore font structure,
476 * returns the font number on success, -1 on failure */
477 int font_load_ex(const char *path
, size_t buffer_size
)
479 int font_id
= find_font_index(path
);
483 if (font_id
> FONT_SYSFIXED
)
485 /* already loaded, no need to reload */
486 struct buflib_alloc_data
*pd
= core_get_data(buflib_allocations
[font_id
]);
487 if (pd
->font
.buffer_size
< buffer_size
)
489 int old_refcount
, old_id
;
491 * 1) save of refcont and id
492 * 2) force unload (set refcount to 1 to make sure it get unloaded)
493 * 3) reload with the larger buffer
494 * 4) restore the id and refcount
497 old_refcount
= pd
->refcount
;
499 font_unload(font_id
);
500 font_id
= font_load_ex(path
, buffer_size
);
503 // not much we can do here, maybe try reloading with the small buffer again
506 if (old_id
!= font_id
)
508 buflib_allocations
[old_id
] = buflib_allocations
[font_id
];
509 buflib_allocations
[font_id
] = -1;
512 pd
= core_get_data(buflib_allocations
[font_id
]);
513 pd
->refcount
= old_refcount
;
516 //printf("reusing handle %d for %s (count: %d)\n", font_id, path, pd->refcount);
520 for (font_id
= FONT_FIRSTUSERFONT
; font_id
< MAXFONTS
; font_id
++)
522 handle
= &buflib_allocations
[font_id
];
528 handle
= &buflib_allocations
[font_id
];
529 *handle
= alloc_and_init(font_id
, path
, buffer_size
);
533 if (handle_for_glyphcache
< 0)
534 handle_for_glyphcache
= *handle
;
536 buffer
= buffer_from_handle(*handle
);
537 lock_font_handle(*handle
, true);
539 if (!internal_load_font(font_id
, path
, buffer
, buffer_size
))
541 lock_font_handle(*handle
, false);
547 lock_font_handle(*handle
, false);
548 //printf("%s -> [%d] -> %d\n", path, font_id, *handle);
549 return font_id
; /* success!*/
551 int font_load(const char *path
)
554 int fd
= open( path
, O_RDONLY
);
558 if (size
> MAX_FONT_SIZE
)
559 size
= MAX_FONT_SIZE
;
561 return font_load_ex(path
, size
);
564 void font_unload(int font_id
)
566 int *handle
= &buflib_allocations
[font_id
];
567 struct buflib_alloc_data
*pdata
= core_get_data(*handle
);
568 struct font
* pf
= &pdata
->font
;
570 if (pdata
->refcount
< 1)
572 //printf("freeing id: %d %s\n", font_id, core_get_name(*handle));
573 if (pf
&& pf
->fd
>= 0)
577 if (handle_for_glyphcache
== *handle
)
578 handle_for_glyphcache
= -1; // should find the next available handle
584 * Return a pointer to an incore font structure.
585 * If the requested font isn't loaded/compiled-in,
586 * decrement the font number and try again.
588 struct font
* font_get(int font
)
593 if (font
<= FONT_SYSFIXED
)
597 if (buflib_allocations
[font
] > 0)
599 struct buflib_alloc_data
*alloc
= core_get_data(buflib_allocations
[font
]);
601 if (pf
&& pf
->height
)
609 static int pf_to_handle(struct font
* pf
)
612 for (i
=0; i
<MAXFONTS
; i
++)
614 int handle
= buflib_allocations
[i
];
617 struct buflib_alloc_data
*pdata
= core_get_data(handle
);
618 if (pf
== &pdata
->font
)
626 * Reads an entry into cache entry
629 load_cache_entry(struct font_cache_entry
* p
, void* callback_data
)
631 struct font
* pf
= callback_data
;
632 int handle
= pf_to_handle(pf
);
633 unsigned short char_code
= p
->_char_code
;
634 unsigned char tmp
[2];
637 lock_font_handle(handle
, true);
638 if (pf
->file_width_offset
)
640 int width_offset
= pf
->file_width_offset
+ char_code
;
641 lseek(pf
->fd
, width_offset
, SEEK_SET
);
642 read(pf
->fd
, &(p
->width
), 1);
646 p
->width
= pf
->maxwidth
;
649 int32_t bitmap_offset
= 0;
651 if (pf
->file_offset_offset
)
653 int32_t offset
= pf
->file_offset_offset
+ char_code
* (pf
->long_offset
? sizeof(int32_t) : sizeof(int16_t));
654 lseek(pf
->fd
, offset
, SEEK_SET
);
655 read (pf
->fd
, tmp
, 2);
656 bitmap_offset
= tmp
[0] | (tmp
[1] << 8);
657 if (pf
->long_offset
) {
658 read (pf
->fd
, tmp
, 2);
659 bitmap_offset
|= (tmp
[0] << 16) | (tmp
[1] << 24);
664 bitmap_offset
= char_code
* glyph_bytes(pf
, p
->width
);
667 int32_t file_offset
= FONT_HEADER_SIZE
+ bitmap_offset
;
668 lseek(pf
->fd
, file_offset
, SEEK_SET
);
669 int src_bytes
= glyph_bytes(pf
, p
->width
);
670 read(pf
->fd
, p
->bitmap
, src_bytes
);
673 lock_font_handle(handle
, false);
677 * Converts cbuf into a font cache
679 static void cache_create(struct font
* pf
)
681 /* maximum size of rotated bitmap */
682 int bitmap_size
= glyph_bytes( pf
, pf
->maxwidth
);
684 /* Initialise cache */
685 font_cache_create(&pf
->cache
, pf
->buffer_start
, pf
->buffer_size
, bitmap_size
);
689 * Returns width of character
691 int font_get_width(struct font
* pf
, unsigned short char_code
)
693 /* check input range*/
694 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
695 char_code
= pf
->defaultchar
;
696 char_code
-= pf
->firstchar
;
698 return (pf
->fd
>= 0 && pf
!= &sysfont
)?
699 font_cache_get(&pf
->cache
,char_code
,load_cache_entry
,pf
)->width
:
700 pf
->width
? pf
->width
[char_code
]: pf
->maxwidth
;
703 const unsigned char* font_get_bits(struct font
* pf
, unsigned short char_code
)
705 const unsigned char* bits
;
707 /* check input range*/
708 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
709 char_code
= pf
->defaultchar
;
710 char_code
-= pf
->firstchar
;
712 if (pf
->fd
>= 0 && pf
!= &sysfont
)
715 (unsigned char*)font_cache_get(&pf
->cache
,char_code
,load_cache_entry
, pf
)->bitmap
;
722 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
723 bits
+= ((uint16_t*)(pf
->offset
))[char_code
];
725 bits
+= ((uint32_t*)(pf
->offset
))[char_code
];
728 bits
+= char_code
* glyph_bytes(pf
, pf
->maxwidth
);
734 static void glyph_file_write(void* data
)
736 struct font_cache_entry
* p
= data
;
737 int handle
= handle_for_glyphcache
;
738 struct font
* pf
= pf_from_handle(handle
);
740 unsigned char tmp
[2];
742 if ( p
->_char_code
== 0xffff )
745 ch
= p
->_char_code
+ pf
->firstchar
;
747 if ( cache_fd
>= 0) {
750 if (write(cache_fd
, tmp
, 2) != 2) {
758 /* save the char codes of the loaded glyphs to a file */
759 void glyph_cache_save(struct font
* pf
)
761 if (pf
!= pf_from_handle(handle_for_glyphcache
))
765 cache_fd
= open(GLYPH_CACHE_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
769 lru_traverse(&pf
->cache
._lru
, glyph_file_write
);
780 int font_glyphs_to_bufsize(const char *path
, int glyphs
)
784 char buf
[FONT_HEADER_SIZE
];
786 f
.buffer_start
= buf
;
787 f
.buffer_size
= sizeof(buf
);
788 f
.buffer_position
= buf
;
790 f
.fd
= open(path
, O_RDONLY
|O_BINARY
);
794 read(f
.fd
, f
.buffer_position
, FONT_HEADER_SIZE
);
795 f
.buffer_end
= f
.buffer_position
+ FONT_HEADER_SIZE
;
797 if( !font_load_header(&f
) )
804 bufsize
= LRU_SLOT_OVERHEAD
+ sizeof(struct font_cache_entry
) +
805 sizeof( unsigned short);
806 bufsize
+= glyph_bytes(&f
, f
.maxwidth
);
808 if ( bufsize
< FONT_HEADER_SIZE
)
809 bufsize
= FONT_HEADER_SIZE
;
813 static int ushortcmp(const void *a
, const void *b
)
815 return ((int)(*(unsigned short*)a
- *(unsigned short*)b
));
817 static void glyph_cache_load(struct font
* pf
)
819 if (handle_for_glyphcache
<= 0)
822 if (pf
->fd
>= 0 && pf
== pf_from_handle(handle_for_glyphcache
)) {
825 unsigned char tmp
[2];
827 unsigned short glyphs
[MAX_SORT
];
828 unsigned short glyphs_lru_order
[MAX_SORT
];
829 int glyph_file_skip
=0, glyph_file_size
=0;
831 int sort_size
= pf
->cache
._capacity
;
832 if ( sort_size
> MAX_SORT
)
833 sort_size
= MAX_SORT
;
835 fd
= open(GLYPH_CACHE_FILE
, O_RDONLY
|O_BINARY
);
838 /* only read what fits */
839 glyph_file_size
= filesize( fd
);
840 if ( glyph_file_size
> 2*pf
->cache
._capacity
) {
841 glyph_file_skip
= glyph_file_size
- 2*pf
->cache
._capacity
;
842 lseek( fd
, glyph_file_skip
, SEEK_SET
);
848 read( fd
, tmp
, 2 ) == 2 && size
< sort_size
;
851 glyphs
[size
] = (tmp
[0] << 8) | tmp
[1];
852 glyphs_lru_order
[size
] = glyphs
[size
];
855 /* sort glyphs array to make sector cache happy */
856 qsort((void *)glyphs
, size
, sizeof(unsigned short),
859 /* load font bitmaps */
861 font_get_bits(pf
, glyphs
[i
]);
862 for ( i
= 1; i
< size
; i
++) {
863 if ( glyphs
[i
] != glyphs
[i
-1] )
864 font_get_bits(pf
, glyphs
[i
]);
867 /* redo to fix lru order */
868 for ( i
= 0; i
< size
; i
++)
869 font_get_bits(pf
, glyphs_lru_order
[i
]);
871 if ( size
< sort_size
)
877 /* load latin1 chars into cache */
878 for ( ch
= 32 ; ch
< 256 && ch
< pf
->cache
._capacity
+ 32; ch
++ )
879 font_get_bits(pf
, ch
);
884 #else /* BOOTLOADER */
891 * Bootloader only supports the built-in sysfont.
893 struct font
* font_get(int font
)
900 * Returns width of character
902 int font_get_width(struct font
* pf
, unsigned short char_code
)
904 /* check input range*/
905 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
906 char_code
= pf
->defaultchar
;
907 char_code
-= pf
->firstchar
;
909 return pf
->width
? pf
->width
[char_code
]: pf
->maxwidth
;
912 const unsigned char* font_get_bits(struct font
* pf
, unsigned short char_code
)
914 const unsigned char* bits
;
916 /* check input range*/
917 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
918 char_code
= pf
->defaultchar
;
919 char_code
-= pf
->firstchar
;
921 /* assume small font with uint16_t offsets*/
922 bits
= pf
->bits
+ (pf
->offset
?
923 ((uint16_t*)(pf
->offset
))[char_code
]:
924 (((pf
->height
+ 7) / 8) * pf
->maxwidth
* char_code
));
929 #endif /* BOOTLOADER */
932 * Returns the stringsize of a given string.
934 int font_getstringsize(const unsigned char *str
, int *w
, int *h
, int fontnumber
)
936 struct font
* pf
= font_get(fontnumber
);
940 for (str
= utf8decode(str
, &ch
); ch
!= 0 ; str
= utf8decode(str
, &ch
))
942 if (is_diacritic(ch
, NULL
))
945 /* get proportional width and glyph bits*/
946 width
+= font_get_width(pf
,ch
);
955 /* -----------------------------------------------------------------
956 * vim: et sw=4 ts=8 sts=4 tw=78