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