style cleanup, brackets in else/if, some indentation.
[blender.git] / source / blender / blenlib / intern / freetypefont.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is written by Rob Haarsma (phase)
19  * All rights reserved.
20  *
21  * Contributor(s): none yet.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  * This code parses the Freetype font outline data to chains of Blender's beziertriples.
26  * Additional information can be found at the bottom of this file.
27  *
28  * Code that uses exotic character maps is present but commented out.
29  */
30
31 /** \file blender/blenlib/intern/freetypefont.c
32  *  \ingroup bli
33  */
34
35
36 #ifdef WIN32
37 #pragma warning (disable:4244)
38 #endif
39
40 #include <ft2build.h>
41 #include FT_FREETYPE_H
42 /* not needed yet */
43 // #include FT_GLYPH_H
44 // #include FT_BBOX_H
45 // #include FT_SIZES_H
46 // #include <freetype/ttnameid.h>
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_vfontdata.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_math.h"
53 #include "BLI_utildefines.h"
54
55 //XXX #include "BIF_toolbox.h"
56
57 #include "BKE_font.h"
58
59
60 #include "DNA_vfont_types.h"
61 #include "DNA_packedFile_types.h"
62 #include "DNA_curve_types.h"
63
64 #define myMIN_ASCII     32
65 #define myMAX_ASCII     255
66
67 /* local variables */
68 static FT_Library       library;
69 static FT_Error         err;
70
71
72 static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
73 {
74         // Blender
75         struct Nurb *nu;
76         struct VChar *che;
77         struct BezTriple *bezt;
78         
79         // Freetype2
80         FT_GlyphSlot glyph;
81         FT_UInt glyph_index;
82         FT_Outline ftoutline;
83         float scale, height;
84         float dx, dy;
85         int j,k,l,m=0;
86         
87         // adjust font size
88         height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
89         if(height != 0.0f)
90                 scale = 1.0f / height;
91         else
92                 scale = 1.0f / 1000.0f;
93         
94         //      
95         // Generate the character 3D data
96         //
97         // Get the FT Glyph index and load the Glyph
98         glyph_index= FT_Get_Char_Index(face, charcode);
99         err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
100         
101         // If loading succeeded, convert the FT glyph to the internal format
102         if(!err) {
103                 int *npoints;
104                 int *onpoints;
105                 
106                 // First we create entry for the new character to the character list
107                 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
108                 BLI_addtail(&vfd->characters, che);
109                 
110                 // Take some data for modifying purposes
111                 glyph= face->glyph;
112                 ftoutline= glyph->outline;
113                 
114                 // Set the width and character code
115                 che->index= charcode;
116                 che->width= glyph->advance.x * scale;
117                 
118                 // Start converting the FT data
119                 npoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int),"endpoints");
120                 onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int),"onpoints");
121
122                 // calculate total points of each contour
123                 for(j = 0; j < ftoutline.n_contours; j++) {
124                         if(j == 0)
125                                 npoints[j] = ftoutline.contours[j] + 1;
126                         else
127                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
128                 }
129
130                 // get number of on-curve points for beziertriples (including conic virtual on-points) 
131                 for(j = 0; j < ftoutline.n_contours; j++) {
132                         for(k = 0; k < npoints[j]; k++) {
133                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
134                                         if(ftoutline.tags[l] == FT_Curve_Tag_On)
135                                                 onpoints[j]++;
136
137                                 if(k < npoints[j] - 1 )
138                                         if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
139                                                 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
140                                                 onpoints[j]++;
141                         }
142                 }
143
144                 //contour loop, bezier & conic styles merged
145                 for(j = 0; j < ftoutline.n_contours; j++) {
146                         // add new curve
147                         nu  =  (Nurb *)MEM_callocN(sizeof(struct Nurb), "objfnt_nurb");
148                         bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt");
149                         BLI_addtail(&che->nurbsbase, nu);
150
151                         nu->type= CU_BEZIER;
152                         nu->pntsu = onpoints[j];
153                         nu->resolu= 8;
154                         nu->flag= CU_2D;
155                         nu->flagu= CU_NURB_CYCLIC;
156                         nu->bezt = bezt;
157
158                         //individual curve loop, start-end
159                         for(k = 0; k < npoints[j]; k++) {
160                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
161                                 if(k == 0) m = l;
162                                         
163                                 //virtual conic on-curve points
164                                 if (k < npoints[j] - 1) {
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.0f;
167                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0f;
168
169                                                 //left handle
170                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0f;
171                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0f;
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.0f;
179                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0f;
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.0f;
197                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0f;
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.0f;
201                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0f;
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.0f;
211                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0f;
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.0f;
215                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0f;
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.0f;
232                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0f;
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.0f;
236                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0f;
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.0f;
246                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0f;
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.0f;
250                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0f;
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.001f) &&
261                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001f*0.0001f) &&
262                                                 (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001f*0.0001f) &&
263                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002f*0.0001f) &&
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                 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 #if 0
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 #endif
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 #if 0
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 #endif
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         BLI_strncpy(vfd->name, (fontname == NULL) ? "" : fontname, sizeof(vfd->name));
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                 FT_CharMap  found = NULL;
371                 FT_CharMap  charmap;
372                 int n;
373
374                 for (n = 0; n < face->num_charmaps; n++) {
375                         charmap = face->charmaps[n];
376                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) {
377                                 found = charmap;
378                                 break;
379                         }
380                 }
381
382                 err = FT_Set_Charmap( face, found );
383
384                 if( err ) 
385                         return NULL;
386
387                 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
388         }
389
390         // Load characters
391         while(charcode < 256)
392         {
393                 // Generate the font data
394                 freetypechar_to_vchar(face, charcode, vfd);
395
396                 // Next glyph
397                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
398
399                 // Check that we won't start infinite loop
400                 if(charcode <= lcode)
401                         break;
402                 lcode = charcode;
403         }
404
405         return vfd;     
406 }
407
408
409 static int check_freetypefont(PackedFile * pf)
410 {
411         FT_Face                 face;
412         FT_GlyphSlot    glyph;
413         FT_UInt                 glyph_index;
414 #if 0
415         FT_CharMap  charmap;
416         FT_CharMap  found;
417         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
418         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
419         int         n;
420 #endif
421         int success = 0;
422
423         err = FT_New_Memory_Face( library,
424                                                         pf->data,
425                                                         pf->size,
426                                                         0,
427                                                         &face );
428         if(err) {
429                 success = 0;
430                 //XXX error("This is not a valid font");
431         }
432         else {
433
434 #if 0
435                 for ( n = 0; n < face->num_charmaps; n++) {
436                         charmap = face->charmaps[n];
437                         if (charmap->platform_id == my_platform_id && charmap->encoding_id == my_encoding_id) {
438                                 found = charmap;
439                                 break;
440                         }
441                 }
442
443                 if (!found ) { return 0; }
444
445                 // now, select the charmap for the face object 
446                 err = FT_Set_Charmap( face, found );
447                 if ( err ) { return 0; }
448 #endif
449
450                 glyph_index = FT_Get_Char_Index( face, 'A' );
451                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
452                 if(err) success = 0;
453                 else {
454                         glyph = face->glyph;
455                         if (glyph->format == ft_glyph_format_outline ) {
456                                 success = 1;
457                         } else {
458                                 //XXX error("Selected Font has no outline data");
459                                 success = 0;
460                         }
461                 }
462         }
463         
464         return success;
465 }
466
467
468 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
469 {
470         VFontData *vfd= NULL;
471         int success = 0;
472
473         //init Freetype 
474         err = FT_Init_FreeType( &library);
475         if(err) {
476                 //XXX error("Failed to load the Freetype font library");
477                 return NULL;
478         }
479
480         success = check_freetypefont(pf);
481         
482         if (success) {
483                 vfd= objfnt_to_ftvfontdata(pf);
484         }
485
486         //free Freetype
487         FT_Done_FreeType( library);
488         
489         return vfd;
490 }
491
492 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
493 {
494         int success = FALSE;
495
496         if(!vfont) return FALSE;
497
498         // Init Freetype
499         err = FT_Init_FreeType(&library);
500         if(err) {
501                 //XXX error("Failed to load the Freetype font library");
502                 return 0;
503         }
504
505         // Load the character
506         success = objchr_to_ftvfontdata(vfont, character);
507         if(success == FALSE) return FALSE;
508
509         // Free Freetype
510         FT_Done_FreeType(library);
511
512         // Ahh everything ok
513         return TRUE;
514 }
515
516 #if 0
517
518 // Freetype2 Outline struct
519
520 typedef struct  FT_Outline_
521   {
522         short       n_contours;      /* number of contours in glyph        */
523         short       n_points;        /* number of points in the glyph      */
524
525         FT_Vector*  points;          /* the outline's points               */
526         char*       tags;            /* the points flags                   */
527         short*      contours;        /* the contour end points             */
528
529         int         flags;           /* outline masks                      */
530
531   } FT_Outline;
532
533 #endif
534
535 /***//*
536 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
537
538 Vectorial representation of Freetype glyphs
539
540 The source format of outlines is a collection of closed paths called "contours". Each contour is
541 made of a series of line segments and bezier arcs. Depending on the file format, these can be
542 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
543 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
544 Type1 format.
545
546 Each arc is described through a series of start, end and control points. Each point of the outline
547 has a specific tag which indicates wether it is used to describe a line segment or an arc.
548
549
550 The following rules are applied to decompose the contour's points into segments and arcs :
551
552 # two successive "on" points indicate a line segment joining them.
553
554 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
555   the control point, and the "on" ones the start and end points.
556
557 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
558   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
559   "off" point between two "on" points is forbidden, for example).
560
561 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
562   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
563   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
564   outlines are described in the TrueType specification.
565
566 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
567 font driver produces such outlines.
568
569                                                                   *            # on      
570                                                                                            * off
571                                                            __---__
572   #-__                      _--       -_
573           --__                _-            -
574                   --__           #               \
575                           --__                        #
576                                   -#
577                                                    Two "on" points
578    Two "on" points       and one "conic" point
579                                                         between them
580
581
582
583                                 *
584   #            __      Two "on" points with two "conic"
585    \          -  -     points between them. The point
586         \        /    \    marked '0' is the middle of the
587          -      0      \   "off" points, and is a 'virtual'
588           -_  _-       #   "on" point where the curve passes.
589                 --             It does not appear in the point
590                                            list.
591                 *
592
593
594
595
596                 *                # on
597                                    *     * off
598                  __---__
599           _--       -_
600         _-            -
601    #               \
602                                         #
603
604          Two "on" points
605    and two "cubic" point
606           between them
607
608
609 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
610 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
611 range from -16384 to 16383.
612
613 Convert conic to bezier arcs:
614 Conic P0 P1 P2
615 Bezier B0 B1 B2 B3
616 B0=P0
617 B1=(P0+2*P1)/3
618 B2=(P2+2*P1)/3
619 B3=P2
620
621 *//****/