code cleanup: remove/comment some unused code.
[blender.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                 BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
175
176                 if (c == BLI_UTF8_ERR)
177                         break;
178                 if (g == NULL)
179                         continue;
180                 if (has_kerning)
181                         BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
182
183                 /* do not return this loop if clipped, we want every character tested */
184                 blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
185
186                 pen_x += g->advance;
187                 g_prev = g;
188         }
189 }
190
191 /* faster version of blf_font_draw, ascii only for view dimensions */
192 void blf_font_draw_ascii(FontBLF *font, const char *str, unsigned int len)
193 {
194         unsigned char c;
195         GlyphBLF *g, *g_prev = NULL;
196         FT_Vector delta;
197         int pen_x = 0, pen_y = 0;
198         GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
199
200         BLF_KERNING_VARS(font, has_kerning, kern_mode);
201
202         blf_font_ensure_ascii_table(font);
203
204         while ((c = *(str++)) && len--) {
205                 if ((g = glyph_ascii_table[c]) == NULL)
206                         continue;
207                 if (has_kerning)
208                         BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
209
210                 /* do not return this loop if clipped, we want every character tested */
211                 blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
212
213                 pen_x += g->advance;
214                 g_prev = g;
215         }
216 }
217
218 /* Sanity checks are done by BLF_draw_buffer() */
219 void blf_font_buffer(FontBLF *font, const char *str)
220 {
221         unsigned int c;
222         GlyphBLF *g, *g_prev = NULL;
223         FT_Vector delta;
224         int pen_x = (int)font->pos[0], pen_y = 0;
225         size_t i = 0;
226         GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
227
228         /* buffer specific vars*/
229         const unsigned char b_col_char[4] = {font->b_col[0] * 255,
230                                              font->b_col[1] * 255,
231                                              font->b_col[2] * 255,
232                                              font->b_col[3] * 255};
233         unsigned char *cbuf;
234         int chx, chy;
235         int y, x;
236         float a, *fbuf;
237
238         BLF_KERNING_VARS(font, has_kerning, kern_mode);
239
240         blf_font_ensure_ascii_table(font);
241
242         while (str[i]) {
243                 BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
244
245                 if (c == BLI_UTF8_ERR)
246                         break;
247                 if (g == NULL)
248                         continue;
249                 if (has_kerning)
250                         BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
251
252                 chx = pen_x + ((int)g->pos_x);
253                 chy = (int)font->pos[1] + g->height;
254
255                 if (g->pitch < 0) {
256                         pen_y = (int)font->pos[1] + (g->height - (int)g->pos_y);
257                 }
258                 else {
259                         pen_y = (int)font->pos[1] - (g->height - (int)g->pos_y);
260                 }
261
262                 if ((chx + g->width) >= 0 && chx < font->bw && (pen_y + g->height) >= 0 && pen_y < font->bh) {
263                         /* don't draw beyond the buffer bounds */
264                         int width_clip = g->width;
265                         int height_clip = g->height;
266                         int yb_start = g->pitch < 0 ? 0 : g->height-1;
267
268                         if (width_clip + chx > font->bw)
269                                 width_clip -= chx + width_clip - font->bw;
270                         if (height_clip + pen_y > font->bh)
271                                 height_clip -= pen_y + height_clip - font->bh;
272                         
273                         /* drawing below the image? */
274                         if (pen_y < 0) {
275                                 yb_start += (g->pitch < 0) ? -pen_y : pen_y;
276                                 height_clip += pen_y;
277                                 pen_y = 0;
278                         }
279
280                         if (font->b_fbuf) {
281                                 int yb = yb_start;
282                                 for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
283                                         for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
284                                                 a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
285
286                                                 if (a > 0.0f) {
287                                                         float alphatest;
288                                                         fbuf = font->b_fbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
289                                                         if (a >= 1.0f) {
290                                                                 fbuf[0] = font->b_col[0];
291                                                                 fbuf[1] = font->b_col[1];
292                                                                 fbuf[2] = font->b_col[2];
293                                                                 fbuf[3] = (alphatest = (fbuf[3] + (font->b_col[3]))) < 1.0f ? alphatest : 1.0f;
294                                                         }
295                                                         else {
296                                                                 fbuf[0] = (font->b_col[0]*a) + (fbuf[0] * (1-a));
297                                                                 fbuf[1] = (font->b_col[1]*a) + (fbuf[1] * (1-a));
298                                                                 fbuf[2] = (font->b_col[2]*a) + (fbuf[2] * (1-a));
299                                                                 fbuf[3] = (alphatest = (fbuf[3] + (font->b_col[3]*a))) < 1.0f ? alphatest : 1.0f;
300                                                         }
301                                                 }
302                                         }
303
304                                         if (g->pitch < 0)
305                                                 yb++;
306                                         else
307                                                 yb--;
308                                 }
309                         }
310
311                         if (font->b_cbuf) {
312                                 int yb = yb_start;
313                                 for (y = 0; y < height_clip; y++) {
314                                         for (x = 0; x < width_clip; x++) {
315                                                 a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
316
317                                                 if (a > 0.0f) {
318                                                         int alphatest;
319                                                         cbuf = font->b_cbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
320                                                         if (a >= 1.0f) {
321                                                                 cbuf[0] = b_col_char[0];
322                                                                 cbuf[1] = b_col_char[1];
323                                                                 cbuf[2] = b_col_char[2];
324                                                                 cbuf[3] = (alphatest = ((int)cbuf[3] + (int)b_col_char[3])) < 255 ? alphatest : 255;
325                                                         }
326                                                         else {
327                                                                 cbuf[0] = (b_col_char[0]*a) + (cbuf[0] * (1-a));
328                                                                 cbuf[1] = (b_col_char[1]*a) + (cbuf[1] * (1-a));
329                                                                 cbuf[2] = (b_col_char[2]*a) + (cbuf[2] * (1-a));
330                                                                 cbuf[3] = (alphatest = ((int)cbuf[3] + (int)((font->b_col[3]*a)*255.0f))) <
331                                                                           255 ? alphatest : 255;
332                                                         }
333                                                 }
334                                         }
335
336                                         if (g->pitch < 0)
337                                                 yb++;
338                                         else
339                                                 yb--;
340                                 }
341                         }
342                 }
343
344                 pen_x += g->advance;
345                 g_prev = g;
346         }
347 }
348
349 void blf_font_boundbox(FontBLF *font, const char *str, rctf *box)
350 {
351         unsigned int c;
352         GlyphBLF *g, *g_prev = NULL;
353         FT_Vector delta;
354         int pen_x = 0, pen_y = 0;
355         size_t i = 0;
356         GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
357
358         rctf gbox;
359
360         BLF_KERNING_VARS(font, has_kerning, kern_mode);
361
362         box->xmin = 32000.0f;
363         box->xmax = -32000.0f;
364         box->ymin = 32000.0f;
365         box->ymax = -32000.0f;
366
367         blf_font_ensure_ascii_table(font);
368
369         while (str[i]) {
370                 BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
371
372                 if (c == BLI_UTF8_ERR)
373                         break;
374                 if (g == NULL)
375                         continue;
376                 if (has_kerning)
377                         BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
378
379                 gbox.xmin = pen_x;
380                 gbox.xmax = pen_x + g->advance;
381                 gbox.ymin = g->box.ymin + pen_y;
382                 gbox.ymax = g->box.ymax + pen_y;
383
384                 if (gbox.xmin < box->xmin) box->xmin = gbox.xmin;
385                 if (gbox.ymin < box->ymin) box->ymin = gbox.ymin;
386
387                 if (gbox.xmax > box->xmax) box->xmax = gbox.xmax;
388                 if (gbox.ymax > box->ymax) box->ymax = gbox.ymax;
389
390                 pen_x += g->advance;
391                 g_prev = g;
392         }
393
394         if (box->xmin > box->xmax) {
395                 box->xmin = 0.0f;
396                 box->ymin = 0.0f;
397                 box->xmax = 0.0f;
398                 box->ymax = 0.0f;
399         }
400 }
401
402 void blf_font_width_and_height(FontBLF *font, const char *str, float *width, float *height)
403 {
404         float xa, ya;
405         rctf box;
406
407         if (font->flags & BLF_ASPECT) {
408                 xa = font->aspect[0];
409                 ya = font->aspect[1];
410         }
411         else {
412                 xa = 1.0f;
413                 ya = 1.0f;
414         }
415
416         blf_font_boundbox(font, str, &box);
417         *width = ((box.xmax - box.xmin) * xa);
418         *height = ((box.ymax - box.ymin) * ya);
419 }
420
421 float blf_font_width(FontBLF *font, const char *str)
422 {
423         float xa;
424         rctf box;
425
426         if (font->flags & BLF_ASPECT)
427                 xa = font->aspect[0];
428         else
429                 xa = 1.0f;
430
431         blf_font_boundbox(font, str, &box);
432         return (box.xmax - box.xmin) * xa;
433 }
434
435 float blf_font_height(FontBLF *font, const char *str)
436 {
437         float ya;
438         rctf box;
439
440         if (font->flags & BLF_ASPECT)
441                 ya = font->aspect[1];
442         else
443                 ya = 1.0f;
444
445         blf_font_boundbox(font, str, &box);
446         return (box.ymax - box.ymin) * ya;
447 }
448
449 float blf_font_fixed_width(FontBLF *font)
450 {
451         const unsigned int c = ' ';
452         GlyphBLF *g = blf_glyph_search(font->glyph_cache, c);
453         if (!g) {
454                 g = blf_glyph_add(font, FT_Get_Char_Index(font->face, c), c);
455
456                 /* if we don't find the glyph. */
457                 if (!g) {
458                         return 0.0f;
459                 }
460         }
461
462         return g->advance;
463 }
464
465 void blf_font_free(FontBLF *font)
466 {
467         GlyphCacheBLF *gc;
468
469         font->glyph_cache = NULL;
470         while (font->cache.first) {
471                 gc = font->cache.first;
472                 BLI_remlink(&font->cache, gc);
473                 blf_glyph_cache_free(gc);
474         }
475
476         FT_Done_Face(font->face);
477         if (font->filename)
478                 MEM_freeN(font->filename);
479         if (font->name)
480                 MEM_freeN(font->name);
481         MEM_freeN(font);
482 }
483
484 static void blf_font_fill(FontBLF *font)
485 {
486         unsigned int i;
487
488         font->aspect[0] = 1.0f;
489         font->aspect[1] = 1.0f;
490         font->aspect[2] = 1.0f;
491         font->pos[0] = 0.0f;
492         font->pos[1] = 0.0f;
493         font->angle = 0.0f;
494
495         for (i = 0; i < 16; i++)
496                 font->m[i] = 0;
497
498         font->clip_rec.xmin = 0.0f;
499         font->clip_rec.xmax = 0.0f;
500         font->clip_rec.ymin = 0.0f;
501         font->clip_rec.ymax = 0.0f;
502         font->flags = 0;
503         font->dpi = 0;
504         font->size = 0;
505         font->cache.first = NULL;
506         font->cache.last = NULL;
507         font->glyph_cache = NULL;
508         font->blur = 0;
509         font->max_tex_size = -1;
510         font->b_fbuf = NULL;
511         font->b_cbuf = NULL;
512         font->bw = 0;
513         font->bh = 0;
514         font->bch = 0;
515         font->b_col[0] = 0;
516         font->b_col[1] = 0;
517         font->b_col[2] = 0;
518         font->b_col[3] = 0;
519         font->ft_lib = ft_lib;
520 }
521
522 FontBLF *blf_font_new(const char *name, const char *filename)
523 {
524         FontBLF *font;
525         FT_Error err;
526         char *mfile;
527
528         font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
529         err = FT_New_Face(ft_lib, filename, 0, &font->face);
530         if (err) {
531                 MEM_freeN(font);
532                 return NULL;
533         }
534
535         err = FT_Select_Charmap(font->face, ft_encoding_unicode);
536         if (err) {
537                 printf("Can't set the unicode character map!\n");
538                 FT_Done_Face(font->face);
539                 MEM_freeN(font);
540                 return NULL;
541         }
542
543         mfile = blf_dir_metrics_search(filename);
544         if (mfile) {
545                 err = FT_Attach_File(font->face, mfile);
546                 if (err) {
547                         fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filename, (int)err);
548                 }
549                 MEM_freeN(mfile);
550         }
551
552         font->name = BLI_strdup(name);
553         font->filename = BLI_strdup(filename);
554         blf_font_fill(font);
555         return font;
556 }
557
558 void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
559 {
560         FT_Open_Args open;
561
562         open.flags = FT_OPEN_MEMORY;
563         open.memory_base = (FT_Byte *)mem;
564         open.memory_size = mem_size;
565         FT_Attach_Stream(font->face, &open);
566 }
567
568 FontBLF *blf_font_new_from_mem(const char *name, unsigned char *mem, int mem_size)
569 {
570         FontBLF *font;
571         FT_Error err;
572
573         font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new_from_mem");
574         err = FT_New_Memory_Face(ft_lib, mem, mem_size, 0, &font->face);
575         if (err) {
576                 MEM_freeN(font);
577                 return NULL;
578         }
579
580         err = FT_Select_Charmap(font->face, ft_encoding_unicode);
581         if (err) {
582                 printf("Can't set the unicode character map!\n");
583                 FT_Done_Face(font->face);
584                 MEM_freeN(font);
585                 return NULL;
586         }
587
588         font->name = BLI_strdup(name);
589         font->filename = NULL;
590         blf_font_fill(font);
591         return font;
592 }