[#18439] Controlling the bevel shape for a text object with a curve no longer works.
[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 #include "BIF_toolbox.h"
53
54 #include "BKE_global.h"
55 #include "BKE_utildefines.h"
56
57 #include "DNA_vfont_types.h"
58 #include "DNA_packedFile_types.h"
59 #include "DNA_curve_types.h"
60
61 #define myMIN_ASCII     32
62 #define myMAX_ASCII     255
63
64 /* local variables */
65 static FT_Library       library;
66 static FT_Error         err;
67
68
69 void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
70 {
71         // Blender
72         struct Nurb *nu;
73         struct VChar *che;
74         struct BezTriple *bezt;
75         
76         // Freetype2
77         FT_GlyphSlot glyph;
78         FT_UInt glyph_index;
79         FT_Outline ftoutline;
80         float scale, height;
81         float dx, dy;
82         int j,k,l,m=0;
83         
84         // adjust font size
85         height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
86         if(height != 0.0)
87                 scale = 1.0 / height;
88         else
89                 scale = 1.0 / 1000.0;
90         
91         //      
92         // Generate the character 3D data
93         //
94         // Get the FT Glyph index and load the Glyph
95         glyph_index= FT_Get_Char_Index(face, charcode);
96         err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
97         
98         // If loading succeeded, convert the FT glyph to the internal format
99         if(!err)
100         {
101                 int *npoints;
102                 int *onpoints;
103                 
104                 // First we create entry for the new character to the character list
105                 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
106                 BLI_addtail(&vfd->characters, che);
107                 
108                 // Take some data for modifying purposes
109                 glyph= face->glyph;
110                 ftoutline= glyph->outline;
111                 
112                 // Set the width and character code
113                 che->index= charcode;
114                 che->width= glyph->advance.x * scale;
115                 
116                 // Start converting the FT data
117                 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
118                 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
119
120                 // calculate total points of each contour
121                 for(j = 0; j < ftoutline.n_contours; j++) {
122                         if(j == 0)
123                                 npoints[j] = ftoutline.contours[j] + 1;
124                         else
125                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
126                 }
127
128                 // get number of on-curve points for beziertriples (including conic virtual on-points) 
129                 for(j = 0; j < ftoutline.n_contours; j++) {
130                         l = 0;
131                         for(k = 0; k < npoints[j]; k++) {
132                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
133                                         if(ftoutline.tags[l] == FT_Curve_Tag_On)
134                                                 onpoints[j]++;
135
136                                 if(k < npoints[j] - 1 )
137                                         if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
138                                                 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
139                                                 onpoints[j]++;
140                         }
141                 }
142
143                 //contour loop, bezier & conic styles merged
144                 for(j = 0; j < ftoutline.n_contours; j++) {
145                         // add new curve
146                         nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
147                         bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
148                         BLI_addtail(&che->nurbsbase, nu);
149
150                         nu->type= CU_BEZIER+CU_2D;
151                         nu->pntsu = onpoints[j];
152                         nu->resolu= 8;
153                         nu->flagu= CU_CYCLIC;
154                         nu->bezt = bezt;
155
156                         //individual curve loop, start-end
157                         for(k = 0; k < npoints[j]; k++) {
158                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
159                                 if(k == 0) m = l;
160                                         
161                                 //virtual conic on-curve points
162                                 if(k < npoints[j] - 1 )
163                                 {
164                                         if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
165                                                 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
166                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
167
168                                                 //left handle
169                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
170                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
171
172                                                 //midpoint (virtual on-curve point)
173                                                 bezt->vec[1][0] = dx;
174                                                 bezt->vec[1][1] = dy;
175
176                                                 //right handle
177                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
178                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
179
180                                                 bezt->h1= bezt->h2= HD_ALIGN;
181                                                 bezt->radius= 1.0f;
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->radius= 1.0f;
269                                         bezt++;
270                                 }
271                         }
272                 }
273                 if(npoints) MEM_freeN(npoints);
274                 if(onpoints) MEM_freeN(onpoints);       
275         }
276 }
277
278 int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
279 {
280         // Freetype2
281         FT_Face face;
282         struct TmpFont *tf;
283         
284         // Find the correct FreeType font
285         tf= G.ttfdata.first;
286         while(tf)
287         {
288                 if(tf->vfont == vfont)
289                         break;
290                 tf= tf->next;           
291         }
292         
293         // What, no font found. Something strange here
294         if(!tf) return FALSE;
295         
296         // Load the font to memory
297         if(tf->pf)
298         {
299                 err= FT_New_Memory_Face( library,
300                         tf->pf->data,
301                         tf->pf->size,
302                         0,
303                         &face);                 
304         }
305         else
306                 err= TRUE;
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 /*
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 */
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         for ( n = 0; n < face->num_charmaps; n++ )
343         {
344                 charmap = face->charmaps[n];
345                 if ( charmap->platform_id == my_platform_id &&
346                         charmap->encoding_id == my_encoding_id )
347                 {
348                         found = charmap;
349                         break;
350                 }
351         }
352
353         if ( !found ) { return NULL; }
354
355         // now, select the charmap for the face object
356         err = FT_Set_Charmap( face, found );
357         if ( err ) { return NULL; }
358 */
359
360         // allocate blender font
361         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
362
363         // get the name
364         fontname = FT_Get_Postscript_Name(face);
365         strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
366
367         // Extract the first 256 character from TTF
368         lcode= charcode= FT_Get_First_Char(face, &glyph_index);
369
370         // No charmap found from the ttf so we need to figure it out
371         if(glyph_index == 0)
372         {
373                 FT_CharMap  found = 0;
374                 FT_CharMap  charmap;
375                 int n;
376
377                 for ( n = 0; n < face->num_charmaps; n++ )
378                 {
379                         charmap = face->charmaps[n];
380                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
381                         {
382                                 found = charmap;
383                                 break;
384                         }
385                 }
386
387                 err = FT_Set_Charmap( face, found );
388
389                 if( err ) 
390                         return NULL;
391
392                 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
393         }
394
395         // Load characters
396         while(charcode < 256)
397         {
398                 // Generate the font data
399                 freetypechar_to_vchar(face, charcode, vfd);
400
401                 // Next glyph
402                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
403
404                 // Check that we won't start infinite loop
405                 if(charcode <= lcode)
406                         break;
407                 lcode = charcode;
408         }
409
410         return vfd;     
411 }
412
413
414 static int check_freetypefont(PackedFile * pf)
415 {
416         FT_Face                 face;
417         FT_GlyphSlot    glyph;
418         FT_UInt                 glyph_index;
419 /*
420         FT_CharMap  charmap;
421         FT_CharMap  found;
422         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
423         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
424         int         n;
425 */
426         int success = 0;
427
428         err = FT_New_Memory_Face( library,
429                                                         pf->data,
430                                                         pf->size,
431                                                         0,
432                                                         &face );
433         if(err) {
434                 success = 0;
435             error("This is not a valid font");
436         }
437         else {
438 /*
439                 for ( n = 0; n < face->num_charmaps; n++ )
440                 {
441                   charmap = face->charmaps[n];
442                   if ( charmap->platform_id == my_platform_id &&
443                            charmap->encoding_id == my_encoding_id )
444                   {
445                         found = charmap;
446                         break;
447                   }
448                 }
449
450                 if ( !found ) { return 0; }
451
452                 // now, select the charmap for the face object 
453                 err = FT_Set_Charmap( face, found );
454                 if ( err ) { return 0; }
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                                 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                 error("Failed to load the Freetype font library");
483                 return 0;
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                 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 #endif // WITH_FREETYPE2
523
524
525
526 #if 0
527
528 // Freetype2 Outline struct
529
530 typedef struct  FT_Outline_
531   {
532     short       n_contours;      /* number of contours in glyph        */
533     short       n_points;        /* number of points in the glyph      */
534
535     FT_Vector*  points;          /* the outline's points               */
536     char*       tags;            /* the points flags                   */
537     short*      contours;        /* the contour end points             */
538
539     int         flags;           /* outline masks                      */
540
541   } FT_Outline;
542
543 #endif
544
545 /***//*
546 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
547
548 Vectorial representation of Freetype glyphs
549
550 The source format of outlines is a collection of closed paths called "contours". Each contour is
551 made of a series of line segments and bezier arcs. Depending on the file format, these can be
552 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
553 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
554 Type1 format.
555
556 Each arc is described through a series of start, end and control points. Each point of the outline
557 has a specific tag which indicates wether it is used to describe a line segment or an arc.
558
559
560 The following rules are applied to decompose the contour's points into segments and arcs :
561
562 # two successive "on" points indicate a line segment joining them.
563
564 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
565   the control point, and the "on" ones the start and end points.
566
567 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
568   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
569   "off" point between two "on" points is forbidden, for example).
570
571 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
572   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
573   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
574   outlines are described in the TrueType specification.
575
576 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
577 font driver produces such outlines.
578
579                                   *            # on      
580                                                * off
581                                __---__
582   #-__                      _--       -_
583       --__                _-            -
584           --__           #               \
585               --__                        #
586                   -#
587                            Two "on" points
588    Two "on" points       and one "conic" point
589                             between them
590
591
592
593                 *
594   #            __      Two "on" points with two "conic"
595    \          -  -     points between them. The point
596     \        /    \    marked '0' is the middle of the
597      -      0      \   "off" points, and is a 'virtual'
598       -_  _-       #   "on" point where the curve passes.
599         --             It does not appear in the point
600                        list.
601         *
602
603
604
605
606         *                # on
607                    *     * off
608          __---__
609       _--       -_
610     _-            -
611    #               \
612                     #
613
614      Two "on" points
615    and two "cubic" point
616       between them
617
618
619 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
620 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
621 range from -16384 to 16383.
622
623 Convert conic to bezier arcs:
624 Conic P0 P1 P2
625 Bezier B0 B1 B2 B3
626 B0=P0
627 B1=(P0+2*P1)/3
628 B2=(P2+2*P1)/3
629 B3=P2
630
631 *//****/