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.hh"
  31 
  32 #include "hb-ft.h"
  33 
  34 #include "hb-font.hh"
  35 #include "hb-machinery.hh"
  36 #include "hb-cache.hh"
  37 
  38 #include FT_ADVANCES_H
  39 #include FT_MULTIPLE_MASTERS_H
  40 #include FT_TRUETYPE_TABLES_H
  41 
  42 
  43 /**
  44  * SECTION:hb-ft
  45  * @title: hb-ft
  46  * @short_description: FreeType integration
  47  * @include: hb-ft.h
  48  *
  49  * Functions for using HarfBuzz with the FreeType library to provide face and
  50  * font data.
  51  **/
  52 
  53 
  54 /* TODO:
  55  *
  56  * In general, this file does a fine job of what it's supposed to do.
  57  * There are, however, things that need more work:
  58  *
  59  *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
  60  *     would work fine.  However, we also abuse this API for performing in font-space,
  61  *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
  62  *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
  63  *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
  64  *     ourselves.
  65  *
  66  *   - We don't handle / allow for emboldening / obliqueing.
  67  *
  68  *   - In the future, we should add constructors to create fonts in font space?
  69  */
  70 
  71 
  72 struct hb_ft_font_t
  73 {
  74   mutable hb_mutex_t lock;
  75   FT_Face ft_face;
  76   int load_flags;
  77   bool symbol; /* Whether selected cmap is symbol cmap. */
  78   bool unref; /* Whether to destroy ft_face when done. */
  79 
  80   mutable hb_atomic_int_t cached_x_scale;
  81   mutable hb_advance_cache_t advance_cache;
  82 };
  83 
  84 static hb_ft_font_t *
  85 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
  86 {
  87   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
  88 
  89   if (unlikely (!ft_font))
  90     return nullptr;
  91 
  92   ft_font->lock.init ();
  93   ft_font->ft_face = ft_face;
  94   ft_font->symbol = symbol;
  95   ft_font->unref = unref;
  96 
  97   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
  98 
  99   ft_font->cached_x_scale.set (0);
 100   ft_font->advance_cache.init ();
 101 
 102   return ft_font;
 103 }
 104 
 105 static void
 106 _hb_ft_face_destroy (void *data)
 107 {
 108   FT_Done_Face ((FT_Face) data);
 109 }
 110 
 111 static void
 112 _hb_ft_font_destroy (void *data)
 113 {
 114   hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
 115 
 116   ft_font->advance_cache.fini ();
 117 
 118   if (ft_font->unref)
 119     _hb_ft_face_destroy (ft_font->ft_face);
 120 
 121   ft_font->lock.fini ();
 122 
 123   free (ft_font);
 124 }
 125 
 126 /**
 127  * hb_ft_font_set_load_flags:
 128  * @font:
 129  * @load_flags:
 130  *
 131  *
 132  *
 133  * Since: 1.0.5
 134  **/
 135 void
 136 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
 137 {
 138   if (hb_object_is_immutable (font))
 139     return;
 140 
 141   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 142     return;
 143 
 144   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
 145 
 146   ft_font->load_flags = load_flags;
 147 }
 148 
 149 /**
 150  * hb_ft_font_get_load_flags:
 151  * @font:
 152  *
 153  *
 154  *
 155  * Return value:
 156  * Since: 1.0.5
 157  **/
 158 int
 159 hb_ft_font_get_load_flags (hb_font_t *font)
 160 {
 161   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 162     return 0;
 163 
 164   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 165 
 166   return ft_font->load_flags;
 167 }
 168 
 169 FT_Face
 170 hb_ft_font_get_face (hb_font_t *font)
 171 {
 172   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 173     return nullptr;
 174 
 175   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 176 
 177   return ft_font->ft_face;
 178 }
 179 
 180 
 181 
 182 static hb_bool_t
 183 hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 184                          void *font_data,
 185                          hb_codepoint_t unicode,
 186                          hb_codepoint_t *glyph,
 187                          void *user_data HB_UNUSED)
 188 {
 189   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 190   hb_lock_t lock (ft_font->lock);
 191   unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
 192 
 193   if (unlikely (!g))
 194   {
 195     if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
 196     {
 197       /* For symbol-encoded OpenType fonts, we duplicate the
 198        * U+F000..F0FF range at U+0000..U+00FF.  That's what
 199        * Windows seems to do, and that's hinted about at:
 200        * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
 201        * under "Non-Standard (Symbol) Fonts". */
 202       g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
 203       if (!g)
 204         return false;
 205     }
 206     else
 207       return false;
 208   }
 209 
 210   *glyph = g;
 211   return true;
 212 }
 213 
 214 static unsigned int
 215 hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
 216                           void *font_data,
 217                           unsigned int count,
 218                           const hb_codepoint_t *first_unicode,
 219                           unsigned int unicode_stride,
 220                           hb_codepoint_t *first_glyph,
 221                           unsigned int glyph_stride,
 222                           void *user_data HB_UNUSED)
 223 {
 224   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 225   hb_lock_t lock (ft_font->lock);
 226   unsigned int done;
 227   for (done = 0;
 228        done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
 229        done++)
 230   {
 231     first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
 232     first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
 233   }
 234   /* We don't need to do ft_font->symbol dance here, since HB calls the singular
 235    * nominal_glyph() for what we don't handle here. */
 236   return done;
 237 }
 238 
 239 
 240 static hb_bool_t
 241 hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
 242                            void *font_data,
 243                            hb_codepoint_t unicode,
 244                            hb_codepoint_t variation_selector,
 245                            hb_codepoint_t *glyph,
 246                            void *user_data HB_UNUSED)
 247 {
 248   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 249   hb_lock_t lock (ft_font->lock);
 250   unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
 251 
 252   if (unlikely (!g))
 253     return false;
 254 
 255   *glyph = g;
 256   return true;
 257 }
 258 
 259 static void
 260 hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
 261                             unsigned count,
 262                             const hb_codepoint_t *first_glyph,
 263                             unsigned glyph_stride,
 264                             hb_position_t *first_advance,
 265                             unsigned advance_stride,
 266                             void *user_data HB_UNUSED)
 267 {
 268   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 269   hb_lock_t lock (ft_font->lock);
 270   FT_Face ft_face = ft_font->ft_face;
 271   int load_flags = ft_font->load_flags;
 272   int mult = font->x_scale < 0 ? -1 : +1;
 273 
 274   if (font->x_scale != ft_font->cached_x_scale.get ())
 275   {
 276     ft_font->advance_cache.clear ();
 277     ft_font->cached_x_scale.set (font->x_scale);
 278   }
 279 
 280   for (unsigned int i = 0; i < count; i++)
 281   {
 282     FT_Fixed v = 0;
 283     hb_codepoint_t glyph = *first_glyph;
 284 
 285     unsigned int cv;
 286     if (ft_font->advance_cache.get (glyph, &cv))
 287       v = cv;
 288     else
 289     {
 290       FT_Get_Advance (ft_face, glyph, load_flags, &v);
 291       ft_font->advance_cache.set (glyph, v);
 292     }
 293 
 294     *first_advance = (v * mult + (1<<9)) >> 10;
 295     first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
 296     first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
 297   }
 298 }
 299 
 300 static hb_position_t
 301 hb_ft_get_glyph_v_advance (hb_font_t *font,
 302                            void *font_data,
 303                            hb_codepoint_t glyph,
 304                            void *user_data HB_UNUSED)
 305 {
 306   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 307   hb_lock_t lock (ft_font->lock);
 308   FT_Fixed v;
 309 
 310   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
 311     return 0;
 312 
 313   if (font->y_scale < 0)
 314     v = -v;
 315 
 316   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
 317    * have a Y growing upward.  Hence the extra negation. */
 318   return (-v + (1<<9)) >> 10;
 319 }
 320 
 321 static hb_bool_t
 322 hb_ft_get_glyph_v_origin (hb_font_t *font,
 323                           void *font_data,
 324                           hb_codepoint_t glyph,
 325                           hb_position_t *x,
 326                           hb_position_t *y,
 327                           void *user_data HB_UNUSED)
 328 {
 329   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 330   hb_lock_t lock (ft_font->lock);
 331   FT_Face ft_face = ft_font->ft_face;
 332 
 333   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
 334     return false;
 335 
 336   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
 337    * have a Y growing upward.  Hence the extra negation. */
 338   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
 339   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
 340 
 341   if (font->x_scale < 0)
 342     *x = -*x;
 343   if (font->y_scale < 0)
 344     *y = -*y;
 345 
 346   return true;
 347 }
 348 
 349 static hb_bool_t
 350 hb_ft_get_glyph_extents (hb_font_t *font,
 351                          void *font_data,
 352                          hb_codepoint_t glyph,
 353                          hb_glyph_extents_t *extents,
 354                          void *user_data HB_UNUSED)
 355 {
 356   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 357   hb_lock_t lock (ft_font->lock);
 358   FT_Face ft_face = ft_font->ft_face;
 359 
 360   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
 361     return false;
 362 
 363   extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
 364   extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
 365   extents->width = ft_face->glyph->metrics.width;
 366   extents->height = -ft_face->glyph->metrics.height;
 367   if (font->x_scale < 0)
 368   {
 369     extents->x_bearing = -extents->x_bearing;
 370     extents->width = -extents->width;
 371   }
 372   if (font->y_scale < 0)
 373   {
 374     extents->y_bearing = -extents->y_bearing;
 375     extents->height = -extents->height;
 376   }
 377   return true;
 378 }
 379 
 380 static hb_bool_t
 381 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
 382                                void *font_data,
 383                                hb_codepoint_t glyph,
 384                                unsigned int point_index,
 385                                hb_position_t *x,
 386                                hb_position_t *y,
 387                                void *user_data HB_UNUSED)
 388 {
 389   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 390   hb_lock_t lock (ft_font->lock);
 391   FT_Face ft_face = ft_font->ft_face;
 392 
 393   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
 394       return false;
 395 
 396   if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
 397       return false;
 398 
 399   if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
 400       return false;
 401 
 402   *x = ft_face->glyph->outline.points[point_index].x;
 403   *y = ft_face->glyph->outline.points[point_index].y;
 404 
 405   return true;
 406 }
 407 
 408 static hb_bool_t
 409 hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
 410                       void *font_data,
 411                       hb_codepoint_t glyph,
 412                       char *name, unsigned int size,
 413                       void *user_data HB_UNUSED)
 414 {
 415   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 416   hb_lock_t lock (ft_font->lock);
 417   FT_Face ft_face = ft_font->ft_face;
 418 
 419   hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
 420   if (ret && (size && !*name))
 421     ret = false;
 422 
 423   return ret;
 424 }
 425 
 426 static hb_bool_t
 427 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
 428                            void *font_data,
 429                            const char *name, int len, /* -1 means nul-terminated */
 430                            hb_codepoint_t *glyph,
 431                            void *user_data HB_UNUSED)
 432 {
 433   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 434   hb_lock_t lock (ft_font->lock);
 435   FT_Face ft_face = ft_font->ft_face;
 436 
 437   if (len < 0)
 438     *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
 439   else {
 440     /* Make a nul-terminated version. */
 441     char buf[128];
 442     len = MIN (len, (int) sizeof (buf) - 1);
 443     strncpy (buf, name, len);
 444     buf[len] = '\0';
 445     *glyph = FT_Get_Name_Index (ft_face, buf);
 446   }
 447 
 448   if (*glyph == 0)
 449   {
 450     /* Check whether the given name was actually the name of glyph 0. */
 451     char buf[128];
 452     if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
 453         len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
 454       return true;
 455   }
 456 
 457   return *glyph != 0;
 458 }
 459 
 460 static hb_bool_t
 461 hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
 462                           void *font_data,
 463                           hb_font_extents_t *metrics,
 464                           void *user_data HB_UNUSED)
 465 {
 466   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 467   hb_lock_t lock (ft_font->lock);
 468   FT_Face ft_face = ft_font->ft_face;
 469   metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
 470   metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
 471   metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
 472   if (font->y_scale < 0)
 473   {
 474     metrics->ascender = -metrics->ascender;
 475     metrics->descender = -metrics->descender;
 476     metrics->line_gap = -metrics->line_gap;
 477   }
 478   return true;
 479 }
 480 
 481 #if HB_USE_ATEXIT
 482 static void free_static_ft_funcs ();
 483 #endif
 484 
 485 static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
 486 {
 487   static hb_font_funcs_t *create ()
 488   {
 489     hb_font_funcs_t *funcs = hb_font_funcs_create ();
 490 
 491     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
 492     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
 493     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
 494     hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
 495     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
 496     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
 497     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
 498     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
 499     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
 500     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
 501     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
 502     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
 503     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 504 
 505     hb_font_funcs_make_immutable (funcs);
 506 
 507 #if HB_USE_ATEXIT
 508     atexit (free_static_ft_funcs);
 509 #endif
 510 
 511     return funcs;
 512   }
 513 } static_ft_funcs;
 514 
 515 #if HB_USE_ATEXIT
 516 static
 517 void free_static_ft_funcs ()
 518 {
 519   static_ft_funcs.free_instance ();
 520 }
 521 #endif
 522 
 523 static hb_font_funcs_t *
 524 _hb_ft_get_font_funcs ()
 525 {
 526   return static_ft_funcs.get_unconst ();
 527 }
 528 
 529 static void
 530 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
 531 {
 532   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
 533 
 534   hb_font_set_funcs (font,
 535                      _hb_ft_get_font_funcs (),
 536                      _hb_ft_font_create (ft_face, symbol, unref),
 537                      _hb_ft_font_destroy);
 538 }
 539 
 540 
 541 static hb_blob_t *
 542 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 543 {
 544   FT_Face ft_face = (FT_Face) user_data;
 545   FT_Byte *buffer;
 546   FT_ULong  length = 0;
 547   FT_Error error;
 548 
 549   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
 550 
 551   error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
 552   if (error)
 553     return nullptr;
 554 
 555   buffer = (FT_Byte *) malloc (length);
 556   if (!buffer)
 557     return nullptr;
 558 
 559   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
 560   if (error)
 561   {
 562     free (buffer);
 563     return nullptr;
 564   }
 565 
 566   return hb_blob_create ((const char *) buffer, length,
 567                          HB_MEMORY_MODE_WRITABLE,
 568                          buffer, free);
 569 }
 570 
 571 /**
 572  * hb_ft_face_create:
 573  * @ft_face: (destroy destroy) (scope notified):
 574  * @destroy:
 575  *
 576  *
 577  *
 578  * Return value: (transfer full):
 579  * Since: 0.9.2
 580  **/
 581 hb_face_t *
 582 hb_ft_face_create (FT_Face           ft_face,
 583                    hb_destroy_func_t destroy)
 584 {
 585   hb_face_t *face;
 586 
 587   if (!ft_face->stream->read) {
 588     hb_blob_t *blob;
 589 
 590     blob = hb_blob_create ((const char *) ft_face->stream->base,
 591                            (unsigned int) ft_face->stream->size,
 592                            HB_MEMORY_MODE_READONLY,
 593                            ft_face, destroy);
 594     face = hb_face_create (blob, ft_face->face_index);
 595     hb_blob_destroy (blob);
 596   } else {
 597     face = hb_face_create_for_tables (reference_table, ft_face, destroy);
 598   }
 599 
 600   hb_face_set_index (face, ft_face->face_index);
 601   hb_face_set_upem (face, ft_face->units_per_EM);
 602 
 603   return face;
 604 }
 605 
 606 /**
 607  * hb_ft_face_create_referenced:
 608  * @ft_face:
 609  *
 610  *
 611  *
 612  * Return value: (transfer full):
 613  * Since: 0.9.38
 614  **/
 615 hb_face_t *
 616 hb_ft_face_create_referenced (FT_Face ft_face)
 617 {
 618   FT_Reference_Face (ft_face);
 619   return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
 620 }
 621 
 622 static void
 623 hb_ft_face_finalize (FT_Face ft_face)
 624 {
 625   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
 626 }
 627 
 628 /**
 629  * hb_ft_face_create_cached:
 630  * @ft_face:
 631  *
 632  *
 633  *
 634  * Return value: (transfer full):
 635  * Since: 0.9.2
 636  **/
 637 hb_face_t *
 638 hb_ft_face_create_cached (FT_Face ft_face)
 639 {
 640   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
 641   {
 642     if (ft_face->generic.finalizer)
 643       ft_face->generic.finalizer (ft_face);
 644 
 645     ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
 646     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
 647   }
 648 
 649   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 650 }
 651 
 652 
 653 /**
 654  * hb_ft_font_create:
 655  * @ft_face: (destroy destroy) (scope notified):
 656  * @destroy:
 657  *
 658  *
 659  *
 660  * Return value: (transfer full):
 661  * Since: 0.9.2
 662  **/
 663 hb_font_t *
 664 hb_ft_font_create (FT_Face           ft_face,
 665                    hb_destroy_func_t destroy)
 666 {
 667   hb_font_t *font;
 668   hb_face_t *face;
 669 
 670   face = hb_ft_face_create (ft_face, destroy);
 671   font = hb_font_create (face);
 672   hb_face_destroy (face);
 673   _hb_ft_font_set_funcs (font, ft_face, false);
 674   hb_ft_font_changed (font);
 675   return font;
 676 }
 677 
 678 void
 679 hb_ft_font_changed (hb_font_t *font)
 680 {
 681   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 682     return;
 683 
 684   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
 685   FT_Face ft_face = ft_font->ft_face;
 686 
 687   hb_font_set_scale (font,
 688                      (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
 689                      (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
 690 #if 0 /* hb-ft works in no-hinting model */
 691   hb_font_set_ppem (font,
 692                     ft_face->size->metrics.x_ppem,
 693                     ft_face->size->metrics.y_ppem);
 694 #endif
 695 
 696 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
 697   FT_MM_Var *mm_var = nullptr;
 698   if (!FT_Get_MM_Var (ft_face, &mm_var))
 699   {
 700     FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
 701     int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
 702     if (coords && ft_coords)
 703     {
 704       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
 705       {
 706         bool nonzero = false;
 707 
 708         for (unsigned int i = 0; i < mm_var->num_axis; ++i)
 709          {
 710           coords[i] = ft_coords[i] >>= 2;
 711           nonzero = nonzero || coords[i];
 712          }
 713 
 714         if (nonzero)
 715           hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
 716         else
 717           hb_font_set_var_coords_normalized (font, nullptr, 0);
 718       }
 719     }
 720     free (coords);
 721     free (ft_coords);
 722 #ifdef HAVE_FT_DONE_MM_VAR
 723     FT_Done_MM_Var (ft_face->glyph->library, mm_var);
 724 #else
 725     free (mm_var);
 726 #endif
 727   }
 728 #endif
 729 }
 730 
 731 /**
 732  * hb_ft_font_create_referenced:
 733  * @ft_face:
 734  *
 735  *
 736  *
 737  * Return value: (transfer full):
 738  * Since: 0.9.38
 739  **/
 740 hb_font_t *
 741 hb_ft_font_create_referenced (FT_Face ft_face)
 742 {
 743   FT_Reference_Face (ft_face);
 744   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 745 }
 746 
 747 #if HB_USE_ATEXIT
 748 static void free_static_ft_library ();
 749 #endif
 750 
 751 static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
 752                                                              hb_ft_library_lazy_loader_t>
 753 {
 754   static FT_Library create ()
 755   {
 756     FT_Library l;
 757     if (FT_Init_FreeType (&l))
 758       return nullptr;
 759 
 760 #if HB_USE_ATEXIT
 761     atexit (free_static_ft_library);
 762 #endif
 763 
 764     return l;
 765   }
 766   static void destroy (FT_Library l)
 767   {
 768     FT_Done_FreeType (l);
 769   }
 770   static FT_Library get_null ()
 771   {
 772     return nullptr;
 773   }
 774 } static_ft_library;
 775 
 776 #if HB_USE_ATEXIT
 777 static
 778 void free_static_ft_library ()
 779 {
 780   static_ft_library.free_instance ();
 781 }
 782 #endif
 783 
 784 static FT_Library
 785 get_ft_library ()
 786 {
 787   return static_ft_library.get_unconst ();
 788 }
 789 
 790 static void
 791 _release_blob (FT_Face ft_face)
 792 {
 793   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 794 }
 795 
 796 void
 797 hb_ft_font_set_funcs (hb_font_t *font)
 798 {
 799   hb_blob_t *blob = hb_face_reference_blob (font->face);
 800   unsigned int blob_length;
 801   const char *blob_data = hb_blob_get_data (blob, &blob_length);
 802   if (unlikely (!blob_length))
 803     DEBUG_MSG (FT, font, "Font face has empty blob");
 804 
 805   FT_Face ft_face = nullptr;
 806   FT_Error err = FT_New_Memory_Face (get_ft_library (),
 807                                      (const FT_Byte *) blob_data,
 808                                      blob_length,
 809                                      hb_face_get_index (font->face),
 810                                      &ft_face);
 811 
 812   if (unlikely (err)) {
 813     hb_blob_destroy (blob);
 814     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
 815     return;
 816   }
 817 
 818   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
 819     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
 820 
 821   FT_Set_Char_Size (ft_face,
 822                     abs (font->x_scale), abs (font->y_scale),
 823                     0, 0);
 824 #if 0
 825                     font->x_ppem * 72 * 64 / font->x_scale,
 826                     font->y_ppem * 72 * 64 / font->y_scale);
 827 #endif
 828   if (font->x_scale < 0 || font->y_scale < 0)
 829   {
 830     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
 831                           0, font->y_scale < 0 ? -1 : +1};
 832     FT_Set_Transform (ft_face, &matrix, nullptr);
 833   }
 834 
 835 #ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
 836   unsigned int num_coords;
 837   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
 838   if (num_coords)
 839   {
 840     FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
 841     if (ft_coords)
 842     {
 843       for (unsigned int i = 0; i < num_coords; i++)
 844         ft_coords[i] = coords[i] << 2;
 845       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
 846       free (ft_coords);
 847     }
 848   }
 849 #endif
 850 
 851   ft_face->generic.data = blob;
 852   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
 853 
 854   _hb_ft_font_set_funcs (font, ft_face, true);
 855   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
 856 }