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