Applied checks for more secure 3D font handling.
[blender.git] / source / blender / blenlib / intern / freetypefont.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is written by Rob Haarsma (phase)
24  * All rights reserved.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL/BL DUAL LICENSE BLOCK *****
29  *
30  * This code parses the Freetype font outline data to chains of Blender's beziertriples.
31  * Additional information can be found at the bottom of this file.
32  *
33  * Code that uses exotic character maps is present but commented out.
34  */
35
36 #ifdef WITH_FREETYPE2
37
38 #ifdef WIN32
39 #pragma warning (disable:4244)
40 #endif
41
42 #include <ft2build.h>
43 #include FT_FREETYPE_H
44 #include FT_GLYPH_H
45 #include FT_BBOX_H
46 #include FT_SIZES_H
47 #include <freetype/ttnameid.h>
48
49 #include "MEM_guardedalloc.h"
50
51 #include "BLI_vfontdata.h"
52 #include "BLI_blenlib.h"
53 #include "BLI_arithb.h"  
54
55 #include "BIF_toolbox.h"
56
57 #include "BKE_utildefines.h"
58
59 #include "DNA_packedFile_types.h"
60 #include "DNA_curve_types.h"
61
62 #define myMIN_ASCII     32
63 #define myMAX_ASCII     255
64
65 /* local variables */
66 static FT_Library       library;
67 static FT_Error         err;
68
69
70 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
71 {
72         // Blender
73         VFontData *vfd;
74         struct Nurb *nu;
75         struct BezTriple *bezt;
76
77         // Freetype2
78         FT_Face         face;
79         FT_GlyphSlot  glyph;
80         FT_UInt         glyph_index;
81         FT_Outline      ftoutline;
82 /*
83     FT_CharMap  found = 0;
84         FT_CharMap  charmap;
85         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
86         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
87         int         n;
88 */
89         const char *fontname;
90         float scale, height;
91         float dx, dy;
92         int i, j, k, l, m;
93
94         // load the freetype font
95         err = FT_New_Memory_Face( library,
96                                                 pf->data,
97                                                 pf->size,
98                                                 0,
99                                                 &face );
100
101         if(err) return NULL;
102 /*
103     for ( n = 0; n < face->num_charmaps; n++ )
104     {
105       charmap = face->charmaps[n];
106       if ( charmap->platform_id == my_platform_id &&
107            charmap->encoding_id == my_encoding_id )
108       {
109         found = charmap;
110         break;
111       }
112     }
113
114     if ( !found ) { return NULL; }
115
116     // now, select the charmap for the face object
117     err = FT_Set_Charmap( face, found );
118     if ( err ) { return NULL; }
119 */
120
121         // allocate blender font
122         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
123
124         // get the name
125         fontname = FT_Get_Postscript_Name(face);
126         strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
127
128         // adjust font size
129         height = ((double) face->bbox.yMax - (double) face->bbox.yMin);
130
131         if(height != 0.0)
132                 scale = 1.0 / height;
133         else
134                 scale = 1.0 / 1000.0;
135
136         // extract generic ascii character range
137         for(i = myMIN_ASCII; i <= myMAX_ASCII; i++) {
138                 int  *npoints;  //total points of each contour
139                 int  *onpoints; //num points on curve
140
141                 glyph_index = FT_Get_Char_Index( face, i );
142                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
143
144                 if(!err) {
145                         glyph = face->glyph;
146                         ftoutline = glyph->outline;
147
148                         vfd->width[i] = glyph->advance.x* scale;
149
150                         npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
151                         onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
152
153                         // calculate total points of each contour
154                         for(j = 0; j < ftoutline.n_contours; j++) {
155                                 if(j == 0)
156                                         npoints[j] = ftoutline.contours[j] + 1;
157                                 else
158                                         npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
159                         }
160
161                         // get number of on-curve points for beziertriples (including conic virtual on-points) 
162                         for(j = 0; j < ftoutline.n_contours; j++) {
163                                 l = 0;
164                                 for(k = 0; k < npoints[j]; k++) {
165                                         if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
166
167                                         if(ftoutline.tags[l] == FT_Curve_Tag_On)
168                                                 onpoints[j]++;
169
170                                         if(k < npoints[j] - 1 )
171                                                 if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
172                                                         ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
173                                                         onpoints[j]++;
174                                 }
175                         }
176
177                         //contour loop, bezier & conic styles merged
178                         for(j = 0; j < ftoutline.n_contours; j++) {
179                                 // add new curve
180                                 nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
181                                 bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
182                                 BLI_addtail(&vfd->nurbsbase[i], nu);
183
184                                 nu->type= CU_BEZIER+CU_2D;
185                                 nu->pntsu = onpoints[j];
186                                 nu->resolu= 8;
187                                 nu->flagu= 1;
188                                 nu->bezt = bezt;
189
190                                 //individual curve loop, start-end
191                                 for(k = 0; k < npoints[j]; k++) {
192                                         if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
193                                         if(k == 0) m = l;
194                                         
195                                         //virtual conic on-curve points
196                                         if(k < npoints[j] - 1 )
197                                                 if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
198                                                         dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
199                                                         dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
200
201                                                         //left handle
202                                                         bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
203                                                         bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
204
205                                                         //midpoint (virtual on-curve point)
206                                                         bezt->vec[1][0] = dx;
207                                                         bezt->vec[1][1] = dy;
208
209                                                         //right handle
210                                                         bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
211                                                         bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
212
213                                                         bezt->h1= bezt->h2= HD_ALIGN;
214                                                         bezt++;
215                                                 }
216
217                                         //on-curve points
218                                         if(ftoutline.tags[l] == FT_Curve_Tag_On) {
219                                                 //left handle
220                                                 if(k > 0) {
221                                                         if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
222                                                                 bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
223                                                                 bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
224                                                                 bezt->h1= HD_FREE;
225                                                         } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
226                                                                 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
227                                                                 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
228                                                                 bezt->h1= HD_FREE;
229                                                         } else {
230                                                                 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
231                                                                 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
232                                                                 bezt->h1= HD_VECT;
233                                                         }
234                                                 } else { //first point on curve
235                                                         if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
236                                                                 bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
237                                                                 bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
238                                                                 bezt->h1= HD_FREE;
239                                                         } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
240                                                                 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
241                                                                 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
242                                                                 bezt->h1= HD_FREE;
243                                                         } else {
244                                                                 bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
245                                                                 bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
246                                                                 bezt->h1= HD_VECT;
247                                                         }
248                                                 }
249
250                                                 //midpoint (on-curve point)
251                                                 bezt->vec[1][0] = ftoutline.points[l].x* scale;
252                                                 bezt->vec[1][1] = ftoutline.points[l].y* scale;
253
254                                                 //right handle
255                                                 if(k < (npoints[j] - 1)) {
256                                                         if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
257                                                                 bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
258                                                                 bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
259                                                                 bezt->h2= HD_FREE;
260                                                         } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
261                                                                 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
262                                                                 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
263                                                                 bezt->h2= HD_FREE;
264                                                         } else {
265                                                                 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
266                                                                 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
267                                                                 bezt->h2= HD_VECT;
268                                                         }
269                                                 } else { //last point on curve
270                                                         if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
271                                                                 bezt->vec[2][0] = ftoutline.points[m].x* scale;
272                                                                 bezt->vec[2][1] = ftoutline.points[m].y* scale;
273                                                                 bezt->h2= HD_FREE;
274                                                         } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
275                                                                 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
276                                                                 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
277                                                                 bezt->h2= HD_FREE;
278                                                         } else {
279                                                                 bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
280                                                                 bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
281                                                                 bezt->h2= HD_VECT;
282                                                         }
283                                                 }
284
285                                                 // get the handles that are aligned, tricky...
286                                                 // DistVL2Dfl, check if the three beztriple points are on one line
287                                                 // VecLenf, see if there's a distance between the three points
288                                                 // VecLenf again, to check the angle between the handles 
289                                                 // finally, check if one of them is a vector handle 
290                                                 if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
291                                                         (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
292                                                         (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
293                                                         (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
294                                                         (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
295                                                         bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
296                                                 {
297                                                         bezt->h1= bezt->h2= HD_ALIGN;
298                                                 }
299                                                 bezt++;
300                                         }
301                                 }
302                         }
303                 }
304
305                 if(npoints) MEM_freeN(npoints);
306                 if(onpoints) MEM_freeN(onpoints);
307         }
308         return vfd;
309 }
310
311
312 static int check_freetypefont(PackedFile * pf)
313 {
314         FT_Face                 face;
315         FT_GlyphSlot    glyph;
316         FT_UInt                 glyph_index;
317 /*
318         FT_CharMap  charmap;
319         FT_CharMap  found;
320         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
321         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
322         int         n;
323 */
324         int success = 0;
325
326         err = FT_New_Memory_Face( library,
327                                                         pf->data,
328                                                         pf->size,
329                                                         0,
330                                                         &face );
331         if(err) {
332                 success = 0;
333             error("This is not a valid font");
334         }
335         else {
336 /*
337                 for ( n = 0; n < face->num_charmaps; n++ )
338                 {
339                   charmap = face->charmaps[n];
340                   if ( charmap->platform_id == my_platform_id &&
341                            charmap->encoding_id == my_encoding_id )
342                   {
343                         found = charmap;
344                         break;
345                   }
346                 }
347
348                 if ( !found ) { return 0; }
349
350                 // now, select the charmap for the face object 
351                 err = FT_Set_Charmap( face, found );
352                 if ( err ) { return 0; }
353 */
354                 glyph_index = FT_Get_Char_Index( face, 'A' );
355                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
356                 if(err) success = 0;
357                 else {
358                         glyph = face->glyph;
359                         if (glyph->format == ft_glyph_format_outline ) {
360                                 success = 1;
361                         } else {
362                                 error("Selected Font has no outline data");
363                                 success = 0;
364                         }
365                 }
366         }
367         
368         return success;
369 }
370
371
372 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
373 {
374         VFontData *vfd= NULL;
375         int success = 0;
376
377         //init Freetype 
378         err = FT_Init_FreeType( &library);
379         if(err) {
380             error("Failed to load the Freetype font library");
381                 return 0;
382         }
383
384         success = check_freetypefont(pf);
385         
386         if (success) {
387                 vfd= objfnt_to_ftvfontdata(pf);
388         }
389
390         //free Freetype
391         FT_Done_FreeType( library);
392         
393         return vfd;
394 }
395
396 #endif // WITH_FREETYPE2
397
398
399
400 #if 0
401
402 // Freetype2 Outline struct
403
404 typedef struct  FT_Outline_
405   {
406     short       n_contours;      /* number of contours in glyph        */
407     short       n_points;        /* number of points in the glyph      */
408
409     FT_Vector*  points;          /* the outline's points               */
410     char*       tags;            /* the points flags                   */
411     short*      contours;        /* the contour end points             */
412
413     int         flags;           /* outline masks                      */
414
415   } FT_Outline;
416
417 #endif
418
419 /***//*
420 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
421
422 Vectorial representation of Freetype glyphs
423
424 The source format of outlines is a collection of closed paths called "contours". Each contour is
425 made of a series of line segments and bezier arcs. Depending on the file format, these can be
426 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
427 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
428 Type1 format.
429
430 Each arc is described through a series of start, end and control points. Each point of the outline
431 has a specific tag which indicates wether it is used to describe a line segment or an arc.
432
433
434 The following rules are applied to decompose the contour's points into segments and arcs :
435
436 # two successive "on" points indicate a line segment joining them.
437
438 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
439   the control point, and the "on" ones the start and end points.
440
441 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
442   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
443   "off" point between two "on" points is forbidden, for example).
444
445 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
446   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
447   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
448   outlines are described in the TrueType specification.
449
450 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
451 font driver produces such outlines.
452
453                                   *            # on      
454                                                * off
455                                __---__
456   #-__                      _--       -_
457       --__                _-            -
458           --__           #               \
459               --__                        #
460                   -#
461                            Two "on" points
462    Two "on" points       and one "conic" point
463                             between them
464
465
466
467                 *
468   #            __      Two "on" points with two "conic"
469    \          -  -     points between them. The point
470     \        /    \    marked '0' is the middle of the
471      -      0      \   "off" points, and is a 'virtual'
472       -_  _-       #   "on" point where the curve passes.
473         --             It does not appear in the point
474                        list.
475         *
476
477
478
479
480         *                # on
481                    *     * off
482          __---__
483       _--       -_
484     _-            -
485    #               \
486                     #
487
488      Two "on" points
489    and two "cubic" point
490       between them
491
492
493 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
494 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
495 range from -16384 to 16383.
496
497 Convert conic to bezier arcs:
498 Conic P0 P1 P2
499 Bezier B0 B1 B2 B3
500 B0=P0
501 B1=(P0+2*P1)/3
502 B2=(P2+2*P1)/3
503 B3=P2
504
505 *//****/