Fix leaking file descriptors on error.
[kugel-rb.git] / firmware / font_cache.c
blob843c1520c182ea7a4d0c811bd996df90a5f21bd6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2003 Tat Tang
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 #include <string.h>
22 #include "font_cache.h"
23 #include "debug.h"
25 /*******************************************************************************
26 * font_cache_lru_init
27 ******************************************************************************/
28 static void font_cache_lru_init(void* data)
30 struct font_cache_entry* p = data;
31 p->_char_code = 0xffff; /* assume invalid char */
34 /*******************************************************************************
35 * font_cache_create
36 ******************************************************************************/
37 void font_cache_create(
38 struct font_cache* fcache,
39 void *buf,
40 int buf_size,
41 int bitmap_bytes_size)
43 int font_cache_entry_size =
44 sizeof(struct font_cache_entry) + bitmap_bytes_size;
46 /* make sure font cache entries are a multiple of 16 bits */
47 if (font_cache_entry_size % 2 != 0)
48 font_cache_entry_size++;
50 int cache_size = buf_size /
51 (font_cache_entry_size + LRU_SLOT_OVERHEAD + sizeof(short));
53 fcache->_size = 1;
54 fcache->_capacity = cache_size;
56 /* set up index */
57 fcache->_index = buf;
59 /* set up lru list */
60 unsigned char* lru_buf = buf;
61 lru_buf += sizeof(short) * cache_size;
62 lru_create(&fcache->_lru, lru_buf, cache_size, font_cache_entry_size);
64 /* initialise cache */
65 lru_traverse(&fcache->_lru, font_cache_lru_init);
66 short i;
67 for (i = 0; i < cache_size; i++)
68 fcache->_index[i] = i; /* small cheat here */
71 /*******************************************************************************
72 * font_cache_index_of
73 ******************************************************************************/
74 static int font_cache_index_of(
75 struct font_cache* fcache,
76 unsigned short char_code)
78 struct font_cache_entry* p;
79 int left, right, mid, c;
80 left = 0;
81 right = fcache->_size - 1;
85 mid = (left + right) / 2;
87 p = lru_data(&fcache->_lru, fcache->_index[mid]);
88 c = p->_char_code - char_code;
90 if (c == 0)
91 return mid;
93 if (c < 0)
94 left = mid + 1;
95 else
96 right = mid - 1;
98 while (left <= right);
100 return -1;
103 /*******************************************************************************
104 * font_cache_insertion_point
105 ******************************************************************************/
106 static int font_cache_insertion_point(
107 struct font_cache* fcache,
108 unsigned short char_code)
110 struct font_cache_entry* p;
111 short *index = fcache->_index;
113 p = lru_data(&fcache->_lru, index[0]);
114 if (char_code < p->_char_code)
115 return -1;
117 p = lru_data(&fcache->_lru, index[fcache->_capacity - 1]);
118 if (char_code > p->_char_code)
119 return fcache->_capacity - 1;
121 int left, right, mid, c;
123 left = 0;
124 right = fcache->_capacity - 1;
128 mid = (left + right) / 2;
130 p = lru_data(&fcache->_lru, index[mid]);
131 c = char_code - p->_char_code;
133 if (c >= 0)
135 p = lru_data(&fcache->_lru, index[mid+1]);
136 int z = char_code - p->_char_code;
138 if (z < 0)
139 return mid;
141 if (z == 0)
142 return mid + 1;
146 if (c > 0)
147 left = mid + 1;
148 else
149 right = mid - 1;
151 while (left <= right);
153 /* not found */
154 return -2;
157 /*******************************************************************************
158 * font_cache_get
159 ******************************************************************************/
160 struct font_cache_entry* font_cache_get(
161 struct font_cache* fcache,
162 unsigned short char_code,
163 void (*callback) (struct font_cache_entry* p, void *callback_data),
164 void *callback_data)
166 int insertion_point = font_cache_insertion_point(fcache, char_code);
167 if (insertion_point >= 0)
169 short lru_handle = fcache->_index[insertion_point];
170 struct font_cache_entry* p = lru_data(&fcache->_lru, lru_handle);
171 if (p->_char_code == char_code)
173 lru_touch(&fcache->_lru, lru_handle);
174 return lru_data(&fcache->_lru, lru_handle);
178 /* not found */
179 short lru_handle_to_replace = fcache->_lru._head;
180 struct font_cache_entry* p =
181 lru_data(&fcache->_lru, lru_handle_to_replace);
182 int index_to_replace = font_cache_index_of(fcache, p->_char_code);
184 if (insertion_point < index_to_replace)
186 /* shift memory up */
187 memmove(fcache->_index + insertion_point + 2,
188 fcache->_index + insertion_point + 1,
189 (index_to_replace - insertion_point - 1) * sizeof(short));
191 /* add to index */
192 fcache->_index[insertion_point + 1] = lru_handle_to_replace;
194 else if (insertion_point > index_to_replace)
196 /* shift memory down */
197 memmove(fcache->_index + index_to_replace,
198 fcache->_index + index_to_replace + 1,
199 (insertion_point - index_to_replace) * sizeof(short));
201 /* add to index */
202 fcache->_index[insertion_point] = lru_handle_to_replace;
205 /* load new entry into cache */
206 lru_touch(&fcache->_lru, lru_handle_to_replace);
208 if (fcache->_size < fcache->_capacity)
209 fcache->_size++;
211 p->_char_code = char_code;
212 callback(p, callback_data);
214 return p;