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