FS#10984 - multifont! 2 major additions:
1) seperate UI font for the remote and main displays
2) allow individual skins to load additional fonts for use in the skin (Uo to 7 extra in this first version) see CustomWPS for info on how to load a font in the skins.

Code should always use FONT_UI+screen_number to get the correct user font


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24644 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/SOURCES b/apps/SOURCES
index 7580caa..cd7cde7 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -90,6 +90,9 @@
 gui/skin_engine/skin_buffer.c
 gui/skin_engine/wps_debug.c
 gui/skin_engine/skin_display.c
+#ifdef HAVE_LCD_BITMAP
+gui/skin_engine/skin_fonts.c
+#endif
 gui/skin_engine/skin_parser.c
 gui/skin_engine/skin_tokens.c
 
diff --git a/apps/filetree.c b/apps/filetree.c
index 6062080..c9c8b38 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -379,6 +379,32 @@
 
     return 0;
 }
+#ifdef HAVE_LCD_BITMAP
+static void ft_load_font(char *file)
+{
+#if NB_SCREENS > 1
+    MENUITEM_STRINGLIST(menu, ID2P(LANG_CUSTOM_FONT), NULL, 
+                        ID2P(LANG_MAIN_SCREEN), ID2P(LANG_REMOTE_SCREEN))
+    switch (do_menu(&menu, NULL, NULL, false))
+    {
+        case 0: /* main lcd */        
+            splash(0, ID2P(LANG_WAIT));
+            font_load(NULL, file);
+            set_file(file, (char *)global_settings.font_file, MAX_FILENAME);
+            break;
+        case 1: /* remote */
+            splash(0, ID2P(LANG_WAIT));
+            font_load_remoteui(file);
+            set_file(file, (char *)global_settings.remote_font_file, MAX_FILENAME);
+            break;
+    }
+#else
+    splash(0, ID2P(LANG_WAIT));
+    font_load(NULL, file);
+    set_file(file, (char *)global_settings.font_file, MAX_FILENAME);
+#endif
+}    
+#endif
 
 int ft_enter(struct tree_context* c)
 {
@@ -547,9 +573,7 @@
 
 #ifdef HAVE_LCD_BITMAP
             case FILE_ATTR_FONT:
-                splash(0, ID2P(LANG_WAIT));
-                font_load(buf);
-                set_file(buf, (char *)global_settings.font_file, MAX_FILENAME);
+                ft_load_font(buf);
                 break;
 
             case FILE_ATTR_KBD:
diff --git a/apps/gui/skin_engine/skin_fonts.c b/apps/gui/skin_engine/skin_fonts.c
new file mode 100644
index 0000000..1d3ef84
--- /dev/null
+++ b/apps/gui/skin_engine/skin_fonts.c
@@ -0,0 +1,139 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: skin_tokens.c 24526 2010-02-05 23:58:53Z jdgordon $
+ *
+ * Copyright (C) 2010 Jonathan Gordon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "file.h"
+#include "settings.h"
+#include "font.h"
+#include "skin_buffer.h"
+#include "skin_fonts.h"
+#define FONT_SIZE 10000
+
+
+static struct skin_font {
+    struct font font;
+    int font_id;
+    char name[MAX_PATH];
+    char *buffer;
+    int ref_count; /* how many times has this font been loaded? */
+} font_table[MAXUSERFONTS];
+
+/* need this to know if we should be closing font fd's on the next init */
+static bool first_load = true;
+
+void skin_font_init(void)
+{
+    int i;
+    for(i=0;i<MAXUSERFONTS;i++)
+    {
+        if (!first_load)
+            font_unload(font_table[i].font_id);
+        font_table[i].font_id = -1;
+        font_table[i].name[0] = '\0';
+        font_table[i].buffer = NULL;
+        font_table[i].ref_count = 0;
+    }
+}
+
+/* load a font into the skin buffer. return the font id. */
+int skin_font_load(char* font_name)
+{
+    int i;
+    struct font *pf;
+    struct skin_font *font = NULL;
+    char filename[MAX_PATH];
+    
+    if (!strcmp(font_name, global_settings.font_file))
+        return FONT_UI;
+#ifdef HAVE_REMOTE_LCD
+    if (!strcmp(font_name, global_settings.remote_font_file))
+        return FONT_UI_REMOTE;
+#endif
+    for(i=0;i<MAXUSERFONTS;i++)
+    {
+        if (font_table[i].font_id >= 0 && !strcmp(font_table[i].name, font_name))
+        {
+            font_table[i].ref_count++;
+            return font_table[i].font_id;
+        }
+        else if (!font && font_table[i].font_id == -1)
+        {
+            font = &font_table[i];
+        }
+    }
+    if (!font)
+        return -1; /* too many fonts loaded */
+    
+    pf = &font->font;
+    if (!font->buffer)
+    {
+        pf->buffer_start = skin_buffer_alloc(FONT_SIZE);
+        if (!pf->buffer_start)
+            return -1;
+        font->buffer = pf->buffer_start;
+    }
+    else
+    {
+        pf->buffer_start = font->buffer;
+    }
+    pf->buffer_size = FONT_SIZE;
+    
+    snprintf(filename, MAX_PATH, FONT_DIR "/%s.fnt", font_name);
+    strcpy(font->name, font_name);
+    
+    pf->fd = -1;
+    font->font_id = font_load(pf, filename);
+    
+    if (font->font_id < 0)
+        return -1;
+    font->ref_count = 1;    
+    
+    return font->font_id;
+}
+
+/* unload a skin font. If a font has been loaded more than once it wont actually
+ * be unloaded untill all references have been unloaded */
+void skin_font_unload(int font_id)
+{
+    int i;
+    for(i=0;i<MAXUSERFONTS;i++)
+    {
+        if (font_table[i].font_id == font_id)
+        {
+            if (--font_table[i].ref_count == 0)
+            {
+                font_unload(font_id);
+                font_table[i].font_id = -1;
+                font_table[i].name[0] = '\0';
+            }                
+            return;
+        }
+    }
+}
+    
+    
+            
+    
+
diff --git a/apps/gui/skin_engine/skin_fonts.h b/apps/gui/skin_engine/skin_fonts.h
new file mode 100644
index 0000000..3b43012
--- /dev/null
+++ b/apps/gui/skin_engine/skin_fonts.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: skin_tokens.c 24526 2010-02-05 23:58:53Z jdgordon $
+ *
+ * Copyright (C) 2010 Jonathan Gordon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "file.h"
+#include "settings.h"
+#include "font.h"
+#include "skin_buffer.h"
+
+#ifndef _SKINFONTS_H_
+#define _SKINFONTS_H_
+
+#define MAXUSERFONTS (MAXFONTS - SYSTEMFONTCOUNT)
+
+void skin_font_init(void);
+
+/* load a font into the skin buffer. return the font id. */
+int skin_font_load(char* font_name);
+
+/* unload a skin font. If a font has been loaded more than once it wont actually
+ * be unloaded untill all references have been unloaded */
+void skin_font_unload(int font_id);
+    
+#endif
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index 4655bf0..034ff53 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -52,6 +52,7 @@
 #include "skin_engine.h"
 #include "settings.h"
 #include "settings_list.h"
+#include "skin_fonts.h"
 
 #ifdef HAVE_LCD_BITMAP
 #include "bmp.h"
@@ -157,6 +158,8 @@
         struct wps_token *token, struct wps_data *wps_data);
 static int parse_image_load(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data);
+static int parse_font_load(const char *wps_bufptr,
+        struct wps_token *token, struct wps_data *wps_data);
 #endif /*HAVE_LCD_BITMAP */
 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
 static int parse_image_special(const char *wps_bufptr,
@@ -353,6 +356,7 @@
                                                        parse_image_display },
 
     { WPS_TOKEN_IMAGE_DISPLAY,            "x",   0,       parse_image_load },
+    { WPS_NO_TOKEN,                       "Fl",  0,       parse_font_load },
 #ifdef HAVE_ALBUMART
     { WPS_NO_TOKEN,                       "Cl",  0,    parse_albumart_load },
     { WPS_TOKEN_ALBUMART_DISPLAY,         "C",   WPS_REFRESH_STATIC,  parse_albumart_display },
@@ -688,6 +692,39 @@
     return skip_end_of_line(wps_bufptr);
 }
 
+static int font_ids[MAXUSERFONTS];
+static int parse_font_load(const char *wps_bufptr,
+        struct wps_token *token, struct wps_data *wps_data)
+{
+    (void)wps_data; (void)token;
+    const char *ptr = wps_bufptr;
+    int id;
+    char *filename, buf[MAX_PATH];
+    
+    if (*ptr != '|')
+        return WPS_ERROR_INVALID_PARAM;
+
+    ptr++;
+
+    if (!(ptr = parse_list("ds", NULL, '|', ptr, &id, &filename)))
+        return WPS_ERROR_INVALID_PARAM;
+
+    /* Check there is a terminating | */
+    if (*ptr != '|')
+        return WPS_ERROR_INVALID_PARAM;
+        
+    if (id <= FONT_UI || id >= MAXFONTS-1)
+        return WPS_ERROR_INVALID_PARAM;
+    id -= SYSTEMFONTCOUNT;
+    
+    memcpy(buf, filename, ptr-filename);
+    buf[ptr-filename] = '\0';
+    font_ids[id] = skin_font_load(buf);
+    
+    return font_ids[id] >= 0 ? skip_end_of_line(wps_bufptr) : WPS_ERROR_INVALID_PARAM;
+}
+    
+    
 static int parse_viewport_display(const char *wps_bufptr,
                                   struct wps_token *token,
                                   struct wps_data *wps_data)
@@ -890,7 +927,8 @@
     else
         vp->flags &= ~VP_FLAG_ALIGN_RIGHT; /* ignore right-to-left languages */
 
-
+    if (vp->font >= SYSTEMFONTCOUNT)
+        vp->font = font_ids[vp->font - SYSTEMFONTCOUNT];
 
     struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp);
     if (!list)
diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c
index 9d447f6..fac6756 100644
--- a/apps/gui/statusbar-skinned.c
+++ b/apps/gui/statusbar-skinned.c
@@ -32,6 +32,7 @@
 #include "statusbar.h"
 #include "statusbar-skinned.h"
 #include "debug.h"
+#include "font.h"
 
 
 /* currently only one wps_state is needed */
@@ -183,7 +184,8 @@
             default:
                 height = screens[screen].lcdheight;
         }
-        len = snprintf(ptr, remaining, "%%ax%%Vi|0|%d|-|%d|1|-|-|\n", y, height);
+        len = snprintf(ptr, remaining, "%%ax%%Vi|0|%d|-|%d|%d|-|-|\n", 
+                       y, height, FONT_UI + screen);
     }
     sb_skin_data_load(screen, buf, false);
 }
diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c
index eaee2cc..ee233b9 100644
--- a/apps/gui/viewport.c
+++ b/apps/gui/viewport.c
@@ -315,7 +315,7 @@
 #ifndef __PCTOOL__
     set_default_align_flags(vp);
 #endif
-    vp->font = FONT_UI; /* default to UI to discourage SYSFONT use */
+    vp->font = FONT_UI + screen; /* default to UI to discourage SYSFONT use */
     vp->drawmode = DRMODE_SOLID;
 #if LCD_DEPTH > 1
 #ifdef HAVE_REMOTE_LCD
@@ -453,11 +453,15 @@
         return NULL;
     }
 
-    /* Default to using the user font if the font was an invalid number or '-'*/
-    if (((vp->font != FONT_SYSFIXED) && (vp->font != FONT_UI))
-            || !LIST_VALUE_PARSED(set, PL_FONT)
-            )
-        vp->font = FONT_UI;
+    /* Default to using the user font if the font was an invalid number or '-'
+     * font 1 is *always* the UI font for the current screen
+     * 2 is always the first extra font    */
+    if (!LIST_VALUE_PARSED(set, PL_FONT))
+        vp->font = FONT_UI + screen;
+#ifdef HAVE_REMOTE_LCD
+    else if (vp->font == FONT_UI && screen == SCREEN_REMOTE)
+        vp->font = FONT_UI_REMOTE;
+#endif
 
     /* Set the defaults for fields not user-specified */
     vp->drawmode = DRMODE_SOLID;
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index afb60e1..ecbd415 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -13315,3 +13315,37 @@
     lcd_bitmap: "Remote Base Skin"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_MAIN_SCREEN
+  desc: in the main menu
+  user: core
+  <source>
+    *:none
+    remote: "Main Screen"
+  </source>
+  <dest>
+    *:none
+    remote: "Main Screen"
+  </dest>
+  <voice>
+    *:none
+    remote: "Main Screen"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_REMOTE_SCREEN
+  desc: in the main menu
+  user: core
+  <source>
+    *:none
+    remote: "Remote Screen"
+  </source>
+  <dest>
+    *:none
+    remote: "Remote Screen"
+  </dest>
+  <voice>
+    *:none
+    remote: "Remote Screen"
+  </voice>
+</phrase>
diff --git a/apps/plugin.c b/apps/plugin.c
index 0d4d8ed..46ab6e6 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -247,6 +247,10 @@
     lcd_remote_bitmap,
 #endif
     viewport_set_defaults,
+#ifdef HAVE_LCD_BITMAP
+    viewportmanager_theme_enable,
+    viewportmanager_theme_undo,
+#endif
     
     /* list */
     gui_synclist_init,
@@ -292,6 +296,7 @@
 #endif /* HAVE_BUTTON_LIGHT */
 
     /* file */
+    open_utf8,
 #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
     (open_func)open_wrapper,
     close_wrapper,
@@ -325,6 +330,7 @@
     create_numbered_filename,
     file_exists,
     strip_extension,
+    crc_32,
 
     /* dir */
     opendir,
@@ -432,6 +438,7 @@
     atoi,
     strchr,
     strcat,
+    strlcat,
     memchr,
     memcmp,
     strcasestr,
@@ -476,6 +483,7 @@
     pcm_get_peak_buffer,
     pcm_play_lock,
     pcm_play_unlock,
+    pcmbuf_beep,
 #ifdef HAVE_RECORDING
     &rec_freq_sampr[0],
     pcm_init_recording,
@@ -588,6 +596,9 @@
 #endif
 
     /* misc */
+#if !defined(SIMULATOR) || defined(__MINGW32__) || defined(__CYGWIN__)
+    &errno,
+#endif
     srand,
     rand,
     (qsort_func)qsort,
@@ -698,19 +709,6 @@
     appsversion,
     /* new stuff at the end, sort into place next time
        the API gets incompatible */
-#if (CONFIG_CODEC == SWCODEC)
-    pcmbuf_beep,
-#endif
-    crc_32,
-    open_utf8,
-#ifdef HAVE_LCD_BITMAP
-    viewportmanager_theme_enable,
-    viewportmanager_theme_undo,
-#endif
-#if !defined(SIMULATOR) || defined(__MINGW32__) || defined(__CYGWIN__)
-    &errno,
-#endif
-    strlcat,
 };
 
 int plugin_load(const char* plugin, const void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index e5766c6..b1cfa30 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -135,12 +135,12 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 180
+#define PLUGIN_API_VERSION 181
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
    new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 180
+#define PLUGIN_MIN_API_VERSION 181
 
 /* plugin return codes */
 enum plugin_status {
@@ -250,7 +250,7 @@
 #endif
     unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation );
     const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code );
-    struct font* (*font_load)(const char *path);
+    int (*font_load)(struct font*, const char *path);
     struct font* (*font_get)(int font);
     int  (*font_getstringsize)(const unsigned char *str, int *w, int *h,
                                int fontnumber);
@@ -336,7 +336,12 @@
                               int width, int height);
 #endif
     void (*viewport_set_defaults)(struct viewport *vp,
-                                  const enum screen_type screen);
+                                  const enum screen_type screen);                                  
+#ifdef HAVE_LCD_BITMAP
+    void (*viewportmanager_theme_enable)(enum screen_type screen, bool enable,
+                                         struct viewport *viewport);
+    void (*viewportmanager_theme_undo)(enum screen_type screen, bool force_redraw);
+#endif
     /* list */
     void (*gui_synclist_init)(struct gui_synclist * lists,
             list_get_name callback_get_item_name, void * data,
@@ -390,6 +395,7 @@
 #endif /* HAVE_BUTTON_LIGHT */
 
     /* file */
+    int (*open_utf8)(const char* pathname, int flags);
     int (*open)(const char* pathname, int flags);
     int (*close)(int fd);
     ssize_t (*read)(int fd, void* buf, size_t count);
@@ -416,6 +422,7 @@
                                       int numberlen IF_CNFN_NUM_(, int *num));
     bool (*file_exists)(const char *file);
     char* (*strip_extension)(char* buffer, int buffer_size, const char *filename);
+    unsigned (*crc_32)(const void *src, unsigned len, unsigned crc32);
 
 
     /* dir */
@@ -537,6 +544,7 @@
     int (*atoi)(const char *str);
     char *(*strchr)(const char *s, int c);
     char *(*strcat)(char *s1, const char *s2);
+    size_t (*strlcat)(char *dst, const char *src, size_t length);
     void *(*memchr)(const void *s1, int c, size_t n);
     int (*memcmp)(const void *s1, const void *s2, size_t n);
     char *(*strcasestr) (const char* phaystack, const char* pneedle);
@@ -583,6 +591,9 @@
     const void* (*pcm_get_peak_buffer)(int *count);
     void (*pcm_play_lock)(void);
     void (*pcm_play_unlock)(void);
+    void (*pcmbuf_beep)(unsigned int frequency,
+                        size_t duration,
+                        int amplitude);
 #ifdef HAVE_RECORDING
     const unsigned long *rec_freq_sampr;
     void (*pcm_init_recording)(void);
@@ -716,6 +727,9 @@
 #endif
 
     /* misc */
+#if !defined(SIMULATOR) || defined(__MINGW32__) || defined(__CYGWIN__)
+    int* __errno;
+#endif
     void (*srand)(unsigned int seed);
     int  (*rand)(void);
     void (*qsort)(void *base, size_t nmemb, size_t size,
@@ -848,23 +862,6 @@
     const char *appsversion;
     /* new stuff at the end, sort into place next time
        the API gets incompatible */
-
-#if (CONFIG_CODEC == SWCODEC)
-    void (*pcmbuf_beep)(unsigned int frequency,
-                        size_t duration,
-                        int amplitude);
-#endif
-    unsigned (*crc_32)(const void *src, unsigned len, unsigned crc32);
-    int (*open_utf8)(const char* pathname, int flags);
-#ifdef HAVE_LCD_BITMAP
-    void (*viewportmanager_theme_enable)(enum screen_type screen, bool enable,
-                                         struct viewport *viewport);
-    void (*viewportmanager_theme_undo)(enum screen_type screen, bool force_redraw);
-#endif
-#if !defined(SIMULATOR) || defined(__MINGW32__) || defined(__CYGWIN__)
-    int* __errno;
-#endif
-    size_t (*strlcat)(char *dst, const char *src, size_t length);
 };
 
 /* plugin header */
diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c
index 96de7ab..ae28258 100644
--- a/apps/plugins/rockpaint.c
+++ b/apps/plugins/rockpaint.c
@@ -854,7 +854,7 @@
                     continue;
                 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
                               de->d_name );
-                rb->font_load( bbuf );
+                rb->font_load(NULL, bbuf );
                 rb->font_getstringsize( de->d_name, &fw, &fh, FONT_UI );
                 if( nvih > 0 )
                 {
@@ -887,12 +887,12 @@
                 {
                     rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
                           de->d_name );
-                    rb->font_load( bbuf );
+                    rb->font_load(NULL, bbuf );
                     rb->font_getstringsize( de->d_name, NULL, &fh, FONT_UI );
                     nvih = fh;
                 }
             }
-            rb->font_load( buffer.text.old_font );
+            rb->font_load(NULL, buffer.text.old_font );
             rb->closedir( d );
         }
 
@@ -1526,7 +1526,7 @@
             case TEXT_MENU_FONT:
                 if( browse_fonts( buffer.text.font, MAX_PATH ) )
                 {
-                    rb->font_load( buffer.text.font );
+                    rb->font_load(NULL, buffer.text.font );
                 }
                 break;
 
@@ -1583,7 +1583,7 @@
             case TEXT_MENU_CANCEL:
             default:
                 restore_screen();
-                rb->font_load( buffer.text.old_font );
+                rb->font_load(NULL, buffer.text.old_font );
                 return;
         }
     }
diff --git a/apps/settings.c b/apps/settings.c
index becb516..574aa27 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -68,6 +68,7 @@
 #endif
 #include "wps.h"
 #include "skin_engine/skin_engine.h"
+#include "skin_engine/skin_fonts.h"
 #include "viewport.h"
 #include "statusbar-skinned.h"
 
@@ -740,6 +741,7 @@
     /* re-initialize the skin buffer before we start reloading skins */
     skin_buffer_init();
 #ifdef HAVE_LCD_BITMAP
+    skin_font_init();
     if ( global_settings.sbs_file[0] &&
         global_settings.sbs_file[0] != 0xff )
     {
@@ -887,18 +889,26 @@
 
     if (read_disk)
     {
-        
 #ifdef HAVE_LCD_BITMAP
         /* fonts need to be loaded before the WPS */
         if ( global_settings.font_file[0]) {
             snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
                      global_settings.font_file);
-            if (font_load(buf) == NULL)
-                font_reset();
+            if (font_load(NULL, buf) < 0)
+                font_reset(NULL);
         }
         else
-            font_reset();
-    
+            font_reset(NULL);
+#ifdef HAVE_REMOTE_LCD        
+        if ( global_settings.remote_font_file[0]) {
+            snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                     global_settings.remote_font_file);
+            if (font_load_remoteui(buf) < 0)
+                font_load_remoteui(NULL);
+        }
+        else
+            font_load_remoteui(NULL);
+#endif
         if ( global_settings.kbd_file[0]) {
             snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
                      global_settings.kbd_file);
diff --git a/apps/settings.h b/apps/settings.h
index ea7138c..6a42ca3 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -681,6 +681,9 @@
     unsigned char icon_file[MAX_FILENAME+1];
     unsigned char viewers_icon_file[MAX_FILENAME+1];
     unsigned char font_file[MAX_FILENAME+1]; /* last font */
+#ifdef HAVE_REMOTE_LCD
+    unsigned char remote_font_file[MAX_FILENAME+1]; /* last font */
+#endif
     unsigned char kbd_file[MAX_FILENAME+1];  /* last keyboard */
 #endif /* HAVE_LCD_BITMAP */
 
diff --git a/apps/settings_list.c b/apps/settings_list.c
index c5f9932..d2700b3 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -1432,6 +1432,10 @@
     TEXT_SETTING(F_THEMESETTING, font_file, "font",
                      DEFAULT_FONTNAME, FONT_DIR "/", ".fnt"),
 #endif
+#ifdef HAVE_REMOTE_LCD
+    TEXT_SETTING(F_THEMESETTING, remote_font_file, "remote font",
+                     "", FONT_DIR "/", ".fnt"),
+#endif
     TEXT_SETTING(F_THEMESETTING,wps_file, "wps",
                      DEFAULT_WPSNAME, WPS_DIR "/", ".wps"),
 #ifdef HAVE_LCD_BITMAP
diff --git a/firmware/export/font.h b/firmware/export/font.h
index 0fe6c30..e9bf086 100644
--- a/firmware/export/font.h
+++ b/firmware/export/font.h
@@ -30,6 +30,7 @@
 
 #if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
 #ifndef __PCTOOL__
+#include "font_cache.h"
 #include "sysfont.h"
 #endif
 
@@ -47,9 +48,14 @@
 enum {
     FONT_SYSFIXED, /* system fixed pitch font*/
     FONT_UI,       /* system porportional font*/
-    MAXFONTS
+#ifdef HAVE_REMOTE_LCD
+    FONT_UI_REMOTE, /* UI font for remote LCD */
+#endif
+    SYSTEMFONTCOUNT /* Number of fonts reserved for the system and ui */
 };
 
+#define MAXFONTS 10
+
 /*
  * .fnt loadable font file format definition
  *
@@ -89,17 +95,38 @@
     const unsigned char *width;   /* character widths or NULL if fixed*/
     int          defaultchar;     /* default char (not glyph index)*/
     int32_t      bits_size;       /* # bytes of glyph bits*/
+    
+    /* file, buffer and cache management */
+    int          fd;              /* fd for the font file. >= 0 if cached */
+    unsigned char *buffer_start;    /* buffer to store the font in */       
+    unsigned char *buffer_position; /* position in the buffer */    
+    unsigned char *buffer_end;      /* end of the buffer */
+    int          buffer_size;       /* size of the buffer in bytes */
+#ifndef __PCTOOL__    
+    struct font_cache cache;
+    uint32_t file_width_offset;    /* offset to file width data    */
+    uint32_t file_offset_offset;   /* offset to file offset data   */
+    int long_offset;
+#endif    
+    
 };
 
 /* font routines*/
 void font_init(void);
-struct font* font_load(const char *path);
+#ifdef HAVE_REMOTE_LCD
+/* Load a font into the special remote ui font slot */
+int font_load_remoteui(const char* path);
+#endif
+int font_load(struct font* pf, const char *path);
+void font_unload(int font_id);
+
 struct font* font_get(int font);
-void font_reset(void);
+
+void font_reset(struct font *pf);
 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber);
 int font_get_width(struct font* ft, unsigned short ch);
 const unsigned char * font_get_bits(struct font* ft, unsigned short ch);
-void glyph_cache_save(void);
+void glyph_cache_save(struct font* pf);
 
 #else /* HAVE_LCD_BITMAP */
 
diff --git a/firmware/font.c b/firmware/font.c
index a8734e9..52c6ffa 100644
--- a/firmware/font.c
+++ b/firmware/font.c
@@ -75,64 +75,77 @@
 
 /* structure filled in by font_load */
 static struct font font_ui;
+/* static buffer allocation structures */
+static unsigned char main_buf[MAX_FONT_SIZE];
+#ifdef HAVE_REMOTE_LCD
+#define REMOTE_FONT_SIZE 10000
+static struct font remote_font_ui;
+static unsigned char remote_buf[REMOTE_FONT_SIZE];
+#endif
 
 /* system font table, in order of FONT_xxx definition */
-static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
+static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL};
 
-/* static buffer allocation structures */
-static unsigned char mbuf[MAX_FONT_SIZE];
-static unsigned char *freeptr = mbuf;
-static unsigned char *fileptr;
-static unsigned char *eofptr;
 
 /* Font cache structures */
-static struct font_cache font_cache_ui;
-static int fnt_file = -1;           /* >=0 if font is cached   */
-static uint32_t file_width_offset;    /* offset to file width data    */
-static uint32_t file_offset_offset;   /* offset to file offset data   */
-static void cache_create(int maxwidth, int height);
-static int long_offset = 0;
-static int glyph_file;
+static void cache_create(struct font* pf, int maxwidth, int height);
+static void glyph_cache_load(struct font* pf);
 /* End Font cache structures */
 
-static void glyph_cache_load(void);
-
 void font_init(void)
 {
-    memset(&font_ui, 0, sizeof(struct font));
+    int i = SYSTEMFONTCOUNT;
+    while (i<MAXFONTS)
+        sysfonts[i++] = NULL;
+    font_reset(NULL);
 }
 
 /* Check if we have x bytes left in the file buffer */
-#define HAVEBYTES(x) (fileptr + (x) <= eofptr)
+#define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
 
 /* Helper functions to read big-endian unaligned short or long from
    the file buffer.  Bounds-checking must be done in the calling
    function.
  */
 
-static short readshort(void)
+static short readshort(struct font *pf)
 {
     unsigned short s;
 
-    s = *fileptr++ & 0xff;
-    s |= (*fileptr++ << 8);
+    s = *pf->buffer_position++ & 0xff;
+    s |= (*pf->buffer_position++ << 8);
     return s;
 }
 
-static int32_t readlong(void)
+static int32_t readlong(struct font *pf)
 {
     uint32_t l;
 
-    l = *fileptr++ & 0xff;
-    l |= *fileptr++ << 8;
-    l |= ((uint32_t)(*fileptr++)) << 16;
-    l |= ((uint32_t)(*fileptr++)) << 24;
+    l = *pf->buffer_position++ & 0xff;
+    l |= *pf->buffer_position++ << 8;
+    l |= ((uint32_t)(*pf->buffer_position++)) << 16;
+    l |= ((uint32_t)(*pf->buffer_position++)) << 24;
     return l;
 }
 
-void font_reset(void)
+void font_reset(struct font *pf)
 {
-    memset(&font_ui, 0, sizeof(struct font));
+    unsigned char* buffer = NULL;
+    size_t buf_size = 0;
+    if (pf == NULL)
+        pf = &font_ui;
+    else
+    {
+        buffer = pf->buffer_start;
+        buf_size = pf->buffer_size;
+    }
+    memset(pf, 0, sizeof(struct font));
+    pf->fd = -1;
+    if (buffer)
+    {
+        pf->buffer_start = buffer;
+        pf->buffer_size = buf_size;
+    }
 }
 
 static struct font* font_load_header(struct font *pf)
@@ -142,23 +155,23 @@
         return NULL;
 
     /* read magic and version #*/
-    if (memcmp(fileptr, VERSION, 4) != 0)
+    if (memcmp(pf->buffer_position, VERSION, 4) != 0)
         return NULL;
 
-    fileptr += 4;
+    pf->buffer_position += 4;
 
     /* font info*/
-    pf->maxwidth = readshort();
-    pf->height = readshort();
-    pf->ascent = readshort();
-    fileptr += 2; /* Skip padding */
-    pf->firstchar = readlong();
-    pf->defaultchar = readlong();
-    pf->size = readlong();
+    pf->maxwidth = readshort(pf);
+    pf->height = readshort(pf);
+    pf->ascent = readshort(pf);
+    pf->buffer_position += 2; /* Skip padding */
+    pf->firstchar = readlong(pf);
+    pf->defaultchar = readlong(pf);
+    pf->size = readlong(pf);
 
     /* get variable font data sizes*/
     /* # words of bitmap_t*/
-    pf->bits_size = readlong();
+    pf->bits_size = readlong(pf);
 
     return pf;
 }
@@ -171,32 +184,32 @@
         return NULL;
 
     /* # longs of offset*/
-    noffset = readlong();
+    noffset = readlong(pf);
 
     /* # bytes of width*/
-    nwidth = readlong();
+    nwidth = readlong(pf);
 
     /* variable font data*/
-    pf->bits = (unsigned char *)fileptr;
-    fileptr += pf->bits_size*sizeof(unsigned char);
+    pf->bits = (unsigned char *)pf->buffer_position;
+    pf->buffer_position += pf->bits_size*sizeof(unsigned char);
 
     if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
     {
         /* pad to 16-bit boundary */
-        fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
+        pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
     }
     else
     {
         /* pad to 32-bit boundary*/
-        fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
+        pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
     }
 
     if (noffset)
     {
         if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
         {
-            long_offset = 0;
-            pf->offset = (uint16_t*)fileptr;
+            pf->long_offset = 0;
+            pf->offset = (uint16_t*)pf->buffer_position;
 
             /* Check we have sufficient buffer */
             if (!HAVEBYTES(noffset * sizeof(uint16_t)))
@@ -204,13 +217,13 @@
 
             for (i=0; i<noffset; ++i)
             {
-                ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort();
+                ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
             }
         }
         else
         {
-            long_offset = 1;
-            pf->offset = (uint16_t*)fileptr;
+            pf->long_offset = 1;
+            pf->offset = (uint16_t*)pf->buffer_position;
 
             /* Check we have sufficient buffer */
             if (!HAVEBYTES(noffset * sizeof(int32_t)))
@@ -218,7 +231,7 @@
 
             for (i=0; i<noffset; ++i)
             {
-                ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong();
+                ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
             }
         }
     }
@@ -226,13 +239,13 @@
         pf->offset = NULL;
 
     if (nwidth) {
-        pf->width = (unsigned char *)fileptr;
-        fileptr += nwidth*sizeof(unsigned char);
+        pf->width = (unsigned char *)pf->buffer_position;
+        pf->buffer_position += nwidth*sizeof(unsigned char);
     }
     else
         pf->width = NULL;
 
-    if (fileptr > eofptr)
+    if (pf->buffer_position > pf->buffer_end)
         return NULL;
 
     return pf;    /* success!*/
@@ -242,135 +255,203 @@
 static struct font* font_load_cached(struct font* pf)
 {
     uint32_t noffset, nwidth;
-    unsigned char* oldfileptr = fileptr;
+    unsigned char* oldfileptr = pf->buffer_position;
 
     if (!HAVEBYTES(2 * sizeof(int32_t)))
         return NULL;
 
     /* # longs of offset*/
-    noffset = readlong();
+    noffset = readlong(pf);
 
     /* # bytes of width*/
-    nwidth = readlong();
+    nwidth = readlong(pf);
 
     /* We are now at the bitmap data, this is fixed at 36.. */
     pf->bits = NULL;
 
     /* Calculate offset to offset data */
-    fileptr += pf->bits_size * sizeof(unsigned char);
+    pf->buffer_position += pf->bits_size * sizeof(unsigned char);
 
     if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
     {
-        long_offset = 0;
+        pf->long_offset = 0;
         /* pad to 16-bit boundary */
-        fileptr = (unsigned char *)(((intptr_t)fileptr + 1) & ~1);
+        pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
     }
     else
     {
-        long_offset = 1;
+        pf->long_offset = 1;
         /* pad to 32-bit boundary*/
-        fileptr = (unsigned char *)(((intptr_t)fileptr + 3) & ~3);
+        pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
     }
 
     if (noffset)
-        file_offset_offset = (uint32_t)(fileptr - freeptr);
+        pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
     else
-        file_offset_offset = 0;
+        pf->file_offset_offset = 0;
 
     /* Calculate offset to widths data */
     if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
-        fileptr += noffset * sizeof(uint16_t);
+        pf->buffer_position += noffset * sizeof(uint16_t);
     else
-        fileptr += noffset * sizeof(uint32_t);
+        pf->buffer_position += noffset * sizeof(uint32_t);
 
     if (nwidth)
-        file_width_offset = (uint32_t)(fileptr - freeptr);
+        pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
     else
-        file_width_offset = 0;
+        pf->file_width_offset = 0;
 
-    fileptr = oldfileptr;
+    pf->buffer_position = oldfileptr;
 
     /* Create the cache */
-    cache_create(pf->maxwidth, pf->height);
+    cache_create(pf, pf->maxwidth, pf->height);
 
     return pf;
 }
 
-/* read and load font into incore font structure*/
-struct font* font_load(const char *path)
+static bool internal_load_font(struct font* pf, const char *path,
+                               char *buf, size_t buf_size)
 {
     int size;
-    struct font* pf = &font_ui;
-
+    
     /* save loaded glyphs */
-    glyph_cache_save();
-
+    glyph_cache_save(pf);
     /* Close font file handle */
-    if (fnt_file >= 0)
-        close(fnt_file);
+    if (pf->fd >= 0)
+        close(pf->fd);
+
+    font_reset(pf);
 
     /* open and read entire font file*/
-    fnt_file = open(path, O_RDONLY|O_BINARY);
+    pf->fd = open(path, O_RDONLY|O_BINARY);
 
-    if (fnt_file < 0) {
+    if (pf->fd < 0) {
         DEBUGF("Can't open font: %s\n", path);
-        return NULL;
+        return false;
     }
 
     /* Check file size */
-    size = filesize(fnt_file);
-
-    font_reset();
-
-    /* currently, font loading replaces earlier font allocation*/
-    freeptr = (unsigned char *)(((intptr_t)mbuf + 3) & ~3);
-    fileptr = freeptr;
-
-
-    if (size > MAX_FONT_SIZE)
+    size = filesize(pf->fd);
+    pf->buffer_start = buf;
+    pf->buffer_size = buf_size;
+    
+    pf->buffer_position = buf;
+    
+    if (size > pf->buffer_size)
     {
-        read(fnt_file, fileptr, FONT_HEADER_SIZE);
-        eofptr = fileptr + FONT_HEADER_SIZE;
+        read(pf->fd, pf->buffer_position, FONT_HEADER_SIZE);
+        pf->buffer_end = pf->buffer_position + FONT_HEADER_SIZE;
 
         if (!font_load_header(pf))
         {
             DEBUGF("Failed font header load");
-            return NULL;
+            return false;
         }
 
         if (!font_load_cached(pf))
         {
             DEBUGF("Failed font cache load");
-            return NULL;
+            return false;
         }
 
-        glyph_cache_load();
+        glyph_cache_load(pf);
     }
     else
     {
-        read(fnt_file, fileptr, MAX_FONT_SIZE);
-        eofptr = fileptr + size;
-        close(fnt_file);
-        fnt_file = -1;
+        read(pf->fd, pf->buffer_position, pf->buffer_size);
+        pf->buffer_end = pf->buffer_position + size;
+        close(pf->fd);
+        pf->fd = -1;
 
         if (!font_load_header(pf))
         {
             DEBUGF("Failed font header load");
-            return NULL;
+            return false;
         }
 
         if (!font_load_in_memory(pf))
         {
             DEBUGF("Failed mem load");
-            return NULL;
+            return false;
         }
     }
+    return true;
+}
+    
+#ifdef HAVE_REMOTE_LCD
+/* Load a font into the special remote ui font slot */
+int font_load_remoteui(const char* path)
+{
+    struct font* pf = &remote_font_ui;
+    if (!path)
+    {
+        if (sysfonts[FONT_UI_REMOTE] && sysfonts[FONT_UI_REMOTE] != sysfonts[FONT_UI])
+            font_unload(FONT_UI_REMOTE);
+        sysfonts[FONT_UI_REMOTE] = NULL;
+        return FONT_UI;
+    }
+    if (!internal_load_font(pf, path, remote_buf, REMOTE_FONT_SIZE))
+    {
+        sysfonts[FONT_UI_REMOTE] = NULL;
+        return -1;
+    }
+    
+    sysfonts[FONT_UI_REMOTE] = pf;
+    return FONT_UI_REMOTE;
+}
+#endif
 
-    /* no need for multiple font loads currently*/
-    /*freeptr += filesize;*/
-    /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/  /* pad freeptr*/
+/* read and load font into incore font structure,
+ * returns the font number on success, -1 on failure */
+int font_load(struct font* pf, const char *path)
+{
+    int font_id = -1;
+    char *buffer;
+    size_t buffer_size;
+    if (pf == NULL)
+    {
+        pf = &font_ui;
+        font_id = FONT_UI;
+    }
+    else
+    {
+        for (font_id = SYSTEMFONTCOUNT; font_id < MAXFONTS; font_id++)
+        {
+            if (sysfonts[font_id] == NULL)
+                break;
+        }
+        if (font_id == MAXFONTS)
+            return -1; /* too many fonts */
+    }
+    
+    if (font_id == FONT_UI)
+    {
+        /* currently, font loading replaces earlier font allocation*/
+        buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3);
+        buffer_size = MAX_FONT_SIZE;
+    }
+    else
+    {
+        buffer = pf->buffer_start;
+        buffer_size = pf->buffer_size;
+    }
+    
+    if (!internal_load_font(pf, path, buffer, buffer_size))
+        return -1;
+        
+    sysfonts[font_id] = pf;
+    return font_id; /* success!*/
+}
 
-    return pf; /* success!*/
+void font_unload(int font_id)
+{
+    struct font* pf = sysfonts[font_id];
+    if (font_id >= SYSTEMFONTCOUNT && pf)
+    {
+        if (pf->fd >= 0)
+            close(pf->fd);
+        sysfonts[font_id] = NULL;
+    }
 }
 
 /*
@@ -382,9 +463,6 @@
 {
     struct font* pf;
 
-    if (font >= MAXFONTS)
-        font = 0;
-
     while (1) {
         pf = sysfonts[font];
         if (pf && pf->height)
@@ -404,11 +482,11 @@
     unsigned short char_code = p->_char_code;
     unsigned char tmp[2];
  
-    if (file_width_offset)
+    if (pf->file_width_offset)
     {
-        int width_offset = file_width_offset + char_code;
-        lseek(fnt_file, width_offset, SEEK_SET);
-        read(fnt_file, &(p->width), 1);
+        int width_offset = pf->file_width_offset + char_code;
+        lseek(pf->fd, width_offset, SEEK_SET);
+        read(pf->fd, &(p->width), 1);
     }
     else
     {
@@ -417,14 +495,14 @@
  
     int32_t bitmap_offset = 0;
 
-    if (file_offset_offset)
+    if (pf->file_offset_offset)
     {
-        int32_t offset = file_offset_offset + char_code * (long_offset ? sizeof(int32_t) : sizeof(int16_t));
-        lseek(fnt_file, offset, SEEK_SET);
-        read (fnt_file, tmp, 2);
+        int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
+        lseek(pf->fd, offset, SEEK_SET);
+        read (pf->fd, tmp, 2);
         bitmap_offset = tmp[0] | (tmp[1] << 8);
-        if (long_offset) {
-            read (fnt_file, tmp, 2);
+        if (pf->long_offset) {
+            read (pf->fd, tmp, 2);
             bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
         }
     }
@@ -434,22 +512,22 @@
     }
 
     int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
-    lseek(fnt_file, file_offset, SEEK_SET);
+    lseek(pf->fd, file_offset, SEEK_SET);
 
     int src_bytes = p->width * ((pf->height + 7) / 8);
-    read(fnt_file, p->bitmap, src_bytes);
+    read(pf->fd, p->bitmap, src_bytes);
 }
 
 /*
  * Converts cbuf into a font cache
  */
-static void cache_create(int maxwidth, int height)
+static void cache_create(struct font* pf, int maxwidth, int height)
 {
     /* maximum size of rotated bitmap */
     int bitmap_size = maxwidth * ((height + 7) / 8);
     
     /* Initialise cache */
-    font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
+    font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
 }
 
 /*
@@ -462,8 +540,8 @@
         char_code = pf->defaultchar;
     char_code -= pf->firstchar;
 
-    return (fnt_file >= 0 && pf != &sysfont)?
-        font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
+    return (pf->fd >= 0 && pf != &sysfont)?
+        font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->width:
         pf->width? pf->width[char_code]: pf->maxwidth;
 }
  
@@ -476,10 +554,10 @@
         char_code = pf->defaultchar;
     char_code -= pf->firstchar;
 
-    if (fnt_file >= 0 && pf != &sysfont)
+    if (pf->fd >= 0 && pf != &sysfont)
     {
         bits =
-            (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
+            (unsigned char*)font_cache_get(&pf->cache,char_code,load_cache_entry,pf)->bitmap;
     }
     else
     {
@@ -497,7 +575,7 @@
 
     return bits;
 }
-
+static int cache_fd;
 static void glyph_file_write(void* data)
 {
     struct font_cache_entry* p = data;
@@ -507,45 +585,48 @@
 
     ch = p->_char_code + pf->firstchar;
 
-    if (ch != 0xffff && glyph_file >= 0) {
+    if (ch != 0xffff && cache_fd >= 0) {
         tmp[0] = ch >> 8;
         tmp[1] = ch & 0xff;
-        if (write(glyph_file, tmp, 2) != 2) {
-            close(glyph_file);
-            glyph_file = -1;
+        if (write(cache_fd, tmp, 2) != 2) {
+            close(cache_fd);
+            cache_fd = -1;
         }
     }
     return;
 }
 
 /* save the char codes of the loaded glyphs to a file */
-void glyph_cache_save(void)
+void glyph_cache_save(struct font* pf)
 {
-
-    if (fnt_file >= 0) {
+    if (!pf)
+        pf = &font_ui;
+    if (pf->fd >= 0 && pf == &font_ui) 
+    {
 #ifdef WPSEDITOR
-        glyph_file = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
+        cache_fd = open(GLYPH_CACHE_FILE, O_WRONLY|O_CREAT|O_TRUNC);
 #else
-        glyph_file = creat(GLYPH_CACHE_FILE);
+        cache_fd = creat(GLYPH_CACHE_FILE);
 #endif
-        if (glyph_file < 0) return;
+        if (cache_fd < 0) return;
 
-        lru_traverse(&font_cache_ui._lru, glyph_file_write);
-
-        if (glyph_file >= 0)
-            close(glyph_file);
+        lru_traverse(&pf->cache._lru, glyph_file_write);
+        
+        if (cache_fd < 0)
+        {
+            close(cache_fd);
+            cache_fd = -1;
+        }
     }
     return;
 }
 
-static void glyph_cache_load(void)
+static void glyph_cache_load(struct font* pf)
 {
-    if (fnt_file >= 0) {
-
+    if (pf->fd >= 0) {
         int fd;
         unsigned char tmp[2];
         unsigned short ch;
-        struct font* pf = &font_ui;
 
         fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
 
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 5f48881..3f2b3c0 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -744,7 +744,7 @@
 
     if (battery_level_safe()) { /* do not save on critical battery */
 #ifdef HAVE_LCD_BITMAP
-        glyph_cache_save();
+      glyph_cache_save(NULL);
 #endif
 
 /* Commit pending writes if needed. Even though we don't do write caching,
diff --git a/tools/checkwps/SOURCES b/tools/checkwps/SOURCES
index 06ef3b9..6223b97 100644
--- a/tools/checkwps/SOURCES
+++ b/tools/checkwps/SOURCES
@@ -1,6 +1,9 @@
 ../../apps/gui/skin_engine/wps_debug.c
 ../../apps/gui/skin_engine/skin_parser.c
 ../../apps/gui/skin_engine/skin_buffer.c
+#ifdef HAVE_LCD_BITMAP
+../../apps/gui/skin_engine/skin_fonts.c
+#endif
 ../../apps/gui/viewport.c
 ../../apps/misc.c
 ../../firmware/common/strlcpy.c
diff --git a/tools/checkwps/checkwps.c b/tools/checkwps/checkwps.c
index 38a650a..32b6daa 100644
--- a/tools/checkwps/checkwps.c
+++ b/tools/checkwps/checkwps.c
@@ -31,6 +31,7 @@
 #include "settings.h"
 #include "viewport.h"
 #include "file.h"
+#include "font.h"
 
 bool debug_wps = true;
 int wps_verbose_level = 0;
@@ -236,6 +237,21 @@
 }
 #endif
 
+#ifdef HAVE_LCD_BITMAP
+static int loaded_fonts = 0;
+int font_load(struct font* pf, const char *path)
+{
+    int id = SYSTEMFONTCOUNT + loaded_fonts;
+    loaded_fonts++;
+    return id;
+}
+    
+void font_unload(int font_id)
+{
+    (void)font_id;
+}
+#endif
+
 int main(int argc, char **argv)
 {
     int res;
diff --git a/tools/convbdf.c b/tools/convbdf.c
index fd82fb5..9e42cb8 100644
--- a/tools/convbdf.c
+++ b/tools/convbdf.c
@@ -1393,7 +1393,16 @@
             "  %s  /* offset */\n"
             "  %s\n"
             "  %d,  /* defaultchar */\n"
-            "  %d   /* bits_size */\n"
+            "  %d,   /* bits_size */\n"
+            "  -1,   /* font fd */\n"
+            "  0,   /* buffer start */\n"
+            "  0,   /* ^ position */\n"
+            "  0,   /* ^ end */\n"
+            "  0,   /* ^ size  */\n"
+            "  {{0,0,0,0,0},0,0,0},   /* cache  */\n"
+            "  0,   /*   */\n"
+            "  0,   /*   */\n"
+            "  0,   /*   */\n"
             "};\n"
             "#endif /* HAVE_LCD_BITMAP */\n",
             pf->maxwidth, pf->height,