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