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 
  32 #include "hb-ft.h"
  33 
  34 #include "hb-font-private.hh"
  35 
  36 #include "hb-cache-private.hh" // Maybe use in the future?
  37 
  38 #include FT_ADVANCES_H
  39 #include FT_MULTIPLE_MASTERS_H
  40 #include FT_TRUETYPE_TABLES_H
  41 
  42 
  43 
  44 #ifndef HB_DEBUG_FT
  45 #define HB_DEBUG_FT (HB_DEBUG+0)
  46 #endif
  47 
  48 
  49 /* TODO:
  50  *
  51  * In general, this file does a fine job of what it's supposed to do.
  52  * There are, however, things that need more work:
  53  *
  54  *   - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
  55  *     Have not investigated.
  56  *
  57  *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
  58  *     would work fine.  However, we also abuse this API for performing in font-space,
  59  *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
  60  *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
  61  *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
  62  *     ourselves, like we do in uniscribe, etc.
  63  *
  64  *   - We don't handle / allow for emboldening / obliqueing.
  65  *
  66  *   - In the future, we should add constructors to create fonts in font space?
  67  *
  68  *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
  69  */
  70 
  71 
  72 struct hb_ft_font_t
  73 {
  74   FT_Face ft_face;
  75   int load_flags;
  76   bool symbol; /* Whether selected cmap is symbol cmap. */
  77   bool unref; /* Whether to destroy ft_face when done. */
  78 };
  79 
  80 static hb_ft_font_t *
  81 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
  82 {
  83   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
  84 
  85   if (unlikely (!ft_font))
  86     return NULL;
  87 
  88   ft_font->ft_face = ft_face;
  89   ft_font->symbol = symbol;
  90   ft_font->unref = unref;
  91 
  92   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
  93 
  94   return ft_font;
  95 }
  96 
  97 static void
  98 _hb_ft_face_destroy (FT_Face ft_face)
  99 {
 100   FT_Done_Face (ft_face);
 101 }
 102 
 103 static void
 104 _hb_ft_font_destroy (hb_ft_font_t *ft_font)
 105 {
 106   if (ft_font->unref)
 107     _hb_ft_face_destroy (ft_font->ft_face);
 108 
 109   free (ft_font);
 110 }
 111 
 112 /**
 113  * hb_ft_font_set_load_flags:
 114  * @font:
 115  * @load_flags:
 116  *
 117  * 
 118  *
 119  * Since: 1.0.5
 120  **/
 121 void
 122 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
 123 {
 124   if (font->immutable)
 125     return;
 126 
 127   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 128     return;
 129 
 130   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
 131 
 132   ft_font->load_flags = load_flags;
 133 }
 134 
 135 /**
 136  * hb_ft_font_get_load_flags:
 137  * @font:
 138  *
 139  * 
 140  *
 141  * Return value:
 142  * Since: 1.0.5
 143  **/
 144 int
 145 hb_ft_font_get_load_flags (hb_font_t *font)
 146 {
 147   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 148     return 0;
 149 
 150   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 151 
 152   return ft_font->load_flags;
 153 }
 154 
 155 FT_Face
 156 hb_ft_font_get_face (hb_font_t *font)
 157 {
 158   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 159     return NULL;
 160 
 161   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 162 
 163   return ft_font->ft_face;
 164 }
 165 
 166 
 167 
 168 static hb_bool_t
 169 hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 170                          void *font_data,
 171                          hb_codepoint_t unicode,
 172                          hb_codepoint_t *glyph,
 173                          void *user_data HB_UNUSED)
 174 {
 175   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 176   unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
 177 
 178   if (unlikely (!g))
 179   {
 180     if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
 181     {
 182       /* For symbol-encoded OpenType fonts, we duplicate the
 183        * U+F000..F0FF range at U+0000..U+00FF.  That's what
 184        * Windows seems to do, and that's hinted about at:
 185        * http://www.microsoft.com/typography/otspec/recom.htm
 186        * under "Non-Standard (Symbol) Fonts". */
 187       g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
 188       if (!g)
 189         return false;
 190     }
 191     else
 192       return false;
 193   }
 194 
 195   *glyph = g;
 196   return true;
 197 }
 198 
 199 static hb_bool_t
 200 hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
 201                            void *font_data,
 202                            hb_codepoint_t unicode,
 203                            hb_codepoint_t variation_selector,
 204                            hb_codepoint_t *glyph,
 205                            void *user_data HB_UNUSED)
 206 {
 207   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 208   unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
 209 
 210   if (unlikely (!g))
 211     return false;
 212 
 213   *glyph = g;
 214   return true;
 215 }
 216 
 217 static hb_position_t
 218 hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
 219                            void *font_data,
 220                            hb_codepoint_t glyph,
 221                            void *user_data HB_UNUSED)
 222 {
 223   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 224   FT_Fixed v;
 225 
 226   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
 227     return 0;
 228 
 229   if (font->x_scale < 0)
 230     v = -v;
 231 
 232   return (v + (1<<9)) >> 10;
 233 }
 234 
 235 static hb_position_t
 236 hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
 237                            void *font_data,
 238                            hb_codepoint_t glyph,
 239                            void *user_data HB_UNUSED)
 240 {
 241   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 242   FT_Fixed v;
 243 
 244   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
 245     return 0;
 246 
 247   if (font->y_scale < 0)
 248     v = -v;
 249 
 250   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
 251    * have a Y growing upward.  Hence the extra negation. */
 252   return (-v + (1<<9)) >> 10;
 253 }
 254 
 255 static hb_bool_t
 256 hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
 257                           void *font_data,
 258                           hb_codepoint_t glyph,
 259                           hb_position_t *x,
 260                           hb_position_t *y,
 261                           void *user_data HB_UNUSED)
 262 {
 263   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 264   FT_Face ft_face = ft_font->ft_face;
 265 
 266   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
 267     return false;
 268 
 269   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
 270    * have a Y growing upward.  Hence the extra negation. */
 271   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
 272   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
 273 
 274   if (font->x_scale < 0)
 275     *x = -*x;
 276   if (font->y_scale < 0)
 277     *y = -*y;
 278 
 279   return true;
 280 }
 281 
 282 static hb_position_t
 283 hb_ft_get_glyph_h_kerning (hb_font_t *font,
 284                            void *font_data,
 285                            hb_codepoint_t left_glyph,
 286                            hb_codepoint_t right_glyph,
 287                            void *user_data HB_UNUSED)
 288 {
 289   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 290   FT_Vector kerningv;
 291 
 292   FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
 293   if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
 294     return 0;
 295 
 296   return kerningv.x;
 297 }
 298 
 299 static hb_bool_t
 300 hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
 301                          void *font_data,
 302                          hb_codepoint_t glyph,
 303                          hb_glyph_extents_t *extents,
 304                          void *user_data HB_UNUSED)
 305 {
 306   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 307   FT_Face ft_face = ft_font->ft_face;
 308 
 309   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
 310     return false;
 311 
 312   extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
 313   extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
 314   extents->width = ft_face->glyph->metrics.width;
 315   extents->height = -ft_face->glyph->metrics.height;
 316   if (font->x_scale < 0)
 317   {
 318     extents->x_bearing = -extents->x_bearing;
 319     extents->width = -extents->width;
 320   }
 321   if (font->y_scale < 0)
 322   {
 323     extents->y_bearing = -extents->y_bearing;
 324     extents->height = -extents->height;
 325   }
 326   return true;
 327 }
 328 
 329 static hb_bool_t
 330 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
 331                                void *font_data,
 332                                hb_codepoint_t glyph,
 333                                unsigned int point_index,
 334                                hb_position_t *x,
 335                                hb_position_t *y,
 336                                void *user_data HB_UNUSED)
 337 {
 338   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 339   FT_Face ft_face = ft_font->ft_face;
 340 
 341   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
 342       return false;
 343 
 344   if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
 345       return false;
 346 
 347   if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
 348       return false;
 349 
 350   *x = ft_face->glyph->outline.points[point_index].x;
 351   *y = ft_face->glyph->outline.points[point_index].y;
 352 
 353   return true;
 354 }
 355 
 356 static hb_bool_t
 357 hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
 358                       void *font_data,
 359                       hb_codepoint_t glyph,
 360                       char *name, unsigned int size,
 361                       void *user_data HB_UNUSED)
 362 {
 363   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 364 
 365   hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
 366   if (ret && (size && !*name))
 367     ret = false;
 368 
 369   return ret;
 370 }
 371 
 372 static hb_bool_t
 373 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
 374                            void *font_data,
 375                            const char *name, int len, /* -1 means nul-terminated */
 376                            hb_codepoint_t *glyph,
 377                            void *user_data HB_UNUSED)
 378 {
 379   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 380   FT_Face ft_face = ft_font->ft_face;
 381 
 382   if (len < 0)
 383     *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
 384   else {
 385     /* Make a nul-terminated version. */
 386     char buf[128];
 387     len = MIN (len, (int) sizeof (buf) - 1);
 388     strncpy (buf, name, len);
 389     buf[len] = '\0';
 390     *glyph = FT_Get_Name_Index (ft_face, buf);
 391   }
 392 
 393   if (*glyph == 0)
 394   {
 395     /* Check whether the given name was actually the name of glyph 0. */
 396     char buf[128];
 397     if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
 398         len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
 399       return true;
 400   }
 401 
 402   return *glyph != 0;
 403 }
 404 
 405 static hb_bool_t
 406 hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
 407                           void *font_data,
 408                           hb_font_extents_t *metrics,
 409                           void *user_data HB_UNUSED)
 410 {
 411   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 412   FT_Face ft_face = ft_font->ft_face;
 413   metrics->ascender = ft_face->size->metrics.ascender;
 414   metrics->descender = ft_face->size->metrics.descender;
 415   metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
 416   if (font->y_scale < 0)
 417   {
 418     metrics->ascender = -metrics->ascender;
 419     metrics->descender = -metrics->descender;
 420     metrics->line_gap = -metrics->line_gap;
 421   }
 422   return true;
 423 }
 424 
 425 static hb_font_funcs_t *static_ft_funcs = NULL;
 426 
 427 #ifdef HB_USE_ATEXIT
 428 static
 429 void free_static_ft_funcs (void)
 430 {
 431   hb_font_funcs_destroy (static_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, NULL, NULL);
 446     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
 447     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
 448     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
 449     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
 450     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
 451     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
 452     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
 453     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
 454     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
 455     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
 456     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
 457     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
 458     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
 459 
 460     hb_font_funcs_make_immutable (funcs);
 461 
 462     if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, 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_destroy_func_t) _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, NULL, &length);
 492   if (error)
 493     return NULL;
 494 
 495   buffer = (FT_Byte *) malloc (length);
 496   if (buffer == NULL)
 497     return NULL;
 498 
 499   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
 500   if (error)
 501     return NULL;
 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 == NULL) {
 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_destroy_func_t) _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, NULL);
 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_font_set_scale (font,
 612                      (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
 613                      (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
 614 #if 0 /* hb-ft works in no-hinting model */
 615   hb_font_set_ppem (font,
 616                     ft_face->size->metrics.x_ppem,
 617                     ft_face->size->metrics.y_ppem);
 618 #endif
 619 
 620 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
 621   FT_MM_Var *mm_var = NULL;
 622   if (!FT_Get_MM_Var (ft_face, &mm_var))
 623   {
 624     FT_Fixed coords[mm_var->num_axis];
 625     int hbCoords[mm_var->num_axis];
 626     if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, coords))
 627     {
 628       for (int i = 0; i < mm_var->num_axis; ++i)
 629         hbCoords[i] = coords[i] >> 2;
 630 
 631       hb_font_set_var_coords_normalized (font, hbCoords, mm_var->num_axis);
 632     }
 633   }
 634   free (mm_var);
 635 #endif
 636 
 637   return font;
 638 }
 639 
 640 /**
 641  * hb_ft_font_create_referenced:
 642  * @ft_face:
 643  *
 644  * 
 645  *
 646  * Return value: (transfer full): 
 647  * Since: 0.9.38
 648  **/
 649 hb_font_t *
 650 hb_ft_font_create_referenced (FT_Face ft_face)
 651 {
 652   FT_Reference_Face (ft_face);
 653   return hb_ft_font_create (ft_face, (hb_destroy_func_t) _hb_ft_face_destroy);
 654 }
 655 
 656 
 657 /* Thread-safe, lock-free, FT_Library */
 658 
 659 static FT_Library ft_library;
 660 
 661 #ifdef HB_USE_ATEXIT
 662 static
 663 void free_ft_library (void)
 664 {
 665   FT_Done_FreeType (ft_library);
 666 }
 667 #endif
 668 
 669 static FT_Library
 670 get_ft_library (void)
 671 {
 672 retry:
 673   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
 674 
 675   if (unlikely (!library))
 676   {
 677     /* Not found; allocate one. */
 678     if (FT_Init_FreeType (&library))
 679       return NULL;
 680 
 681     if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
 682       FT_Done_FreeType (library);
 683       goto retry;
 684     }
 685 
 686 #ifdef HB_USE_ATEXIT
 687     atexit (free_ft_library); /* First person registers atexit() callback. */
 688 #endif
 689   }
 690 
 691   return library;
 692 }
 693 
 694 static void
 695 _release_blob (FT_Face ft_face)
 696 {
 697   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 698 }
 699 
 700 void
 701 hb_ft_font_set_funcs (hb_font_t *font)
 702 {
 703   hb_blob_t *blob = hb_face_reference_blob (font->face);
 704   unsigned int blob_length;
 705   const char *blob_data = hb_blob_get_data (blob, &blob_length);
 706   if (unlikely (!blob_length))
 707     DEBUG_MSG (FT, font, "Font face has empty blob");
 708 
 709   FT_Face ft_face = NULL;
 710   FT_Error err = FT_New_Memory_Face (get_ft_library (),
 711                                      (const FT_Byte *) blob_data,
 712                                      blob_length,
 713                                      hb_face_get_index (font->face),
 714                                      &ft_face);
 715 
 716   if (unlikely (err)) {
 717     hb_blob_destroy (blob);
 718     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
 719     return;
 720   }
 721 
 722   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
 723     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
 724 
 725   FT_Set_Char_Size (ft_face,
 726                     abs (font->x_scale), abs (font->y_scale),
 727                     0, 0);
 728 #if 0
 729                     font->x_ppem * 72 * 64 / font->x_scale,
 730                     font->y_ppem * 72 * 64 / font->y_scale);
 731 #endif
 732   if (font->x_scale < 0 || font->y_scale < 0)
 733   {
 734     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
 735                           0, font->y_scale < 0 ? -1 : +1};
 736     FT_Set_Transform (ft_face, &matrix, NULL);
 737   }
 738 
 739   ft_face->generic.data = blob;
 740   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
 741 
 742   _hb_ft_font_set_funcs (font, ft_face, true);
 743   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
 744 }