2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17434...
[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 //XXX #include "BIF_toolbox.h"
53
54 #include "BKE_global.h"
55 #include "BKE_font.h"
56 #include "BKE_utildefines.h"
57
58 #include "DNA_vfont_types.h"
59 #include "DNA_packedFile_types.h"
60 #include "DNA_curve_types.h"
61
62 #define myMIN_ASCII     32
63 #define myMAX_ASCII     255
64
65 /* local variables */
66 static FT_Library       library;
67 static FT_Error         err;
68
69
70 void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
71 {
72         // Blender
73         struct Nurb *nu;
74         struct VChar *che;
75         struct BezTriple *bezt;
76         
77         // Freetype2
78         FT_GlyphSlot glyph;
79         FT_UInt glyph_index;
80         FT_Outline ftoutline;
81         float scale, height;
82         float dx, dy;
83         int j,k,l,m=0;
84         
85         // adjust font size
86         height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
87         if(height != 0.0)
88                 scale = 1.0 / height;
89         else
90                 scale = 1.0 / 1000.0;
91         
92         //      
93         // Generate the character 3D data
94         //
95         // Get the FT Glyph index and load the Glyph
96         glyph_index= FT_Get_Char_Index(face, charcode);
97         err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
98         
99         // If loading succeeded, convert the FT glyph to the internal format
100         if(!err)
101         {
102                 int *npoints;
103                 int *onpoints;
104                 
105                 // First we create entry for the new character to the character list
106                 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
107                 BLI_addtail(&vfd->characters, che);
108                 
109                 // Take some data for modifying purposes
110                 glyph= face->glyph;
111                 ftoutline= glyph->outline;
112                 
113                 // Set the width and character code
114                 che->index= charcode;
115                 che->width= glyph->advance.x * scale;
116                 
117                 // Start converting the FT data
118                 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
119                 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
120
121                 // calculate total points of each contour
122                 for(j = 0; j < ftoutline.n_contours; j++) {
123                         if(j == 0)
124                                 npoints[j] = ftoutline.contours[j] + 1;
125                         else
126                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
127                 }
128
129                 // get number of on-curve points for beziertriples (including conic virtual on-points) 
130                 for(j = 0; j < ftoutline.n_contours; j++) {
131                         l = 0;
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+CU_2D;
152                         nu->pntsu = onpoints[j];
153                         nu->resolu= 8;
154                         nu->flagu= CU_CYCLIC;
155                         nu->bezt = bezt;
156
157                         //individual curve loop, start-end
158                         for(k = 0; k < npoints[j]; k++) {
159                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
160                                 if(k == 0) m = l;
161                                         
162                                 //virtual conic on-curve points
163                                 if(k < npoints[j] - 1 )
164                                 {
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.0;
167                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
168
169                                                 //left handle
170                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
171                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
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.0;
179                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
180
181                                                 bezt->h1= bezt->h2= HD_ALIGN;
182                                                 bezt++;
183                                         }
184                                 }
185
186                                 //on-curve points
187                                 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
188                                         //left handle
189                                         if(k > 0) {
190                                                 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
191                                                         bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
192                                                         bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
193                                                         bezt->h1= HD_FREE;
194                                                 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
195                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
196                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
197                                                         bezt->h1= HD_FREE;
198                                                 } else {
199                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
200                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
201                                                         bezt->h1= HD_VECT;
202                                                 }
203                                         } else { //first point on curve
204                                                 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
205                                                         bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
206                                                         bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
207                                                         bezt->h1= HD_FREE;
208                                                 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
209                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
210                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
211                                                         bezt->h1= HD_FREE;
212                                                 } else {
213                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
214                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
215                                                         bezt->h1= HD_VECT;
216                                                 }
217                                         }
218
219                                         //midpoint (on-curve point)
220                                         bezt->vec[1][0] = ftoutline.points[l].x* scale;
221                                         bezt->vec[1][1] = ftoutline.points[l].y* scale;
222
223                                         //right handle
224                                         if(k < (npoints[j] - 1)) {
225                                                 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
226                                                         bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
227                                                         bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
228                                                         bezt->h2= HD_FREE;
229                                                 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
230                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
231                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
232                                                         bezt->h2= HD_FREE;
233                                                 } else {
234                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
235                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
236                                                         bezt->h2= HD_VECT;
237                                                 }
238                                         } else { //last point on curve
239                                                 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
240                                                         bezt->vec[2][0] = ftoutline.points[m].x* scale;
241                                                         bezt->vec[2][1] = ftoutline.points[m].y* scale;
242                                                         bezt->h2= HD_FREE;
243                                                 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
244                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
245                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
246                                                         bezt->h2= HD_FREE;
247                                                 } else {
248                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
249                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
250                                                         bezt->h2= HD_VECT;
251                                                 }
252                                         }
253
254                                         // get the handles that are aligned, tricky...
255                                         // DistVL2Dfl, check if the three beztriple points are on one line
256                                         // VecLenf, see if there's a distance between the three points
257                                         // VecLenf again, to check the angle between the handles 
258                                         // finally, check if one of them is a vector handle 
259                                         if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
260                                                 (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
261                                                 (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
262                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
263                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
264                                                 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
265                                         {
266                                                 bezt->h1= bezt->h2= HD_ALIGN;
267                                         }
268                                         bezt++;
269                                 }
270                         }
271                 }
272                 if(npoints) MEM_freeN(npoints);
273                 if(onpoints) MEM_freeN(onpoints);       
274         }
275 }
276
277 int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
278 {
279         // Freetype2
280         FT_Face face;
281         struct TmpFont *tf;
282         
283         // Find the correct FreeType font
284         tf= vfont_find_tmpfont(vfont);
285         
286         // What, no font found. Something strange here
287         if(!tf) return FALSE;
288         
289         // Load the font to memory
290         if(tf->pf)
291         {
292                 err= FT_New_Memory_Face( library,
293                         tf->pf->data,
294                         tf->pf->size,
295                         0,
296                         &face);                 
297         }
298         else
299                 err= TRUE;
300                 
301         // Read the char
302         freetypechar_to_vchar(face, charcode, vfont->data);
303         
304         // And everything went ok
305         return TRUE;
306 }
307
308
309 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
310 {
311         // Variables
312         FT_Face face;
313         FT_ULong charcode = 0, lcode;
314         FT_UInt glyph_index;
315         const char *fontname;
316         VFontData *vfd;
317
318 /*
319         FT_CharMap  found = 0;
320         FT_CharMap  charmap;
321         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
322         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
323         int         n;
324 */
325
326         // load the freetype font
327         err = FT_New_Memory_Face( library,
328                                                 pf->data,
329                                                 pf->size,
330                                                 0,
331                                                 &face );
332
333         if(err) return NULL;
334 /*
335         for ( n = 0; n < face->num_charmaps; n++ )
336         {
337                 charmap = face->charmaps[n];
338                 if ( charmap->platform_id == my_platform_id &&
339                         charmap->encoding_id == my_encoding_id )
340                 {
341                         found = charmap;
342                         break;
343                 }
344         }
345
346         if ( !found ) { return NULL; }
347
348         // now, select the charmap for the face object
349         err = FT_Set_Charmap( face, found );
350         if ( err ) { return NULL; }
351 */
352
353         // allocate blender font
354         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
355
356         // get the name
357         fontname = FT_Get_Postscript_Name(face);
358         strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
359
360         // Extract the first 256 character from TTF
361         lcode= charcode= FT_Get_First_Char(face, &glyph_index);
362
363         // No charmap found from the ttf so we need to figure it out
364         if(glyph_index == 0)
365         {
366                 FT_CharMap  found = 0;
367                 FT_CharMap  charmap;
368                 int n;
369
370                 for ( n = 0; n < face->num_charmaps; n++ )
371                 {
372                         charmap = face->charmaps[n];
373                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
374                         {
375                                 found = charmap;
376                                 break;
377                         }
378                 }
379
380                 err = FT_Set_Charmap( face, found );
381
382                 if( err ) 
383                         return NULL;
384
385                 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
386         }
387
388         // Load characters
389         while(charcode < 256)
390         {
391                 // Generate the font data
392                 freetypechar_to_vchar(face, charcode, vfd);
393
394                 // Next glyph
395                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
396
397                 // Check that we won't start infinite loop
398                 if(charcode <= lcode)
399                         break;
400                 lcode = charcode;
401         }
402
403         return vfd;     
404 }
405
406
407 static int check_freetypefont(PackedFile * pf)
408 {
409         FT_Face                 face;
410         FT_GlyphSlot    glyph;
411         FT_UInt                 glyph_index;
412 /*
413         FT_CharMap  charmap;
414         FT_CharMap  found;
415         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
416         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
417         int         n;
418 */
419         int success = 0;
420
421         err = FT_New_Memory_Face( library,
422                                                         pf->data,
423                                                         pf->size,
424                                                         0,
425                                                         &face );
426         if(err) {
427                 success = 0;
428             //XXX error("This is not a valid font");
429         }
430         else {
431 /*
432                 for ( n = 0; n < face->num_charmaps; n++ )
433                 {
434                   charmap = face->charmaps[n];
435                   if ( charmap->platform_id == my_platform_id &&
436                            charmap->encoding_id == my_encoding_id )
437                   {
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 */
449                 glyph_index = FT_Get_Char_Index( face, 'A' );
450                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
451                 if(err) success = 0;
452                 else {
453                         glyph = face->glyph;
454                         if (glyph->format == ft_glyph_format_outline ) {
455                                 success = 1;
456                         } else {
457                                 //XXX error("Selected Font has no outline data");
458                                 success = 0;
459                         }
460                 }
461         }
462         
463         return success;
464 }
465
466
467 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
468 {
469         VFontData *vfd= NULL;
470         int success = 0;
471
472         //init Freetype 
473         err = FT_Init_FreeType( &library);
474         if(err) {
475                 //XXX error("Failed to load the Freetype font library");
476                 return 0;
477         }
478
479         success = check_freetypefont(pf);
480         
481         if (success) {
482                 vfd= objfnt_to_ftvfontdata(pf);
483         }
484
485         //free Freetype
486         FT_Done_FreeType( library);
487         
488         return vfd;
489 }
490
491 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
492 {
493         int success = FALSE;
494
495         if(!vfont) return FALSE;
496
497         // Init Freetype
498         err = FT_Init_FreeType(&library);
499         if(err) {
500                 //XXX error("Failed to load the Freetype font library");
501                 return 0;
502         }
503
504         // Load the character
505         success = objchr_to_ftvfontdata(vfont, character);
506         if(success == FALSE) return FALSE;
507
508         // Free Freetype
509         FT_Done_FreeType(library);
510
511         // Ahh everything ok
512         return TRUE;
513 }
514
515 #endif // WITH_FREETYPE2
516
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 *//****/