Fix syntax for ID keyword.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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_math.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;
104         int pen_x, pen_y;
105         int i, has_kerning, st;
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
116         while (str[i]) {
117                 c= blf_utf8_next((unsigned char *)str, &i);
118                 if (c == 0)
119                         break;
120
121                 g= blf_glyph_search(font->glyph_cache, c);
122                 if (!g) {
123                         glyph_index= FT_Get_Char_Index(font->face, c);
124                         g= blf_glyph_add(font, glyph_index, c);
125                 }
126
127                 /* if we don't found a glyph, skip it. */
128                 if (!g)
129                         continue;
130
131                 if (has_kerning && g_prev) {
132                         delta.x= 0;
133                         delta.y= 0;
134
135                         if (font->flags & BLF_KERNING_DEFAULT)
136                                 st= FT_Get_Kerning(font->face, g_prev->idx, g->idx, ft_kerning_default, &delta);
137                         else
138                                 st= FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNFITTED, &delta);
139
140                         if (st == 0)
141                                 pen_x += delta.x >> 6;
142                 }
143
144                 /* do not return this loop if clipped, we want every character tested */
145                 blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
146
147                 pen_x += g->advance;
148                 g_prev= g;
149         }
150 }
151
152 void blf_font_buffer(FontBLF *font, char *str)
153 {
154         unsigned char *data, *cbuf;
155         unsigned int c;
156         GlyphBLF *g, *g_prev;
157         FT_Vector delta;
158         FT_UInt glyph_index;
159         float a, *fbuf;
160         int pen_x, pen_y, y, x, yb, diff;
161         int i, has_kerning, st, chx, chy;
162
163         if (!font->glyph_cache)
164                 return;
165
166         i= 0;
167         pen_x= (int)font->pos[0];
168         pen_y= (int)font->pos[1];
169         has_kerning= FT_HAS_KERNING(font->face);
170         g_prev= NULL;
171
172         while (str[i]) {
173                 c= blf_utf8_next((unsigned char *)str, &i);
174                 if (c == 0)
175                         break;
176
177                 g= blf_glyph_search(font->glyph_cache, c);
178                 if (!g) {
179                         glyph_index= FT_Get_Char_Index(font->face, c);
180                         g= blf_glyph_add(font, glyph_index, c);
181                 }
182
183                 /* if we don't found a glyph, skip it. */
184                 if (!g)
185                         continue;
186
187                 if (has_kerning && g_prev) {
188                         delta.x= 0;
189                         delta.y= 0;
190
191                         if (font->flags & BLF_KERNING_DEFAULT)
192                                 st= FT_Get_Kerning(font->face, g_prev->idx, g->idx, ft_kerning_default, &delta);
193                         else
194                                 st= FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNFITTED, &delta);
195
196                         if (st == 0)
197                                 pen_x += delta.x >> 6;
198                 }
199
200                 chx= pen_x + ((int)g->pos_x);
201                 diff= g->height - ((int)g->pos_y);
202                 if (diff > 0) {
203                         if (g->pitch < 0)
204                                 pen_y += diff;
205                         else
206                                 pen_y -= diff;
207                 }
208                 else if (diff < 0) {
209                         if (g->pitch < 0)
210                                 pen_y -= diff;
211                         else
212                                 pen_y += diff;
213                 }
214
215                 if (g->pitch < 0)
216                         chy= pen_y - ((int)g->pos_y);
217                 else
218                         chy= pen_y + ((int)g->pos_y);
219
220                 if (font->b_fbuf) {
221                         if (chx >= 0 && chx < font->bw && pen_y >= 0 && pen_y < font->bh) {
222                                 if (g->pitch < 0)
223                                         yb= 0;
224                                 else
225                                         yb= g->height-1;
226
227                                 for (y= 0; y < g->height; y++) {
228                                         for (x= 0; x < g->width; x++) {
229                                                 
230                                                 a= *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
231
232                                                 if(a > 0.0f) {
233                                                         fbuf= font->b_fbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
234                                                         if (a >= 1.0f) {
235                                                                 fbuf[0]= font->b_col[0];
236                                                                 fbuf[1]= font->b_col[1];
237                                                                 fbuf[2]= font->b_col[2];
238                                                         }
239                                                         else {
240                                                                 fbuf[0]= (font->b_col[0]*a) + (fbuf[0] * (1-a));
241                                                                 fbuf[1]= (font->b_col[1]*a) + (fbuf[1] * (1-a));
242                                                                 fbuf[2]= (font->b_col[2]*a) + (fbuf[2] * (1-a));
243                                                         }
244                                                 }
245                                         }
246
247                                         if (g->pitch < 0)
248                                                 yb++;
249                                         else
250                                                 yb--;
251                                 }
252                         }
253                 }
254
255                 if (font->b_cbuf) {
256                         if (chx >= 0 && chx < font->bw && pen_y >= 0 && pen_y < font->bh) {
257                                 char b_col_char[3];
258                                 b_col_char[0]= font->b_col[0] * 255;
259                                 b_col_char[1]= font->b_col[1] * 255;
260                                 b_col_char[2]= font->b_col[2] * 255;
261
262                                 if (g->pitch < 0)
263                                         yb= 0;
264                                 else
265                                         yb= g->height-1;
266
267                                 for (y= 0; y < g->height; y++) {
268                                         for (x= 0; x < g->width; x++) {
269                                                 a= *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
270
271                                                 if(a > 0.0f) {
272                                                         cbuf= font->b_cbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
273                                                         if (a >= 1.0f) {
274                                                                 cbuf[0]= b_col_char[0];
275                                                                 cbuf[1]= b_col_char[1];
276                                                                 cbuf[2]= b_col_char[2];
277                                                         }
278                                                         else {
279                                                                 cbuf[0]= (b_col_char[0]*a) + (cbuf[0] * (1-a));
280                                                                 cbuf[1]= (b_col_char[1]*a) + (cbuf[1] * (1-a));
281                                                                 cbuf[2]= (b_col_char[2]*a) + (cbuf[2] * (1-a));
282                                                         }
283                                                 }
284                                         }
285
286                                         if (g->pitch < 0)
287                                                 yb++;
288                                         else
289                                                 yb--;
290                                 }
291                         }
292                 }
293
294                 if (diff > 0) {
295                         if (g->pitch < 0)
296                                 pen_x -= diff;
297                         else
298                                 pen_y += diff;
299                 }
300                 else if (diff < 0) {
301                         if (g->pitch < 0)
302                                 pen_x += diff;
303                         else
304                                 pen_y -= diff;
305                 }
306
307                 pen_x += g->advance;
308                 g_prev= g;
309         }
310 }
311
312 void blf_font_boundbox(FontBLF *font, char *str, rctf *box)
313 {
314         unsigned int c;
315         GlyphBLF *g, *g_prev;
316         FT_Vector delta;
317         FT_UInt glyph_index;
318         rctf gbox;
319         int pen_x, pen_y;
320         int i, has_kerning, st;
321
322         if (!font->glyph_cache)
323                 return;
324
325         box->xmin= 32000.0f;
326         box->xmax= -32000.0f;
327         box->ymin= 32000.0f;
328         box->ymax= -32000.0f;
329
330         i= 0;
331         pen_x= 0;
332         pen_y= 0;
333         has_kerning= FT_HAS_KERNING(font->face);
334         g_prev= NULL;
335
336         while (str[i]) {
337                 c= blf_utf8_next((unsigned char *)str, &i);
338                 if (c == 0)
339                         break;
340
341                 g= blf_glyph_search(font->glyph_cache, c);
342                 if (!g) {
343                         glyph_index= FT_Get_Char_Index(font->face, c);
344                         g= blf_glyph_add(font, glyph_index, c);
345                 }
346
347                 /* if we don't found a glyph, skip it. */
348                 if (!g)
349                         continue;
350
351                 if (has_kerning && g_prev) {
352                         delta.x= 0;
353                         delta.y= 0;
354
355                         if (font->flags & BLF_KERNING_DEFAULT)
356                                 st= FT_Get_Kerning(font->face, g_prev->idx, g->idx, ft_kerning_default, &delta);
357                         else
358                                 st= FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNFITTED, &delta);
359
360                         if (st == 0)
361                                 pen_x += delta.x >> 6;
362                 }
363
364                 gbox.xmin= pen_x;
365                 gbox.xmax= pen_x + g->advance;
366                 gbox.ymin= g->box.ymin + pen_y;
367                 gbox.ymax= g->box.ymax + pen_y;
368
369                 if (gbox.xmin < box->xmin)
370                         box->xmin= gbox.xmin;
371                 if (gbox.ymin < box->ymin)
372                         box->ymin= gbox.ymin;
373
374                 if (gbox.xmax > box->xmax)
375                         box->xmax= gbox.xmax;
376                 if (gbox.ymax > box->ymax)
377                         box->ymax= gbox.ymax;
378
379                 pen_x += g->advance;
380                 g_prev= g;
381         }
382
383         if (box->xmin > box->xmax) {
384                 box->xmin= 0.0f;
385                 box->ymin= 0.0f;
386                 box->xmax= 0.0f;
387                 box->ymax= 0.0f;
388         }
389 }
390
391 void blf_font_width_and_height(FontBLF *font, char *str, float *width, float *height)
392 {
393         rctf box;
394
395         if (font->glyph_cache) {
396                 blf_font_boundbox(font, str, &box);
397                 *width= ((box.xmax - box.xmin) * font->aspect);
398                 *height= ((box.ymax - box.ymin) * font->aspect);
399         }
400 }
401
402 float blf_font_width(FontBLF *font, char *str)
403 {
404         rctf box;
405
406         if (!font->glyph_cache)
407                 return(0.0f);
408
409         blf_font_boundbox(font, str, &box);
410         return((box.xmax - box.xmin) * font->aspect);
411 }
412
413 float blf_font_height(FontBLF *font, char *str)
414 {
415         rctf box;
416
417         if (!font->glyph_cache)
418                 return(0.0f);
419
420         blf_font_boundbox(font, str, &box);
421         return((box.ymax - box.ymin) * font->aspect);
422 }
423
424 float blf_font_fixed_width(FontBLF *font)
425 {
426         GlyphBLF *g;
427         FT_UInt glyph_index;
428         unsigned int c = ' ';
429
430         if (!font->glyph_cache)
431                 return 0.0f;
432
433         glyph_index= FT_Get_Char_Index(font->face, c);
434         g= blf_glyph_search(font->glyph_cache, c);
435         if (!g)
436                 g= blf_glyph_add(font, glyph_index, c);
437
438         /* if we don't find the glyph. */
439         if (!g)
440                 return 0.0f;
441         
442         return g->advance;
443 }
444
445 void blf_font_free(FontBLF *font)
446 {
447         GlyphCacheBLF *gc;
448
449         font->glyph_cache= NULL;
450         while (font->cache.first) {
451                 gc= font->cache.first;
452                 BLI_remlink(&font->cache, gc);
453                 blf_glyph_cache_free(gc);
454         }
455
456         FT_Done_Face(font->face);
457         if (font->filename)
458                 MEM_freeN(font->filename);
459         if (font->name)
460                 MEM_freeN(font->name);
461         MEM_freeN(font);
462 }
463
464 static void blf_font_fill(FontBLF *font)
465 {
466         font->aspect= 1.0f;
467         font->pos[0]= 0.0f;
468         font->pos[1]= 0.0f;
469         font->angle= 0.0f;
470         unit_m4(font->mat);
471         font->clip_rec.xmin= 0.0f;
472         font->clip_rec.xmax= 0.0f;
473         font->clip_rec.ymin= 0.0f;
474         font->clip_rec.ymax= 0.0f;
475         font->flags= 0;
476         font->dpi= 0;
477         font->size= 0;
478         font->cache.first= NULL;
479         font->cache.last= NULL;
480         font->glyph_cache= NULL;
481         font->blur= 0;
482         font->max_tex_size= -1;
483         font->b_fbuf= NULL;
484         font->b_cbuf= NULL;
485         font->bw= 0;
486         font->bh= 0;
487         font->bch= 0;
488         font->b_col[0]= 0;
489         font->b_col[1]= 0;
490         font->b_col[2]= 0;
491         font->b_col[3]= 0;
492 }
493
494 FontBLF *blf_font_new(char *name, char *filename)
495 {
496         FontBLF *font;
497         FT_Error err;
498         char *mfile;
499
500         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new");
501         err= FT_New_Face(global_ft_lib, filename, 0, &font->face);
502         if (err) {
503                 MEM_freeN(font);
504                 return(NULL);
505         }
506
507         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
508         if (err) {
509                 printf("Can't set the unicode character map!\n");
510                 FT_Done_Face(font->face);
511                 MEM_freeN(font);
512                 return(NULL);
513         }
514
515         mfile= blf_dir_metrics_search(filename);
516         if (mfile) {
517                 err= FT_Attach_File(font->face, mfile);
518                 MEM_freeN(mfile);
519         }
520
521         font->name= BLI_strdup(name);
522         font->filename= BLI_strdup(filename);
523         blf_font_fill(font);
524         return(font);
525 }
526
527 void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
528 {
529         FT_Open_Args open;
530
531         open.flags= FT_OPEN_MEMORY;
532         open.memory_base= (FT_Byte *)mem;
533         open.memory_size= mem_size;
534         FT_Attach_Stream(font->face, &open);
535 }
536
537 FontBLF *blf_font_new_from_mem(char *name, unsigned char *mem, int mem_size)
538 {
539         FontBLF *font;
540         FT_Error err;
541
542         font= (FontBLF *)MEM_mallocN(sizeof(FontBLF), "blf_font_new_from_mem");
543         err= FT_New_Memory_Face(global_ft_lib, mem, mem_size, 0, &font->face);
544         if (err) {
545                 MEM_freeN(font);
546                 return(NULL);
547         }
548
549         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
550         if (err) {
551                 printf("Can't set the unicode character map!\n");
552                 FT_Done_Face(font->face);
553                 MEM_freeN(font);
554                 return(NULL);
555         }
556
557         font->name= BLI_strdup(name);
558         font->filename= NULL;
559         blf_font_fill(font);
560         return(font);
561 }