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