Made the kerning a float, this give a little more of tweak.
[blender.git] / source / blender / blenfont / intern / blf_font.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <ft2build.h>
34
35 #include FT_FREETYPE_H
36 #include FT_GLYPH_H
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_listBase.h"
41 #include "DNA_vec_types.h"
42
43 #include "BKE_utildefines.h"
44
45 #include "BLI_blenlib.h"
46 #include "BLI_linklist.h"       /* linknode */
47 #include "BLI_string.h"
48 #include "BLI_arithb.h"
49
50 #include "BIF_gl.h"
51 #include "BLF_api.h"
52
53 #include "blf_internal_types.h"
54 #include "blf_internal.h"
55
56
57 /* freetype2 handle. */
58 FT_Library global_ft_lib;
59
60 int blf_font_init(void)
61 {
62         return(FT_Init_FreeType(&global_ft_lib));
63 }
64
65 void blf_font_exit(void)
66 {
67         FT_Done_FreeType(global_ft_lib);
68 }
69
70 void blf_font_size(FontBLF *font, int size, int dpi)
71 {
72         GlyphCacheBLF *gc;
73         FT_Error err;
74
75         err= FT_Set_Char_Size(font->face, 0, (size * 64), dpi, dpi);
76         if (err) {
77                 /* FIXME: here we can go through the fixed size and choice a close one */
78                 printf("The current font don't support the size, %d and dpi, %d\n", size, dpi);
79                 return;
80         }
81
82         font->size= size;
83         font->dpi= dpi;
84
85         gc= blf_glyph_cache_find(font, size, dpi);
86         if (gc)
87                 font->glyph_cache= gc;
88         else {
89                 gc= blf_glyph_cache_new(font);
90                 if (gc)
91                         font->glyph_cache= gc;
92                 else
93                         font->glyph_cache= NULL;
94         }
95 }
96
97 void blf_font_draw(FontBLF *font, char *str)
98 {
99         unsigned int c;
100         GlyphBLF *g, *g_prev;
101         FT_Vector delta;
102         FT_UInt glyph_index, g_prev_index;
103         float pen_x, pen_y, old_pen_x;
104         int i, has_kerning;
105
106         if (!font->glyph_cache)
107                 return;
108
109         i= 0;
110         pen_x= 0;
111         pen_y= 0;
112         has_kerning= FT_HAS_KERNING(font->face);
113         g_prev= NULL;
114         g_prev_index= 0;
115
116         while (str[i]) {
117                 c= blf_utf8_next((unsigned char *)str, &i);
118                 if (c == 0)
119                         break;
120
121                 glyph_index= FT_Get_Char_Index(font->face, c);
122                 g= blf_glyph_search(font->glyph_cache, c);
123                 if (!g)
124                         g= blf_glyph_add(font, glyph_index, c);
125
126                 /* if we don't found a glyph, skip it. */
127                 if (!g)
128                         continue;
129
130                 /*
131                  * This happen if we change the mode of the
132                  * font, we don't drop the glyph cache, so it's
133                  * possible that some glyph don't have the
134                  * bitmap or texture information.
135                  */
136                 if (font->mode == BLF_MODE_BITMAP && (!g->bitmap_data))
137                         g= blf_glyph_add(font, glyph_index, c);
138                 else if (font->mode == BLF_MODE_TEXTURE && (!g->tex_data))
139                         g= blf_glyph_add(font, glyph_index, c);
140
141                 if ((font->flags & BLF_FONT_KERNING) && has_kerning && g_prev) {
142                         old_pen_x= pen_x;
143                         delta.x= 0;
144                         delta.y= 0;
145
146                         FT_Get_Kerning(font->face, g_prev_index, glyph_index, FT_KERNING_UNFITTED, &delta);
147                         pen_x += delta.x >> 6;
148
149                         if (pen_x < old_pen_x)
150                                 pen_x= old_pen_x;
151                 }
152
153                 if (font->flags & BLF_USER_KERNING) {
154                         old_pen_x= pen_x;
155                         pen_x += font->kerning;
156
157                         if (pen_x < old_pen_x)
158                                 pen_x= old_pen_x;
159                 }
160
161                 /* do not return this loop if clipped, we want every character tested */
162                 blf_glyph_render(font, g, pen_x, pen_y);
163
164                 pen_x += g->advance;
165                 g_prev= g;
166                 g_prev_index= glyph_index;
167         }
168 }
169
170 void blf_font_boundbox(FontBLF *font, char *str, rctf *box)
171 {
172         unsigned int c;
173         GlyphBLF *g, *g_prev;
174         FT_Vector delta;
175         FT_UInt glyph_index, g_prev_index;
176         rctf gbox;
177         int pen_x, pen_y, old_pen_x;
178         int i, has_kerning;
179
180         if (!font->glyph_cache)
181                 return;
182
183         box->xmin= 32000.0f;
184         box->xmax= -32000.0f;
185         box->ymin= 32000.0f;
186         box->ymax= -32000.0f;
187
188         i= 0;
189         pen_x= 0;
190         pen_y= 0;
191         has_kerning= FT_HAS_KERNING(font->face);
192         g_prev= NULL;
193         g_prev_index= 0;
194
195         while (str[i]) {
196                 c= blf_utf8_next((unsigned char *)str, &i);
197                 if (c == 0)
198                         break;
199
200                 glyph_index= FT_Get_Char_Index(font->face, c);
201                 g= blf_glyph_search(font->glyph_cache, c);
202                 if (!g)
203                         g= blf_glyph_add(font, glyph_index, c);
204
205                 /* if we don't found a glyph, skip it. */
206                 if (!g)
207                         continue;
208
209                 /*
210                  * This happen if we change the mode of the
211                  * font, we don't drop the glyph cache, so it's
212                  * possible that some glyph don't have the
213                  * bitmap or texture information.
214                  */
215                 if (font->mode == BLF_MODE_BITMAP && (!g->bitmap_data))
216                         g= blf_glyph_add(font, glyph_index, c);
217                 else if (font->mode == BLF_MODE_TEXTURE && (!g->tex_data))
218                         g= blf_glyph_add(font, glyph_index, c);
219
220                 if ((font->flags & BLF_FONT_KERNING) && has_kerning && g_prev) {
221                         old_pen_x= pen_x;
222                         delta.x= 0;
223                         delta.y= 0;
224
225                         FT_Get_Kerning(font->face, g_prev_index, glyph_index, FT_KERNING_UNFITTED, &delta);
226                         pen_x += delta.x >> 6;
227
228                         if (pen_x < old_pen_x)
229                                 old_pen_x= pen_x;
230                 }
231
232                 if (font->flags & BLF_USER_KERNING) {
233                         old_pen_x= pen_x;
234                         pen_x += font->kerning;
235
236                         if (pen_x < old_pen_x)
237                                 old_pen_x= pen_x;
238                 }
239
240                 gbox.xmin= g->box.xmin + pen_x;
241                 gbox.xmax= g->box.xmax + pen_x;
242                 gbox.ymin= g->box.ymin + pen_y;
243                 gbox.ymax= g->box.ymax + pen_y;
244
245                 if (gbox.xmin < box->xmin)
246                         box->xmin= gbox.xmin;
247                 if (gbox.ymin < box->ymin)
248                         box->ymin= gbox.ymin;
249
250                 if (gbox.xmax > box->xmax)
251                         box->xmax= gbox.xmax;
252                 if (gbox.ymax > box->ymax)
253                         box->ymax= gbox.ymax;
254
255                 pen_x += g->advance;
256                 g_prev= g;
257                 g_prev_index= glyph_index;
258         }
259
260         if (box->xmin > box->xmax) {
261                 box->xmin= 0.0f;
262                 box->ymin= 0.0f;
263                 box->xmax= 0.0f;
264                 box->ymax= 0.0f;
265         }
266 }
267
268 float blf_font_width(FontBLF *font, char *str)
269 {
270         rctf box;
271
272         if (!font->glyph_cache)
273                 return(0.0f);
274
275         blf_font_boundbox(font, str, &box);
276         return((box.xmax - box.xmin) * font->aspect);
277 }
278
279 float blf_font_height(FontBLF *font, char *str)
280 {
281         rctf box;
282
283         if (!font->glyph_cache)
284                 return(0.0f);
285
286         blf_font_boundbox(font, str, &box);
287         return((box.ymax - box.ymin) * font->aspect);
288 }
289
290 void blf_font_free(FontBLF *font)
291 {
292         GlyphCacheBLF *gc;
293
294         font->glyph_cache= NULL;
295         while (font->cache.first) {
296                 gc= font->cache.first;
297                 BLI_remlink(&font->cache, gc);
298                 blf_glyph_cache_free(gc);
299         }
300
301         FT_Done_Face(font->face);
302         if (font->filename)
303                 MEM_freeN(font->filename);
304         if (font->name)
305                 MEM_freeN(font->name);
306         MEM_freeN(font);
307 }
308
309 void blf_font_fill(FontBLF *font)
310 {
311         font->mode= BLF_MODE_TEXTURE;
312         font->aspect= 1.0f;
313         font->pos[0]= 0.0f;
314         font->pos[1]= 0.0f;
315         font->angle= 0.0f;
316         Mat4One(font->mat);
317         font->clip_rec.xmin= 0.0f;
318         font->clip_rec.xmax= 0.0f;
319         font->clip_rec.ymin= 0.0f;
320         font->clip_rec.ymax= 0.0f;
321         font->flags= BLF_USER_KERNING;
322         font->dpi= 0;
323         font->size= 0;
324         font->kerning= 0.0f;
325         font->cache.first= NULL;
326         font->cache.last= NULL;
327         font->glyph_cache= NULL;
328         font->blur= 0;
329         glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size);
330 }
331
332 FontBLF *blf_font_new(char *name, char *filename)
333 {
334         FontBLF *font;
335         FT_Error err;
336         char *mfile;
337
338         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new");
339         err= FT_New_Face(global_ft_lib, filename, 0, &font->face);
340         if (err) {
341                 MEM_freeN(font);
342                 return(NULL);
343         }
344
345         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
346         if (err) {
347                 printf("Can't set the unicode character map!\n");
348                 FT_Done_Face(font->face);
349                 MEM_freeN(font);
350                 return(NULL);
351         }
352
353         mfile= blf_dir_metrics_search(filename);
354         if (mfile) {
355                 err= FT_Attach_File(font->face, mfile);
356                 MEM_freeN(mfile);
357         }
358
359         font->name= BLI_strdup(name);
360         font->filename= BLI_strdup(filename);
361         blf_font_fill(font);
362         return(font);
363 }
364
365 void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
366 {
367         FT_Open_Args open;
368
369         open.flags= FT_OPEN_MEMORY;
370         open.memory_base= (FT_Byte *)mem;
371         open.memory_size= mem_size;
372         FT_Attach_Stream(font->face, &open);
373 }
374
375 FontBLF *blf_font_new_from_mem(char *name, unsigned char *mem, int mem_size)
376 {
377         FontBLF *font;
378         FT_Error err;
379
380         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new_from_mem");
381         err= FT_New_Memory_Face(global_ft_lib, mem, mem_size, 0, &font->face);
382         if (err) {
383                 MEM_freeN(font);
384                 return(NULL);
385         }
386
387         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
388         if (err) {
389                 printf("Can't set the unicode character map!\n");
390                 FT_Done_Face(font->face);
391                 MEM_freeN(font);
392                 return(NULL);
393         }
394
395         font->name= BLI_strdup(name);
396         font->filename= NULL;
397         blf_font_fill(font);
398         return(font);
399 }