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