f63302e3cee47cf66c5293c99e8f690044495cf7
[blender.git] / source / blender / blenlib / intern / freetypefont.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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.
10  *
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.
15  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is written by Rob Haarsma (phase)
21  * All rights reserved.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
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.
29  *
30  * Code that uses exotic character maps is present but commented out.
31  */
32
33 #ifdef WIN32
34 #pragma warning (disable:4244)
35 #endif
36
37 #include <ft2build.h>
38 #include FT_FREETYPE_H
39 /* not needed yet */
40 // #include FT_GLYPH_H
41 // #include FT_BBOX_H
42 // #include FT_SIZES_H
43 // #include <freetype/ttnameid.h>
44
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_vfontdata.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_math.h"
50 #include "BLI_utildefines.h"
51
52 //XXX #include "BIF_toolbox.h"
53
54 #include "BKE_font.h"
55
56
57 #include "DNA_vfont_types.h"
58 #include "DNA_packedFile_types.h"
59 #include "DNA_curve_types.h"
60
61 #define myMIN_ASCII     32
62 #define myMAX_ASCII     255
63
64 /* local variables */
65 static FT_Library       library;
66 static FT_Error         err;
67
68
69 static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
70 {
71         // Blender
72         struct Nurb *nu;
73         struct VChar *che;
74         struct BezTriple *bezt;
75         
76         // Freetype2
77         FT_GlyphSlot glyph;
78         FT_UInt glyph_index;
79         FT_Outline ftoutline;
80         float scale, height;
81         float dx, dy;
82         int j,k,l,m=0;
83         
84         // adjust font size
85         height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
86         if(height != 0.0)
87                 scale = 1.0 / height;
88         else
89                 scale = 1.0 / 1000.0;
90         
91         //      
92         // Generate the character 3D data
93         //
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);
97         
98         // If loading succeeded, convert the FT glyph to the internal format
99         if(!err)
100         {
101                 int *npoints;
102                 int *onpoints;
103                 
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);
107                 
108                 // Take some data for modifying purposes
109                 glyph= face->glyph;
110                 ftoutline= glyph->outline;
111                 
112                 // Set the width and character code
113                 che->index= charcode;
114                 che->width= glyph->advance.x * scale;
115                 
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") ;
119
120                 // calculate total points of each contour
121                 for(j = 0; j < ftoutline.n_contours; j++) {
122                         if(j == 0)
123                                 npoints[j] = ftoutline.contours[j] + 1;
124                         else
125                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
126                 }
127
128                 // get number of on-curve points for beziertriples (including conic virtual on-points) 
129                 for(j = 0; j < ftoutline.n_contours; j++) {
130                         l = 0;
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)
134                                                 onpoints[j]++;
135
136                                 if(k < npoints[j] - 1 )
137                                         if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
138                                                 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
139                                                 onpoints[j]++;
140                         }
141                 }
142
143                 //contour loop, bezier & conic styles merged
144                 for(j = 0; j < ftoutline.n_contours; j++) {
145                         // add new curve
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);
149
150                         nu->type= CU_BEZIER;
151                         nu->pntsu = onpoints[j];
152                         nu->resolu= 8;
153                         nu->flag= CU_2D;
154                         nu->flagu= CU_NURB_CYCLIC;
155                         nu->bezt = bezt;
156
157                         //individual curve loop, start-end
158                         for(k = 0; k < npoints[j]; k++) {
159                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
160                                 if(k == 0) m = l;
161                                         
162                                 //virtual conic on-curve points
163                                 if(k < npoints[j] - 1 )
164                                 {
165                                         if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
166                                                 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
167                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
168
169                                                 //left handle
170                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
171                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
172
173                                                 //midpoint (virtual on-curve point)
174                                                 bezt->vec[1][0] = dx;
175                                                 bezt->vec[1][1] = dy;
176
177                                                 //right handle
178                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
179                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
180
181                                                 bezt->h1= bezt->h2= HD_ALIGN;
182                                                 bezt->radius= 1.0f;
183                                                 bezt++;
184                                         }
185                                 }
186
187                                 //on-curve points
188                                 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
189                                         //left handle
190                                         if(k > 0) {
191                                                 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
192                                                         bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
193                                                         bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
194                                                         bezt->h1= HD_FREE;
195                                                 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
196                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
197                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
198                                                         bezt->h1= HD_FREE;
199                                                 } else {
200                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
201                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
202                                                         bezt->h1= HD_VECT;
203                                                 }
204                                         } else { //first point on curve
205                                                 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
206                                                         bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
207                                                         bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
208                                                         bezt->h1= HD_FREE;
209                                                 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
210                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
211                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
212                                                         bezt->h1= HD_FREE;
213                                                 } else {
214                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
215                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
216                                                         bezt->h1= HD_VECT;
217                                                 }
218                                         }
219
220                                         //midpoint (on-curve point)
221                                         bezt->vec[1][0] = ftoutline.points[l].x* scale;
222                                         bezt->vec[1][1] = ftoutline.points[l].y* scale;
223
224                                         //right handle
225                                         if(k < (npoints[j] - 1)) {
226                                                 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
227                                                         bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
228                                                         bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
229                                                         bezt->h2= HD_FREE;
230                                                 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
231                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
232                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
233                                                         bezt->h2= HD_FREE;
234                                                 } else {
235                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
236                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
237                                                         bezt->h2= HD_VECT;
238                                                 }
239                                         } else { //last point on curve
240                                                 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
241                                                         bezt->vec[2][0] = ftoutline.points[m].x* scale;
242                                                         bezt->vec[2][1] = ftoutline.points[m].y* scale;
243                                                         bezt->h2= HD_FREE;
244                                                 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
245                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
246                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
247                                                         bezt->h2= HD_FREE;
248                                                 } else {
249                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
250                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
251                                                         bezt->h2= HD_VECT;
252                                                 }
253                                         }
254
255                                         // get the handles that are aligned, tricky...
256                                         // dist_to_line_v2, check if the three beztriple points are on one line
257                                         // len_squared_v2v2, see if there's a distance between the three points
258                                         // len_squared_v2v2 again, to check the angle between the handles 
259                                         // finally, check if one of them is a vector handle 
260                                         if((dist_to_line_v2(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
261                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001*0.0001) &&
262                                                 (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001*0.0001) &&
263                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002*0.0001) &&
264                                                 (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]))) &&
265                                                 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
266                                         {
267                                                 bezt->h1= bezt->h2= HD_ALIGN;
268                                         }
269                                         bezt->radius= 1.0f;
270                                         bezt++;
271                                 }
272                         }
273                 }
274                 if(npoints) MEM_freeN(npoints);
275                 if(onpoints) MEM_freeN(onpoints);       
276         }
277 }
278
279 static int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
280 {
281         // Freetype2
282         FT_Face face;
283         struct TmpFont *tf;
284         
285         // Find the correct FreeType font
286         tf= vfont_find_tmpfont(vfont);
287         
288         // What, no font found. Something strange here
289         if(!tf) return FALSE;
290         
291         // Load the font to memory
292         if(tf->pf)
293         {
294                 err= FT_New_Memory_Face( library,
295                         tf->pf->data,
296                         tf->pf->size,
297                         0,
298                         &face);                 
299                 if (err) return FALSE;
300         }
301         else {
302                 err = TRUE;
303                 return FALSE;
304         }
305                 
306         // Read the char
307         freetypechar_to_vchar(face, charcode, vfont->data);
308         
309         // And everything went ok
310         return TRUE;
311 }
312
313
314 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
315 {
316         // Variables
317         FT_Face face;
318         FT_ULong charcode = 0, lcode;
319         FT_UInt glyph_index;
320         const char *fontname;
321         VFontData *vfd;
322
323 /*
324         FT_CharMap  found = 0;
325         FT_CharMap  charmap;
326         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
327         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
328         int         n;
329 */
330
331         // load the freetype font
332         err = FT_New_Memory_Face( library,
333                                                 pf->data,
334                                                 pf->size,
335                                                 0,
336                                                 &face );
337
338         if(err) return NULL;
339 /*
340         for ( n = 0; n < face->num_charmaps; n++ )
341         {
342                 charmap = face->charmaps[n];
343                 if ( charmap->platform_id == my_platform_id &&
344                         charmap->encoding_id == my_encoding_id )
345                 {
346                         found = charmap;
347                         break;
348                 }
349         }
350
351         if ( !found ) { return NULL; }
352
353         // now, select the charmap for the face object
354         err = FT_Set_Charmap( face, found );
355         if ( err ) { return NULL; }
356 */
357
358         // allocate blender font
359         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
360
361         // get the name
362         fontname = FT_Get_Postscript_Name(face);
363         strcpy(vfd->name, (fontname == NULL) ? "" : fontname);
364
365         // Extract the first 256 character from TTF
366         lcode= charcode= FT_Get_First_Char(face, &glyph_index);
367
368         // No charmap found from the ttf so we need to figure it out
369         if(glyph_index == 0)
370         {
371                 FT_CharMap  found = 0;
372                 FT_CharMap  charmap;
373                 int n;
374
375                 for ( n = 0; n < face->num_charmaps; n++ )
376                 {
377                         charmap = face->charmaps[n];
378                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
379                         {
380                                 found = charmap;
381                                 break;
382                         }
383                 }
384
385                 err = FT_Set_Charmap( face, found );
386
387                 if( err ) 
388                         return NULL;
389
390                 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
391         }
392
393         // Load characters
394         while(charcode < 256)
395         {
396                 // Generate the font data
397                 freetypechar_to_vchar(face, charcode, vfd);
398
399                 // Next glyph
400                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
401
402                 // Check that we won't start infinite loop
403                 if(charcode <= lcode)
404                         break;
405                 lcode = charcode;
406         }
407
408         return vfd;     
409 }
410
411
412 static int check_freetypefont(PackedFile * pf)
413 {
414         FT_Face                 face;
415         FT_GlyphSlot    glyph;
416         FT_UInt                 glyph_index;
417 /*
418         FT_CharMap  charmap;
419         FT_CharMap  found;
420         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
421         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
422         int         n;
423 */
424         int success = 0;
425
426         err = FT_New_Memory_Face( library,
427                                                         pf->data,
428                                                         pf->size,
429                                                         0,
430                                                         &face );
431         if(err) {
432                 success = 0;
433                 //XXX error("This is not a valid font");
434         }
435         else {
436 /*
437                 for ( n = 0; n < face->num_charmaps; n++ )
438                 {
439                   charmap = face->charmaps[n];
440                   if ( charmap->platform_id == my_platform_id &&
441                            charmap->encoding_id == my_encoding_id )
442                   {
443                         found = charmap;
444                         break;
445                   }
446                 }
447
448                 if ( !found ) { return 0; }
449
450                 // now, select the charmap for the face object 
451                 err = FT_Set_Charmap( face, found );
452                 if ( err ) { return 0; }
453 */
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);
456                 if(err) success = 0;
457                 else {
458                         glyph = face->glyph;
459                         if (glyph->format == ft_glyph_format_outline ) {
460                                 success = 1;
461                         } else {
462                                 //XXX error("Selected Font has no outline data");
463                                 success = 0;
464                         }
465                 }
466         }
467         
468         return success;
469 }
470
471
472 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
473 {
474         VFontData *vfd= NULL;
475         int success = 0;
476
477         //init Freetype 
478         err = FT_Init_FreeType( &library);
479         if(err) {
480                 //XXX error("Failed to load the Freetype font library");
481                 return 0;
482         }
483
484         success = check_freetypefont(pf);
485         
486         if (success) {
487                 vfd= objfnt_to_ftvfontdata(pf);
488         }
489
490         //free Freetype
491         FT_Done_FreeType( library);
492         
493         return vfd;
494 }
495
496 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
497 {
498         int success = FALSE;
499
500         if(!vfont) return FALSE;
501
502         // Init Freetype
503         err = FT_Init_FreeType(&library);
504         if(err) {
505                 //XXX error("Failed to load the Freetype font library");
506                 return 0;
507         }
508
509         // Load the character
510         success = objchr_to_ftvfontdata(vfont, character);
511         if(success == FALSE) return FALSE;
512
513         // Free Freetype
514         FT_Done_FreeType(library);
515
516         // Ahh everything ok
517         return TRUE;
518 }
519
520 #if 0
521
522 // Freetype2 Outline struct
523
524 typedef struct  FT_Outline_
525   {
526         short       n_contours;      /* number of contours in glyph        */
527         short       n_points;        /* number of points in the glyph      */
528
529         FT_Vector*  points;          /* the outline's points               */
530         char*       tags;            /* the points flags                   */
531         short*      contours;        /* the contour end points             */
532
533         int         flags;           /* outline masks                      */
534
535   } FT_Outline;
536
537 #endif
538
539 /***//*
540 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
541
542 Vectorial representation of Freetype glyphs
543
544 The source format of outlines is a collection of closed paths called "contours". Each contour is
545 made of a series of line segments and bezier arcs. Depending on the file format, these can be
546 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
547 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
548 Type1 format.
549
550 Each arc is described through a series of start, end and control points. Each point of the outline
551 has a specific tag which indicates wether it is used to describe a line segment or an arc.
552
553
554 The following rules are applied to decompose the contour's points into segments and arcs :
555
556 # two successive "on" points indicate a line segment joining them.
557
558 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
559   the control point, and the "on" ones the start and end points.
560
561 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
562   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
563   "off" point between two "on" points is forbidden, for example).
564
565 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
566   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
567   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
568   outlines are described in the TrueType specification.
569
570 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
571 font driver produces such outlines.
572
573                                                                   *            # on      
574                                                                                            * off
575                                                            __---__
576   #-__                      _--       -_
577           --__                _-            -
578                   --__           #               \
579                           --__                        #
580                                   -#
581                                                    Two "on" points
582    Two "on" points       and one "conic" point
583                                                         between them
584
585
586
587                                 *
588   #            __      Two "on" points with two "conic"
589    \          -  -     points between them. The point
590         \        /    \    marked '0' is the middle of the
591          -      0      \   "off" points, and is a 'virtual'
592           -_  _-       #   "on" point where the curve passes.
593                 --             It does not appear in the point
594                                            list.
595                 *
596
597
598
599
600                 *                # on
601                                    *     * off
602                  __---__
603           _--       -_
604         _-            -
605    #               \
606                                         #
607
608          Two "on" points
609    and two "cubic" point
610           between them
611
612
613 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
614 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
615 range from -16384 to 16383.
616
617 Convert conic to bezier arcs:
618 Conic P0 P1 P2
619 Bezier B0 B1 B2 B3
620 B0=P0
621 B1=(P0+2*P1)/3
622 B2=(P2+2*P1)/3
623 B3=P2
624
625 *//****/