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.
39 #include "rbunicode.h"
40 #include "diacritic.h"
43 #define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
45 /* max static loadable font buffer size */
49 #define MAX_FONT_SIZE 60000
51 #define MAX_FONT_SIZE 10000
54 #define MAX_FONT_SIZE 4000
58 #ifndef FONT_HEADER_SIZE
59 #define FONT_HEADER_SIZE 36
63 /* Font cache includes */
64 #include "font_cache.h"
72 /* compiled-in font */
73 extern struct font sysfont
;
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
;
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 */
98 int i
= SYSTEMFONTCOUNT
;
100 sysfonts
[i
++] = NULL
;
102 #ifdef HAVE_REMOTE_LCD
103 font_reset(&remote_font_ui
);
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
115 static short readshort(struct font
*pf
)
119 s
= *pf
->buffer_position
++ & 0xff;
120 s
|= (*pf
->buffer_position
++ << 8);
124 static int32_t readlong(struct font
*pf
)
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;
135 static int glyph_bytes( struct font
*pf
, int width
)
138 (pf
->height
* width
+ 1) / 2:
139 width
* ((pf
->height
+ 7) / 8);
142 void font_reset(struct font
*pf
)
144 unsigned char* buffer
= NULL
;
150 buffer
= pf
->buffer_start
;
151 buf_size
= pf
->buffer_size
;
153 memset(pf
, 0, sizeof(struct font
));
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 */
168 /* read magic and version #*/
169 if (memcmp(pf
->buffer_position
, VERSION
, 4) != 0)
172 pf
->buffer_position
+= 4;
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
);
189 /* Load memory font */
190 static struct font
* font_load_in_memory(struct font
* pf
)
192 int32_t i
, noffset
, nwidth
;
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);
214 /* pad to 32-bit boundary*/
215 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
220 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
223 pf
->offset
= (uint16_t*)pf
->buffer_position
;
225 /* Check we have sufficient buffer */
226 if (!HAVEBYTES(noffset
* sizeof(uint16_t)))
229 for (i
=0; i
<noffset
; ++i
)
231 ((uint16_t*)(pf
->offset
))[i
] = (uint16_t)readshort(pf
);
237 pf
->offset
= (uint16_t*)pf
->buffer_position
;
239 /* Check we have sufficient buffer */
240 if (!HAVEBYTES(noffset
* sizeof(int32_t)))
243 for (i
=0; i
<noffset
; ++i
)
245 ((uint32_t*)(pf
->offset
))[i
] = (uint32_t)readlong(pf
);
253 pf
->width
= (unsigned char *)pf
->buffer_position
;
254 pf
->buffer_position
+= nwidth
*sizeof(unsigned char);
259 if (pf
->buffer_position
> pf
->buffer_end
)
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)))
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.. */
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
)
289 /* pad to 16-bit boundary */
290 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 1) & ~1);
295 /* pad to 32-bit boundary*/
296 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
300 pf
->file_offset_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
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);
308 pf
->buffer_position
+= noffset
* sizeof(uint32_t);
311 pf
->file_width_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
313 pf
->file_width_offset
= 0;
315 pf
->buffer_position
= oldfileptr
;
317 /* Create the cache */
323 static bool internal_load_font(struct font
* pf
, const char *path
,
324 char *buf
, size_t buf_size
)
328 /* save loaded glyphs */
329 glyph_cache_save(pf
);
330 /* Close font file handle */
336 /* open and read entire font file*/
337 pf
->fd
= open(path
, O_RDONLY
|O_BINARY
);
340 DEBUGF("Can't open font: %s\n", path
);
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");
364 if (!font_load_cached(pf
))
366 DEBUGF("Failed font cache load");
372 glyph_cache_load(pf
);
376 read(pf
->fd
, pf
->buffer_position
, pf
->buffer_size
);
377 pf
->buffer_end
= pf
->buffer_position
+ size
;
381 if (!font_load_header(pf
))
383 DEBUGF("Failed font header load");
387 if (!font_load_in_memory(pf
))
389 DEBUGF("Failed mem load");
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
;
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
;
408 if (!internal_load_font(pf
, path
, remote_buf
, REMOTE_FONT_SIZE
))
410 sysfonts
[FONT_UI_REMOTE
] = NULL
;
414 sysfonts
[FONT_UI_REMOTE
] = pf
;
415 return FONT_UI_REMOTE
;
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
)
433 for (font_id
= SYSTEMFONTCOUNT
; font_id
< MAXFONTS
; font_id
++)
435 if (sysfonts
[font_id
] == NULL
)
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;
451 buffer
= pf
->buffer_start
;
452 buffer_size
= pf
->buffer_size
;
455 if (!internal_load_font(pf
, path
, buffer
, buffer_size
))
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
)
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
)
484 if (pf
&& pf
->height
)
492 * Reads an entry into cache entry
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);
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);
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
)
575 (unsigned char*)font_cache_get(&pf
->cache
,char_code
,load_cache_entry
,pf
)->bitmap
;
582 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
583 bits
+= ((uint16_t*)(pf
->offset
))[char_code
];
585 bits
+= ((uint32_t*)(pf
->offset
))[char_code
];
588 bits
+= char_code
* glyph_bytes(pf
, pf
->maxwidth
);
594 static void glyph_file_write(void* data
)
596 struct font_cache_entry
* p
= data
;
597 struct font
* pf
= &font_ui
;
599 unsigned char tmp
[2];
601 if ( p
->_char_code
== 0xffff )
604 ch
= p
->_char_code
+ pf
->firstchar
;
606 if ( cache_fd
>= 0) {
609 if (write(cache_fd
, tmp
, 2) != 2) {
617 /* save the char codes of the loaded glyphs to a file */
618 void glyph_cache_save(struct font
* pf
)
622 if (pf
->fd
>= 0 && pf
== &font_ui
)
624 cache_fd
= open(GLYPH_CACHE_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
628 lru_traverse(&pf
->cache
._lru
, glyph_file_write
);
639 int font_glyphs_to_bufsize(const char *path
, int glyphs
)
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
);
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
) )
663 bufsize
= LRU_SLOT_OVERHEAD
+ sizeof(struct font_cache_entry
) +
664 sizeof( unsigned short);
665 bufsize
+= glyph_bytes(&f
, f
.maxwidth
);
667 if ( bufsize
< FONT_HEADER_SIZE
)
668 bufsize
= FONT_HEADER_SIZE
;
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
)
683 unsigned char tmp
[2];
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
);
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
);
706 read( fd
, tmp
, 2 ) == 2 && size
< sort_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),
717 /* load font bitmaps */
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
)
735 /* load latin1 chars into cache */
736 for ( ch
= 32 ; ch
< 256 && ch
< pf
->cache
._capacity
+ 32; ch
++ )
737 font_get_bits(pf
, ch
);
742 #else /* BOOTLOADER */
749 * Bootloader only supports the built-in sysfont.
751 struct font
* font_get(int font
)
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
));
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
);
798 for (str
= utf8decode(str
, &ch
); ch
!= 0 ; str
= utf8decode(str
, &ch
))
800 if (is_diacritic(ch
, NULL
))
803 /* get proportional width and glyph bits*/
804 width
+= font_get_width(pf
,ch
);
813 /* -----------------------------------------------------------------
814 * vim: et sw=4 ts=8 sts=4 tw=78