Blender  V3.3
vfontdata_freetype.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * The Original Code is written by Rob Haarsma (phase). All rights reserved. */
3 
13 #include <ft2build.h>
14 #include FT_FREETYPE_H
15 /* not needed yet */
16 // #include FT_GLYPH_H
17 // #include FT_BBOX_H
18 // #include FT_SIZES_H
19 // #include <freetype/ttnameid.h>
20 
21 #include "MEM_guardedalloc.h"
22 
23 #include "BLI_ghash.h"
24 #include "BLI_listbase.h"
25 #include "BLI_math.h"
26 #include "BLI_string.h"
27 #include "BLI_string_utf8.h"
28 #include "BLI_utildefines.h"
29 
30 #include "BKE_curve.h"
31 #include "BKE_vfontdata.h"
32 
33 #include "DNA_curve_types.h"
34 #include "DNA_packedFile_types.h"
35 #include "DNA_vfont_types.h"
36 
37 /* local variables */
38 static FT_Library library;
39 static FT_Error err;
40 
41 static VChar *freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
42 {
43  const float scale = vfd->scale;
44  const float eps = 0.0001f;
45  const float eps_sq = eps * eps;
46  /* Blender */
47  struct Nurb *nu;
48  struct VChar *che;
49  struct BezTriple *bezt;
50 
51  /* Freetype2 */
52  FT_GlyphSlot glyph;
53  FT_UInt glyph_index;
54  FT_Outline ftoutline;
55  float dx, dy;
56  int j, k, l, l_first = 0;
57 
58  /*
59  * Generate the character 3D data
60  *
61  * Get the FT Glyph index and load the Glyph */
62  glyph_index = FT_Get_Char_Index(face, charcode);
63  err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
64 
65  /* If loading succeeded, convert the FT glyph to the internal format */
66  if (!err) {
67  /* initialize as -1 to add 1 on first loop each time */
68  int contour_prev;
69  int *onpoints;
70 
71  /* First we create entry for the new character to the character list */
72  che = (VChar *)MEM_callocN(sizeof(struct VChar), "objfnt_char");
73 
74  /* Take some data for modifying purposes */
75  glyph = face->glyph;
76  ftoutline = glyph->outline;
77 
78  /* Set the width and character code */
79  che->index = charcode;
80  che->width = glyph->advance.x * scale;
81 
83 
84  /* Start converting the FT data */
85  onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints");
86 
87  /* Get number of on-curve points for bezier-triples (including conic virtual on-points). */
88  for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
89  const int n = ftoutline.contours[j] - contour_prev;
90  contour_prev = ftoutline.contours[j];
91 
92  for (k = 0; k < n; k++) {
93  l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
94  if (k == 0) {
95  l_first = l;
96  }
97 
98  if (ftoutline.tags[l] == FT_Curve_Tag_On) {
99  onpoints[j]++;
100  }
101 
102  {
103  const int l_next = (k < n - 1) ? (l + 1) : l_first;
104  if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
105  ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
106  onpoints[j]++;
107  }
108  }
109  }
110  }
111 
112  /* contour loop, bezier & conic styles merged */
113  for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
114  const int n = ftoutline.contours[j] - contour_prev;
115  contour_prev = ftoutline.contours[j];
116 
117  /* add new curve */
118  nu = (Nurb *)MEM_callocN(sizeof(struct Nurb), "objfnt_nurb");
119  bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt");
120  BLI_addtail(&che->nurbsbase, nu);
121 
122  nu->type = CU_BEZIER;
123  nu->pntsu = onpoints[j];
124  nu->resolu = 8;
125  nu->flagu = CU_NURB_CYCLIC;
126  nu->bezt = bezt;
127 
128  /* individual curve loop, start-end */
129  for (k = 0; k < n; k++) {
130  l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
131  if (k == 0) {
132  l_first = l;
133  }
134 
135  /* virtual conic on-curve points */
136  {
137  const int l_next = (k < n - 1) ? (l + 1) : l_first;
138  if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
139  ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
140  dx = (ftoutline.points[l].x + ftoutline.points[l_next].x) * scale / 2.0f;
141  dy = (ftoutline.points[l].y + ftoutline.points[l_next].y) * scale / 2.0f;
142 
143  /* left handle */
144  bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x) * scale) / 3.0f;
145  bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y) * scale) / 3.0f;
146 
147  /* midpoint (virtual on-curve point) */
148  bezt->vec[1][0] = dx;
149  bezt->vec[1][1] = dy;
150 
151  /* right handle */
152  bezt->vec[2][0] = (dx + (2 * ftoutline.points[l_next].x) * scale) / 3.0f;
153  bezt->vec[2][1] = (dy + (2 * ftoutline.points[l_next].y) * scale) / 3.0f;
154 
155  bezt->h1 = bezt->h2 = HD_ALIGN;
156  bezt->radius = 1.0f;
157  bezt++;
158  }
159  }
160 
161  /* on-curve points */
162  if (ftoutline.tags[l] == FT_Curve_Tag_On) {
163  const int l_prev = (k > 0) ? (l - 1) : ftoutline.contours[j];
164  const int l_next = (k < n - 1) ? (l + 1) : l_first;
165 
166  /* left handle */
167  if (ftoutline.tags[l_prev] == FT_Curve_Tag_Cubic) {
168  bezt->vec[0][0] = ftoutline.points[l_prev].x * scale;
169  bezt->vec[0][1] = ftoutline.points[l_prev].y * scale;
170  bezt->h1 = HD_FREE;
171  }
172  else if (ftoutline.tags[l_prev] == FT_Curve_Tag_Conic) {
173  bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l_prev].x)) * scale /
174  3.0f;
175  bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l_prev].y)) * scale /
176  3.0f;
177  bezt->h1 = HD_FREE;
178  }
179  else {
180  bezt->vec[0][0] = ftoutline.points[l].x * scale -
181  (ftoutline.points[l].x - ftoutline.points[l_prev].x) * scale / 3.0f;
182  bezt->vec[0][1] = ftoutline.points[l].y * scale -
183  (ftoutline.points[l].y - ftoutline.points[l_prev].y) * scale / 3.0f;
184  bezt->h1 = HD_VECT;
185  }
186 
187  /* midpoint (on-curve point) */
188  bezt->vec[1][0] = ftoutline.points[l].x * scale;
189  bezt->vec[1][1] = ftoutline.points[l].y * scale;
190 
191  /* right handle */
192  if (ftoutline.tags[l_next] == FT_Curve_Tag_Cubic) {
193  bezt->vec[2][0] = ftoutline.points[l_next].x * scale;
194  bezt->vec[2][1] = ftoutline.points[l_next].y * scale;
195  bezt->h2 = HD_FREE;
196  }
197  else if (ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
198  bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l_next].x)) * scale /
199  3.0f;
200  bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l_next].y)) * scale /
201  3.0f;
202  bezt->h2 = HD_FREE;
203  }
204  else {
205  bezt->vec[2][0] = ftoutline.points[l].x * scale -
206  (ftoutline.points[l].x - ftoutline.points[l_next].x) * scale / 3.0f;
207  bezt->vec[2][1] = ftoutline.points[l].y * scale -
208  (ftoutline.points[l].y - ftoutline.points[l_next].y) * scale / 3.0f;
209  bezt->h2 = HD_VECT;
210  }
211 
212  /* get the handles that are aligned, tricky...
213  * - check if one of them is a vector handle.
214  * - dist_squared_to_line_v2, check if the three beztriple points are on one line
215  * - len_squared_v2v2, see if there's a distance between the three points
216  * - len_squared_v2v2 again, to check the angle between the handles
217  */
218  if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) &&
219  (dist_squared_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) <
220  (0.001f * 0.001f)) &&
221  (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > eps_sq) &&
222  (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > eps_sq) &&
223  (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > eps_sq) &&
224  (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) >
225  max_ff(len_squared_v2v2(bezt->vec[0], bezt->vec[1]),
226  len_squared_v2v2(bezt->vec[1], bezt->vec[2])))) {
227  bezt->h1 = bezt->h2 = HD_ALIGN;
228  }
229  bezt->radius = 1.0f;
230  bezt++;
231  }
232  }
233  }
234 
235  MEM_freeN(onpoints);
236 
237  return che;
238  }
239 
240  return NULL;
241 }
242 
243 static VChar *objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
244 {
245  VChar *che;
246 
247  /* Freetype2 */
248  FT_Face face;
249 
250  /* Load the font to memory */
251  if (vfont->temp_pf) {
252  err = FT_New_Memory_Face(library, vfont->temp_pf->data, vfont->temp_pf->size, 0, &face);
253  if (err) {
254  return NULL;
255  }
256  }
257  else {
258  err = true;
259  return NULL;
260  }
261 
262  /* Read the char */
263  che = freetypechar_to_vchar(face, charcode, vfont->data);
264 
265  /* And everything went ok */
266  return che;
267 }
268 
270 {
271  /* Variables */
272  FT_Face face;
273  const FT_ULong charcode_reserve = 256;
274  FT_ULong charcode = 0, lcode;
275  FT_UInt glyph_index;
276  VFontData *vfd;
277 
278  /* load the freetype font */
279  err = FT_New_Memory_Face(library, pf->data, pf->size, 0, &face);
280 
281  if (err) {
282  return NULL;
283  }
284 
285  /* allocate blender font */
286  vfd = MEM_callocN(sizeof(*vfd), "FTVFontData");
287 
288  /* Get the name. */
289  if (face->family_name) {
290  BLI_snprintf(vfd->name, sizeof(vfd->name), "%s %s", face->family_name, face->style_name);
291  BLI_str_utf8_invalid_strip(vfd->name, strlen(vfd->name));
292  }
293 
294  /* Select a character map. */
295  err = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
296  if (err) {
297  err = FT_Select_Charmap(face, FT_ENCODING_APPLE_ROMAN);
298  }
299  if (err && face->num_charmaps > 0) {
300  err = FT_Select_Charmap(face, face->charmaps[0]->encoding);
301  }
302  if (err) {
303  FT_Done_Face(face);
304  MEM_freeN(vfd);
305  return NULL;
306  }
307 
308  /* Extract the first 256 character from TTF */
309  lcode = charcode = FT_Get_First_Char(face, &glyph_index);
310 
311  /* Blender default BFont is not "complete". */
312  const bool complete_font = (face->ascender != 0) && (face->descender != 0) &&
313  (face->ascender != face->descender);
314 
315  if (complete_font) {
316  /* We can get descender as well, but we simple store descender in relation to the ascender.
317  * Also note that descender is stored as a negative number. */
318  vfd->ascender = (float)face->ascender / (face->ascender - face->descender);
319  }
320  else {
321  vfd->ascender = 0.8f;
322  vfd->em_height = 1.0f;
323  }
324 
325  /* Adjust font size */
326  if (face->bbox.yMax != face->bbox.yMin) {
327  vfd->scale = (float)(1.0 / (double)(face->bbox.yMax - face->bbox.yMin));
328 
329  if (complete_font) {
330  vfd->em_height = (float)(face->ascender - face->descender) /
331  (face->bbox.yMax - face->bbox.yMin);
332  }
333  }
334  else {
335  vfd->scale = 1.0f / 1000.0f;
336  }
337 
338  /* Load characters */
339  vfd->characters = BLI_ghash_int_new_ex(__func__, charcode_reserve);
340 
341  while (charcode < charcode_reserve) {
342  /* Generate the font data */
343  freetypechar_to_vchar(face, charcode, vfd);
344 
345  /* Next glyph */
346  charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
347 
348  /* Check that we won't start infinite loop */
349  if (charcode <= lcode) {
350  break;
351  }
352  lcode = charcode;
353  }
354 
355  return vfd;
356 }
357 
359 {
360  FT_Face face = NULL;
361  FT_UInt glyph_index = 0;
362  bool success = false;
363 
364  err = FT_New_Memory_Face(library, pf->data, pf->size, 0, &face);
365  if (err) {
366  return false;
367  // XXX error("This is not a valid font");
368  }
369 
370  FT_Get_First_Char(face, &glyph_index);
371  if (glyph_index) {
372  err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
373  if (!err) {
374  success = (face->glyph->format == ft_glyph_format_outline);
375  }
376  }
377 
378  FT_Done_Face(face);
379 
380  return success;
381 }
382 
384 {
385  VFontData *vfd = NULL;
386 
387  /* init Freetype */
388  err = FT_Init_FreeType(&library);
389  if (err) {
390  /* XXX error("Failed to load the Freetype font library"); */
391  return NULL;
392  }
393 
394  if (check_freetypefont(pf)) {
395  vfd = objfnt_to_ftvfontdata(pf);
396  }
397 
398  /* free Freetype */
399  FT_Done_FreeType(library);
400 
401  return vfd;
402 }
403 
404 static void *vfontdata_copy_characters_value_cb(const void *src)
405 {
407 }
408 
409 VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag))
410 {
411  VFontData *vfont_dst = MEM_dupallocN(vfont_src);
412 
413  if (vfont_src->characters != NULL) {
414  vfont_dst->characters = BLI_ghash_copy(
416  }
417 
418  return vfont_dst;
419 }
420 
421 VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, unsigned long character)
422 {
423  VChar *che = NULL;
424 
425  if (!vfont) {
426  return NULL;
427  }
428 
429  /* Init Freetype */
430  err = FT_Init_FreeType(&library);
431  if (err) {
432  /* XXX error("Failed to load the Freetype font library"); */
433  return NULL;
434  }
435 
436  /* Load the character */
437  che = objchr_to_ftvfontdata(vfont, character);
438 
439  /* Free Freetype */
440  FT_Done_FreeType(library);
441 
442  return che;
443 }
444 
446 {
447  VChar *vchar_dst = MEM_dupallocN(vchar_src);
448 
449  BLI_listbase_clear(&vchar_dst->nurbsbase);
450  BKE_nurbList_duplicate(&vchar_dst->nurbsbase, &vchar_src->nurbsbase);
451 
452  return vchar_dst;
453 }
454 
typedef float(TangentPoint)[2]
void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2)
A structure to represent vector fonts, and to load them from PostScript fonts.
GHash * BLI_ghash_int_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
GHash * BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:694
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE float max_ff(float a, float b)
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:270
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1)
Definition: string_utf8.c:181
#define UNUSED(x)
#define POINTER_FROM_UINT(i)
@ CU_BEZIER
@ CU_NURB_CYCLIC
@ HD_VECT
@ HD_FREE
@ HD_ALIGN
struct BezTriple BezTriple
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMLoop * l
SyclQueue void void * src
#define pf(_x, _i)
Prefetch 64.
Definition: gim_memory.h:48
flat(Type::VEC4, "color_flat") .no_perspective(Type col offset fragColor glyph
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
const btScalar eps
Definition: poly34.cpp:11
uint8_t h1
float vec[3][3]
uint8_t h2
short flagu
short type
BezTriple * bezt
short resolu
float width
Definition: BKE_vfontdata.h:33
ListBase nurbsbase
Definition: BKE_vfontdata.h:31
unsigned int index
Definition: BKE_vfontdata.h:32
float scale
Definition: BKE_vfontdata.h:24
float ascender
Definition: BKE_vfontdata.h:27
struct GHash * characters
Definition: BKE_vfontdata.h:22
char name[128]
Definition: BKE_vfontdata.h:23
float em_height
Definition: BKE_vfontdata.h:26
struct VFontData * data
struct PackedFile * temp_pf
static bool check_freetypefont(PackedFile *pf)
VFontData * BKE_vfontdata_from_freetypefont(PackedFile *pf)
static VChar * objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
VChar * BKE_vfontdata_char_copy(const VChar *vchar_src)
VFontData * BKE_vfontdata_copy(const VFontData *vfont_src, const int UNUSED(flag))
static void * vfontdata_copy_characters_value_cb(const void *src)
static FT_Library library
static FT_Error err
VChar * BKE_vfontdata_char_from_freetypefont(VFont *vfont, unsigned long character)
static VFontData * objfnt_to_ftvfontdata(PackedFile *pf)
static VChar * freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)