remove misc unused vars and correct theme name for face angles.
[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                         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_NURB_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                                         // dist_to_line_v2, check if the three beztriple points are on one line
256                                         // len_squared_v2v2, see if there's a distance between the three points
257                                         // len_squared_v2v2 again, to check the angle between the handles 
258                                         // finally, check if one of them is a vector handle 
259                                         if((dist_to_line_v2(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
260                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001*0.0001) &&
261                                                 (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001*0.0001) &&
262                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002*0.0001) &&
263                                                 (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]))) &&
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);
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 *//****/