2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19323...
[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->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.0;
197                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
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.0;
201                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
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.0 ;
211                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
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.0;
215                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
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.0;
232                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
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.0;
236                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
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.0 ;
246                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
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.0;
250                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
251                                                         bezt->h2= HD_VECT;
252                                                 }
253                                         }
254
255                                         // get the handles that are aligned, tricky...
256                                         // DistVL2Dfl, check if the three beztriple points are on one line
257                                         // VecLenf, see if there's a distance between the three points
258                                         // VecLenf again, to check the angle between the handles 
259                                         // finally, check if one of them is a vector handle 
260                                         if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
261                                                 (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
262                                                 (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
263                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
264                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(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 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         {
294                 err= FT_New_Memory_Face( library,
295                         tf->pf->data,
296                         tf->pf->size,
297                         0,
298                         &face);                 
299         }
300         else
301                 err= TRUE;
302                 
303         // Read the char
304         freetypechar_to_vchar(face, charcode, vfont->data);
305         
306         // And everything went ok
307         return TRUE;
308 }
309
310
311 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
312 {
313         // Variables
314         FT_Face face;
315         FT_ULong charcode = 0, lcode;
316         FT_UInt glyph_index;
317         const char *fontname;
318         VFontData *vfd;
319
320 /*
321         FT_CharMap  found = 0;
322         FT_CharMap  charmap;
323         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
324         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
325         int         n;
326 */
327
328         // load the freetype font
329         err = FT_New_Memory_Face( library,
330                                                 pf->data,
331                                                 pf->size,
332                                                 0,
333                                                 &face );
334
335         if(err) return NULL;
336 /*
337         for ( n = 0; n < face->num_charmaps; n++ )
338         {
339                 charmap = face->charmaps[n];
340                 if ( charmap->platform_id == my_platform_id &&
341                         charmap->encoding_id == my_encoding_id )
342                 {
343                         found = charmap;
344                         break;
345                 }
346         }
347
348         if ( !found ) { return NULL; }
349
350         // now, select the charmap for the face object
351         err = FT_Set_Charmap( face, found );
352         if ( err ) { return NULL; }
353 */
354
355         // allocate blender font
356         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
357
358         // get the name
359         fontname = FT_Get_Postscript_Name(face);
360         strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
361
362         // Extract the first 256 character from TTF
363         lcode= charcode= FT_Get_First_Char(face, &glyph_index);
364
365         // No charmap found from the ttf so we need to figure it out
366         if(glyph_index == 0)
367         {
368                 FT_CharMap  found = 0;
369                 FT_CharMap  charmap;
370                 int n;
371
372                 for ( n = 0; n < face->num_charmaps; n++ )
373                 {
374                         charmap = face->charmaps[n];
375                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
376                         {
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 /*
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 */
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                 for ( n = 0; n < face->num_charmaps; n++ )
435                 {
436                   charmap = face->charmaps[n];
437                   if ( charmap->platform_id == my_platform_id &&
438                            charmap->encoding_id == my_encoding_id )
439                   {
440                         found = charmap;
441                         break;
442                   }
443                 }
444
445                 if ( !found ) { return 0; }
446
447                 // now, select the charmap for the face object 
448                 err = FT_Set_Charmap( face, found );
449                 if ( err ) { return 0; }
450 */
451                 glyph_index = FT_Get_Char_Index( face, 'A' );
452                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
453                 if(err) success = 0;
454                 else {
455                         glyph = face->glyph;
456                         if (glyph->format == ft_glyph_format_outline ) {
457                                 success = 1;
458                         } else {
459                                 //XXX error("Selected Font has no outline data");
460                                 success = 0;
461                         }
462                 }
463         }
464         
465         return success;
466 }
467
468
469 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
470 {
471         VFontData *vfd= NULL;
472         int success = 0;
473
474         //init Freetype 
475         err = FT_Init_FreeType( &library);
476         if(err) {
477                 //XXX error("Failed to load the Freetype font library");
478                 return 0;
479         }
480
481         success = check_freetypefont(pf);
482         
483         if (success) {
484                 vfd= objfnt_to_ftvfontdata(pf);
485         }
486
487         //free Freetype
488         FT_Done_FreeType( library);
489         
490         return vfd;
491 }
492
493 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
494 {
495         int success = FALSE;
496
497         if(!vfont) return FALSE;
498
499         // Init Freetype
500         err = FT_Init_FreeType(&library);
501         if(err) {
502                 //XXX error("Failed to load the Freetype font library");
503                 return 0;
504         }
505
506         // Load the character
507         success = objchr_to_ftvfontdata(vfont, character);
508         if(success == FALSE) return FALSE;
509
510         // Free Freetype
511         FT_Done_FreeType(library);
512
513         // Ahh everything ok
514         return TRUE;
515 }
516
517 #endif // WITH_FREETYPE2
518
519
520
521 #if 0
522
523 // Freetype2 Outline struct
524
525 typedef struct  FT_Outline_
526   {
527     short       n_contours;      /* number of contours in glyph        */
528     short       n_points;        /* number of points in the glyph      */
529
530     FT_Vector*  points;          /* the outline's points               */
531     char*       tags;            /* the points flags                   */
532     short*      contours;        /* the contour end points             */
533
534     int         flags;           /* outline masks                      */
535
536   } FT_Outline;
537
538 #endif
539
540 /***//*
541 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
542
543 Vectorial representation of Freetype glyphs
544
545 The source format of outlines is a collection of closed paths called "contours". Each contour is
546 made of a series of line segments and bezier arcs. Depending on the file format, these can be
547 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
548 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
549 Type1 format.
550
551 Each arc is described through a series of start, end and control points. Each point of the outline
552 has a specific tag which indicates wether it is used to describe a line segment or an arc.
553
554
555 The following rules are applied to decompose the contour's points into segments and arcs :
556
557 # two successive "on" points indicate a line segment joining them.
558
559 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
560   the control point, and the "on" ones the start and end points.
561
562 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
563   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
564   "off" point between two "on" points is forbidden, for example).
565
566 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
567   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
568   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
569   outlines are described in the TrueType specification.
570
571 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
572 font driver produces such outlines.
573
574                                   *            # on      
575                                                * off
576                                __---__
577   #-__                      _--       -_
578       --__                _-            -
579           --__           #               \
580               --__                        #
581                   -#
582                            Two "on" points
583    Two "on" points       and one "conic" point
584                             between them
585
586
587
588                 *
589   #            __      Two "on" points with two "conic"
590    \          -  -     points between them. The point
591     \        /    \    marked '0' is the middle of the
592      -      0      \   "off" points, and is a 'virtual'
593       -_  _-       #   "on" point where the curve passes.
594         --             It does not appear in the point
595                        list.
596         *
597
598
599
600
601         *                # on
602                    *     * off
603          __---__
604       _--       -_
605     _-            -
606    #               \
607                     #
608
609      Two "on" points
610    and two "cubic" point
611       between them
612
613
614 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
615 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
616 range from -16384 to 16383.
617
618 Convert conic to bezier arcs:
619 Conic P0 P1 P2
620 Bezier B0 B1 B2 B3
621 B0=P0
622 B1=(P0+2*P1)/3
623 B2=(P2+2*P1)/3
624 B3=P2
625
626 *//****/