4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is written by Rob Haarsma (phase)
21 * All rights reserved.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
27 * This code parses the Freetype font outline data to chains of Blender's beziertriples.
28 * Additional information can be found at the bottom of this file.
30 * Code that uses exotic character maps is present but commented out.
36 #pragma warning (disable:4244)
40 #include FT_FREETYPE_H
44 #include <freetype/ttnameid.h>
46 #include "MEM_guardedalloc.h"
48 #include "BLI_vfontdata.h"
49 #include "BLI_blenlib.h"
50 #include "BLI_arithb.h"
52 #include "BIF_toolbox.h"
54 #include "BKE_global.h"
55 #include "BKE_utildefines.h"
57 #include "DNA_vfont_types.h"
58 #include "DNA_packedFile_types.h"
59 #include "DNA_curve_types.h"
61 #define myMIN_ASCII 32
62 #define myMAX_ASCII 255
65 static FT_Library library;
69 void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
74 struct BezTriple *bezt;
85 height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
92 // Generate the character 3D data
94 // Get the FT Glyph index and load the Glyph
95 glyph_index= FT_Get_Char_Index(face, charcode);
96 err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
98 // If loading succeeded, convert the FT glyph to the internal format
104 // First we create entry for the new character to the character list
105 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
106 BLI_addtail(&vfd->characters, che);
108 // Take some data for modifying purposes
110 ftoutline= glyph->outline;
112 // Set the width and character code
113 che->index= charcode;
114 che->width= glyph->advance.x * scale;
116 // Start converting the FT data
117 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
118 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
120 // calculate total points of each contour
121 for(j = 0; j < ftoutline.n_contours; j++) {
123 npoints[j] = ftoutline.contours[j] + 1;
125 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
128 // get number of on-curve points for beziertriples (including conic virtual on-points)
129 for(j = 0; j < ftoutline.n_contours; j++) {
131 for(k = 0; k < npoints[j]; k++) {
132 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
133 if(ftoutline.tags[l] == FT_Curve_Tag_On)
136 if(k < npoints[j] - 1 )
137 if( ftoutline.tags[l] == FT_Curve_Tag_Conic &&
138 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
143 //contour loop, bezier & conic styles merged
144 for(j = 0; j < ftoutline.n_contours; j++) {
146 nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
147 bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
148 BLI_addtail(&che->nurbsbase, nu);
150 nu->type= CU_BEZIER+CU_2D;
151 nu->pntsu = onpoints[j];
153 nu->flagu= CU_CYCLIC;
156 //individual curve loop, start-end
157 for(k = 0; k < npoints[j]; k++) {
158 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
161 //virtual conic on-curve points
162 if(k < npoints[j] - 1 )
164 if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
165 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
166 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
169 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
170 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
172 //midpoint (virtual on-curve point)
173 bezt->vec[1][0] = dx;
174 bezt->vec[1][1] = dy;
177 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
178 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
180 bezt->h1= bezt->h2= HD_ALIGN;
186 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
189 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
190 bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
191 bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
193 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
194 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
195 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
198 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
199 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
202 } else { //first point on curve
203 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
204 bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
205 bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
207 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
208 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
209 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
212 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
213 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
218 //midpoint (on-curve point)
219 bezt->vec[1][0] = ftoutline.points[l].x* scale;
220 bezt->vec[1][1] = ftoutline.points[l].y* scale;
223 if(k < (npoints[j] - 1)) {
224 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
225 bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
226 bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
228 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
229 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
230 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
233 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
234 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
237 } else { //last point on curve
238 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
239 bezt->vec[2][0] = ftoutline.points[m].x* scale;
240 bezt->vec[2][1] = ftoutline.points[m].y* scale;
242 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
243 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
244 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
247 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
248 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
253 // get the handles that are aligned, tricky...
254 // DistVL2Dfl, check if the three beztriple points are on one line
255 // VecLenf, see if there's a distance between the three points
256 // VecLenf again, to check the angle between the handles
257 // finally, check if one of them is a vector handle
258 if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
259 (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
260 (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
261 (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
262 (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
263 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
265 bezt->h1= bezt->h2= HD_ALIGN;
271 if(npoints) MEM_freeN(npoints);
272 if(onpoints) MEM_freeN(onpoints);
276 int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
282 // Find the correct FreeType font
286 if(tf->vfont == vfont)
291 // What, no font found. Something strange here
292 if(!tf) return FALSE;
294 // Load the font to memory
297 err= FT_New_Memory_Face( library,
307 freetypechar_to_vchar(face, charcode, vfont->data);
309 // And everything went ok
314 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
318 FT_ULong charcode = 0, lcode;
320 const char *fontname;
324 FT_CharMap found = 0;
326 FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
327 FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
331 // load the freetype font
332 err = FT_New_Memory_Face( library,
340 for ( n = 0; n < face->num_charmaps; n++ )
342 charmap = face->charmaps[n];
343 if ( charmap->platform_id == my_platform_id &&
344 charmap->encoding_id == my_encoding_id )
351 if ( !found ) { return NULL; }
353 // now, select the charmap for the face object
354 err = FT_Set_Charmap( face, found );
355 if ( err ) { return NULL; }
358 // allocate blender font
359 vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
362 fontname = FT_Get_Postscript_Name(face);
363 strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
365 // Extract the first 256 character from TTF
366 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
368 // No charmap found from the ttf so we need to figure it out
371 FT_CharMap found = 0;
375 for ( n = 0; n < face->num_charmaps; n++ )
377 charmap = face->charmaps[n];
378 if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
385 err = FT_Set_Charmap( face, found );
390 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
394 while(charcode < 256)
396 // Generate the font data
397 freetypechar_to_vchar(face, charcode, vfd);
400 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
402 // Check that we won't start infinite loop
403 if(charcode <= lcode)
412 static int check_freetypefont(PackedFile * pf)
420 FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
421 FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
426 err = FT_New_Memory_Face( library,
433 error("This is not a valid font");
437 for ( n = 0; n < face->num_charmaps; n++ )
439 charmap = face->charmaps[n];
440 if ( charmap->platform_id == my_platform_id &&
441 charmap->encoding_id == my_encoding_id )
448 if ( !found ) { return 0; }
450 // now, select the charmap for the face object
451 err = FT_Set_Charmap( face, found );
452 if ( err ) { return 0; }
454 glyph_index = FT_Get_Char_Index( face, 'A' );
455 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
459 if (glyph->format == ft_glyph_format_outline ) {
462 error("Selected Font has no outline data");
472 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
474 VFontData *vfd= NULL;
478 err = FT_Init_FreeType( &library);
480 error("Failed to load the Freetype font library");
484 success = check_freetypefont(pf);
487 vfd= objfnt_to_ftvfontdata(pf);
491 FT_Done_FreeType( library);
496 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
500 if(!vfont) return FALSE;
503 err = FT_Init_FreeType(&library);
505 error("Failed to load the Freetype font library");
509 // Load the character
510 success = objchr_to_ftvfontdata(vfont, character);
511 if(success == FALSE) return FALSE;
514 FT_Done_FreeType(library);
520 #endif // WITH_FREETYPE2
526 // Freetype2 Outline struct
528 typedef struct FT_Outline_
530 short n_contours; /* number of contours in glyph */
531 short n_points; /* number of points in the glyph */
533 FT_Vector* points; /* the outline's points */
534 char* tags; /* the points flags */
535 short* contours; /* the contour end points */
537 int flags; /* outline masks */
544 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
546 Vectorial representation of Freetype glyphs
548 The source format of outlines is a collection of closed paths called "contours". Each contour is
549 made of a series of line segments and bezier arcs. Depending on the file format, these can be
550 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
551 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
554 Each arc is described through a series of start, end and control points. Each point of the outline
555 has a specific tag which indicates wether it is used to describe a line segment or an arc.
558 The following rules are applied to decompose the contour's points into segments and arcs :
560 # two successive "on" points indicate a line segment joining them.
562 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
563 the control point, and the "on" ones the start and end points.
565 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
566 be exactly two cubic control points and two on points for each cubic arc (using a single cubic
567 "off" point between two "on" points is forbidden, for example).
569 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
570 conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
571 greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
572 outlines are described in the TrueType specification.
574 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
575 font driver produces such outlines.
586 Two "on" points and one "conic" point
592 # __ Two "on" points with two "conic"
593 \ - - points between them. The point
594 \ / \ marked '0' is the middle of the
595 - 0 \ "off" points, and is a 'virtual'
596 -_ _- # "on" point where the curve passes.
597 -- It does not appear in the point
613 and two "cubic" point
617 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
618 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
619 range from -16384 to 16383.
621 Convert conic to bezier arcs: