7caafba839f667138569dd35e96363f102690bb0
[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_destroy_func_t) _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_destroy_func_t) _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_destroy_func_t) _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        * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
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,
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,
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,
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,
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 retry:
427   hb_font_funcs_t *ft_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
428   if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, ft_funcs, nullptr))
429     goto retry;
430
431   hb_font_funcs_destroy (ft_funcs);
432 }
433 #endif
434
435 static void
436 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
437 {
438 retry:
439   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
440
441   if (unlikely (!funcs))
442   {
443     funcs = hb_font_funcs_create ();
444
445     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
446     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
447     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
448     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
449     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
450     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
451     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
452     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
453     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
454     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
455     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
456     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
457     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
458     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
459
460     hb_font_funcs_make_immutable (funcs);
461
462     if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
463       hb_font_funcs_destroy (funcs);
464       goto retry;
465     }
466
467 #ifdef HB_USE_ATEXIT
468     atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
469 #endif
470   };
471
472   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
473
474   hb_font_set_funcs (font,
475                      funcs,
476                      _hb_ft_font_create (ft_face, symbol, unref),
477                      _hb_ft_font_destroy);
478 }
479
480
481 static hb_blob_t *
482 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
483 {
484   FT_Face ft_face = (FT_Face) user_data;
485   FT_Byte *buffer;
486   FT_ULong  length = 0;
487   FT_Error error;
488
489   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
490
491   error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
492   if (error)
493     return nullptr;
494
495   buffer = (FT_Byte *) malloc (length);
496   if (!buffer)
497     return nullptr;
498
499   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
500   if (error)
501     return nullptr;
502
503   return hb_blob_create ((const char *) buffer, length,
504                          HB_MEMORY_MODE_WRITABLE,
505                          buffer, free);
506 }
507
508 /**
509  * hb_ft_face_create:
510  * @ft_face: (destroy destroy) (scope notified):
511  * @destroy:
512  *
513  *
514  *
515  * Return value: (transfer full):
516  * Since: 0.9.2
517  **/
518 hb_face_t *
519 hb_ft_face_create (FT_Face           ft_face,
520                    hb_destroy_func_t destroy)
521 {
522   hb_face_t *face;
523
524   if (!ft_face->stream->read) {
525     hb_blob_t *blob;
526
527     blob = hb_blob_create ((const char *) ft_face->stream->base,
528                            (unsigned int) ft_face->stream->size,
529                            HB_MEMORY_MODE_READONLY,
530                            ft_face, destroy);
531     face = hb_face_create (blob, ft_face->face_index);
532     hb_blob_destroy (blob);
533   } else {
534     face = hb_face_create_for_tables (reference_table, ft_face, destroy);
535   }
536
537   hb_face_set_index (face, ft_face->face_index);
538   hb_face_set_upem (face, ft_face->units_per_EM);
539
540   return face;
541 }
542
543 /**
544  * hb_ft_face_create_referenced:
545  * @ft_face:
546  *
547  *
548  *
549  * Return value: (transfer full):
550  * Since: 0.9.38
551  **/
552 hb_face_t *
553 hb_ft_face_create_referenced (FT_Face ft_face)
554 {
555   FT_Reference_Face (ft_face);
556   return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
557 }
558
559 static void
560 hb_ft_face_finalize (FT_Face ft_face)
561 {
562   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
563 }
564
565 /**
566  * hb_ft_face_create_cached:
567  * @ft_face:
568  *
569  *
570  *
571  * Return value: (transfer full):
572  * Since: 0.9.2
573  **/
574 hb_face_t *
575 hb_ft_face_create_cached (FT_Face ft_face)
576 {
577   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
578   {
579     if (ft_face->generic.finalizer)
580       ft_face->generic.finalizer (ft_face);
581
582     ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
583     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
584   }
585
586   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
587 }
588
589
590 /**
591  * hb_ft_font_create:
592  * @ft_face: (destroy destroy) (scope notified):
593  * @destroy:
594  *
595  *
596  *
597  * Return value: (transfer full):
598  * Since: 0.9.2
599  **/
600 hb_font_t *
601 hb_ft_font_create (FT_Face           ft_face,
602                    hb_destroy_func_t destroy)
603 {
604   hb_font_t *font;
605   hb_face_t *face;
606
607   face = hb_ft_face_create (ft_face, destroy);
608   font = hb_font_create (face);
609   hb_face_destroy (face);
610   _hb_ft_font_set_funcs (font, ft_face, false);
611   hb_ft_font_changed (font);
612   return font;
613 }
614
615 void
616 hb_ft_font_changed (hb_font_t *font)
617 {
618   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
619     return;
620
621   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
622   FT_Face ft_face = ft_font->ft_face;
623
624   hb_font_set_scale (font,
625                      (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
626                      (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
627 #if 0 /* hb-ft works in no-hinting model */
628   hb_font_set_ppem (font,
629                     ft_face->size->metrics.x_ppem,
630                     ft_face->size->metrics.y_ppem);
631 #endif
632
633 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
634   FT_MM_Var *mm_var = nullptr;
635   if (!FT_Get_MM_Var (ft_face, &mm_var))
636   {
637     FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
638     int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
639     if (coords && ft_coords)
640     {
641       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
642       {
643         bool nonzero = false;
644
645         for (unsigned int i = 0; i < mm_var->num_axis; ++i)
646          {
647           coords[i] = ft_coords[i] >>= 2;
648           nonzero = nonzero || coords[i];
649          }
650
651         if (nonzero)
652           hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
653         else
654           hb_font_set_var_coords_normalized (font, nullptr, 0);
655       }
656     }
657     free (coords);
658     free (ft_coords);
659 #ifdef HAVE_FT_DONE_MM_VAR
660     FT_Done_MM_Var (ft_face->glyph->library, mm_var);
661 #else
662     free (mm_var);
663 #endif
664   }
665 #endif
666 }
667
668 /**
669  * hb_ft_font_create_referenced:
670  * @ft_face:
671  *
672  *
673  *
674  * Return value: (transfer full):
675  * Since: 0.9.38
676  **/
677 hb_font_t *
678 hb_ft_font_create_referenced (FT_Face ft_face)
679 {
680   FT_Reference_Face (ft_face);
681   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
682 }
683
684
685 /* Thread-safe, lock-free, FT_Library */
686
687 static FT_Library ft_library;
688
689 #ifdef HB_USE_ATEXIT
690 static
691 void free_ft_library (void)
692 {
693 retry:
694   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
695   if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr))
696     goto retry;
697
698   FT_Done_FreeType (library);
699 }
700 #endif
701
702 static FT_Library
703 get_ft_library (void)
704 {
705 retry:
706   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
707
708   if (unlikely (!library))
709   {
710     /* Not found; allocate one. */
711     if (FT_Init_FreeType (&library))
712       return nullptr;
713
714     if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
715       FT_Done_FreeType (library);
716       goto retry;
717     }
718
719 #ifdef HB_USE_ATEXIT
720     atexit (free_ft_library); /* First person registers atexit() callback. */
721 #endif
722   }
723
724   return library;
725 }
726
727 static void
728 _release_blob (FT_Face ft_face)
729 {
730   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
731 }
732
733 void
734 hb_ft_font_set_funcs (hb_font_t *font)
735 {
736   hb_blob_t *blob = hb_face_reference_blob (font->face);
737   unsigned int blob_length;
738   const char *blob_data = hb_blob_get_data (blob, &blob_length);
739   if (unlikely (!blob_length))
740     DEBUG_MSG (FT, font, "Font face has empty blob");
741
742   FT_Face ft_face = nullptr;
743   FT_Error err = FT_New_Memory_Face (get_ft_library (),
744                                      (const FT_Byte *) blob_data,
745                                      blob_length,
746                                      hb_face_get_index (font->face),
747                                      &ft_face);
748
749   if (unlikely (err)) {
750     hb_blob_destroy (blob);
751     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
752     return;
753   }
754
755   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
756     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
757
758   FT_Set_Char_Size (ft_face,
759                     abs (font->x_scale), abs (font->y_scale),
760                     0, 0);
761 #if 0
762                     font->x_ppem * 72 * 64 / font->x_scale,
763                     font->y_ppem * 72 * 64 / font->y_scale);
764 #endif
765   if (font->x_scale < 0 || font->y_scale < 0)
766   {
767     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
768                           0, font->y_scale < 0 ? -1 : +1};
769     FT_Set_Transform (ft_face, &matrix, nullptr);
770   }
771
772 #ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
773   unsigned int num_coords;
774   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
775   if (num_coords)
776   {
777     FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
778     if (ft_coords)
779     {
780       for (unsigned int i = 0; i < num_coords; i++)
781         ft_coords[i] = coords[i] << 2;
782       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
783       free (ft_coords);
784     }
785   }
786 #endif
787
788   ft_face->generic.data = blob;
789   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
790
791   _hb_ft_font_set_funcs (font, ft_face, true);
792   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
793 }