Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2011,2014  Google, Inc.
      3  *
      4  *  This is part of HarfBuzz, a text shaping library.
      5  *
      6  * Permission is hereby granted, without written agreement and without
      7  * license or royalty fees, to use, copy, modify, and distribute this
      8  * software and its documentation for any purpose, provided that the
      9  * above copyright notice and the following two paragraphs appear in
     10  * all copies of this software.
     11  *
     12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     16  * DAMAGE.
     17  *
     18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     23  *
     24  * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
     25  */
     26 
     27 #include "hb-private.hh"
     28 
     29 #include "hb-ot.h"
     30 
     31 #include "hb-font-private.hh"
     32 
     33 #include "hb-ot-cmap-table.hh"
     34 #include "hb-ot-cbdt-table.hh"
     35 #include "hb-ot-glyf-table.hh"
     36 #include "hb-ot-head-table.hh"
     37 #include "hb-ot-hhea-table.hh"
     38 #include "hb-ot-hmtx-table.hh"
     39 #include "hb-ot-os2-table.hh"
     40 #include "hb-ot-var-hvar-table.hh"
     41 //#include "hb-ot-post-table.hh"
     42 
     43 
     44 struct hb_ot_face_metrics_accelerator_t
     45 {
     46   unsigned int num_metrics;
     47   unsigned int num_advances;
     48   unsigned int default_advance;
     49   unsigned short ascender;
     50   unsigned short descender;
     51   unsigned short line_gap;
     52   bool has_font_extents;
     53 
     54   const OT::hmtxvmtx *table;
     55   hb_blob_t *blob;
     56 
     57   const OT::HVARVVAR *var;
     58   hb_blob_t *var_blob;
     59 
     60   inline void init (hb_face_t *face,
     61 		    hb_tag_t _hea_tag,
     62 		    hb_tag_t _mtx_tag,
     63 		    hb_tag_t _var_tag,
     64 		    hb_tag_t os2_tag,
     65 		    unsigned int default_advance = 0)
     66   {
     67     this->default_advance = default_advance ? default_advance : face->get_upem ();
     68 
     69     bool got_font_extents = false;
     70     if (os2_tag)
     71     {
     72       hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
     73       const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
     74 #define USE_TYPO_METRICS (1u<<7)
     75       if (0 != (os2->fsSelection & USE_TYPO_METRICS))
     76       {
     77 	this->ascender = os2->sTypoAscender;
     78 	this->descender = os2->sTypoDescender;
     79 	this->line_gap = os2->sTypoLineGap;
     80 	got_font_extents = (this->ascender | this->descender) != 0;
     81       }
     82       hb_blob_destroy (os2_blob);
     83     }
     84 
     85     hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
     86     const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
     87     this->num_advances = _hea->numberOfLongMetrics;
     88     if (!got_font_extents)
     89     {
     90       this->ascender = _hea->ascender;
     91       this->descender = _hea->descender;
     92       this->line_gap = _hea->lineGap;
     93       got_font_extents = (this->ascender | this->descender) != 0;
     94     }
     95     hb_blob_destroy (_hea_blob);
     96 
     97     this->has_font_extents = got_font_extents;
     98 
     99     this->blob = OT::Sanitizer<OT::hmtxvmtx>::sanitize (face->reference_table (_mtx_tag));
    100 
    101     /* Cap num_metrics() and num_advances() based on table length. */
    102     unsigned int len = hb_blob_get_length (this->blob);
    103     if (unlikely (this->num_advances * 4 > len))
    104       this->num_advances = len / 4;
    105     this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
    106 
    107     /* We MUST set num_metrics to zero if num_advances is zero.
    108      * Our get_advance() depends on that. */
    109     if (unlikely (!this->num_advances))
    110     {
    111       this->num_metrics = this->num_advances = 0;
    112       hb_blob_destroy (this->blob);
    113       this->blob = hb_blob_get_empty ();
    114     }
    115     this->table = OT::Sanitizer<OT::hmtxvmtx>::lock_instance (this->blob);
    116 
    117     this->var_blob = OT::Sanitizer<OT::HVARVVAR>::sanitize (face->reference_table (_var_tag));
    118     this->var = OT::Sanitizer<OT::HVARVVAR>::lock_instance (this->var_blob);
    119   }
    120 
    121   inline void fini (void)
    122   {
    123     hb_blob_destroy (this->blob);
    124     hb_blob_destroy (this->var_blob);
    125   }
    126 
    127   inline unsigned int get_advance (hb_codepoint_t  glyph,
    128 				   hb_font_t      *font) const
    129   {
    130     if (unlikely (glyph >= this->num_metrics))
    131     {
    132       /* If this->num_metrics is zero, it means we don't have the metrics table
    133        * for this direction: return default advance.  Otherwise, it means that the
    134        * glyph index is out of bound: return zero. */
    135       if (this->num_metrics)
    136 	return 0;
    137       else
    138 	return this->default_advance;
    139     }
    140 
    141     return this->table->longMetric[MIN (glyph, this->num_advances - 1)].advance
    142 	 + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
    143   }
    144 };
    145 
    146 struct hb_ot_face_glyf_accelerator_t
    147 {
    148   bool short_offset;
    149   unsigned int num_glyphs;
    150   const OT::loca *loca;
    151   const OT::glyf *glyf;
    152   hb_blob_t *loca_blob;
    153   hb_blob_t *glyf_blob;
    154   unsigned int glyf_len;
    155 
    156   inline void init (hb_face_t *face)
    157   {
    158     hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
    159     const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
    160     if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
    161     {
    162       /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
    163       hb_blob_destroy (head_blob);
    164       return;
    165     }
    166     this->short_offset = 0 == head->indexToLocFormat;
    167     hb_blob_destroy (head_blob);
    168 
    169     this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
    170     this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
    171     this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
    172     this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);
    173 
    174     this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
    175     this->glyf_len = hb_blob_get_length (this->glyf_blob);
    176   }
    177 
    178   inline void fini (void)
    179   {
    180     hb_blob_destroy (this->loca_blob);
    181     hb_blob_destroy (this->glyf_blob);
    182   }
    183 
    184   inline bool get_extents (hb_codepoint_t glyph,
    185 			   hb_glyph_extents_t *extents) const
    186   {
    187     if (unlikely (glyph >= this->num_glyphs))
    188       return false;
    189 
    190     unsigned int start_offset, end_offset;
    191     if (this->short_offset)
    192     {
    193       start_offset = 2 * this->loca->u.shortsZ[glyph];
    194       end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
    195     }
    196     else
    197     {
    198       start_offset = this->loca->u.longsZ[glyph];
    199       end_offset   = this->loca->u.longsZ[glyph + 1];
    200     }
    201 
    202     if (start_offset > end_offset || end_offset > this->glyf_len)
    203       return false;
    204 
    205     if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
    206       return true; /* Empty glyph; zero extents. */
    207 
    208     const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);
    209 
    210     extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
    211     extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
    212     extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
    213     extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
    214 
    215     return true;
    216   }
    217 };
    218 
    219 struct hb_ot_face_cbdt_accelerator_t
    220 {
    221   hb_blob_t *cblc_blob;
    222   hb_blob_t *cbdt_blob;
    223   const OT::CBLC *cblc;
    224   const OT::CBDT *cbdt;
    225 
    226   unsigned int cbdt_len;
    227   float upem;
    228 
    229   inline void init (hb_face_t *face)
    230   {
    231     upem = face->get_upem();
    232 
    233     cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
    234     cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
    235     cbdt_len = hb_blob_get_length (cbdt_blob);
    236 
    237     if (hb_blob_get_length (cblc_blob) == 0) {
    238       cblc = NULL;
    239       cbdt = NULL;
    240       return;  /* Not a bitmap font. */
    241     }
    242     cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
    243     cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
    244 
    245   }
    246 
    247   inline void fini (void)
    248   {
    249     hb_blob_destroy (this->cblc_blob);
    250     hb_blob_destroy (this->cbdt_blob);
    251   }
    252 
    253   inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
    254   {
    255     unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
    256 
    257     if (cblc == NULL)
    258       return false;  // Not a color bitmap font.
    259 
    260     const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
    261     if (subtable_record == NULL)
    262       return false;
    263 
    264     if (subtable_record->get_extents (extents))
    265       return true;
    266 
    267     unsigned int image_offset = 0, image_length = 0, image_format = 0;
    268     if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
    269       return false;
    270 
    271     {
    272       /* TODO Move the following into CBDT struct when adding more formats. */
    273 
    274       if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
    275 	return false;
    276 
    277       switch (image_format)
    278       {
    279 	case 17: {
    280 	  if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
    281 	    return false;
    282 
    283 	  const OT::GlyphBitmapDataFormat17& glyphFormat17 =
    284 	      OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
    285 	  glyphFormat17.glyphMetrics.get_extents (extents);
    286 	}
    287 	break;
    288 	default:
    289 	  // TODO: Support other image formats.
    290 	  return false;
    291       }
    292     }
    293 
    294     /* Convert to the font units. */
    295     extents->x_bearing *= upem / (float) x_ppem;
    296     extents->y_bearing *= upem / (float) y_ppem;
    297     extents->width *= upem / (float) x_ppem;
    298     extents->height *= upem / (float) y_ppem;
    299 
    300     return true;
    301   }
    302 };
    303 
    304 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
    305 					  hb_codepoint_t codepoint,
    306 					  hb_codepoint_t *glyph);
    307 
    308 template <typename Type>
    309 static inline bool get_glyph_from (const void *obj,
    310 				   hb_codepoint_t codepoint,
    311 				   hb_codepoint_t *glyph)
    312 {
    313   const Type *typed_obj = (const Type *) obj;
    314   return typed_obj->get_glyph (codepoint, glyph);
    315 }
    316 
    317 template <typename Type>
    318 static inline bool get_glyph_from_symbol (const void *obj,
    319 					  hb_codepoint_t codepoint,
    320 					  hb_codepoint_t *glyph)
    321 {
    322   const Type *typed_obj = (const Type *) obj;
    323   if (likely (typed_obj->get_glyph (codepoint, glyph)))
    324     return true;
    325 
    326   if (codepoint <= 0x00FFu)
    327   {
    328     /* For symbol-encoded OpenType fonts, we duplicate the
    329      * U+F000..F0FF range at U+0000..U+00FF.  That's what
    330      * Windows seems to do, and that's hinted about at:
    331      * http://www.microsoft.com/typography/otspec/recom.htm
    332      * under "Non-Standard (Symbol) Fonts". */
    333     return typed_obj->get_glyph (0xF000u + codepoint, glyph);
    334   }
    335 
    336   return false;
    337 }
    338 
    339 struct hb_ot_face_cmap_accelerator_t
    340 {
    341   hb_cmap_get_glyph_func_t get_glyph_func;
    342   const void *get_glyph_data;
    343   OT::CmapSubtableFormat4::accelerator_t format4_accel;
    344 
    345   const OT::CmapSubtableFormat14 *uvs_table;
    346   hb_blob_t *blob;
    347 
    348   inline void init (hb_face_t *face)
    349   {
    350     this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
    351     const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
    352     const OT::CmapSubtable *subtable = NULL;
    353     const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
    354 
    355     bool symbol = false;
    356     /* 32-bit subtables. */
    357     if (!subtable) subtable = cmap->find_subtable (3, 10);
    358     if (!subtable) subtable = cmap->find_subtable (0, 6);
    359     if (!subtable) subtable = cmap->find_subtable (0, 4);
    360     /* 16-bit subtables. */
    361     if (!subtable) subtable = cmap->find_subtable (3, 1);
    362     if (!subtable) subtable = cmap->find_subtable (0, 3);
    363     if (!subtable) subtable = cmap->find_subtable (0, 2);
    364     if (!subtable) subtable = cmap->find_subtable (0, 1);
    365     if (!subtable) subtable = cmap->find_subtable (0, 0);
    366     if (!subtable)
    367     {
    368       subtable = cmap->find_subtable (3, 0);
    369       if (subtable) symbol = true;
    370     }
    371     /* Meh. */
    372     if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
    373 
    374     /* UVS subtable. */
    375     if (!subtable_uvs)
    376     {
    377       const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
    378       if (st && st->u.format == 14)
    379         subtable_uvs = &st->u.format14;
    380     }
    381     /* Meh. */
    382     if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
    383 
    384     this->uvs_table = subtable_uvs;
    385 
    386     this->get_glyph_data = subtable;
    387     if (unlikely (symbol))
    388       this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
    389     else
    390       switch (subtable->u.format) {
    391       /* Accelerate format 4 and format 12. */
    392       default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;		break;
    393       case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;	break;
    394       case  4:
    395 	{
    396 	  this->format4_accel.init (&subtable->u.format4);
    397 	  this->get_glyph_data = &this->format4_accel;
    398 	  this->get_glyph_func = this->format4_accel.get_glyph_func;
    399 	}
    400 	break;
    401       }
    402   }
    403 
    404   inline void fini (void)
    405   {
    406     hb_blob_destroy (this->blob);
    407   }
    408 
    409   inline bool get_nominal_glyph (hb_codepoint_t  unicode,
    410 				 hb_codepoint_t *glyph) const
    411   {
    412     return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
    413   }
    414 
    415   inline bool get_variation_glyph (hb_codepoint_t  unicode,
    416 				   hb_codepoint_t  variation_selector,
    417 				   hb_codepoint_t *glyph) const
    418   {
    419     switch (this->uvs_table->get_glyph_variant (unicode,
    420 						variation_selector,
    421 						glyph))
    422     {
    423       case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
    424       case OT::GLYPH_VARIANT_FOUND:		return true;
    425       case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
    426     }
    427 
    428     return get_nominal_glyph (unicode, glyph);
    429   }
    430 };
    431 
    432 struct hb_ot_font_t
    433 {
    434   hb_ot_face_cmap_accelerator_t cmap;
    435   hb_ot_face_metrics_accelerator_t h_metrics;
    436   hb_ot_face_metrics_accelerator_t v_metrics;
    437   OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
    438   OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
    439 };
    440 
    441 
    442 static hb_ot_font_t *
    443 _hb_ot_font_create (hb_face_t *face)
    444 {
    445   hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
    446 
    447   if (unlikely (!ot_font))
    448     return NULL;
    449 
    450   ot_font->cmap.init (face);
    451   ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_HVAR, HB_OT_TAG_os2);
    452   ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_OT_TAG_VVAR, HB_TAG_NONE,
    453 			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
    454   ot_font->glyf.init (face);
    455   ot_font->cbdt.init (face);
    456 
    457   return ot_font;
    458 }
    459 
    460 static void
    461 _hb_ot_font_destroy (hb_ot_font_t *ot_font)
    462 {
    463   ot_font->cmap.fini ();
    464   ot_font->h_metrics.fini ();
    465   ot_font->v_metrics.fini ();
    466   ot_font->glyf.fini ();
    467   ot_font->cbdt.fini ();
    468 
    469   free (ot_font);
    470 }
    471 
    472 
    473 static hb_bool_t
    474 hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
    475 			 void *font_data,
    476 			 hb_codepoint_t unicode,
    477 			 hb_codepoint_t *glyph,
    478 			 void *user_data HB_UNUSED)
    479 
    480 {
    481   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
    482   return ot_font->cmap.get_nominal_glyph (unicode, glyph);
    483 }
    484 
    485 static hb_bool_t
    486 hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
    487 			   void *font_data,
    488 			   hb_codepoint_t unicode,
    489 			   hb_codepoint_t variation_selector,
    490 			   hb_codepoint_t *glyph,
    491 			   void *user_data HB_UNUSED)
    492 {
    493   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
    494   return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
    495 }
    496 
    497 static hb_position_t
    498 hb_ot_get_glyph_h_advance (hb_font_t *font,
    499 			   void *font_data,
    500 			   hb_codepoint_t glyph,
    501 			   void *user_data HB_UNUSED)
    502 {
    503   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
    504   return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font));
    505 }
    506 
    507 static hb_position_t
    508 hb_ot_get_glyph_v_advance (hb_font_t *font,
    509 			   void *font_data,
    510 			   hb_codepoint_t glyph,
    511 			   void *user_data HB_UNUSED)
    512 {
    513   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
    514   return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
    515 }
    516 
    517 static hb_bool_t
    518 hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
    519 			 void *font_data,
    520 			 hb_codepoint_t glyph,
    521 			 hb_glyph_extents_t *extents,
    522 			 void *user_data HB_UNUSED)
    523 {
    524   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
    525   bool ret = ot_font->glyf->get_extents (glyph, extents);
    526   if (!ret)
    527     ret = ot_font->cbdt->get_extents (glyph, extents);
    528   // TODO Hook up side-bearings variations.
    529   extents->x_bearing = font->em_scale_x (extents->x_bearing);
    530   extents->y_bearing = font->em_scale_y (extents->y_bearing);
    531   extents->width     = font->em_scale_x (extents->width);
    532   extents->height    = font->em_scale_y (extents->height);
    533   return ret;
    534 }
    535 
    536 static hb_bool_t
    537 hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
    538 			  void *font_data,
    539 			  hb_font_extents_t *metrics,
    540 			  void *user_data HB_UNUSED)
    541 {
    542   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
    543   metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
    544   metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
    545   metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
    546   // TODO Hook up variations.
    547   return ot_font->h_metrics.has_font_extents;
    548 }
    549 
    550 static hb_bool_t
    551 hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
    552 			  void *font_data,
    553 			  hb_font_extents_t *metrics,
    554 			  void *user_data HB_UNUSED)
    555 {
    556   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
    557   metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
    558   metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
    559   metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
    560   // TODO Hook up variations.
    561   return ot_font->v_metrics.has_font_extents;
    562 }
    563 
    564 static hb_font_funcs_t *static_ot_funcs = NULL;
    565 
    566 #ifdef HB_USE_ATEXIT
    567 static
    568 void free_static_ot_funcs (void)
    569 {
    570   hb_font_funcs_destroy (static_ot_funcs);
    571 }
    572 #endif
    573 
    574 static hb_font_funcs_t *
    575 _hb_ot_get_font_funcs (void)
    576 {
    577 retry:
    578   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
    579 
    580   if (unlikely (!funcs))
    581   {
    582     funcs = hb_font_funcs_create ();
    583 
    584     hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
    585     hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
    586     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
    587     hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
    588     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
    589     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
    590     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
    591     //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
    592     //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
    593     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
    594     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
    595     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
    596     //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
    597     //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
    598 
    599     hb_font_funcs_make_immutable (funcs);
    600 
    601     if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
    602       hb_font_funcs_destroy (funcs);
    603       goto retry;
    604     }
    605 
    606 #ifdef HB_USE_ATEXIT
    607     atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
    608 #endif
    609   };
    610 
    611   return funcs;
    612 }
    613 
    614 
    615 /**
    616  * hb_ot_font_set_funcs:
    617  *
    618  * Since: 0.9.28
    619  **/
    620 void
    621 hb_ot_font_set_funcs (hb_font_t *font)
    622 {
    623   hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
    624   if (unlikely (!ot_font))
    625     return;
    626 
    627   hb_font_set_funcs (font,
    628 		     _hb_ot_get_font_funcs (),
    629 		     ot_font,
    630 		     (hb_destroy_func_t) _hb_ot_font_destroy);
    631 }
    632