|
Blender
V2.59
|
00001 /* 00002 * $Id: freetypefont.c 35953 2011-04-02 02:08:33Z 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 written by Rob Haarsma (phase) 00021 * All rights reserved. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 * 00027 * This code parses the Freetype font outline data to chains of Blender's beziertriples. 00028 * Additional information can be found at the bottom of this file. 00029 * 00030 * Code that uses exotic character maps is present but commented out. 00031 */ 00032 00038 #ifdef WIN32 00039 #pragma warning (disable:4244) 00040 #endif 00041 00042 #include <ft2build.h> 00043 #include FT_FREETYPE_H 00044 /* not needed yet */ 00045 // #include FT_GLYPH_H 00046 // #include FT_BBOX_H 00047 // #include FT_SIZES_H 00048 // #include <freetype/ttnameid.h> 00049 00050 #include "MEM_guardedalloc.h" 00051 00052 #include "BLI_vfontdata.h" 00053 #include "BLI_blenlib.h" 00054 #include "BLI_math.h" 00055 #include "BLI_utildefines.h" 00056 00057 //XXX #include "BIF_toolbox.h" 00058 00059 #include "BKE_font.h" 00060 00061 00062 #include "DNA_vfont_types.h" 00063 #include "DNA_packedFile_types.h" 00064 #include "DNA_curve_types.h" 00065 00066 #define myMIN_ASCII 32 00067 #define myMAX_ASCII 255 00068 00069 /* local variables */ 00070 static FT_Library library; 00071 static FT_Error err; 00072 00073 00074 static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) 00075 { 00076 // Blender 00077 struct Nurb *nu; 00078 struct VChar *che; 00079 struct BezTriple *bezt; 00080 00081 // Freetype2 00082 FT_GlyphSlot glyph; 00083 FT_UInt glyph_index; 00084 FT_Outline ftoutline; 00085 float scale, height; 00086 float dx, dy; 00087 int j,k,l,m=0; 00088 00089 // adjust font size 00090 height= ((double) face->bbox.yMax - (double) face->bbox.yMin); 00091 if(height != 0.0f) 00092 scale = 1.0f / height; 00093 else 00094 scale = 1.0f / 1000.0f; 00095 00096 // 00097 // Generate the character 3D data 00098 // 00099 // Get the FT Glyph index and load the Glyph 00100 glyph_index= FT_Get_Char_Index(face, charcode); 00101 err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); 00102 00103 // If loading succeeded, convert the FT glyph to the internal format 00104 if(!err) 00105 { 00106 int *npoints; 00107 int *onpoints; 00108 00109 // First we create entry for the new character to the character list 00110 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char"); 00111 BLI_addtail(&vfd->characters, che); 00112 00113 // Take some data for modifying purposes 00114 glyph= face->glyph; 00115 ftoutline= glyph->outline; 00116 00117 // Set the width and character code 00118 che->index= charcode; 00119 che->width= glyph->advance.x * scale; 00120 00121 // Start converting the FT data 00122 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ; 00123 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ; 00124 00125 // calculate total points of each contour 00126 for(j = 0; j < ftoutline.n_contours; j++) { 00127 if(j == 0) 00128 npoints[j] = ftoutline.contours[j] + 1; 00129 else 00130 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1]; 00131 } 00132 00133 // get number of on-curve points for beziertriples (including conic virtual on-points) 00134 for(j = 0; j < ftoutline.n_contours; j++) { 00135 for(k = 0; k < npoints[j]; k++) { 00136 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; 00137 if(ftoutline.tags[l] == FT_Curve_Tag_On) 00138 onpoints[j]++; 00139 00140 if(k < npoints[j] - 1 ) 00141 if( ftoutline.tags[l] == FT_Curve_Tag_Conic && 00142 ftoutline.tags[l+1] == FT_Curve_Tag_Conic) 00143 onpoints[j]++; 00144 } 00145 } 00146 00147 //contour loop, bezier & conic styles merged 00148 for(j = 0; j < ftoutline.n_contours; j++) { 00149 // add new curve 00150 nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); 00151 bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ; 00152 BLI_addtail(&che->nurbsbase, nu); 00153 00154 nu->type= CU_BEZIER; 00155 nu->pntsu = onpoints[j]; 00156 nu->resolu= 8; 00157 nu->flag= CU_2D; 00158 nu->flagu= CU_NURB_CYCLIC; 00159 nu->bezt = bezt; 00160 00161 //individual curve loop, start-end 00162 for(k = 0; k < npoints[j]; k++) { 00163 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; 00164 if(k == 0) m = l; 00165 00166 //virtual conic on-curve points 00167 if(k < npoints[j] - 1 ) 00168 { 00169 if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { 00170 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0f; 00171 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0f; 00172 00173 //left handle 00174 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0f; 00175 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0f; 00176 00177 //midpoint (virtual on-curve point) 00178 bezt->vec[1][0] = dx; 00179 bezt->vec[1][1] = dy; 00180 00181 //right handle 00182 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0f; 00183 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0f; 00184 00185 bezt->h1= bezt->h2= HD_ALIGN; 00186 bezt->radius= 1.0f; 00187 bezt++; 00188 } 00189 } 00190 00191 //on-curve points 00192 if(ftoutline.tags[l] == FT_Curve_Tag_On) { 00193 //left handle 00194 if(k > 0) { 00195 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) { 00196 bezt->vec[0][0] = ftoutline.points[l-1].x* scale; 00197 bezt->vec[0][1] = ftoutline.points[l-1].y* scale; 00198 bezt->h1= HD_FREE; 00199 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) { 00200 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0f; 00201 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0f; 00202 bezt->h1= HD_FREE; 00203 } else { 00204 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0f; 00205 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0f; 00206 bezt->h1= HD_VECT; 00207 } 00208 } else { //first point on curve 00209 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) { 00210 bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale; 00211 bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale; 00212 bezt->h1= HD_FREE; 00213 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) { 00214 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0f; 00215 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0f; 00216 bezt->h1= HD_FREE; 00217 } else { 00218 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0f; 00219 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0f; 00220 bezt->h1= HD_VECT; 00221 } 00222 } 00223 00224 //midpoint (on-curve point) 00225 bezt->vec[1][0] = ftoutline.points[l].x* scale; 00226 bezt->vec[1][1] = ftoutline.points[l].y* scale; 00227 00228 //right handle 00229 if(k < (npoints[j] - 1)) { 00230 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) { 00231 bezt->vec[2][0] = ftoutline.points[l+1].x* scale; 00232 bezt->vec[2][1] = ftoutline.points[l+1].y* scale; 00233 bezt->h2= HD_FREE; 00234 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { 00235 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0f; 00236 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0f; 00237 bezt->h2= HD_FREE; 00238 } else { 00239 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0f; 00240 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0f; 00241 bezt->h2= HD_VECT; 00242 } 00243 } else { //last point on curve 00244 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) { 00245 bezt->vec[2][0] = ftoutline.points[m].x* scale; 00246 bezt->vec[2][1] = ftoutline.points[m].y* scale; 00247 bezt->h2= HD_FREE; 00248 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) { 00249 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0f; 00250 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0f; 00251 bezt->h2= HD_FREE; 00252 } else { 00253 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0f; 00254 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0f; 00255 bezt->h2= HD_VECT; 00256 } 00257 } 00258 00259 // get the handles that are aligned, tricky... 00260 // dist_to_line_v2, check if the three beztriple points are on one line 00261 // len_squared_v2v2, see if there's a distance between the three points 00262 // len_squared_v2v2 again, to check the angle between the handles 00263 // finally, check if one of them is a vector handle 00264 if((dist_to_line_v2(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001f) && 00265 (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001f*0.0001f) && 00266 (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001f*0.0001f) && 00267 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002f*0.0001f) && 00268 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > MAX2(len_squared_v2v2(bezt->vec[0], bezt->vec[1]), len_squared_v2v2(bezt->vec[1], bezt->vec[2]))) && 00269 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) 00270 { 00271 bezt->h1= bezt->h2= HD_ALIGN; 00272 } 00273 bezt->radius= 1.0f; 00274 bezt++; 00275 } 00276 } 00277 } 00278 if(npoints) MEM_freeN(npoints); 00279 if(onpoints) MEM_freeN(onpoints); 00280 } 00281 } 00282 00283 static int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode) 00284 { 00285 // Freetype2 00286 FT_Face face; 00287 struct TmpFont *tf; 00288 00289 // Find the correct FreeType font 00290 tf= vfont_find_tmpfont(vfont); 00291 00292 // What, no font found. Something strange here 00293 if(!tf) return FALSE; 00294 00295 // Load the font to memory 00296 if(tf->pf) 00297 { 00298 err= FT_New_Memory_Face( library, 00299 tf->pf->data, 00300 tf->pf->size, 00301 0, 00302 &face); 00303 if (err) return FALSE; 00304 } 00305 else { 00306 err = TRUE; 00307 return FALSE; 00308 } 00309 00310 // Read the char 00311 freetypechar_to_vchar(face, charcode, vfont->data); 00312 00313 // And everything went ok 00314 return TRUE; 00315 } 00316 00317 00318 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf) 00319 { 00320 // Variables 00321 FT_Face face; 00322 FT_ULong charcode = 0, lcode; 00323 FT_UInt glyph_index; 00324 const char *fontname; 00325 VFontData *vfd; 00326 00327 /* 00328 FT_CharMap found = 0; 00329 FT_CharMap charmap; 00330 FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT; 00331 FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS; 00332 int n; 00333 */ 00334 00335 // load the freetype font 00336 err = FT_New_Memory_Face( library, 00337 pf->data, 00338 pf->size, 00339 0, 00340 &face ); 00341 00342 if(err) return NULL; 00343 /* 00344 for ( n = 0; n < face->num_charmaps; n++ ) 00345 { 00346 charmap = face->charmaps[n]; 00347 if ( charmap->platform_id == my_platform_id && 00348 charmap->encoding_id == my_encoding_id ) 00349 { 00350 found = charmap; 00351 break; 00352 } 00353 } 00354 00355 if ( !found ) { return NULL; } 00356 00357 // now, select the charmap for the face object 00358 err = FT_Set_Charmap( face, found ); 00359 if ( err ) { return NULL; } 00360 */ 00361 00362 // allocate blender font 00363 vfd= MEM_callocN(sizeof(*vfd), "FTVFontData"); 00364 00365 // get the name 00366 fontname = FT_Get_Postscript_Name(face); 00367 strcpy(vfd->name, (fontname == NULL) ? "" : fontname); 00368 00369 // Extract the first 256 character from TTF 00370 lcode= charcode= FT_Get_First_Char(face, &glyph_index); 00371 00372 // No charmap found from the ttf so we need to figure it out 00373 if(glyph_index == 0) 00374 { 00375 FT_CharMap found = NULL; 00376 FT_CharMap charmap; 00377 int n; 00378 00379 for ( n = 0; n < face->num_charmaps; n++ ) 00380 { 00381 charmap = face->charmaps[n]; 00382 if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) 00383 { 00384 found = charmap; 00385 break; 00386 } 00387 } 00388 00389 err = FT_Set_Charmap( face, found ); 00390 00391 if( err ) 00392 return NULL; 00393 00394 lcode= charcode= FT_Get_First_Char(face, &glyph_index); 00395 } 00396 00397 // Load characters 00398 while(charcode < 256) 00399 { 00400 // Generate the font data 00401 freetypechar_to_vchar(face, charcode, vfd); 00402 00403 // Next glyph 00404 charcode = FT_Get_Next_Char(face, charcode, &glyph_index); 00405 00406 // Check that we won't start infinite loop 00407 if(charcode <= lcode) 00408 break; 00409 lcode = charcode; 00410 } 00411 00412 return vfd; 00413 } 00414 00415 00416 static int check_freetypefont(PackedFile * pf) 00417 { 00418 FT_Face face; 00419 FT_GlyphSlot glyph; 00420 FT_UInt glyph_index; 00421 /* 00422 FT_CharMap charmap; 00423 FT_CharMap found; 00424 FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT; 00425 FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS; 00426 int n; 00427 */ 00428 int success = 0; 00429 00430 err = FT_New_Memory_Face( library, 00431 pf->data, 00432 pf->size, 00433 0, 00434 &face ); 00435 if(err) { 00436 success = 0; 00437 //XXX error("This is not a valid font"); 00438 } 00439 else { 00440 /* 00441 for ( n = 0; n < face->num_charmaps; n++ ) 00442 { 00443 charmap = face->charmaps[n]; 00444 if ( charmap->platform_id == my_platform_id && 00445 charmap->encoding_id == my_encoding_id ) 00446 { 00447 found = charmap; 00448 break; 00449 } 00450 } 00451 00452 if ( !found ) { return 0; } 00453 00454 // now, select the charmap for the face object 00455 err = FT_Set_Charmap( face, found ); 00456 if ( err ) { return 0; } 00457 */ 00458 glyph_index = FT_Get_Char_Index( face, 'A' ); 00459 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); 00460 if(err) success = 0; 00461 else { 00462 glyph = face->glyph; 00463 if (glyph->format == ft_glyph_format_outline ) { 00464 success = 1; 00465 } else { 00466 //XXX error("Selected Font has no outline data"); 00467 success = 0; 00468 } 00469 } 00470 } 00471 00472 return success; 00473 } 00474 00475 00476 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf) 00477 { 00478 VFontData *vfd= NULL; 00479 int success = 0; 00480 00481 //init Freetype 00482 err = FT_Init_FreeType( &library); 00483 if(err) { 00484 //XXX error("Failed to load the Freetype font library"); 00485 return NULL; 00486 } 00487 00488 success = check_freetypefont(pf); 00489 00490 if (success) { 00491 vfd= objfnt_to_ftvfontdata(pf); 00492 } 00493 00494 //free Freetype 00495 FT_Done_FreeType( library); 00496 00497 return vfd; 00498 } 00499 00500 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character) 00501 { 00502 int success = FALSE; 00503 00504 if(!vfont) return FALSE; 00505 00506 // Init Freetype 00507 err = FT_Init_FreeType(&library); 00508 if(err) { 00509 //XXX error("Failed to load the Freetype font library"); 00510 return 0; 00511 } 00512 00513 // Load the character 00514 success = objchr_to_ftvfontdata(vfont, character); 00515 if(success == FALSE) return FALSE; 00516 00517 // Free Freetype 00518 FT_Done_FreeType(library); 00519 00520 // Ahh everything ok 00521 return TRUE; 00522 } 00523 00524 #if 0 00525 00526 // Freetype2 Outline struct 00527 00528 typedef struct FT_Outline_ 00529 { 00530 short n_contours; /* number of contours in glyph */ 00531 short n_points; /* number of points in the glyph */ 00532 00533 FT_Vector* points; /* the outline's points */ 00534 char* tags; /* the points flags */ 00535 short* contours; /* the contour end points */ 00536 00537 int flags; /* outline masks */ 00538 00539 } FT_Outline; 00540 00541 #endif 00542 00543 /***//* 00544 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1 00545 00546 Vectorial representation of Freetype glyphs 00547 00548 The source format of outlines is a collection of closed paths called "contours". Each contour is 00549 made of a series of line segments and bezier arcs. Depending on the file format, these can be 00550 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and 00551 they come from the TrueType format. The latter are called cubic arcs and mostly come from the 00552 Type1 format. 00553 00554 Each arc is described through a series of start, end and control points. Each point of the outline 00555 has a specific tag which indicates wether it is used to describe a line segment or an arc. 00556 00557 00558 The following rules are applied to decompose the contour's points into segments and arcs : 00559 00560 # two successive "on" points indicate a line segment joining them. 00561 00562 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being 00563 the control point, and the "on" ones the start and end points. 00564 00565 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must 00566 be exactly two cubic control points and two on points for each cubic arc (using a single cubic 00567 "off" point between two "on" points is forbidden, for example). 00568 00569 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line 00570 conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This 00571 greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way 00572 outlines are described in the TrueType specification. 00573 00574 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current 00575 font driver produces such outlines. 00576 00577 * # on 00578 * off 00579 __---__ 00580 #-__ _-- -_ 00581 --__ _- - 00582 --__ # \ 00583 --__ # 00584 -# 00585 Two "on" points 00586 Two "on" points and one "conic" point 00587 between them 00588 00589 00590 00591 * 00592 # __ Two "on" points with two "conic" 00593 \ - - points between them. The point 00594 \ / \ marked '0' is the middle of the 00595 - 0 \ "off" points, and is a 'virtual' 00596 -_ _- # "on" point where the curve passes. 00597 -- It does not appear in the point 00598 list. 00599 * 00600 00601 00602 00603 00604 * # on 00605 * * off 00606 __---__ 00607 _-- -_ 00608 _- - 00609 # \ 00610 # 00611 00612 Two "on" points 00613 and two "cubic" point 00614 between them 00615 00616 00617 Each glyph's original outline points are located on a grid of indivisible units. The points are stored 00618 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus 00619 range from -16384 to 16383. 00620 00621 Convert conic to bezier arcs: 00622 Conic P0 P1 P2 00623 Bezier B0 B1 B2 B3 00624 B0=P0 00625 B1=(P0+2*P1)/3 00626 B2=(P2+2*P1)/3 00627 B3=P2 00628 00629 *//****/