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