1 #include "config.h"
2
3 #include <ft2build.h>
4 #include FT_FREETYPE_H
5 #include FT_GLYPH_H
6 #include <math.h>
7 #include <string.h>
8 #include <sys/types.h>
9
10 #include "blend.h"
11 #include "colormod.h"
12 #include "common.h"
13 #include "font.h"
14 #include "image.h"
15 #include "rgbadraw.h"
16 #include "rotate.h"
17
18 FT_Library ft_lib;
19
20 static int __imlib_hash_gen(const char *key);
21 static int imlib_list_alloc_error(void);
22
23 static int _imlib_hash_alloc_error = 0;
24 static int _imlib_list_alloc_error = 0;
25
26 void
__imlib_font_init(void)27 __imlib_font_init(void)
28 {
29 static int initialised = 0;
30 int error;
31
32 if (initialised)
33 return;
34 error = FT_Init_FreeType(&ft_lib);
35 if (error)
36 return;
37 initialised = 1;
38 }
39
40 int
__imlib_font_ascent_get(ImlibFont * fn)41 __imlib_font_ascent_get(ImlibFont * fn)
42 {
43 int val;
44 int ret;
45
46 val = (int)fn->ft.face->ascender;
47 fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
48 * val */
49 ret =
50 (val * fn->ft.face->size->metrics.y_scale) /
51 (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
52 return ret;
53 }
54
55 int
__imlib_font_descent_get(ImlibFont * fn)56 __imlib_font_descent_get(ImlibFont * fn)
57 {
58 int val;
59 int ret;
60
61 val = -(int)fn->ft.face->descender;
62 fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
63 * val */
64 ret =
65 (val * fn->ft.face->size->metrics.y_scale) /
66 (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
67 return ret;
68 }
69
70 int
__imlib_font_max_ascent_get(ImlibFont * fn)71 __imlib_font_max_ascent_get(ImlibFont * fn)
72 {
73 int val;
74 int ret;
75
76 val = (int)fn->ft.face->bbox.yMax;
77 fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
78 * val */
79 ret =
80 (val * fn->ft.face->size->metrics.y_scale) /
81 (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
82 return ret;
83 }
84
85 int
__imlib_font_max_descent_get(ImlibFont * fn)86 __imlib_font_max_descent_get(ImlibFont * fn)
87 {
88 int val;
89 int ret;
90
91 val = (int)fn->ft.face->bbox.yMin;
92 fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
93 * val */
94 ret =
95 (val * fn->ft.face->size->metrics.y_scale) /
96 (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
97 return ret;
98 }
99
100 int
__imlib_font_get_line_advance(ImlibFont * fn)101 __imlib_font_get_line_advance(ImlibFont * fn)
102 {
103 int val;
104 int ret;
105
106 val = (int)fn->ft.face->height;
107 fn->ft.face->units_per_EM = 2048; /* nasy hack - need to have correct
108 * val */
109 ret =
110 (val * fn->ft.face->size->metrics.y_scale) /
111 (fn->ft.face->units_per_EM * fn->ft.face->units_per_EM);
112 return ret;
113 }
114
115 int
__imlib_font_utf8_get_next(unsigned char * buf,int * iindex)116 __imlib_font_utf8_get_next(unsigned char *buf, int *iindex)
117 {
118 /* Reads UTF8 bytes from @buf, starting at *@index and returns the code
119 * point of the next valid code point. @index is updated ready for the
120 * next call.
121 *
122 * * Returns 0 to indicate an error (e.g. invalid UTF8) */
123
124 int index = *iindex, r;
125 unsigned char d = buf[index++], d2, d3, d4;
126
127 if (!d)
128 return 0;
129 if (d < 0x80)
130 {
131 *iindex = index;
132 return d;
133 }
134 if ((d & 0xe0) == 0xc0)
135 {
136 /* 2 byte */
137 d2 = buf[index++];
138 if ((d2 & 0xc0) != 0x80)
139 return 0;
140 r = d & 0x1f; /* copy lower 5 */
141 r <<= 6;
142 r |= (d2 & 0x3f); /* copy lower 6 */
143 }
144 else if ((d & 0xf0) == 0xe0)
145 {
146 /* 3 byte */
147 d2 = buf[index++];
148 d3 = buf[index++];
149 if ((d2 & 0xc0) != 0x80 || (d3 & 0xc0) != 0x80)
150 return 0;
151 r = d & 0x0f; /* copy lower 4 */
152 r <<= 6;
153 r |= (d2 & 0x3f);
154 r <<= 6;
155 r |= (d3 & 0x3f);
156 }
157 else
158 {
159 /* 4 byte */
160 d2 = buf[index++];
161 d3 = buf[index++];
162 d4 = buf[index++];
163 if ((d2 & 0xc0) != 0x80 || (d3 & 0xc0) != 0x80 || (d4 & 0xc0) != 0x80)
164 return 0;
165 r = d & 0x0f; /* copy lower 4 */
166 r <<= 6;
167 r |= (d2 & 0x3f);
168 r <<= 6;
169 r |= (d3 & 0x3f);
170 r <<= 6;
171 r |= (d4 & 0x3f);
172
173 }
174 *iindex = index;
175 return r;
176 }
177
178 /* TODO put this somewhere else */
179
180 void *
__imlib_object_list_prepend(void * in_list,void * in_item)181 __imlib_object_list_prepend(void *in_list, void *in_item)
182 {
183 Imlib_Object_List *new_l;
184 Imlib_Object_List *list, *item;
185
186 list = in_list;
187 item = in_item;
188 new_l = item;
189 new_l->prev = NULL;
190 if (!list)
191 {
192 new_l->next = NULL;
193 new_l->last = new_l;
194 return new_l;
195 }
196 new_l->next = list;
197 list->prev = new_l;
198 new_l->last = list->last;
199 list->last = NULL;
200 return new_l;
201 }
202
203 void *
__imlib_object_list_remove(void * in_list,void * in_item)204 __imlib_object_list_remove(void *in_list, void *in_item)
205 {
206 Imlib_Object_List *return_l;
207 Imlib_Object_List *list, *item;
208
209 /* checkme */
210 if (!in_list)
211 return in_list;
212
213 list = in_list;
214 item = in_item;
215 if (!item)
216 return list;
217 if (item->next)
218 item->next->prev = item->prev;
219 if (item->prev)
220 {
221 item->prev->next = item->next;
222 return_l = list;
223 }
224 else
225 {
226 return_l = item->next;
227 if (return_l)
228 return_l->last = list->last;
229 }
230 if (item == list->last)
231 list->last = item->prev;
232 item->next = NULL;
233 item->prev = NULL;
234 return return_l;
235 }
236
237 static int
__imlib_hash_gen(const char * key)238 __imlib_hash_gen(const char *key)
239 {
240 unsigned int hash_num = 0;
241 const unsigned char *ptr;
242
243 if (!key)
244 return 0;
245
246 for (ptr = (unsigned char *)key; *ptr; ptr++)
247 hash_num ^= (int)(*ptr);
248
249 hash_num &= 0xff;
250 return (int)hash_num;
251 }
252
253 Imlib_Hash *
__imlib_hash_add(Imlib_Hash * hash,const char * key,const void * data)254 __imlib_hash_add(Imlib_Hash * hash, const char *key, const void *data)
255 {
256 int hash_num;
257 Imlib_Hash_El *el;
258
259 _imlib_hash_alloc_error = 0;
260 if (!hash)
261 {
262 hash = calloc(1, sizeof(struct _Imlib_Hash));
263 if (!hash)
264 {
265 _imlib_hash_alloc_error = 1;
266 return NULL;
267 }
268 }
269 if (!(el = malloc(sizeof(struct _Imlib_Hash_El))))
270 {
271 if (hash->population <= 0)
272 {
273 free(hash);
274 hash = NULL;
275 }
276 _imlib_hash_alloc_error = 1;
277 return hash;
278 };
279 if (key)
280 {
281 el->key = strdup(key);
282 if (!el->key)
283 {
284 free(el);
285 _imlib_hash_alloc_error = 1;
286 return hash;
287 }
288 hash_num = __imlib_hash_gen(key);
289 }
290 else
291 {
292 el->key = NULL;
293 hash_num = 0;
294 }
295 el->data = (void *)data;
296
297 hash->buckets[hash_num] =
298 __imlib_object_list_prepend(hash->buckets[hash_num], el);
299
300 if (imlib_list_alloc_error())
301 {
302 _imlib_hash_alloc_error = 1;
303 if (el->key)
304 free(el->key);
305 free(el);
306 return hash;
307 }
308 hash->population++;
309 return hash;
310 }
311
312 void *
__imlib_hash_find(Imlib_Hash * hash,const char * key)313 __imlib_hash_find(Imlib_Hash * hash, const char *key)
314 {
315 int hash_num;
316 Imlib_Hash_El *el;
317 Imlib_Object_List *l;
318
319 _imlib_hash_alloc_error = 0;
320 if (!hash)
321 return NULL;
322 hash_num = __imlib_hash_gen(key);
323 for (l = hash->buckets[hash_num]; l; l = l->next)
324 {
325 el = (Imlib_Hash_El *) l;
326 if (((el->key) && (key) && (!strcmp(el->key, key)))
327 || ((!el->key) && (!key)))
328 {
329 if (l != hash->buckets[hash_num])
330 {
331 /* FIXME: move to front of list without alloc */
332 hash->buckets[hash_num] =
333 __imlib_object_list_remove(hash->buckets[hash_num], el);
334 hash->buckets[hash_num] =
335 __imlib_object_list_prepend(hash->buckets[hash_num], el);
336 if (imlib_list_alloc_error())
337 {
338 _imlib_hash_alloc_error = 1;
339 return el->data;
340 }
341 }
342 return el->data;
343 }
344 }
345 return NULL;
346 }
347
348 static int
__imlib_hash_size(Imlib_Hash * hash)349 __imlib_hash_size(Imlib_Hash * hash)
350 {
351 if (!hash)
352 return 0;
353 return 256;
354 }
355
356 void
__imlib_hash_free(Imlib_Hash * hash)357 __imlib_hash_free(Imlib_Hash * hash)
358 {
359 int i, size;
360
361 if (!hash)
362 return;
363 size = __imlib_hash_size(hash);
364 for (i = 0; i < size; i++)
365 {
366 while (hash->buckets[i])
367 {
368 Imlib_Hash_El *el;
369
370 el = (Imlib_Hash_El *) hash->buckets[i];
371 if (el->key)
372 free(el->key);
373 hash->buckets[i] =
374 __imlib_object_list_remove(hash->buckets[i], el);
375 free(el);
376 }
377 }
378 free(hash);
379 }
380
381 void
__imlib_hash_foreach(Imlib_Hash * hash,int (* func)(Imlib_Hash * hash,const char * key,void * data,void * fdata),const void * fdata)382 __imlib_hash_foreach(Imlib_Hash * hash, int (*func)(Imlib_Hash * hash,
383 const char *key,
384 void *data, void *fdata),
385 const void *fdata)
386 {
387 int i, size;
388
389 if (!hash)
390 return;
391 size = __imlib_hash_size(hash);
392 for (i = 0; i < size; i++)
393 {
394 Imlib_Object_List *l, *next_l;
395
396 for (l = hash->buckets[i]; l;)
397 {
398 Imlib_Hash_El *el;
399
400 next_l = l->next;
401 el = (Imlib_Hash_El *) l;
402 if (!func(hash, el->key, el->data, (void *)fdata))
403 return;
404 l = next_l;
405 }
406 }
407 }
408
409 int
imlib_list_alloc_error(void)410 imlib_list_alloc_error(void)
411 {
412 return _imlib_list_alloc_error;
413 }
414