Improvements to bmesh edge rotate
[blender-staging.git] / source / blender / blenfont / intern / blf_font.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/blenfont/intern/blf_font.c
28  *  \ingroup blf
29  */
30
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #include <ft2build.h>
38
39 #include FT_FREETYPE_H
40 #include FT_GLYPH_H
41
42 #include "MEM_guardedalloc.h"
43
44 #include "DNA_vec_types.h"
45
46
47 #include "BLI_blenlib.h"
48 #include "BLI_linklist.h"       /* linknode */
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 ONLY for this file!. */
59 static FT_Library ft_lib;
60
61 int blf_font_init(void)
62 {
63         return FT_Init_FreeType(&ft_lib);
64 }
65
66 void blf_font_exit(void)
67 {
68         FT_Done_FreeType(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 static void blf_font_ensure_ascii_table(FontBLF *font)
99 {
100         GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
101
102         /* build ascii on demand */
103         if(glyph_ascii_table['0']==NULL) {
104                 GlyphBLF *g;
105                 unsigned int i;
106                 for(i=0; i<256; i++) {
107                         g= blf_glyph_search(font->glyph_cache, i);
108                         if (!g) {
109                                 FT_UInt glyph_index= FT_Get_Char_Index(font->face, i);
110                                 g= blf_glyph_add(font, glyph_index, i);
111                         }
112                         glyph_ascii_table[i]= g;
113                 }
114         }
115 }
116
117 /* Fast path for runs of ASCII characters. Given that common UTF-8
118  * input will consist of an overwhelming majority of ASCII
119  * characters.
120  */
121
122 /* Note,
123  * blf_font_ensure_ascii_table(font); must be called before this macro */
124
125 #define BLF_UTF8_NEXT_FAST(_font, _g, _str, _i, _c, _glyph_ascii_table)       \
126         if(((_c)= (_str)[_i]) < 0x80) {                                           \
127                 _g= (_glyph_ascii_table)[_c];                                         \
128                 _i++;                                                                 \
129         }                                                                         \
130         else if ((_c= BLI_str_utf8_as_unicode_step(_str, &(_i)))!=BLI_UTF8_ERR) { \
131                 if ((_g= blf_glyph_search((_font)->glyph_cache, _c)) == NULL) {       \
132                         _g= blf_glyph_add(_font,                                          \
133                                           FT_Get_Char_Index((_font)->face, _c), _c);      \
134                 }                                                                     \
135         }                                                                         \
136
137
138 #define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode)                     \
139         const short _has_kerning= FT_HAS_KERNING((_font)->face);                  \
140         const FT_UInt _kern_mode= (_has_kerning == 0) ? 0 :                       \
141                                  (((_font)->flags & BLF_KERNING_DEFAULT) ?        \
142                                   ft_kerning_default : FT_KERNING_UNFITTED)       \
143
144
145 #define BLF_KERNING_STEP(_font, _kern_mode, _g_prev, _g, _delta, _pen_x)      \
146 {                                                                             \
147         if (_g_prev) {                                                            \
148                 _delta.x= _delta.y= 0;                                                \
149                 if (FT_Get_Kerning((_font)->face,                                     \
150                                    (_g_prev)->idx,                                    \
151                                    (_g)->idx,                                         \
152                                    _kern_mode,                                        \
153                                    &(_delta)) == 0)                                   \
154                 {                                                                     \
155                         _pen_x += delta.x >> 6;                                           \
156                 }                                                                     \
157         }                                                                         \
158 }                                                                             \
159
160 void blf_font_draw(FontBLF *font, const char *str, unsigned int len)
161 {
162         unsigned int c;
163         GlyphBLF *g, *g_prev= NULL;
164         FT_Vector delta;
165         int pen_x= 0, pen_y= 0;
166         size_t i= 0;
167         GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
168
169         BLF_KERNING_VARS(font, has_kerning, kern_mode);
170
171         blf_font_ensure_ascii_table(font);
172
173         while (str[i] && i < len) {
174
175                 BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
176
177                 if (c == BLI_UTF8_ERR)  break;
178                 if (g == NULL)          continue;
179                 if (has_kerning)        BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
180
181                 /* do not return this loop if clipped, we want every character tested */
182                 blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
183
184                 pen_x += g->advance;
185                 g_prev= g;
186         }
187 }
188
189 /* faster version of blf_font_draw, ascii only for view dimensions */
190 void blf_font_draw_ascii(FontBLF *font, const char *str, unsigned int len)
191 {
192         unsigned char c;
193         GlyphBLF *g, *g_prev= NULL;
194         FT_Vector delta;
195         int pen_x= 0, pen_y= 0;
196         GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
197
198         BLF_KERNING_VARS(font, has_kerning, kern_mode);
199
200         blf_font_ensure_ascii_table(font);
201
202         while ((c= *(str++)) && len--) {
203                 if ((g= glyph_ascii_table[c]) == NULL) continue;
204                 if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
205
206                 /* do not return this loop if clipped, we want every character tested */
207                 blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
208
209                 pen_x += g->advance;
210                 g_prev= g;
211         }
212 }
213
214 /* Sanity checks are done by BLF_draw_buffer() */
215 void blf_font_buffer(FontBLF *font, const char *str)
216 {
217         unsigned int c;
218         GlyphBLF *g, *g_prev= NULL;
219         FT_Vector delta;
220         int pen_x= (int)font->pos[0], pen_y= 0;
221         size_t i= 0;
222         GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
223
224         /* buffer specific vars*/
225         const unsigned char b_col_char[4]= {font->b_col[0] * 255,
226                                             font->b_col[1] * 255,
227                                             font->b_col[2] * 255,
228                                             font->b_col[3] * 255};
229         unsigned char *cbuf;
230         int chx, chy;
231         int y, x;
232         float a, *fbuf;
233
234         BLF_KERNING_VARS(font, has_kerning, kern_mode);
235
236         blf_font_ensure_ascii_table(font);
237
238         while (str[i]) {
239
240                 BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
241
242                 if (c == BLI_UTF8_ERR)  break;
243                 if (g == NULL)          continue;
244                 if (has_kerning)        BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
245
246                 chx= pen_x + ((int)g->pos_x);
247                 chy= (int)font->pos[1] + g->height;
248
249                 if (g->pitch < 0) {
250                         pen_y = (int)font->pos[1] + (g->height - (int)g->pos_y);
251                 }
252                 else {
253                         pen_y = (int)font->pos[1] - (g->height - (int)g->pos_y);
254                 }
255
256                 if ((chx + g->width) >= 0 && chx < font->bw && (pen_y + g->height) >= 0 && pen_y < font->bh) {
257                         /* dont draw beyond the buffer bounds */
258                         int width_clip= g->width;
259                         int height_clip= g->height;
260                         int yb_start= g->pitch < 0 ? 0 : g->height-1;
261
262                         if (width_clip + chx > font->bw)        width_clip  -= chx + width_clip - font->bw;
263                         if (height_clip + pen_y > font->bh) height_clip -= pen_y + height_clip - font->bh;
264                         
265                         /* drawing below the image? */
266                         if(pen_y < 0) {
267                                 yb_start += (g->pitch < 0) ? -pen_y : pen_y;
268                                 height_clip += pen_y;
269                                 pen_y= 0;
270                         }
271
272                         if (font->b_fbuf) {
273                                 int yb= yb_start;
274                                 for (y=(chy >= 0 ? 0:-chy); y < height_clip; y++) {
275                                         for (x=(chx >= 0 ? 0:-chx); x < width_clip; x++) {
276                                                 
277                                                 a= *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
278
279                                                 if(a > 0.0f) {
280                                                         float alphatest;
281                                                         fbuf= font->b_fbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
282                                                         if (a >= 1.0f) {
283                                                                 fbuf[0]= font->b_col[0];
284                                                                 fbuf[1]= font->b_col[1];
285                                                                 fbuf[2]= font->b_col[2];
286                                                                 fbuf[3]= (alphatest= (fbuf[3] + (font->b_col[3]))) < 1.0f ? alphatest : 1.0f;
287                                                         }
288                                                         else {
289                                                                 fbuf[0]= (font->b_col[0]*a) + (fbuf[0] * (1-a));
290                                                                 fbuf[1]= (font->b_col[1]*a) + (fbuf[1] * (1-a));
291                                                                 fbuf[2]= (font->b_col[2]*a) + (fbuf[2] * (1-a));
292                                                                 fbuf[3]= (alphatest= (fbuf[3] + (font->b_col[3]*a))) < 1.0f ? alphatest : 1.0f;
293                                                         }
294                                                 }
295                                         }
296
297                                         if (g->pitch < 0)
298                                                 yb++;
299                                         else
300                                                 yb--;
301                                 }
302                         }
303
304                         if (font->b_cbuf) {
305                                 int yb= yb_start;
306                                 for (y= 0; y < height_clip; y++) {
307                                         for (x= 0; x < width_clip; x++) {
308                                                 a= *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
309
310                                                 if(a > 0.0f) {
311                                                         int alphatest;
312                                                         cbuf= font->b_cbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
313                                                         if (a >= 1.0f) {
314                                                                 cbuf[0]= b_col_char[0];
315                                                                 cbuf[1]= b_col_char[1];
316                                                                 cbuf[2]= b_col_char[2];
317                                                                 cbuf[3]= (alphatest= ((int)cbuf[3] + (int)b_col_char[3])) < 255 ? alphatest : 255;
318                                                         }
319                                                         else {
320                                                                 cbuf[0]= (b_col_char[0]*a) + (cbuf[0] * (1-a));
321                                                                 cbuf[1]= (b_col_char[1]*a) + (cbuf[1] * (1-a));
322                                                                 cbuf[2]= (b_col_char[2]*a) + (cbuf[2] * (1-a));
323                                                                 cbuf[3]= (alphatest= ((int)cbuf[3] + (int)((font->b_col[3]*a)*255.0f))) < 255 ? alphatest : 255;
324                                                         }
325                                                 }
326                                         }
327
328                                         if (g->pitch < 0)
329                                                 yb++;
330                                         else
331                                                 yb--;
332                                 }
333                         }
334                 }
335
336                 pen_x += g->advance;
337                 g_prev= g;
338         }
339 }
340
341 void blf_font_boundbox(FontBLF *font, const char *str, rctf *box)
342 {
343         unsigned int c;
344         GlyphBLF *g, *g_prev= NULL;
345         FT_Vector delta;
346         int pen_x= 0, pen_y= 0;
347         size_t i= 0;
348         GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
349
350         rctf gbox;
351
352         BLF_KERNING_VARS(font, has_kerning, kern_mode);
353
354         box->xmin= 32000.0f;
355         box->xmax= -32000.0f;
356         box->ymin= 32000.0f;
357         box->ymax= -32000.0f;
358
359         blf_font_ensure_ascii_table(font);
360
361         while (str[i]) {
362
363                 BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
364
365                 if (c == BLI_UTF8_ERR)  break;
366                 if (g == NULL)          continue;
367                 if (has_kerning)        BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
368
369                 gbox.xmin= pen_x;
370                 gbox.xmax= pen_x + g->advance;
371                 gbox.ymin= g->box.ymin + pen_y;
372                 gbox.ymax= g->box.ymax + pen_y;
373
374                 if (gbox.xmin < box->xmin) box->xmin= gbox.xmin;
375                 if (gbox.ymin < box->ymin) box->ymin= gbox.ymin;
376
377                 if (gbox.xmax > box->xmax) box->xmax= gbox.xmax;
378                 if (gbox.ymax > box->ymax) box->ymax= gbox.ymax;
379
380                 pen_x += g->advance;
381                 g_prev= g;
382         }
383
384         if (box->xmin > box->xmax) {
385                 box->xmin= 0.0f;
386                 box->ymin= 0.0f;
387                 box->xmax= 0.0f;
388                 box->ymax= 0.0f;
389         }
390 }
391
392 void blf_font_width_and_height(FontBLF *font, const char *str, float *width, float *height)
393 {
394         float xa, ya;
395         rctf box;
396
397         if (font->flags & BLF_ASPECT) {
398                 xa= font->aspect[0];
399                 ya= font->aspect[1];
400         }
401         else {
402                 xa= 1.0f;
403                 ya= 1.0f;
404         }
405
406         blf_font_boundbox(font, str, &box);
407         *width= ((box.xmax - box.xmin) * xa);
408         *height= ((box.ymax - box.ymin) * ya);
409 }
410
411 float blf_font_width(FontBLF *font, const char *str)
412 {
413         float xa;
414         rctf box;
415
416         if (font->flags & BLF_ASPECT)
417                 xa= font->aspect[0];
418         else
419                 xa= 1.0f;
420
421         blf_font_boundbox(font, str, &box);
422         return (box.xmax - box.xmin) * xa;
423 }
424
425 float blf_font_height(FontBLF *font, const char *str)
426 {
427         float ya;
428         rctf box;
429
430         if (font->flags & BLF_ASPECT)
431                 ya= font->aspect[1];
432         else
433                 ya= 1.0f;
434
435         blf_font_boundbox(font, str, &box);
436         return (box.ymax - box.ymin) * ya;
437 }
438
439 float blf_font_fixed_width(FontBLF *font)
440 {
441         const unsigned int c = ' ';
442         GlyphBLF *g= blf_glyph_search(font->glyph_cache, c);
443         if (!g) {
444                 g= blf_glyph_add(font, FT_Get_Char_Index(font->face, c), c);
445
446                 /* if we don't find the glyph. */
447                 if (!g) {
448                         return 0.0f;
449                 }
450         }
451
452         return g->advance;
453 }
454
455 void blf_font_free(FontBLF *font)
456 {
457         GlyphCacheBLF *gc;
458
459         font->glyph_cache= NULL;
460         while (font->cache.first) {
461                 gc= font->cache.first;
462                 BLI_remlink(&font->cache, gc);
463                 blf_glyph_cache_free(gc);
464         }
465
466         FT_Done_Face(font->face);
467         if (font->filename)
468                 MEM_freeN(font->filename);
469         if (font->name)
470                 MEM_freeN(font->name);
471         MEM_freeN(font);
472 }
473
474 static void blf_font_fill(FontBLF *font)
475 {
476         unsigned int i;
477
478         font->aspect[0]= 1.0f;
479         font->aspect[1]= 1.0f;
480         font->aspect[2]= 1.0f;
481         font->pos[0]= 0.0f;
482         font->pos[1]= 0.0f;
483         font->angle= 0.0f;
484
485         for (i= 0; i < 16; i++)
486                 font->m[i]= 0;
487
488         font->clip_rec.xmin= 0.0f;
489         font->clip_rec.xmax= 0.0f;
490         font->clip_rec.ymin= 0.0f;
491         font->clip_rec.ymax= 0.0f;
492         font->flags= 0;
493         font->dpi= 0;
494         font->size= 0;
495         font->cache.first= NULL;
496         font->cache.last= NULL;
497         font->glyph_cache= NULL;
498         font->blur= 0;
499         font->max_tex_size= -1;
500         font->b_fbuf= NULL;
501         font->b_cbuf= NULL;
502         font->bw= 0;
503         font->bh= 0;
504         font->bch= 0;
505         font->b_col[0]= 0;
506         font->b_col[1]= 0;
507         font->b_col[2]= 0;
508         font->b_col[3]= 0;
509         font->ft_lib= ft_lib;
510 }
511
512 FontBLF *blf_font_new(const char *name, const char *filename)
513 {
514         FontBLF *font;
515         FT_Error err;
516         char *mfile;
517
518         font= (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
519         err= FT_New_Face(ft_lib, filename, 0, &font->face);
520         if (err) {
521                 MEM_freeN(font);
522                 return NULL;
523         }
524
525         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
526         if (err) {
527                 printf("Can't set the unicode character map!\n");
528                 FT_Done_Face(font->face);
529                 MEM_freeN(font);
530                 return NULL;
531         }
532
533         mfile= blf_dir_metrics_search(filename);
534         if (mfile) {
535                 err= FT_Attach_File(font->face, mfile);
536                 if(err) {
537                         fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filename, (int)err);
538                 }
539                 MEM_freeN(mfile);
540         }
541
542         font->name= BLI_strdup(name);
543         font->filename= BLI_strdup(filename);
544         blf_font_fill(font);
545         return font;
546 }
547
548 void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
549 {
550         FT_Open_Args open;
551
552         open.flags= FT_OPEN_MEMORY;
553         open.memory_base= (FT_Byte *)mem;
554         open.memory_size= mem_size;
555         FT_Attach_Stream(font->face, &open);
556 }
557
558 FontBLF *blf_font_new_from_mem(const char *name, unsigned char *mem, int mem_size)
559 {
560         FontBLF *font;
561         FT_Error err;
562
563         font= (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new_from_mem");
564         err= FT_New_Memory_Face(ft_lib, mem, mem_size, 0, &font->face);
565         if (err) {
566                 MEM_freeN(font);
567                 return NULL;
568         }
569
570         err= FT_Select_Charmap(font->face, ft_encoding_unicode);
571         if (err) {
572                 printf("Can't set the unicode character map!\n");
573                 FT_Done_Face(font->face);
574                 MEM_freeN(font);
575                 return NULL;
576         }
577
578         font->name= BLI_strdup(name);
579         font->filename= NULL;
580         blf_font_fill(font);
581         return font;
582 }