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
, int maxwidth
, int height
);
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 void font_reset(struct font
*pf
)
137 unsigned char* buffer
= NULL
;
143 buffer
= pf
->buffer_start
;
144 buf_size
= pf
->buffer_size
;
146 memset(pf
, 0, sizeof(struct font
));
150 pf
->buffer_start
= buffer
;
151 pf
->buffer_size
= buf_size
;
155 static struct font
* font_load_header(struct font
*pf
)
157 /* Check we have enough data */
161 /* read magic and version #*/
162 if (memcmp(pf
->buffer_position
, VERSION
, 4) != 0)
165 pf
->buffer_position
+= 4;
168 pf
->maxwidth
= readshort(pf
);
169 pf
->height
= readshort(pf
);
170 pf
->ascent
= readshort(pf
);
171 pf
->buffer_position
+= 2; /* Skip padding */
172 pf
->firstchar
= readlong(pf
);
173 pf
->defaultchar
= readlong(pf
);
174 pf
->size
= readlong(pf
);
176 /* get variable font data sizes*/
177 /* # words of bitmap_t*/
178 pf
->bits_size
= readlong(pf
);
182 /* Load memory font */
183 static struct font
* font_load_in_memory(struct font
* pf
)
185 int32_t i
, noffset
, nwidth
;
190 /* # longs of offset*/
191 noffset
= readlong(pf
);
193 /* # bytes of width*/
194 nwidth
= readlong(pf
);
196 /* variable font data*/
197 pf
->bits
= (unsigned char *)pf
->buffer_position
;
198 pf
->buffer_position
+= pf
->bits_size
*sizeof(unsigned char);
200 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
202 /* pad to 16-bit boundary */
203 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 1) & ~1);
207 /* pad to 32-bit boundary*/
208 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
213 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
216 pf
->offset
= (uint16_t*)pf
->buffer_position
;
218 /* Check we have sufficient buffer */
219 if (!HAVEBYTES(noffset
* sizeof(uint16_t)))
222 for (i
=0; i
<noffset
; ++i
)
224 ((uint16_t*)(pf
->offset
))[i
] = (uint16_t)readshort(pf
);
230 pf
->offset
= (uint16_t*)pf
->buffer_position
;
232 /* Check we have sufficient buffer */
233 if (!HAVEBYTES(noffset
* sizeof(int32_t)))
236 for (i
=0; i
<noffset
; ++i
)
238 ((uint32_t*)(pf
->offset
))[i
] = (uint32_t)readlong(pf
);
246 pf
->width
= (unsigned char *)pf
->buffer_position
;
247 pf
->buffer_position
+= nwidth
*sizeof(unsigned char);
252 if (pf
->buffer_position
> pf
->buffer_end
)
255 return pf
; /* success!*/
258 /* Load cached font */
259 static struct font
* font_load_cached(struct font
* pf
)
261 uint32_t noffset
, nwidth
;
262 unsigned char* oldfileptr
= pf
->buffer_position
;
264 if (!HAVEBYTES(2 * sizeof(int32_t)))
267 /* # longs of offset*/
268 noffset
= readlong(pf
);
270 /* # bytes of width*/
271 nwidth
= readlong(pf
);
273 /* We are now at the bitmap data, this is fixed at 36.. */
276 /* Calculate offset to offset data */
277 pf
->buffer_position
+= pf
->bits_size
* sizeof(unsigned char);
279 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
282 /* pad to 16-bit boundary */
283 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 1) & ~1);
288 /* pad to 32-bit boundary*/
289 pf
->buffer_position
= (unsigned char *)(((intptr_t)pf
->buffer_position
+ 3) & ~3);
293 pf
->file_offset_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
295 pf
->file_offset_offset
= 0;
297 /* Calculate offset to widths data */
298 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
299 pf
->buffer_position
+= noffset
* sizeof(uint16_t);
301 pf
->buffer_position
+= noffset
* sizeof(uint32_t);
304 pf
->file_width_offset
= (uint32_t)(pf
->buffer_position
- pf
->buffer_start
);
306 pf
->file_width_offset
= 0;
308 pf
->buffer_position
= oldfileptr
;
310 /* Create the cache */
311 cache_create(pf
, pf
->maxwidth
, pf
->height
);
316 static bool internal_load_font(struct font
* pf
, const char *path
,
317 char *buf
, size_t buf_size
)
321 /* save loaded glyphs */
322 glyph_cache_save(pf
);
323 /* Close font file handle */
329 /* open and read entire font file*/
330 pf
->fd
= open(path
, O_RDONLY
|O_BINARY
);
333 DEBUGF("Can't open font: %s\n", path
);
337 /* Check file size */
338 size
= filesize(pf
->fd
);
339 pf
->buffer_start
= buf
;
340 pf
->buffer_size
= buf_size
;
342 pf
->buffer_position
= buf
;
344 if (size
> pf
->buffer_size
)
346 read(pf
->fd
, pf
->buffer_position
, FONT_HEADER_SIZE
);
347 pf
->buffer_end
= pf
->buffer_position
+ FONT_HEADER_SIZE
;
349 if (!font_load_header(pf
))
351 DEBUGF("Failed font header load");
357 if (!font_load_cached(pf
))
359 DEBUGF("Failed font cache load");
365 glyph_cache_load(pf
);
369 read(pf
->fd
, pf
->buffer_position
, pf
->buffer_size
);
370 pf
->buffer_end
= pf
->buffer_position
+ size
;
374 if (!font_load_header(pf
))
376 DEBUGF("Failed font header load");
380 if (!font_load_in_memory(pf
))
382 DEBUGF("Failed mem load");
389 #ifdef HAVE_REMOTE_LCD
390 /* Load a font into the special remote ui font slot */
391 int font_load_remoteui(const char* path
)
393 struct font
* pf
= &remote_font_ui
;
396 if (sysfonts
[FONT_UI_REMOTE
] && sysfonts
[FONT_UI_REMOTE
] != sysfonts
[FONT_UI
])
397 font_unload(FONT_UI_REMOTE
);
398 sysfonts
[FONT_UI_REMOTE
] = NULL
;
401 if (!internal_load_font(pf
, path
, remote_buf
, REMOTE_FONT_SIZE
))
403 sysfonts
[FONT_UI_REMOTE
] = NULL
;
407 sysfonts
[FONT_UI_REMOTE
] = pf
;
408 return FONT_UI_REMOTE
;
412 /* read and load font into incore font structure,
413 * returns the font number on success, -1 on failure */
414 int font_load(struct font
* pf
, const char *path
)
426 for (font_id
= SYSTEMFONTCOUNT
; font_id
< MAXFONTS
; font_id
++)
428 if (sysfonts
[font_id
] == NULL
)
431 if (font_id
== MAXFONTS
)
432 return -1; /* too many fonts */
435 if (font_id
== FONT_UI
)
437 /* currently, font loading replaces earlier font allocation*/
438 buffer
= (unsigned char *)(((intptr_t)main_buf
+ 3) & ~3);
439 buffer_size
= MAX_FONT_SIZE
;
443 buffer
= pf
->buffer_start
;
444 buffer_size
= pf
->buffer_size
;
447 if (!internal_load_font(pf
, path
, buffer
, buffer_size
))
450 sysfonts
[font_id
] = pf
;
451 return font_id
; /* success!*/
454 void font_unload(int font_id
)
456 struct font
* pf
= sysfonts
[font_id
];
457 if (font_id
>= SYSTEMFONTCOUNT
&& pf
)
461 sysfonts
[font_id
] = NULL
;
466 * Return a pointer to an incore font structure.
467 * If the requested font isn't loaded/compiled-in,
468 * decrement the font number and try again.
470 struct font
* font_get(int font
)
476 if (pf
&& pf
->height
)
484 * Reads an entry into cache entry
487 load_cache_entry(struct font_cache_entry
* p
, void* callback_data
)
489 struct font
* pf
= callback_data
;
490 unsigned short char_code
= p
->_char_code
;
491 unsigned char tmp
[2];
493 if (pf
->file_width_offset
)
495 int width_offset
= pf
->file_width_offset
+ char_code
;
496 lseek(pf
->fd
, width_offset
, SEEK_SET
);
497 read(pf
->fd
, &(p
->width
), 1);
501 p
->width
= pf
->maxwidth
;
504 int32_t bitmap_offset
= 0;
506 if (pf
->file_offset_offset
)
508 int32_t offset
= pf
->file_offset_offset
+ char_code
* (pf
->long_offset
? sizeof(int32_t) : sizeof(int16_t));
509 lseek(pf
->fd
, offset
, SEEK_SET
);
510 read (pf
->fd
, tmp
, 2);
511 bitmap_offset
= tmp
[0] | (tmp
[1] << 8);
512 if (pf
->long_offset
) {
513 read (pf
->fd
, tmp
, 2);
514 bitmap_offset
|= (tmp
[0] << 16) | (tmp
[1] << 24);
519 bitmap_offset
= ((pf
->height
+ 7) / 8) * p
->width
* char_code
;
522 int32_t file_offset
= FONT_HEADER_SIZE
+ bitmap_offset
;
523 lseek(pf
->fd
, file_offset
, SEEK_SET
);
525 int src_bytes
= p
->width
* ((pf
->height
+ 7) / 8);
526 read(pf
->fd
, p
->bitmap
, src_bytes
);
530 * Converts cbuf into a font cache
532 static void cache_create(struct font
* pf
, int maxwidth
, int height
)
534 /* maximum size of rotated bitmap */
535 int bitmap_size
= maxwidth
* ((height
+ 7) / 8);
537 /* Initialise cache */
538 font_cache_create(&pf
->cache
, pf
->buffer_start
, pf
->buffer_size
, bitmap_size
);
542 * Returns width of character
544 int font_get_width(struct font
* pf
, unsigned short char_code
)
546 /* check input range*/
547 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
548 char_code
= pf
->defaultchar
;
549 char_code
-= pf
->firstchar
;
551 return (pf
->fd
>= 0 && pf
!= &sysfont
)?
552 font_cache_get(&pf
->cache
,char_code
,load_cache_entry
,pf
)->width
:
553 pf
->width
? pf
->width
[char_code
]: pf
->maxwidth
;
556 const unsigned char* font_get_bits(struct font
* pf
, unsigned short char_code
)
558 const unsigned char* bits
;
560 /* check input range*/
561 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
562 char_code
= pf
->defaultchar
;
563 char_code
-= pf
->firstchar
;
565 if (pf
->fd
>= 0 && pf
!= &sysfont
)
568 (unsigned char*)font_cache_get(&pf
->cache
,char_code
,load_cache_entry
,pf
)->bitmap
;
575 if (pf
->bits_size
< MAX_FONTSIZE_FOR_16_BIT_OFFSETS
)
576 bits
+= ((uint16_t*)(pf
->offset
))[char_code
];
578 bits
+= ((uint32_t*)(pf
->offset
))[char_code
];
581 bits
+= ((pf
->height
+ 7) / 8) * pf
->maxwidth
* char_code
;
587 static void glyph_file_write(void* data
)
589 struct font_cache_entry
* p
= data
;
590 struct font
* pf
= &font_ui
;
592 unsigned char tmp
[2];
594 if ( p
->_char_code
== 0xffff )
597 ch
= p
->_char_code
+ pf
->firstchar
;
599 if ( cache_fd
>= 0) {
602 if (write(cache_fd
, tmp
, 2) != 2) {
610 /* save the char codes of the loaded glyphs to a file */
611 void glyph_cache_save(struct font
* pf
)
615 if (pf
->fd
>= 0 && pf
== &font_ui
)
617 cache_fd
= open(GLYPH_CACHE_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
621 lru_traverse(&pf
->cache
._lru
, glyph_file_write
);
632 int font_glyphs_to_bufsize(const char *path
, int glyphs
)
636 char buf
[FONT_HEADER_SIZE
];
638 f
.buffer_start
= buf
;
639 f
.buffer_size
= sizeof(buf
);
640 f
.buffer_position
= buf
;
642 f
.fd
= open(path
, O_RDONLY
|O_BINARY
);
646 read(f
.fd
, f
.buffer_position
, FONT_HEADER_SIZE
);
647 f
.buffer_end
= f
.buffer_position
+ FONT_HEADER_SIZE
;
649 if( !font_load_header(&f
) )
656 bufsize
= LRU_SLOT_OVERHEAD
+ sizeof(struct font_cache_entry
) +
657 sizeof( unsigned short);
658 bufsize
+= f
.maxwidth
* ((f
.height
+ 7) / 8);
660 if ( bufsize
< FONT_HEADER_SIZE
)
661 bufsize
= FONT_HEADER_SIZE
;
665 static int ushortcmp(const void *a
, const void *b
)
667 return ((int)(*(unsigned short*)a
- *(unsigned short*)b
));
669 static void glyph_cache_load(struct font
* pf
)
676 unsigned char tmp
[2];
678 unsigned short glyphs
[MAX_SORT
];
679 unsigned short glyphs_lru_order
[MAX_SORT
];
680 int glyph_file_skip
=0, glyph_file_size
=0;
682 int sort_size
= pf
->cache
._capacity
;
683 if ( sort_size
> MAX_SORT
)
684 sort_size
= MAX_SORT
;
686 fd
= open(GLYPH_CACHE_FILE
, O_RDONLY
|O_BINARY
);
689 /* only read what fits */
690 glyph_file_size
= filesize( fd
);
691 if ( glyph_file_size
> 2*pf
->cache
._capacity
) {
692 glyph_file_skip
= glyph_file_size
- 2*pf
->cache
._capacity
;
693 lseek( fd
, glyph_file_skip
, SEEK_SET
);
699 read( fd
, tmp
, 2 ) == 2 && size
< sort_size
;
702 glyphs
[size
] = (tmp
[0] << 8) | tmp
[1];
703 glyphs_lru_order
[size
] = glyphs
[size
];
706 /* sort glyphs array to make sector cache happy */
707 qsort((void *)glyphs
, size
, sizeof(unsigned short),
710 /* load font bitmaps */
712 font_get_bits(pf
, glyphs
[i
]);
713 for ( i
= 1; i
< size
; i
++) {
714 if ( glyphs
[i
] != glyphs
[i
-1] )
715 font_get_bits(pf
, glyphs
[i
]);
718 /* redo to fix lru order */
719 for ( i
= 0; i
< size
; i
++)
720 font_get_bits(pf
, glyphs_lru_order
[i
]);
722 if ( size
< sort_size
)
728 /* load latin1 chars into cache */
729 for ( ch
= 32 ; ch
< 256 && ch
< pf
->cache
._capacity
+ 32; ch
++ )
730 font_get_bits(pf
, ch
);
735 #else /* BOOTLOADER */
742 * Bootloader only supports the built-in sysfont.
744 struct font
* font_get(int font
)
751 * Returns width of character
753 int font_get_width(struct font
* pf
, unsigned short char_code
)
755 /* check input range*/
756 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
757 char_code
= pf
->defaultchar
;
758 char_code
-= pf
->firstchar
;
760 return pf
->width
? pf
->width
[char_code
]: pf
->maxwidth
;
763 const unsigned char* font_get_bits(struct font
* pf
, unsigned short char_code
)
765 const unsigned char* bits
;
767 /* check input range*/
768 if (char_code
< pf
->firstchar
|| char_code
>= pf
->firstchar
+pf
->size
)
769 char_code
= pf
->defaultchar
;
770 char_code
-= pf
->firstchar
;
772 /* assume small font with uint16_t offsets*/
773 bits
= pf
->bits
+ (pf
->offset
?
774 ((uint16_t*)(pf
->offset
))[char_code
]:
775 (((pf
->height
+ 7) / 8) * pf
->maxwidth
* char_code
));
780 #endif /* BOOTLOADER */
783 * Returns the stringsize of a given string.
785 int font_getstringsize(const unsigned char *str
, int *w
, int *h
, int fontnumber
)
787 struct font
* pf
= font_get(fontnumber
);
791 for (str
= utf8decode(str
, &ch
); ch
!= 0 ; str
= utf8decode(str
, &ch
))
793 if (is_diacritic(ch
, NULL
))
796 /* get proportional width and glyph bits*/
797 width
+= font_get_width(pf
,ch
);
806 /* -----------------------------------------------------------------
807 * vim: et sw=4 ts=8 sts=4 tw=78