diff options
author | Marcoen Hirschberg <marcoen@gmail.com> | 2005-12-06 13:27:15 +0000 |
---|---|---|
committer | Marcoen Hirschberg <marcoen@gmail.com> | 2005-12-06 13:27:15 +0000 |
commit | b0fee17d6e1a463dcd84568e5997663b69488998 (patch) | |
tree | fffce775c4d1636a8bbc9e97669aa99b9378fc15 /firmware/font.c | |
parent | 01917ec9809f1abff87cb372b700fc09476d343e (diff) | |
download | rockbox-b0fee17d6e1a463dcd84568e5997663b69488998.tar.gz rockbox-b0fee17d6e1a463dcd84568e5997663b69488998.zip |
waiting is over: initial unicode commit
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8169 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/font.c')
-rw-r--r-- | firmware/font.c | 392 |
1 files changed, 347 insertions, 45 deletions
diff --git a/firmware/font.c b/firmware/font.c index 303887701d..e8d5db46b9 100644 --- a/firmware/font.c +++ b/firmware/font.c | |||
@@ -33,6 +33,10 @@ | |||
33 | #include "file.h" | 33 | #include "file.h" |
34 | #include "debug.h" | 34 | #include "debug.h" |
35 | #include "panic.h" | 35 | #include "panic.h" |
36 | #include "rbunicode.h" | ||
37 | /* Font cache includes */ | ||
38 | #include "font_cache.h" | ||
39 | #include "lru.h" | ||
36 | 40 | ||
37 | #ifndef O_BINARY | 41 | #ifndef O_BINARY |
38 | #define O_BINARY 0 | 42 | #define O_BINARY 0 |
@@ -53,6 +57,16 @@ static unsigned char *freeptr = mbuf; | |||
53 | static unsigned char *fileptr; | 57 | static unsigned char *fileptr; |
54 | static unsigned char *eofptr; | 58 | static unsigned char *eofptr; |
55 | 59 | ||
60 | /* Font cache structures */ | ||
61 | static struct font_cache font_cache_ui; | ||
62 | static int fnt_file = -1; /* >=0 if font is cached */ | ||
63 | unsigned long file_width_offset; /* offset to file width data */ | ||
64 | unsigned long file_offset_offset; /* offset to file offset data */ | ||
65 | static void cache_create(int maxwidth, int height); | ||
66 | static int long_offset = 0; | ||
67 | static int glyph_file; | ||
68 | /* End Font cache structures */ | ||
69 | |||
56 | void font_init(void) | 70 | void font_init(void) |
57 | { | 71 | { |
58 | memset(&font_ui, 0, sizeof(struct font)); | 72 | memset(&font_ui, 0, sizeof(struct font)); |
@@ -94,41 +108,12 @@ void font_reset(void) | |||
94 | memset(&font_ui, 0, sizeof(struct font)); | 108 | memset(&font_ui, 0, sizeof(struct font)); |
95 | } | 109 | } |
96 | 110 | ||
97 | /* read and load font into incore font structure*/ | 111 | static struct font* font_load_header(struct font *pf) |
98 | struct font* font_load(const char *path) | ||
99 | { | 112 | { |
100 | int fd, filesize; | 113 | char version[4+1]; |
101 | unsigned short maxwidth, height, ascent, pad; | 114 | unsigned short maxwidth, height, ascent, pad; |
102 | unsigned long firstchar, defaultchar, size; | 115 | unsigned long firstchar, defaultchar, size; |
103 | unsigned long i, nbits, noffset, nwidth; | 116 | unsigned long nbits; |
104 | char version[4+1]; | ||
105 | struct font* pf = &font_ui; | ||
106 | |||
107 | /* open and read entire font file*/ | ||
108 | fd = open(path, O_RDONLY|O_BINARY); | ||
109 | if (fd < 0) { | ||
110 | DEBUGF("Can't open font: %s\n", path); | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | font_reset(); | ||
115 | |||
116 | /* currently, font loading replaces earlier font allocation*/ | ||
117 | freeptr = (unsigned char *)(((int)mbuf + 3) & ~3); | ||
118 | |||
119 | fileptr = freeptr; | ||
120 | filesize = read(fd, fileptr, MAX_FONT_SIZE); | ||
121 | eofptr = fileptr + filesize; | ||
122 | |||
123 | /* no need for multiple font loads currently*/ | ||
124 | /*freeptr += filesize;*/ | ||
125 | /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/ | ||
126 | |||
127 | close(fd); | ||
128 | if (filesize == MAX_FONT_SIZE) { | ||
129 | DEBUGF("Font %s too large: %d\n", path, filesize); | ||
130 | return NULL; | ||
131 | } | ||
132 | 117 | ||
133 | /* read magic and version #*/ | 118 | /* read magic and version #*/ |
134 | memset(version, 0, sizeof(version)); | 119 | memset(version, 0, sizeof(version)); |
@@ -163,6 +148,14 @@ struct font* font_load(const char *path) | |||
163 | /* # words of bitmap_t*/ | 148 | /* # words of bitmap_t*/ |
164 | if (!readlong(&nbits)) | 149 | if (!readlong(&nbits)) |
165 | return NULL; | 150 | return NULL; |
151 | pf->bits_size = nbits; | ||
152 | |||
153 | return pf; | ||
154 | } | ||
155 | /* Load memory font */ | ||
156 | struct font* font_load_in_memory(struct font* pf) | ||
157 | { | ||
158 | long i, noffset, nwidth; | ||
166 | 159 | ||
167 | /* # longs of offset*/ | 160 | /* # longs of offset*/ |
168 | if (!readlong(&noffset)) | 161 | if (!readlong(&noffset)) |
@@ -174,19 +167,44 @@ struct font* font_load(const char *path) | |||
174 | 167 | ||
175 | /* variable font data*/ | 168 | /* variable font data*/ |
176 | pf->bits = (unsigned char *)fileptr; | 169 | pf->bits = (unsigned char *)fileptr; |
177 | fileptr += nbits*sizeof(unsigned char); | 170 | fileptr += pf->bits_size*sizeof(unsigned char); |
178 | 171 | ||
179 | /* pad to 16 bit boundary*/ | 172 | if ( pf->bits_size < 0xFFDB ) |
180 | fileptr = (unsigned char *)(((long)fileptr + 1) & ~1); | 173 | { |
174 | /* pad to 16-bit boundary */ | ||
175 | fileptr = (unsigned char *)(((int)fileptr + 1) & ~1); | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | /* pad to 32-bit boundary*/ | ||
180 | fileptr = (unsigned char *)(((int)fileptr + 3) & ~3); | ||
181 | } | ||
181 | 182 | ||
182 | if (noffset) { | 183 | if (noffset) |
183 | pf->offset = (unsigned short *)fileptr; | 184 | { |
184 | for (i=0; i<noffset; ++i) | 185 | if ( pf->bits_size < 0xFFDB ) |
186 | { | ||
187 | long_offset = 0; | ||
188 | pf->offset = (unsigned short *)fileptr; | ||
189 | for (i=0; i<noffset; ++i) | ||
190 | { | ||
191 | unsigned short offset; | ||
192 | if (!readshort(&offset)) | ||
193 | return NULL; | ||
194 | ((unsigned short*)(pf->offset))[i] = (unsigned short)offset; | ||
195 | } | ||
196 | } | ||
197 | else | ||
185 | { | 198 | { |
186 | unsigned short offset; | 199 | long_offset = 1; |
187 | if (!readshort(&offset)) | 200 | pf->offset = (unsigned short *)fileptr; |
188 | return NULL; | 201 | for (i=0; i<noffset; ++i) |
189 | ((unsigned short*)(pf->offset))[i] = (unsigned short)offset; | 202 | { |
203 | unsigned long offset; | ||
204 | if (!readlong(&offset)) | ||
205 | return NULL; | ||
206 | ((unsigned long*)(pf->offset))[i] = (unsigned long)offset; | ||
207 | } | ||
190 | } | 208 | } |
191 | } | 209 | } |
192 | else | 210 | else |
@@ -205,6 +223,141 @@ struct font* font_load(const char *path) | |||
205 | return pf; /* success!*/ | 223 | return pf; /* success!*/ |
206 | } | 224 | } |
207 | 225 | ||
226 | /* Load cached font */ | ||
227 | struct font* font_load_cached(struct font* pf) | ||
228 | { | ||
229 | unsigned long noffset, nwidth; | ||
230 | unsigned char* oldfileptr = fileptr; | ||
231 | |||
232 | /* # longs of offset*/ | ||
233 | if (!readlong(&noffset)) | ||
234 | return NULL; | ||
235 | |||
236 | /* # bytes of width*/ | ||
237 | if (!readlong(&nwidth)) | ||
238 | return NULL; | ||
239 | |||
240 | /* We are now at the bitmap data, this is fixed at 36.. */ | ||
241 | pf->bits = NULL; | ||
242 | |||
243 | /* Calculate offset to offset data */ | ||
244 | fileptr += pf->bits_size * sizeof(unsigned char); | ||
245 | |||
246 | if ( pf->bits_size < 0xFFDB ) | ||
247 | { | ||
248 | long_offset = 0; | ||
249 | /* pad to 16-bit boundary */ | ||
250 | fileptr = (unsigned char *)(((int)fileptr + 1) & ~1); | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | long_offset = 1; | ||
255 | /* pad to 32-bit boundary*/ | ||
256 | fileptr = (unsigned char *)(((int)fileptr + 3) & ~3); | ||
257 | } | ||
258 | |||
259 | if (noffset) | ||
260 | file_offset_offset = (unsigned long)(fileptr - freeptr); | ||
261 | else | ||
262 | file_offset_offset = 0; | ||
263 | |||
264 | /* Calculate offset to widths data */ | ||
265 | if ( pf->bits_size < 0xFFDB ) | ||
266 | fileptr += noffset * sizeof(unsigned short); | ||
267 | else | ||
268 | fileptr += noffset * sizeof(unsigned long); | ||
269 | |||
270 | if (nwidth) | ||
271 | file_width_offset = (unsigned long)(fileptr - freeptr); | ||
272 | else | ||
273 | file_width_offset = 0; | ||
274 | |||
275 | fileptr = oldfileptr; | ||
276 | |||
277 | /* Create the cache */ | ||
278 | cache_create(pf->maxwidth, pf->height); | ||
279 | |||
280 | return pf; | ||
281 | } | ||
282 | |||
283 | /* read and load font into incore font structure*/ | ||
284 | struct font* font_load(const char *path) | ||
285 | { | ||
286 | int filesize; | ||
287 | struct font* pf = &font_ui; | ||
288 | |||
289 | /* save loaded glyphs */ | ||
290 | glyph_cache_save(); | ||
291 | |||
292 | /* Close font file handle */ | ||
293 | if (fnt_file >= 0) | ||
294 | close(fnt_file); | ||
295 | |||
296 | /* open and read entire font file*/ | ||
297 | fnt_file = open(path, O_RDONLY|O_BINARY); | ||
298 | |||
299 | if (fnt_file < 0) { | ||
300 | DEBUGF("Can't open font: %s\n", path); | ||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | /* Check file size */ | ||
305 | filesize = lseek(fnt_file, 0, SEEK_END); | ||
306 | lseek(fnt_file, 0, SEEK_SET); | ||
307 | |||
308 | font_reset(); | ||
309 | |||
310 | /* currently, font loading replaces earlier font allocation*/ | ||
311 | freeptr = (unsigned char *)(((int)mbuf + 3) & ~3); | ||
312 | fileptr = freeptr; | ||
313 | |||
314 | |||
315 | if (filesize > MAX_FONT_SIZE) | ||
316 | { | ||
317 | read(fnt_file, fileptr, FONT_HEADER_SIZE); | ||
318 | eofptr = fileptr + FONT_HEADER_SIZE; | ||
319 | |||
320 | if (!font_load_header(pf)) | ||
321 | { | ||
322 | DEBUGF("Failed font header load"); | ||
323 | return NULL; | ||
324 | } | ||
325 | |||
326 | if (!font_load_cached(pf)) | ||
327 | { | ||
328 | DEBUGF("Failed font cache load"); | ||
329 | return NULL; | ||
330 | } | ||
331 | |||
332 | glyph_cache_load(); | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | read(fnt_file, fileptr, MAX_FONT_SIZE); | ||
337 | eofptr = fileptr + filesize; | ||
338 | close(fnt_file); | ||
339 | fnt_file = -1; | ||
340 | |||
341 | if (!font_load_header(pf)) | ||
342 | { | ||
343 | DEBUGF("Failed font header load"); | ||
344 | return NULL; | ||
345 | } | ||
346 | |||
347 | if (!font_load_in_memory(pf)) | ||
348 | { | ||
349 | DEBUGF("Failed mem load"); | ||
350 | return NULL; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | /* no need for multiple font loads currently*/ | ||
355 | /*freeptr += filesize;*/ | ||
356 | /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/ | ||
357 | |||
358 | return pf; /* success!*/ | ||
359 | } | ||
360 | |||
208 | /* | 361 | /* |
209 | * Return a pointer to an incore font structure. | 362 | * Return a pointer to an incore font structure. |
210 | * If the requested font isn't loaded/compiled-in, | 363 | * If the requested font isn't loaded/compiled-in, |
@@ -231,17 +384,18 @@ struct font* font_get(int font) | |||
231 | int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber) | 384 | int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber) |
232 | { | 385 | { |
233 | struct font* pf = font_get(fontnumber); | 386 | struct font* pf = font_get(fontnumber); |
234 | int ch; | 387 | unsigned short ch; |
235 | int width = 0; | 388 | int width = 0; |
236 | 389 | ||
237 | while((ch = *str++)) { | 390 | for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch)) |
391 | { | ||
238 | /* check input range*/ | 392 | /* check input range*/ |
239 | if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) | 393 | if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) |
240 | ch = pf->defaultchar; | 394 | ch = pf->defaultchar; |
241 | ch -= pf->firstchar; | 395 | ch -= pf->firstchar; |
242 | 396 | ||
243 | /* get proportional width and glyph bits*/ | 397 | /* get proportional width and glyph bits*/ |
244 | width += pf->width? pf->width[ch]: pf->maxwidth; | 398 | width += font_get_width(pf,ch); |
245 | } | 399 | } |
246 | if ( w ) | 400 | if ( w ) |
247 | *w = width; | 401 | *w = width; |
@@ -250,6 +404,154 @@ int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber) | |||
250 | return width; | 404 | return width; |
251 | } | 405 | } |
252 | 406 | ||
407 | /* | ||
408 | * Reads an entry into cache entry | ||
409 | */ | ||
410 | static void | ||
411 | load_cache_entry(struct font_cache_entry* p, void* callback_data) | ||
412 | { | ||
413 | struct font* pf = callback_data; | ||
414 | unsigned short char_code = p->_char_code; | ||
415 | unsigned char tmp[2]; | ||
416 | |||
417 | if (file_width_offset) | ||
418 | { | ||
419 | int width_offset = file_width_offset + char_code; | ||
420 | lseek(fnt_file, width_offset, SEEK_SET); | ||
421 | read(fnt_file, &(p->width), 1); | ||
422 | } | ||
423 | else | ||
424 | { | ||
425 | p->width = pf->maxwidth; | ||
426 | } | ||
427 | |||
428 | long bitmap_offset = 0; | ||
429 | |||
430 | if (file_offset_offset) | ||
431 | { | ||
432 | long offset = file_offset_offset + char_code * (long_offset ? sizeof(long) : sizeof(short)); | ||
433 | lseek(fnt_file, offset, SEEK_SET); | ||
434 | read (fnt_file, tmp, 2); | ||
435 | bitmap_offset = tmp[0] | (tmp[1] << 8); | ||
436 | if (long_offset) { | ||
437 | read (fnt_file, tmp, 2); | ||
438 | bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24); | ||
439 | } | ||
440 | } | ||
441 | else | ||
442 | { | ||
443 | bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code; | ||
444 | } | ||
445 | |||
446 | long file_offset = FONT_HEADER_SIZE + bitmap_offset; | ||
447 | lseek(fnt_file, file_offset, SEEK_SET); | ||
448 | |||
449 | int src_bytes = p->width * ((pf->height + 7) / 8); | ||
450 | read(fnt_file, p->bitmap, src_bytes); | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * Converts cbuf into a font cache | ||
455 | */ | ||
456 | static void cache_create(int maxwidth, int height) | ||
457 | { | ||
458 | /* maximum size of rotated bitmap */ | ||
459 | int bitmap_size = maxwidth * ((height + 7) / 8); | ||
460 | |||
461 | /* Initialise cache */ | ||
462 | font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Returns width of character | ||
467 | */ | ||
468 | int font_get_width(struct font* pf, unsigned short char_code) | ||
469 | { | ||
470 | return (fnt_file >= 0 && pf != &sysfont)? | ||
471 | font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width: | ||
472 | pf->width? pf->width[char_code]: pf->maxwidth; | ||
473 | } | ||
474 | |||
475 | const unsigned char* font_get_bits(struct font* pf, unsigned short char_code) | ||
476 | { | ||
477 | const unsigned char* bits; | ||
478 | if (fnt_file >= 0 && pf != &sysfont) | ||
479 | { | ||
480 | bits = | ||
481 | (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap; | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | bits = pf->bits + (pf->offset? | ||
486 | pf->offset[char_code]: | ||
487 | (((pf->height + 7) / 8) * pf->maxwidth * char_code)); | ||
488 | } | ||
489 | |||
490 | return bits; | ||
491 | } | ||
492 | |||
493 | void glyph_file_write(void* data) | ||
494 | { | ||
495 | struct font_cache_entry* p = data; | ||
496 | unsigned char tmp[2]; | ||
497 | |||
498 | if (p->_char_code != 0xffff && glyph_file >= 0) { | ||
499 | tmp[0] = p->_char_code >> 8; | ||
500 | tmp[1] = p->_char_code & 0xff; | ||
501 | if (write(glyph_file, tmp, 2) != 2) { | ||
502 | close(glyph_file); | ||
503 | glyph_file = -1; | ||
504 | } | ||
505 | } | ||
506 | return; | ||
507 | } | ||
508 | |||
509 | /* save the char codes of the loaded glyphs to a file */ | ||
510 | void glyph_cache_save(void) | ||
511 | { | ||
512 | |||
513 | if (fnt_file >= 0) { | ||
514 | |||
515 | glyph_file = creat(GLYPH_CACHE_FILE, 0); | ||
516 | |||
517 | if (glyph_file < 0) return; | ||
518 | |||
519 | lru_traverse(&font_cache_ui._lru, glyph_file_write); | ||
520 | |||
521 | if (glyph_file >= 0) | ||
522 | close(glyph_file); | ||
523 | } | ||
524 | return; | ||
525 | } | ||
526 | |||
527 | void glyph_cache_load(void) | ||
528 | { | ||
529 | if (fnt_file >= 0) { | ||
530 | |||
531 | int fd; | ||
532 | unsigned char tmp[2]; | ||
533 | unsigned short ch; | ||
534 | struct font* pf = &font_ui; | ||
535 | |||
536 | fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY); | ||
537 | |||
538 | if (fd >= 0) { | ||
539 | |||
540 | while (read(fd, tmp, 2) == 2) { | ||
541 | ch = (tmp[0] << 8) | tmp[1]; | ||
542 | font_get_bits(pf, ch); | ||
543 | } | ||
544 | |||
545 | close(fd); | ||
546 | } else { | ||
547 | /* load latin1 chars into cache */ | ||
548 | ch = 255 - pf->firstchar; | ||
549 | while (ch--) | ||
550 | font_get_bits(pf, ch); | ||
551 | } | ||
552 | } | ||
553 | return; | ||
554 | } | ||
253 | 555 | ||
254 | #endif /* HAVE_LCD_BITMAP */ | 556 | #endif /* HAVE_LCD_BITMAP */ |
255 | 557 | ||