fix target id for HiFiMAN HM-801
[maemo-rb.git] / firmware / font.c
blobff5bc4b008a5fa1c19719d7664b55548229f5ba7
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 "system.h"
35 #include "font.h"
36 #include "file.h"
37 #include "core_alloc.h"
38 #include "debug.h"
39 #include "panic.h"
40 #include "rbunicode.h"
41 #include "diacritic.h"
42 #include "rbpaths.h"
44 #define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
46 /* max static loadable font buffer size */
47 #ifndef MAX_FONT_SIZE
48 #if LCD_HEIGHT > 64
49 #if MEMORYSIZE > 2
50 #define MAX_FONT_SIZE 60000
51 #else
52 #define MAX_FONT_SIZE 10000
53 #endif
54 #else
55 #define MAX_FONT_SIZE 4000
56 #endif
57 #endif
59 #ifndef FONT_HEADER_SIZE
60 #define FONT_HEADER_SIZE 36
61 #endif
63 #ifndef BOOTLOADER
64 /* Font cache includes */
65 #include "font_cache.h"
66 #include "lru.h"
67 #endif
69 #ifndef O_BINARY
70 #define O_BINARY 0
71 #endif
73 /* Define this to try loading /.rockbox/.glyphcache *
74 * when a font specific file fails. This requires the *
75 * user to copy and rename a font glyph cache file */
76 //#define TRY_DEFAULT_GLYPHCACHE
78 /* compiled-in font */
79 extern struct font sysfont;
81 #ifndef BOOTLOADER
83 struct buflib_alloc_data {
84 struct font font;
85 int handle_locks; /* is the buflib handle currently locked? */
86 int refcount; /* how many times has this font been loaded? */
87 unsigned char buffer[];
89 static int buflib_allocations[MAXFONTS];
91 static int cache_fd;
92 static struct font* cache_pf;
94 static int buflibmove_callback(int handle, void* current, void* new)
96 (void)handle;
97 struct buflib_alloc_data *alloc = (struct buflib_alloc_data*)current;
98 ptrdiff_t diff = new - current;
100 if (alloc->handle_locks > 0)
101 return BUFLIB_CB_CANNOT_MOVE;
103 #define UPDATE(x) if (x) { x = PTR_ADD(x, diff); }
105 UPDATE(alloc->font.bits);
106 UPDATE(alloc->font.offset);
107 UPDATE(alloc->font.width);
109 UPDATE(alloc->font.buffer_start);
110 UPDATE(alloc->font.buffer_end);
111 UPDATE(alloc->font.buffer_position);
113 UPDATE(alloc->font.cache._index);
114 UPDATE(alloc->font.cache._lru._base);
116 return BUFLIB_CB_OK;
118 static void lock_font_handle(int handle, bool lock)
120 struct buflib_alloc_data *alloc = core_get_data(handle);
121 if ( lock )
122 alloc->handle_locks++;
123 else
124 alloc->handle_locks--;
127 void font_lock(int font_id, bool lock)
129 if( font_id == FONT_SYSFIXED )
130 return;
131 if( buflib_allocations[font_id] >= 0 )
132 lock_font_handle(buflib_allocations[font_id], lock);
135 static struct buflib_callbacks buflibops = {buflibmove_callback, NULL };
137 static inline struct font *pf_from_handle(int handle)
139 struct buflib_alloc_data *alloc = core_get_data(handle);
140 struct font *pf = &alloc->font;
141 return pf;
144 static inline unsigned char *buffer_from_handle(int handle)
146 struct buflib_alloc_data *alloc = core_get_data(handle);
147 unsigned char* buffer = alloc->buffer;
148 return buffer;
151 /* Font cache structures */
152 static void cache_create(struct font* pf);
153 static void glyph_cache_load(int fond_id);
154 /* End Font cache structures */
156 void font_init(void)
158 int i = 0;
159 cache_fd = -1;
160 while (i<MAXFONTS)
161 buflib_allocations[i++] = -1;
164 /* Check if we have x bytes left in the file buffer */
165 #define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
167 /* Helper functions to read big-endian unaligned short or long from
168 the file buffer. Bounds-checking must be done in the calling
169 function.
172 static short readshort(struct font *pf)
174 unsigned short s;
176 s = *pf->buffer_position++ & 0xff;
177 s |= (*pf->buffer_position++ << 8);
178 return s;
181 static int32_t readlong(struct font *pf)
183 uint32_t l;
185 l = *pf->buffer_position++ & 0xff;
186 l |= *pf->buffer_position++ << 8;
187 l |= ((uint32_t)(*pf->buffer_position++)) << 16;
188 l |= ((uint32_t)(*pf->buffer_position++)) << 24;
189 return l;
192 static int glyph_bytes( struct font *pf, int width )
194 int ret;
195 if (pf->depth)
196 ret = ( pf->height * width + 1 ) / 2;
197 else
198 ret = width * ((pf->height + 7) / 8);
199 return (ret + 1) & ~1;
202 static struct font* font_load_header(struct font *pf)
204 /* Check we have enough data */
205 if (!HAVEBYTES(28))
206 return NULL;
208 /* read magic and version #*/
209 if (memcmp(pf->buffer_position, VERSION, 4) != 0)
210 return NULL;
212 pf->buffer_position += 4;
214 /* font info*/
215 pf->maxwidth = readshort(pf);
216 pf->height = readshort(pf);
217 pf->ascent = readshort(pf);
218 pf->depth = readshort(pf);
219 pf->firstchar = readlong(pf);
220 pf->defaultchar = readlong(pf);
221 pf->size = readlong(pf);
223 /* get variable font data sizes*/
224 /* # words of bitmap_t*/
225 pf->bits_size = readlong(pf);
227 return pf;
229 /* Load memory font */
230 static struct font* font_load_in_memory(struct font* pf)
232 int32_t i, noffset, nwidth;
234 if (!HAVEBYTES(4))
235 return NULL;
237 /* # longs of offset*/
238 noffset = readlong(pf);
240 /* # bytes of width*/
241 nwidth = readlong(pf);
243 /* variable font data*/
244 pf->bits = (unsigned char *)pf->buffer_position;
245 pf->buffer_position += pf->bits_size*sizeof(unsigned char);
247 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
249 /* pad to 16-bit boundary */
250 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
252 else
254 /* pad to 32-bit boundary*/
255 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
258 if (noffset)
260 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
262 pf->long_offset = 0;
263 pf->offset = (uint16_t*)pf->buffer_position;
265 /* Check we have sufficient buffer */
266 if (!HAVEBYTES(noffset * sizeof(uint16_t)))
267 return NULL;
269 for (i=0; i<noffset; ++i)
271 ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
274 else
276 pf->long_offset = 1;
277 pf->offset = (uint16_t*)pf->buffer_position;
279 /* Check we have sufficient buffer */
280 if (!HAVEBYTES(noffset * sizeof(int32_t)))
281 return NULL;
283 for (i=0; i<noffset; ++i)
285 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
289 else
290 pf->offset = NULL;
292 if (nwidth) {
293 pf->width = (unsigned char *)pf->buffer_position;
294 pf->buffer_position += nwidth*sizeof(unsigned char);
296 else
297 pf->width = NULL;
299 if (pf->buffer_position > pf->buffer_end)
300 return NULL;
302 return pf; /* success!*/
305 /* Load cached font */
306 static struct font* font_load_cached(struct font* pf)
308 uint32_t noffset, nwidth;
309 unsigned char* oldfileptr = pf->buffer_position;
311 if (!HAVEBYTES(2 * sizeof(int32_t)))
312 return NULL;
314 /* # longs of offset*/
315 noffset = readlong(pf);
317 /* # bytes of width*/
318 nwidth = readlong(pf);
320 /* We are now at the bitmap data, this is fixed at 36.. */
321 pf->bits = NULL;
323 /* Calculate offset to offset data */
324 pf->buffer_position += pf->bits_size * sizeof(unsigned char);
326 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
328 pf->long_offset = 0;
329 /* pad to 16-bit boundary */
330 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
332 else
334 pf->long_offset = 1;
335 /* pad to 32-bit boundary*/
336 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
339 if (noffset)
340 pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
341 else
342 pf->file_offset_offset = 0;
344 /* Calculate offset to widths data */
345 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
346 pf->buffer_position += noffset * sizeof(uint16_t);
347 else
348 pf->buffer_position += noffset * sizeof(uint32_t);
350 if (nwidth)
351 pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
352 else
353 pf->file_width_offset = 0;
355 pf->buffer_position = oldfileptr;
357 /* Create the cache */
358 cache_create(pf);
360 return pf;
363 static bool internal_load_font(int font_id, const char *path, char *buf,
364 size_t buf_size, int handle)
366 size_t size;
367 struct font* pf = pf_from_handle(handle);
369 /* open and read entire font file*/
370 pf->fd = open(path, O_RDONLY|O_BINARY);
372 if (pf->fd < 0) {
373 DEBUGF("Can't open font: %s\n", path);
374 return false;
377 /* Check file size */
378 size = filesize(pf->fd);
379 pf->buffer_start = buf;
380 pf->buffer_size = buf_size;
382 pf->buffer_position = buf;
384 if (size > pf->buffer_size)
386 read(pf->fd, pf->buffer_position, FONT_HEADER_SIZE);
387 pf->buffer_end = pf->buffer_position + FONT_HEADER_SIZE;
389 if (!font_load_header(pf))
391 DEBUGF("Failed font header load");
392 close(pf->fd);
393 pf->fd = -1;
394 return false;
397 if (!font_load_cached(pf))
399 DEBUGF("Failed font cache load");
400 close(pf->fd);
401 pf->fd = -1;
402 return false;
405 /* Cheat to get sector cache for different parts of font *
406 * file while preloading glyphs. Without this the disk head *
407 * thrashes between the width, offset, and bitmap data *
408 * in glyph_cache_load(). */
409 pf->fd_width = open(path, O_RDONLY|O_BINARY);
410 pf->fd_offset = open(path, O_RDONLY|O_BINARY);
412 glyph_cache_load(font_id);
414 if(pf->fd_width >= 0)
415 close(pf->fd_width);
416 pf->fd_width = -1;
418 if(pf->fd_offset >= 0)
419 close(pf->fd_offset);
420 pf->fd_offset = -1;
422 else
424 read(pf->fd, pf->buffer_position, pf->buffer_size);
425 pf->buffer_end = pf->buffer_position + size;
426 close(pf->fd);
427 pf->fd = -1;
428 pf->fd_width = -1;
429 pf->fd_offset = -1;
431 if (!font_load_header(pf))
433 DEBUGF("Failed font header load");
434 return false;
437 if (!font_load_in_memory(pf))
439 DEBUGF("Failed mem load");
440 return false;
443 return true;
446 static int find_font_index(const char* path)
448 int index = 0, handle;
450 while (index < MAXFONTS)
452 handle = buflib_allocations[index];
453 if (handle > 0 && !strcmp(core_get_name(handle), path))
454 return index;
455 index++;
457 return FONT_SYSFIXED;
460 static int alloc_and_init(int font_idx, const char* name, size_t size)
462 int *phandle = &buflib_allocations[font_idx];
463 int handle = *phandle;
464 struct buflib_alloc_data *pdata;
465 struct font *pf;
466 size_t alloc_size = size + sizeof(struct buflib_alloc_data);
467 if (handle > 0)
468 return handle;
469 *phandle = core_alloc_ex(name, alloc_size, &buflibops);
470 handle = *phandle;
471 if (handle < 0)
472 return handle;
473 pdata = core_get_data(handle);
474 pf = &pdata->font;
475 pdata->handle_locks = 0;
476 pdata->refcount = 1;
477 pf->buffer_position = pf->buffer_start = buffer_from_handle(handle);
478 pf->buffer_size = size;
479 pf->fd_width = -1;
480 pf->fd_offset = -1;
481 return handle;
484 const char* font_filename(int font_id)
486 int handle = buflib_allocations[font_id];
487 if (handle > 0)
488 return core_get_name(handle);
489 return NULL;
492 /* read and load font into incore font structure,
493 * returns the font number on success, -1 on failure */
494 int font_load_ex(const char *path, size_t buffer_size)
496 int font_id = find_font_index(path);
497 char *buffer;
498 int handle;
500 if (font_id > FONT_SYSFIXED)
502 /* already loaded, no need to reload */
503 struct buflib_alloc_data *pd = core_get_data(buflib_allocations[font_id]);
504 if (pd->font.buffer_size < buffer_size)
506 int old_refcount, old_id;
507 /* reload the font:
508 * 1) save of refcont and id
509 * 2) force unload (set refcount to 1 to make sure it get unloaded)
510 * 3) reload with the larger buffer
511 * 4) restore the id and refcount
513 old_id = font_id;
514 old_refcount = pd->refcount;
515 pd->refcount = 1;
516 font_unload(font_id);
517 font_id = font_load_ex(path, buffer_size);
518 if (font_id < 0)
520 // not much we can do here, maybe try reloading with the small buffer again
521 return -1;
523 if (old_id != font_id)
525 buflib_allocations[old_id] = buflib_allocations[font_id];
526 buflib_allocations[font_id] = -1;
527 font_id = old_id;
529 pd = core_get_data(buflib_allocations[font_id]);
530 pd->refcount = old_refcount;
532 pd->refcount++;
533 //printf("reusing handle %d for %s (count: %d)\n", font_id, path, pd->refcount);
534 return font_id;
537 for (font_id = FONT_FIRSTUSERFONT; font_id < MAXFONTS; font_id++)
539 handle = buflib_allocations[font_id];
540 if (handle < 0)
542 break;
545 handle = alloc_and_init(font_id, path, buffer_size);
546 if (handle < 0)
547 return -1;
549 buffer = buffer_from_handle(handle);
550 lock_font_handle(handle, true);
552 if (!internal_load_font(font_id, path, buffer, buffer_size, handle))
554 lock_font_handle(handle, false);
555 core_free(handle);
556 buflib_allocations[font_id] = -1;
557 return -1;
560 lock_font_handle(handle, false);
561 buflib_allocations[font_id] = handle;
562 //printf("%s -> [%d] -> %d\n", path, font_id, *handle);
563 return font_id; /* success!*/
565 int font_load(const char *path)
567 int size;
568 int fd = open( path, O_RDONLY );
569 if ( fd < 0 )
570 return -1;
571 size = filesize(fd);
572 if (size > MAX_FONT_SIZE)
573 size = MAX_FONT_SIZE;
574 close(fd);
575 return font_load_ex(path, size);
578 void font_unload(int font_id)
580 if ( font_id == FONT_SYSFIXED )
581 return;
582 int handle = buflib_allocations[font_id];
583 if ( handle < 0 )
584 return;
585 struct buflib_alloc_data *pdata = core_get_data(handle);
586 struct font* pf = &pdata->font;
587 pdata->refcount--;
588 if (pdata->refcount < 1)
590 //printf("freeing id: %d %s\n", font_id, core_get_name(*handle));
591 if (pf && pf->fd >= 0)
593 glyph_cache_save(font_id);
594 close(pf->fd);
596 if (handle > 0)
597 core_free(handle);
598 buflib_allocations[font_id] = -1;
603 void font_unload_all(void)
605 int i;
606 for (i=0; i<MAXFONTS; i++)
608 if (buflib_allocations[i] > 0)
610 struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[i]);
611 alloc->refcount = 1; /* force unload */
612 font_unload(i);
618 * Return a pointer to an incore font structure.
619 * If the requested font isn't loaded/compiled-in,
620 * decrement the font number and try again.
622 struct font* font_get(int font)
624 struct font* pf;
625 if (font == FONT_UI)
626 font = MAXFONTS-1;
627 if (font <= FONT_SYSFIXED)
628 return &sysfont;
630 while (1) {
631 if (buflib_allocations[font] > 0)
633 struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[font]);
634 pf = &alloc->font;
635 if (pf && pf->height)
636 return pf;
638 if (--font < 0)
639 return &sysfont;
643 static int pf_to_handle(struct font* pf)
645 int i;
646 for (i=0; i<MAXFONTS; i++)
648 int handle = buflib_allocations[i];
649 if (handle > 0)
651 struct buflib_alloc_data *pdata = core_get_data(handle);
652 if (pf == &pdata->font)
653 return handle;
656 return -1;
660 * Reads an entry into cache entry
662 static void
663 load_cache_entry(struct font_cache_entry* p, void* callback_data)
665 struct font* pf = callback_data;
666 int handle = pf_to_handle(pf);
667 unsigned short char_code = p->_char_code;
668 unsigned char tmp[2];
669 int fd;
671 if (handle > 0)
672 lock_font_handle(handle, true);
673 if (pf->file_width_offset)
675 int width_offset = pf->file_width_offset + char_code;
676 /* load via different fd to get this file section cached */
677 if(pf->fd_width >=0 )
678 fd = pf->fd_width;
679 else
680 fd = pf->fd;
681 lseek(fd, width_offset, SEEK_SET);
682 read(fd, &(p->width), 1);
684 else
686 p->width = pf->maxwidth;
689 int32_t bitmap_offset = 0;
691 if (pf->file_offset_offset)
693 int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
694 /* load via different fd to get this file section cached */
695 if(pf->fd_offset >=0 )
696 fd = pf->fd_offset;
697 else
698 fd = pf->fd;
699 lseek(fd, offset, SEEK_SET);
700 read (fd, tmp, 2);
701 bitmap_offset = tmp[0] | (tmp[1] << 8);
702 if (pf->long_offset) {
703 read (fd, tmp, 2);
704 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
707 else
709 bitmap_offset = char_code * glyph_bytes(pf, p->width);
712 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
713 lseek(pf->fd, file_offset, SEEK_SET);
714 int src_bytes = glyph_bytes(pf, p->width);
715 read(pf->fd, p->bitmap, src_bytes);
717 if (handle > 0)
718 lock_font_handle(handle, false);
722 * Converts cbuf into a font cache
724 static void cache_create(struct font* pf)
726 /* maximum size of rotated bitmap */
727 int bitmap_size = glyph_bytes( pf, pf->maxwidth);
729 /* Initialise cache */
730 font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
734 * Returns width of character
736 int font_get_width(struct font* pf, unsigned short char_code)
738 /* check input range*/
739 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
740 char_code = pf->defaultchar;
741 char_code -= pf->firstchar;
743 return (pf->fd >= 0 && pf != &sysfont)?
744 font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
745 pf->width? pf->width[char_code]: pf->maxwidth;
748 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
750 const unsigned char* bits;
752 /* check input range*/
753 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
754 char_code = pf->defaultchar;
755 char_code -= pf->firstchar;
757 if (pf->fd >= 0 && pf != &sysfont)
759 bits =
760 (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry, pf)->bitmap;
762 else
764 bits = pf->bits;
765 if (pf->offset)
767 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
768 bits += ((uint16_t*)(pf->offset))[char_code];
769 else
770 bits += ((uint32_t*)(pf->offset))[char_code];
772 else
773 bits += char_code * glyph_bytes(pf, pf->maxwidth);
776 return bits;
779 static void font_path_to_glyph_path( const char *font_path, char *glyph_path)
781 /* take full file name, cut extension, and add .glyphcache */
782 strlcpy(glyph_path, font_path, MAX_PATH);
783 glyph_path[strlen(glyph_path)-4] = '\0';
784 strcat(glyph_path, ".gc");
787 /* call with NULL to flush */
788 static void glyph_file_write(void* data)
790 struct font_cache_entry* p = data;
791 struct font* pf = cache_pf;
792 unsigned short ch;
793 static int buffer_pos = 0;
794 #define WRITE_BUFFER 256
795 static unsigned char buffer[WRITE_BUFFER];
797 /* flush buffer & reset */
798 if ( data == NULL || buffer_pos >= WRITE_BUFFER)
800 write(cache_fd, buffer, buffer_pos);
801 buffer_pos = 0;
802 if ( data == NULL )
803 return;
805 if ( p->_char_code == 0xffff )
806 return;
808 ch = p->_char_code + pf->firstchar;
809 buffer[buffer_pos] = ch >> 8;
810 buffer[buffer_pos+1] = ch & 0xff;
811 buffer_pos += 2;
812 return;
815 /* save the char codes of the loaded glyphs to a file */
816 void glyph_cache_save(int font_id)
818 int fd;
820 if( font_id < 0 )
821 return;
822 int handle = buflib_allocations[font_id];
823 if ( handle < 0 )
824 return;
826 struct font *pf = pf_from_handle(handle);
827 if(pf && pf->fd >= 0)
829 /* FIXME: This sleep should not be necessary but without it *
830 * unloading multiple fonts and saving glyphcache files *
831 * quickly in succession creates multiple glyphcache files *
832 * with the same name. */
833 sleep(HZ/10);
834 char filename[MAX_PATH];
835 font_path_to_glyph_path(font_filename(font_id), filename);
836 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
837 if (fd < 0)
838 return;
840 cache_pf = pf;
841 cache_fd = fd;
842 lru_traverse(&cache_pf->cache._lru, glyph_file_write);
843 glyph_file_write(NULL);
844 if (cache_fd >= 0)
846 close(cache_fd);
847 cache_fd = -1;
850 return;
853 int font_glyphs_to_bufsize(const char *path, int glyphs)
855 struct font f;
856 int bufsize;
857 char buf[FONT_HEADER_SIZE];
859 f.buffer_start = buf;
860 f.buffer_size = sizeof(buf);
861 f.buffer_position = buf;
863 f.fd = open(path, O_RDONLY|O_BINARY);
864 if(f.fd < 0)
865 return 0;
867 read(f.fd, f.buffer_position, FONT_HEADER_SIZE);
868 f.buffer_end = f.buffer_position + FONT_HEADER_SIZE;
870 if( !font_load_header(&f) )
872 close(f.fd);
873 return 0;
875 close(f.fd);
877 bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) +
878 sizeof( unsigned short);
879 bufsize += glyph_bytes(&f, f.maxwidth);
880 bufsize *= glyphs;
881 if ( bufsize < FONT_HEADER_SIZE )
882 bufsize = FONT_HEADER_SIZE;
883 return bufsize;
886 static int ushortcmp(const void *a, const void *b)
888 return ((int)(*(unsigned short*)a - *(unsigned short*)b));
890 static void glyph_cache_load(int font_id)
892 int handle = buflib_allocations[font_id];
893 if (handle < 0)
894 return;
895 struct font *pf = pf_from_handle(handle);
896 #define MAX_SORT 256
897 if (pf->fd >= 0) {
898 int i, size, fd;
899 unsigned char tmp[2];
900 unsigned short ch;
901 unsigned short glyphs[MAX_SORT];
902 unsigned short glyphs_lru_order[MAX_SORT];
903 int glyph_file_skip=0, glyph_file_size=0;
905 int sort_size = pf->cache._capacity;
906 if ( sort_size > MAX_SORT )
907 sort_size = MAX_SORT;
909 char filename[MAX_PATH];
910 font_path_to_glyph_path(font_filename(font_id), filename);
912 fd = open(filename, O_RDONLY|O_BINARY);
913 #ifdef TRY_DEFAULT_GLYPHCACHE
914 /* if font specific file fails, try default */
915 if (fd < 0)
916 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
917 #endif
918 if (fd >= 0) {
919 /* only read what fits */
920 glyph_file_size = filesize( fd );
921 if ( glyph_file_size > 2*pf->cache._capacity ) {
922 glyph_file_skip = glyph_file_size - 2*pf->cache._capacity;
923 lseek( fd, glyph_file_skip, SEEK_SET );
926 while(1) {
928 for ( size = 0;
929 read( fd, tmp, 2 ) == 2 && size < sort_size;
930 size++ )
932 glyphs[size] = (tmp[0] << 8) | tmp[1];
933 glyphs_lru_order[size] = glyphs[size];
936 /* sort glyphs array to make sector cache happy */
937 qsort((void *)glyphs, size, sizeof(unsigned short),
938 ushortcmp );
940 /* load font bitmaps */
941 for( i = 0; i < size ; i++ )
942 font_get_bits(pf, glyphs[i]);
944 /* redo to fix lru order */
945 for ( i = 0; i < size ; i++)
946 font_get_bits(pf, glyphs_lru_order[i]);
948 if ( size < sort_size )
949 break;
952 close(fd);
953 } else {
954 /* load latin1 chars into cache */
955 for ( ch = 32 ; ch < 256 && ch < pf->cache._capacity + 32; ch++ )
956 font_get_bits(pf, ch);
959 return;
961 #else /* BOOTLOADER */
963 void font_init(void)
967 void font_lock(int font_id, bool lock)
969 (void)font_id;
970 (void)lock;
974 * Bootloader only supports the built-in sysfont.
976 struct font* font_get(int font)
978 (void)font;
979 return &sysfont;
983 * Returns width of character
985 int font_get_width(struct font* pf, unsigned short char_code)
987 /* check input range*/
988 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
989 char_code = pf->defaultchar;
990 char_code -= pf->firstchar;
992 return pf->width? pf->width[char_code]: pf->maxwidth;
995 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
997 const unsigned char* bits;
999 /* check input range*/
1000 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
1001 char_code = pf->defaultchar;
1002 char_code -= pf->firstchar;
1004 /* assume small font with uint16_t offsets*/
1005 bits = pf->bits + (pf->offset?
1006 ((uint16_t*)(pf->offset))[char_code]:
1007 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
1009 return bits;
1012 #endif /* BOOTLOADER */
1015 * Returns the stringsize of a given string.
1017 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
1019 struct font* pf = font_get(fontnumber);
1020 unsigned short ch;
1021 int width = 0;
1023 font_lock( fontnumber, true );
1024 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
1026 if (is_diacritic(ch, NULL))
1027 continue;
1029 /* get proportional width and glyph bits*/
1030 width += font_get_width(pf,ch);
1032 if ( w )
1033 *w = width;
1034 if ( h )
1035 *h = pf->height;
1036 font_lock( fontnumber, false );
1037 return width;
1040 /* -----------------------------------------------------------------
1041 * vim: et sw=4 ts=8 sts=4 tw=78