diff options
Diffstat (limited to 'firmware/font.c')
-rw-r--r-- | firmware/font.c | 286 |
1 files changed, 189 insertions, 97 deletions
diff --git a/firmware/font.c b/firmware/font.c index 0f9f453ae2..fea210a3f1 100644 --- a/firmware/font.c +++ b/firmware/font.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "system.h" | 34 | #include "system.h" |
35 | #include "font.h" | 35 | #include "font.h" |
36 | #include "file.h" | 36 | #include "file.h" |
37 | #include "core_alloc.h" | ||
37 | #include "debug.h" | 38 | #include "debug.h" |
38 | #include "panic.h" | 39 | #include "panic.h" |
39 | #include "rbunicode.h" | 40 | #include "rbunicode.h" |
@@ -74,19 +75,58 @@ extern struct font sysfont; | |||
74 | 75 | ||
75 | #ifndef BOOTLOADER | 76 | #ifndef BOOTLOADER |
76 | 77 | ||
77 | /* structure filled in by font_load */ | 78 | struct buflib_alloc_data { |
78 | static struct font font_ui; | 79 | struct font font; |
79 | /* static buffer allocation structures */ | 80 | bool handle_locked; /* is the buflib handle currently locked? */ |
80 | static unsigned char main_buf[MAX_FONT_SIZE] CACHEALIGN_ATTR; | 81 | int refcount; /* how many times has this font been loaded? */ |
81 | #ifdef HAVE_REMOTE_LCD | 82 | unsigned char buffer[MAX_FONT_SIZE]; |
82 | #define REMOTE_FONT_SIZE 10000 | 83 | }; |
83 | static struct font remote_font_ui; | 84 | static int buflib_allocations[MAXFONTS]; |
84 | static unsigned char remote_buf[REMOTE_FONT_SIZE] CACHEALIGN_ATTR; | 85 | static int handle_for_glyphcache; |
85 | #endif | 86 | |
87 | static int buflibmove_callback(int handle, void* current, void* new) | ||
88 | { | ||
89 | (void)handle; | ||
90 | struct buflib_alloc_data *alloc = (struct buflib_alloc_data*)current; | ||
91 | size_t diff = new - current; | ||
92 | |||
93 | if (alloc->handle_locked) | ||
94 | return BUFLIB_CB_CANNOT_MOVE; | ||
95 | |||
96 | alloc->font.bits += diff; | ||
97 | alloc->font.offset += diff; | ||
98 | if (alloc->font.width) | ||
99 | alloc->font.width += diff; | ||
100 | |||
101 | alloc->font.buffer_start += diff; | ||
102 | alloc->font.buffer_end += diff; | ||
103 | alloc->font.buffer_position += diff; | ||
104 | |||
105 | alloc->font.cache._index += diff; | ||
106 | |||
107 | return BUFLIB_CB_OK; | ||
108 | } | ||
109 | static void lock_font_handle(int handle, bool lock) | ||
110 | { | ||
111 | struct buflib_alloc_data *alloc = core_get_data(handle); | ||
112 | alloc->handle_locked = lock; | ||
113 | } | ||
86 | 114 | ||
87 | /* system font table, in order of FONT_xxx definition */ | 115 | static struct buflib_callbacks buflibops = {buflibmove_callback, NULL }; |
88 | static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL}; | ||
89 | 116 | ||
117 | static inline struct font *pf_from_handle(int handle) | ||
118 | { | ||
119 | struct buflib_alloc_data *alloc = core_get_data(handle); | ||
120 | struct font *pf = &alloc->font; | ||
121 | return pf; | ||
122 | } | ||
123 | |||
124 | static inline unsigned char *buffer_from_handle(int handle) | ||
125 | { | ||
126 | struct buflib_alloc_data *alloc = core_get_data(handle); | ||
127 | unsigned char* buffer = alloc->buffer; | ||
128 | return buffer; | ||
129 | } | ||
90 | 130 | ||
91 | /* Font cache structures */ | 131 | /* Font cache structures */ |
92 | static void cache_create(struct font* pf); | 132 | static void cache_create(struct font* pf); |
@@ -95,13 +135,10 @@ static void glyph_cache_load(struct font* pf); | |||
95 | 135 | ||
96 | void font_init(void) | 136 | void font_init(void) |
97 | { | 137 | { |
98 | int i = SYSTEMFONTCOUNT; | 138 | int i = 0; |
99 | while (i<MAXFONTS) | 139 | while (i<MAXFONTS) |
100 | sysfonts[i++] = NULL; | 140 | buflib_allocations[i++] = -1; |
101 | font_reset(NULL); | 141 | handle_for_glyphcache = -1; |
102 | #ifdef HAVE_REMOTE_LCD | ||
103 | font_reset(&remote_font_ui); | ||
104 | #endif | ||
105 | } | 142 | } |
106 | 143 | ||
107 | /* Check if we have x bytes left in the file buffer */ | 144 | /* Check if we have x bytes left in the file buffer */ |
@@ -139,26 +176,6 @@ static int glyph_bytes( struct font *pf, int width ) | |||
139 | width * ((pf->height + 7) / 8); | 176 | width * ((pf->height + 7) / 8); |
140 | } | 177 | } |
141 | 178 | ||
142 | void font_reset(struct font *pf) | ||
143 | { | ||
144 | unsigned char* buffer = NULL; | ||
145 | size_t buf_size = 0; | ||
146 | if (pf == NULL) | ||
147 | pf = &font_ui; | ||
148 | else | ||
149 | { | ||
150 | buffer = pf->buffer_start; | ||
151 | buf_size = pf->buffer_size; | ||
152 | } | ||
153 | memset(pf, 0, sizeof(struct font)); | ||
154 | pf->fd = -1; | ||
155 | if (buffer) | ||
156 | { | ||
157 | pf->buffer_start = buffer; | ||
158 | pf->buffer_size = buf_size; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | static struct font* font_load_header(struct font *pf) | 179 | static struct font* font_load_header(struct font *pf) |
163 | { | 180 | { |
164 | /* Check we have enough data */ | 181 | /* Check we have enough data */ |
@@ -320,18 +337,27 @@ static struct font* font_load_cached(struct font* pf) | |||
320 | return pf; | 337 | return pf; |
321 | } | 338 | } |
322 | 339 | ||
323 | static bool internal_load_font(struct font* pf, const char *path, | 340 | static void font_reset(int font_id) |
341 | { | ||
342 | struct font *pf = pf_from_handle(buflib_allocations[font_id]); | ||
343 | // fixme | ||
344 | memset(pf, 0, sizeof(struct font)); | ||
345 | pf->fd = -1; | ||
346 | } | ||
347 | |||
348 | |||
349 | static bool internal_load_font(int font_id, const char *path, | ||
324 | char *buf, size_t buf_size) | 350 | char *buf, size_t buf_size) |
325 | { | 351 | { |
326 | int size; | 352 | int size; |
327 | 353 | struct font* pf = pf_from_handle(buflib_allocations[font_id]); | |
328 | /* save loaded glyphs */ | 354 | /* save loaded glyphs */ |
329 | glyph_cache_save(pf); | 355 | glyph_cache_save(pf); |
330 | /* Close font file handle */ | 356 | /* Close font file handle */ |
331 | if (pf->fd >= 0) | 357 | if (pf->fd >= 0) |
332 | close(pf->fd); | 358 | close(pf->fd); |
333 | 359 | ||
334 | font_reset(pf); | 360 | font_reset(font_id); |
335 | 361 | ||
336 | /* open and read entire font file*/ | 362 | /* open and read entire font file*/ |
337 | pf->fd = open(path, O_RDONLY|O_BINARY); | 363 | pf->fd = open(path, O_RDONLY|O_BINARY); |
@@ -393,80 +419,117 @@ static bool internal_load_font(struct font* pf, const char *path, | |||
393 | return true; | 419 | return true; |
394 | } | 420 | } |
395 | 421 | ||
396 | #ifdef HAVE_REMOTE_LCD | 422 | static int find_font_index(const char* path) |
397 | /* Load a font into the special remote ui font slot */ | ||
398 | int font_load_remoteui(const char* path) | ||
399 | { | 423 | { |
400 | struct font* pf = &remote_font_ui; | 424 | int index = 0, handle; |
401 | if (!path) | 425 | |
402 | { | 426 | while (index < MAXFONTS) |
403 | if (sysfonts[FONT_UI_REMOTE] && sysfonts[FONT_UI_REMOTE] != sysfonts[FONT_UI]) | ||
404 | font_unload(FONT_UI_REMOTE); | ||
405 | sysfonts[FONT_UI_REMOTE] = NULL; | ||
406 | return FONT_UI; | ||
407 | } | ||
408 | if (!internal_load_font(pf, path, remote_buf, REMOTE_FONT_SIZE)) | ||
409 | { | 427 | { |
410 | sysfonts[FONT_UI_REMOTE] = NULL; | 428 | handle = buflib_allocations[index]; |
411 | return -1; | 429 | if (handle > 0 && !strcmp(core_get_name(handle), path)) |
430 | return index; | ||
431 | index++; | ||
412 | } | 432 | } |
413 | 433 | return FONT_SYSFIXED; | |
414 | sysfonts[FONT_UI_REMOTE] = pf; | ||
415 | return FONT_UI_REMOTE; | ||
416 | } | 434 | } |
417 | #endif | ||
418 | 435 | ||
436 | static int alloc_and_init(int font_idx, const char* name) | ||
437 | { | ||
438 | int *phandle = &buflib_allocations[font_idx]; | ||
439 | int handle = *phandle; | ||
440 | struct buflib_alloc_data *pdata; | ||
441 | struct font *pf; | ||
442 | if (handle > 0) | ||
443 | return handle; | ||
444 | *phandle = core_alloc_ex(name, sizeof(struct buflib_alloc_data), &buflibops); | ||
445 | handle = *phandle; | ||
446 | if (handle < 0) | ||
447 | return handle; | ||
448 | pdata = core_get_data(handle); | ||
449 | pf = &pdata->font; | ||
450 | font_reset(font_idx); | ||
451 | pdata->handle_locked = false; | ||
452 | pdata->refcount = 1; | ||
453 | pf->buffer_position = pf->buffer_start = buffer_from_handle(handle); | ||
454 | pf->buffer_size = MAX_FONT_SIZE; | ||
455 | return handle; | ||
456 | } | ||
457 | |||
458 | const char* font_filename(int font_id) | ||
459 | { | ||
460 | int handle = buflib_allocations[font_id]; | ||
461 | if (handle > 0) | ||
462 | return core_get_name(handle); | ||
463 | return NULL; | ||
464 | } | ||
465 | |||
419 | /* read and load font into incore font structure, | 466 | /* read and load font into incore font structure, |
420 | * returns the font number on success, -1 on failure */ | 467 | * returns the font number on success, -1 on failure */ |
421 | int font_load(struct font* pf, const char *path) | 468 | int font_load(const char *path) |
422 | { | 469 | { |
423 | int font_id = -1; | 470 | int font_id = find_font_index(path); |
424 | char *buffer; | 471 | char *buffer; |
425 | size_t buffer_size; | 472 | size_t buffer_size; |
426 | if (pf == NULL) | 473 | int *handle; |
474 | |||
475 | if (font_id > FONT_SYSFIXED) | ||
427 | { | 476 | { |
428 | pf = &font_ui; | 477 | /* already loaded, no need to reload */ |
429 | font_id = FONT_UI; | 478 | struct buflib_alloc_data *pd = core_get_data(buflib_allocations[font_id]); |
479 | pd->refcount++; | ||
480 | //printf("reusing handle %d for %s (count: %d)\n", font_id, path, pd->refcount); | ||
481 | return font_id; | ||
430 | } | 482 | } |
431 | else | 483 | |
484 | for (font_id = FONT_FIRSTUSERFONT; font_id < MAXFONTS; font_id++) | ||
432 | { | 485 | { |
433 | for (font_id = SYSTEMFONTCOUNT; font_id < MAXFONTS; font_id++) | 486 | handle = &buflib_allocations[font_id]; |
487 | if (*handle < 0) | ||
434 | { | 488 | { |
435 | if (sysfonts[font_id] == NULL) | 489 | break; |
436 | break; | ||
437 | } | 490 | } |
438 | if (font_id == MAXFONTS) | ||
439 | return -1; /* too many fonts */ | ||
440 | } | 491 | } |
441 | 492 | handle = &buflib_allocations[font_id]; | |
442 | if (font_id == FONT_UI) | 493 | *handle = alloc_and_init(font_id, path); |
443 | { | 494 | if (*handle < 0) |
444 | /* currently, font loading replaces earlier font allocation*/ | 495 | return -1; |
445 | buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3); | 496 | |
446 | /* make sure above doesn't exceed */ | 497 | if (handle_for_glyphcache < 0) |
447 | buffer_size = MAX_FONT_SIZE-3; | 498 | handle_for_glyphcache = *handle; |
448 | } | 499 | |
449 | else | 500 | buffer = buffer_from_handle(*handle); |
501 | buffer_size = MAX_FONT_SIZE; //FIXME | ||
502 | lock_font_handle(*handle, true); | ||
503 | |||
504 | if (!internal_load_font(font_id, path, buffer, buffer_size)) | ||
450 | { | 505 | { |
451 | buffer = pf->buffer_start; | 506 | lock_font_handle(*handle, false); |
452 | buffer_size = pf->buffer_size; | 507 | core_free(*handle); |
453 | } | 508 | *handle = -1; |
454 | |||
455 | if (!internal_load_font(pf, path, buffer, buffer_size)) | ||
456 | return -1; | 509 | return -1; |
510 | } | ||
457 | 511 | ||
458 | sysfonts[font_id] = pf; | 512 | lock_font_handle(*handle, false); |
513 | //printf("%s -> [%d] -> %d\n", path, font_id, *handle); | ||
459 | return font_id; /* success!*/ | 514 | return font_id; /* success!*/ |
460 | } | 515 | } |
461 | 516 | ||
462 | void font_unload(int font_id) | 517 | void font_unload(int font_id) |
463 | { | 518 | { |
464 | struct font* pf = sysfonts[font_id]; | 519 | int *handle = &buflib_allocations[font_id]; |
465 | if (font_id >= SYSTEMFONTCOUNT && pf) | 520 | struct buflib_alloc_data *pdata = core_get_data(*handle); |
521 | struct font* pf = &pdata->font; | ||
522 | pdata->refcount--; | ||
523 | if (pdata->refcount < 1) | ||
466 | { | 524 | { |
467 | if (pf->fd >= 0) | 525 | //printf("freeing id: %d %s\n", font_id, core_get_name(*handle)); |
526 | if (pf && pf->fd >= 0) | ||
468 | close(pf->fd); | 527 | close(pf->fd); |
469 | sysfonts[font_id] = NULL; | 528 | if (*handle > 0) |
529 | core_free(*handle); | ||
530 | if (handle_for_glyphcache == *handle) | ||
531 | handle_for_glyphcache = -1; // should find the next available handle | ||
532 | *handle = -1; | ||
470 | } | 533 | } |
471 | } | 534 | } |
472 | 535 | ||
@@ -478,14 +541,35 @@ void font_unload(int font_id) | |||
478 | struct font* font_get(int font) | 541 | struct font* font_get(int font) |
479 | { | 542 | { |
480 | struct font* pf; | 543 | struct font* pf; |
544 | if (font == FONT_UI) | ||
545 | font = MAXFONTS-1; | ||
546 | if (font <= FONT_SYSFIXED) | ||
547 | return &sysfont; | ||
481 | 548 | ||
482 | while (1) { | 549 | while (1) { |
483 | pf = sysfonts[font]; | 550 | struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[font]); |
551 | pf = &alloc->font; | ||
484 | if (pf && pf->height) | 552 | if (pf && pf->height) |
485 | return pf; | 553 | return pf; |
486 | if (--font < 0) | 554 | if (--font < 0) |
487 | panicf("No font!"); | 555 | return &sysfont; |
556 | } | ||
557 | } | ||
558 | |||
559 | static int pf_to_handle(struct font* pf) | ||
560 | { | ||
561 | int i; | ||
562 | for (i=0; i<MAXFONTS; i++) | ||
563 | { | ||
564 | int handle = buflib_allocations[i]; | ||
565 | if (handle > 0) | ||
566 | { | ||
567 | struct buflib_alloc_data *pdata = core_get_data(handle); | ||
568 | if (pf == &pdata->font) | ||
569 | return handle; | ||
570 | } | ||
488 | } | 571 | } |
572 | return -1; | ||
489 | } | 573 | } |
490 | 574 | ||
491 | /* | 575 | /* |
@@ -495,9 +579,12 @@ static void | |||
495 | load_cache_entry(struct font_cache_entry* p, void* callback_data) | 579 | load_cache_entry(struct font_cache_entry* p, void* callback_data) |
496 | { | 580 | { |
497 | struct font* pf = callback_data; | 581 | struct font* pf = callback_data; |
582 | int handle = pf_to_handle(pf); | ||
498 | unsigned short char_code = p->_char_code; | 583 | unsigned short char_code = p->_char_code; |
499 | unsigned char tmp[2]; | 584 | unsigned char tmp[2]; |
500 | 585 | ||
586 | if (handle > 0) | ||
587 | lock_font_handle(handle, true); | ||
501 | if (pf->file_width_offset) | 588 | if (pf->file_width_offset) |
502 | { | 589 | { |
503 | int width_offset = pf->file_width_offset + char_code; | 590 | int width_offset = pf->file_width_offset + char_code; |
@@ -531,6 +618,9 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data) | |||
531 | lseek(pf->fd, file_offset, SEEK_SET); | 618 | lseek(pf->fd, file_offset, SEEK_SET); |
532 | int src_bytes = glyph_bytes(pf, p->width); | 619 | int src_bytes = glyph_bytes(pf, p->width); |
533 | read(pf->fd, p->bitmap, src_bytes); | 620 | read(pf->fd, p->bitmap, src_bytes); |
621 | |||
622 | if (handle > 0) | ||
623 | lock_font_handle(handle, false); | ||
534 | } | 624 | } |
535 | 625 | ||
536 | /* | 626 | /* |
@@ -572,7 +662,7 @@ const unsigned char* font_get_bits(struct font* pf, unsigned short char_code) | |||
572 | if (pf->fd >= 0 && pf != &sysfont) | 662 | if (pf->fd >= 0 && pf != &sysfont) |
573 | { | 663 | { |
574 | bits = | 664 | bits = |
575 | (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->bitmap; | 665 | (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry, pf)->bitmap; |
576 | } | 666 | } |
577 | else | 667 | else |
578 | { | 668 | { |
@@ -594,7 +684,8 @@ static int cache_fd; | |||
594 | static void glyph_file_write(void* data) | 684 | static void glyph_file_write(void* data) |
595 | { | 685 | { |
596 | struct font_cache_entry* p = data; | 686 | struct font_cache_entry* p = data; |
597 | struct font* pf = &font_ui; | 687 | int handle = handle_for_glyphcache; |
688 | struct font* pf = pf_from_handle(handle); | ||
598 | unsigned short ch; | 689 | unsigned short ch; |
599 | unsigned char tmp[2]; | 690 | unsigned char tmp[2]; |
600 | 691 | ||
@@ -617,9 +708,9 @@ static void glyph_file_write(void* data) | |||
617 | /* save the char codes of the loaded glyphs to a file */ | 708 | /* save the char codes of the loaded glyphs to a file */ |
618 | void glyph_cache_save(struct font* pf) | 709 | void glyph_cache_save(struct font* pf) |
619 | { | 710 | { |
620 | if (!pf) | 711 | if (pf != pf_from_handle(handle_for_glyphcache)) |
621 | pf = &font_ui; | 712 | return; |
622 | if (pf->fd >= 0 && pf == &font_ui) | 713 | if (pf->fd >= 0) |
623 | { | 714 | { |
624 | cache_fd = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666); | 715 | cache_fd = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666); |
625 | if (cache_fd < 0) | 716 | if (cache_fd < 0) |
@@ -675,9 +766,10 @@ static int ushortcmp(const void *a, const void *b) | |||
675 | } | 766 | } |
676 | static void glyph_cache_load(struct font* pf) | 767 | static void glyph_cache_load(struct font* pf) |
677 | { | 768 | { |
678 | 769 | if (handle_for_glyphcache <= 0) | |
770 | return; | ||
679 | #define MAX_SORT 256 | 771 | #define MAX_SORT 256 |
680 | if (pf->fd >= 0) { | 772 | if (pf->fd >= 0 && pf == pf_from_handle(handle_for_glyphcache)) { |
681 | int fd; | 773 | int fd; |
682 | int i, size; | 774 | int i, size; |
683 | unsigned char tmp[2]; | 775 | unsigned char tmp[2]; |