Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-ft.cc
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 extremely 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 *
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
91 _hb_ft_face_destroy (void *data)
92 {
93   FT_Done_Face ((FT_Face) data);
94 }
95
96 static void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
424 void free_static_ft_funcs (void)
425 {
426   hb_font_funcs_destroy (static_ft_funcs);
427 }
428 #endif
429
430 static void
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 *
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 *
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 *
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
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 *
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 *
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
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         bool nonzero = false;
639
640         for (unsigned int i = 0; i < mm_var->num_axis; ++i)
641          {
642           coords[i] = ft_coords[i] >>= 2;
643           nonzero = nonzero || coords[i];
644          }
645
646         if (nonzero)
647           hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
648         else
649           hb_font_set_var_coords_normalized (font, nullptr, 0);
650       }
651     }
652     free (coords);
653     free (ft_coords);
654 #ifdef HAVE_FT_DONE_MM_VAR
655     FT_Done_MM_Var (ft_face->glyph->library, mm_var);
656 #else
657     free (mm_var);
658 #endif
659   }
660 #endif
661 }
662
663 /**
664  * hb_ft_font_create_referenced:
665  * @ft_face:
666  *
667  * 
668  *
669  * Return value: (transfer full): 
670  * Since: 0.9.38
671  **/
672 hb_font_t *
673 hb_ft_font_create_referenced (FT_Face ft_face)
674 {
675   FT_Reference_Face (ft_face);
676   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
677 }
678
679
680 /* Thread-safe, lock-free, FT_Library */
681
682 static FT_Library ft_library;
683
684 #ifdef HB_USE_ATEXIT
685 static
686 void free_ft_library (void)
687 {
688   FT_Done_FreeType (ft_library);
689 }
690 #endif
691
692 static FT_Library
693 get_ft_library (void)
694 {
695 retry:
696   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
697
698   if (unlikely (!library))
699   {
700     /* Not found; allocate one. */
701     if (FT_Init_FreeType (&library))
702       return nullptr;
703
704     if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
705       FT_Done_FreeType (library);
706       goto retry;
707     }
708
709 #ifdef HB_USE_ATEXIT
710     atexit (free_ft_library); /* First person registers atexit() callback. */
711 #endif
712   }
713
714   return library;
715 }
716
717 static void
718 _release_blob (FT_Face ft_face)
719 {
720   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
721 }
722
723 void
724 hb_ft_font_set_funcs (hb_font_t *font)
725 {
726   hb_blob_t *blob = hb_face_reference_blob (font->face);
727   unsigned int blob_length;
728   const char *blob_data = hb_blob_get_data (blob, &blob_length);
729   if (unlikely (!blob_length))
730     DEBUG_MSG (FT, font, "Font face has empty blob");
731
732   FT_Face ft_face = nullptr;
733   FT_Error err = FT_New_Memory_Face (get_ft_library (),
734                                      (const FT_Byte *) blob_data,
735                                      blob_length,
736                                      hb_face_get_index (font->face),
737                                      &ft_face);
738
739   if (unlikely (err)) {
740     hb_blob_destroy (blob);
741     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
742     return;
743   }
744
745   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
746     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
747
748   FT_Set_Char_Size (ft_face,
749                     abs (font->x_scale), abs (font->y_scale),
750                     0, 0);
751 #if 0
752                     font->x_ppem * 72 * 64 / font->x_scale,
753                     font->y_ppem * 72 * 64 / font->y_scale);
754 #endif
755   if (font->x_scale < 0 || font->y_scale < 0)
756   {
757     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
758                           0, font->y_scale < 0 ? -1 : +1};
759     FT_Set_Transform (ft_face, &matrix, nullptr);
760   }
761
762 #ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
763   unsigned int num_coords;
764   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
765   if (num_coords)
766   {
767     FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
768     if (ft_coords)
769     {
770       for (unsigned int i = 0; i < num_coords; i++)
771         ft_coords[i] = coords[i] << 2;
772       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
773       free (ft_coords);
774     }
775   }
776 #endif
777
778   ft_face->generic.data = blob;
779   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
780
781   _hb_ft_font_set_funcs (font, ft_face, true);
782   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
783 }