Blender V2.61 - r43446

blf_font.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2009 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * 
00022  * Contributor(s): Blender Foundation
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <math.h>
00036 
00037 #include <ft2build.h>
00038 
00039 #include FT_FREETYPE_H
00040 #include FT_GLYPH_H
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "DNA_vec_types.h"
00045 
00046 
00047 #include "BLI_blenlib.h"
00048 #include "BLI_linklist.h"   /* linknode */
00049 #include "BLI_math.h"
00050 
00051 #include "BIF_gl.h"
00052 #include "BLF_api.h"
00053 
00054 #include "blf_internal_types.h"
00055 #include "blf_internal.h"
00056 
00057 
00058 /* freetype2 handle ONLY for this file!. */
00059 static FT_Library ft_lib;
00060 
00061 int blf_font_init(void)
00062 {
00063     return FT_Init_FreeType(&ft_lib);
00064 }
00065 
00066 void blf_font_exit(void)
00067 {
00068     FT_Done_FreeType(ft_lib);
00069 }
00070 
00071 void blf_font_size(FontBLF *font, int size, int dpi)
00072 {
00073     GlyphCacheBLF *gc;
00074     FT_Error err;
00075 
00076     err= FT_Set_Char_Size(font->face, 0, (size * 64), dpi, dpi);
00077     if (err) {
00078         /* FIXME: here we can go through the fixed size and choice a close one */
00079         printf("The current font don't support the size, %d and dpi, %d\n", size, dpi);
00080         return;
00081     }
00082 
00083     font->size= size;
00084     font->dpi= dpi;
00085 
00086     gc= blf_glyph_cache_find(font, size, dpi);
00087     if (gc)
00088         font->glyph_cache= gc;
00089     else {
00090         gc= blf_glyph_cache_new(font);
00091         if (gc)
00092             font->glyph_cache= gc;
00093         else
00094             font->glyph_cache= NULL;
00095     }
00096 }
00097 
00098 static void blf_font_ensure_ascii_table(FontBLF *font)
00099 {
00100     GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
00101 
00102     /* build ascii on demand */
00103     if(glyph_ascii_table['0']==NULL) {
00104         GlyphBLF *g;
00105         unsigned int i;
00106         for(i=0; i<256; i++) {
00107             g= blf_glyph_search(font->glyph_cache, i);
00108             if (!g) {
00109                 FT_UInt glyph_index= FT_Get_Char_Index(font->face, i);
00110                 g= blf_glyph_add(font, glyph_index, i);
00111             }
00112             glyph_ascii_table[i]= g;
00113         }
00114     }
00115 }
00116 
00117 /* Fast path for runs of ASCII characters. Given that common UTF-8
00118  * input will consist of an overwhelming majority of ASCII
00119  * characters.
00120  */
00121 
00122 /* Note,
00123  * blf_font_ensure_ascii_table(font); must be called before this macro */
00124 
00125 #define BLF_UTF8_NEXT_FAST(_font, _g, _str, _i, _c, _glyph_ascii_table)       \
00126     if(((_c)= (_str)[_i]) < 0x80) {                                           \
00127         _g= (_glyph_ascii_table)[_c];                                         \
00128         _i++;                                                                 \
00129     }                                                                         \
00130     else if ((_c= BLI_str_utf8_as_unicode_step(_str, &(_i)))!=BLI_UTF8_ERR) { \
00131         if ((_g= blf_glyph_search((_font)->glyph_cache, _c)) == NULL) {       \
00132             _g= blf_glyph_add(_font,                                          \
00133                               FT_Get_Char_Index((_font)->face, _c), _c);      \
00134         }                                                                     \
00135     }                                                                         \
00136 
00137 
00138 #define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode)                     \
00139     const short _has_kerning= FT_HAS_KERNING((_font)->face);                  \
00140     const FT_UInt _kern_mode= (_has_kerning == 0) ? 0 :                       \
00141                              (((_font)->flags & BLF_KERNING_DEFAULT) ?        \
00142                               ft_kerning_default : FT_KERNING_UNFITTED)       \
00143 
00144 
00145 #define BLF_KERNING_STEP(_font, _kern_mode, _g_prev, _g, _delta, _pen_x)      \
00146 {                                                                             \
00147     if (_g_prev) {                                                            \
00148         _delta.x= _delta.y= 0;                                                \
00149         if (FT_Get_Kerning((_font)->face,                                     \
00150                            (_g_prev)->idx,                                    \
00151                            (_g)->idx,                                         \
00152                            _kern_mode,                                        \
00153                            &(_delta)) == 0)                                   \
00154         {                                                                     \
00155             _pen_x += delta.x >> 6;                                           \
00156         }                                                                     \
00157     }                                                                         \
00158 }                                                                             \
00159 
00160 void blf_font_draw(FontBLF *font, const char *str, unsigned int len)
00161 {
00162     unsigned int c;
00163     GlyphBLF *g, *g_prev= NULL;
00164     FT_Vector delta;
00165     int pen_x= 0, pen_y= 0;
00166     size_t i= 0;
00167     GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
00168 
00169     BLF_KERNING_VARS(font, has_kerning, kern_mode);
00170 
00171     blf_font_ensure_ascii_table(font);
00172 
00173     while (str[i] && i < len) {
00174 
00175         BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
00176 
00177         if (c == BLI_UTF8_ERR)  break;
00178         if (g == NULL)          continue;
00179         if (has_kerning)        BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
00180 
00181         /* do not return this loop if clipped, we want every character tested */
00182         blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
00183 
00184         pen_x += g->advance;
00185         g_prev= g;
00186     }
00187 }
00188 
00189 /* faster version of blf_font_draw, ascii only for view dimensions */
00190 void blf_font_draw_ascii(FontBLF *font, const char *str, unsigned int len)
00191 {
00192     unsigned char c;
00193     GlyphBLF *g, *g_prev= NULL;
00194     FT_Vector delta;
00195     int pen_x= 0, pen_y= 0;
00196     GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
00197 
00198     BLF_KERNING_VARS(font, has_kerning, kern_mode);
00199 
00200     blf_font_ensure_ascii_table(font);
00201 
00202     while ((c= *(str++)) && len--) {
00203         if ((g= glyph_ascii_table[c]) == NULL) continue;
00204         if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
00205 
00206         /* do not return this loop if clipped, we want every character tested */
00207         blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
00208 
00209         pen_x += g->advance;
00210         g_prev= g;
00211     }
00212 }
00213 
00214 /* Sanity checks are done by BLF_draw_buffer() */
00215 void blf_font_buffer(FontBLF *font, const char *str)
00216 {
00217     unsigned int c;
00218     GlyphBLF *g, *g_prev= NULL;
00219     FT_Vector delta;
00220     int pen_x= (int)font->pos[0], pen_y= 0;
00221     size_t i= 0;
00222     GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
00223 
00224     /* buffer specific vars*/
00225     const unsigned char b_col_char[4]= {font->b_col[0] * 255,
00226                                         font->b_col[1] * 255,
00227                                         font->b_col[2] * 255,
00228                                         font->b_col[3] * 255};
00229     unsigned char *cbuf;
00230     int chx, chy;
00231     int y, x;
00232     float a, *fbuf;
00233 
00234     BLF_KERNING_VARS(font, has_kerning, kern_mode);
00235 
00236     blf_font_ensure_ascii_table(font);
00237 
00238     while (str[i]) {
00239 
00240         BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
00241 
00242         if (c == BLI_UTF8_ERR)  break;
00243         if (g == NULL)          continue;
00244         if (has_kerning)        BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
00245 
00246         chx= pen_x + ((int)g->pos_x);
00247         chy= (int)font->pos[1] + g->height;
00248 
00249         if (g->pitch < 0) {
00250             pen_y = (int)font->pos[1] + (g->height - (int)g->pos_y);
00251         }
00252         else {
00253             pen_y = (int)font->pos[1] - (g->height - (int)g->pos_y);
00254         }
00255 
00256         if ((chx + g->width) >= 0 && chx < font->bw && (pen_y + g->height) >= 0 && pen_y < font->bh) {
00257             /* dont draw beyond the buffer bounds */
00258             int width_clip= g->width;
00259             int height_clip= g->height;
00260             int yb_start= g->pitch < 0 ? 0 : g->height-1;
00261 
00262             if (width_clip + chx > font->bw)    width_clip  -= chx + width_clip - font->bw;
00263             if (height_clip + pen_y > font->bh) height_clip -= pen_y + height_clip - font->bh;
00264             
00265             /* drawing below the image? */
00266             if(pen_y < 0) {
00267                 yb_start += (g->pitch < 0) ? -pen_y : pen_y;
00268                 height_clip += pen_y;
00269                 pen_y= 0;
00270             }
00271 
00272             if (font->b_fbuf) {
00273                 int yb= yb_start;
00274                 for (y=(chy >= 0 ? 0:-chy); y < height_clip; y++) {
00275                     for (x=(chx >= 0 ? 0:-chx); x < width_clip; x++) {
00276                         
00277                         a= *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
00278 
00279                         if(a > 0.0f) {
00280                             float alphatest;
00281                             fbuf= font->b_fbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
00282                             if (a >= 1.0f) {
00283                                 fbuf[0]= font->b_col[0];
00284                                 fbuf[1]= font->b_col[1];
00285                                 fbuf[2]= font->b_col[2];
00286                                 fbuf[3]= (alphatest= (fbuf[3] + (font->b_col[3]))) < 1.0f ? alphatest : 1.0f;
00287                             }
00288                             else {
00289                                 fbuf[0]= (font->b_col[0]*a) + (fbuf[0] * (1-a));
00290                                 fbuf[1]= (font->b_col[1]*a) + (fbuf[1] * (1-a));
00291                                 fbuf[2]= (font->b_col[2]*a) + (fbuf[2] * (1-a));
00292                                 fbuf[3]= (alphatest= (fbuf[3] + (font->b_col[3]*a))) < 1.0f ? alphatest : 1.0f;
00293                             }
00294                         }
00295                     }
00296 
00297                     if (g->pitch < 0)
00298                         yb++;
00299                     else
00300                         yb--;
00301                 }
00302             }
00303 
00304             if (font->b_cbuf) {
00305                 int yb= yb_start;
00306                 for (y= 0; y < height_clip; y++) {
00307                     for (x= 0; x < width_clip; x++) {
00308                         a= *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
00309 
00310                         if(a > 0.0f) {
00311                             int alphatest;
00312                             cbuf= font->b_cbuf + font->bch * ((chx + x) + ((pen_y + y)*font->bw));
00313                             if (a >= 1.0f) {
00314                                 cbuf[0]= b_col_char[0];
00315                                 cbuf[1]= b_col_char[1];
00316                                 cbuf[2]= b_col_char[2];
00317                                 cbuf[3]= (alphatest= ((int)cbuf[3] + (int)b_col_char[3])) < 255 ? alphatest : 255;
00318                             }
00319                             else {
00320                                 cbuf[0]= (b_col_char[0]*a) + (cbuf[0] * (1-a));
00321                                 cbuf[1]= (b_col_char[1]*a) + (cbuf[1] * (1-a));
00322                                 cbuf[2]= (b_col_char[2]*a) + (cbuf[2] * (1-a));
00323                                 cbuf[3]= (alphatest= ((int)cbuf[3] + (int)((font->b_col[3]*a)*255.0f))) < 255 ? alphatest : 255;
00324                             }
00325                         }
00326                     }
00327 
00328                     if (g->pitch < 0)
00329                         yb++;
00330                     else
00331                         yb--;
00332                 }
00333             }
00334         }
00335 
00336         pen_x += g->advance;
00337         g_prev= g;
00338     }
00339 }
00340 
00341 void blf_font_boundbox(FontBLF *font, const char *str, rctf *box)
00342 {
00343     unsigned int c;
00344     GlyphBLF *g, *g_prev= NULL;
00345     FT_Vector delta;
00346     int pen_x= 0, pen_y= 0;
00347     size_t i= 0;
00348     GlyphBLF **glyph_ascii_table= font->glyph_cache->glyph_ascii_table;
00349 
00350     rctf gbox;
00351 
00352     BLF_KERNING_VARS(font, has_kerning, kern_mode);
00353 
00354     box->xmin= 32000.0f;
00355     box->xmax= -32000.0f;
00356     box->ymin= 32000.0f;
00357     box->ymax= -32000.0f;
00358 
00359     blf_font_ensure_ascii_table(font);
00360 
00361     while (str[i]) {
00362 
00363         BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
00364 
00365         if (c == BLI_UTF8_ERR)  break;
00366         if (g == NULL)          continue;
00367         if (has_kerning)        BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
00368 
00369         gbox.xmin= pen_x;
00370         gbox.xmax= pen_x + g->advance;
00371         gbox.ymin= g->box.ymin + pen_y;
00372         gbox.ymax= g->box.ymax + pen_y;
00373 
00374         if (gbox.xmin < box->xmin) box->xmin= gbox.xmin;
00375         if (gbox.ymin < box->ymin) box->ymin= gbox.ymin;
00376 
00377         if (gbox.xmax > box->xmax) box->xmax= gbox.xmax;
00378         if (gbox.ymax > box->ymax) box->ymax= gbox.ymax;
00379 
00380         pen_x += g->advance;
00381         g_prev= g;
00382     }
00383 
00384     if (box->xmin > box->xmax) {
00385         box->xmin= 0.0f;
00386         box->ymin= 0.0f;
00387         box->xmax= 0.0f;
00388         box->ymax= 0.0f;
00389     }
00390 }
00391 
00392 void blf_font_width_and_height(FontBLF *font, const char *str, float *width, float *height)
00393 {
00394     float xa, ya;
00395     rctf box;
00396 
00397     if (font->flags & BLF_ASPECT) {
00398         xa= font->aspect[0];
00399         ya= font->aspect[1];
00400     }
00401     else {
00402         xa= 1.0f;
00403         ya= 1.0f;
00404     }
00405 
00406     blf_font_boundbox(font, str, &box);
00407     *width= ((box.xmax - box.xmin) * xa);
00408     *height= ((box.ymax - box.ymin) * ya);
00409 }
00410 
00411 float blf_font_width(FontBLF *font, const char *str)
00412 {
00413     float xa;
00414     rctf box;
00415 
00416     if (font->flags & BLF_ASPECT)
00417         xa= font->aspect[0];
00418     else
00419         xa= 1.0f;
00420 
00421     blf_font_boundbox(font, str, &box);
00422     return (box.xmax - box.xmin) * xa;
00423 }
00424 
00425 float blf_font_height(FontBLF *font, const char *str)
00426 {
00427     float ya;
00428     rctf box;
00429 
00430     if (font->flags & BLF_ASPECT)
00431         ya= font->aspect[1];
00432     else
00433         ya= 1.0f;
00434 
00435     blf_font_boundbox(font, str, &box);
00436     return (box.ymax - box.ymin) * ya;
00437 }
00438 
00439 float blf_font_fixed_width(FontBLF *font)
00440 {
00441     const unsigned int c = ' ';
00442     GlyphBLF *g= blf_glyph_search(font->glyph_cache, c);
00443     if (!g) {
00444         g= blf_glyph_add(font, FT_Get_Char_Index(font->face, c), c);
00445 
00446         /* if we don't find the glyph. */
00447         if (!g) {
00448             return 0.0f;
00449         }
00450     }
00451 
00452     return g->advance;
00453 }
00454 
00455 void blf_font_free(FontBLF *font)
00456 {
00457     GlyphCacheBLF *gc;
00458 
00459     font->glyph_cache= NULL;
00460     while (font->cache.first) {
00461         gc= font->cache.first;
00462         BLI_remlink(&font->cache, gc);
00463         blf_glyph_cache_free(gc);
00464     }
00465 
00466     FT_Done_Face(font->face);
00467     if (font->filename)
00468         MEM_freeN(font->filename);
00469     if (font->name)
00470         MEM_freeN(font->name);
00471     MEM_freeN(font);
00472 }
00473 
00474 static void blf_font_fill(FontBLF *font)
00475 {
00476     unsigned int i;
00477 
00478     font->aspect[0]= 1.0f;
00479     font->aspect[1]= 1.0f;
00480     font->aspect[2]= 1.0f;
00481     font->pos[0]= 0.0f;
00482     font->pos[1]= 0.0f;
00483     font->angle= 0.0f;
00484 
00485     for (i= 0; i < 16; i++)
00486         font->m[i]= 0;
00487 
00488     font->clip_rec.xmin= 0.0f;
00489     font->clip_rec.xmax= 0.0f;
00490     font->clip_rec.ymin= 0.0f;
00491     font->clip_rec.ymax= 0.0f;
00492     font->flags= 0;
00493     font->dpi= 0;
00494     font->size= 0;
00495     font->cache.first= NULL;
00496     font->cache.last= NULL;
00497     font->glyph_cache= NULL;
00498     font->blur= 0;
00499     font->max_tex_size= -1;
00500     font->b_fbuf= NULL;
00501     font->b_cbuf= NULL;
00502     font->bw= 0;
00503     font->bh= 0;
00504     font->bch= 0;
00505     font->b_col[0]= 0;
00506     font->b_col[1]= 0;
00507     font->b_col[2]= 0;
00508     font->b_col[3]= 0;
00509     font->ft_lib= ft_lib;
00510 }
00511 
00512 FontBLF *blf_font_new(const char *name, const char *filename)
00513 {
00514     FontBLF *font;
00515     FT_Error err;
00516     char *mfile;
00517 
00518     font= (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
00519     err= FT_New_Face(ft_lib, filename, 0, &font->face);
00520     if (err) {
00521         MEM_freeN(font);
00522         return NULL;
00523     }
00524 
00525     err= FT_Select_Charmap(font->face, ft_encoding_unicode);
00526     if (err) {
00527         printf("Can't set the unicode character map!\n");
00528         FT_Done_Face(font->face);
00529         MEM_freeN(font);
00530         return NULL;
00531     }
00532 
00533     mfile= blf_dir_metrics_search(filename);
00534     if (mfile) {
00535         err= FT_Attach_File(font->face, mfile);
00536         if(err) {
00537             fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filename, (int)err);
00538         }
00539         MEM_freeN(mfile);
00540     }
00541 
00542     font->name= BLI_strdup(name);
00543     font->filename= BLI_strdup(filename);
00544     blf_font_fill(font);
00545     return font;
00546 }
00547 
00548 void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
00549 {
00550     FT_Open_Args open;
00551 
00552     open.flags= FT_OPEN_MEMORY;
00553     open.memory_base= (FT_Byte *)mem;
00554     open.memory_size= mem_size;
00555     FT_Attach_Stream(font->face, &open);
00556 }
00557 
00558 FontBLF *blf_font_new_from_mem(const char *name, unsigned char *mem, int mem_size)
00559 {
00560     FontBLF *font;
00561     FT_Error err;
00562 
00563     font= (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new_from_mem");
00564     err= FT_New_Memory_Face(ft_lib, mem, mem_size, 0, &font->face);
00565     if (err) {
00566         MEM_freeN(font);
00567         return NULL;
00568     }
00569 
00570     err= FT_Select_Charmap(font->face, ft_encoding_unicode);
00571     if (err) {
00572         printf("Can't set the unicode character map!\n");
00573         FT_Done_Face(font->face);
00574         MEM_freeN(font);
00575         return NULL;
00576     }
00577 
00578     font->name= BLI_strdup(name);
00579     font->filename= NULL;
00580     blf_font_fill(font);
00581     return font;
00582 }