source: trunk/lib/font/rbf_font.c @ 1186

Revision 1186, 15.4 KB checked in by reyalp, 2 years ago (diff)

possible workaround for rbf font bug http://chdk.setepontos.com/index.php?topic=6365 - from philmoz in http://chdk.setepontos.com/index.php?topic=650.msg66601#msg66601

  • Property svn:eol-style set to native
Line 
1#include "stdlib.h"
2#include "gui.h"
3#include "font.h"
4#include "../../core/gui_draw.h"
5#include "../../include/conf.h"
6
7//-------------------------------------------------------------------
8#define RBF_MAX_NAME       64
9
10//-------------------------------------------------------------------
11static unsigned int RBF_HDR_MAGIC1 = 0x0DF00EE0;
12static unsigned int RBF_HDR_MAGIC2 = 0x00000003;
13
14// Header as seperate structure so it can be directly loaded from the font file easily
15// structure layout maps to file layout - do not change !
16typedef struct {
17    int magic1, magic2;         // header magic numbers to identify correct font file
18    char name[RBF_MAX_NAME];    // name of font (max 64 characters)
19    int charSize;               // # of bytes used to store each character
20    int points;                 // font size in points
21    int height;                 // font height in pixels
22    int maxWidth;               // width of widest character
23    int charFirst;              // first character #
24    int charLast;               // last character #
25    int _unknown4;              // ?
26    int _wmapAddr;              // offset in font file of wTable array
27    int _cmapAddr;              // offset in font file of cTable array
28    int descent;                // font descent (not used)
29    int intline;                // interline spacing (not used)
30} font_hdr;
31
32typedef struct _font {
33    font_hdr hdr;
34
35    // calculated values (after font is loaded)
36    int charCount;              // count of chars containing in font
37    int width;                  // font element width in pixels
38
39    // Width table
40    // List of character widths. Elements of list is width of char
41    char wTable[256];
42
43    // Character data
44    // List of chars. Element of list is a bytecode string, contains pixels representation of char
45    char *cTable;
46
47    // Flag to indicate we are actually using the built in 8x16 font rather than a loaded font
48    int usingFont8x16;
49
50    // Current size of the cTable data
51    int cTableSize;
52    struct _font *uncached_font;      // address of font in uncached memory (for passing to ufree & read)
53    char *uncached_cTable;            // address of cTable in uncached memory (for passing to ufree & read)
54} font;
55
56static font *rbf_symbol_font = 0, *rbf_font = 0;
57static int rbf_codepage = FONT_CP_WIN;
58
59//-------------------------------------------------------------------
60
61font *new_font() {
62    // allocate font from uncached memory
63    font *f = umalloc(sizeof(font));
64    if (f) {
65        memset(f,0,sizeof(font));      // wipe memory (use uncached address to avoid conflict with read & caching)
66        f->uncached_font = f;          // save uncached memory address
67        // return address in cached memory for faster font rendering
68        return (font*)((int)f & ~CAM_UNCACHED_BIT);
69    }
70
71    // memory not allocated ! should probably do something else in this case ?
72    return 0;
73}
74
75void init_fonts()
76{
77    // Allocate base font memory if needed
78    if (rbf_font == 0) rbf_font = new_font();
79    if (rbf_symbol_font == 0) rbf_symbol_font = new_font();
80}
81
82void alloc_cTable(font *f) {
83
84    // Calculate additional values for font
85    f->width = 8 * f->hdr.charSize / f->hdr.height;
86    f->charCount = f->hdr.charLast - f->hdr.charFirst + 1;
87
88    // set width table to default value
89    memset(f->wTable, f->width, 256);
90   
91    // allocate cTable memory
92
93    // If existing data has been allocated then we are re-using the font data
94    // See if it the existing cTable data is large enough to hold the new font data
95    // If not free it so new memory will be allocated
96    if ((f->cTable != 0) && (f->cTableSize < (f->charCount*f->hdr.charSize))) {
97        ufree(f->uncached_cTable);    // free the memory using the uncached address
98        f->cTable = 0;                // clear pointer so new memory is allocated
99        f->uncached_cTable = 0;
100    }
101
102    // Allocated memory if needed
103    if (f->cTable == 0 && !f->usingFont8x16) {
104        // Allocate memory from uncached pool
105        f->uncached_cTable = umalloc(f->charCount*f->hdr.charSize);
106        // Store cached memory address
107        f->cTable = (char*)((int)f->uncached_cTable & ~CAM_UNCACHED_BIT);
108
109        // save size
110        f->cTableSize = f->charCount*f->hdr.charSize;
111    }
112}
113
114//-------------------------------------------------------------------
115static const char tbl_dos2win[] = {
116    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
117    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
118    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
119    0x2D, 0x2D, 0x2D, 0xA6, 0x2B, 0xA6, 0xA6, 0xAC, 0xAC, 0xA6, 0xA6, 0xAC, 0x2D, 0x2D, 0x2D, 0xAC,
120    0x4C, 0x2B, 0x54, 0x2B, 0x2D, 0x2B, 0xA6, 0xA6, 0x4C, 0xE3, 0xA6, 0x54, 0xA6, 0x3D, 0x2B, 0xA6,
121    0xA6, 0x54, 0x54, 0x4C, 0x4C, 0x2D, 0xE3, 0x2B, 0x2B, 0x2D, 0x2D, 0x2D, 0x2D, 0xA6, 0xA6, 0x2D,
122    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
123    0xA8, 0xB8, 0xAA, 0xBA, 0xAF, 0xBF, 0xA1, 0xA2, 0xB0, 0x95, 0xB7, 0x76, 0xB9, 0xA4, 0xA6, 0xA0
124};
125
126int code_page_char(int ch)
127{
128    // convert character value based on selected code page
129    if ((rbf_codepage == FONT_CP_DOS) && (ch >= 128) && (ch < 256)) {
130        // Convert DOS to WIN char
131        ch = tbl_dos2win[ch-128];
132    }
133    return ch;
134}
135
136//-------------------------------------------------------------------
137// Return address of 'character' data for specified font & char
138char* rbf_font_char(font* f, int ch)
139{
140    if (f && (ch >= f->hdr.charFirst) && (ch <= f->hdr.charLast))
141    {
142        return &f->cTable[(ch-f->hdr.charFirst)*f->hdr.charSize];
143    }
144
145    return 0;
146}
147//-------------------------------------------------------------------
148// Load from from file. If maxchar != 0 limit charLast (for symbols)
149// Note: pass the uncached font address to this function
150int rbf_font_load(char *file, font* f, int maxchar)
151{
152    int i;
153
154    // make sure the font has been allocated
155    if (f == 0) return 0;
156
157    // turn of default font if it was being used
158    f->usingFont8x16 = 0;
159
160    // open file (can't use fopen here due to potential conflict FsIoNotify crash)
161    int fd = open(file, O_RDONLY, 0777);
162    if (fd >= 0) {
163        // read header
164        i = read(fd, &f->hdr, sizeof(font_hdr));
165
166        // check size read is correct and magic numbers are valid
167        if ((i == sizeof(font_hdr)) && (f->hdr.magic1 == RBF_HDR_MAGIC1) && (f->hdr.magic2 == RBF_HDR_MAGIC2)) {
168
169            if (maxchar != 0) {
170                f->hdr.charLast = maxchar;
171            }
172
173            alloc_cTable(f);
174
175            // read width table (using uncached memory address)
176            lseek(fd, f->hdr._wmapAddr, SEEK_SET);
177            read(fd, &f->wTable[f->hdr.charFirst], f->charCount);
178
179            // read cTable data (using uncached memory address)
180            lseek(fd, f->hdr._cmapAddr, SEEK_SET);
181            read(fd, f->uncached_cTable, f->charCount*f->hdr.charSize);
182
183            close(fd);
184
185            // Reset symbol display if symbol font too tall
186            if (conf.menu_symbol_enable && rbf_font && rbf_symbol_font)
187                conf.menu_symbol_enable=(rbf_font->hdr.height>=rbf_symbol_font->hdr.height);
188
189            return 1;
190        }
191    }
192
193    return 0;
194}
195//-------------------------------------------------------------------
196int rbf_load(char *file) {
197    // Allocate font if needed
198    init_fonts();
199    // Load font
200    return rbf_font_load(file, rbf_font->uncached_font, 0);
201}
202
203//-------------------------------------------------------------------
204#define maxSymbols 128
205int rbf_load_symbol(char *file) {
206    // Allocate font if needed
207    init_fonts();
208    // Load font
209    return rbf_font_load(file, rbf_symbol_font->uncached_font, maxSymbols+32);
210}
211
212//-------------------------------------------------------------------
213void rbf_load_from_8x16(unsigned char font[256][16]) {
214
215    // Allocate font if needed
216    init_fonts();
217
218    rbf_font->hdr.charSize  = 16;
219    rbf_font->hdr.height    = 16;
220    rbf_font->hdr.maxWidth  = 8;
221    rbf_font->hdr.charFirst = 0;
222    rbf_font->hdr.charLast  = 255;
223
224    // This is only ever called to copy the 'current_font' data into the rbf_font
225    // Instead of doing this set the rbf_font flag so we call 'draw_char' directly (which uses current_font)
226    // This avoids allocating memory for a copy of something we already have
227    rbf_font->usingFont8x16 = 1;
228
229    alloc_cTable(rbf_font);
230}
231
232//-------------------------------------------------------------------
233void rbf_set_codepage(int codepage) {
234    rbf_codepage = codepage;
235}
236
237//-------------------------------------------------------------------
238int rbf_font_height() {
239    return rbf_font->hdr.height;
240}
241//-------------------------------------------------------------------
242int rbf_symbol_height() {
243    return rbf_symbol_font->hdr.height;
244}
245
246//-------------------------------------------------------------------
247int rbf_char_width(int ch) {
248    return rbf_font->wTable[code_page_char(ch)];
249}
250
251//-------------------------------------------------------------------
252int rbf_symbol_width(int ch) {
253    return rbf_symbol_font->wTable[ch];
254}
255
256//-------------------------------------------------------------------
257int rbf_str_width(const char *str) {
258    int l=0;
259
260    // Calculate how long the string is in pixels
261    while (*str)
262        l+=rbf_char_width(*str++);
263
264    return l;
265}
266
267int rbf_str_clipped_width(const char *str, int l, int maxlen) {
268    // Calculate how long the string is in pixels (possibly clipped to 'maxlen')
269    while (*str && l+rbf_char_width(*str)<=maxlen)
270        l+=rbf_char_width(*str++);
271
272    return l;
273}
274
275//-------------------------------------------------------------------
276void font_draw_char(int x, int y, char *cdata, int width, int height, int pixel_width, color cl) {
277    int xx, yy;
278
279    // draw pixels for font character
280    if (cdata)
281        for (yy=0; yy<height; ++yy)
282            for (xx=0; xx<pixel_width; ++xx)
283                draw_pixel(x+xx ,y+yy, (cdata[yy*width/8+xx/8] & (1<<(xx%8)))? cl&0xff : cl>>8);
284}
285
286//-------------------------------------------------------------------
287int rbf_draw_char(int x, int y, int ch, color cl) {
288    // Convert char for code page
289    ch = code_page_char(ch);
290
291    // Get char data pointer
292    char* cdata = rbf_font_char(rbf_font, ch);
293
294    // Draw font character (either loaded font, or from default font)
295    if (rbf_font->usingFont8x16 || !cdata)
296        draw_char(x,y,ch,cl);
297    else
298        font_draw_char(x, y, cdata, rbf_font->width, rbf_font->hdr.height, rbf_font->wTable[ch], cl);
299
300    return rbf_font->wTable[ch];
301}
302
303//-------------------------------------------------------------------
304int rbf_draw_symbol(int x, int y, int ch, color cl) {
305    int space=0, pixel_width, sym_height, txt_height;
306
307    // Skip if symbol font height taller than text font height (or invalid char value)
308    if (rbf_font->hdr.height<rbf_symbol_font->hdr.height || ch==0x0) return 0;
309
310    // get width of symbol in pixels
311    pixel_width = rbf_symbol_width(ch);
312    // get height of symbol font
313    sym_height = rbf_symbol_font->hdr.height;
314    // get height of text font
315    txt_height = rbf_font->hdr.height;
316
317    // Get char data pointer
318    char* cdata = rbf_font_char(rbf_symbol_font, ch);
319
320    if (cdata) {
321      // if symbol font shorter than text font center symbol vertically and fill empty space above
322      if (txt_height > sym_height) {
323        space = (txt_height - sym_height)/2;
324        draw_filled_rect(x, y, x+pixel_width, y+space, MAKE_COLOR(cl>>8, cl>>8));
325        y+=space;
326      }
327
328      // Draw font character
329      font_draw_char(x, y, cdata, rbf_symbol_font->width, sym_height, pixel_width, cl);
330
331      // Fill space below symbol if shorter than text font
332      if (txt_height > sym_height)
333          draw_filled_rect(x, y+sym_height, x+pixel_width, y-space+txt_height-1, MAKE_COLOR(cl>>8, cl>>8));
334    }
335
336    return pixel_width;
337}
338
339//-------------------------------------------------------------------
340// Draw a string colored 'c1' with the character at string-position 'c' colored 'c2'.
341int rbf_draw_string_c(int x, int y, const char *str, color c1, int c, color c2) {
342     int l=0, i=0;
343
344     while (*str) {
345          l+=rbf_draw_char(x+l, y, *str++, (i==c)?c2:c1);
346          ++i;
347     }
348     return l;
349}
350
351//-------------------------------------------------------------------
352int rbf_draw_string(int x, int y, const char *str, color cl) {
353    return rbf_draw_string_c(x, y, str, cl, -1, 0);
354}
355
356//-------------------------------------------------------------------
357int rbf_draw_clipped_string(int x, int y, const char *str, color cl, int l, int maxlen) {
358    // Draw chars from string up to max pixel length
359    while (*str && l+rbf_char_width(*str)<=maxlen)
360        l+=rbf_draw_char(x+l, y, *str++, cl);
361    return l;
362}
363
364//-------------------------------------------------------------------
365int rbf_draw_string_len(int x, int y, int len, const char *str, color cl) {
366    // Draw string characters
367    int l = rbf_draw_clipped_string(x, y, str, cl, 0, len);
368
369    // Fill any remaining space on right with background color
370    if (l < len)
371        draw_filled_rect(x+l, y, x+len-1, y+rbf_font->hdr.height-1, MAKE_COLOR(cl>>8, cl>>8));
372
373    return len;
374}
375
376//-------------------------------------------------------------------
377int rbf_draw_string_right_len(int x, int y, int len, const char *str, color cl) {
378    // Calulate amount of padding needed on the left
379    int l = len - rbf_str_clipped_width(str, 0, len);
380
381    // Fill padding with background color
382    if (l > 0)
383        draw_filled_rect(x, y, x+l-1, y+rbf_font->hdr.height-1, MAKE_COLOR(cl>>8, cl>>8));
384
385    // Draw chars
386    l = rbf_draw_clipped_string(x, y, str, cl, l, len);
387
388    return l;
389}
390
391//-------------------------------------------------------------------
392int rbf_draw_string_center_len(int x, int y, int len, char symbol, const char *str, color cl) {
393    int l=0, strLen=0, i;
394    const char *s=str;
395
396    // If symbol to be added to string determing the width of the symbol + space
397    if (symbol!=0x0 && conf.menu_symbol_enable && rbf_font_height()>=rbf_symbol_height()) {
398        l += rbf_symbol_width(symbol);
399        l += rbf_char_width(' ');
400    }
401
402    // Add the length of the string (possibly clipped to fit)
403    l = rbf_str_clipped_width(str, l, len);
404
405    // Calculate padding required on left and right side
406    l = (len-l)/2;
407
408    int right = x+len-1, bottom = y+rbf_font_height()-1;
409
410    // Fill left & right sides of string area with a rectangle that has rounded top corners
411    for (i=0; i<=l && i<3; i++) {
412        if (i < 2) {
413            // First and second columns make rounded top corners
414            draw_line(x+i,     y+2-i, x+i,     bottom, MAKE_COLOR(cl>>8, cl>>8));        // left side
415            draw_line(right-i, y+2-i, right-i, bottom, MAKE_COLOR(cl>>8, cl>>8));        // right side
416        }
417        else {
418            // Rest of empty space is just filled with rectangles
419            draw_filled_rect(x+i,     y, x+l-1,    bottom, MAKE_COLOR(cl>>8, cl>>8));    // left side
420            draw_filled_rect(right-l, y, right-i,  bottom, MAKE_COLOR(cl>>8, cl>>8));    // right side
421        }
422    }
423
424    // Draw symbol and space if required
425    if (symbol!=0x0 && conf.menu_symbol_enable && rbf_font_height()>=rbf_symbol_height()) {
426      l += rbf_draw_symbol(x+l, y, symbol, cl);
427      l += rbf_draw_char(x+l, y, ' ', cl);
428    }
429
430    // Draw chars
431    l = rbf_draw_clipped_string(x, y, str, cl, l, len);
432
433    return l;
434}
435
436//-------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.