51e4ab0f47a2ad2cf7d7284cac03613790bf6df7
[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 _MSC_VER
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 #include "BKE_font.h"
56
57 #include "DNA_vfont_types.h"
58 #include "DNA_packedFile_types.h"
59 #include "DNA_curve_types.h"
60
61 /* local variables */
62 static FT_Library library;
63 static FT_Error err;
64
65
66 static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
67 {
68         /* Blender */
69         struct Nurb *nu;
70         struct VChar *che;
71         struct BezTriple *bezt;
72
73         /* Freetype2 */
74         FT_GlyphSlot glyph;
75         FT_UInt glyph_index;
76         FT_Outline ftoutline;
77         float scale, height;
78         float dx, dy;
79         int j, k, l, m = 0;
80
81         /* adjust font size */
82         height = ((double) face->bbox.yMax - (double) face->bbox.yMin);
83         if (height != 0.0f)
84                 scale = 1.0f / height;
85         else
86                 scale = 1.0f / 1000.0f;
87
88         /*
89          * Generate the character 3D data
90          *
91          * Get the FT Glyph index and load the Glyph */
92         glyph_index = FT_Get_Char_Index(face, charcode);
93         err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
94
95         /* If loading succeeded, convert the FT glyph to the internal format */
96         if (!err) {
97                 int *npoints;
98                 int *onpoints;
99
100                 /* First we create entry for the new character to the character list */
101                 che = (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
102                 BLI_addtail(&vfd->characters, che);
103
104                 /* Take some data for modifying purposes */
105                 glyph = face->glyph;
106                 ftoutline = glyph->outline;
107
108                 /* Set the width and character code */
109                 che->index = charcode;
110                 che->width = glyph->advance.x * scale;
111
112                 /* Start converting the FT data */
113                 npoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "endpoints");
114                 onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints");
115
116                 /* calculate total points of each contour */
117                 for (j = 0; j < ftoutline.n_contours; j++) {
118                         if (j == 0)
119                                 npoints[j] = ftoutline.contours[j] + 1;
120                         else
121                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
122                 }
123
124                 /* get number of on-curve points for beziertriples (including conic virtual on-points) */
125                 for (j = 0; j < ftoutline.n_contours; j++) {
126                         for (k = 0; k < npoints[j]; k++) {
127                                 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
128
129                                 if (ftoutline.tags[l] == FT_Curve_Tag_On)
130                                         onpoints[j]++;
131
132                                 if (k < npoints[j] - 1) {
133                                         if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
134                                             ftoutline.tags[l + 1] == FT_Curve_Tag_Conic)
135                                         {
136                                                 onpoints[j]++;
137                                         }
138                                 }
139                         }
140                 }
141
142                 /* contour loop, bezier & conic styles merged */
143                 for (j = 0; j < ftoutline.n_contours; j++) {
144                         /* add new curve */
145                         nu  =  (Nurb *)MEM_callocN(sizeof(struct Nurb), "objfnt_nurb");
146                         bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt");
147                         BLI_addtail(&che->nurbsbase, nu);
148
149                         nu->type = CU_BEZIER;
150                         nu->pntsu = onpoints[j];
151                         nu->resolu = 8;
152                         nu->flag = CU_2D;
153                         nu->flagu = CU_NURB_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                                         if (ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) {
164                                                 dx = (ftoutline.points[l].x + ftoutline.points[l + 1].x) * scale / 2.0f;
165                                                 dy = (ftoutline.points[l].y + ftoutline.points[l + 1].y) * scale / 2.0f;
166
167                                                 /* left handle */
168                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x) * scale) / 3.0f;
169                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y) * scale) / 3.0f;
170
171                                                 /* midpoint (virtual on-curve point) */
172                                                 bezt->vec[1][0] = dx;
173                                                 bezt->vec[1][1] = dy;
174
175                                                 /* right handle */
176                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l + 1].x) * scale) / 3.0f;
177                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l + 1].y) * scale) / 3.0f;
178
179                                                 bezt->h1 = bezt->h2 = HD_ALIGN;
180                                                 bezt->radius = 1.0f;
181                                                 bezt++;
182                                         }
183                                 }
184
185                                 /* on-curve points */
186                                 if (ftoutline.tags[l] == FT_Curve_Tag_On) {
187                                         /* left handle */
188                                         if (k > 0) {
189                                                 if (ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
190                                                         bezt->vec[0][0] = ftoutline.points[l - 1].x * scale;
191                                                         bezt->vec[0][1] = ftoutline.points[l - 1].y * scale;
192                                                         bezt->h1 = HD_FREE;
193                                                 }
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.0f;
196                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y)) * scale / 3.0f;
197                                                         bezt->h1 = HD_FREE;
198                                                 }
199                                                 else {
200                                                         bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l - 1].x) * scale / 3.0f;
201                                                         bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l - 1].y) * scale / 3.0f;
202                                                         bezt->h1 = HD_VECT;
203                                                 }
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                                                 }
211                                                 else if (ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
212                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x)) * scale / 3.0f;
213                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y)) * scale / 3.0f;
214                                                         bezt->h1 = HD_FREE;
215                                                 }
216                                                 else {
217                                                         bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x) * scale / 3.0f;
218                                                         bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y) * scale / 3.0f;
219                                                         bezt->h1 = HD_VECT;
220                                                 }
221                                         }
222
223                                         /* midpoint (on-curve point) */
224                                         bezt->vec[1][0] = ftoutline.points[l].x * scale;
225                                         bezt->vec[1][1] = ftoutline.points[l].y * scale;
226
227                                         /* right handle */
228                                         if (k < (npoints[j] - 1)) {
229                                                 if (ftoutline.tags[l + 1] == FT_Curve_Tag_Cubic) {
230                                                         bezt->vec[2][0] = ftoutline.points[l + 1].x * scale;
231                                                         bezt->vec[2][1] = ftoutline.points[l + 1].y * scale;
232                                                         bezt->h2 = HD_FREE;
233                                                 }
234                                                 else if (ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) {
235                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l + 1].x)) * scale / 3.0f;
236                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l + 1].y)) * scale / 3.0f;
237                                                         bezt->h2 = HD_FREE;
238                                                 }
239                                                 else {
240                                                         bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l + 1].x) * scale / 3.0f;
241                                                         bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l + 1].y) * scale / 3.0f;
242                                                         bezt->h2 = HD_VECT;
243                                                 }
244                                         }
245                                         else { /* last point on curve */
246                                                 if (ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
247                                                         bezt->vec[2][0] = ftoutline.points[m].x * scale;
248                                                         bezt->vec[2][1] = ftoutline.points[m].y * scale;
249                                                         bezt->h2 = HD_FREE;
250                                                 }
251                                                 else if (ftoutline.tags[m] == FT_Curve_Tag_Conic) {
252                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x)) * scale / 3.0f;
253                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y)) * scale / 3.0f;
254                                                         bezt->h2 = HD_FREE;
255                                                 }
256                                                 else {
257                                                         bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[m].x) * scale / 3.0f;
258                                                         bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[m].y) * scale / 3.0f;
259                                                         bezt->h2 = HD_VECT;
260                                                 }
261                                         }
262
263                                         /* get the handles that are aligned, tricky...
264                                          * dist_to_line_v2, check if the three beztriple points are on one line
265                                          * len_squared_v2v2, see if there's a distance between the three points
266                                          * len_squared_v2v2 again, to check the angle between the handles
267                                          * finally, check if one of them is a vector handle */
268                                         if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) &&
269                                             (dist_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) < 0.001f) &&
270                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001f * 0.0001f) &&
271                                             (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001f * 0.0001f) &&
272                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002f * 0.0001f) &&
273                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) >
274                                              maxf(len_squared_v2v2(bezt->vec[0], bezt->vec[1]),
275                                                   len_squared_v2v2(bezt->vec[1], bezt->vec[2]))))
276                                         {
277                                                 bezt->h1 = bezt->h2 = HD_ALIGN;
278                                         }
279                                         bezt->radius = 1.0f;
280                                         bezt++;
281                                 }
282                         }
283                 }
284                 if (npoints) MEM_freeN(npoints);
285                 if (onpoints) MEM_freeN(onpoints);      
286         }
287 }
288
289 static int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
290 {
291         /* Freetype2 */
292         FT_Face face;
293
294         /* Load the font to memory */
295         if (vfont->temp_pf) {
296                 err = FT_New_Memory_Face(library,
297                                          vfont->temp_pf->data,
298                                          vfont->temp_pf->size,
299                                          0,
300                                          &face);
301                 if (err) return FALSE;
302         }
303         else {
304                 err = TRUE;
305                 return FALSE;
306         }
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 #if 0
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 #endif
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 #if 0
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 #endif
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         BLI_strncpy(vfd->name, (fontname == NULL) ? "" : fontname, sizeof(vfd->name));
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                 FT_CharMap found = NULL;
374                 FT_CharMap charmap;
375                 int n;
376
377                 for (n = 0; n < face->num_charmaps; n++) {
378                         charmap = face->charmaps[n];
379                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) {
380                                 found = charmap;
381                                 break;
382                         }
383                 }
384
385                 err = FT_Set_Charmap(face, found);
386
387                 if (err)
388                         return NULL;
389
390                 lcode = charcode = FT_Get_First_Char(face, &glyph_index);
391         }
392
393         /* Load characters */
394         while (charcode < 256) {
395                 /* Generate the font data */
396                 freetypechar_to_vchar(face, charcode, vfd);
397
398                 /* Next glyph */
399                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
400
401                 /* Check that we won't start infinite loop */
402                 if (charcode <= lcode)
403                         break;
404                 lcode = charcode;
405         }
406
407         return vfd;     
408 }
409
410
411 static int check_freetypefont(PackedFile *pf)
412 {
413         FT_Face face;
414         FT_GlyphSlot glyph;
415         FT_UInt glyph_index;
416 #if 0
417         FT_CharMap charmap;
418         FT_CharMap found;
419         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
420         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
421         int n;
422 #endif
423         int success = 0;
424
425         err = FT_New_Memory_Face(library,
426                                  pf->data,
427                                  pf->size,
428                                  0,
429                                  &face);
430         if (err) {
431                 success = 0;
432                 //XXX error("This is not a valid font");
433         }
434         else {
435
436 #if 0
437                 for (n = 0; n < face->num_charmaps; n++) {
438                         charmap = face->charmaps[n];
439                         if (charmap->platform_id == my_platform_id && charmap->encoding_id == my_encoding_id) {
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 #endif
451
452                 glyph_index = FT_Get_Char_Index(face, 'A');
453                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
454                 if (err) success = 0;
455                 else {
456                         glyph = face->glyph;
457                         if (glyph->format == ft_glyph_format_outline) {
458                                 success = 1;
459                         }
460                         else {
461                                 //XXX error("Selected Font has no outline data");
462                                 success = 0;
463                         }
464                 }
465         }
466         
467         return success;
468 }
469
470
471 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
472 {
473         VFontData *vfd = NULL;
474         int success = 0;
475
476         //init Freetype 
477         err = FT_Init_FreeType(&library);
478         if (err) {
479                 //XXX error("Failed to load the Freetype font library");
480                 return NULL;
481         }
482
483         success = check_freetypefont(pf);
484         
485         if (success) {
486                 vfd = objfnt_to_ftvfontdata(pf);
487         }
488
489         //free Freetype
490         FT_Done_FreeType(library);
491         
492         return vfd;
493 }
494
495 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
496 {
497         int success = FALSE;
498
499         if (!vfont) return FALSE;
500
501         /* Init Freetype */
502         err = FT_Init_FreeType(&library);
503         if (err) {
504                 /* XXX error("Failed to load the Freetype font library"); */
505                 return 0;
506         }
507
508         /* Load the character */
509         success = objchr_to_ftvfontdata(vfont, character);
510         if (success == FALSE) return FALSE;
511
512         /* Free Freetype */
513         FT_Done_FreeType(library);
514
515         /* Ahh everything ok */
516         return TRUE;
517 }
518
519 #if 0
520
521 // Freetype2 Outline struct
522
523 typedef struct  FT_Outline_
524 {
525         short       n_contours;      /* number of contours in glyph        */
526         short       n_points;        /* number of points in the glyph      */
527
528         FT_Vector  *points;          /* the outline's points               */
529         char       *tags;            /* the points flags                   */
530         short      *contours;        /* the contour end points             */
531
532         int         flags;           /* outline masks                      */
533 } FT_Outline;
534
535 #endif
536
537 /*
538  * from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
539  *
540  * Vectorial representation of Freetype glyphs
541  *
542  * The source format of outlines is a collection of closed paths called "contours". Each contour is
543  * made of a series of line segments and bezier arcs. Depending on the file format, these can be
544  * second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
545  * they come from the TrueType format. The latter are called cubic arcs and mostly come from the
546  * Type1 format.
547  *
548  * Each arc is described through a series of start, end and control points. Each point of the outline
549  * has a specific tag which indicates whether it is used to describe a line segment or an arc.
550  *
551  *
552  * The following rules are applied to decompose the contour's points into segments and arcs :
553  *
554  * # two successive "on" points indicate a line segment joining them.
555  *
556  * # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
557  *   the control point, and the "on" ones the start and end points.
558  *
559  * # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
560  *   be exactly two cubic control points and two on points for each cubic arc (using a single cubic
561  *   "off" point between two "on" points is forbidden, for example).
562  *
563  * # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
564  *   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
565  *   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
566  *   outlines are described in the TrueType specification.
567  *
568  * Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
569  * font driver produces such outlines.
570  *
571  *                                   *            # on
572  *                                                * off
573  *                                __---__
574  *   #-__                      _--       -_
575  *       --__                _-            -
576  *           --__           #               \
577  *               --__                        #
578  *                   -#
579  *                            Two "on" points
580  *    Two "on" points       and one "conic" point
581  *                             between them
582  *
583  *
584  *
585  *                 *
586  *   #            __      Two "on" points with two "conic"
587  *    \          -  -     points between them. The point
588  *     \        /    \    marked '0' is the middle of the
589  *      -      0      \   "off" points, and is a 'virtual'
590  *       -_  _-       #   "on" point where the curve passes.
591  *         --             It does not appear in the point
592  *                        list.
593  *         *
594  *
595  *
596  *
597  *
598  *         *                # on
599  *                    *     * off
600  *          __---__
601  *       _--       -_
602  *     _-            -
603  *    #               \
604  *                     #
605  *
606  *      Two "on" points
607  *    and two "cubic" point
608  *       between them
609  *
610  *
611  * Each glyph's original outline points are located on a grid of indivisible units. The points are stored
612  * in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0, 0); they thus
613  * range from -16384 to 16383.
614  *
615  * Convert conic to bezier arcs:
616  * Conic P0 P1 P2
617  * Bezier B0 B1 B2 B3
618  * B0=P0
619  * B1=(P0+2*P1)/3
620  * B2=(P2+2*P1)/3
621  * B3=P2
622  *
623  */