a80e97327f3d6cdb20a99f4e8fb359353db419f4
[blender-staging.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 #ifdef WITH_FREETYPE2
34
35 #include <ft2build.h>
36
37 #include FT_FREETYPE_H
38 #include FT_GLYPH_H
39
40 #endif /* WITH_FREETYPE2 */
41
42 #include "MEM_guardedalloc.h"
43
44 #include "DNA_listBase.h"
45 #include "DNA_vec_types.h"
46
47 #include "BKE_utildefines.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_linklist.h"       /* linknode */
51 #include "BLI_string.h"
52 #include "BLI_arithb.h"
53
54 #include "BIF_gl.h"
55 #include "BLF_api.h"
56
57 #include "blf_internal_types.h"
58 #include "blf_internal.h"
59
60
61 #ifdef WITH_FREETYPE2
62
63 /* freetype2 handle. */
64 FT_Library global_ft_lib;
65
66 int blf_font_init(void)
67 {
68         return(FT_Init_FreeType(&global_ft_lib));
69 }
70
71 void blf_font_exit(void)
72 {
73         FT_Done_FreeType(global_ft_lib);
74 }
75
76 void blf_font_size(FontBLF *font, int size, int dpi)
77 {
78         GlyphCacheBLF *gc;
79         FT_Error err;
80
81         err= FT_Set_Char_Size((FT_Face)font->engine, 0, (size * 64), dpi, dpi);
82         if (err) {
83                 /* FIXME: here we can go through the fixed size and choice a close one */
84                 printf("The current font don't support the size, %d and dpi, %d\n", size, dpi);
85                 return;
86         }
87
88         font->size= size;
89         font->dpi= dpi;
90
91         gc= blf_glyph_cache_find(font, size, dpi);
92         if (gc)
93                 font->glyph_cache= gc;
94         else {
95                 gc= blf_glyph_cache_new(font);
96                 if (gc)
97                         font->glyph_cache= gc;
98                 else
99                         font->glyph_cache= NULL;
100         }
101 }
102
103 void blf_font_draw(FontBLF *font, char *str)
104 {
105         unsigned int c;
106         GlyphBLF *g, *g_prev;
107         FT_Vector delta;
108         FT_Face face;
109         FT_UInt glyph_index, g_prev_index;
110         int pen_x, pen_y;
111         int i, has_kerning;
112
113         face= (FT_Face)font->engine;
114         i= 0;
115         pen_x= 0;
116         pen_y= 0;
117         has_kerning= FT_HAS_KERNING(face);
118         g_prev= NULL;
119         g_prev_index= 0;
120
121         while (str[i]) {
122                 c= blf_utf8_next((unsigned char *)str, &i);
123                 if (c == 0)
124                         break;
125
126                 glyph_index= FT_Get_Char_Index(face, c);
127                 g= blf_glyph_search(font->glyph_cache, c);
128                 if (!g)
129                         g= blf_glyph_add(font, glyph_index, c);
130
131                 /* if we don't found a glyph, skip it. */
132                 if (!g)
133                         continue;
134
135                 if (has_kerning && g_prev) {
136                         delta.x= 0;
137                         delta.y= 0;
138
139                         FT_Get_Kerning(face, g_prev_index, glyph_index, FT_KERNING_UNFITTED, &delta);
140                         pen_x += delta.x >> 6;
141                 }
142
143                 /* This only return zero if the clipping is enable and the glyph is out of the clip rctf. */
144                 if (blf_glyph_render(font, g, (float)pen_x, (float)pen_y) == 0)
145                         break;
146
147                 pen_x += g->advance;
148                 g_prev= g;
149                 g_prev_index= glyph_index;
150         }
151 }
152
153 void blf_font_boundbox(FontBLF *font, char *str, rctf *box)
154 {
155         unsigned int c;
156         GlyphBLF *g, *g_prev;
157         FT_Vector delta;
158         FT_UInt glyph_index, g_prev_index;
159         FT_Face face;
160         rctf gbox;
161         int pen_x, pen_y;
162         int i, has_kerning;
163
164         face= (FT_Face)font->engine;
165         box->xmin= 32000.0f;
166         box->xmax= -32000.0f;
167         box->ymin= 32000.0f;
168         box->ymax= -32000.0f;
169
170         i= 0;
171         pen_x= 0;
172         pen_y= 0;
173         has_kerning= FT_HAS_KERNING(face);
174         g_prev= NULL;
175         g_prev_index= 0;
176
177         while (str[i]) {
178                 c= blf_utf8_next((unsigned char *)str, &i);
179                 if (c == 0)
180                         break;
181
182                 glyph_index= FT_Get_Char_Index(face, c);
183                 g= blf_glyph_search(font->glyph_cache, c);
184                 if (!g)
185                         g= blf_glyph_add(font, glyph_index, c);
186
187                 /* if we don't found a glyph, skip it. */
188                 if (!g)
189                         continue;
190
191                 if (has_kerning && g_prev) {
192                         delta.x= 0;
193                         delta.y= 0;
194
195                         FT_Get_Kerning(face, g_prev_index, glyph_index, FT_KERNING_UNFITTED, &delta);
196                         pen_x += delta.x >> 6;
197                 }
198
199                 gbox.xmin= g->box.xmin + pen_x;
200                 gbox.xmax= g->box.xmax + pen_x;
201                 gbox.ymin= g->box.ymin + pen_y;
202                 gbox.ymax= g->box.ymax + pen_y;
203
204                 if (gbox.xmin < box->xmin)
205                         box->xmin= gbox.xmin;
206                 if (gbox.ymin < box->ymin)
207                         box->ymin= gbox.ymin;
208
209                 if (gbox.xmax > box->xmax)
210                         box->xmax= gbox.xmax;
211                 if (gbox.ymax > box->ymax)
212                         box->ymax= gbox.ymax;
213
214                 pen_x += g->advance;
215                 g_prev= g;
216                 g_prev_index= glyph_index;
217         }
218
219         if (box->xmin > box->xmax) {
220                 box->xmin= 0.0f;
221                 box->ymin= 0.0f;
222                 box->xmax= 0.0f;
223                 box->ymax= 0.0f;
224         }
225 }
226
227 float blf_font_width(FontBLF *font, char *str)
228 {
229         rctf box;
230
231         blf_font_boundbox(font, str, &box);
232         return((box.xmax - box.xmin) * font->aspect);
233 }
234
235 float blf_font_height(FontBLF *font, char *str)
236 {
237         rctf box;
238
239         blf_font_boundbox(font, str, &box);
240         return((box.ymax - box.ymin) * font->aspect);
241 }
242
243 void blf_font_free(FontBLF *font)
244 {
245         GlyphCacheBLF *gc;
246
247         font->glyph_cache= NULL;
248         while (font->cache.first) {
249                 gc= font->cache.first;
250                 BLI_remlink(&font->cache, gc);
251                 blf_glyph_cache_free(gc);
252         }
253
254         FT_Done_Face((FT_Face)font->engine);
255         if (font->filename)
256                 MEM_freeN(font->filename);
257         if (font->name)
258                 MEM_freeN(font->name);
259         MEM_freeN(font);
260 }
261
262 void blf_font_fill(FontBLF *font)
263 {
264         font->type= BLF_FONT_FREETYPE2;
265         font->ref= 1;
266         font->aspect= 1.0f;
267         font->pos[0]= 0.0f;
268         font->pos[1]= 0.0f;
269         font->angle= 0.0f;
270         Mat4One(font->mat);
271         font->clip_rec.xmin= 0.0f;
272         font->clip_rec.xmax= 0.0f;
273         font->clip_rec.ymin= 0.0f;
274         font->clip_rec.ymax= 0.0f;
275         font->flags= 0;
276         font->dpi= 0;
277         font->size= 0;
278         font->cache.first= NULL;
279         font->cache.last= NULL;
280         font->glyph_cache= NULL;
281         glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size);
282
283         font->size_set= blf_font_size;
284         font->draw= blf_font_draw;
285         font->boundbox_get= blf_font_boundbox;
286         font->width_get= blf_font_width;
287         font->height_get= blf_font_height;
288         font->free= blf_font_free;
289 }
290
291 FontBLF *blf_font_new(char *name, char *filename)
292 {
293         FontBLF *font;
294         FT_Error err;
295         FT_Face face;
296
297         err= FT_New_Face(global_ft_lib, filename, 0, &face);
298         if (err)
299                 return(NULL);
300
301         err= FT_Select_Charmap(face, ft_encoding_unicode);
302         if (err) {
303                 printf("Can't set the unicode character map!\n");
304                 FT_Done_Face(face);
305                 return(NULL);
306         }
307
308         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new");
309         font->name= BLI_strdup(name);
310         font->filename= BLI_strdup(filename);
311         font->engine= (void *)face;
312         blf_font_fill(font);
313         return(font);
314 }
315
316 FontBLF *blf_font_new_from_mem(char *name, unsigned char *mem, int mem_size)
317 {
318         FontBLF *font;
319         FT_Error err;
320         FT_Face face;
321
322         err= FT_New_Memory_Face(global_ft_lib, mem, mem_size, 0, &face);
323         if (err)
324                 return(NULL);
325
326         err= FT_Select_Charmap(face, ft_encoding_unicode);
327         if (err) {
328                 printf("Can't set the unicode character map!\n");
329                 FT_Done_Face(face);
330                 return(NULL);
331         }
332
333         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new_from_mem");
334         font->name= BLI_strdup(name);
335         font->filename= NULL;
336         font->engine= (void *)face;
337         blf_font_fill(font);
338         return(font);
339 }
340
341 #else /* !WITH_FREETYPE2 */
342
343 int blf_font_init(void)
344 {
345         return(0);
346 }
347
348 void blf_font_exit(void)
349 {
350 }
351
352 #endif /* WITH_FREETYPE2 */