Merge branch 'blender2.7'
[blender.git] / source / blender / blenlib / intern / freetypefont.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is written by Rob Haarsma (phase)
17  * All rights reserved.
18  * This code parses the Freetype font outline data to chains of Blender's beziertriples.
19  * Additional information can be found at the bottom of this file.
20  *
21  * Code that uses exotic character maps is present but commented out.
22  */
23
24 /** \file
25  * \ingroup bli
26  */
27
28 #include <ft2build.h>
29 #include FT_FREETYPE_H
30 /* not needed yet */
31 // #include FT_GLYPH_H
32 // #include FT_BBOX_H
33 // #include FT_SIZES_H
34 // #include <freetype/ttnameid.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_utildefines.h"
39 #include "BLI_vfontdata.h"
40 #include "BLI_listbase.h"
41 #include "BLI_ghash.h"
42 #include "BLI_string.h"
43 #include "BLI_math.h"
44
45 #include "DNA_vfont_types.h"
46 #include "DNA_packedFile_types.h"
47 #include "DNA_curve_types.h"
48
49 /* local variables */
50 static FT_Library library;
51 static FT_Error err;
52
53
54 static VChar *freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
55 {
56         const float scale = vfd->scale;
57         const float eps = 0.0001f;
58         const float eps_sq = eps * eps;
59         /* Blender */
60         struct Nurb *nu;
61         struct VChar *che;
62         struct BezTriple *bezt;
63
64         /* Freetype2 */
65         FT_GlyphSlot glyph;
66         FT_UInt glyph_index;
67         FT_Outline ftoutline;
68         float dx, dy;
69         int j, k, l, l_first = 0;
70
71         /*
72          * Generate the character 3D data
73          *
74          * Get the FT Glyph index and load the Glyph */
75         glyph_index = FT_Get_Char_Index(face, charcode);
76         err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
77
78         /* If loading succeeded, convert the FT glyph to the internal format */
79         if (!err) {
80                 /* initialize as -1 to add 1 on first loop each time */
81                 int contour_prev;
82                 int *onpoints;
83
84                 /* First we create entry for the new character to the character list */
85                 che = (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
86
87                 /* Take some data for modifying purposes */
88                 glyph = face->glyph;
89                 ftoutline = glyph->outline;
90
91                 /* Set the width and character code */
92                 che->index = charcode;
93                 che->width = glyph->advance.x * scale;
94
95                 BLI_ghash_insert(vfd->characters, POINTER_FROM_UINT(che->index), che);
96
97                 /* Start converting the FT data */
98                 onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints");
99
100                 /* get number of on-curve points for beziertriples (including conic virtual on-points) */
101                 for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
102                         const int n = ftoutline.contours[j] - contour_prev;
103                         contour_prev = ftoutline.contours[j];
104
105                         for (k = 0; k < n; k++) {
106                                 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
107                                 if (k == 0) {
108                                         l_first = l;
109                                 }
110
111                                 if (ftoutline.tags[l] == FT_Curve_Tag_On) {
112                                         onpoints[j]++;
113                                 }
114
115                                 {
116                                         const int l_next = (k < n - 1) ? (l + 1) : l_first;
117                                         if (ftoutline.tags[l]      == FT_Curve_Tag_Conic &&
118                                             ftoutline.tags[l_next] == FT_Curve_Tag_Conic)
119                                         {
120                                                 onpoints[j]++;
121                                         }
122                                 }
123                         }
124                 }
125
126                 /* contour loop, bezier & conic styles merged */
127                 for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
128                         const int n = ftoutline.contours[j] - contour_prev;
129                         contour_prev = ftoutline.contours[j];
130
131                         /* add new curve */
132                         nu  =  (Nurb *)MEM_callocN(sizeof(struct Nurb), "objfnt_nurb");
133                         bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt");
134                         BLI_addtail(&che->nurbsbase, nu);
135
136                         nu->type = CU_BEZIER;
137                         nu->pntsu = onpoints[j];
138                         nu->resolu = 8;
139                         nu->flag = CU_2D;
140                         nu->flagu = CU_NURB_CYCLIC;
141                         nu->bezt = bezt;
142
143                         /* individual curve loop, start-end */
144                         for (k = 0; k < n; k++) {
145                                 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
146                                 if (k == 0) {
147                                         l_first = l;
148                                 }
149
150                                 /* virtual conic on-curve points */
151                                 {
152                                         const int l_next = (k < n - 1) ? (l + 1) : l_first;
153                                         if (ftoutline.tags[l]      == FT_Curve_Tag_Conic &&
154                                             ftoutline.tags[l_next] == FT_Curve_Tag_Conic)
155                                         {
156                                                 dx = (ftoutline.points[l].x + ftoutline.points[l_next].x) * scale / 2.0f;
157                                                 dy = (ftoutline.points[l].y + ftoutline.points[l_next].y) * scale / 2.0f;
158
159                                                 /* left handle */
160                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x) * scale) / 3.0f;
161                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y) * scale) / 3.0f;
162
163                                                 /* midpoint (virtual on-curve point) */
164                                                 bezt->vec[1][0] = dx;
165                                                 bezt->vec[1][1] = dy;
166
167                                                 /* right handle */
168                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l_next].x) * scale) / 3.0f;
169                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l_next].y) * scale) / 3.0f;
170
171                                                 bezt->h1 = bezt->h2 = HD_ALIGN;
172                                                 bezt->radius = 1.0f;
173                                                 bezt++;
174                                         }
175                                 }
176
177                                 /* on-curve points */
178                                 if (ftoutline.tags[l] == FT_Curve_Tag_On) {
179                                         const int l_prev = (k > 0)     ? (l - 1) : ftoutline.contours[j];
180                                         const int l_next = (k < n - 1) ? (l + 1) : l_first;
181
182                                         /* left handle */
183                                         if (ftoutline.tags[l_prev] == FT_Curve_Tag_Cubic) {
184                                                 bezt->vec[0][0] = ftoutline.points[l_prev].x * scale;
185                                                 bezt->vec[0][1] = ftoutline.points[l_prev].y * scale;
186                                                 bezt->h1 = HD_FREE;
187                                         }
188                                         else if (ftoutline.tags[l_prev] == FT_Curve_Tag_Conic) {
189                                                 bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l_prev].x)) * scale / 3.0f;
190                                                 bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l_prev].y)) * scale / 3.0f;
191                                                 bezt->h1 = HD_FREE;
192                                         }
193                                         else {
194                                                 bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l_prev].x) * scale / 3.0f;
195                                                 bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l_prev].y) * scale / 3.0f;
196                                                 bezt->h1 = HD_VECT;
197                                         }
198
199                                         /* midpoint (on-curve point) */
200                                         bezt->vec[1][0] = ftoutline.points[l].x * scale;
201                                         bezt->vec[1][1] = ftoutline.points[l].y * scale;
202
203                                         /* right handle */
204                                         if (ftoutline.tags[l_next] == FT_Curve_Tag_Cubic) {
205                                                 bezt->vec[2][0] = ftoutline.points[l_next].x * scale;
206                                                 bezt->vec[2][1] = ftoutline.points[l_next].y * scale;
207                                                 bezt->h2 = HD_FREE;
208                                         }
209                                         else if (ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
210                                                 bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l_next].x)) * scale / 3.0f;
211                                                 bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l_next].y)) * scale / 3.0f;
212                                                 bezt->h2 = HD_FREE;
213                                         }
214                                         else {
215                                                 bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l_next].x) * scale / 3.0f;
216                                                 bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l_next].y) * scale / 3.0f;
217                                                 bezt->h2 = HD_VECT;
218                                         }
219
220                                         /* get the handles that are aligned, tricky...
221                                          * - check if one of them is a vector handle.
222                                          * - dist_squared_to_line_v2, check if the three beztriple points are on one line
223                                          * - len_squared_v2v2, see if there's a distance between the three points
224                                          * - len_squared_v2v2 again, to check the angle between the handles
225                                          */
226                                         if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) &&
227                                             (dist_squared_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) < (0.001f * 0.001f)) &&
228                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > eps_sq) &&
229                                             (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > eps_sq) &&
230                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > eps_sq) &&
231                                             (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) >
232                                              max_ff(len_squared_v2v2(bezt->vec[0], bezt->vec[1]),
233                                                     len_squared_v2v2(bezt->vec[1], bezt->vec[2]))))
234                                         {
235                                                 bezt->h1 = bezt->h2 = HD_ALIGN;
236                                         }
237                                         bezt->radius = 1.0f;
238                                         bezt++;
239                                 }
240                         }
241                 }
242
243                 MEM_freeN(onpoints);
244
245                 return che;
246         }
247
248         return NULL;
249 }
250
251 static VChar *objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
252 {
253         VChar *che;
254
255         /* Freetype2 */
256         FT_Face face;
257
258         /* Load the font to memory */
259         if (vfont->temp_pf) {
260                 err = FT_New_Memory_Face(library,
261                                          vfont->temp_pf->data,
262                                          vfont->temp_pf->size,
263                                          0,
264                                          &face);
265                 if (err) {
266                         return NULL;
267                 }
268         }
269         else {
270                 err = true;
271                 return NULL;
272         }
273
274         /* Read the char */
275         che = freetypechar_to_vchar(face, charcode, vfont->data);
276
277         /* And everything went ok */
278         return che;
279 }
280
281
282 static VFontData *objfnt_to_ftvfontdata(PackedFile *pf)
283 {
284         /* Variables */
285         FT_Face face;
286         const FT_ULong charcode_reserve = 256;
287         FT_ULong charcode = 0, lcode;
288         FT_UInt glyph_index;
289         const char *fontname;
290         VFontData *vfd;
291
292         /* load the freetype font */
293         err = FT_New_Memory_Face(library,
294                                  pf->data,
295                                  pf->size,
296                                  0,
297                                  &face);
298
299         if (err) {
300                 return NULL;
301         }
302
303         /* allocate blender font */
304         vfd = MEM_callocN(sizeof(*vfd), "FTVFontData");
305
306         /* get the name */
307         fontname = FT_Get_Postscript_Name(face);
308         BLI_strncpy(vfd->name, (fontname == NULL) ? "" : fontname, sizeof(vfd->name));
309
310         /* Extract the first 256 character from TTF */
311         lcode = charcode = FT_Get_First_Char(face, &glyph_index);
312
313         /* No charmap found from the ttf so we need to figure it out */
314         if (glyph_index == 0) {
315                 FT_CharMap found = NULL;
316                 FT_CharMap charmap;
317                 int n;
318
319                 for (n = 0; n < face->num_charmaps; n++) {
320                         charmap = face->charmaps[n];
321                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) {
322                                 found = charmap;
323                                 break;
324                         }
325                 }
326
327                 err = FT_Set_Charmap(face, found);
328
329                 if (err) {
330                         return NULL;
331                 }
332
333                 lcode = charcode = FT_Get_First_Char(face, &glyph_index);
334         }
335
336         /* Blender default BFont is not "complete". */
337         const bool complete_font = (face->ascender != 0) && (face->descender != 0) &&
338                                    (face->ascender != face->descender);
339
340         if (complete_font) {
341                 /* We can get descender as well, but we simple store descender in relation to the ascender.
342                  * Also note that descender is stored as a negative number. */
343                 vfd->ascender = (float)face->ascender / (face->ascender - face->descender);
344         }
345         else {
346                 vfd->ascender = 0.8f;
347                 vfd->em_height = 1.0f;
348         }
349
350         /* Adjust font size */
351         if (face->bbox.yMax != face->bbox.yMin) {
352                 vfd->scale = (float)(1.0 / (double)(face->bbox.yMax - face->bbox.yMin));
353
354                 if (complete_font) {
355                         vfd->em_height = (float)(face->ascender - face->descender) / (face->bbox.yMax - face->bbox.yMin);
356                 }
357         }
358         else {
359                 vfd->scale = 1.0f / 1000.0f;
360         }
361
362         /* Load characters */
363         vfd->characters = BLI_ghash_int_new_ex(__func__, charcode_reserve);
364
365         while (charcode < charcode_reserve) {
366                 /* Generate the font data */
367                 freetypechar_to_vchar(face, charcode, vfd);
368
369                 /* Next glyph */
370                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
371
372                 /* Check that we won't start infinite loop */
373                 if (charcode <= lcode) {
374                         break;
375                 }
376                 lcode = charcode;
377         }
378
379         return vfd;
380 }
381
382
383 static int check_freetypefont(PackedFile *pf)
384 {
385         FT_Face face;
386         FT_GlyphSlot glyph;
387         FT_UInt glyph_index;
388         int success = 0;
389
390         err = FT_New_Memory_Face(library,
391                                  pf->data,
392                                  pf->size,
393                                  0,
394                                  &face);
395         if (err) {
396                 success = 0;
397                 //XXX error("This is not a valid font");
398         }
399         else {
400                 glyph_index = FT_Get_Char_Index(face, 'A');
401                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
402                 if (err) {
403                         success = 0;
404                 }
405                 else {
406                         glyph = face->glyph;
407                         if (glyph->format == ft_glyph_format_outline) {
408                                 success = 1;
409                         }
410                         else {
411                                 //XXX error("Selected Font has no outline data");
412                                 success = 0;
413                         }
414                 }
415         }
416
417         return success;
418 }
419
420 /**
421  * Construct a new VFontData structure from
422  * Freetype font data in a PackedFile.
423  *
424  * \param pf: The font data.
425  * \retval A new VFontData structure, or NULL
426  * if unable to load.
427  */
428 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
429 {
430         VFontData *vfd = NULL;
431         int success = 0;
432
433         /* init Freetype */
434         err = FT_Init_FreeType(&library);
435         if (err) {
436                 /* XXX error("Failed to load the Freetype font library"); */
437                 return NULL;
438         }
439
440         success = check_freetypefont(pf);
441
442         if (success) {
443                 vfd = objfnt_to_ftvfontdata(pf);
444         }
445
446         /* free Freetype */
447         FT_Done_FreeType(library);
448
449         return vfd;
450 }
451
452 static void *vfontdata_copy_characters_value_cb(const void *src)
453 {
454         return BLI_vfontchar_copy(src, 0);
455 }
456
457 VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag))
458 {
459         VFontData *vfont_dst = MEM_dupallocN(vfont_src);
460
461         if (vfont_src->characters != NULL) {
462                 vfont_dst->characters = BLI_ghash_copy(vfont_src->characters, NULL, vfontdata_copy_characters_value_cb);
463         }
464
465         return vfont_dst;
466 }
467
468 VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
469 {
470         VChar *che = NULL;
471
472         if (!vfont) {
473                 return NULL;
474         }
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         /* Load the character */
484         che = objchr_to_ftvfontdata(vfont, character);
485
486         /* Free Freetype */
487         FT_Done_FreeType(library);
488
489         return che;
490 }
491
492 /* Yeah, this is very bad... But why is this in BLI in the first place, since it uses Nurb data?
493  * Anyway, do not feel like duplicating whole Nurb copy code here,
494  * so unless someone has a better idea... */
495 #include "../../blenkernel/BKE_curve.h"
496
497 VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag))
498 {
499         VChar *vchar_dst = MEM_dupallocN(vchar_src);
500
501         BLI_listbase_clear(&vchar_dst->nurbsbase);
502         BKE_nurbList_duplicate(&vchar_dst->nurbsbase, &vchar_src->nurbsbase);
503
504         return vchar_dst;
505 }
506
507
508 /*
509  * from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
510  *
511  * Vectorial representation of Freetype glyphs
512  *
513  * The source format of outlines is a collection of closed paths called "contours". Each contour is
514  * made of a series of line segments and bezier arcs. Depending on the file format, these can be
515  * second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
516  * they come from the TrueType format. The latter are called cubic arcs and mostly come from the
517  * Type1 format.
518  *
519  * Each arc is described through a series of start, end and control points. Each point of the outline
520  * has a specific tag which indicates whether it is used to describe a line segment or an arc.
521  * The following rules are applied to decompose the contour's points into segments and arcs :
522  *
523  * # two successive "on" points indicate a line segment joining them.
524  *
525  * # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
526  *   the control point, and the "on" ones the start and end points.
527  *
528  * # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
529  *   be exactly two cubic control points and two on points for each cubic arc (using a single cubic
530  *   "off" point between two "on" points is forbidden, for example).
531  *
532  * # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
533  *   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
534  *   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
535  *   outlines are described in the TrueType specification.
536  *
537  * Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
538  * font driver produces such outlines.
539  *
540  *                                   *            # on
541  *                                                * off
542  *                                __---__
543  *   #-__                      _--       -_
544  *       --__                _-            -
545  *           --__           #               \
546  *               --__                        #
547  *                   -#
548  *                            Two "on" points
549  *    Two "on" points       and one "conic" point
550  *                             between them
551  *                 *
552  *   #            __      Two "on" points with two "conic"
553  *    \          -  -     points between them. The point
554  *     \        /    \    marked '0' is the middle of the
555  *      -      0      \   "off" points, and is a 'virtual'
556  *       -_  _-       #   "on" point where the curve passes.
557  *         --             It does not appear in the point
558  *                        list.
559  *         *
560  *         *                # on
561  *                    *     * off
562  *          __---__
563  *       _--       -_
564  *     _-            -
565  *    #               \
566  *                     #
567  *
568  *      Two "on" points
569  *    and two "cubic" point
570  *       between them
571  * Each glyph's original outline points are located on a grid of indivisible units. The points are stored
572  * in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0, 0); they thus
573  * range from -16384 to 16383.
574  *
575  * Convert conic to bezier arcs:
576  * Conic P0 P1 P2
577  * Bezier B0 B1 B2 B3
578  * B0=P0
579  * B1=(P0+2*P1)/3
580  * B2=(P2+2*P1)/3
581  * B3=P2
582  */