• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2009  Red Hat, Inc.
3  * Copyright © 2009  Keith Stribley
4  * Copyright © 2015  Google, Inc.
5  *
6  *  This is part of HarfBuzz, a text shaping library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Red Hat Author(s): Behdad Esfahbod
27  * Google Author(s): Behdad Esfahbod
28  */
29 
30 #include "hb-private.hh"
31 #include "hb-debug.hh"
32 
33 #include "hb-ft.h"
34 
35 #include "hb-font-private.hh"
36 
37 #include FT_ADVANCES_H
38 #include FT_MULTIPLE_MASTERS_H
39 #include FT_TRUETYPE_TABLES_H
40 
41 
42 /* TODO:
43  *
44  * In general, this file does a fine job of what it's supposed to do.
45  * There are, however, things that need more work:
46  *
47  *   - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
48  *     Have not investigated.
49  *
50  *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
51  *     would work fine.  However, we also abuse this API for performing in font-space,
52  *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
53  *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
54  *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
55  *     ourselves, like we do in uniscribe, etc.
56  *
57  *   - We don't handle / allow for emboldening / obliqueing.
58  *
59  *   - In the future, we should add constructors to create fonts in font space?
60  *
61  *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
62  */
63 
64 
65 struct hb_ft_font_t
66 {
67   FT_Face ft_face;
68   int load_flags;
69   bool symbol; /* Whether selected cmap is symbol cmap. */
70   bool unref; /* Whether to destroy ft_face when done. */
71 };
72 
73 static hb_ft_font_t *
_hb_ft_font_create(FT_Face ft_face,bool symbol,bool unref)74 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
75 {
76   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
77 
78   if (unlikely (!ft_font))
79     return nullptr;
80 
81   ft_font->ft_face = ft_face;
82   ft_font->symbol = symbol;
83   ft_font->unref = unref;
84 
85   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
86 
87   return ft_font;
88 }
89 
90 static void
_hb_ft_face_destroy(void * data)91 _hb_ft_face_destroy (void *data)
92 {
93   FT_Done_Face ((FT_Face) data);
94 }
95 
96 static void
_hb_ft_font_destroy(void * data)97 _hb_ft_font_destroy (void *data)
98 {
99   hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
100 
101   if (ft_font->unref)
102     _hb_ft_face_destroy (ft_font->ft_face);
103 
104   free (ft_font);
105 }
106 
107 /**
108  * hb_ft_font_set_load_flags:
109  * @font:
110  * @load_flags:
111  *
112  *
113  *
114  * Since: 1.0.5
115  **/
116 void
hb_ft_font_set_load_flags(hb_font_t * font,int load_flags)117 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
118 {
119   if (font->immutable)
120     return;
121 
122   if (font->destroy != _hb_ft_font_destroy)
123     return;
124 
125   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
126 
127   ft_font->load_flags = load_flags;
128 }
129 
130 /**
131  * hb_ft_font_get_load_flags:
132  * @font:
133  *
134  *
135  *
136  * Return value:
137  * Since: 1.0.5
138  **/
139 int
hb_ft_font_get_load_flags(hb_font_t * font)140 hb_ft_font_get_load_flags (hb_font_t *font)
141 {
142   if (font->destroy != _hb_ft_font_destroy)
143     return 0;
144 
145   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
146 
147   return ft_font->load_flags;
148 }
149 
150 FT_Face
hb_ft_font_get_face(hb_font_t * font)151 hb_ft_font_get_face (hb_font_t *font)
152 {
153   if (font->destroy != _hb_ft_font_destroy)
154     return nullptr;
155 
156   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
157 
158   return ft_font->ft_face;
159 }
160 
161 
162 
163 static hb_bool_t
hb_ft_get_nominal_glyph(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t unicode,hb_codepoint_t * glyph,void * user_data HB_UNUSED)164 hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
165 			 void *font_data,
166 			 hb_codepoint_t unicode,
167 			 hb_codepoint_t *glyph,
168 			 void *user_data HB_UNUSED)
169 {
170   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
171   unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
172 
173   if (unlikely (!g))
174   {
175     if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
176     {
177       /* For symbol-encoded OpenType fonts, we duplicate the
178        * U+F000..F0FF range at U+0000..U+00FF.  That's what
179        * Windows seems to do, and that's hinted about at:
180        * http://www.microsoft.com/typography/otspec/recom.htm
181        * under "Non-Standard (Symbol) Fonts". */
182       g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
183       if (!g)
184 	return false;
185     }
186     else
187       return false;
188   }
189 
190   *glyph = g;
191   return true;
192 }
193 
194 static hb_bool_t
hb_ft_get_variation_glyph(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t unicode,hb_codepoint_t variation_selector,hb_codepoint_t * glyph,void * user_data HB_UNUSED)195 hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
196 			   void *font_data,
197 			   hb_codepoint_t unicode,
198 			   hb_codepoint_t variation_selector,
199 			   hb_codepoint_t *glyph,
200 			   void *user_data HB_UNUSED)
201 {
202   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
203   unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
204 
205   if (unlikely (!g))
206     return false;
207 
208   *glyph = g;
209   return true;
210 }
211 
212 static hb_position_t
hb_ft_get_glyph_h_advance(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t glyph,void * user_data HB_UNUSED)213 hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
214 			   void *font_data,
215 			   hb_codepoint_t glyph,
216 			   void *user_data HB_UNUSED)
217 {
218   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
219   FT_Fixed v;
220 
221   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
222     return 0;
223 
224   if (font->x_scale < 0)
225     v = -v;
226 
227   return (v + (1<<9)) >> 10;
228 }
229 
230 static hb_position_t
hb_ft_get_glyph_v_advance(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t glyph,void * user_data HB_UNUSED)231 hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
232 			   void *font_data,
233 			   hb_codepoint_t glyph,
234 			   void *user_data HB_UNUSED)
235 {
236   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
237   FT_Fixed v;
238 
239   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
240     return 0;
241 
242   if (font->y_scale < 0)
243     v = -v;
244 
245   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
246    * have a Y growing upward.  Hence the extra negation. */
247   return (-v + (1<<9)) >> 10;
248 }
249 
250 static hb_bool_t
hb_ft_get_glyph_v_origin(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t glyph,hb_position_t * x,hb_position_t * y,void * user_data HB_UNUSED)251 hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
252 			  void *font_data,
253 			  hb_codepoint_t glyph,
254 			  hb_position_t *x,
255 			  hb_position_t *y,
256 			  void *user_data HB_UNUSED)
257 {
258   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
259   FT_Face ft_face = ft_font->ft_face;
260 
261   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
262     return false;
263 
264   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
265    * have a Y growing upward.  Hence the extra negation. */
266   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
267   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
268 
269   if (font->x_scale < 0)
270     *x = -*x;
271   if (font->y_scale < 0)
272     *y = -*y;
273 
274   return true;
275 }
276 
277 static hb_position_t
hb_ft_get_glyph_h_kerning(hb_font_t * font,void * font_data,hb_codepoint_t left_glyph,hb_codepoint_t right_glyph,void * user_data HB_UNUSED)278 hb_ft_get_glyph_h_kerning (hb_font_t *font,
279 			   void *font_data,
280 			   hb_codepoint_t left_glyph,
281 			   hb_codepoint_t right_glyph,
282 			   void *user_data HB_UNUSED)
283 {
284   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
285   FT_Vector kerningv;
286 
287   FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
288   if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
289     return 0;
290 
291   return kerningv.x;
292 }
293 
294 static hb_bool_t
hb_ft_get_glyph_extents(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t glyph,hb_glyph_extents_t * extents,void * user_data HB_UNUSED)295 hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
296 			 void *font_data,
297 			 hb_codepoint_t glyph,
298 			 hb_glyph_extents_t *extents,
299 			 void *user_data HB_UNUSED)
300 {
301   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
302   FT_Face ft_face = ft_font->ft_face;
303 
304   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
305     return false;
306 
307   extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
308   extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
309   extents->width = ft_face->glyph->metrics.width;
310   extents->height = -ft_face->glyph->metrics.height;
311   if (font->x_scale < 0)
312   {
313     extents->x_bearing = -extents->x_bearing;
314     extents->width = -extents->width;
315   }
316   if (font->y_scale < 0)
317   {
318     extents->y_bearing = -extents->y_bearing;
319     extents->height = -extents->height;
320   }
321   return true;
322 }
323 
324 static hb_bool_t
hb_ft_get_glyph_contour_point(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t glyph,unsigned int point_index,hb_position_t * x,hb_position_t * y,void * user_data HB_UNUSED)325 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
326 			       void *font_data,
327 			       hb_codepoint_t glyph,
328 			       unsigned int point_index,
329 			       hb_position_t *x,
330 			       hb_position_t *y,
331 			       void *user_data HB_UNUSED)
332 {
333   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
334   FT_Face ft_face = ft_font->ft_face;
335 
336   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
337       return false;
338 
339   if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
340       return false;
341 
342   if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
343       return false;
344 
345   *x = ft_face->glyph->outline.points[point_index].x;
346   *y = ft_face->glyph->outline.points[point_index].y;
347 
348   return true;
349 }
350 
351 static hb_bool_t
hb_ft_get_glyph_name(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t glyph,char * name,unsigned int size,void * user_data HB_UNUSED)352 hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
353 		      void *font_data,
354 		      hb_codepoint_t glyph,
355 		      char *name, unsigned int size,
356 		      void *user_data HB_UNUSED)
357 {
358   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
359 
360   hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
361   if (ret && (size && !*name))
362     ret = false;
363 
364   return ret;
365 }
366 
367 static hb_bool_t
hb_ft_get_glyph_from_name(hb_font_t * font HB_UNUSED,void * font_data,const char * name,int len,hb_codepoint_t * glyph,void * user_data HB_UNUSED)368 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
369 			   void *font_data,
370 			   const char *name, int len, /* -1 means nul-terminated */
371 			   hb_codepoint_t *glyph,
372 			   void *user_data HB_UNUSED)
373 {
374   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
375   FT_Face ft_face = ft_font->ft_face;
376 
377   if (len < 0)
378     *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
379   else {
380     /* Make a nul-terminated version. */
381     char buf[128];
382     len = MIN (len, (int) sizeof (buf) - 1);
383     strncpy (buf, name, len);
384     buf[len] = '\0';
385     *glyph = FT_Get_Name_Index (ft_face, buf);
386   }
387 
388   if (*glyph == 0)
389   {
390     /* Check whether the given name was actually the name of glyph 0. */
391     char buf[128];
392     if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
393         len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
394       return true;
395   }
396 
397   return *glyph != 0;
398 }
399 
400 static hb_bool_t
hb_ft_get_font_h_extents(hb_font_t * font HB_UNUSED,void * font_data,hb_font_extents_t * metrics,void * user_data HB_UNUSED)401 hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
402 			  void *font_data,
403 			  hb_font_extents_t *metrics,
404 			  void *user_data HB_UNUSED)
405 {
406   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
407   FT_Face ft_face = ft_font->ft_face;
408   metrics->ascender = ft_face->size->metrics.ascender;
409   metrics->descender = ft_face->size->metrics.descender;
410   metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
411   if (font->y_scale < 0)
412   {
413     metrics->ascender = -metrics->ascender;
414     metrics->descender = -metrics->descender;
415     metrics->line_gap = -metrics->line_gap;
416   }
417   return true;
418 }
419 
420 static hb_font_funcs_t *static_ft_funcs = nullptr;
421 
422 #ifdef HB_USE_ATEXIT
423 static
free_static_ft_funcs(void)424 void free_static_ft_funcs (void)
425 {
426   hb_font_funcs_destroy (static_ft_funcs);
427 }
428 #endif
429 
430 static void
_hb_ft_font_set_funcs(hb_font_t * font,FT_Face ft_face,bool unref)431 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
432 {
433 retry:
434   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
435 
436   if (unlikely (!funcs))
437   {
438     funcs = hb_font_funcs_create ();
439 
440     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
441     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
442     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
443     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
444     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
445     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
446     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
447     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
448     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
449     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
450     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
451     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
452     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
453     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
454 
455     hb_font_funcs_make_immutable (funcs);
456 
457     if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
458       hb_font_funcs_destroy (funcs);
459       goto retry;
460     }
461 
462 #ifdef HB_USE_ATEXIT
463     atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
464 #endif
465   };
466 
467   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
468 
469   hb_font_set_funcs (font,
470 		     funcs,
471 		     _hb_ft_font_create (ft_face, symbol, unref),
472 		     _hb_ft_font_destroy);
473 }
474 
475 
476 static hb_blob_t *
reference_table(hb_face_t * face HB_UNUSED,hb_tag_t tag,void * user_data)477 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
478 {
479   FT_Face ft_face = (FT_Face) user_data;
480   FT_Byte *buffer;
481   FT_ULong  length = 0;
482   FT_Error error;
483 
484   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
485 
486   error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
487   if (error)
488     return nullptr;
489 
490   buffer = (FT_Byte *) malloc (length);
491   if (!buffer)
492     return nullptr;
493 
494   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
495   if (error)
496     return nullptr;
497 
498   return hb_blob_create ((const char *) buffer, length,
499 			 HB_MEMORY_MODE_WRITABLE,
500 			 buffer, free);
501 }
502 
503 /**
504  * hb_ft_face_create:
505  * @ft_face: (destroy destroy) (scope notified):
506  * @destroy:
507  *
508  *
509  *
510  * Return value: (transfer full):
511  * Since: 0.9.2
512  **/
513 hb_face_t *
hb_ft_face_create(FT_Face ft_face,hb_destroy_func_t destroy)514 hb_ft_face_create (FT_Face           ft_face,
515 		   hb_destroy_func_t destroy)
516 {
517   hb_face_t *face;
518 
519   if (!ft_face->stream->read) {
520     hb_blob_t *blob;
521 
522     blob = hb_blob_create ((const char *) ft_face->stream->base,
523 			   (unsigned int) ft_face->stream->size,
524 			   HB_MEMORY_MODE_READONLY,
525 			   ft_face, destroy);
526     face = hb_face_create (blob, ft_face->face_index);
527     hb_blob_destroy (blob);
528   } else {
529     face = hb_face_create_for_tables (reference_table, ft_face, destroy);
530   }
531 
532   hb_face_set_index (face, ft_face->face_index);
533   hb_face_set_upem (face, ft_face->units_per_EM);
534 
535   return face;
536 }
537 
538 /**
539  * hb_ft_face_create_referenced:
540  * @ft_face:
541  *
542  *
543  *
544  * Return value: (transfer full):
545  * Since: 0.9.38
546  **/
547 hb_face_t *
hb_ft_face_create_referenced(FT_Face ft_face)548 hb_ft_face_create_referenced (FT_Face ft_face)
549 {
550   FT_Reference_Face (ft_face);
551   return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
552 }
553 
554 static void
hb_ft_face_finalize(FT_Face ft_face)555 hb_ft_face_finalize (FT_Face ft_face)
556 {
557   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
558 }
559 
560 /**
561  * hb_ft_face_create_cached:
562  * @ft_face:
563  *
564  *
565  *
566  * Return value: (transfer full):
567  * Since: 0.9.2
568  **/
569 hb_face_t *
hb_ft_face_create_cached(FT_Face ft_face)570 hb_ft_face_create_cached (FT_Face ft_face)
571 {
572   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
573   {
574     if (ft_face->generic.finalizer)
575       ft_face->generic.finalizer (ft_face);
576 
577     ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
578     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
579   }
580 
581   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
582 }
583 
584 
585 /**
586  * hb_ft_font_create:
587  * @ft_face: (destroy destroy) (scope notified):
588  * @destroy:
589  *
590  *
591  *
592  * Return value: (transfer full):
593  * Since: 0.9.2
594  **/
595 hb_font_t *
hb_ft_font_create(FT_Face ft_face,hb_destroy_func_t destroy)596 hb_ft_font_create (FT_Face           ft_face,
597 		   hb_destroy_func_t destroy)
598 {
599   hb_font_t *font;
600   hb_face_t *face;
601 
602   face = hb_ft_face_create (ft_face, destroy);
603   font = hb_font_create (face);
604   hb_face_destroy (face);
605   _hb_ft_font_set_funcs (font, ft_face, false);
606   hb_ft_font_changed (font);
607   return font;
608 }
609 
610 void
hb_ft_font_changed(hb_font_t * font)611 hb_ft_font_changed (hb_font_t *font)
612 {
613   if (font->destroy != _hb_ft_font_destroy)
614     return;
615 
616   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
617   FT_Face ft_face = ft_font->ft_face;
618 
619   hb_font_set_scale (font,
620 		     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
621 		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
622 #if 0 /* hb-ft works in no-hinting model */
623   hb_font_set_ppem (font,
624 		    ft_face->size->metrics.x_ppem,
625 		    ft_face->size->metrics.y_ppem);
626 #endif
627 
628 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
629   FT_MM_Var *mm_var = nullptr;
630   if (!FT_Get_MM_Var (ft_face, &mm_var))
631   {
632     FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
633     int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
634     if (coords && ft_coords)
635     {
636       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
637       {
638 	for (unsigned int i = 0; i < mm_var->num_axis; ++i)
639 	  coords[i] = ft_coords[i] >>= 2;
640 
641 	hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
642       }
643     }
644     free (coords);
645     free (ft_coords);
646     free (mm_var);
647   }
648 #endif
649 }
650 
651 /**
652  * hb_ft_font_create_referenced:
653  * @ft_face:
654  *
655  *
656  *
657  * Return value: (transfer full):
658  * Since: 0.9.38
659  **/
660 hb_font_t *
hb_ft_font_create_referenced(FT_Face ft_face)661 hb_ft_font_create_referenced (FT_Face ft_face)
662 {
663   FT_Reference_Face (ft_face);
664   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
665 }
666 
667 
668 /* Thread-safe, lock-free, FT_Library */
669 
670 static FT_Library ft_library;
671 
672 #ifdef HB_USE_ATEXIT
673 static
free_ft_library(void)674 void free_ft_library (void)
675 {
676   FT_Done_FreeType (ft_library);
677 }
678 #endif
679 
680 static FT_Library
get_ft_library(void)681 get_ft_library (void)
682 {
683 retry:
684   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
685 
686   if (unlikely (!library))
687   {
688     /* Not found; allocate one. */
689     if (FT_Init_FreeType (&library))
690       return nullptr;
691 
692     if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
693       FT_Done_FreeType (library);
694       goto retry;
695     }
696 
697 #ifdef HB_USE_ATEXIT
698     atexit (free_ft_library); /* First person registers atexit() callback. */
699 #endif
700   }
701 
702   return library;
703 }
704 
705 static void
_release_blob(FT_Face ft_face)706 _release_blob (FT_Face ft_face)
707 {
708   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
709 }
710 
711 void
hb_ft_font_set_funcs(hb_font_t * font)712 hb_ft_font_set_funcs (hb_font_t *font)
713 {
714   hb_blob_t *blob = hb_face_reference_blob (font->face);
715   unsigned int blob_length;
716   const char *blob_data = hb_blob_get_data (blob, &blob_length);
717   if (unlikely (!blob_length))
718     DEBUG_MSG (FT, font, "Font face has empty blob");
719 
720   FT_Face ft_face = nullptr;
721   FT_Error err = FT_New_Memory_Face (get_ft_library (),
722 				     (const FT_Byte *) blob_data,
723 				     blob_length,
724 				     hb_face_get_index (font->face),
725 				     &ft_face);
726 
727   if (unlikely (err)) {
728     hb_blob_destroy (blob);
729     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
730     return;
731   }
732 
733   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
734     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
735 
736   FT_Set_Char_Size (ft_face,
737 		    abs (font->x_scale), abs (font->y_scale),
738 		    0, 0);
739 #if 0
740 		    font->x_ppem * 72 * 64 / font->x_scale,
741 		    font->y_ppem * 72 * 64 / font->y_scale);
742 #endif
743   if (font->x_scale < 0 || font->y_scale < 0)
744   {
745     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
746 			  0, font->y_scale < 0 ? -1 : +1};
747     FT_Set_Transform (ft_face, &matrix, nullptr);
748   }
749 
750 #ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
751   unsigned int num_coords;
752   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
753   if (num_coords)
754   {
755     FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
756     if (ft_coords)
757     {
758       for (unsigned int i = 0; i < num_coords; i++)
759 	ft_coords[i] = coords[i] << 2;
760       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
761       free (ft_coords);
762     }
763   }
764 #endif
765 
766   ft_face->generic.data = blob;
767   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
768 
769   _hb_ft_font_set_funcs (font, ft_face, true);
770   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
771 }
772