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