Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2009  Red Hat, Inc.
      3  * Copyright  2009  Keith Stribley
      4  *
      5  *  This is part of HarfBuzz, a text shaping library.
      6  *
      7  * Permission is hereby granted, without written agreement and without
      8  * license or royalty fees, to use, copy, modify, and distribute this
      9  * software and its documentation for any purpose, provided that the
     10  * above copyright notice and the following two paragraphs appear in
     11  * all copies of this software.
     12  *
     13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17  * DAMAGE.
     18  *
     19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24  *
     25  * Red Hat Author(s): Behdad Esfahbod
     26  */
     27 
     28 #include "hb-private.hh"
     29 
     30 #include "hb-ft.h"
     31 
     32 #include "hb-font-private.hh"
     33 
     34 #include FT_ADVANCES_H
     35 #include FT_TRUETYPE_TABLES_H
     36 
     37 
     38 
     39 #ifndef HB_DEBUG_FT
     40 #define HB_DEBUG_FT (HB_DEBUG+0)
     41 #endif
     42 
     43 
     44 /* TODO:
     45  *
     46  * In general, this file does a fine job of what it's supposed to do.
     47  * There are, however, things that need more work:
     48  *
     49  *   - We don't handle any load_flags.  That definitely has API implications. :(
     50  *     I believe hb_ft_font_create() should take load_flags input.
     51  *     In particular, FT_Get_Advance() without the NO_HINTING flag seems to be
     52  *     buggy.
     53  *
     54  *   - We don't handle / allow for emboldening / obliqueing.
     55  *
     56  *   - In the future, we should add constructors to create fonts in font space?
     57  *
     58  *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
     59  */
     60 
     61 
     62 static hb_bool_t
     63 hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
     64 		 void *font_data,
     65 		 hb_codepoint_t unicode,
     66 		 hb_codepoint_t variation_selector,
     67 		 hb_codepoint_t *glyph,
     68 		 void *user_data HB_UNUSED)
     69 
     70 {
     71   FT_Face ft_face = (FT_Face) font_data;
     72 
     73 #ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
     74   if (unlikely (variation_selector)) {
     75     *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
     76     if (*glyph)
     77       return true;
     78   }
     79 #endif
     80 
     81   *glyph = FT_Get_Char_Index (ft_face, unicode);
     82   return *glyph != 0;
     83 }
     84 
     85 static hb_position_t
     86 hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
     87 			   void *font_data,
     88 			   hb_codepoint_t glyph,
     89 			   void *user_data HB_UNUSED)
     90 {
     91   FT_Face ft_face = (FT_Face) font_data;
     92   int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
     93   FT_Fixed v;
     94 
     95   if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
     96     return 0;
     97 
     98   return v >> 10;
     99 }
    100 
    101 static hb_position_t
    102 hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
    103 			   void *font_data,
    104 			   hb_codepoint_t glyph,
    105 			   void *user_data HB_UNUSED)
    106 {
    107   FT_Face ft_face = (FT_Face) font_data;
    108   int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT;
    109   FT_Fixed v;
    110 
    111   if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
    112     return 0;
    113 
    114   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    115    * have a Y growing upward.  Hence the extra negation. */
    116   return -v >> 10;
    117 }
    118 
    119 static hb_bool_t
    120 hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
    121 			  void *font_data HB_UNUSED,
    122 			  hb_codepoint_t glyph HB_UNUSED,
    123 			  hb_position_t *x HB_UNUSED,
    124 			  hb_position_t *y HB_UNUSED,
    125 			  void *user_data HB_UNUSED)
    126 {
    127   /* We always work in the horizontal coordinates. */
    128   return true;
    129 }
    130 
    131 static hb_bool_t
    132 hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
    133 			  void *font_data,
    134 			  hb_codepoint_t glyph,
    135 			  hb_position_t *x,
    136 			  hb_position_t *y,
    137 			  void *user_data HB_UNUSED)
    138 {
    139   FT_Face ft_face = (FT_Face) font_data;
    140   int load_flags = FT_LOAD_DEFAULT;
    141 
    142   if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
    143     return false;
    144 
    145   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    146    * have a Y growing upward.  Hence the extra negation. */
    147   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
    148   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
    149 
    150   return true;
    151 }
    152 
    153 static hb_position_t
    154 hb_ft_get_glyph_h_kerning (hb_font_t *font,
    155 			   void *font_data,
    156 			   hb_codepoint_t left_glyph,
    157 			   hb_codepoint_t right_glyph,
    158 			   void *user_data HB_UNUSED)
    159 {
    160   FT_Face ft_face = (FT_Face) font_data;
    161   FT_Vector kerningv;
    162 
    163   FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
    164   if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv))
    165     return 0;
    166 
    167   return kerningv.x;
    168 }
    169 
    170 static hb_position_t
    171 hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
    172 			   void *font_data HB_UNUSED,
    173 			   hb_codepoint_t top_glyph HB_UNUSED,
    174 			   hb_codepoint_t bottom_glyph HB_UNUSED,
    175 			   void *user_data HB_UNUSED)
    176 {
    177   /* FreeType API doesn't support vertical kerning */
    178   return 0;
    179 }
    180 
    181 static hb_bool_t
    182 hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
    183 			 void *font_data,
    184 			 hb_codepoint_t glyph,
    185 			 hb_glyph_extents_t *extents,
    186 			 void *user_data HB_UNUSED)
    187 {
    188   FT_Face ft_face = (FT_Face) font_data;
    189   int load_flags = FT_LOAD_DEFAULT;
    190 
    191   if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
    192     return false;
    193 
    194   extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
    195   extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
    196   extents->width = ft_face->glyph->metrics.width;
    197   extents->height = -ft_face->glyph->metrics.height;
    198   return true;
    199 }
    200 
    201 static hb_bool_t
    202 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
    203 			       void *font_data,
    204 			       hb_codepoint_t glyph,
    205 			       unsigned int point_index,
    206 			       hb_position_t *x,
    207 			       hb_position_t *y,
    208 			       void *user_data HB_UNUSED)
    209 {
    210   FT_Face ft_face = (FT_Face) font_data;
    211   int load_flags = FT_LOAD_DEFAULT;
    212 
    213   if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
    214       return false;
    215 
    216   if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
    217       return false;
    218 
    219   if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
    220       return false;
    221 
    222   *x = ft_face->glyph->outline.points[point_index].x;
    223   *y = ft_face->glyph->outline.points[point_index].y;
    224 
    225   return true;
    226 }
    227 
    228 static hb_bool_t
    229 hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
    230 		      void *font_data,
    231 		      hb_codepoint_t glyph,
    232 		      char *name, unsigned int size,
    233 		      void *user_data HB_UNUSED)
    234 {
    235   FT_Face ft_face = (FT_Face) font_data;
    236 
    237   hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
    238   if (ret && (size && !*name))
    239     ret = false;
    240 
    241   return ret;
    242 }
    243 
    244 static hb_bool_t
    245 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
    246 			   void *font_data,
    247 			   const char *name, int len, /* -1 means nul-terminated */
    248 			   hb_codepoint_t *glyph,
    249 			   void *user_data HB_UNUSED)
    250 {
    251   FT_Face ft_face = (FT_Face) font_data;
    252 
    253   if (len < 0)
    254     *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
    255   else {
    256     /* Make a nul-terminated version. */
    257     char buf[128];
    258     len = MIN (len, (int) sizeof (buf) - 1);
    259     strncpy (buf, name, len);
    260     buf[len] = '\0';
    261     *glyph = FT_Get_Name_Index (ft_face, buf);
    262   }
    263 
    264   return *glyph != 0;
    265 }
    266 
    267 
    268 static hb_font_funcs_t *
    269 _hb_ft_get_font_funcs (void)
    270 {
    271   static const hb_font_funcs_t ft_ffuncs = {
    272     HB_OBJECT_HEADER_STATIC,
    273 
    274     true, /* immutable */
    275 
    276     {
    277 #define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name,
    278       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
    279 #undef HB_FONT_FUNC_IMPLEMENT
    280     }
    281   };
    282 
    283   return const_cast<hb_font_funcs_t *> (&ft_ffuncs);
    284 }
    285 
    286 
    287 static hb_blob_t *
    288 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
    289 {
    290   FT_Face ft_face = (FT_Face) user_data;
    291   FT_Byte *buffer;
    292   FT_ULong  length = 0;
    293   FT_Error error;
    294 
    295   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
    296 
    297   error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
    298   if (error)
    299     return NULL;
    300 
    301   buffer = (FT_Byte *) malloc (length);
    302   if (buffer == NULL)
    303     return NULL;
    304 
    305   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
    306   if (error)
    307     return NULL;
    308 
    309   return hb_blob_create ((const char *) buffer, length,
    310 			 HB_MEMORY_MODE_WRITABLE,
    311 			 buffer, free);
    312 }
    313 
    314 
    315 hb_face_t *
    316 hb_ft_face_create (FT_Face           ft_face,
    317 		   hb_destroy_func_t destroy)
    318 {
    319   hb_face_t *face;
    320 
    321   if (ft_face->stream->read == NULL) {
    322     hb_blob_t *blob;
    323 
    324     blob = hb_blob_create ((const char *) ft_face->stream->base,
    325 			   (unsigned int) ft_face->stream->size,
    326 			   /* TODO: We assume that it's mmap()'ed, but FreeType code
    327 			    * suggests that there are cases we reach here but font is
    328 			    * not mmapped.  For example, when mmap() fails.  No idea
    329 			    * how to deal with it better here. */
    330 			   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
    331 			   ft_face, destroy);
    332     face = hb_face_create (blob, ft_face->face_index);
    333     hb_blob_destroy (blob);
    334   } else {
    335     face = hb_face_create_for_tables (reference_table, ft_face, destroy);
    336   }
    337 
    338   hb_face_set_index (face, ft_face->face_index);
    339   hb_face_set_upem (face, ft_face->units_per_EM);
    340 
    341   return face;
    342 }
    343 
    344 static void
    345 hb_ft_face_finalize (FT_Face ft_face)
    346 {
    347   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
    348 }
    349 
    350 hb_face_t *
    351 hb_ft_face_create_cached (FT_Face ft_face)
    352 {
    353   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
    354   {
    355     if (ft_face->generic.finalizer)
    356       ft_face->generic.finalizer (ft_face);
    357 
    358     ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
    359     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
    360   }
    361 
    362   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
    363 }
    364 
    365 static void
    366 _do_nothing (void)
    367 {
    368 }
    369 
    370 
    371 hb_font_t *
    372 hb_ft_font_create (FT_Face           ft_face,
    373 		   hb_destroy_func_t destroy)
    374 {
    375   hb_font_t *font;
    376   hb_face_t *face;
    377 
    378   face = hb_ft_face_create (ft_face, destroy);
    379   font = hb_font_create (face);
    380   hb_face_destroy (face);
    381   hb_font_set_funcs (font,
    382 		     _hb_ft_get_font_funcs (),
    383 		     ft_face, (hb_destroy_func_t) _do_nothing);
    384   hb_font_set_scale (font,
    385 		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
    386 		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
    387   hb_font_set_ppem (font,
    388 		    ft_face->size->metrics.x_ppem,
    389 		    ft_face->size->metrics.y_ppem);
    390 
    391   return font;
    392 }
    393 
    394 
    395 /* Thread-safe, lock-free, FT_Library */
    396 
    397 static FT_Library ft_library;
    398 
    399 static inline
    400 void free_ft_library (void)
    401 {
    402   FT_Done_FreeType (ft_library);
    403 }
    404 
    405 static FT_Library
    406 get_ft_library (void)
    407 {
    408 retry:
    409   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
    410 
    411   if (unlikely (!library))
    412   {
    413     /* Not found; allocate one. */
    414     if (FT_Init_FreeType (&library))
    415       return NULL;
    416 
    417     if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
    418       FT_Done_FreeType (library);
    419       goto retry;
    420     }
    421 
    422 #ifdef HAVE_ATEXIT
    423     atexit (free_ft_library); /* First person registers atexit() callback. */
    424 #endif
    425   }
    426 
    427   return library;
    428 }
    429 
    430 static void
    431 _release_blob (FT_Face ft_face)
    432 {
    433   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
    434 }
    435 
    436 void
    437 hb_ft_font_set_funcs (hb_font_t *font)
    438 {
    439   hb_blob_t *blob = hb_face_reference_blob (font->face);
    440   unsigned int blob_length;
    441   const char *blob_data = hb_blob_get_data (blob, &blob_length);
    442   if (unlikely (!blob_length))
    443     DEBUG_MSG (FT, font, "Font face has empty blob");
    444 
    445   FT_Face ft_face = NULL;
    446   FT_Error err = FT_New_Memory_Face (get_ft_library (),
    447 				     (const FT_Byte *) blob_data,
    448 				     blob_length,
    449 				     hb_face_get_index (font->face),
    450 				     &ft_face);
    451 
    452   if (unlikely (err)) {
    453     hb_blob_destroy (blob);
    454     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
    455     return;
    456   }
    457 
    458   FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
    459 
    460   assert (font->y_scale >= 0);
    461   FT_Set_Char_Size (ft_face,
    462 		    font->x_scale, font->y_scale,
    463 		    0, 0);
    464 #if 0
    465 		    font->x_ppem * 72 * 64 / font->x_scale,
    466 		    font->y_ppem * 72 * 64 / font->y_scale);
    467 #endif
    468 
    469   ft_face->generic.data = blob;
    470   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
    471 
    472   hb_font_set_funcs (font,
    473 		     _hb_ft_get_font_funcs (),
    474 		     ft_face,
    475 		     (hb_destroy_func_t) FT_Done_Face);
    476 }
    477 
    478 FT_Face
    479 hb_ft_font_get_face (hb_font_t *font)
    480 {
    481   if (font->destroy == (hb_destroy_func_t) FT_Done_Face ||
    482       font->destroy == (hb_destroy_func_t) _do_nothing)
    483     return (FT_Face) font->user_data;
    484 
    485   return NULL;
    486 }
    487