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