Fix playlist catalog directory manual spelling
[maemo-rb.git] / firmware / font.c
blobeb15bb7420e7c3354de90dfdef7916c3df1127a5
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 font_ui = -1;
92 static int cache_fd;
93 static struct font* cache_pf;
95 static int buflibmove_callback(int handle, void* current, void* new)
97 (void)handle;
98 struct buflib_alloc_data *alloc = (struct buflib_alloc_data*)current;
99 ptrdiff_t diff = new - current;
101 if (alloc->handle_locks > 0)
102 return BUFLIB_CB_CANNOT_MOVE;
104 #define UPDATE(x) if (x) { x = PTR_ADD(x, diff); }
106 UPDATE(alloc->font.bits);
107 UPDATE(alloc->font.offset);
108 UPDATE(alloc->font.width);
110 UPDATE(alloc->font.buffer_start);
111 UPDATE(alloc->font.buffer_end);
112 UPDATE(alloc->font.buffer_position);
114 UPDATE(alloc->font.cache._index);
115 UPDATE(alloc->font.cache._lru._base);
117 return BUFLIB_CB_OK;
119 static void lock_font_handle(int handle, bool lock)
121 struct buflib_alloc_data *alloc = core_get_data(handle);
122 if ( lock )
123 alloc->handle_locks++;
124 else
125 alloc->handle_locks--;
128 void font_lock(int font_id, bool lock)
130 if( font_id == FONT_SYSFIXED )
131 return;
132 if( buflib_allocations[font_id] >= 0 )
133 lock_font_handle(buflib_allocations[font_id], lock);
136 static struct buflib_callbacks buflibops = {buflibmove_callback, NULL };
138 static inline struct font *pf_from_handle(int handle)
140 struct buflib_alloc_data *alloc = core_get_data(handle);
141 struct font *pf = &alloc->font;
142 return pf;
145 static inline unsigned char *buffer_from_handle(int handle)
147 struct buflib_alloc_data *alloc = core_get_data(handle);
148 unsigned char* buffer = alloc->buffer;
149 return buffer;
152 /* Font cache structures */
153 static void cache_create(struct font* pf);
154 static void glyph_cache_load(int fond_id);
155 /* End Font cache structures */
157 void font_init(void)
159 int i = 0;
160 cache_fd = -1;
161 while (i<MAXFONTS)
162 buflib_allocations[i++] = -1;
165 /* Check if we have x bytes left in the file buffer */
166 #define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
168 /* Helper functions to read big-endian unaligned short or long from
169 the file buffer. Bounds-checking must be done in the calling
170 function.
173 static short readshort(struct font *pf)
175 unsigned short s;
177 s = *pf->buffer_position++ & 0xff;
178 s |= (*pf->buffer_position++ << 8);
179 return s;
182 static int32_t readlong(struct font *pf)
184 uint32_t l;
186 l = *pf->buffer_position++ & 0xff;
187 l |= *pf->buffer_position++ << 8;
188 l |= ((uint32_t)(*pf->buffer_position++)) << 16;
189 l |= ((uint32_t)(*pf->buffer_position++)) << 24;
190 return l;
193 static int glyph_bytes( struct font *pf, int width )
195 int ret;
196 if (pf->depth)
197 ret = ( pf->height * width + 1 ) / 2;
198 else
199 ret = width * ((pf->height + 7) / 8);
200 return (ret + 1) & ~1;
203 static struct font* font_load_header(struct font *pf)
205 /* Check we have enough data */
206 if (!HAVEBYTES(28))
207 return NULL;
209 /* read magic and version #*/
210 if (memcmp(pf->buffer_position, VERSION, 4) != 0)
211 return NULL;
213 pf->buffer_position += 4;
215 /* font info*/
216 pf->maxwidth = readshort(pf);
217 pf->height = readshort(pf);
218 pf->ascent = readshort(pf);
219 pf->depth = readshort(pf);
220 pf->firstchar = readlong(pf);
221 pf->defaultchar = readlong(pf);
222 pf->size = readlong(pf);
224 /* get variable font data sizes*/
225 /* # words of bitmap_t*/
226 pf->bits_size = readlong(pf);
228 return pf;
230 /* Load memory font */
231 static struct font* font_load_in_memory(struct font* pf)
233 int32_t i, noffset, nwidth;
235 if (!HAVEBYTES(4))
236 return NULL;
238 /* # longs of offset*/
239 noffset = readlong(pf);
241 /* # bytes of width*/
242 nwidth = readlong(pf);
244 /* variable font data*/
245 pf->bits = (unsigned char *)pf->buffer_position;
246 pf->buffer_position += pf->bits_size*sizeof(unsigned char);
248 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
250 /* pad to 16-bit boundary */
251 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
253 else
255 /* pad to 32-bit boundary*/
256 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
259 if (noffset)
261 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
263 pf->long_offset = 0;
264 pf->offset = (uint16_t*)pf->buffer_position;
266 /* Check we have sufficient buffer */
267 if (!HAVEBYTES(noffset * sizeof(uint16_t)))
268 return NULL;
270 for (i=0; i<noffset; ++i)
272 ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
275 else
277 pf->long_offset = 1;
278 pf->offset = (uint16_t*)pf->buffer_position;
280 /* Check we have sufficient buffer */
281 if (!HAVEBYTES(noffset * sizeof(int32_t)))
282 return NULL;
284 for (i=0; i<noffset; ++i)
286 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
290 else
291 pf->offset = NULL;
293 if (nwidth) {
294 pf->width = (unsigned char *)pf->buffer_position;
295 pf->buffer_position += nwidth*sizeof(unsigned char);
297 else
298 pf->width = NULL;
300 if (pf->buffer_position > pf->buffer_end)
301 return NULL;
303 return pf; /* success!*/
306 /* Load cached font */
307 static struct font* font_load_cached(struct font* pf)
309 uint32_t noffset, nwidth;
310 unsigned char* oldfileptr = pf->buffer_position;
312 if (!HAVEBYTES(2 * sizeof(int32_t)))
313 return NULL;
315 /* # longs of offset*/
316 noffset = readlong(pf);
318 /* # bytes of width*/
319 nwidth = readlong(pf);
321 /* We are now at the bitmap data, this is fixed at 36.. */
322 pf->bits = NULL;
324 /* Calculate offset to offset data */
325 pf->buffer_position += pf->bits_size * sizeof(unsigned char);
327 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
329 pf->long_offset = 0;
330 /* pad to 16-bit boundary */
331 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
333 else
335 pf->long_offset = 1;
336 /* pad to 32-bit boundary*/
337 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
340 if (noffset)
341 pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
342 else
343 pf->file_offset_offset = 0;
345 /* Calculate offset to widths data */
346 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
347 pf->buffer_position += noffset * sizeof(uint16_t);
348 else
349 pf->buffer_position += noffset * sizeof(uint32_t);
351 if (nwidth)
352 pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
353 else
354 pf->file_width_offset = 0;
356 pf->buffer_position = oldfileptr;
358 /* Create the cache */
359 cache_create(pf);
361 return pf;
364 static bool internal_load_font(int font_id, const char *path, char *buf,
365 size_t buf_size, int handle)
367 size_t size;
368 struct font* pf = pf_from_handle(handle);
370 /* open and read entire font file*/
371 pf->fd = open(path, O_RDONLY|O_BINARY);
373 if (pf->fd < 0) {
374 DEBUGF("Can't open font: %s\n", path);
375 return false;
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");
393 close(pf->fd);
394 pf->fd = -1;
395 return false;
398 if (!font_load_cached(pf))
400 DEBUGF("Failed font cache load");
401 close(pf->fd);
402 pf->fd = -1;
403 return false;
406 /* Cheat to get sector cache for different parts of font *
407 * file while preloading glyphs. Without this the disk head *
408 * thrashes between the width, offset, and bitmap data *
409 * in glyph_cache_load(). */
410 pf->fd_width = open(path, O_RDONLY|O_BINARY);
411 pf->fd_offset = open(path, O_RDONLY|O_BINARY);
413 glyph_cache_load(font_id);
415 if(pf->fd_width >= 0)
416 close(pf->fd_width);
417 pf->fd_width = -1;
419 if(pf->fd_offset >= 0)
420 close(pf->fd_offset);
421 pf->fd_offset = -1;
423 else
425 read(pf->fd, pf->buffer_position, pf->buffer_size);
426 pf->buffer_end = pf->buffer_position + size;
427 close(pf->fd);
428 pf->fd = -1;
429 pf->fd_width = -1;
430 pf->fd_offset = -1;
432 if (!font_load_header(pf))
434 DEBUGF("Failed font header load");
435 return false;
438 if (!font_load_in_memory(pf))
440 DEBUGF("Failed mem load");
441 return false;
444 return true;
447 static int find_font_index(const char* path)
449 int index = 0, handle;
451 while (index < MAXFONTS)
453 handle = buflib_allocations[index];
454 if (handle > 0 && !strcmp(core_get_name(handle), path))
455 return index;
456 index++;
458 return FONT_SYSFIXED;
461 static int alloc_and_init(int font_idx, const char* name, size_t size)
463 int *phandle = &buflib_allocations[font_idx];
464 int handle = *phandle;
465 struct buflib_alloc_data *pdata;
466 struct font *pf;
467 size_t alloc_size = size + sizeof(struct buflib_alloc_data);
468 if (handle > 0)
469 return handle;
470 *phandle = core_alloc_ex(name, alloc_size, &buflibops);
471 handle = *phandle;
472 if (handle < 0)
473 return handle;
474 pdata = core_get_data(handle);
475 pf = &pdata->font;
476 pdata->handle_locks = 0;
477 pdata->refcount = 1;
478 pf->buffer_position = pf->buffer_start = buffer_from_handle(handle);
479 pf->buffer_size = size;
480 pf->fd_width = -1;
481 pf->fd_offset = -1;
482 return handle;
485 const char* font_filename(int font_id)
487 int handle = buflib_allocations[font_id];
488 if (handle > 0)
489 return core_get_name(handle);
490 return NULL;
493 /* read and load font into incore font structure,
494 * returns the font number on success, -1 on failure */
495 int font_load_ex(const char *path, size_t buffer_size)
497 int font_id = find_font_index(path);
498 char *buffer;
499 int handle;
501 if (font_id > FONT_SYSFIXED)
503 /* already loaded, no need to reload */
504 struct buflib_alloc_data *pd = core_get_data(buflib_allocations[font_id]);
505 if (pd->font.buffer_size < buffer_size)
507 int old_refcount, old_id;
508 /* reload the font:
509 * 1) save of refcont and id
510 * 2) force unload (set refcount to 1 to make sure it get unloaded)
511 * 3) reload with the larger buffer
512 * 4) restore the id and refcount
514 old_id = font_id;
515 old_refcount = pd->refcount;
516 pd->refcount = 1;
517 font_unload(font_id);
518 font_id = font_load_ex(path, buffer_size);
519 if (font_id < 0)
521 // not much we can do here, maybe try reloading with the small buffer again
522 return -1;
524 if (old_id != font_id)
526 buflib_allocations[old_id] = buflib_allocations[font_id];
527 buflib_allocations[font_id] = -1;
528 font_id = old_id;
530 pd = core_get_data(buflib_allocations[font_id]);
531 pd->refcount = old_refcount;
533 pd->refcount++;
534 //printf("reusing handle %d for %s (count: %d)\n", font_id, path, pd->refcount);
535 return font_id;
538 for (font_id = FONT_FIRSTUSERFONT; font_id < MAXFONTS; font_id++)
540 handle = buflib_allocations[font_id];
541 if (handle < 0)
543 break;
546 handle = alloc_and_init(font_id, path, buffer_size);
547 if (handle < 0)
548 return -1;
550 buffer = buffer_from_handle(handle);
551 lock_font_handle(handle, true);
553 if (!internal_load_font(font_id, path, buffer, buffer_size, handle))
555 lock_font_handle(handle, false);
556 core_free(handle);
557 buflib_allocations[font_id] = -1;
558 return -1;
561 lock_font_handle(handle, false);
562 buflib_allocations[font_id] = handle;
563 //printf("%s -> [%d] -> %d\n", path, font_id, handle);
564 return font_id; /* success!*/
566 int font_load(const char *path)
568 int size;
569 int fd = open( path, O_RDONLY );
570 if ( fd < 0 )
571 return -1;
572 size = filesize(fd);
573 if (size > MAX_FONT_SIZE)
574 size = MAX_FONT_SIZE;
575 close(fd);
576 return font_load_ex(path, size);
579 void font_unload(int font_id)
581 if ( font_id == FONT_SYSFIXED )
582 return;
583 int handle = buflib_allocations[font_id];
584 if ( handle < 0 )
585 return;
586 struct buflib_alloc_data *pdata = core_get_data(handle);
587 struct font* pf = &pdata->font;
588 pdata->refcount--;
589 if (pdata->refcount < 1)
591 //printf("freeing id: %d %s\n", font_id, core_get_name(*handle));
592 if (pf && pf->fd >= 0)
594 glyph_cache_save(font_id);
595 close(pf->fd);
597 if (handle > 0)
598 core_free(handle);
599 buflib_allocations[font_id] = -1;
604 void font_unload_all(void)
606 int i;
607 for (i=0; i<MAXFONTS; i++)
609 if (buflib_allocations[i] > 0)
611 struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[i]);
612 alloc->refcount = 1; /* force unload */
613 font_unload(i);
619 * Return a pointer to an incore font structure.
620 * Return the requested font, font_ui, or sysfont
622 struct font* font_get(int font_id)
624 struct buflib_alloc_data *alloc;
625 struct font *pf;
626 int handle, id=-1;
628 if( font_id == FONT_UI )
629 id = font_ui;
631 if( font_id == FONT_SYSFIXED )
632 return &sysfont;
634 if( id == -1 )
635 id = font_id;
637 handle = buflib_allocations[id];
638 if( handle > 0 )
640 alloc = core_get_data(buflib_allocations[id]);
641 pf=&alloc->font;
642 if( pf && pf->height )
643 return pf;
645 handle = buflib_allocations[font_ui];
646 if( handle > 0 )
648 alloc = core_get_data(buflib_allocations[font_ui]);
649 pf=&alloc->font;
650 if( pf && pf->height )
651 return pf;
654 return &sysfont;
657 void font_set_ui( int font_id )
659 font_ui = font_id;
660 return;
663 int font_get_ui()
665 return font_ui;
668 static int pf_to_handle(struct font* pf)
670 int i;
671 for (i=0; i<MAXFONTS; i++)
673 int handle = buflib_allocations[i];
674 if (handle > 0)
676 struct buflib_alloc_data *pdata = core_get_data(handle);
677 if (pf == &pdata->font)
678 return handle;
681 return -1;
685 * Reads an entry into cache entry
687 static void
688 load_cache_entry(struct font_cache_entry* p, void* callback_data)
690 struct font* pf = callback_data;
691 int handle = pf_to_handle(pf);
692 unsigned short char_code = p->_char_code;
693 unsigned char tmp[2];
694 int fd;
696 if (handle > 0)
697 lock_font_handle(handle, true);
698 if (pf->file_width_offset)
700 int width_offset = pf->file_width_offset + char_code;
701 /* load via different fd to get this file section cached */
702 if(pf->fd_width >=0 )
703 fd = pf->fd_width;
704 else
705 fd = pf->fd;
706 lseek(fd, width_offset, SEEK_SET);
707 read(fd, &(p->width), 1);
709 else
711 p->width = pf->maxwidth;
714 int32_t bitmap_offset = 0;
716 if (pf->file_offset_offset)
718 int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
719 /* load via different fd to get this file section cached */
720 if(pf->fd_offset >=0 )
721 fd = pf->fd_offset;
722 else
723 fd = pf->fd;
724 lseek(fd, offset, SEEK_SET);
725 read (fd, tmp, 2);
726 bitmap_offset = tmp[0] | (tmp[1] << 8);
727 if (pf->long_offset) {
728 read (fd, tmp, 2);
729 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
732 else
734 bitmap_offset = char_code * glyph_bytes(pf, p->width);
737 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
738 lseek(pf->fd, file_offset, SEEK_SET);
739 int src_bytes = glyph_bytes(pf, p->width);
740 read(pf->fd, p->bitmap, src_bytes);
742 if (handle > 0)
743 lock_font_handle(handle, false);
747 * Converts cbuf into a font cache
749 static void cache_create(struct font* pf)
751 /* maximum size of rotated bitmap */
752 int bitmap_size = glyph_bytes( pf, pf->maxwidth);
754 /* Initialise cache */
755 font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
759 * Returns width of character
761 int font_get_width(struct font* pf, unsigned short char_code)
763 /* check input range*/
764 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
765 char_code = pf->defaultchar;
766 char_code -= pf->firstchar;
768 return (pf->fd >= 0 && pf != &sysfont)?
769 font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
770 pf->width? pf->width[char_code]: pf->maxwidth;
773 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
775 const unsigned char* bits;
777 /* check input range*/
778 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
779 char_code = pf->defaultchar;
780 char_code -= pf->firstchar;
782 if (pf->fd >= 0 && pf != &sysfont)
784 bits =
785 (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry, pf)->bitmap;
787 else
789 bits = pf->bits;
790 if (pf->offset)
792 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
793 bits += ((uint16_t*)(pf->offset))[char_code];
794 else
795 bits += ((uint32_t*)(pf->offset))[char_code];
797 else
798 bits += char_code * glyph_bytes(pf, pf->maxwidth);
801 return bits;
804 void font_path_to_glyph_path( const char *font_path, char *glyph_path)
807 /* take full file name, cut extension, and add .glyphcache */
808 strlcpy(glyph_path, font_path, MAX_PATH);
809 glyph_path[strlen(glyph_path)-4] = '\0';
810 strcat(glyph_path, ".gc");
813 /* call with NULL to flush */
814 static void glyph_file_write(void* data)
816 struct font_cache_entry* p = data;
817 struct font* pf = cache_pf;
818 unsigned short ch;
819 static int buffer_pos = 0;
820 #define WRITE_BUFFER 256
821 static unsigned char buffer[WRITE_BUFFER];
823 /* flush buffer & reset */
824 if ( data == NULL || buffer_pos >= WRITE_BUFFER)
826 write(cache_fd, buffer, buffer_pos);
827 buffer_pos = 0;
828 if ( data == NULL )
829 return;
831 if ( p->_char_code == 0xffff )
832 return;
834 ch = p->_char_code + pf->firstchar;
835 buffer[buffer_pos] = ch >> 8;
836 buffer[buffer_pos+1] = ch & 0xff;
837 buffer_pos += 2;
838 return;
841 /* save the char codes of the loaded glyphs to a file */
842 void glyph_cache_save(int font_id)
844 int fd;
846 if( font_id < 0 )
847 return;
848 int handle = buflib_allocations[font_id];
849 if ( handle < 0 )
850 return;
852 struct font *pf = pf_from_handle(handle);
853 if(pf && pf->fd >= 0)
855 /* FIXME: This sleep should not be necessary but without it *
856 * unloading multiple fonts and saving glyphcache files *
857 * quickly in succession creates multiple glyphcache files *
858 * with the same name. */
859 sleep(HZ/10);
860 char filename[MAX_PATH];
861 font_path_to_glyph_path(font_filename(font_id), filename);
862 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
863 if (fd < 0)
864 return;
866 cache_pf = pf;
867 cache_fd = fd;
868 lru_traverse(&cache_pf->cache._lru, glyph_file_write);
869 glyph_file_write(NULL);
870 if (cache_fd >= 0)
872 close(cache_fd);
873 cache_fd = -1;
876 return;
879 int font_glyphs_to_bufsize(const char *path, int glyphs)
881 struct font f;
882 int bufsize;
883 char buf[FONT_HEADER_SIZE];
885 f.buffer_start = buf;
886 f.buffer_size = sizeof(buf);
887 f.buffer_position = buf;
889 f.fd = open(path, O_RDONLY|O_BINARY);
890 if(f.fd < 0)
891 return 0;
893 read(f.fd, f.buffer_position, FONT_HEADER_SIZE);
894 f.buffer_end = f.buffer_position + FONT_HEADER_SIZE;
896 if( !font_load_header(&f) )
898 close(f.fd);
899 return 0;
901 close(f.fd);
903 bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) +
904 sizeof( unsigned short);
905 bufsize += glyph_bytes(&f, f.maxwidth);
906 bufsize *= glyphs;
907 if ( bufsize < FONT_HEADER_SIZE )
908 bufsize = FONT_HEADER_SIZE;
909 return bufsize;
912 static int ushortcmp(const void *a, const void *b)
914 return ((int)(*(unsigned short*)a - *(unsigned short*)b));
916 static void glyph_cache_load(int font_id)
918 int handle = buflib_allocations[font_id];
919 if (handle < 0)
920 return;
921 struct font *pf = pf_from_handle(handle);
922 #define MAX_SORT 256
923 if (pf->fd >= 0) {
924 int i, size, fd;
925 unsigned char tmp[2];
926 unsigned short ch;
927 unsigned short glyphs[MAX_SORT];
928 unsigned short glyphs_lru_order[MAX_SORT];
929 int glyph_file_skip=0, glyph_file_size=0;
931 int sort_size = pf->cache._capacity;
932 if ( sort_size > MAX_SORT )
933 sort_size = MAX_SORT;
935 char filename[MAX_PATH];
936 font_path_to_glyph_path(font_filename(font_id), filename);
938 fd = open(filename, O_RDONLY|O_BINARY);
939 #ifdef TRY_DEFAULT_GLYPHCACHE
940 /* if font specific file fails, try default */
941 if (fd < 0)
942 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
943 #endif
944 if (fd >= 0) {
945 /* only read what fits */
946 glyph_file_size = filesize( fd );
947 if ( glyph_file_size > 2*pf->cache._capacity ) {
948 glyph_file_skip = glyph_file_size - 2*pf->cache._capacity;
949 lseek( fd, glyph_file_skip, SEEK_SET );
952 while(1) {
954 for ( size = 0;
955 read( fd, tmp, 2 ) == 2 && size < sort_size;
956 size++ )
958 glyphs[size] = (tmp[0] << 8) | tmp[1];
959 glyphs_lru_order[size] = glyphs[size];
962 /* sort glyphs array to make sector cache happy */
963 qsort((void *)glyphs, size, sizeof(unsigned short),
964 ushortcmp );
966 /* load font bitmaps */
967 for( i = 0; i < size ; i++ )
968 font_get_bits(pf, glyphs[i]);
970 /* redo to fix lru order */
971 for ( i = 0; i < size ; i++)
972 font_get_bits(pf, glyphs_lru_order[i]);
974 if ( size < sort_size )
975 break;
978 close(fd);
979 } else {
980 /* load latin1 chars into cache */
981 for ( ch = 32 ; ch < 256 && ch < pf->cache._capacity + 32; ch++ )
982 font_get_bits(pf, ch);
985 return;
987 #else /* BOOTLOADER */
989 void font_init(void)
993 void font_lock(int font_id, bool lock)
995 (void)font_id;
996 (void)lock;
1000 * Bootloader only supports the built-in sysfont.
1002 struct font* font_get(int font)
1004 (void)font;
1005 return &sysfont;
1008 void font_set_ui(int font_id)
1010 (void)font_id;
1011 return;
1014 int font_get_ui()
1016 return FONT_SYSFIXED;
1021 * Returns width of character
1023 int font_get_width(struct font* pf, unsigned short char_code)
1025 /* check input range*/
1026 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
1027 char_code = pf->defaultchar;
1028 char_code -= pf->firstchar;
1030 return pf->width? pf->width[char_code]: pf->maxwidth;
1033 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
1035 const unsigned char* bits;
1037 /* check input range*/
1038 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
1039 char_code = pf->defaultchar;
1040 char_code -= pf->firstchar;
1042 /* assume small font with uint16_t offsets*/
1043 bits = pf->bits + (pf->offset?
1044 ((uint16_t*)(pf->offset))[char_code]:
1045 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
1047 return bits;
1050 #endif /* BOOTLOADER */
1053 * Returns the stringsize of a given string.
1055 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
1057 struct font* pf = font_get(fontnumber);
1058 unsigned short ch;
1059 int width = 0;
1061 font_lock( fontnumber, true );
1062 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
1064 if (is_diacritic(ch, NULL))
1065 continue;
1067 /* get proportional width and glyph bits*/
1068 width += font_get_width(pf,ch);
1070 if ( w )
1071 *w = width;
1072 if ( h )
1073 *h = pf->height;
1074 font_lock( fontnumber, false );
1075 return width;
1078 /* -----------------------------------------------------------------
1079 * vim: et sw=4 ts=8 sts=4 tw=78