reverted to previous version, changes weren't meant for a commit.
[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  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 #ifdef WITH_FREETYPE2
33
34 #ifdef WIN32
35 #pragma warning (disable:4244)
36 #endif
37
38 #include <ft2build.h>
39 #include FT_FREETYPE_H
40 #include FT_GLYPH_H
41 #include <freetype/ttnameid.h>
42
43 #include "MEM_guardedalloc.h"
44
45 #include "BLI_vfontdata.h"
46 #include "BLI_blenlib.h"
47 #include "BLI_arithb.h"  
48
49 #include "BIF_toolbox.h"
50
51 #include "DNA_packedFile_types.h"
52 #include "DNA_curve_types.h"
53
54 #define myMIN_ASCII     32
55 #define myMAX_ASCII     126
56
57 // should come from arithb.c
58 #define MIN2(x,y)               ( (x)<(y) ? (x) : (y) )
59 #define MAX2(x,y)               ( (x)>(y) ? (x) : (y) )
60
61 /* local variables */
62 static FT_Library       library;
63 static FT_Error         err;
64
65 #if 0
66 // Freetype2 Outline struct
67
68 typedef struct  FT_Outline_
69   {
70     short       n_contours;      /* number of contours in glyph        */
71     short       n_points;        /* number of points in the glyph      */
72
73     FT_Vector*  points;          /* the outline's points               */
74     char*       tags;            /* the points flags                   */
75     short*      contours;        /* the contour end points             */
76
77     int         flags;           /* outline masks                      */
78
79   } FT_Outline;
80 #endif
81
82 /***//*
83 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
84
85 Vectorial representation of Freetype glyphs
86
87 The source format of outlines is a collection of closed paths called "contours". Each contour is
88 made of a series of line segments and bezier arcs. Depending on the file format, these can be
89 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
90 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
91 Type1 format.
92
93 Each arc is described through a series of start, end and control points. Each point of the outline
94 has a specific tag which indicates wether it is used to describe a line segment or an arc.
95
96
97 The following rules are applied to decompose the contour's points into segments and arcs :
98
99 # two successive "on" points indicate a line segment joining them.
100
101 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
102   the control point, and the "on" ones the start and end points.
103
104 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
105   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
106   "off" point between two "on" points is forbidden, for example).
107
108 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
109   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
110   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
111   outlines are described in the TrueType specification.
112
113 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
114 font driver produces such outlines.
115
116                                   *            # on      
117                                                * off
118                                __---__
119   #-__                      _--       -_
120       --__                _-            -
121           --__           #               \
122               --__                        #
123                   -#
124                            Two "on" points
125    Two "on" points       and one "conic" point
126                             between them
127
128
129
130                 *
131   #            __      Two "on" points with two "conic"
132    \          -  -     points between them. The point
133     \        /    \    marked '0' is the middle of the
134      -      0      \   "off" points, and is a 'virtual'
135       -_  _-       #   "on" point where the curve passes.
136         --             It does not appear in the point
137                        list.
138         *
139
140
141
142
143         *                # on
144                    *     * off
145          __---__
146       _--       -_
147     _-            -
148    #               \
149                     #
150
151      Two "on" points
152    and two "cubic" point
153       between them
154
155
156 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
157 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
158 range from -16384 to 16383.
159
160
161 Convert conic to bezier arcs:
162 Conic P0 P1 P2
163 Bezier B0 B1 B2 B3
164 B0=P0
165 B1=(P0+2*P1)/3
166 B2=(P2+2*P1)/3
167 B3=P2
168
169 *//****/
170
171 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
172 {
173         // Blender
174         VFontData *vfd;
175         struct Nurb *nu;
176         struct BezTriple *bezt;
177
178         // Freetype2
179         FT_Face         face;
180         FT_GlyphSlot  glyph;
181         FT_UInt         glyph_index;
182         FT_Outline      ftoutline;
183 /*
184     FT_CharMap  found = 0;
185         FT_CharMap  charmap;
186         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
187         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
188         int         n;
189 */
190
191         float scale= 1. / 1024.; //needs text_height from metrics to make a standard linedist
192         float dx, dy;
193         int i, j, k, l, m; /* uhoh, kiddie C loops */
194         /* i = characters, j = curves/contours, k = points, l = curvepoint, m = first point on curve */
195
196         // test is used for BIF_printf
197         char test[2];
198
199         
200         // load the freetype font
201         err = FT_New_Memory_Face( library,
202                                                 pf->data,
203                                                 pf->size,
204                                                 0,
205                                                 &face );
206
207         if(err) return NULL;
208 /*
209     for ( n = 0; n < face->num_charmaps; n++ )
210     {
211       charmap = face->charmaps[n];
212       if ( charmap->platform_id == my_platform_id &&
213            charmap->encoding_id == my_encoding_id )
214       {
215         found = charmap;
216         break;
217       }
218     }
219
220     if ( !found ) { return NULL; }
221
222     // now, select the charmap for the face object
223     err = FT_Set_Charmap( face, found );
224     if ( err ) { return NULL; }
225 */
226
227         // allocate blender font
228         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
229
230         // extract generic ascii character range (needs international support, dynamic loading of chars, etcetc)
231         for(i = myMIN_ASCII; i <= myMAX_ASCII; i++) {
232                 int  *npoints;  //total points of each contour
233                 int  *onpoints; //num points on curve
234
235                 test[0] = i;
236                 test[1] = '\0'; //to print character
237
238                 glyph_index = FT_Get_Char_Index( face, i );
239                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE);
240                 glyph = face->glyph;
241                 ftoutline = glyph->outline;
242
243                 vfd->width[i] = glyph->advance.x* scale;
244 //              BIF_printf("sx %d sy %d", glyph->advance.x, face->glyph->metrics->text_height);
245
246                 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
247                 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
248
249                 // calculate total points of each contour
250                 for(j = 0; j < ftoutline.n_contours; j++) {
251                         if(j == 0)
252                                 npoints[j] = ftoutline.contours[j] + 1;
253                         else
254                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
255                 }
256
257                 // get number of on-curve points for beziertriples (including conic virtual on-points) 
258                 for(j = 0; j < ftoutline.n_contours; j++) {
259                         l = 0;
260                         for(k = 0; k < npoints[j]; k++) {
261                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
262
263 //                              if(i == 67) BIF_printf("%d->%s : |k %2d|l %2d|t %2d|", i, test, k, l, ftoutline.n_points);
264
265                                 if(ftoutline.tags[l] == FT_Curve_Tag_On)
266                                         onpoints[j]++;
267
268                                 if(k < npoints[j] - 1 )
269                                         if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
270                                                 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
271                                                 onpoints[j]++;
272                         }
273                 }
274
275                 //final contour loop, bezier & conic styles merged
276                 for(j = 0; j < ftoutline.n_contours; j++) {
277                         // add new curve
278                         nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
279                         bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
280                         BLI_addtail(&vfd->nurbsbase[i], nu);
281                         nu->type= CU_BEZIER+CU_2D;
282                         nu->pntsu = onpoints[j];
283                         nu->resolu= 8;
284                         nu->flagu= 1;
285                         nu->bezt = bezt;
286
287                         //individual curve loop, start-end
288                         for(k = 0; k < npoints[j]; k++) {
289                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
290                                 if(k == 0) m = l;
291                                 
292                                 //virtual conic on-curve points
293                                 if(k < npoints[j] - 1 )
294                                         if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
295                                                 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
296                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
297
298                                                 //left handle
299                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
300                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
301
302                                                 //midpoint (virtual on-curve point)
303                                                 bezt->vec[1][0] = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
304                                                 bezt->vec[1][1] = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
305
306                                                 //right handle
307                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
308                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
309
310                                                 bezt->h1= bezt->h2= HD_ALIGN;
311                                                 bezt++;
312                                         }
313
314                                 //on-curve points
315                                 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
316                                         //left handle
317                                         if(k > 0) {
318                                                 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
319                                                         bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
320                                                         bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
321                                                         bezt->h1= HD_FREE;
322                                                 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
323                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
324                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
325                                                         bezt->h1= HD_FREE;
326                                                 } else {
327                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
328                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
329                                                         bezt->h1= HD_VECT;
330                                                 }
331                                         } else { //first point on curve
332                                                 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
333                                                         bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
334                                                         bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
335                                                         bezt->h1= HD_FREE;
336                                                 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
337                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
338                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
339                                                         bezt->h1= HD_FREE;
340                                                 } else {
341                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
342                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
343                                                         bezt->h1= HD_VECT;
344                                                 }
345                                         }
346
347                                         //midpoint (on-curve point)
348                                         bezt->vec[1][0] = ftoutline.points[l].x* scale;
349                                         bezt->vec[1][1] = ftoutline.points[l].y* scale;
350
351                                         //right handle
352                                         if(k < (npoints[j] - 1)) {
353                                                 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
354                                                         bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
355                                                         bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
356                                                         bezt->h2= HD_FREE;
357                                                 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
358                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
359                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
360                                                         bezt->h2= HD_FREE;
361                                                 } else {
362                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
363                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
364                                                         bezt->h2= HD_VECT;
365                                                 }
366                                         } else { //last point on curve
367                                                 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
368 //                                                      okee("hhuh");
369                                                         bezt->vec[2][0] = ftoutline.points[m].x* scale;
370                                                         bezt->vec[2][1] = ftoutline.points[m].y* scale;
371                                                         bezt->h2= HD_FREE;
372                                                 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
373                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
374                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
375                                                         bezt->h2= HD_FREE;
376                                                 } else {
377                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
378                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
379                                                         bezt->h2= HD_VECT;
380                                                 }
381                                         }
382
383                                         // get the handles that are aligned, tricky...
384                                         // DistVL2Dfl, check if the three beztriple points are on one line
385                                         // VecLenf, see if there's a distance between the three points
386                                         // VecLenf again, to check the angle between the handles 
387                                         // finally, check if one of them is a vector handle 
388                                         if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
389                                                 (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
390                                                 (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
391                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
392                                                 (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
393                                                 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
394                                         {
395                                                 bezt->h1= bezt->h2= HD_ALIGN;
396                                         }
397                                         bezt++;
398                                 }
399                         }
400                 }
401
402                 if(npoints) MEM_freeN(npoints);
403                 if(onpoints) MEM_freeN(onpoints);
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             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_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                                 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             error("Failed loading 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 #endif // WITH_FREETYPE2