< prev index next >

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

Print this page




  11  * above copyright notice and the following two paragraphs appear in
  12  * all copies of this software.
  13  *
  14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  18  * DAMAGE.
  19  *
  20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  25  *
  26  * Red Hat Author(s): Behdad Esfahbod
  27  * Google Author(s): Behdad Esfahbod
  28  */
  29 
  30 #include "hb-private.hh"

  31 
  32 #include "hb-ft.h"
  33 
  34 #include "hb-font-private.hh"
  35 
  36 #include "hb-cache-private.hh" // Maybe use in the future?
  37 
  38 #include FT_ADVANCES_H
  39 #include FT_MULTIPLE_MASTERS_H
  40 #include FT_TRUETYPE_TABLES_H
  41 
  42 
  43 
  44 #ifndef HB_DEBUG_FT
  45 #define HB_DEBUG_FT (HB_DEBUG+0)
  46 #endif
  47 
  48 
  49 /* TODO:
  50  *
  51  * In general, this file does a fine job of what it's supposed to do.
  52  * There are, however, things that need more work:
  53  *
  54  *   - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
  55  *     Have not investigated.
  56  *
  57  *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
  58  *     would work fine.  However, we also abuse this API for performing in font-space,
  59  *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
  60  *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
  61  *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
  62  *     ourselves, like we do in uniscribe, etc.
  63  *
  64  *   - We don't handle / allow for emboldening / obliqueing.
  65  *
  66  *   - In the future, we should add constructors to create fonts in font space?
  67  *
  68  *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
  69  */
  70 
  71 
  72 struct hb_ft_font_t
  73 {
  74   FT_Face ft_face;
  75   int load_flags;
  76   bool symbol; /* Whether selected cmap is symbol cmap. */
  77   bool unref; /* Whether to destroy ft_face when done. */
  78 };
  79 
  80 static hb_ft_font_t *
  81 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
  82 {
  83   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
  84 
  85   if (unlikely (!ft_font))
  86     return NULL;
  87 
  88   ft_font->ft_face = ft_face;
  89   ft_font->symbol = symbol;
  90   ft_font->unref = unref;
  91 
  92   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
  93 
  94   return ft_font;
  95 }
  96 
  97 static void
  98 _hb_ft_face_destroy (FT_Face ft_face)
  99 {
 100   FT_Done_Face (ft_face);
 101 }
 102 
 103 static void
 104 _hb_ft_font_destroy (hb_ft_font_t *ft_font)
 105 {


 106   if (ft_font->unref)
 107     _hb_ft_face_destroy (ft_font->ft_face);
 108 
 109   free (ft_font);
 110 }
 111 
 112 /**
 113  * hb_ft_font_set_load_flags:
 114  * @font:
 115  * @load_flags:
 116  *
 117  * 
 118  *
 119  * Since: 1.0.5
 120  **/
 121 void
 122 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
 123 {
 124   if (font->immutable)
 125     return;
 126 
 127   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 128     return;
 129 
 130   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
 131 
 132   ft_font->load_flags = load_flags;
 133 }
 134 
 135 /**
 136  * hb_ft_font_get_load_flags:
 137  * @font:
 138  *
 139  * 
 140  *
 141  * Return value:
 142  * Since: 1.0.5
 143  **/
 144 int
 145 hb_ft_font_get_load_flags (hb_font_t *font)
 146 {
 147   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 148     return 0;
 149 
 150   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 151 
 152   return ft_font->load_flags;
 153 }
 154 
 155 FT_Face
 156 hb_ft_font_get_face (hb_font_t *font)
 157 {
 158   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
 159     return NULL;
 160 
 161   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 162 
 163   return ft_font->ft_face;
 164 }
 165 
 166 
 167 
 168 static hb_bool_t
 169 hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
 170                          void *font_data,
 171                          hb_codepoint_t unicode,
 172                          hb_codepoint_t *glyph,
 173                          void *user_data HB_UNUSED)
 174 {
 175   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 176   unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
 177 
 178   if (unlikely (!g))
 179   {


 405 static hb_bool_t
 406 hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
 407                           void *font_data,
 408                           hb_font_extents_t *metrics,
 409                           void *user_data HB_UNUSED)
 410 {
 411   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 412   FT_Face ft_face = ft_font->ft_face;
 413   metrics->ascender = ft_face->size->metrics.ascender;
 414   metrics->descender = ft_face->size->metrics.descender;
 415   metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
 416   if (font->y_scale < 0)
 417   {
 418     metrics->ascender = -metrics->ascender;
 419     metrics->descender = -metrics->descender;
 420     metrics->line_gap = -metrics->line_gap;
 421   }
 422   return true;
 423 }
 424 
 425 static hb_font_funcs_t *static_ft_funcs = NULL;
 426 
 427 #ifdef HB_USE_ATEXIT
 428 static
 429 void free_static_ft_funcs (void)
 430 {
 431   hb_font_funcs_destroy (static_ft_funcs);
 432 }
 433 #endif
 434 
 435 static void
 436 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
 437 {
 438 retry:
 439   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
 440 
 441   if (unlikely (!funcs))
 442   {
 443     funcs = hb_font_funcs_create ();
 444 
 445     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
 446     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
 447     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
 448     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
 449     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
 450     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
 451     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
 452     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
 453     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
 454     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
 455     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
 456     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
 457     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
 458     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
 459 
 460     hb_font_funcs_make_immutable (funcs);
 461 
 462     if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
 463       hb_font_funcs_destroy (funcs);
 464       goto retry;
 465     }
 466 
 467 #ifdef HB_USE_ATEXIT
 468     atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
 469 #endif
 470   };
 471 
 472   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
 473 
 474   hb_font_set_funcs (font,
 475                      funcs,
 476                      _hb_ft_font_create (ft_face, symbol, unref),
 477                      (hb_destroy_func_t) _hb_ft_font_destroy);
 478 }
 479 
 480 
 481 static hb_blob_t *
 482 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 483 {
 484   FT_Face ft_face = (FT_Face) user_data;
 485   FT_Byte *buffer;
 486   FT_ULong  length = 0;
 487   FT_Error error;
 488 
 489   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
 490 
 491   error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
 492   if (error)
 493     return NULL;
 494 
 495   buffer = (FT_Byte *) malloc (length);
 496   if (buffer == NULL)
 497     return NULL;
 498 
 499   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
 500   if (error)
 501     return NULL;
 502 
 503   return hb_blob_create ((const char *) buffer, length,
 504                          HB_MEMORY_MODE_WRITABLE,
 505                          buffer, free);
 506 }
 507 
 508 /**
 509  * hb_ft_face_create:
 510  * @ft_face: (destroy destroy) (scope notified): 
 511  * @destroy:
 512  *
 513  * 
 514  *
 515  * Return value: (transfer full): 
 516  * Since: 0.9.2
 517  **/
 518 hb_face_t *
 519 hb_ft_face_create (FT_Face           ft_face,
 520                    hb_destroy_func_t destroy)
 521 {
 522   hb_face_t *face;
 523 
 524   if (ft_face->stream->read == NULL) {
 525     hb_blob_t *blob;
 526 
 527     blob = hb_blob_create ((const char *) ft_face->stream->base,
 528                            (unsigned int) ft_face->stream->size,
 529                            HB_MEMORY_MODE_READONLY,
 530                            ft_face, destroy);
 531     face = hb_face_create (blob, ft_face->face_index);
 532     hb_blob_destroy (blob);
 533   } else {
 534     face = hb_face_create_for_tables (reference_table, ft_face, destroy);
 535   }
 536 
 537   hb_face_set_index (face, ft_face->face_index);
 538   hb_face_set_upem (face, ft_face->units_per_EM);
 539 
 540   return face;
 541 }
 542 
 543 /**
 544  * hb_ft_face_create_referenced:
 545  * @ft_face:
 546  *
 547  * 
 548  *
 549  * Return value: (transfer full): 
 550  * Since: 0.9.38
 551  **/
 552 hb_face_t *
 553 hb_ft_face_create_referenced (FT_Face ft_face)
 554 {
 555   FT_Reference_Face (ft_face);
 556   return hb_ft_face_create (ft_face, (hb_destroy_func_t) _hb_ft_face_destroy);
 557 }
 558 
 559 static void
 560 hb_ft_face_finalize (FT_Face ft_face)
 561 {
 562   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
 563 }
 564 
 565 /**
 566  * hb_ft_face_create_cached:
 567  * @ft_face: 
 568  *
 569  * 
 570  *
 571  * Return value: (transfer full): 
 572  * Since: 0.9.2
 573  **/
 574 hb_face_t *
 575 hb_ft_face_create_cached (FT_Face ft_face)
 576 {
 577   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
 578   {
 579     if (ft_face->generic.finalizer)
 580       ft_face->generic.finalizer (ft_face);
 581 
 582     ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
 583     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
 584   }
 585 
 586   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 587 }
 588 
 589 
 590 /**
 591  * hb_ft_font_create:
 592  * @ft_face: (destroy destroy) (scope notified): 
 593  * @destroy:
 594  *
 595  * 
 596  *
 597  * Return value: (transfer full): 
 598  * Since: 0.9.2
 599  **/
 600 hb_font_t *
 601 hb_ft_font_create (FT_Face           ft_face,
 602                    hb_destroy_func_t destroy)
 603 {
 604   hb_font_t *font;
 605   hb_face_t *face;
 606 
 607   face = hb_ft_face_create (ft_face, destroy);
 608   font = hb_font_create (face);
 609   hb_face_destroy (face);
 610   _hb_ft_font_set_funcs (font, ft_face, false);













 611   hb_font_set_scale (font,
 612                      (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
 613                      (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
 614 #if 0 /* hb-ft works in no-hinting model */
 615   hb_font_set_ppem (font,
 616                     ft_face->size->metrics.x_ppem,
 617                     ft_face->size->metrics.y_ppem);
 618 #endif
 619 
 620 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
 621   FT_MM_Var *mm_var = NULL;
 622   if (!FT_Get_MM_Var (ft_face, &mm_var))
 623   {
 624     FT_Fixed coords[mm_var->num_axis];
 625     int hbCoords[mm_var->num_axis];
 626     if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, coords))
 627     {
 628       for (int i = 0; i < mm_var->num_axis; ++i)
 629         hbCoords[i] = coords[i] >> 2;


 630 
 631       hb_font_set_var_coords_normalized (font, hbCoords, mm_var->num_axis);
 632     }
 633   }


 634   free (mm_var);

 635 #endif
 636 
 637   return font;
 638 }
 639 
 640 /**
 641  * hb_ft_font_create_referenced:
 642  * @ft_face:
 643  *
 644  * 
 645  *
 646  * Return value: (transfer full): 
 647  * Since: 0.9.38
 648  **/
 649 hb_font_t *
 650 hb_ft_font_create_referenced (FT_Face ft_face)
 651 {
 652   FT_Reference_Face (ft_face);
 653   return hb_ft_font_create (ft_face, (hb_destroy_func_t) _hb_ft_face_destroy);
 654 }
 655 
 656 
 657 /* Thread-safe, lock-free, FT_Library */
 658 
 659 static FT_Library ft_library;
 660 
 661 #ifdef HB_USE_ATEXIT
 662 static
 663 void free_ft_library (void)
 664 {
 665   FT_Done_FreeType (ft_library);
 666 }
 667 #endif
 668 
 669 static FT_Library
 670 get_ft_library (void)
 671 {
 672 retry:
 673   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
 674 
 675   if (unlikely (!library))
 676   {
 677     /* Not found; allocate one. */
 678     if (FT_Init_FreeType (&library))
 679       return NULL;
 680 
 681     if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
 682       FT_Done_FreeType (library);
 683       goto retry;
 684     }
 685 
 686 #ifdef HB_USE_ATEXIT
 687     atexit (free_ft_library); /* First person registers atexit() callback. */
 688 #endif
 689   }
 690 
 691   return library;
 692 }
 693 
 694 static void
 695 _release_blob (FT_Face ft_face)
 696 {
 697   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 698 }
 699 
 700 void
 701 hb_ft_font_set_funcs (hb_font_t *font)
 702 {
 703   hb_blob_t *blob = hb_face_reference_blob (font->face);
 704   unsigned int blob_length;
 705   const char *blob_data = hb_blob_get_data (blob, &blob_length);
 706   if (unlikely (!blob_length))
 707     DEBUG_MSG (FT, font, "Font face has empty blob");
 708 
 709   FT_Face ft_face = NULL;
 710   FT_Error err = FT_New_Memory_Face (get_ft_library (),
 711                                      (const FT_Byte *) blob_data,
 712                                      blob_length,
 713                                      hb_face_get_index (font->face),
 714                                      &ft_face);
 715 
 716   if (unlikely (err)) {
 717     hb_blob_destroy (blob);
 718     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
 719     return;
 720   }
 721 
 722   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
 723     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
 724 
 725   FT_Set_Char_Size (ft_face,
 726                     abs (font->x_scale), abs (font->y_scale),
 727                     0, 0);
 728 #if 0
 729                     font->x_ppem * 72 * 64 / font->x_scale,
 730                     font->y_ppem * 72 * 64 / font->y_scale);
 731 #endif
 732   if (font->x_scale < 0 || font->y_scale < 0)
 733   {
 734     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
 735                           0, font->y_scale < 0 ? -1 : +1};
 736     FT_Set_Transform (ft_face, &matrix, NULL);














 737   }
 738 
 739   ft_face->generic.data = blob;
 740   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
 741 
 742   _hb_ft_font_set_funcs (font, ft_face, true);
 743   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
 744 }


  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 exteremely 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_ft_font_destroy)
 123     return;
 124 
 125   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
 126 
 127   ft_font->load_flags = load_flags;
 128 }
 129 
 130 /**
 131  * hb_ft_font_get_load_flags:
 132  * @font:
 133  *
 134  *
 135  *
 136  * Return value:
 137  * Since: 1.0.5
 138  **/
 139 int
 140 hb_ft_font_get_load_flags (hb_font_t *font)
 141 {
 142   if (font->destroy != _hb_ft_font_destroy)
 143     return 0;
 144 
 145   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 146 
 147   return ft_font->load_flags;
 148 }
 149 
 150 FT_Face
 151 hb_ft_font_get_face (hb_font_t *font)
 152 {
 153   if (font->destroy != _hb_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   {


 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   hb_font_funcs_destroy (static_ft_funcs);
 427 }
 428 #endif
 429 
 430 static void
 431 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
 432 {
 433 retry:
 434   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
 435 
 436   if (unlikely (!funcs))
 437   {
 438     funcs = hb_font_funcs_create ();
 439 
 440     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
 441     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
 442     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
 443     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
 444     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
 445     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
 446     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
 447     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
 448     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
 449     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
 450     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
 451     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
 452     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
 453     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 454 
 455     hb_font_funcs_make_immutable (funcs);
 456 
 457     if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
 458       hb_font_funcs_destroy (funcs);
 459       goto retry;
 460     }
 461 
 462 #ifdef HB_USE_ATEXIT
 463     atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
 464 #endif
 465   };
 466 
 467   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
 468 
 469   hb_font_set_funcs (font,
 470                      funcs,
 471                      _hb_ft_font_create (ft_face, symbol, unref),
 472                      _hb_ft_font_destroy);
 473 }
 474 
 475 
 476 static hb_blob_t *
 477 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 478 {
 479   FT_Face ft_face = (FT_Face) user_data;
 480   FT_Byte *buffer;
 481   FT_ULong  length = 0;
 482   FT_Error error;
 483 
 484   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
 485 
 486   error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
 487   if (error)
 488     return nullptr;
 489 
 490   buffer = (FT_Byte *) malloc (length);
 491   if (!buffer)
 492     return nullptr;
 493 
 494   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
 495   if (error)
 496     return nullptr;
 497 
 498   return hb_blob_create ((const char *) buffer, length,
 499                          HB_MEMORY_MODE_WRITABLE,
 500                          buffer, free);
 501 }
 502 
 503 /**
 504  * hb_ft_face_create:
 505  * @ft_face: (destroy destroy) (scope notified):
 506  * @destroy:
 507  *
 508  *
 509  *
 510  * Return value: (transfer full):
 511  * Since: 0.9.2
 512  **/
 513 hb_face_t *
 514 hb_ft_face_create (FT_Face           ft_face,
 515                    hb_destroy_func_t destroy)
 516 {
 517   hb_face_t *face;
 518 
 519   if (!ft_face->stream->read) {
 520     hb_blob_t *blob;
 521 
 522     blob = hb_blob_create ((const char *) ft_face->stream->base,
 523                            (unsigned int) ft_face->stream->size,
 524                            HB_MEMORY_MODE_READONLY,
 525                            ft_face, destroy);
 526     face = hb_face_create (blob, ft_face->face_index);
 527     hb_blob_destroy (blob);
 528   } else {
 529     face = hb_face_create_for_tables (reference_table, ft_face, destroy);
 530   }
 531 
 532   hb_face_set_index (face, ft_face->face_index);
 533   hb_face_set_upem (face, ft_face->units_per_EM);
 534 
 535   return face;
 536 }
 537 
 538 /**
 539  * hb_ft_face_create_referenced:
 540  * @ft_face:
 541  *
 542  *
 543  *
 544  * Return value: (transfer full):
 545  * Since: 0.9.38
 546  **/
 547 hb_face_t *
 548 hb_ft_face_create_referenced (FT_Face ft_face)
 549 {
 550   FT_Reference_Face (ft_face);
 551   return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
 552 }
 553 
 554 static void
 555 hb_ft_face_finalize (FT_Face ft_face)
 556 {
 557   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
 558 }
 559 
 560 /**
 561  * hb_ft_face_create_cached:
 562  * @ft_face:
 563  *
 564  *
 565  *
 566  * Return value: (transfer full):
 567  * Since: 0.9.2
 568  **/
 569 hb_face_t *
 570 hb_ft_face_create_cached (FT_Face ft_face)
 571 {
 572   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
 573   {
 574     if (ft_face->generic.finalizer)
 575       ft_face->generic.finalizer (ft_face);
 576 
 577     ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
 578     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
 579   }
 580 
 581   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 582 }
 583 
 584 
 585 /**
 586  * hb_ft_font_create:
 587  * @ft_face: (destroy destroy) (scope notified):
 588  * @destroy:
 589  *
 590  *
 591  *
 592  * Return value: (transfer full):
 593  * Since: 0.9.2
 594  **/
 595 hb_font_t *
 596 hb_ft_font_create (FT_Face           ft_face,
 597                    hb_destroy_func_t destroy)
 598 {
 599   hb_font_t *font;
 600   hb_face_t *face;
 601 
 602   face = hb_ft_face_create (ft_face, destroy);
 603   font = hb_font_create (face);
 604   hb_face_destroy (face);
 605   _hb_ft_font_set_funcs (font, ft_face, false);
 606   hb_ft_font_changed (font);
 607   return font;
 608 }
 609 
 610 void
 611 hb_ft_font_changed (hb_font_t *font)
 612 {
 613   if (font->destroy != _hb_ft_font_destroy)
 614     return;
 615 
 616   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
 617   FT_Face ft_face = ft_font->ft_face;
 618 
 619   hb_font_set_scale (font,
 620                      (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
 621                      (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
 622 #if 0 /* hb-ft works in no-hinting model */
 623   hb_font_set_ppem (font,
 624                     ft_face->size->metrics.x_ppem,
 625                     ft_face->size->metrics.y_ppem);
 626 #endif
 627 
 628 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
 629   FT_MM_Var *mm_var = nullptr;
 630   if (!FT_Get_MM_Var (ft_face, &mm_var))
 631   {
 632     FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
 633     int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
 634     if (coords && ft_coords)
 635     {
 636       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
 637       {
 638         for (unsigned int i = 0; i < mm_var->num_axis; ++i)
 639           coords[i] = ft_coords[i] >>= 2;
 640 
 641         hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
 642       }
 643     }
 644     free (coords);
 645     free (ft_coords);
 646     free (mm_var);
 647   }
 648 #endif


 649 }
 650 
 651 /**
 652  * hb_ft_font_create_referenced:
 653  * @ft_face:
 654  *
 655  *
 656  *
 657  * Return value: (transfer full):
 658  * Since: 0.9.38
 659  **/
 660 hb_font_t *
 661 hb_ft_font_create_referenced (FT_Face ft_face)
 662 {
 663   FT_Reference_Face (ft_face);
 664   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 665 }
 666 
 667 
 668 /* Thread-safe, lock-free, FT_Library */
 669 
 670 static FT_Library ft_library;
 671 
 672 #ifdef HB_USE_ATEXIT
 673 static
 674 void free_ft_library (void)
 675 {
 676   FT_Done_FreeType (ft_library);
 677 }
 678 #endif
 679 
 680 static FT_Library
 681 get_ft_library (void)
 682 {
 683 retry:
 684   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
 685 
 686   if (unlikely (!library))
 687   {
 688     /* Not found; allocate one. */
 689     if (FT_Init_FreeType (&library))
 690       return nullptr;
 691 
 692     if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
 693       FT_Done_FreeType (library);
 694       goto retry;
 695     }
 696 
 697 #ifdef HB_USE_ATEXIT
 698     atexit (free_ft_library); /* First person registers atexit() callback. */
 699 #endif
 700   }
 701 
 702   return library;
 703 }
 704 
 705 static void
 706 _release_blob (FT_Face ft_face)
 707 {
 708   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 709 }
 710 
 711 void
 712 hb_ft_font_set_funcs (hb_font_t *font)
 713 {
 714   hb_blob_t *blob = hb_face_reference_blob (font->face);
 715   unsigned int blob_length;
 716   const char *blob_data = hb_blob_get_data (blob, &blob_length);
 717   if (unlikely (!blob_length))
 718     DEBUG_MSG (FT, font, "Font face has empty blob");
 719 
 720   FT_Face ft_face = nullptr;
 721   FT_Error err = FT_New_Memory_Face (get_ft_library (),
 722                                      (const FT_Byte *) blob_data,
 723                                      blob_length,
 724                                      hb_face_get_index (font->face),
 725                                      &ft_face);
 726 
 727   if (unlikely (err)) {
 728     hb_blob_destroy (blob);
 729     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
 730     return;
 731   }
 732 
 733   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
 734     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
 735 
 736   FT_Set_Char_Size (ft_face,
 737                     abs (font->x_scale), abs (font->y_scale),
 738                     0, 0);
 739 #if 0
 740                     font->x_ppem * 72 * 64 / font->x_scale,
 741                     font->y_ppem * 72 * 64 / font->y_scale);
 742 #endif
 743   if (font->x_scale < 0 || font->y_scale < 0)
 744   {
 745     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
 746                           0, font->y_scale < 0 ? -1 : +1};
 747     FT_Set_Transform (ft_face, &matrix, nullptr);
 748   }
 749 
 750   unsigned int num_coords;
 751   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
 752   if (num_coords)
 753   {
 754     FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
 755     if (ft_coords)
 756     {
 757       for (unsigned int i = 0; i < num_coords; i++)
 758         ft_coords[i] = coords[i] << 2;
 759       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
 760       free (ft_coords);
 761     }
 762   }
 763 
 764   ft_face->generic.data = blob;
 765   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
 766 
 767   _hb_ft_font_set_funcs (font, ft_face, true);
 768   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
 769 }
< prev index next >