diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/font.h | 7 | ||||
-rw-r--r-- | firmware/font.c | 116 | ||||
-rw-r--r-- | firmware/font_cache.c | 3 | ||||
-rw-r--r-- | firmware/include/font_cache.h | 10 |
4 files changed, 123 insertions, 13 deletions
diff --git a/firmware/export/font.h b/firmware/export/font.h index ed003f220a..d19e0b87ad 100644 --- a/firmware/export/font.h +++ b/firmware/export/font.h | |||
@@ -125,6 +125,13 @@ void font_unload(int font_id); | |||
125 | void font_unload_all(void); | 125 | void font_unload_all(void); |
126 | void font_lock(int font_id, bool lock); | 126 | void font_lock(int font_id, bool lock); |
127 | 127 | ||
128 | /* Closes the file descriptor if the font file (if cached) but keeps | ||
129 | * the cache intact, so font_get_{bits,width} still work. */ | ||
130 | void font_disable_all(void); | ||
131 | /* Re-opens the file descriptor of the font file. Should be called as | ||
132 | * counter-part of font_disable_all(); */ | ||
133 | void font_enable_all(void); | ||
134 | |||
128 | struct font* font_get(int font); | 135 | struct font* font_get(int font); |
129 | 136 | ||
130 | int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber); | 137 | int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber); |
diff --git a/firmware/font.c b/firmware/font.c index e7a574f0dd..723c972e3b 100644 --- a/firmware/font.c +++ b/firmware/font.c | |||
@@ -88,9 +88,10 @@ extern struct font sysfont; | |||
88 | #ifndef BOOTLOADER | 88 | #ifndef BOOTLOADER |
89 | 89 | ||
90 | struct buflib_alloc_data { | 90 | struct buflib_alloc_data { |
91 | struct font font; | 91 | struct font font; /* must be the first member! */ |
92 | int handle_locks; /* is the buflib handle currently locked? */ | 92 | int handle_locks; /* is the buflib handle currently locked? */ |
93 | int refcount; /* how many times has this font been loaded? */ | 93 | int refcount; /* how many times has this font been loaded? */ |
94 | int disabled; /* font disabled (use fallback glyphs, from sysfont) */ | ||
94 | unsigned char buffer[]; | 95 | unsigned char buffer[]; |
95 | }; | 96 | }; |
96 | static int buflib_allocations[MAXFONTS]; | 97 | static int buflib_allocations[MAXFONTS]; |
@@ -285,6 +286,7 @@ static struct font* font_load_cached(struct font* pf, | |||
285 | int32_t noffset) | 286 | int32_t noffset) |
286 | { | 287 | { |
287 | /* We are now at the bitmap data, this is fixed at 36.. */ | 288 | /* We are now at the bitmap data, this is fixed at 36.. */ |
289 | pf->width = NULL; | ||
288 | pf->bits = NULL; | 290 | pf->bits = NULL; |
289 | 291 | ||
290 | /* Calculate offset to offset data */ | 292 | /* Calculate offset to offset data */ |
@@ -412,11 +414,10 @@ int font_load_ex( const char *path, size_t buf_size, int glyphs ) | |||
412 | /* load font struct f with file header */ | 414 | /* load font struct f with file header */ |
413 | int file_size = filesize( fd ); | 415 | int file_size = filesize( fd ); |
414 | struct font header; | 416 | struct font header; |
415 | struct font *pheader = &header; | ||
416 | struct font f; | 417 | struct font f; |
417 | 418 | ||
418 | uint32_t nwidth, noffset; | 419 | uint32_t nwidth, noffset; |
419 | if ( !font_load_header( fd, pheader, &f, &nwidth, &noffset ) | 420 | if ( !font_load_header( fd, &header, &f, &nwidth, &noffset ) |
420 | #if LCD_DEPTH < 16 | 421 | #if LCD_DEPTH < 16 |
421 | || f.depth | 422 | || f.depth |
422 | #endif | 423 | #endif |
@@ -470,6 +471,7 @@ int font_load_ex( const char *path, size_t buf_size, int glyphs ) | |||
470 | old_id = font_id; | 471 | old_id = font_id; |
471 | old_refcount = pd->refcount; | 472 | old_refcount = pd->refcount; |
472 | pd->refcount = 1; | 473 | pd->refcount = 1; |
474 | pd->disabled = false; | ||
473 | font_unload(font_id); | 475 | font_unload(font_id); |
474 | font_id = font_load_ex(path, bufsize, glyphs); | 476 | font_id = font_load_ex(path, bufsize, glyphs); |
475 | if (font_id < 0) | 477 | if (font_id < 0) |
@@ -623,6 +625,58 @@ void font_unload_all(void) | |||
623 | } | 625 | } |
624 | } | 626 | } |
625 | 627 | ||
628 | static void font_disable(int font_id) | ||
629 | { | ||
630 | if ( font_id < 0 || font_id >= MAXFONTS ) | ||
631 | return; | ||
632 | int handle = buflib_allocations[font_id]; | ||
633 | if ( handle < 0 ) | ||
634 | return; | ||
635 | struct buflib_alloc_data *pdata = core_get_data(handle); | ||
636 | struct font *pf = &pdata->font; | ||
637 | |||
638 | if (pf->fd >= 0) | ||
639 | { | ||
640 | /* save the cache, but it keep it in-RAM so that cache lookups | ||
641 | * can still succeed on the same font */ | ||
642 | glyph_cache_save(font_id); | ||
643 | close(pf->fd); | ||
644 | pf->fd = -1; | ||
645 | pdata->disabled = true; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | void font_disable_all(void) | ||
650 | { | ||
651 | for(int i = 0; i < MAXFONTS; i++) | ||
652 | font_disable(i); | ||
653 | } | ||
654 | |||
655 | static void font_enable(int font_id) | ||
656 | { | ||
657 | if ( font_id < 0 || font_id >= MAXFONTS ) | ||
658 | return; | ||
659 | int handle = buflib_allocations[font_id]; | ||
660 | if ( handle < 0 ) | ||
661 | return; | ||
662 | struct buflib_alloc_data *pdata = core_get_data(handle); | ||
663 | struct font *pf = &pdata->font; | ||
664 | |||
665 | if (pdata->disabled && pf->fd < 0) | ||
666 | { | ||
667 | const char *filename = font_filename(font_id); | ||
668 | pf->fd = open(filename, O_RDONLY); | ||
669 | pdata->disabled = false; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | void font_enable_all(void) | ||
674 | { | ||
675 | for(int i = 0; i < MAXFONTS; i++) | ||
676 | font_enable(i); | ||
677 | } | ||
678 | |||
679 | |||
626 | /* | 680 | /* |
627 | * Return a pointer to an incore font structure. | 681 | * Return a pointer to an incore font structure. |
628 | * If the requested font isn't loaded/compiled-in, | 682 | * If the requested font isn't loaded/compiled-in, |
@@ -715,10 +769,15 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data) | |||
715 | static void cache_create(struct font* pf) | 769 | static void cache_create(struct font* pf) |
716 | { | 770 | { |
717 | /* maximum size of rotated bitmap */ | 771 | /* maximum size of rotated bitmap */ |
718 | int bitmap_size = glyph_bytes( pf, pf->maxwidth); | 772 | int bitmap_size = glyph_bytes(pf, pf->maxwidth); |
719 | 773 | /* reserve one blank glyph that is guaranteed to be available, even | |
774 | * when the font file is closed during USB */ | ||
775 | unsigned char *cache_buf = pf->buffer_start + bitmap_size; | ||
776 | size_t cache_size = pf->buffer_size - (cache_buf - pf->buffer_start); | ||
777 | ALIGN_BUFFER(cache_buf, cache_size, 2); | ||
778 | memset(pf->buffer_start, 0, bitmap_size); | ||
720 | /* Initialise cache */ | 779 | /* Initialise cache */ |
721 | font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size); | 780 | font_cache_create(&pf->cache, cache_buf, cache_size, bitmap_size); |
722 | } | 781 | } |
723 | 782 | ||
724 | /* | 783 | /* |
@@ -726,32 +785,65 @@ static void cache_create(struct font* pf) | |||
726 | */ | 785 | */ |
727 | int font_get_width(struct font* pf, unsigned short char_code) | 786 | int font_get_width(struct font* pf, unsigned short char_code) |
728 | { | 787 | { |
788 | int width; | ||
789 | struct font_cache_entry *e; | ||
790 | struct buflib_alloc_data *data = (struct buflib_alloc_data *) pf; | ||
791 | bool cache_only = data->disabled; | ||
792 | |||
729 | /* check input range*/ | 793 | /* check input range*/ |
730 | if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size) | 794 | if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size) |
731 | char_code = pf->defaultchar; | 795 | char_code = pf->defaultchar; |
732 | char_code -= pf->firstchar; | 796 | char_code -= pf->firstchar; |
733 | 797 | ||
734 | return (pf->fd >= 0 && pf != &sysfont)? | 798 | if ((pf->fd >= 0 || cache_only) && pf != &sysfont |
735 | font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width: | 799 | && (e = font_cache_get(&pf->cache,char_code,cache_only,load_cache_entry,pf))) |
736 | pf->width? pf->width[char_code]: pf->maxwidth; | 800 | width = e->width; |
801 | else if (pf->width) | ||
802 | width = pf->width[char_code]; | ||
803 | else | ||
804 | width = pf->maxwidth; | ||
805 | |||
806 | return width; | ||
737 | } | 807 | } |
738 | 808 | ||
739 | const unsigned char* font_get_bits(struct font* pf, unsigned short char_code) | 809 | const unsigned char* font_get_bits(struct font* pf, unsigned short char_code) |
740 | { | 810 | { |
741 | const unsigned char* bits; | 811 | const unsigned char* bits; |
812 | struct buflib_alloc_data *data; | ||
742 | 813 | ||
743 | /* check input range*/ | 814 | /* check input range*/ |
744 | if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size) | 815 | if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size) |
745 | char_code = pf->defaultchar; | 816 | char_code = pf->defaultchar; |
746 | char_code -= pf->firstchar; | 817 | char_code -= pf->firstchar; |
747 | 818 | ||
819 | data = (struct buflib_alloc_data *) pf; | ||
820 | |||
748 | if (pf->fd >= 0 && pf != &sysfont) | 821 | if (pf->fd >= 0 && pf != &sysfont) |
749 | { | 822 | { |
750 | bits = | 823 | bits = |
751 | (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry, pf)->bitmap; | 824 | (unsigned char*)font_cache_get(&pf->cache, char_code, |
825 | false, load_cache_entry, data)->bitmap; | ||
826 | } | ||
827 | else if (data->disabled) | ||
828 | { | ||
829 | /* the font handle is closed, but the cache is intact. Attempt | ||
830 | * a lookup, which is very likely to succeed. Return a placeholder | ||
831 | * glyph on miss (again, this is very unlikely */ | ||
832 | struct font_cache_entry *e = font_cache_get(&pf->cache, char_code, | ||
833 | true, NULL, NULL); | ||
834 | if (LIKELY(e)) | ||
835 | bits = (unsigned char *) e->bitmap; | ||
836 | else | ||
837 | { | ||
838 | /* Could attempt to find a suitable fallback glyph from the same | ||
839 | * font. For now just return blank space which is | ||
840 | * reserved by cache_create() at buffer_start */ | ||
841 | bits = pf->buffer_start; | ||
842 | } | ||
752 | } | 843 | } |
753 | else | 844 | else |
754 | { | 845 | { |
846 | /* This font is entirely in RAM */ | ||
755 | bits = pf->bits; | 847 | bits = pf->bits; |
756 | if (pf->offset) | 848 | if (pf->offset) |
757 | { | 849 | { |
diff --git a/firmware/font_cache.c b/firmware/font_cache.c index 4604d1524e..0b03edaf76 100644 --- a/firmware/font_cache.c +++ b/firmware/font_cache.c | |||
@@ -125,6 +125,7 @@ static int search(struct font_cache* fcache, | |||
125 | struct font_cache_entry* font_cache_get( | 125 | struct font_cache_entry* font_cache_get( |
126 | struct font_cache* fcache, | 126 | struct font_cache* fcache, |
127 | unsigned short char_code, | 127 | unsigned short char_code, |
128 | bool cache_only, | ||
128 | void (*callback) (struct font_cache_entry* p, void *callback_data), | 129 | void (*callback) (struct font_cache_entry* p, void *callback_data), |
129 | void *callback_data) | 130 | void *callback_data) |
130 | { | 131 | { |
@@ -166,6 +167,8 @@ struct font_cache_entry* font_cache_get( | |||
166 | } | 167 | } |
167 | 168 | ||
168 | /* not found */ | 169 | /* not found */ |
170 | if (cache_only) | ||
171 | return NULL; | ||
169 | 172 | ||
170 | /* find index to replace */ | 173 | /* find index to replace */ |
171 | short lru_handle_to_replace = fcache->_lru._head; | 174 | short lru_handle_to_replace = fcache->_lru._head; |
diff --git a/firmware/include/font_cache.h b/firmware/include/font_cache.h index a4c959e336..1809720ed5 100644 --- a/firmware/include/font_cache.h +++ b/firmware/include/font_cache.h | |||
@@ -17,8 +17,10 @@ | |||
17 | * KIND, either express or implied. | 17 | * KIND, either express or implied. |
18 | * | 18 | * |
19 | ****************************************************************************/ | 19 | ****************************************************************************/ |
20 | |||
20 | #ifndef _FONT_CACHE_H_ | 21 | #ifndef _FONT_CACHE_H_ |
21 | #define _FONT_CACHE_H_ | 22 | #define _FONT_CACHE_H_ |
23 | #include <stdbool.h> | ||
22 | #include "lru.h" | 24 | #include "lru.h" |
23 | 25 | ||
24 | /******************************************************************************* | 26 | /******************************************************************************* |
@@ -45,10 +47,16 @@ struct font_cache_entry | |||
45 | /* Create an auto sized font cache from buf */ | 47 | /* Create an auto sized font cache from buf */ |
46 | void font_cache_create( | 48 | void font_cache_create( |
47 | struct font_cache* fcache, void* buf, int buf_size, int bitmap_bytes_size); | 49 | struct font_cache* fcache, void* buf, int buf_size, int bitmap_bytes_size); |
48 | /* Get font cache entry */ | 50 | |
51 | /* Get font cache entry for the given char_code | ||
52 | * | ||
53 | * cache_only: true if only a cache lookup should be performed and loading on miss should be avoided | ||
54 | * | ||
55 | * Note: With cache_only this can return NULL, which otherwise never happens */ | ||
49 | struct font_cache_entry* font_cache_get( | 56 | struct font_cache_entry* font_cache_get( |
50 | struct font_cache* fcache, | 57 | struct font_cache* fcache, |
51 | unsigned short char_code, | 58 | unsigned short char_code, |
59 | bool cache_only, | ||
52 | void (*callback) (struct font_cache_entry* p, void *callback_data), | 60 | void (*callback) (struct font_cache_entry* p, void *callback_data), |
53 | void *callback_data); | 61 | void *callback_data); |
54 | 62 | ||