Merge from 2.5 r21112 through r21160
[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 #include <math.h>
33
34 #include <ft2build.h>
35
36 #include FT_FREETYPE_H
37 #include FT_GLYPH_H
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_listBase.h"
42 #include "DNA_vec_types.h"
43
44 #include "BKE_utildefines.h"
45
46 #include "BLI_blenlib.h"
47 #include "BLI_linklist.h"       /* linknode */
48 #include "BLI_string.h"
49 #include "BLI_arithb.h"
50
51 #include "BIF_gl.h"
52 #include "BLF_api.h"
53
54 #include "blf_internal_types.h"
55 #include "blf_internal.h"
56
57
58 /* freetype2 handle. */
59 FT_Library global_ft_lib;
60
61 int blf_font_init(void)
62 {
63         return(FT_Init_FreeType(&global_ft_lib));
64 }
65
66 void blf_font_exit(void)
67 {
68         FT_Done_FreeType(global_ft_lib);
69 }
70
71 void blf_font_size(FontBLF *font, int size, int dpi)
72 {
73         GlyphCacheBLF *gc;
74         FT_Error err;
75
76         err= FT_Set_Char_Size(font->face, 0, (size * 64), dpi, dpi);
77         if (err) {
78                 /* FIXME: here we can go through the fixed size and choice a close one */
79                 printf("The current font don't support the size, %d and dpi, %d\n", size, dpi);
80                 return;
81         }
82
83         font->size= size;
84         font->dpi= dpi;
85
86         gc= blf_glyph_cache_find(font, size, dpi);
87         if (gc)
88                 font->glyph_cache= gc;
89         else {
90                 gc= blf_glyph_cache_new(font);
91                 if (gc)
92                         font->glyph_cache= gc;
93                 else
94                         font->glyph_cache= NULL;
95         }
96 }
97
98 void blf_font_draw(FontBLF *font, char *str)
99 {
100         unsigned int c;
101         GlyphBLF *g, *g_prev;
102         FT_Vector delta;
103         FT_UInt glyph_index, g_prev_index;
104         float pen_x, pen_y, old_pen_x;
105         int i, has_kerning;
106
107         if (!font->glyph_cache)
108                 return;
109
110         i= 0;
111         pen_x= 0;
112         pen_y= 0;
113         has_kerning= FT_HAS_KERNING(font->face);
114         g_prev= NULL;
115         g_prev_index= 0;
116
117         while (str[i]) {
118                 c= blf_utf8_next((unsigned char *)str, &i);
119                 if (c == 0)
120                         break;
121
122                 glyph_index= FT_Get_Char_Index(font->face, c);
123                 g= blf_glyph_search(font->glyph_cache, c);
124                 if (!g)
125                         g= blf_glyph_add(font, glyph_index, c);
126
127                 /* if we don't found a glyph, skip it. */
128                 if (!g)
129                         continue;
130
131                 /*
132                  * This happen if we change the mode of the
133                  * font, we don't drop the glyph cache, so it's
134                  * possible that some glyph don't have the
135                  * bitmap or texture information.
136                  */
137                 if (font->mode == BLF_MODE_BITMAP && (!g->bitmap_data))
138                         g= blf_glyph_add(font, glyph_index, c);
139                 else if (font->mode == BLF_MODE_TEXTURE && (!g->tex_data))
140                         g= blf_glyph_add(font, glyph_index, c);
141
142                 if ((font->flags & BLF_FONT_KERNING) && has_kerning && g_prev) {
143                         old_pen_x= pen_x;
144                         delta.x= 0;
145                         delta.y= 0;
146
147                         if (FT_Get_Kerning(font->face, g_prev_index, glyph_index, FT_KERNING_UNFITTED, &delta) == 0) {
148                                 pen_x += delta.x >> 6;
149
150                                 if (font->flags & BLF_OVERLAP_CHAR) {
151                                         if (pen_x < old_pen_x)
152                                                 pen_x= old_pen_x;
153                                 }
154                         }
155                 }
156
157                 if (font->flags & BLF_USER_KERNING) {
158                         old_pen_x= pen_x;
159                         pen_x += font->kerning;
160
161                         if (font->flags & BLF_OVERLAP_CHAR) {
162                                 if (pen_x < old_pen_x)
163                                         pen_x= old_pen_x;
164                         }
165                 }
166
167                 /* do not return this loop if clipped, we want every character tested */
168                 blf_glyph_render(font, g, pen_x, pen_y);
169
170                 pen_x += g->advance;
171                 g_prev= g;
172                 g_prev_index= glyph_index;
173         }
174 }
175
176 void blf_font_boundbox(FontBLF *font, char *str, rctf *box)
177 {
178         unsigned int c;
179         GlyphBLF *g, *g_prev;
180         FT_Vector delta;
181         FT_UInt glyph_index, g_prev_index;
182         rctf gbox;
183         float pen_x, pen_y, old_pen_x;
184         int i, has_kerning;
185
186         if (!font->glyph_cache)
187                 return;
188
189         box->xmin= 32000.0f;
190         box->xmax= -32000.0f;
191         box->ymin= 32000.0f;
192         box->ymax= -32000.0f;
193
194         i= 0;
195         pen_x= 0;
196         pen_y= 0;
197         has_kerning= FT_HAS_KERNING(font->face);
198         g_prev= NULL;
199         g_prev_index= 0;
200
201         while (str[i]) {
202                 c= blf_utf8_next((unsigned char *)str, &i);
203                 if (c == 0)
204                         break;
205
206                 glyph_index= FT_Get_Char_Index(font->face, c);
207                 g= blf_glyph_search(font->glyph_cache, c);
208                 if (!g)
209                         g= blf_glyph_add(font, glyph_index, c);
210
211                 /* if we don't found a glyph, skip it. */
212                 if (!g)
213                         continue;
214
215                 /*
216                  * This happen if we change the mode of the
217                  * font, we don't drop the glyph cache, so it's
218                  * possible that some glyph don't have the
219                  * bitmap or texture information.
220                  */
221                 if (font->mode == BLF_MODE_BITMAP && (!g->bitmap_data))
222                         g= blf_glyph_add(font, glyph_index, c);
223                 else if (font->mode == BLF_MODE_TEXTURE && (!g->tex_data))
224                         g= blf_glyph_add(font, glyph_index, c);
225
226                 if ((font->flags & BLF_FONT_KERNING) && has_kerning && g_prev) {
227                         old_pen_x= pen_x;
228                         delta.x= 0;
229                         delta.y= 0;
230
231                         if (FT_Get_Kerning(font->face, g_prev_index, glyph_index, FT_KERNING_UNFITTED, &delta) == 0) {
232                                 pen_x += delta.x >> 6;
233
234                                 if (font->flags & BLF_OVERLAP_CHAR) {
235                                         if (pen_x < old_pen_x)
236                                                 pen_x= old_pen_x;
237                                 }
238                         }
239                 }
240
241                 if (font->flags & BLF_USER_KERNING) {
242                         old_pen_x= pen_x;
243                         pen_x += font->kerning;
244
245                         if (font->flags & BLF_OVERLAP_CHAR) {
246                                 if (pen_x < old_pen_x)
247                                         pen_x= old_pen_x;
248                         }
249                 }
250
251                 gbox.xmin= g->box.xmin + pen_x;
252                 gbox.xmax= g->box.xmax + pen_x;
253                 gbox.ymin= g->box.ymin + pen_y;
254                 gbox.ymax= g->box.ymax + pen_y;
255
256                 if (gbox.xmin < box->xmin)
257                         box->xmin= gbox.xmin;
258                 if (gbox.ymin < box->ymin)
259                         box->ymin= gbox.ymin;
260
261                 if (gbox.xmax > box->xmax)
262                         box->xmax= gbox.xmax;
263                 if (gbox.ymax > box->ymax)
264                         box->ymax= gbox.ymax;
265
266                 pen_x += g->advance;
267                 g_prev= g;
268                 g_prev_index= glyph_index;
269         }
270
271         if (box->xmin > box->xmax) {
272                 box->xmin= 0.0f;
273                 box->ymin= 0.0f;
274                 box->xmax= 0.0f;
275                 box->ymax= 0.0f;
276         }
277 }
278
279 float blf_font_width(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.xmax - box.xmin) * font->aspect);
288 }
289
290 float blf_font_height(FontBLF *font, char *str)
291 {
292         rctf box;
293
294         if (!font->glyph_cache)
295                 return(0.0f);
296
297         blf_font_boundbox(font, str, &box);
298         return((box.ymax - box.ymin) * font->aspect);
299 }
300
301 void blf_font_free(FontBLF *font)
302 {
303         GlyphCacheBLF *gc;
304
305         font->glyph_cache= NULL;
306         while (font->cache.first) {
307                 gc= font->cache.first;
308                 BLI_remlink(&font->cache, gc);
309                 blf_glyph_cache_free(gc);
310         }
311
312         FT_Done_Face(font->face);
313         if (font->filename)
314                 MEM_freeN(font->filename);
315         if (font->name)
316                 MEM_freeN(font->name);
317         MEM_freeN(font);
318 }
319
320 void blf_font_fill(FontBLF *font)
321 {
322         font->mode= BLF_MODE_TEXTURE;
323         font->aspect= 1.0f;
324         font->pos[0]= 0.0f;
325         font->pos[1]= 0.0f;
326         font->angle= 0.0f;
327         Mat4One(font->mat);
328         font->clip_rec.xmin= 0.0f;
329         font->clip_rec.xmax= 0.0f;
330         font->clip_rec.ymin= 0.0f;
331         font->clip_rec.ymax= 0.0f;
332         font->flags= BLF_USER_KERNING | BLF_FONT_KERNING;
333         font->dpi= 0;
334         font->size= 0;
335         font->kerning= 0.0f;
336         font->cache.first= NULL;
337         font->cache.last= NULL;
338         font->glyph_cache= NULL;
339         font->blur= 0;
340         glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size);
341 }
342
343 FontBLF *blf_font_new(char *name, char *filename)
344 {
345         FontBLF *font;
346         FT_Error err;
347         char *mfile;
348
349         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new");
350         err= FT_New_Face(global_ft_lib, filename, 0, &font->face);
351         if (err) {
352                 MEM_freeN(font);
353                 return(NULL);
354         }
355
356         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
357         if (err) {
358                 printf("Can't set the unicode character map!\n");
359                 FT_Done_Face(font->face);
360                 MEM_freeN(font);
361                 return(NULL);
362         }
363
364         mfile= blf_dir_metrics_search(filename);
365         if (mfile) {
366                 err= FT_Attach_File(font->face, mfile);
367                 MEM_freeN(mfile);
368         }
369
370         font->name= BLI_strdup(name);
371         font->filename= BLI_strdup(filename);
372         blf_font_fill(font);
373         return(font);
374 }
375
376 void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
377 {
378         FT_Open_Args open;
379
380         open.flags= FT_OPEN_MEMORY;
381         open.memory_base= (FT_Byte *)mem;
382         open.memory_size= mem_size;
383         FT_Attach_Stream(font->face, &open);
384 }
385
386 FontBLF *blf_font_new_from_mem(char *name, unsigned char *mem, int mem_size)
387 {
388         FontBLF *font;
389         FT_Error err;
390
391         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new_from_mem");
392         err= FT_New_Memory_Face(global_ft_lib, mem, mem_size, 0, &font->face);
393         if (err) {
394                 MEM_freeN(font);
395                 return(NULL);
396         }
397
398         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
399         if (err) {
400                 printf("Can't set the unicode character map!\n");
401                 FT_Done_Face(font->face);
402                 MEM_freeN(font);
403                 return(NULL);
404         }
405
406         font->name= BLI_strdup(name);
407         font->filename= NULL;
408         blf_font_fill(font);
409         return(font);
410 }