merge trunk 16118 -> 116886
[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 WITH_FREETYPE2
34
35 #ifdef WIN32
36 #pragma warning (disable:4244)
37 #endif
38
39 #include <ft2build.h>
40 #include FT_FREETYPE_H
41 #include FT_GLYPH_H
42 #include FT_BBOX_H
43 #include FT_SIZES_H
44 #include <freetype/ttnameid.h>
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_vfontdata.h"
49 #include "BLI_blenlib.h"
50 #include "BLI_arithb.h"  
51
52 #include "BIF_toolbox.h"
53
54 #include "BKE_global.h"
55 #include "BKE_utildefines.h"
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 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+CU_2D;
151                         nu->pntsu = onpoints[j];
152                         nu->resolu= 8;
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++;
182                                         }
183                                 }
184
185                                 //on-curve points
186                                 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
187                                         //left handle
188                                         if(k > 0) {
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;
192                                                         bezt->h1= HD_FREE;
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;
196                                                         bezt->h1= HD_FREE;
197                                                 } else {
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;
200                                                         bezt->h1= HD_VECT;
201                                                 }
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;
206                                                         bezt->h1= HD_FREE;
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 ;
210                                                         bezt->h1= HD_FREE;
211                                                 } else {
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;
214                                                         bezt->h1= HD_VECT;
215                                                 }
216                                         }
217
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;
221
222                                         //right handle
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;
227                                                         bezt->h2= HD_FREE;
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;
231                                                         bezt->h2= HD_FREE;
232                                                 } else {
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;
235                                                         bezt->h2= HD_VECT;
236                                                 }
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;
241                                                         bezt->h2= HD_FREE;
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 ;
245                                                         bezt->h2= HD_FREE;
246                                                 } else {
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;
249                                                         bezt->h2= HD_VECT;
250                                                 }
251                                         }
252
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)
264                                         {
265                                                 bezt->h1= bezt->h2= HD_ALIGN;
266                                         }
267                                         bezt++;
268                                 }
269                         }
270                 }
271                 if(npoints) MEM_freeN(npoints);
272                 if(onpoints) MEM_freeN(onpoints);       
273         }
274 }
275
276 int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
277 {
278         // Freetype2
279         FT_Face face;
280         struct TmpFont *tf;
281         
282         // Find the correct FreeType font
283         tf= G.ttfdata.first;
284         while(tf)
285         {
286                 if(tf->vfont == vfont)
287                         break;
288                 tf= tf->next;           
289         }
290         
291         // What, no font found. Something strange here
292         if(!tf) return FALSE;
293         
294         // Load the font to memory
295         if(tf->pf)
296         {
297                 err= FT_New_Memory_Face( library,
298                         tf->pf->data,
299                         tf->pf->size,
300                         0,
301                         &face);                 
302         }
303         else
304                 err= TRUE;
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 not available" : 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             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                                 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                 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                 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 #endif // WITH_FREETYPE2
521
522
523
524 #if 0
525
526 // Freetype2 Outline struct
527
528 typedef struct  FT_Outline_
529   {
530     short       n_contours;      /* number of contours in glyph        */
531     short       n_points;        /* number of points in the glyph      */
532
533     FT_Vector*  points;          /* the outline's points               */
534     char*       tags;            /* the points flags                   */
535     short*      contours;        /* the contour end points             */
536
537     int         flags;           /* outline masks                      */
538
539   } FT_Outline;
540
541 #endif
542
543 /***//*
544 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
545
546 Vectorial representation of Freetype glyphs
547
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
552 Type1 format.
553
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.
556
557
558 The following rules are applied to decompose the contour's points into segments and arcs :
559
560 # two successive "on" points indicate a line segment joining them.
561
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.
564
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).
568
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.
573
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.
576
577                                   *            # on      
578                                                * off
579                                __---__
580   #-__                      _--       -_
581       --__                _-            -
582           --__           #               \
583               --__                        #
584                   -#
585                            Two "on" points
586    Two "on" points       and one "conic" point
587                             between them
588
589
590
591                 *
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
598                        list.
599         *
600
601
602
603
604         *                # on
605                    *     * off
606          __---__
607       _--       -_
608     _-            -
609    #               \
610                     #
611
612      Two "on" points
613    and two "cubic" point
614       between them
615
616
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.
620
621 Convert conic to bezier arcs:
622 Conic P0 P1 P2
623 Bezier B0 B1 B2 B3
624 B0=P0
625 B1=(P0+2*P1)/3
626 B2=(P2+2*P1)/3
627 B3=P2
628
629 *//****/