Fix FS#12824 : Malfunctioning FFT plugin in Sansa Clip Zip
[maemo-rb.git] / firmware / font.c
blob06f104054fa6de79b4c3e5ae4fc105c85de9bc60
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
58 #define GLYPHS_TO_CACHE 256
60 #if MEMORYSIZE < 4
61 #define FONT_HARD_LIMIT
62 #endif
64 #ifndef FONT_HEADER_SIZE
65 #define FONT_HEADER_SIZE 36
66 #endif
68 #ifndef BOOTLOADER
69 /* Font cache includes */
70 #include "font_cache.h"
71 #include "lru.h"
72 #endif
74 #ifndef O_BINARY
75 #define O_BINARY 0
76 #endif
78 /* Define this to try loading /.rockbox/.glyphcache *
79 * when a font specific file fails. This requires the *
80 * user to copy and rename a font glyph cache file */
81 //#define TRY_DEFAULT_GLYPHCACHE
83 /* compiled-in font */
84 extern struct font sysfont;
86 #ifndef BOOTLOADER
88 struct buflib_alloc_data {
89 struct font font;
90 int handle_locks; /* is the buflib handle currently locked? */
91 int refcount; /* how many times has this font been loaded? */
92 unsigned char buffer[];
94 static int buflib_allocations[MAXFONTS];
96 static int cache_fd;
97 static struct font* cache_pf;
99 static void glyph_cache_save(int font_id);
101 static int buflibmove_callback(int handle, void* current, void* new)
103 (void)handle;
104 struct buflib_alloc_data *alloc = (struct buflib_alloc_data*)current;
105 ptrdiff_t diff = new - current;
107 if (alloc->handle_locks > 0)
108 return BUFLIB_CB_CANNOT_MOVE;
110 #define UPDATE(x) if (x) { x = PTR_ADD(x, diff); }
112 UPDATE(alloc->font.bits);
113 UPDATE(alloc->font.offset);
114 UPDATE(alloc->font.width);
116 UPDATE(alloc->font.buffer_start);
117 UPDATE(alloc->font.buffer_end);
118 UPDATE(alloc->font.buffer_position);
120 UPDATE(alloc->font.cache._index);
121 UPDATE(alloc->font.cache._lru._base);
123 return BUFLIB_CB_OK;
125 static void lock_font_handle(int handle, bool lock)
127 if ( handle < 0 )
128 return;
129 struct buflib_alloc_data *alloc = core_get_data(handle);
130 if ( lock )
131 alloc->handle_locks++;
132 else
133 alloc->handle_locks--;
136 void font_lock(int font_id, bool lock)
138 if( font_id < 0 || font_id >= MAXFONTS )
139 return;
140 if( buflib_allocations[font_id] >= 0 )
141 lock_font_handle(buflib_allocations[font_id], lock);
144 static struct buflib_callbacks buflibops = {buflibmove_callback, NULL, NULL };
146 static inline struct font *pf_from_handle(int handle)
148 struct buflib_alloc_data *alloc = core_get_data(handle);
149 struct font *pf = &alloc->font;
150 return pf;
153 static inline unsigned char *buffer_from_handle(int handle)
155 struct buflib_alloc_data *alloc = core_get_data(handle);
156 unsigned char* buffer = alloc->buffer;
157 return buffer;
160 /* Font cache structures */
161 static void cache_create(struct font* pf);
162 static void glyph_cache_load(const char *font_path, struct font *pf);
163 /* End Font cache structures */
165 void font_init(void)
167 int i = 0;
168 cache_fd = -1;
169 while (i<MAXFONTS)
170 buflib_allocations[i++] = -1;
173 /* Check if we have x bytes left in the file buffer */
174 #define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
176 /* Helper functions to read big-endian unaligned short or long from
177 the file buffer. Bounds-checking must be done in the calling
178 function.
181 static short readshort(struct font *pf)
183 unsigned short s;
185 s = *pf->buffer_position++ & 0xff;
186 s |= (*pf->buffer_position++ << 8);
187 return s;
190 static int32_t readlong(struct font *pf)
192 uint32_t l;
194 l = *pf->buffer_position++ & 0xff;
195 l |= *pf->buffer_position++ << 8;
196 l |= ((uint32_t)(*pf->buffer_position++)) << 16;
197 l |= ((uint32_t)(*pf->buffer_position++)) << 24;
198 return l;
201 static int glyph_bytes( struct font *pf, int width )
203 int ret;
204 if (pf->depth)
205 ret = ( pf->height * width + 1 ) / 2;
206 else
207 ret = width * ((pf->height + 7) / 8);
208 return (ret + 1) & ~1;
211 /* Load memory font */
212 static struct font* font_load_in_memory(struct font* pf,
213 int32_t nwidth,
214 int32_t noffset )
216 int i;
217 /* variable font data*/
218 pf->buffer_position = pf->buffer_start + 36;
219 pf->bits = (unsigned char *)pf->buffer_position;
220 pf->buffer_position += pf->bits_size*sizeof(unsigned char);
222 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
224 /* pad to 16-bit boundary */
225 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
227 else
229 /* pad to 32-bit boundary*/
230 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
233 if (noffset)
235 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
237 pf->long_offset = 0;
238 pf->offset = (uint16_t*)pf->buffer_position;
240 /* Check we have sufficient buffer */
241 if (!HAVEBYTES(noffset * sizeof(uint16_t)))
242 return NULL;
244 for (i=0; i<noffset; ++i)
246 ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
249 else
251 pf->long_offset = 1;
252 pf->offset = (uint16_t*)pf->buffer_position;
254 /* Check we have sufficient buffer */
255 if (!HAVEBYTES(noffset * sizeof(int32_t)))
256 return NULL;
258 for (i=0; i<noffset; ++i)
260 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
264 else
265 pf->offset = NULL;
267 if (nwidth) {
268 pf->width = (unsigned char *)pf->buffer_position;
269 pf->buffer_position += nwidth*sizeof(unsigned char);
271 else
272 pf->width = NULL;
274 if (pf->buffer_position > pf->buffer_end)
275 return NULL;
277 return pf; /* success!*/
280 /* Load cached font */
281 static struct font* font_load_cached(struct font* pf,
282 int32_t nwidth,
283 int32_t noffset)
285 /* We are now at the bitmap data, this is fixed at 36.. */
286 pf->bits = NULL;
288 /* Calculate offset to offset data */
289 pf->buffer_position += pf->bits_size * sizeof(unsigned char);
291 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
293 pf->long_offset = 0;
294 /* pad to 16-bit boundary */
295 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
297 else
299 pf->long_offset = 1;
300 /* pad to 32-bit boundary*/
301 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
304 if (noffset)
305 pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
306 else
307 pf->file_offset_offset = 0;
309 /* Calculate offset to widths data */
310 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
311 pf->buffer_position += noffset * sizeof(uint16_t);
312 else
313 pf->buffer_position += noffset * sizeof(uint32_t);
315 if (nwidth)
316 pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
317 else
318 pf->file_width_offset = 0;
320 /* Create the cache */
321 cache_create(pf);
323 return pf;
327 static int find_font_index(const char* path)
329 int index = 0, handle;
331 while (index < MAXFONTS)
333 handle = buflib_allocations[index];
334 if (handle > 0 && !strcmp(core_get_name(handle), path))
335 return index;
336 index++;
338 return FONT_SYSFIXED;
341 const char* font_filename(int font_id)
343 if ( font_id < 0 || font_id >= MAXFONTS )
344 return NULL;
345 int handle = buflib_allocations[font_id];
346 if (handle > 0)
347 return core_get_name(handle);
348 return NULL;
351 static size_t font_glyphs_to_bufsize(struct font *pf, int glyphs)
353 size_t bufsize;
355 /* LRU bytes per glyph */
356 bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) +
357 sizeof( unsigned short);
358 /* Image bytes per glyph */
359 bufsize += glyph_bytes(pf, pf->maxwidth);
360 bufsize *= glyphs;
362 return bufsize;
365 static struct font* font_load_header(int fd, struct font *pheader,
366 struct font *pf,
367 uint32_t *nwidth, uint32_t *noffset)
369 /* Load the header. Readshort() and readlong() *
370 * update buffer_position address as they read */
371 pheader->buffer_start = pheader->buffer_position = (char *)pheader;
372 pheader->buffer_size = FONT_HEADER_SIZE;
373 pheader->buffer_end = pheader->buffer_start + pheader->buffer_size;
375 if (read(fd, pheader, FONT_HEADER_SIZE) != FONT_HEADER_SIZE)
376 return NULL;
378 /* read magic and version #*/
379 if (memcmp(pheader->buffer_position, VERSION, 4) != 0)
380 return NULL;
382 pheader->buffer_position += 4;
384 /* font info*/
385 pf->maxwidth = readshort(pheader);
386 pf->height = readshort(pheader);
387 pf->ascent = readshort(pheader);
388 pf->depth = readshort(pheader);
389 pf->firstchar = readlong(pheader);
390 pf->defaultchar = readlong(pheader);
391 pf->size = readlong(pheader);
393 /* get variable font data sizes*/
394 /* # words of bitmap_t*/
395 pf->bits_size = readlong(pheader);
396 *noffset = readlong(pheader);
397 *nwidth = readlong(pheader);
399 return pf;
402 /* load a font with room for glyphs, limited to bufsize if not zero */
403 int font_load_ex( const char *path, size_t buf_size, int glyphs )
405 //printf("\nfont_load_ex(%s, %d, %d)\n", path, buf_size, glyphs);
406 int fd = open(path, O_RDONLY|O_BINARY);
407 if ( fd < 0 )
408 return -1;
410 /* load font struct f with file header */
411 int file_size = filesize( fd );
412 struct font header;
413 struct font *pheader = &header;
414 struct font f;
416 uint32_t nwidth, noffset;
417 if ( !font_load_header( fd, pheader, &f, &nwidth, &noffset )
418 #if LCD_DEPTH < 16
419 || f.depth
420 #endif
423 close(fd);
424 return -1;
427 /* examine f and calc buffer size */
428 bool cached = false;
429 size_t bufsize = buf_size;
430 size_t glyph_buf_size = font_glyphs_to_bufsize( &f, glyphs );
432 if ( bufsize && glyphs && bufsize > glyph_buf_size)
433 bufsize = glyph_buf_size;
434 else
436 if ( glyphs )
437 bufsize = glyph_buf_size;
438 else
439 bufsize = MAX_FONT_SIZE;
441 #ifdef FONT_HARD_LIMIT
442 if ( bufsize > MAX_FONT_SIZE )
443 bufsize = MAX_FONT_SIZE;
444 #endif
445 if ( bufsize < (size_t) file_size )
446 cached = true;
447 else
448 bufsize = file_size;
450 /* check already loaded */
451 int font_id = find_font_index(path);
453 if (font_id > FONT_SYSFIXED)
455 /* already loaded, no need to reload */
456 struct buflib_alloc_data *pd = core_get_data(buflib_allocations[font_id]);
457 if (pd->font.buffer_size < bufsize)
459 int old_refcount, old_id;
460 size_t old_bufsize = pd->font.buffer_size;
461 bool failed = false;
462 /* reload the font:
463 * 1) save of refcont and id
464 * 2) force unload (set refcount to 1 to make sure it get unloaded)
465 * 3) reload with the larger buffer
466 * 4) restore the id and refcount
468 old_id = font_id;
469 old_refcount = pd->refcount;
470 pd->refcount = 1;
471 font_unload(font_id);
472 font_id = font_load_ex(path, bufsize, glyphs);
473 if (font_id < 0)
475 failed = true;
476 font_id = font_load_ex(path, old_bufsize, 0);
477 /* we couldn't even get the old size, this shouldn't happen */
478 if ( font_id < 0 )
479 return -1;
481 if (old_id != font_id)
483 buflib_allocations[old_id] = buflib_allocations[font_id];
484 buflib_allocations[font_id] = -1;
485 font_id = old_id;
487 pd = core_get_data(buflib_allocations[font_id]);
488 pd->refcount = old_refcount;
489 if(failed)
490 /* return error because we didn't satisfy the new buffer size */
491 return -1;
493 pd->refcount++;
494 //printf("reusing handle %d for %s (count: %d)\n", font_id, path, pd->refcount);
495 close(fd);
496 return font_id;
499 int open_slot = -1;
501 for (font_id = FONT_FIRSTUSERFONT; font_id < MAXFONTS; font_id++)
503 if (buflib_allocations[ font_id ] < 0)
505 open_slot = font_id;
506 break;
509 if ( open_slot == -1 )
510 return -1;
511 font_id = open_slot;
513 /* allocate mem */
514 int handle = core_alloc_ex( path,
515 bufsize + sizeof( struct buflib_alloc_data ),
516 &buflibops );
517 if ( handle <= 0 )
519 return -1;
521 struct buflib_alloc_data *pdata;
522 pdata = core_get_data(handle);
523 pdata->handle_locks = 1;
524 pdata->refcount = 1;
526 /* load and init */
527 struct font *pf = pf_from_handle( handle );
528 memcpy(pf, &f, sizeof( struct font) );
530 pf->fd = fd;
531 pf->fd_width = pf->fd_offset = -1;
532 pf->handle = handle;
534 pf->buffer_start = buffer_from_handle( pf->handle );
535 pf->buffer_position = pf->buffer_start + FONT_HEADER_SIZE;
536 pf->buffer_size = bufsize;
537 pf->buffer_end = pf->buffer_start + bufsize;
539 if ( cached )
541 if ( ! font_load_cached( pf, nwidth, noffset ) )
543 core_free( handle );
544 return -1;
547 /* trick to get a small cache for each file section *
548 * during glyph_cache_load() */
549 pf->fd_width = open( path, O_RDONLY|O_BINARY );
550 pf->fd_offset = open( path, O_RDONLY|O_BINARY );
552 glyph_cache_load( path, pf );
554 /* cached font: pf->fd stays open until the font is unloaded */
555 close( pf->fd_width );
556 pf->fd_width = -1;
557 close( pf->fd_offset );
558 pf->fd_offset = -1;
560 else
562 lseek( fd, 0, SEEK_SET);
563 read(fd, pf->buffer_start, pf->buffer_size);
565 close( fd );
566 pf->fd = -1;
568 if ( ! font_load_in_memory( pf, nwidth, noffset ) )
570 core_free( handle );
571 return -1;
574 buflib_allocations[font_id] = handle;
575 //printf("%s -> [%d] -> %d\n", path, font_id, *handle);
576 lock_font_handle( handle, false );
577 return font_id; /* success!*/
580 int font_load(const char *path)
582 return font_load_ex(path, MAX_FONT_SIZE, GLYPHS_TO_CACHE);
585 void font_unload(int font_id)
587 if ( font_id < 0 || font_id >= MAXFONTS )
588 return;
589 int handle = buflib_allocations[font_id];
590 if ( handle < 0 )
591 return;
592 struct buflib_alloc_data *pdata = core_get_data(handle);
593 struct font* pf = &pdata->font;
594 pdata->refcount--;
595 if (pdata->refcount < 1)
597 //printf("freeing id: %d %s\n", font_id, core_get_name(*handle));
598 if (pf && pf->fd >= 0)
600 glyph_cache_save(font_id);
601 close(pf->fd);
603 if (handle > 0)
604 core_free(handle);
605 buflib_allocations[font_id] = -1;
610 void font_unload_all(void)
612 int i;
613 for (i=0; i<MAXFONTS; i++)
615 if (buflib_allocations[i] > 0)
617 struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[i]);
618 alloc->refcount = 1; /* force unload */
619 font_unload(i);
625 * Return a pointer to an incore font structure.
626 * If the requested font isn't loaded/compiled-in,
627 * decrement the font number and try again.
629 struct font* font_get(int font)
631 struct font* pf;
632 if (font == FONT_UI)
633 font = MAXFONTS-1;
634 if (font <= FONT_SYSFIXED)
635 return &sysfont;
637 while (1) {
638 if (buflib_allocations[font] > 0)
640 struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[font]);
641 pf = &alloc->font;
642 if (pf && pf->height)
643 return pf;
645 if (--font < 0)
646 return &sysfont;
651 * Reads an entry into cache entry
653 static void
654 load_cache_entry(struct font_cache_entry* p, void* callback_data)
656 struct font* pf = callback_data;
658 unsigned short char_code = p->_char_code;
659 unsigned char tmp[2];
660 int fd;
662 lock_font_handle(pf->handle, true);
663 if (pf->file_width_offset)
665 int width_offset = pf->file_width_offset + char_code;
666 /* load via different fd to get this file section cached */
667 if(pf->fd_width >=0 )
668 fd = pf->fd_width;
669 else
670 fd = pf->fd;
671 lseek(fd, width_offset, SEEK_SET);
672 read(fd, &(p->width), 1);
674 else
676 p->width = pf->maxwidth;
679 int32_t bitmap_offset = 0;
681 if (pf->file_offset_offset)
683 int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
684 /* load via different fd to get this file section cached */
685 if(pf->fd_offset >=0 )
686 fd = pf->fd_offset;
687 else
688 fd = pf->fd;
689 lseek(fd, offset, SEEK_SET);
690 read (fd, tmp, 2);
691 bitmap_offset = tmp[0] | (tmp[1] << 8);
692 if (pf->long_offset) {
693 read (fd, tmp, 2);
694 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
697 else
699 bitmap_offset = char_code * glyph_bytes(pf, p->width);
702 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
703 lseek(pf->fd, file_offset, SEEK_SET);
704 int src_bytes = glyph_bytes(pf, p->width);
705 read(pf->fd, p->bitmap, src_bytes);
707 lock_font_handle(pf->handle, false);
711 * Converts cbuf into a font cache
713 static void cache_create(struct font* pf)
715 /* maximum size of rotated bitmap */
716 int bitmap_size = glyph_bytes( pf, pf->maxwidth);
718 /* Initialise cache */
719 font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
723 * Returns width of character
725 int font_get_width(struct font* pf, unsigned short char_code)
727 /* check input range*/
728 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
729 char_code = pf->defaultchar;
730 char_code -= pf->firstchar;
732 return (pf->fd >= 0 && pf != &sysfont)?
733 font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
734 pf->width? pf->width[char_code]: pf->maxwidth;
737 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
739 const unsigned char* bits;
741 /* check input range*/
742 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
743 char_code = pf->defaultchar;
744 char_code -= pf->firstchar;
746 if (pf->fd >= 0 && pf != &sysfont)
748 bits =
749 (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry, pf)->bitmap;
751 else
753 bits = pf->bits;
754 if (pf->offset)
756 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
757 bits += ((uint16_t*)(pf->offset))[char_code];
758 else
759 bits += ((uint32_t*)(pf->offset))[char_code];
761 else
762 bits += char_code * glyph_bytes(pf, pf->maxwidth);
765 return bits;
768 static void font_path_to_glyph_path( const char *font_path, char *glyph_path)
770 /* take full file name, cut extension, and add .glyphcache */
771 strlcpy(glyph_path, font_path, MAX_PATH);
772 glyph_path[strlen(glyph_path)-4] = '\0';
773 strcat(glyph_path, ".gc");
776 /* call with NULL to flush */
777 static void glyph_file_write(void* data)
779 struct font_cache_entry* p = data;
780 struct font* pf = cache_pf;
781 unsigned short ch;
782 static int buffer_pos = 0;
783 #define WRITE_BUFFER 256
784 static unsigned char buffer[WRITE_BUFFER];
786 /* flush buffer & reset */
787 if ( data == NULL || buffer_pos >= WRITE_BUFFER)
789 write(cache_fd, buffer, buffer_pos);
790 buffer_pos = 0;
791 if ( data == NULL )
792 return;
794 if ( p->_char_code == 0xffff )
795 return;
797 ch = p->_char_code + pf->firstchar;
798 buffer[buffer_pos] = ch >> 8;
799 buffer[buffer_pos+1] = ch & 0xff;
800 buffer_pos += 2;
801 return;
804 /* save the char codes of the loaded glyphs to a file */
805 static void glyph_cache_save(int font_id)
807 int fd;
809 if( font_id < 0 )
810 return;
811 int handle = buflib_allocations[font_id];
812 if ( handle < 0 )
813 return;
815 struct font *pf = pf_from_handle(handle);
816 if(pf && pf->fd >= 0)
818 char filename[MAX_PATH];
819 font_path_to_glyph_path(font_filename(font_id), filename);
820 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
821 if (fd < 0)
822 return;
824 cache_pf = pf;
825 cache_fd = fd;
826 lru_traverse(&cache_pf->cache._lru, glyph_file_write);
827 glyph_file_write(NULL);
828 if (cache_fd >= 0)
830 close(cache_fd);
831 cache_fd = -1;
834 return;
838 static int ushortcmp(const void *a, const void *b)
840 return ((int)(*(unsigned short*)a - *(unsigned short*)b));
842 static void glyph_cache_load(const char *font_path, struct font *pf)
844 #define MAX_SORT 256
845 if (pf->fd >= 0) {
846 int i, size, fd;
847 unsigned char tmp[2];
848 unsigned short ch;
849 unsigned short glyphs[MAX_SORT];
850 unsigned short glyphs_lru_order[MAX_SORT];
851 int glyph_file_skip=0, glyph_file_size=0;
853 int sort_size = pf->cache._capacity;
854 if ( sort_size > MAX_SORT )
855 sort_size = MAX_SORT;
857 char filename[MAX_PATH];
858 font_path_to_glyph_path(font_path, filename);
860 fd = open(filename, O_RDONLY|O_BINARY);
861 #ifdef TRY_DEFAULT_GLYPHCACHE
862 /* if font specific file fails, try default */
863 if (fd < 0)
864 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
865 #endif
866 if (fd >= 0) {
867 /* only read what fits */
868 glyph_file_size = filesize( fd );
869 if ( glyph_file_size > 2*pf->cache._capacity ) {
870 glyph_file_skip = glyph_file_size - 2*pf->cache._capacity;
871 lseek( fd, glyph_file_skip, SEEK_SET );
874 while(1) {
876 for ( size = 0;
877 read( fd, tmp, 2 ) == 2 && size < sort_size;
878 size++ )
880 glyphs[size] = (tmp[0] << 8) | tmp[1];
881 glyphs_lru_order[size] = glyphs[size];
884 /* sort glyphs array to make sector cache happy */
885 qsort((void *)glyphs, size, sizeof(unsigned short),
886 ushortcmp );
888 /* load font bitmaps */
889 for( i = 0; i < size ; i++ )
890 font_get_bits(pf, glyphs[i]);
892 /* redo to fix lru order */
893 for ( i = 0; i < size ; i++)
894 font_get_bits(pf, glyphs_lru_order[i]);
896 if ( size < sort_size )
897 break;
900 close(fd);
901 } else {
902 /* load latin1 chars into cache */
903 for ( ch = 32 ; ch < 256 && ch < pf->cache._capacity + 32; ch++ )
904 font_get_bits(pf, ch);
907 return;
909 #else /* BOOTLOADER */
911 void font_init(void)
915 void font_lock(int font_id, bool lock)
917 (void)font_id;
918 (void)lock;
922 * Bootloader only supports the built-in sysfont.
924 struct font* font_get(int font)
926 (void)font;
927 return &sysfont;
931 * Returns width of character
933 int font_get_width(struct font* pf, unsigned short char_code)
935 /* check input range*/
936 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
937 char_code = pf->defaultchar;
938 char_code -= pf->firstchar;
940 return pf->width? pf->width[char_code]: pf->maxwidth;
943 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
945 const unsigned char* bits;
947 /* check input range*/
948 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
949 char_code = pf->defaultchar;
950 char_code -= pf->firstchar;
952 /* assume small font with uint16_t offsets*/
953 bits = pf->bits + (pf->offset?
954 ((uint16_t*)(pf->offset))[char_code]:
955 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
957 return bits;
960 #endif /* BOOTLOADER */
963 * Returns the stringsize of a given string.
965 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
967 struct font* pf = font_get(fontnumber);
968 unsigned short ch;
969 int width = 0;
971 font_lock( fontnumber, true );
972 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
974 if (is_diacritic(ch, NULL))
975 continue;
977 /* get proportional width and glyph bits*/
978 width += font_get_width(pf,ch);
980 if ( w )
981 *w = width;
982 if ( h )
983 *h = pf->height;
984 font_lock( fontnumber, false );
985 return width;
988 /* -----------------------------------------------------------------
989 * vim: et sw=4 ts=8 sts=4 tw=78