style cleanyp
[blender.git] / source / blender / blenlib / intern / freetypefont.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is written by Rob Haarsma (phase)
19  * All rights reserved.
20  *
21  * Contributor(s): none yet.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  * This code parses the Freetype font outline data to chains of Blender's beziertriples.
26  * Additional information can be found at the bottom of this file.
27  *
28  * Code that uses exotic character maps is present but commented out.
29  */
30
31 /** \file blender/blenlib/intern/freetypefont.c
32  *  \ingroup bli
33  */
34
35
36 #ifdef WIN32
37 #pragma warning (disable:4244)
38 #endif
39
40 #include <ft2build.h>
41 #include FT_FREETYPE_H
42 /* not needed yet */
43 // #include FT_GLYPH_H
44 // #include FT_BBOX_H
45 // #include FT_SIZES_H
46 // #include <freetype/ttnameid.h>
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_vfontdata.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_math.h"
53 #include "BLI_utildefines.h"
54
55 //XXX #include "BIF_toolbox.h"
56
57 #include "BKE_font.h"
58
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 static 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.0f)
90                 scale = 1.0f / height;
91         else
92                 scale = 1.0f / 1000.0f;
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                 int *npoints;
104                 int *onpoints;
105                 
106                 // First we create entry for the new character to the character list
107                 che = (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
108                 BLI_addtail(&vfd->characters, che);
109                 
110                 // Take some data for modifying purposes
111                 glyph = face->glyph;
112                 ftoutline = glyph->outline;
113                 
114                 // Set the width and character code
115                 che->index = charcode;
116                 che->width = glyph->advance.x * scale;
117                 
118                 // Start converting the FT data
119                 npoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "endpoints");
120                 onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints");
121
122                 // calculate total points of each contour
123                 for (j = 0; j < ftoutline.n_contours; j++) {
124                         if (j == 0)
125                                 npoints[j] = ftoutline.contours[j] + 1;
126                         else
127                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
128                 }
129
130                 // get number of on-curve points for beziertriples (including conic virtual on-points)
131                 for (j = 0; j < ftoutline.n_contours; j++) {
132                         for (k = 0; k < npoints[j]; k++) {
133                                 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
134
135                                 if (ftoutline.tags[l] == FT_Curve_Tag_On)
136                                         onpoints[j]++;
137
138                                 if (k < npoints[j] - 1) {
139                                         if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
140                                             ftoutline.tags[l + 1] == FT_Curve_Tag_Conic)
141                                         {
142                                                 onpoints[j]++;
143                                         }
144                                 }
145                         }
146                 }
147
148                 //contour loop, bezier & conic styles merged
149                 for (j = 0; j < ftoutline.n_contours; j++) {
150                         // add new curve
151                         nu  =  (Nurb *)MEM_callocN(sizeof(struct Nurb), "objfnt_nurb");
152                         bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt");
153                         BLI_addtail(&che->nurbsbase, nu);
154
155                         nu->type = CU_BEZIER;
156                         nu->pntsu = onpoints[j];
157                         nu->resolu = 8;
158                         nu->flag = CU_2D;
159                         nu->flagu = CU_NURB_CYCLIC;
160                         nu->bezt = bezt;
161
162                         //individual curve loop, start-end
163                         for (k = 0; k < npoints[j]; k++) {
164                                 if (j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
165                                 if (k == 0) m = l;
166                                         
167                                 //virtual conic on-curve points
168                                 if (k < npoints[j] - 1) {
169                                         if (ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) {
170                                                 dx = (ftoutline.points[l].x + ftoutline.points[l + 1].x) * scale / 2.0f;
171                                                 dy = (ftoutline.points[l].y + ftoutline.points[l + 1].y) * scale / 2.0f;
172
173                                                 //left handle
174                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x) * scale) / 3.0f;
175                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y) * scale) / 3.0f;
176
177                                                 //midpoint (virtual on-curve point)
178                                                 bezt->vec[1][0] = dx;
179                                                 bezt->vec[1][1] = dy;
180
181                                                 //right handle
182                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l + 1].x) * scale) / 3.0f;
183                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l + 1].y) * scale) / 3.0f;
184
185                                                 bezt->h1 = bezt->h2 = HD_ALIGN;
186                                                 bezt->radius = 1.0f;
187                                                 bezt++;
188                                         }
189                                 }
190
191                                 //on-curve points
192                                 if (ftoutline.tags[l] == FT_Curve_Tag_On) {
193                                         //left handle
194                                         if (k > 0) {
195                                                 if (ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
196                                                         bezt->vec[0][0] = ftoutline.points[l - 1].x * scale;
197                                                         bezt->vec[0][1] = ftoutline.points[l - 1].y * scale;
198                                                         bezt->h1 = HD_FREE;
199                                                 }
200                                                 else if (ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
201                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x)) * scale / 3.0f;
202                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y)) * scale / 3.0f;
203                                                         bezt->h1 = HD_FREE;
204                                                 }
205                                                 else {
206                                                         bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l - 1].x) * scale / 3.0f;
207                                                         bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l - 1].y) * scale / 3.0f;
208                                                         bezt->h1 = HD_VECT;
209                                                 }
210                                         }
211                                         else { //first point on curve
212                                                 if (ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
213                                                         bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
214                                                         bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
215                                                         bezt->h1 = HD_FREE;
216                                                 }
217                                                 else if (ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
218                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x)) * scale / 3.0f;
219                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y)) * scale / 3.0f;
220                                                         bezt->h1 = HD_FREE;
221                                                 }
222                                                 else {
223                                                         bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x) * scale / 3.0f;
224                                                         bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y) * scale / 3.0f;
225                                                         bezt->h1 = HD_VECT;
226                                                 }
227                                         }
228
229                                         //midpoint (on-curve point)
230                                         bezt->vec[1][0] = ftoutline.points[l].x * scale;
231                                         bezt->vec[1][1] = ftoutline.points[l].y * scale;
232
233                                         //right handle
234                                         if (k < (npoints[j] - 1)) {
235                                                 if (ftoutline.tags[l + 1] == FT_Curve_Tag_Cubic) {
236                                                         bezt->vec[2][0] = ftoutline.points[l + 1].x * scale;
237                                                         bezt->vec[2][1] = ftoutline.points[l + 1].y * scale;
238                                                         bezt->h2 = HD_FREE;
239                                                 }
240                                                 else if (ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) {
241                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l + 1].x)) * scale / 3.0f;
242                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l + 1].y)) * scale / 3.0f;
243                                                         bezt->h2 = HD_FREE;
244                                                 }
245                                                 else {
246                                                         bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l + 1].x) * scale / 3.0f;
247                                                         bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l + 1].y) * scale / 3.0f;
248                                                         bezt->h2 = HD_VECT;
249                                                 }
250                                         }
251                                         else { //last point on curve
252                                                 if (ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
253                                                         bezt->vec[2][0] = ftoutline.points[m].x * scale;
254                                                         bezt->vec[2][1] = ftoutline.points[m].y * scale;
255                                                         bezt->h2 = HD_FREE;
256                                                 }
257                                                 else if (ftoutline.tags[m] == FT_Curve_Tag_Conic) {
258                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x)) * scale / 3.0f;
259                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y)) * scale / 3.0f;
260                                                         bezt->h2 = HD_FREE;
261                                                 }
262                                                 else {
263                                                         bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[m].x) * scale / 3.0f;
264                                                         bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[m].y) * scale / 3.0f;
265                                                         bezt->h2 = HD_VECT;
266                                                 }
267                                         }
268
269                                         // get the handles that are aligned, tricky...
270                                         // dist_to_line_v2, check if the three beztriple points are on one line
271                                         // len_squared_v2v2, see if there's a distance between the three points
272                                         // len_squared_v2v2 again, to check the angle between the handles 
273                                         // finally, check if one of them is a vector handle 
274                                         if ((dist_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) < 0.001f) &&
275                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001f * 0.0001f) &&
276                                             (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001f * 0.0001f) &&
277                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002f * 0.0001f) &&
278                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > MAX2(len_squared_v2v2(bezt->vec[0], bezt->vec[1]), len_squared_v2v2(bezt->vec[1], bezt->vec[2]))) &&
279                                             bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
280                                         {
281                                                 bezt->h1 = bezt->h2 = HD_ALIGN;
282                                         }
283                                         bezt->radius = 1.0f;
284                                         bezt++;
285                                 }
286                         }
287                 }
288                 if (npoints) MEM_freeN(npoints);
289                 if (onpoints) MEM_freeN(onpoints);      
290         }
291 }
292
293 static int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
294 {
295         // Freetype2
296         FT_Face face;
297         struct TmpFont *tf;
298         
299         // Find the correct FreeType font
300         tf = BKE_vfont_find_tmpfont(vfont);
301         
302         // What, no font found. Something strange here
303         if (!tf) return FALSE;
304         
305         // Load the font to memory
306         if (tf->pf) {
307                 err = FT_New_Memory_Face(library,
308                                          tf->pf->data,
309                                          tf->pf->size,
310                                          0,
311                                          &face);
312                 if (err) return FALSE;
313         }
314         else {
315                 err = TRUE;
316                 return FALSE;
317         }
318                 
319         // Read the char
320         freetypechar_to_vchar(face, charcode, vfont->data);
321         
322         // And everything went ok
323         return TRUE;
324 }
325
326
327 static VFontData *objfnt_to_ftvfontdata(PackedFile *pf)
328 {
329         // Variables
330         FT_Face face;
331         FT_ULong charcode = 0, lcode;
332         FT_UInt glyph_index;
333         const char *fontname;
334         VFontData *vfd;
335
336 #if 0
337         FT_CharMap found = 0;
338         FT_CharMap charmap;
339         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
340         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
341         int n;
342 #endif
343
344         // load the freetype font
345         err = FT_New_Memory_Face(library,
346                                  pf->data,
347                                  pf->size,
348                                  0,
349                                  &face);
350
351         if (err) return NULL;
352
353 #if 0
354         for (n = 0; n < face->num_charmaps; n++)
355         {
356                 charmap = face->charmaps[n];
357                 if (charmap->platform_id == my_platform_id &&
358                     charmap->encoding_id == my_encoding_id)
359                 {
360                         found = charmap;
361                         break;
362                 }
363         }
364
365         if (!found) { return NULL; }
366
367         // now, select the charmap for the face object
368         err = FT_Set_Charmap(face, found);
369         if (err) { return NULL; }
370 #endif
371
372         // allocate blender font
373         vfd = MEM_callocN(sizeof(*vfd), "FTVFontData");
374
375         // get the name
376         fontname = FT_Get_Postscript_Name(face);
377         BLI_strncpy(vfd->name, (fontname == NULL) ? "" : fontname, sizeof(vfd->name));
378
379         // Extract the first 256 character from TTF
380         lcode = charcode = FT_Get_First_Char(face, &glyph_index);
381
382         // No charmap found from the ttf so we need to figure it out
383         if (glyph_index == 0) {
384                 FT_CharMap found = NULL;
385                 FT_CharMap charmap;
386                 int n;
387
388                 for (n = 0; n < face->num_charmaps; n++) {
389                         charmap = face->charmaps[n];
390                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) {
391                                 found = charmap;
392                                 break;
393                         }
394                 }
395
396                 err = FT_Set_Charmap(face, found);
397
398                 if (err)
399                         return NULL;
400
401                 lcode = charcode = FT_Get_First_Char(face, &glyph_index);
402         }
403
404         // Load characters
405         while (charcode < 256) {
406                 // Generate the font data
407                 freetypechar_to_vchar(face, charcode, vfd);
408
409                 // Next glyph
410                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
411
412                 // Check that we won't start infinite loop
413                 if (charcode <= lcode)
414                         break;
415                 lcode = charcode;
416         }
417
418         return vfd;     
419 }
420
421
422 static int check_freetypefont(PackedFile *pf)
423 {
424         FT_Face face;
425         FT_GlyphSlot glyph;
426         FT_UInt glyph_index;
427 #if 0
428         FT_CharMap charmap;
429         FT_CharMap found;
430         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
431         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
432         int n;
433 #endif
434         int success = 0;
435
436         err = FT_New_Memory_Face(library,
437                                  pf->data,
438                                  pf->size,
439                                  0,
440                                  &face);
441         if (err) {
442                 success = 0;
443                 //XXX error("This is not a valid font");
444         }
445         else {
446
447 #if 0
448                 for (n = 0; n < face->num_charmaps; n++) {
449                         charmap = face->charmaps[n];
450                         if (charmap->platform_id == my_platform_id && charmap->encoding_id == my_encoding_id) {
451                                 found = charmap;
452                                 break;
453                         }
454                 }
455
456                 if (!found) { return 0; }
457
458                 // now, select the charmap for the face object 
459                 err = FT_Set_Charmap(face, found);
460                 if (err) { return 0; }
461 #endif
462
463                 glyph_index = FT_Get_Char_Index(face, 'A');
464                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
465                 if (err) success = 0;
466                 else {
467                         glyph = face->glyph;
468                         if (glyph->format == ft_glyph_format_outline) {
469                                 success = 1;
470                         }
471                         else {
472                                 //XXX error("Selected Font has no outline data");
473                                 success = 0;
474                         }
475                 }
476         }
477         
478         return success;
479 }
480
481
482 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
483 {
484         VFontData *vfd = NULL;
485         int success = 0;
486
487         //init Freetype 
488         err = FT_Init_FreeType(&library);
489         if (err) {
490                 //XXX error("Failed to load the Freetype font library");
491                 return NULL;
492         }
493
494         success = check_freetypefont(pf);
495         
496         if (success) {
497                 vfd = objfnt_to_ftvfontdata(pf);
498         }
499
500         //free Freetype
501         FT_Done_FreeType(library);
502         
503         return vfd;
504 }
505
506 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
507 {
508         int success = FALSE;
509
510         if (!vfont) return FALSE;
511
512         // Init Freetype
513         err = FT_Init_FreeType(&library);
514         if (err) {
515                 //XXX error("Failed to load the Freetype font library");
516                 return 0;
517         }
518
519         // Load the character
520         success = objchr_to_ftvfontdata(vfont, character);
521         if (success == FALSE) return FALSE;
522
523         // Free Freetype
524         FT_Done_FreeType(library);
525
526         // Ahh everything ok
527         return TRUE;
528 }
529
530 #if 0
531
532 // Freetype2 Outline struct
533
534 typedef struct  FT_Outline_
535   {
536         short       n_contours;      /* number of contours in glyph        */
537         short       n_points;        /* number of points in the glyph      */
538
539         FT_Vector*  points;          /* the outline's points               */
540         char*       tags;            /* the points flags                   */
541         short*      contours;        /* the contour end points             */
542
543         int         flags;           /* outline masks                      */
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 *//****/