|
Blender
V2.59
|
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 }