The regular warning fix update; includes two variables that were used
[blender.git] / source / blender / blenlib / intern / freetypefont.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is written by Rob Haarsma (phase)
24  * All rights reserved.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL/BL DUAL LICENSE BLOCK *****
29  *
30  * This code parses the Freetype font outline data to chains of Blender's beziertriples.
31  * Additional information can be found at the bottom of this file.
32  *
33  * Code that uses exotic character maps is present but commented out.
34  */
35
36 #ifdef WITH_FREETYPE2
37
38 #ifdef WIN32
39 #pragma warning (disable:4244)
40 #endif
41
42 #include <ft2build.h>
43 #include FT_FREETYPE_H
44 #include FT_GLYPH_H
45 #include FT_BBOX_H
46 #include FT_SIZES_H
47 #include <freetype/ttnameid.h>
48
49 #include "MEM_guardedalloc.h"
50
51 #include "BLI_vfontdata.h"
52 #include "BLI_blenlib.h"
53 #include "BLI_arithb.h"  
54
55 #include "BIF_toolbox.h"
56
57 #include "BKE_global.h"
58 #include "BKE_utildefines.h"
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 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.0)
90                 scale = 1.0 / height;
91         else
92                 scale = 1.0 / 1000.0;
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                         l = 0;
134                         for(k = 0; k < npoints[j]; k++) {
135                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
136                                         if(ftoutline.tags[l] == FT_Curve_Tag_On)
137                                                 onpoints[j]++;
138
139                                 if(k < npoints[j] - 1 )
140                                         if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
141                                                 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
142                                                 onpoints[j]++;
143                         }
144                 }
145
146                 //contour loop, bezier & conic styles merged
147                 for(j = 0; j < ftoutline.n_contours; j++) {
148                         // add new curve
149                         nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
150                         bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
151                         BLI_addtail(&che->nurbsbase, nu);
152
153                         nu->type= CU_BEZIER+CU_2D;
154                         nu->pntsu = onpoints[j];
155                         nu->resolu= 8;
156                         nu->flagu= 1;
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.0;
169                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
170
171                                                 //left handle
172                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
173                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
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.0;
181                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
182
183                                                 bezt->h1= bezt->h2= HD_ALIGN;
184                                                 bezt++;
185                                         }
186                                 }
187
188                                 //on-curve points
189                                 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
190                                         //left handle
191                                         if(k > 0) {
192                                                 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
193                                                         bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
194                                                         bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
195                                                         bezt->h1= HD_FREE;
196                                                 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
197                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
198                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
199                                                         bezt->h1= HD_FREE;
200                                                 } else {
201                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
202                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
203                                                         bezt->h1= HD_VECT;
204                                                 }
205                                         } else { //first point on curve
206                                                 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
207                                                         bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
208                                                         bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
209                                                         bezt->h1= HD_FREE;
210                                                 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
211                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
212                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
213                                                         bezt->h1= HD_FREE;
214                                                 } else {
215                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
216                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
217                                                         bezt->h1= HD_VECT;
218                                                 }
219                                         }
220
221                                         //midpoint (on-curve point)
222                                         bezt->vec[1][0] = ftoutline.points[l].x* scale;
223                                         bezt->vec[1][1] = ftoutline.points[l].y* scale;
224
225                                         //right handle
226                                         if(k < (npoints[j] - 1)) {
227                                                 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
228                                                         bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
229                                                         bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
230                                                         bezt->h2= HD_FREE;
231                                                 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
232                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
233                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
234                                                         bezt->h2= HD_FREE;
235                                                 } else {
236                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
237                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
238                                                         bezt->h2= HD_VECT;
239                                                 }
240                                         } else { //last point on curve
241                                                 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
242                                                         bezt->vec[2][0] = ftoutline.points[m].x* scale;
243                                                         bezt->vec[2][1] = ftoutline.points[m].y* scale;
244                                                         bezt->h2= HD_FREE;
245                                                 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
246                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
247                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
248                                                         bezt->h2= HD_FREE;
249                                                 } else {
250                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
251                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
252                                                         bezt->h2= HD_VECT;
253                                                 }
254                                         }
255
256                                         // get the handles that are aligned, tricky...
257                                         // DistVL2Dfl, check if the three beztriple points are on one line
258                                         // VecLenf, see if there's a distance between the three points
259                                         // VecLenf again, to check the angle between the handles 
260                                         // finally, check if one of them is a vector handle 
261                                         if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
262                                                 (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
263                                                 (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
264                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
265                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
266                                                 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
267                                         {
268                                                 bezt->h1= bezt->h2= HD_ALIGN;
269                                         }
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= G.ttfdata.first;
287         while(tf)
288         {
289                 if(tf->vfont == vfont)
290                         break;
291                 tf= tf->next;           
292         }
293         
294         // What, no font found. Something strange here
295         if(!tf) return FALSE;
296         
297         // Load the font to memory
298         if(tf->pf)
299         {
300                 err= FT_New_Memory_Face( library,
301                         tf->pf->data,
302                         tf->pf->size,
303                         0,
304                         &face);                 
305         }
306         else
307                 err= TRUE;
308                 
309         // Read the char
310         freetypechar_to_vchar(face, charcode, vfont->data);
311         
312         // And everything went ok
313         return TRUE;
314 }
315
316
317 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
318 {
319         // Variables
320         FT_Face face;
321         FT_ULong charcode = 0, lcode;
322         FT_UInt glyph_index;
323         const char *fontname;
324         VFontData *vfd;
325
326 /*
327         FT_CharMap  found = 0;
328         FT_CharMap  charmap;
329         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
330         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
331         int         n;
332 */
333
334         // load the freetype font
335         err = FT_New_Memory_Face( library,
336                                                 pf->data,
337                                                 pf->size,
338                                                 0,
339                                                 &face );
340
341         if(err) return NULL;
342 /*
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 */
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         strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
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 = 0;
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         err = FT_Set_Charmap( face, (FT_CharMap) FT_ENCODING_UNICODE );
412
413         return vfd;     
414 }
415
416
417 static int check_freetypefont(PackedFile * pf)
418 {
419         FT_Face                 face;
420         FT_GlyphSlot    glyph;
421         FT_UInt                 glyph_index;
422 /*
423         FT_CharMap  charmap;
424         FT_CharMap  found;
425         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
426         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
427         int         n;
428 */
429         int success = 0;
430
431         err = FT_New_Memory_Face( library,
432                                                         pf->data,
433                                                         pf->size,
434                                                         0,
435                                                         &face );
436         if(err) {
437                 success = 0;
438             error("This is not a valid font");
439         }
440         else {
441 /*
442                 for ( n = 0; n < face->num_charmaps; n++ )
443                 {
444                   charmap = face->charmaps[n];
445                   if ( charmap->platform_id == my_platform_id &&
446                            charmap->encoding_id == my_encoding_id )
447                   {
448                         found = charmap;
449                         break;
450                   }
451                 }
452
453                 if ( !found ) { return 0; }
454
455                 // now, select the charmap for the face object 
456                 err = FT_Set_Charmap( face, found );
457                 if ( err ) { return 0; }
458 */
459                 glyph_index = FT_Get_Char_Index( face, 'A' );
460                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
461                 if(err) success = 0;
462                 else {
463                         glyph = face->glyph;
464                         if (glyph->format == ft_glyph_format_outline ) {
465                                 success = 1;
466                         } else {
467                                 error("Selected Font has no outline data");
468                                 success = 0;
469                         }
470                 }
471         }
472         
473         return success;
474 }
475
476
477 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
478 {
479         VFontData *vfd= NULL;
480         int success = 0;
481
482         //init Freetype 
483         err = FT_Init_FreeType( &library);
484         if(err) {
485                 error("Failed to load the Freetype font library");
486                 return 0;
487         }
488
489         success = check_freetypefont(pf);
490         
491         if (success) {
492                 vfd= objfnt_to_ftvfontdata(pf);
493         }
494
495         //free Freetype
496         FT_Done_FreeType( library);
497         
498         return vfd;
499 }
500
501 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
502 {
503         int success = FALSE;
504
505         if(!vfont) return FALSE;
506
507         // Init Freetype
508         err = FT_Init_FreeType(&library);
509         if(err) {
510                 error("Failed to load the Freetype font library");
511                 return 0;
512         }
513
514         // Load the character
515         success = objchr_to_ftvfontdata(vfont, character);
516         if(success == FALSE) return FALSE;
517
518         // Free Freetype
519         FT_Done_FreeType(library);
520
521         // Ahh everything ok
522         return TRUE;
523 }
524
525 #endif // WITH_FREETYPE2
526
527
528
529 #if 0
530
531 // Freetype2 Outline struct
532
533 typedef struct  FT_Outline_
534   {
535     short       n_contours;      /* number of contours in glyph        */
536     short       n_points;        /* number of points in the glyph      */
537
538     FT_Vector*  points;          /* the outline's points               */
539     char*       tags;            /* the points flags                   */
540     short*      contours;        /* the contour end points             */
541
542     int         flags;           /* outline masks                      */
543
544   } FT_Outline;
545
546 #endif
547
548 /***//*
549 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
550
551 Vectorial representation of Freetype glyphs
552
553 The source format of outlines is a collection of closed paths called "contours". Each contour is
554 made of a series of line segments and bezier arcs. Depending on the file format, these can be
555 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
556 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
557 Type1 format.
558
559 Each arc is described through a series of start, end and control points. Each point of the outline
560 has a specific tag which indicates wether it is used to describe a line segment or an arc.
561
562
563 The following rules are applied to decompose the contour's points into segments and arcs :
564
565 # two successive "on" points indicate a line segment joining them.
566
567 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
568   the control point, and the "on" ones the start and end points.
569
570 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
571   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
572   "off" point between two "on" points is forbidden, for example).
573
574 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
575   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
576   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
577   outlines are described in the TrueType specification.
578
579 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
580 font driver produces such outlines.
581
582                                   *            # on      
583                                                * off
584                                __---__
585   #-__                      _--       -_
586       --__                _-            -
587           --__           #               \
588               --__                        #
589                   -#
590                            Two "on" points
591    Two "on" points       and one "conic" point
592                             between them
593
594
595
596                 *
597   #            __      Two "on" points with two "conic"
598    \          -  -     points between them. The point
599     \        /    \    marked '0' is the middle of the
600      -      0      \   "off" points, and is a 'virtual'
601       -_  _-       #   "on" point where the curve passes.
602         --             It does not appear in the point
603                        list.
604         *
605
606
607
608
609         *                # on
610                    *     * off
611          __---__
612       _--       -_
613     _-            -
614    #               \
615                     #
616
617      Two "on" points
618    and two "cubic" point
619       between them
620
621
622 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
623 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
624 range from -16384 to 16383.
625
626 Convert conic to bezier arcs:
627 Conic P0 P1 P2
628 Bezier B0 B1 B2 B3
629 B0=P0
630 B1=(P0+2*P1)/3
631 B2=(P2+2*P1)/3
632 B3=P2
633
634 *//****/