< prev index next >

src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc

Print this page




  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


 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     free (buffer);
 502     return nullptr;
 503   }
 504 
 505   return hb_blob_create ((const char *) buffer, length,
 506                          HB_MEMORY_MODE_WRITABLE,
 507                          buffer, free);
 508 }
 509 
 510 /**
 511  * hb_ft_face_create:
 512  * @ft_face: (destroy destroy) (scope notified):
 513  * @destroy:
 514  *
 515  *
 516  *
 517  * Return value: (transfer full):
 518  * Since: 0.9.2
 519  **/
 520 hb_face_t *


 666   }
 667 #endif
 668 }
 669 
 670 /**
 671  * hb_ft_font_create_referenced:
 672  * @ft_face:
 673  *
 674  *
 675  *
 676  * Return value: (transfer full):
 677  * Since: 0.9.38
 678  **/
 679 hb_font_t *
 680 hb_ft_font_create_referenced (FT_Face ft_face)
 681 {
 682   FT_Reference_Face (ft_face);
 683   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 684 }
 685 



 686 
 687 /* Thread-safe, lock-free, FT_Library */
 688 
 689 static FT_Library ft_library;
 690 
 691 #ifdef HB_USE_ATEXIT
 692 static
 693 void free_ft_library (void)
 694 {
 695 retry:
 696   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
 697   if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr))
 698     goto retry;

 699 
 700   FT_Done_FreeType (library);
 701 }
 702 #endif
 703 
 704 static FT_Library
 705 get_ft_library (void)
 706 {
 707 retry:
 708   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
 709 
 710   if (unlikely (!library))
 711   {
 712     /* Not found; allocate one. */
 713     if (FT_Init_FreeType (&library))
 714       return nullptr;
 715 
 716     if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
 717       FT_Done_FreeType (library);
 718       goto retry;
 719     }

 720 
 721 #ifdef HB_USE_ATEXIT
 722     atexit (free_ft_library); /* First person registers atexit() callback. */




 723 #endif
 724   }
 725 
 726   return library;



 727 }
 728 
 729 static void
 730 _release_blob (FT_Face ft_face)
 731 {
 732   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 733 }
 734 
 735 void
 736 hb_ft_font_set_funcs (hb_font_t *font)
 737 {
 738   hb_blob_t *blob = hb_face_reference_blob (font->face);
 739   unsigned int blob_length;
 740   const char *blob_data = hb_blob_get_data (blob, &blob_length);
 741   if (unlikely (!blob_length))
 742     DEBUG_MSG (FT, font, "Font face has empty blob");
 743 
 744   FT_Face ft_face = nullptr;
 745   FT_Error err = FT_New_Memory_Face (get_ft_library (),
 746                                      (const FT_Byte *) blob_data,




  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


 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 *


 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,


< prev index next >