blob: 617a8a33e3537ed4e13de68af8e34bcf50860c61 [file] [log] [blame]
Daniel Stenberg93b231c2002-09-12 13:33:59 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2002 by Greg Haerr <greg@censoft.com>
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Daniel Stenberg93b231c2002-09-12 13:33:59 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21/*
22 * Rockbox startup font initialization
23 * This file specifies which fonts get compiled-in and
24 * loaded at startup, as well as their mapping into
25 * the FONT_SYSFIXED, FONT_UI and FONT_MP3 ids.
26 */
Daniel Stenberg93b231c2002-09-12 13:33:59 +000027#include <stdio.h>
28#include <string.h>
Frank Gevaerts1994df62010-08-23 18:17:54 +000029#include <stdlib.h>
Thomas Martitz281d1fa2014-01-05 01:22:19 +010030#include <stdint.h>
31#include <stddef.h>
32
33#include "config.h"
Michael Sparmann751303c2011-02-27 22:44:30 +000034#include "system.h"
Thomas Martitz281d1fa2014-01-05 01:22:19 +010035#include "kernel.h"
36#include "lcd.h"
Daniel Stenberg93b231c2002-09-12 13:33:59 +000037#include "font.h"
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000038#include "file.h"
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +000039#include "core_alloc.h"
Daniel Stenberg93b231c2002-09-12 13:33:59 +000040#include "debug.h"
41#include "panic.h"
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +000042#include "rbunicode.h"
Tomer Shalev7682cb52009-11-24 20:41:42 +000043#include "diacritic.h"
Thomas Martitz9c0b2472010-08-01 16:15:27 +000044#include "rbpaths.h"
Jens Arnoldae878ff2008-09-23 21:35:54 +000045
Nils Wallménius559c5692009-12-13 11:07:40 +000046#define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB
47
48/* max static loadable font buffer size */
49#ifndef MAX_FONT_SIZE
50#if LCD_HEIGHT > 64
Andree Buschmann5d849a92011-02-02 17:43:32 +000051#if MEMORYSIZE > 2
Nils Wallménius559c5692009-12-13 11:07:40 +000052#define MAX_FONT_SIZE 60000
53#else
54#define MAX_FONT_SIZE 10000
55#endif
56#else
57#define MAX_FONT_SIZE 4000
58#endif
59#endif
Fred Bauerea7a8962011-11-19 23:34:26 +000060#define GLYPHS_TO_CACHE 256
61
62#if MEMORYSIZE < 4
63#define FONT_HARD_LIMIT
64#endif
Nils Wallménius559c5692009-12-13 11:07:40 +000065
66#ifndef FONT_HEADER_SIZE
67#define FONT_HEADER_SIZE 36
68#endif
69
Jens Arnoldae878ff2008-09-23 21:35:54 +000070#ifndef BOOTLOADER
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +000071/* Font cache includes */
72#include "font_cache.h"
73#include "lru.h"
Jens Arnoldae878ff2008-09-23 21:35:54 +000074#endif
Daniel Stenberg93b231c2002-09-12 13:33:59 +000075
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000076#ifndef O_BINARY
77#define O_BINARY 0
Daniel Stenberg93b231c2002-09-12 13:33:59 +000078#endif
Daniel Stenberg0a1c2212002-09-13 06:37:49 +000079
Fred Bauer10097412011-10-16 13:18:46 +000080/* Define this to try loading /.rockbox/.glyphcache *
81 * when a font specific file fails. This requires the *
82 * user to copy and rename a font glyph cache file */
83//#define TRY_DEFAULT_GLYPHCACHE
84
Björn Stenbergbed3d3f2002-09-20 08:07:51 +000085/* compiled-in font */
86extern struct font sysfont;
87
Jens Arnoldae878ff2008-09-23 21:35:54 +000088#ifndef BOOTLOADER
89
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +000090struct buflib_alloc_data {
Thomas Martitzc23ce622014-01-15 13:37:40 +010091 struct font font; /* must be the first member! */
92 int handle_locks; /* is the buflib handle currently locked? */
93 int refcount; /* how many times has this font been loaded? */
Jonathan Gordon83cfbf42011-09-24 14:52:16 +000094 unsigned char buffer[];
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +000095};
96static int buflib_allocations[MAXFONTS];
Fred Bauer10097412011-10-16 13:18:46 +000097
98static int cache_fd;
99static struct font* cache_pf;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000100
Frank Gevaertse5a3c262011-11-27 15:24:53 +0000101static void glyph_cache_save(int font_id);
102
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000103static int buflibmove_callback(int handle, void* current, void* new)
104{
105 (void)handle;
106 struct buflib_alloc_data *alloc = (struct buflib_alloc_data*)current;
Thomas Martitz57835052011-10-07 19:29:18 +0000107 ptrdiff_t diff = new - current;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000108
Fred Bauerde3e2e72011-10-14 20:35:52 +0000109 if (alloc->handle_locks > 0)
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000110 return BUFLIB_CB_CANNOT_MOVE;
111
Thomas Martitz57835052011-10-07 19:29:18 +0000112#define UPDATE(x) if (x) { x = PTR_ADD(x, diff); }
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000113
Thomas Martitz57835052011-10-07 19:29:18 +0000114 UPDATE(alloc->font.bits);
115 UPDATE(alloc->font.offset);
116 UPDATE(alloc->font.width);
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000117
Thomas Martitz57835052011-10-07 19:29:18 +0000118 UPDATE(alloc->font.buffer_start);
119 UPDATE(alloc->font.buffer_end);
120 UPDATE(alloc->font.buffer_position);
121
122 UPDATE(alloc->font.cache._index);
123 UPDATE(alloc->font.cache._lru._base);
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000124
125 return BUFLIB_CB_OK;
126}
127static void lock_font_handle(int handle, bool lock)
128{
Fred Bauerea7a8962011-11-19 23:34:26 +0000129 if ( handle < 0 )
130 return;
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000131 struct buflib_alloc_data *alloc = core_get_data(handle);
Fred Bauerde3e2e72011-10-14 20:35:52 +0000132 if ( lock )
133 alloc->handle_locks++;
134 else
135 alloc->handle_locks--;
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000136}
137
Fred Bauer04a015d2011-10-21 18:05:52 +0000138void font_lock(int font_id, bool lock)
139{
Frank Gevaerts6e664f42011-11-27 15:36:03 +0000140 if( font_id < 0 || font_id >= MAXFONTS )
Fred Bauer04a015d2011-10-21 18:05:52 +0000141 return;
142 if( buflib_allocations[font_id] >= 0 )
143 lock_font_handle(buflib_allocations[font_id], lock);
144}
145
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400146static struct buflib_callbacks buflibops = {buflibmove_callback, NULL, NULL };
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000147
148static inline struct font *pf_from_handle(int handle)
149{
150 struct buflib_alloc_data *alloc = core_get_data(handle);
151 struct font *pf = &alloc->font;
152 return pf;
153}
154
155static inline unsigned char *buffer_from_handle(int handle)
156{
157 struct buflib_alloc_data *alloc = core_get_data(handle);
158 unsigned char* buffer = alloc->buffer;
159 return buffer;
160}
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000161
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000162/* Font cache structures */
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000163static void cache_create(struct font* pf);
Fred Bauerea7a8962011-11-19 23:34:26 +0000164static void glyph_cache_load(const char *font_path, struct font *pf);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000165/* End Font cache structures */
166
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000167void font_init(void)
168{
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000169 int i = 0;
Fred Bauer10097412011-10-16 13:18:46 +0000170 cache_fd = -1;
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000171 while (i<MAXFONTS)
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000172 buflib_allocations[i++] = -1;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000173}
174
Dave Chapmane10f4552007-04-13 19:51:19 +0000175/* Check if we have x bytes left in the file buffer */
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000176#define HAVEBYTES(x) (pf->buffer_position + (x) <= pf->buffer_end)
Dave Chapmane10f4552007-04-13 19:51:19 +0000177
178/* Helper functions to read big-endian unaligned short or long from
179 the file buffer. Bounds-checking must be done in the calling
180 function.
181 */
182
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000183static short readshort(struct font *pf)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000184{
185 unsigned short s;
186
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000187 s = *pf->buffer_position++ & 0xff;
188 s |= (*pf->buffer_position++ << 8);
Dave Chapmane10f4552007-04-13 19:51:19 +0000189 return s;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000190}
191
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000192static int32_t readlong(struct font *pf)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000193{
Nils Wallméniusdf155c82007-06-30 17:54:02 +0000194 uint32_t l;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000195
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000196 l = *pf->buffer_position++ & 0xff;
197 l |= *pf->buffer_position++ << 8;
198 l |= ((uint32_t)(*pf->buffer_position++)) << 16;
199 l |= ((uint32_t)(*pf->buffer_position++)) << 24;
Dave Chapmane10f4552007-04-13 19:51:19 +0000200 return l;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000201}
202
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000203static int glyph_bytes( struct font *pf, int width )
204{
Fred Bauer01b36e82011-09-26 18:13:34 +0000205 int ret;
206 if (pf->depth)
207 ret = ( pf->height * width + 1 ) / 2;
208 else
209 ret = width * ((pf->height + 7) / 8);
210 return (ret + 1) & ~1;
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000211}
212
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000213/* Load memory font */
Fred Bauerea7a8962011-11-19 23:34:26 +0000214static struct font* font_load_in_memory(struct font* pf,
Fred Bauer95a828b2011-11-20 17:49:47 +0000215 int32_t nwidth,
216 int32_t noffset )
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000217{
Fred Bauerea7a8962011-11-19 23:34:26 +0000218 int i;
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000219 /* variable font data*/
Fred Bauerea7a8962011-11-19 23:34:26 +0000220 pf->buffer_position = pf->buffer_start + 36;
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000221 pf->bits = (unsigned char *)pf->buffer_position;
222 pf->buffer_position += pf->bits_size*sizeof(unsigned char);
Jörg Hohensohn5d36aaf2004-08-26 21:15:07 +0000223
Nils Wallménius559c5692009-12-13 11:07:40 +0000224 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000225 {
226 /* pad to 16-bit boundary */
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000227 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000228 }
229 else
230 {
231 /* pad to 32-bit boundary*/
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000232 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000233 }
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000234
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000235 if (noffset)
236 {
Nils Wallménius559c5692009-12-13 11:07:40 +0000237 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
Jörg Hohensohn5d36aaf2004-08-26 21:15:07 +0000238 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000239 pf->long_offset = 0;
240 pf->offset = (uint16_t*)pf->buffer_position;
Dave Chapmane10f4552007-04-13 19:51:19 +0000241
242 /* Check we have sufficient buffer */
Nils Wallménius559c5692009-12-13 11:07:40 +0000243 if (!HAVEBYTES(noffset * sizeof(uint16_t)))
Dave Chapmane10f4552007-04-13 19:51:19 +0000244 return NULL;
245
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000246 for (i=0; i<noffset; ++i)
247 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000248 ((uint16_t*)(pf->offset))[i] = (uint16_t)readshort(pf);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000249 }
250 }
251 else
252 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000253 pf->long_offset = 1;
254 pf->offset = (uint16_t*)pf->buffer_position;
Dave Chapmane10f4552007-04-13 19:51:19 +0000255
256 /* Check we have sufficient buffer */
Nils Wallméniusdf155c82007-06-30 17:54:02 +0000257 if (!HAVEBYTES(noffset * sizeof(int32_t)))
Dave Chapmane10f4552007-04-13 19:51:19 +0000258 return NULL;
259
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000260 for (i=0; i<noffset; ++i)
261 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000262 ((uint32_t*)(pf->offset))[i] = (uint32_t)readlong(pf);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000263 }
Jörg Hohensohn5d36aaf2004-08-26 21:15:07 +0000264 }
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000265 }
266 else
267 pf->offset = NULL;
268
269 if (nwidth) {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000270 pf->width = (unsigned char *)pf->buffer_position;
271 pf->buffer_position += nwidth*sizeof(unsigned char);
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000272 }
273 else
274 pf->width = NULL;
275
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000276 if (pf->buffer_position > pf->buffer_end)
Björn Stenbergbed3d3f2002-09-20 08:07:51 +0000277 return NULL;
278
Jens Arnold6dc88dc2004-05-14 23:08:08 +0000279 return pf; /* success!*/
Daniel Stenberg93b231c2002-09-12 13:33:59 +0000280}
281
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000282/* Load cached font */
Fred Bauerea7a8962011-11-19 23:34:26 +0000283static struct font* font_load_cached(struct font* pf,
284 int32_t nwidth,
285 int32_t noffset)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000286{
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000287 /* We are now at the bitmap data, this is fixed at 36.. */
Thomas Martitzc23ce622014-01-15 13:37:40 +0100288 pf->width = NULL;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000289 pf->bits = NULL;
290
291 /* Calculate offset to offset data */
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000292 pf->buffer_position += pf->bits_size * sizeof(unsigned char);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000293
Nils Wallménius559c5692009-12-13 11:07:40 +0000294 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000295 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000296 pf->long_offset = 0;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000297 /* pad to 16-bit boundary */
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000298 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 1) & ~1);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000299 }
300 else
301 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000302 pf->long_offset = 1;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000303 /* pad to 32-bit boundary*/
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000304 pf->buffer_position = (unsigned char *)(((intptr_t)pf->buffer_position + 3) & ~3);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000305 }
306
307 if (noffset)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000308 pf->file_offset_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000309 else
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000310 pf->file_offset_offset = 0;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000311
312 /* Calculate offset to widths data */
Nils Wallménius559c5692009-12-13 11:07:40 +0000313 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000314 pf->buffer_position += noffset * sizeof(uint16_t);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000315 else
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000316 pf->buffer_position += noffset * sizeof(uint32_t);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000317
318 if (nwidth)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000319 pf->file_width_offset = (uint32_t)(pf->buffer_position - pf->buffer_start);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000320 else
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000321 pf->file_width_offset = 0;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000322
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000323 /* Create the cache */
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000324 cache_create(pf);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000325
326 return pf;
327}
328
Teruaki Kawashima3e4b5c62010-02-26 07:16:32 +0000329
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000330static int find_font_index(const char* path)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000331{
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000332 int index = 0, handle;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000333
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000334 while (index < MAXFONTS)
335 {
336 handle = buflib_allocations[index];
337 if (handle > 0 && !strcmp(core_get_name(handle), path))
338 return index;
339 index++;
340 }
341 return FONT_SYSFIXED;
342}
343
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000344const char* font_filename(int font_id)
345{
Frank Gevaerts6e664f42011-11-27 15:36:03 +0000346 if ( font_id < 0 || font_id >= MAXFONTS )
347 return NULL;
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000348 int handle = buflib_allocations[font_id];
349 if (handle > 0)
350 return core_get_name(handle);
351 return NULL;
352}
Fred Bauerea7a8962011-11-19 23:34:26 +0000353
Bertrik Sikkencb972ab2011-12-20 20:35:28 +0000354static size_t font_glyphs_to_bufsize(struct font *pf, int glyphs)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000355{
Fred Bauerea7a8962011-11-19 23:34:26 +0000356 size_t bufsize;
357
358 /* LRU bytes per glyph */
359 bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) +
360 sizeof( unsigned short);
361 /* Image bytes per glyph */
362 bufsize += glyph_bytes(pf, pf->maxwidth);
363 bufsize *= glyphs;
364
365 return bufsize;
366}
367
368static struct font* font_load_header(int fd, struct font *pheader,
369 struct font *pf,
370 uint32_t *nwidth, uint32_t *noffset)
371{
372 /* Load the header. Readshort() and readlong() *
373 * update buffer_position address as they read */
374 pheader->buffer_start = pheader->buffer_position = (char *)pheader;
375 pheader->buffer_size = FONT_HEADER_SIZE;
376 pheader->buffer_end = pheader->buffer_start + pheader->buffer_size;
377
378 if (read(fd, pheader, FONT_HEADER_SIZE) != FONT_HEADER_SIZE)
379 return NULL;
380
381 /* read magic and version #*/
382 if (memcmp(pheader->buffer_position, VERSION, 4) != 0)
383 return NULL;
384
385 pheader->buffer_position += 4;
386
387 /* font info*/
388 pf->maxwidth = readshort(pheader);
389 pf->height = readshort(pheader);
390 pf->ascent = readshort(pheader);
391 pf->depth = readshort(pheader);
392 pf->firstchar = readlong(pheader);
393 pf->defaultchar = readlong(pheader);
394 pf->size = readlong(pheader);
395
396 /* get variable font data sizes*/
397 /* # words of bitmap_t*/
398 pf->bits_size = readlong(pheader);
399 *noffset = readlong(pheader);
400 *nwidth = readlong(pheader);
401
402 return pf;
403}
404
405/* load a font with room for glyphs, limited to bufsize if not zero */
406int font_load_ex( const char *path, size_t buf_size, int glyphs )
407{
408 //printf("\nfont_load_ex(%s, %d, %d)\n", path, buf_size, glyphs);
409 int fd = open(path, O_RDONLY|O_BINARY);
410 if ( fd < 0 )
411 return -1;
412
413 /* load font struct f with file header */
414 int file_size = filesize( fd );
415 struct font header;
Fred Bauerea7a8962011-11-19 23:34:26 +0000416 struct font f;
417
418 uint32_t nwidth, noffset;
Thomas Martitzc23ce622014-01-15 13:37:40 +0100419 if ( !font_load_header( fd, &header, &f, &nwidth, &noffset )
Fred Bauerea7a8962011-11-19 23:34:26 +0000420#if LCD_DEPTH < 16
421 || f.depth
422#endif
423 )
424 {
425 close(fd);
426 return -1;
427 }
428
429 /* examine f and calc buffer size */
430 bool cached = false;
431 size_t bufsize = buf_size;
432 size_t glyph_buf_size = font_glyphs_to_bufsize( &f, glyphs );
433
434 if ( bufsize && glyphs && bufsize > glyph_buf_size)
435 bufsize = glyph_buf_size;
436 else
437 {
438 if ( glyphs )
439 bufsize = glyph_buf_size;
440 else
441 bufsize = MAX_FONT_SIZE;
442 }
443#ifdef FONT_HARD_LIMIT
444 if ( bufsize > MAX_FONT_SIZE )
445 bufsize = MAX_FONT_SIZE;
446#endif
447 if ( bufsize < (size_t) file_size )
448 cached = true;
449 else
450 bufsize = file_size;
451
452 /* check already loaded */
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000453 int font_id = find_font_index(path);
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000454
455 if (font_id > FONT_SYSFIXED)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000456 {
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000457 /* already loaded, no need to reload */
458 struct buflib_alloc_data *pd = core_get_data(buflib_allocations[font_id]);
Fred Bauerea7a8962011-11-19 23:34:26 +0000459 if (pd->font.buffer_size < bufsize)
Jonathan Gordon83cfbf42011-09-24 14:52:16 +0000460 {
461 int old_refcount, old_id;
Fred Bauerea7a8962011-11-19 23:34:26 +0000462 size_t old_bufsize = pd->font.buffer_size;
463 bool failed = false;
Jonathan Gordon83cfbf42011-09-24 14:52:16 +0000464 /* reload the font:
465 * 1) save of refcont and id
466 * 2) force unload (set refcount to 1 to make sure it get unloaded)
467 * 3) reload with the larger buffer
468 * 4) restore the id and refcount
469 */
470 old_id = font_id;
471 old_refcount = pd->refcount;
472 pd->refcount = 1;
473 font_unload(font_id);
Fred Bauerea7a8962011-11-19 23:34:26 +0000474 font_id = font_load_ex(path, bufsize, glyphs);
Jonathan Gordon83cfbf42011-09-24 14:52:16 +0000475 if (font_id < 0)
476 {
Fred Bauerea7a8962011-11-19 23:34:26 +0000477 failed = true;
478 font_id = font_load_ex(path, old_bufsize, 0);
479 /* we couldn't even get the old size, this shouldn't happen */
480 if ( font_id < 0 )
481 return -1;
Jonathan Gordon83cfbf42011-09-24 14:52:16 +0000482 }
483 if (old_id != font_id)
484 {
485 buflib_allocations[old_id] = buflib_allocations[font_id];
486 buflib_allocations[font_id] = -1;
487 font_id = old_id;
488 }
489 pd = core_get_data(buflib_allocations[font_id]);
490 pd->refcount = old_refcount;
Fred Bauerea7a8962011-11-19 23:34:26 +0000491 if(failed)
492 /* return error because we didn't satisfy the new buffer size */
493 return -1;
Jonathan Gordon83cfbf42011-09-24 14:52:16 +0000494 }
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000495 pd->refcount++;
496 //printf("reusing handle %d for %s (count: %d)\n", font_id, path, pd->refcount);
Fred Bauerea7a8962011-11-19 23:34:26 +0000497 close(fd);
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000498 return font_id;
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000499 }
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000500
Fred Bauerea7a8962011-11-19 23:34:26 +0000501 int open_slot = -1;
502
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000503 for (font_id = FONT_FIRSTUSERFONT; font_id < MAXFONTS; font_id++)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000504 {
Fred Bauerea7a8962011-11-19 23:34:26 +0000505 if (buflib_allocations[ font_id ] < 0)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000506 {
Fred Bauerea7a8962011-11-19 23:34:26 +0000507 open_slot = font_id;
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000508 break;
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000509 }
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000510 }
Fred Bauerea7a8962011-11-19 23:34:26 +0000511 if ( open_slot == -1 )
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000512 return -1;
Fred Bauerea7a8962011-11-19 23:34:26 +0000513 font_id = open_slot;
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000514
Fred Bauerea7a8962011-11-19 23:34:26 +0000515 /* allocate mem */
516 int handle = core_alloc_ex( path,
517 bufsize + sizeof( struct buflib_alloc_data ),
518 &buflibops );
Bertrik Sikkend023bf02012-06-10 17:15:47 +0200519 if ( handle <= 0 )
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000520 {
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000521 return -1;
522 }
Fred Bauerea7a8962011-11-19 23:34:26 +0000523 struct buflib_alloc_data *pdata;
524 pdata = core_get_data(handle);
525 pdata->handle_locks = 1;
526 pdata->refcount = 1;
527
528 /* load and init */
Thomas Martitz08d9b7f2014-01-16 10:31:15 +0100529 struct font *pf = &pdata->font;
Fred Bauerea7a8962011-11-19 23:34:26 +0000530 memcpy(pf, &f, sizeof( struct font) );
531
532 pf->fd = fd;
533 pf->fd_width = pf->fd_offset = -1;
534 pf->handle = handle;
Thomas Martitz37be80a2014-01-26 13:56:53 +0100535 pf->disabled = false;
Fred Bauerea7a8962011-11-19 23:34:26 +0000536
537 pf->buffer_start = buffer_from_handle( pf->handle );
538 pf->buffer_position = pf->buffer_start + FONT_HEADER_SIZE;
539 pf->buffer_size = bufsize;
540 pf->buffer_end = pf->buffer_start + bufsize;
541
542 if ( cached )
543 {
544 if ( ! font_load_cached( pf, nwidth, noffset ) )
545 {
546 core_free( handle );
547 return -1;
548 }
549
550 /* trick to get a small cache for each file section *
551 * during glyph_cache_load() */
552 pf->fd_width = open( path, O_RDONLY|O_BINARY );
553 pf->fd_offset = open( path, O_RDONLY|O_BINARY );
554
555 glyph_cache_load( path, pf );
556
557 /* cached font: pf->fd stays open until the font is unloaded */
558 close( pf->fd_width );
559 pf->fd_width = -1;
560 close( pf->fd_offset );
561 pf->fd_offset = -1;
562 }
563 else
564 {
565 lseek( fd, 0, SEEK_SET);
566 read(fd, pf->buffer_start, pf->buffer_size);
567
568 close( fd );
569 pf->fd = -1;
570
571 if ( ! font_load_in_memory( pf, nwidth, noffset ) )
572 {
573 core_free( handle );
574 return -1;
575 }
576 }
Fred Baueree7de142011-10-14 14:04:27 +0000577 buflib_allocations[font_id] = handle;
Jonathan Gordonf19f3ef2011-11-08 10:09:33 +0000578 //printf("%s -> [%d] -> %d\n", path, font_id, *handle);
Fred Bauerea7a8962011-11-19 23:34:26 +0000579 lock_font_handle( handle, false );
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000580 return font_id; /* success!*/
581}
Fred Bauerea7a8962011-11-19 23:34:26 +0000582
Jonathan Gordon83cfbf42011-09-24 14:52:16 +0000583int font_load(const char *path)
584{
Fred Bauerea7a8962011-11-19 23:34:26 +0000585 return font_load_ex(path, MAX_FONT_SIZE, GLYPHS_TO_CACHE);
Jonathan Gordon83cfbf42011-09-24 14:52:16 +0000586}
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000587
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000588void font_unload(int font_id)
589{
Frank Gevaerts6e664f42011-11-27 15:36:03 +0000590 if ( font_id < 0 || font_id >= MAXFONTS )
Fred Bauer10097412011-10-16 13:18:46 +0000591 return;
592 int handle = buflib_allocations[font_id];
593 if ( handle < 0 )
594 return;
595 struct buflib_alloc_data *pdata = core_get_data(handle);
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000596 struct font* pf = &pdata->font;
597 pdata->refcount--;
598 if (pdata->refcount < 1)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000599 {
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000600 //printf("freeing id: %d %s\n", font_id, core_get_name(*handle));
601 if (pf && pf->fd >= 0)
Fred Bauer10097412011-10-16 13:18:46 +0000602 {
603 glyph_cache_save(font_id);
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000604 close(pf->fd);
Fred Bauer10097412011-10-16 13:18:46 +0000605 }
606 if (handle > 0)
607 core_free(handle);
608 buflib_allocations[font_id] = -1;
609
610 }
611}
612
613void font_unload_all(void)
614{
615 int i;
616 for (i=0; i<MAXFONTS; i++)
617 {
618 if (buflib_allocations[i] > 0)
619 {
620 struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[i]);
621 alloc->refcount = 1; /* force unload */
622 font_unload(i);
623 }
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000624 }
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000625}
626
Thomas Martitzc23ce622014-01-15 13:37:40 +0100627static void font_disable(int font_id)
628{
629 if ( font_id < 0 || font_id >= MAXFONTS )
630 return;
631 int handle = buflib_allocations[font_id];
632 if ( handle < 0 )
633 return;
634 struct buflib_alloc_data *pdata = core_get_data(handle);
635 struct font *pf = &pdata->font;
636
637 if (pf->fd >= 0)
638 {
639 /* save the cache, but it keep it in-RAM so that cache lookups
640 * can still succeed on the same font */
641 glyph_cache_save(font_id);
642 close(pf->fd);
643 pf->fd = -1;
Thomas Martitz37be80a2014-01-26 13:56:53 +0100644 pf->disabled = true;
Thomas Martitzc23ce622014-01-15 13:37:40 +0100645 }
646}
647
648void font_disable_all(void)
649{
650 for(int i = 0; i < MAXFONTS; i++)
651 font_disable(i);
652}
653
654static void font_enable(int font_id)
655{
656 if ( font_id < 0 || font_id >= MAXFONTS )
657 return;
658 int handle = buflib_allocations[font_id];
659 if ( handle < 0 )
660 return;
661 struct buflib_alloc_data *pdata = core_get_data(handle);
662 struct font *pf = &pdata->font;
663
Thomas Martitz37be80a2014-01-26 13:56:53 +0100664 if (pf->disabled && pf->fd < 0)
Thomas Martitzc23ce622014-01-15 13:37:40 +0100665 {
666 const char *filename = font_filename(font_id);
667 pf->fd = open(filename, O_RDONLY);
Thomas Martitz37be80a2014-01-26 13:56:53 +0100668 pf->disabled = false;
Thomas Martitzc23ce622014-01-15 13:37:40 +0100669 }
670}
671
672void font_enable_all(void)
673{
674 for(int i = 0; i < MAXFONTS; i++)
675 font_enable(i);
676}
677
678
Daniel Stenberg93b231c2002-09-12 13:33:59 +0000679/*
680 * Return a pointer to an incore font structure.
Jonathan Gordonf19f3ef2011-11-08 10:09:33 +0000681 * If the requested font isn't loaded/compiled-in,
682 * decrement the font number and try again.
Daniel Stenberg93b231c2002-09-12 13:33:59 +0000683 */
Jonathan Gordonf19f3ef2011-11-08 10:09:33 +0000684struct font* font_get(int font)
Daniel Stenberg93b231c2002-09-12 13:33:59 +0000685{
Jonathan Gordonf19f3ef2011-11-08 10:09:33 +0000686 struct font* pf;
687 if (font == FONT_UI)
688 font = MAXFONTS-1;
689 if (font <= FONT_SYSFIXED)
Fred Bauere299eb32011-10-22 17:13:33 +0000690 return &sysfont;
Jonathan Gordonf19f3ef2011-11-08 10:09:33 +0000691
692 while (1) {
693 if (buflib_allocations[font] > 0)
694 {
695 struct buflib_alloc_data *alloc = core_get_data(buflib_allocations[font]);
696 pf = &alloc->font;
697 if (pf && pf->height)
698 return pf;
699 }
700 if (--font < 0)
701 return &sysfont;
Daniel Stenberg93b231c2002-09-12 13:33:59 +0000702 }
703}
Christian Gmeinerc6ec0f42005-04-19 12:47:16 +0000704
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000705/*
706 * Reads an entry into cache entry
707 */
708static void
709load_cache_entry(struct font_cache_entry* p, void* callback_data)
710{
711 struct font* pf = callback_data;
Fred Bauerea7a8962011-11-19 23:34:26 +0000712
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000713 unsigned short char_code = p->_char_code;
714 unsigned char tmp[2];
Fred Bauer8c901722011-10-17 13:17:04 +0000715 int fd;
Teruaki Kawashima3e4b5c62010-02-26 07:16:32 +0000716
Fred Bauerea7a8962011-11-19 23:34:26 +0000717 lock_font_handle(pf->handle, true);
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000718 if (pf->file_width_offset)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000719 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000720 int width_offset = pf->file_width_offset + char_code;
Fred Bauer8c901722011-10-17 13:17:04 +0000721 /* load via different fd to get this file section cached */
722 if(pf->fd_width >=0 )
723 fd = pf->fd_width;
724 else
725 fd = pf->fd;
726 lseek(fd, width_offset, SEEK_SET);
727 read(fd, &(p->width), 1);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000728 }
729 else
730 {
731 p->width = pf->maxwidth;
732 }
Teruaki Kawashima3e4b5c62010-02-26 07:16:32 +0000733
Nils Wallméniusdf155c82007-06-30 17:54:02 +0000734 int32_t bitmap_offset = 0;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000735
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000736 if (pf->file_offset_offset)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000737 {
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000738 int32_t offset = pf->file_offset_offset + char_code * (pf->long_offset ? sizeof(int32_t) : sizeof(int16_t));
Fred Bauer8c901722011-10-17 13:17:04 +0000739 /* load via different fd to get this file section cached */
740 if(pf->fd_offset >=0 )
741 fd = pf->fd_offset;
742 else
743 fd = pf->fd;
744 lseek(fd, offset, SEEK_SET);
745 read (fd, tmp, 2);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000746 bitmap_offset = tmp[0] | (tmp[1] << 8);
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000747 if (pf->long_offset) {
Fred Bauer8c901722011-10-17 13:17:04 +0000748 read (fd, tmp, 2);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000749 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
750 }
751 }
752 else
753 {
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000754 bitmap_offset = char_code * glyph_bytes(pf, p->width);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000755 }
756
Nils Wallméniusdf155c82007-06-30 17:54:02 +0000757 int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000758 lseek(pf->fd, file_offset, SEEK_SET);
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000759 int src_bytes = glyph_bytes(pf, p->width);
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000760 read(pf->fd, p->bitmap, src_bytes);
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000761
Fred Bauerea7a8962011-11-19 23:34:26 +0000762 lock_font_handle(pf->handle, false);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000763}
764
765/*
766 * Converts cbuf into a font cache
767 */
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000768static void cache_create(struct font* pf)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000769{
770 /* maximum size of rotated bitmap */
Thomas Martitzc23ce622014-01-15 13:37:40 +0100771 int bitmap_size = glyph_bytes(pf, pf->maxwidth);
772 /* reserve one blank glyph that is guaranteed to be available, even
773 * when the font file is closed during USB */
774 unsigned char *cache_buf = pf->buffer_start + bitmap_size;
Thomas Martitz37be80a2014-01-26 13:56:53 +0100775 size_t cache_size = pf->buffer_size - bitmap_size;
Thomas Martitzc23ce622014-01-15 13:37:40 +0100776 ALIGN_BUFFER(cache_buf, cache_size, 2);
777 memset(pf->buffer_start, 0, bitmap_size);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000778 /* Initialise cache */
Thomas Martitzc23ce622014-01-15 13:37:40 +0100779 font_cache_create(&pf->cache, cache_buf, cache_size, bitmap_size);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000780}
781
782/*
783 * Returns width of character
784 */
785int font_get_width(struct font* pf, unsigned short char_code)
786{
Thomas Martitzc23ce622014-01-15 13:37:40 +0100787 int width;
788 struct font_cache_entry *e;
Thomas Martitzc23ce622014-01-15 13:37:40 +0100789
Marcoen Hirschbergd2576832006-03-22 09:53:27 +0000790 /* check input range*/
791 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
792 char_code = pf->defaultchar;
793 char_code -= pf->firstchar;
794
Thomas Martitz37be80a2014-01-26 13:56:53 +0100795 if (pf->fd >= 0 && pf != &sysfont)
796 width = font_cache_get(&pf->cache,char_code,false,load_cache_entry,pf)->width;
797 else if (pf->disabled &&
798 (e = font_cache_get(&pf->cache,char_code,true,load_cache_entry,pf)))
799 width = e->width; /* falls back to pf->maxwidth if !e */
Thomas Martitzc23ce622014-01-15 13:37:40 +0100800 else if (pf->width)
801 width = pf->width[char_code];
802 else
803 width = pf->maxwidth;
804
805 return width;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000806}
Teruaki Kawashima3e4b5c62010-02-26 07:16:32 +0000807
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000808const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
809{
810 const unsigned char* bits;
Marcoen Hirschbergd2576832006-03-22 09:53:27 +0000811
812 /* check input range*/
813 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
814 char_code = pf->defaultchar;
815 char_code -= pf->firstchar;
816
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000817 if (pf->fd >= 0 && pf != &sysfont)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000818 {
Fred Bauerea7a8962011-11-19 23:34:26 +0000819 bits =
Thomas Martitzc23ce622014-01-15 13:37:40 +0100820 (unsigned char*)font_cache_get(&pf->cache, char_code,
Thomas Martitz37be80a2014-01-26 13:56:53 +0100821 false, load_cache_entry, pf)->bitmap;
Thomas Martitzc23ce622014-01-15 13:37:40 +0100822 }
Thomas Martitz37be80a2014-01-26 13:56:53 +0100823 else if (pf->disabled)
Thomas Martitzc23ce622014-01-15 13:37:40 +0100824 {
825 /* the font handle is closed, but the cache is intact. Attempt
826 * a lookup, which is very likely to succeed. Return a placeholder
827 * glyph on miss (again, this is very unlikely */
828 struct font_cache_entry *e = font_cache_get(&pf->cache, char_code,
829 true, NULL, NULL);
830 if (LIKELY(e))
831 bits = (unsigned char *) e->bitmap;
832 else
833 {
834 /* Could attempt to find a suitable fallback glyph from the same
835 * font. For now just return blank space which is
836 * reserved by cache_create() at buffer_start */
837 bits = pf->buffer_start;
838 }
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000839 }
840 else
841 {
Thomas Martitzc23ce622014-01-15 13:37:40 +0100842 /* This font is entirely in RAM */
Nils Wallménius559c5692009-12-13 11:07:40 +0000843 bits = pf->bits;
844 if (pf->offset)
845 {
846 if (pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS)
847 bits += ((uint16_t*)(pf->offset))[char_code];
848 else
849 bits += ((uint32_t*)(pf->offset))[char_code];
850 }
851 else
Thomas Martitz9edd6d42011-03-05 18:36:51 +0000852 bits += char_code * glyph_bytes(pf, pf->maxwidth);
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000853 }
Nils Wallménius559c5692009-12-13 11:07:40 +0000854
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000855 return bits;
856}
Fred Bauer10097412011-10-16 13:18:46 +0000857
Bertrik Sikkene71750b2011-11-03 23:32:49 +0000858static void font_path_to_glyph_path( const char *font_path, char *glyph_path)
Fred Bauer10097412011-10-16 13:18:46 +0000859{
860 /* take full file name, cut extension, and add .glyphcache */
861 strlcpy(glyph_path, font_path, MAX_PATH);
862 glyph_path[strlen(glyph_path)-4] = '\0';
863 strcat(glyph_path, ".gc");
864}
865
866/* call with NULL to flush */
Nils Wallméniusdf155c82007-06-30 17:54:02 +0000867static void glyph_file_write(void* data)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000868{
869 struct font_cache_entry* p = data;
Fred Bauer10097412011-10-16 13:18:46 +0000870 struct font* pf = cache_pf;
Marcoen Hirschbergd2576832006-03-22 09:53:27 +0000871 unsigned short ch;
Fred Bauer10097412011-10-16 13:18:46 +0000872 static int buffer_pos = 0;
873#define WRITE_BUFFER 256
874 static unsigned char buffer[WRITE_BUFFER];
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000875
Fred Bauer10097412011-10-16 13:18:46 +0000876 /* flush buffer & reset */
877 if ( data == NULL || buffer_pos >= WRITE_BUFFER)
878 {
879 write(cache_fd, buffer, buffer_pos);
880 buffer_pos = 0;
881 if ( data == NULL )
882 return;
883 }
Frank Gevaerts1994df62010-08-23 18:17:54 +0000884 if ( p->_char_code == 0xffff )
885 return;
886
Marcoen Hirschbergd2576832006-03-22 09:53:27 +0000887 ch = p->_char_code + pf->firstchar;
Fred Bauer10097412011-10-16 13:18:46 +0000888 buffer[buffer_pos] = ch >> 8;
889 buffer[buffer_pos+1] = ch & 0xff;
890 buffer_pos += 2;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000891 return;
892}
893
894/* save the char codes of the loaded glyphs to a file */
Frank Gevaertsdfd5d062011-11-27 15:28:16 +0000895static void glyph_cache_save(int font_id)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000896{
Fred Bauer10097412011-10-16 13:18:46 +0000897 int fd;
898
899 if( font_id < 0 )
Jonathan Gordonaa0f4a42011-09-24 13:19:34 +0000900 return;
Fred Bauer10097412011-10-16 13:18:46 +0000901 int handle = buflib_allocations[font_id];
902 if ( handle < 0 )
903 return;
904
905 struct font *pf = pf_from_handle(handle);
906 if(pf && pf->fd >= 0)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000907 {
Fred Bauer10097412011-10-16 13:18:46 +0000908 char filename[MAX_PATH];
909 font_path_to_glyph_path(font_filename(font_id), filename);
910 fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
911 if (fd < 0)
Thomas Martitz9c0b2472010-08-01 16:15:27 +0000912 return;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000913
Fred Bauer10097412011-10-16 13:18:46 +0000914 cache_pf = pf;
915 cache_fd = fd;
916 lru_traverse(&cache_pf->cache._lru, glyph_file_write);
917 glyph_file_write(NULL);
918 if (cache_fd >= 0)
Jonathan Gordon1c2aa352010-02-14 06:26:16 +0000919 {
920 close(cache_fd);
921 cache_fd = -1;
922 }
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000923 }
924 return;
925}
926
Jonathan Gordonfaaf4312010-08-25 14:11:38 +0000927
Frank Gevaerts1994df62010-08-23 18:17:54 +0000928static int ushortcmp(const void *a, const void *b)
929{
930 return ((int)(*(unsigned short*)a - *(unsigned short*)b));
931}
Fred Bauerea7a8962011-11-19 23:34:26 +0000932static void glyph_cache_load(const char *font_path, struct font *pf)
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000933{
Frank Gevaerts1994df62010-08-23 18:17:54 +0000934#define MAX_SORT 256
Fred Bauer10097412011-10-16 13:18:46 +0000935 if (pf->fd >= 0) {
936 int i, size, fd;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000937 unsigned char tmp[2];
938 unsigned short ch;
Frank Gevaerts1994df62010-08-23 18:17:54 +0000939 unsigned short glyphs[MAX_SORT];
940 unsigned short glyphs_lru_order[MAX_SORT];
941 int glyph_file_skip=0, glyph_file_size=0;
942
943 int sort_size = pf->cache._capacity;
944 if ( sort_size > MAX_SORT )
945 sort_size = MAX_SORT;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000946
Fred Bauer10097412011-10-16 13:18:46 +0000947 char filename[MAX_PATH];
Fred Bauerea7a8962011-11-19 23:34:26 +0000948 font_path_to_glyph_path(font_path, filename);
Fred Bauer10097412011-10-16 13:18:46 +0000949
950 fd = open(filename, O_RDONLY|O_BINARY);
951#ifdef TRY_DEFAULT_GLYPHCACHE
952 /* if font specific file fails, try default */
953 if (fd < 0)
954 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
955#endif
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000956 if (fd >= 0) {
Frank Gevaerts1994df62010-08-23 18:17:54 +0000957 /* only read what fits */
958 glyph_file_size = filesize( fd );
959 if ( glyph_file_size > 2*pf->cache._capacity ) {
960 glyph_file_skip = glyph_file_size - 2*pf->cache._capacity;
961 lseek( fd, glyph_file_skip, SEEK_SET );
962 }
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000963
Frank Gevaerts1994df62010-08-23 18:17:54 +0000964 while(1) {
965
966 for ( size = 0;
967 read( fd, tmp, 2 ) == 2 && size < sort_size;
968 size++ )
969 {
970 glyphs[size] = (tmp[0] << 8) | tmp[1];
971 glyphs_lru_order[size] = glyphs[size];
972 }
973
974 /* sort glyphs array to make sector cache happy */
975 qsort((void *)glyphs, size, sizeof(unsigned short),
976 ushortcmp );
977
978 /* load font bitmaps */
Fred Bauer10097412011-10-16 13:18:46 +0000979 for( i = 0; i < size ; i++ )
Frank Gevaerts1994df62010-08-23 18:17:54 +0000980 font_get_bits(pf, glyphs[i]);
Frank Gevaerts1994df62010-08-23 18:17:54 +0000981
982 /* redo to fix lru order */
983 for ( i = 0; i < size ; i++)
984 font_get_bits(pf, glyphs_lru_order[i]);
985
986 if ( size < sort_size )
987 break;
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000988 }
989
990 close(fd);
991 } else {
992 /* load latin1 chars into cache */
Fred Baueredb28752010-08-27 15:10:30 +0000993 for ( ch = 32 ; ch < 256 && ch < pf->cache._capacity + 32; ch++ )
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +0000994 font_get_bits(pf, ch);
995 }
996 }
997 return;
998}
Jens Arnoldae878ff2008-09-23 21:35:54 +0000999#else /* BOOTLOADER */
Daniel Stenberg93b231c2002-09-12 13:33:59 +00001000
Jens Arnoldae878ff2008-09-23 21:35:54 +00001001void font_init(void)
1002{
1003}
1004
Dominik Riebelingc032b9d2011-10-21 20:15:26 +00001005void font_lock(int font_id, bool lock)
1006{
1007 (void)font_id;
1008 (void)lock;
1009}
1010
Jens Arnoldae878ff2008-09-23 21:35:54 +00001011/*
1012 * Bootloader only supports the built-in sysfont.
1013 */
1014struct font* font_get(int font)
1015{
1016 (void)font;
Andree Buschmann05778b52010-01-03 10:50:34 +00001017 return &sysfont;
Jens Arnoldae878ff2008-09-23 21:35:54 +00001018}
1019
1020/*
1021 * Returns width of character
1022 */
1023int font_get_width(struct font* pf, unsigned short char_code)
1024{
1025 /* check input range*/
1026 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
1027 char_code = pf->defaultchar;
1028 char_code -= pf->firstchar;
1029
1030 return pf->width? pf->width[char_code]: pf->maxwidth;
1031}
Teruaki Kawashima3e4b5c62010-02-26 07:16:32 +00001032
Jens Arnoldae878ff2008-09-23 21:35:54 +00001033const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
1034{
1035 const unsigned char* bits;
1036
1037 /* check input range*/
1038 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
1039 char_code = pf->defaultchar;
1040 char_code -= pf->firstchar;
1041
Nils Wallménius559c5692009-12-13 11:07:40 +00001042 /* assume small font with uint16_t offsets*/
Jens Arnoldae878ff2008-09-23 21:35:54 +00001043 bits = pf->bits + (pf->offset?
Nils Wallménius66776bc2009-12-13 11:19:06 +00001044 ((uint16_t*)(pf->offset))[char_code]:
Jens Arnoldae878ff2008-09-23 21:35:54 +00001045 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
Teruaki Kawashima3e4b5c62010-02-26 07:16:32 +00001046
Jens Arnoldae878ff2008-09-23 21:35:54 +00001047 return bits;
1048}
1049
1050#endif /* BOOTLOADER */
1051
1052/*
1053 * Returns the stringsize of a given string.
1054 */
1055int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
1056{
1057 struct font* pf = font_get(fontnumber);
1058 unsigned short ch;
1059 int width = 0;
1060
Fred Bauer04a015d2011-10-21 18:05:52 +00001061 font_lock( fontnumber, true );
Jens Arnoldae878ff2008-09-23 21:35:54 +00001062 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
1063 {
Tomer Shalev7682cb52009-11-24 20:41:42 +00001064 if (is_diacritic(ch, NULL))
1065 continue;
Jens Arnoldae878ff2008-09-23 21:35:54 +00001066
1067 /* get proportional width and glyph bits*/
1068 width += font_get_width(pf,ch);
1069 }
1070 if ( w )
1071 *w = width;
1072 if ( h )
1073 *h = pf->height;
Fred Bauer04a015d2011-10-21 18:05:52 +00001074 font_lock( fontnumber, false );
Jens Arnoldae878ff2008-09-23 21:35:54 +00001075 return width;
1076}
Daniel Stenberg93b231c2002-09-12 13:33:59 +00001077
1078/* -----------------------------------------------------------------
Eric Linenberg038df5c2002-09-16 03:18:49 +00001079 * vim: et sw=4 ts=8 sts=4 tw=78
Daniel Stenberg93b231c2002-09-12 13:33:59 +00001080 */