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