Cleanup: remove redundant, invalid info from headers
[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 #if 0
288         FT_CharMap found = 0;
289         FT_CharMap charmap;
290         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
291         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
292         int n;
293 #endif
294
295         /* load the freetype font */
296         err = FT_New_Memory_Face(library,
297                                  pf->data,
298                                  pf->size,
299                                  0,
300                                  &face);
301
302         if (err) return NULL;
303
304 #if 0
305         for (n = 0; n < face->num_charmaps; n++)
306         {
307                 charmap = face->charmaps[n];
308                 if (charmap->platform_id == my_platform_id &&
309                     charmap->encoding_id == my_encoding_id)
310                 {
311                         found = charmap;
312                         break;
313                 }
314         }
315
316         if (!found) { return NULL; }
317
318         /* now, select the charmap for the face object */
319         err = FT_Set_Charmap(face, found);
320         if (err) { return NULL; }
321 #endif
322
323         /* allocate blender font */
324         vfd = MEM_callocN(sizeof(*vfd), "FTVFontData");
325
326         /* get the name */
327         fontname = FT_Get_Postscript_Name(face);
328         BLI_strncpy(vfd->name, (fontname == NULL) ? "" : fontname, sizeof(vfd->name));
329
330         /* Extract the first 256 character from TTF */
331         lcode = charcode = FT_Get_First_Char(face, &glyph_index);
332
333         /* No charmap found from the ttf so we need to figure it out */
334         if (glyph_index == 0) {
335                 FT_CharMap found = NULL;
336                 FT_CharMap charmap;
337                 int n;
338
339                 for (n = 0; n < face->num_charmaps; n++) {
340                         charmap = face->charmaps[n];
341                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN) {
342                                 found = charmap;
343                                 break;
344                         }
345                 }
346
347                 err = FT_Set_Charmap(face, found);
348
349                 if (err)
350                         return NULL;
351
352                 lcode = charcode = FT_Get_First_Char(face, &glyph_index);
353         }
354
355
356         /* Adjust font size */
357         if (face->bbox.yMax != face->bbox.yMin) {
358                 vfd->scale = (float)(1.0 / (double)(face->bbox.yMax - face->bbox.yMin));
359         }
360         else {
361                 vfd->scale = 1.0f / 1000.0f;
362         }
363
364         /* Load characters */
365         vfd->characters = BLI_ghash_int_new_ex(__func__, charcode_reserve);
366
367         while (charcode < charcode_reserve) {
368                 /* Generate the font data */
369                 freetypechar_to_vchar(face, charcode, vfd);
370
371                 /* Next glyph */
372                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
373
374                 /* Check that we won't start infinite loop */
375                 if (charcode <= lcode)
376                         break;
377                 lcode = charcode;
378         }
379
380         return vfd;
381 }
382
383
384 static int check_freetypefont(PackedFile *pf)
385 {
386         FT_Face face;
387         FT_GlyphSlot glyph;
388         FT_UInt glyph_index;
389 #if 0
390         FT_CharMap charmap;
391         FT_CharMap found;
392         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
393         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
394         int n;
395 #endif
396         int success = 0;
397
398         err = FT_New_Memory_Face(library,
399                                  pf->data,
400                                  pf->size,
401                                  0,
402                                  &face);
403         if (err) {
404                 success = 0;
405                 //XXX error("This is not a valid font");
406         }
407         else {
408
409 #if 0
410                 for (n = 0; n < face->num_charmaps; n++) {
411                         charmap = face->charmaps[n];
412                         if (charmap->platform_id == my_platform_id && charmap->encoding_id == my_encoding_id) {
413                                 found = charmap;
414                                 break;
415                         }
416                 }
417
418                 if (!found) { return 0; }
419
420                 /* now, select the charmap for the face object */
421                 err = FT_Set_Charmap(face, found);
422                 if (err) { return 0; }
423 #endif
424
425                 glyph_index = FT_Get_Char_Index(face, 'A');
426                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
427                 if (err) {
428                         success = 0;
429                 }
430                 else {
431                         glyph = face->glyph;
432                         if (glyph->format == ft_glyph_format_outline) {
433                                 success = 1;
434                         }
435                         else {
436                                 //XXX error("Selected Font has no outline data");
437                                 success = 0;
438                         }
439                 }
440         }
441
442         return success;
443 }
444
445 /**
446  * Construct a new VFontData structure from
447  * Freetype font data in a PackedFile.
448  *
449  * \param pf: The font data.
450  * \retval A new VFontData structure, or NULL
451  * if unable to load.
452  */
453 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
454 {
455         VFontData *vfd = NULL;
456         int success = 0;
457
458         /* init Freetype */
459         err = FT_Init_FreeType(&library);
460         if (err) {
461                 /* XXX error("Failed to load the Freetype font library"); */
462                 return NULL;
463         }
464
465         success = check_freetypefont(pf);
466
467         if (success) {
468                 vfd = objfnt_to_ftvfontdata(pf);
469         }
470
471         /* free Freetype */
472         FT_Done_FreeType(library);
473
474         return vfd;
475 }
476
477 static void *vfontdata_copy_characters_value_cb(const void *src)
478 {
479         return BLI_vfontchar_copy(src, 0);
480 }
481
482 VFontData *BLI_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag))
483 {
484         VFontData *vfont_dst = MEM_dupallocN(vfont_src);
485
486         if (vfont_src->characters != NULL) {
487                 vfont_dst->characters = BLI_ghash_copy(vfont_src->characters, NULL, vfontdata_copy_characters_value_cb);
488         }
489
490         return vfont_dst;
491 }
492
493 VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
494 {
495         VChar *che = NULL;
496
497         if (!vfont) return NULL;
498
499         /* Init Freetype */
500         err = FT_Init_FreeType(&library);
501         if (err) {
502                 /* XXX error("Failed to load the Freetype font library"); */
503                 return NULL;
504         }
505
506         /* Load the character */
507         che = objchr_to_ftvfontdata(vfont, character);
508
509         /* Free Freetype */
510         FT_Done_FreeType(library);
511
512         return che;
513 }
514
515 /* Yeah, this is very bad... But why is this in BLI in the first place, since it uses Nurb data?
516  * Anyway, do not feel like duplicating whole Nurb copy code here,
517  * so unless someone has a better idea... */
518 #include "../../blenkernel/BKE_curve.h"
519
520 VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag))
521 {
522         VChar *vchar_dst = MEM_dupallocN(vchar_src);
523
524         BLI_listbase_clear(&vchar_dst->nurbsbase);
525         BKE_nurbList_duplicate(&vchar_dst->nurbsbase, &vchar_src->nurbsbase);
526
527         return vchar_dst;
528 }
529
530 #if 0
531
532 /* Freetype2 Outline struct */
533
534 typedef struct  FT_Outline_ {
535         short       n_contours;      /* number of contours in glyph        */
536         short       n_points;        /* number of points in the glyph      */
537
538         FT_Vector  *points;          /* the outline's points               */
539         char       *tags;            /* the points flags                   */
540         short      *contours;        /* the contour end points             */
541
542         int         flags;           /* outline masks                      */
543 } FT_Outline;
544
545 #endif
546
547 /*
548  * from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
549  *
550  * Vectorial representation of Freetype glyphs
551  *
552  * The source format of outlines is a collection of closed paths called "contours". Each contour is
553  * made of a series of line segments and bezier arcs. Depending on the file format, these can be
554  * second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
555  * they come from the TrueType format. The latter are called cubic arcs and mostly come from the
556  * Type1 format.
557  *
558  * Each arc is described through a series of start, end and control points. Each point of the outline
559  * has a specific tag which indicates whether it is used to describe a line segment or an arc.
560  * The following rules are applied to decompose the contour's points into segments and arcs :
561  *
562  * # two successive "on" points indicate a line segment joining them.
563  *
564  * # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
565  *   the control point, and the "on" ones the start and end points.
566  *
567  * # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
568  *   be exactly two cubic control points and two on points for each cubic arc (using a single cubic
569  *   "off" point between two "on" points is forbidden, for example).
570  *
571  * # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
572  *   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
573  *   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
574  *   outlines are described in the TrueType specification.
575  *
576  * Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
577  * font driver produces such outlines.
578  *
579  *                                   *            # on
580  *                                                * off
581  *                                __---__
582  *   #-__                      _--       -_
583  *       --__                _-            -
584  *           --__           #               \
585  *               --__                        #
586  *                   -#
587  *                            Two "on" points
588  *    Two "on" points       and one "conic" point
589  *                             between them
590  *                 *
591  *   #            __      Two "on" points with two "conic"
592  *    \          -  -     points between them. The point
593  *     \        /    \    marked '0' is the middle of the
594  *      -      0      \   "off" points, and is a 'virtual'
595  *       -_  _-       #   "on" point where the curve passes.
596  *         --             It does not appear in the point
597  *                        list.
598  *         *
599  *         *                # on
600  *                    *     * off
601  *          __---__
602  *       _--       -_
603  *     _-            -
604  *    #               \
605  *                     #
606  *
607  *      Two "on" points
608  *    and two "cubic" point
609  *       between them
610  * Each glyph's original outline points are located on a grid of indivisible units. The points are stored
611  * in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0, 0); they thus
612  * range from -16384 to 16383.
613  *
614  * Convert conic to bezier arcs:
615  * Conic P0 P1 P2
616  * Bezier B0 B1 B2 B3
617  * B0=P0
618  * B1=(P0+2*P1)/3
619  * B2=(P2+2*P1)/3
620  * B3=P2
621  */